summaryrefslogtreecommitdiffstats
path: root/dom/browser-element
diff options
context:
space:
mode:
Diffstat (limited to 'dom/browser-element')
-rw-r--r--dom/browser-element/BrowserElementAudioChannel.cpp591
-rw-r--r--dom/browser-element/BrowserElementAudioChannel.h97
-rw-r--r--dom/browser-element/BrowserElementChild.js83
-rw-r--r--dom/browser-element/BrowserElementChildPreload.js1823
-rw-r--r--dom/browser-element/BrowserElementCopyPaste.js125
-rw-r--r--dom/browser-element/BrowserElementParent.cpp317
-rw-r--r--dom/browser-element/BrowserElementParent.h135
-rw-r--r--dom/browser-element/BrowserElementParent.js1202
-rw-r--r--dom/browser-element/BrowserElementParent.manifest2
-rw-r--r--dom/browser-element/BrowserElementPromptService.jsm685
-rw-r--r--dom/browser-element/BrowserElementProxy.js219
-rw-r--r--dom/browser-element/BrowserElementProxy.manifest2
-rw-r--r--dom/browser-element/mochitest/async.js78
-rw-r--r--dom/browser-element/mochitest/audio.oggbin0 -> 14293 bytes
-rw-r--r--dom/browser-element/mochitest/browserElementTestHelpers.js306
-rw-r--r--dom/browser-element/mochitest/browserElement_ActiveStateChange.js108
-rw-r--r--dom/browser-element/mochitest/browserElement_Alert.js304
-rw-r--r--dom/browser-element/mochitest/browserElement_AlertInFrame.js24
-rw-r--r--dom/browser-element/mochitest/browserElement_AudioChannel.js199
-rw-r--r--dom/browser-element/mochitest/browserElement_AudioChannelMutedByDefault.js103
-rw-r--r--dom/browser-element/mochitest/browserElement_AudioChannelSeeking.js128
-rw-r--r--dom/browser-element/mochitest/browserElement_AudioChannel_nested.js69
-rw-r--r--dom/browser-element/mochitest/browserElement_AudioPlayback.js75
-rw-r--r--dom/browser-element/mochitest/browserElement_Auth.js246
-rw-r--r--dom/browser-element/mochitest/browserElement_BackForward.js104
-rw-r--r--dom/browser-element/mochitest/browserElement_BadScreenshot.js71
-rw-r--r--dom/browser-element/mochitest/browserElement_BrowserWindowNamespace.js57
-rw-r--r--dom/browser-element/mochitest/browserElement_BrowserWindowResize.js51
-rw-r--r--dom/browser-element/mochitest/browserElement_Close.js24
-rw-r--r--dom/browser-element/mochitest/browserElement_CloseFromOpener.js33
-rw-r--r--dom/browser-element/mochitest/browserElement_ContextmenuEvents.js351
-rw-r--r--dom/browser-element/mochitest/browserElement_CookiesNotThirdParty.js51
-rw-r--r--dom/browser-element/mochitest/browserElement_CopyPaste.js339
-rw-r--r--dom/browser-element/mochitest/browserElement_DOMRequestError.js62
-rw-r--r--dom/browser-element/mochitest/browserElement_DataURI.js68
-rw-r--r--dom/browser-element/mochitest/browserElement_DocumentFirstPaint.js69
-rw-r--r--dom/browser-element/mochitest/browserElement_Download.js37
-rw-r--r--dom/browser-element/mochitest/browserElement_ErrorSecurity.js58
-rw-r--r--dom/browser-element/mochitest/browserElement_ExecuteScript.js119
-rw-r--r--dom/browser-element/mochitest/browserElement_ExposableURI.js55
-rw-r--r--dom/browser-element/mochitest/browserElement_Find.js145
-rw-r--r--dom/browser-element/mochitest/browserElement_FirstPaint.js43
-rw-r--r--dom/browser-element/mochitest/browserElement_ForwardName.js43
-rw-r--r--dom/browser-element/mochitest/browserElement_FrameWrongURI.js52
-rw-r--r--dom/browser-element/mochitest/browserElement_GetContentDimensions.js66
-rw-r--r--dom/browser-element/mochitest/browserElement_GetScreenshot.js117
-rw-r--r--dom/browser-element/mochitest/browserElement_GetScreenshotDppx.js107
-rw-r--r--dom/browser-element/mochitest/browserElement_Iconchange.js129
-rw-r--r--dom/browser-element/mochitest/browserElement_LoadEvents.js120
-rw-r--r--dom/browser-element/mochitest/browserElement_Manifestchange.js96
-rw-r--r--dom/browser-element/mochitest/browserElement_Metachange.js177
-rw-r--r--dom/browser-element/mochitest/browserElement_NextPaint.js43
-rw-r--r--dom/browser-element/mochitest/browserElement_NoAudioTrack.js96
-rw-r--r--dom/browser-element/mochitest/browserElement_OpenMixedProcess.js105
-rw-r--r--dom/browser-element/mochitest/browserElement_OpenNamed.js57
-rw-r--r--dom/browser-element/mochitest/browserElement_OpenTab.js69
-rw-r--r--dom/browser-element/mochitest/browserElement_OpenWindow.js58
-rw-r--r--dom/browser-element/mochitest/browserElement_OpenWindowDifferentOrigin.js41
-rw-r--r--dom/browser-element/mochitest/browserElement_OpenWindowEmpty.js31
-rw-r--r--dom/browser-element/mochitest/browserElement_OpenWindowInFrame.js65
-rw-r--r--dom/browser-element/mochitest/browserElement_OpenWindowRejected.js44
-rw-r--r--dom/browser-element/mochitest/browserElement_OpenWindowRejected2.js47
-rw-r--r--dom/browser-element/mochitest/browserElement_Opensearch.js109
-rw-r--r--dom/browser-element/mochitest/browserElement_PrivateBrowsing.js49
-rw-r--r--dom/browser-element/mochitest/browserElement_PromptCheck.js59
-rw-r--r--dom/browser-element/mochitest/browserElement_PromptConfirm.js87
-rw-r--r--dom/browser-element/mochitest/browserElement_Proxy.js163
-rw-r--r--dom/browser-element/mochitest/browserElement_PurgeHistory.js87
-rw-r--r--dom/browser-element/mochitest/browserElement_Reload.js59
-rw-r--r--dom/browser-element/mochitest/browserElement_ReloadPostRequest.js116
-rw-r--r--dom/browser-element/mochitest/browserElement_RemoveBrowserElement.js30
-rw-r--r--dom/browser-element/mochitest/browserElement_ScrollEvent.js27
-rw-r--r--dom/browser-element/mochitest/browserElement_SecurityChange.js82
-rw-r--r--dom/browser-element/mochitest/browserElement_SendEvent.js85
-rw-r--r--dom/browser-element/mochitest/browserElement_SetInputMethodActive.js323
-rw-r--r--dom/browser-element/mochitest/browserElement_SetVisible.js75
-rw-r--r--dom/browser-element/mochitest/browserElement_SetVisibleFrames.js89
-rw-r--r--dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js55
-rw-r--r--dom/browser-element/mochitest/browserElement_Stop.js52
-rw-r--r--dom/browser-element/mochitest/browserElement_TargetBlank.js26
-rw-r--r--dom/browser-element/mochitest/browserElement_TargetTop.js31
-rw-r--r--dom/browser-element/mochitest/browserElement_ThemeColor.js85
-rw-r--r--dom/browser-element/mochitest/browserElement_Titlechange.js68
-rw-r--r--dom/browser-element/mochitest/browserElement_TopBarrier.js81
-rw-r--r--dom/browser-element/mochitest/browserElement_Viewmode.js71
-rw-r--r--dom/browser-element/mochitest/browserElement_VisibilityChange.js42
-rw-r--r--dom/browser-element/mochitest/browserElement_XFrameOptions.js26
-rw-r--r--dom/browser-element/mochitest/browserElement_XFrameOptionsAllowFrom.js60
-rw-r--r--dom/browser-element/mochitest/browserElement_XFrameOptionsDeny.js63
-rw-r--r--dom/browser-element/mochitest/browserElement_XFrameOptionsSameOrigin.js28
-rw-r--r--dom/browser-element/mochitest/browserElement_getWebManifest.js64
-rw-r--r--dom/browser-element/mochitest/chrome.ini92
-rw-r--r--dom/browser-element/mochitest/createNewTest.py126
-rw-r--r--dom/browser-element/mochitest/file_audio.html15
-rw-r--r--dom/browser-element/mochitest/file_browserElement_ActiveStateChange.html25
-rw-r--r--dom/browser-element/mochitest/file_browserElement_AlertInFrame.html6
-rw-r--r--dom/browser-element/mochitest/file_browserElement_AlertInFrame_Inner.html12
-rw-r--r--dom/browser-element/mochitest/file_browserElement_AudioChannelMutedByDefault.html65
-rw-r--r--dom/browser-element/mochitest/file_browserElement_AudioChannelSeeking.html62
-rw-r--r--dom/browser-element/mochitest/file_browserElement_AudioChannel_nested.html63
-rw-r--r--dom/browser-element/mochitest/file_browserElement_BrowserWindowNamespace.html9
-rw-r--r--dom/browser-element/mochitest/file_browserElement_CloseFromOpener.html8
-rw-r--r--dom/browser-element/mochitest/file_browserElement_CookiesNotThirdParty.html25
-rw-r--r--dom/browser-element/mochitest/file_browserElement_ExecuteScript.html8
-rw-r--r--dom/browser-element/mochitest/file_browserElement_ForwardName.html15
-rw-r--r--dom/browser-element/mochitest/file_browserElement_FrameWrongURI.html5
-rw-r--r--dom/browser-element/mochitest/file_browserElement_LoadEvents.html14
-rw-r--r--dom/browser-element/mochitest/file_browserElement_Metachange.sjs7
-rw-r--r--dom/browser-element/mochitest/file_browserElement_NextPaint.html9
-rw-r--r--dom/browser-element/mochitest/file_browserElement_NoAudioTrack.html32
-rw-r--r--dom/browser-element/mochitest/file_browserElement_Open1.html34
-rw-r--r--dom/browser-element/mochitest/file_browserElement_Open2.html5
-rw-r--r--dom/browser-element/mochitest/file_browserElement_OpenMixedProcess.html22
-rw-r--r--dom/browser-element/mochitest/file_browserElement_OpenNamed.html7
-rw-r--r--dom/browser-element/mochitest/file_browserElement_OpenNamed2.html7
-rw-r--r--dom/browser-element/mochitest/file_browserElement_OpenWindowDifferentOrigin.html18
-rw-r--r--dom/browser-element/mochitest/file_browserElement_OpenWindowEmpty.html7
-rw-r--r--dom/browser-element/mochitest/file_browserElement_OpenWindowInFrame.html6
-rw-r--r--dom/browser-element/mochitest/file_browserElement_OpenWindowRejected.html16
-rw-r--r--dom/browser-element/mochitest/file_browserElement_PrivateBrowsing.html15
-rw-r--r--dom/browser-element/mochitest/file_browserElement_SecurityChange.html21
-rw-r--r--dom/browser-element/mochitest/file_browserElement_SendEvent.html15
-rw-r--r--dom/browser-element/mochitest/file_browserElement_SetInputMethodActive.html2
-rw-r--r--dom/browser-element/mochitest/file_browserElement_SetVisibleFrames2_Outer.html25
-rw-r--r--dom/browser-element/mochitest/file_browserElement_SetVisibleFrames_Inner.html18
-rw-r--r--dom/browser-element/mochitest/file_browserElement_SetVisibleFrames_Outer.html45
-rw-r--r--dom/browser-element/mochitest/file_browserElement_TargetBlank.html18
-rw-r--r--dom/browser-element/mochitest/file_browserElement_TargetTop.html12
-rw-r--r--dom/browser-element/mochitest/file_browserElement_ThemeColor.html8
-rw-r--r--dom/browser-element/mochitest/file_browserElement_Viewmode.html8
-rw-r--r--dom/browser-element/mochitest/file_browserElement_XFrameOptions.sjs9
-rw-r--r--dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.html43
-rw-r--r--dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.sjs16
-rw-r--r--dom/browser-element/mochitest/file_browserElement_XFrameOptionsDeny.html57
-rw-r--r--dom/browser-element/mochitest/file_browserElement_XFrameOptionsSameOrigin.html5
-rw-r--r--dom/browser-element/mochitest/file_bug709759.sjs5
-rw-r--r--dom/browser-element/mochitest/file_bug741717.sjs27
-rw-r--r--dom/browser-element/mochitest/file_download_bin.sjs4
-rw-r--r--dom/browser-element/mochitest/file_empty.html14
-rw-r--r--dom/browser-element/mochitest/file_empty_script.js0
-rw-r--r--dom/browser-element/mochitest/file_focus.html24
-rw-r--r--dom/browser-element/mochitest/file_http_401_response.sjs16
-rw-r--r--dom/browser-element/mochitest/file_http_407_response.sjs16
-rw-r--r--dom/browser-element/mochitest/file_illegal_web_manifest.html7
-rw-r--r--dom/browser-element/mochitest/file_post_request.html15
-rw-r--r--dom/browser-element/mochitest/file_web_manifest.html6
-rw-r--r--dom/browser-element/mochitest/file_web_manifest.json1
-rw-r--r--dom/browser-element/mochitest/file_wyciwyg.html14
-rw-r--r--dom/browser-element/mochitest/iframe_file_audio.html5
-rw-r--r--dom/browser-element/mochitest/mochitest-oop.ini135
-rw-r--r--dom/browser-element/mochitest/mochitest.ini159
-rw-r--r--dom/browser-element/mochitest/noaudio.webmbin0 -> 105755 bytes
-rw-r--r--dom/browser-element/mochitest/priority/chrome.ini19
-rw-r--r--dom/browser-element/mochitest/priority/file_Audio.html19
-rw-r--r--dom/browser-element/mochitest/priority/file_HighPriority.html20
-rw-r--r--dom/browser-element/mochitest/priority/file_MultipleFrames.html14
-rw-r--r--dom/browser-element/mochitest/priority/file_NestedFramesOuter.html20
-rw-r--r--dom/browser-element/mochitest/priority/file_WebGLContextLost.html22
-rw-r--r--dom/browser-element/mochitest/priority/mochitest.ini19
-rw-r--r--dom/browser-element/mochitest/priority/silence.oggbin0 -> 5940 bytes
-rw-r--r--dom/browser-element/mochitest/priority/test_Activity.html62
-rw-r--r--dom/browser-element/mochitest/priority/test_Audio.html53
-rw-r--r--dom/browser-element/mochitest/priority/test_Background.html53
-rw-r--r--dom/browser-element/mochitest/priority/test_HighPriority.html133
-rw-r--r--dom/browser-element/mochitest/priority/test_Keyboard.html54
-rw-r--r--dom/browser-element/mochitest/priority/test_MultipleFrames.html58
-rw-r--r--dom/browser-element/mochitest/priority/test_NestedFrames.html62
-rw-r--r--dom/browser-element/mochitest/priority/test_Preallocated.html71
-rw-r--r--dom/browser-element/mochitest/priority/test_Simple.html59
-rw-r--r--dom/browser-element/mochitest/priority/test_Visibility.html51
-rw-r--r--dom/browser-element/mochitest/priority/test_WebGLContextLost.html99
-rw-r--r--dom/browser-element/mochitest/test_browserElement_NoAttr.html46
-rw-r--r--dom/browser-element/mochitest/test_browserElement_NoPermission.html49
-rw-r--r--dom/browser-element/mochitest/test_browserElement_NoPref.html49
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_ActiveStateChange.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Alert.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_AlertInFrame.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_AudioChannel.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_AudioChannelMutedByDefault.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_AudioChannelSeeking.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_AudioChannel_nested.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_AudioPlayback.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Auth.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_BackForward.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_BadScreenshot.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_BrowserWindowNamespace.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_BrowserWindowResize.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Close.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_CloseFromOpener.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_ContextmenuEvents.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_CookiesNotThirdParty.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_CopyPaste.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_DOMRequestError.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_DataURI.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_DocumentFirstPaint.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Download.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_ErrorSecurity.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_ExecuteScript.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_ExposableURI.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Find.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_FirstPaint.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_ForwardName.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_FrameWrongURI.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_GetContentDimensions.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_GetScreenshot.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_GetScreenshotDppx.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Iconchange.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_LoadEvents.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Manifestchange.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Metachange.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_NextPaint.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_NoAudioTrack.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_OpenMixedProcess.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_OpenNamed.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_OpenTab.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_OpenWindow.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowDifferentOrigin.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowEmpty.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowInFrame.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowRejected.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowRejected2.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Opensearch.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_PrivateBrowsing.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_PromptCheck.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_PromptConfirm.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Proxy.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_PurgeHistory.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Reload.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_ReloadPostRequest.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_RemoveBrowserElement.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_ScrollEvent.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_SecurityChange.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_SendEvent.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_SetInputMethodActive.html14
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_SetVisible.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames2.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Stop.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_TargetBlank.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_TargetTop.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_ThemeColor.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Titlechange.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_TopBarrier.html21
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_Viewmode.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_VisibilityChange.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptions.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsAllowFrom.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsDeny.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsSameOrigin.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_inproc_getWebManifest.html17
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_ActiveStateChange.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Alert.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_AlertInFrame.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_AudioChannel.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_AudioChannelMutedByDefault.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_AudioChannelSeeking.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_AudioChannel_nested.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_AudioPlayback.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Auth.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_BackForward.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_BadScreenshot.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_BrowserWindowResize.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Close.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_CloseFromOpener.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_ContextmenuEvents.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_CookiesNotThirdParty.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_CopyPaste.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_DOMRequestError.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_DataURI.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_DocumentFirstPaint.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Download.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_ErrorSecurity.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_ExecuteScript.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_ExposableURI.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Find.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_FirstPaint.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_ForwardName.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_FrameWrongURI.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_GetContentDimensions.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_GetScreenshot.html20
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_GetScreenshotDppx.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Iconchange.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_LoadEvents.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Manifestchange.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Metachange.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_NextPaint.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_NoAudioTrack.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_OpenMixedProcess.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_OpenNamed.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_OpenTab.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_OpenWindow.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_OpenWindowDifferentOrigin.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_OpenWindowEmpty.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_OpenWindowInFrame.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_OpenWindowRejected.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_OpenWindowRejected2.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Opensearch.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_PrivateBrowsing.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_PromptCheck.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_PromptConfirm.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Proxy.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_PurgeHistory.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Reload.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_ReloadPostRequest.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_RemoveBrowserElement.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_ScrollEvent.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_SecurityChange.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_SendEvent.html18
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_SetInputMethodActive.html14
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_SetVisible.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames2.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Stop.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_TargetBlank.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_TargetTop.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_ThemeColor.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Titlechange.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_TopBarrier.html20
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_Viewmode.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_VisibilityChange.html19
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_XFrameOptions.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsAllowFrom.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsDeny.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsSameOrigin.html13
-rw-r--r--dom/browser-element/mochitest/test_browserElement_oop_getWebManifest.html16
-rw-r--r--dom/browser-element/moz.build60
-rw-r--r--dom/browser-element/nsIBrowserElementAPI.idl112
327 files changed, 17433 insertions, 0 deletions
diff --git a/dom/browser-element/BrowserElementAudioChannel.cpp b/dom/browser-element/BrowserElementAudioChannel.cpp
new file mode 100644
index 000000000..c9c29e2ea
--- /dev/null
+++ b/dom/browser-element/BrowserElementAudioChannel.cpp
@@ -0,0 +1,591 @@
+/* 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 "BrowserElementAudioChannel.h"
+
+#include "mozilla/Preferences.h"
+#include "mozilla/Services.h"
+#include "mozilla/dom/BrowserElementAudioChannelBinding.h"
+#include "mozilla/dom/DOMRequest.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/TabParent.h"
+#include "mozilla/dom/ToJSValue.h"
+#include "AudioChannelService.h"
+#include "nsContentUtils.h"
+#include "nsIBrowserElementAPI.h"
+#include "nsIDocShell.h"
+#include "nsIDOMDOMRequest.h"
+#include "nsIObserverService.h"
+#include "nsISupportsPrimitives.h"
+#include "nsITabParent.h"
+#include "nsPIDOMWindow.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_ADDREF_INHERITED(BrowserElementAudioChannel, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(BrowserElementAudioChannel, DOMEventTargetHelper)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BrowserElementAudioChannel)
+ NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+ NS_INTERFACE_MAP_ENTRY(nsIObserver)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(BrowserElementAudioChannel,
+ DOMEventTargetHelper,
+ mFrameLoader,
+ mFrameWindow,
+ mTabParent,
+ mBrowserElementAPI)
+
+/* static */ already_AddRefed<BrowserElementAudioChannel>
+BrowserElementAudioChannel::Create(nsPIDOMWindowInner* aWindow,
+ nsIFrameLoader* aFrameLoader,
+ nsIBrowserElementAPI* aAPI,
+ AudioChannel aAudioChannel,
+ ErrorResult& aRv)
+{
+ RefPtr<BrowserElementAudioChannel> ac =
+ new BrowserElementAudioChannel(aWindow, aFrameLoader, aAPI, aAudioChannel);
+
+ aRv = ac->Initialize();
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+
+ MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
+ ("BrowserElementAudioChannel, Create, channel = %p, type = %d\n",
+ ac.get(), aAudioChannel));
+
+ return ac.forget();
+}
+
+BrowserElementAudioChannel::BrowserElementAudioChannel(
+ nsPIDOMWindowInner* aWindow,
+ nsIFrameLoader* aFrameLoader,
+ nsIBrowserElementAPI* aAPI,
+ AudioChannel aAudioChannel)
+ : DOMEventTargetHelper(aWindow)
+ , mFrameLoader(aFrameLoader)
+ , mBrowserElementAPI(aAPI)
+ , mAudioChannel(aAudioChannel)
+ , mState(eStateUnknown)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+ if (obs) {
+ nsAutoString name;
+ AudioChannelService::GetAudioChannelString(aAudioChannel, name);
+
+ nsAutoCString topic;
+ topic.Assign("audiochannel-activity-");
+ topic.Append(NS_ConvertUTF16toUTF8(name));
+
+ obs->AddObserver(this, topic.get(), true);
+ }
+}
+
+BrowserElementAudioChannel::~BrowserElementAudioChannel()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+ if (obs) {
+ nsAutoString name;
+ AudioChannelService::GetAudioChannelString(mAudioChannel, name);
+
+ nsAutoCString topic;
+ topic.Assign("audiochannel-activity-");
+ topic.Append(NS_ConvertUTF16toUTF8(name));
+
+ obs->RemoveObserver(this, topic.get());
+ }
+}
+
+nsresult
+BrowserElementAudioChannel::Initialize()
+{
+ if (!mFrameLoader) {
+ nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
+ if (!window) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mFrameWindow = window->GetScriptableTop();
+ mFrameWindow = mFrameWindow->GetOuterWindow();
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsIDocShell> docShell;
+ nsresult rv = mFrameLoader->GetDocShell(getter_AddRefs(docShell));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ if (docShell) {
+ nsCOMPtr<nsPIDOMWindowOuter> window = docShell->GetWindow();
+ if (!window) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mFrameWindow = window->GetScriptableTop();
+ mFrameWindow = mFrameWindow->GetOuterWindow();
+ return NS_OK;
+ }
+
+ rv = mFrameLoader->GetTabParent(getter_AddRefs(mTabParent));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ MOZ_ASSERT(mTabParent);
+ return NS_OK;
+}
+
+JSObject*
+BrowserElementAudioChannel::WrapObject(JSContext *aCx,
+ JS::Handle<JSObject*> aGivenProto)
+{
+ return BrowserElementAudioChannelBinding::Wrap(aCx, this, aGivenProto);
+}
+
+AudioChannel
+BrowserElementAudioChannel::Name() const
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ return mAudioChannel;
+}
+
+namespace {
+
+class BaseRunnable : public Runnable
+{
+protected:
+ nsCOMPtr<nsPIDOMWindowInner> mParentWindow;
+ nsCOMPtr<nsPIDOMWindowOuter> mFrameWindow;
+ RefPtr<DOMRequest> mRequest;
+ AudioChannel mAudioChannel;
+
+ virtual void DoWork(AudioChannelService* aService,
+ JSContext* aCx) = 0;
+
+public:
+ BaseRunnable(nsPIDOMWindowInner* aParentWindow,
+ nsPIDOMWindowOuter* aFrameWindow,
+ DOMRequest* aRequest, AudioChannel aAudioChannel)
+ : mParentWindow(aParentWindow)
+ , mFrameWindow(aFrameWindow)
+ , mRequest(aRequest)
+ , mAudioChannel(aAudioChannel)
+ {}
+
+ NS_IMETHOD Run() override
+ {
+ RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
+ if (!service) {
+ return NS_OK;
+ }
+
+ AutoJSAPI jsapi;
+ if (!jsapi.Init(mParentWindow)) {
+ mRequest->FireError(NS_ERROR_FAILURE);
+ return NS_OK;
+ }
+
+ DoWork(service, jsapi.cx());
+ return NS_OK;
+ }
+};
+
+class GetVolumeRunnable final : public BaseRunnable
+{
+public:
+ GetVolumeRunnable(nsPIDOMWindowInner* aParentWindow,
+ nsPIDOMWindowOuter* aFrameWindow,
+ DOMRequest* aRequest, AudioChannel aAudioChannel)
+ : BaseRunnable(aParentWindow, aFrameWindow, aRequest, aAudioChannel)
+ {}
+
+protected:
+ virtual void DoWork(AudioChannelService* aService, JSContext* aCx) override
+ {
+ float volume = aService->GetAudioChannelVolume(mFrameWindow, mAudioChannel);
+
+ JS::Rooted<JS::Value> value(aCx);
+ if (!ToJSValue(aCx, volume, &value)) {
+ mRequest->FireError(NS_ERROR_FAILURE);
+ return;
+ }
+
+ mRequest->FireSuccess(value);
+ }
+};
+
+class GetMutedRunnable final : public BaseRunnable
+{
+public:
+ GetMutedRunnable(nsPIDOMWindowInner* aParentWindow,
+ nsPIDOMWindowOuter* aFrameWindow,
+ DOMRequest* aRequest, AudioChannel aAudioChannel)
+ : BaseRunnable(aParentWindow, aFrameWindow, aRequest, aAudioChannel)
+ {}
+
+protected:
+ virtual void DoWork(AudioChannelService* aService, JSContext* aCx) override
+ {
+ bool muted = aService->GetAudioChannelMuted(mFrameWindow, mAudioChannel);
+
+ JS::Rooted<JS::Value> value(aCx);
+ if (!ToJSValue(aCx, muted, &value)) {
+ mRequest->FireError(NS_ERROR_FAILURE);
+ return;
+ }
+
+ mRequest->FireSuccess(value);
+ }
+};
+
+class IsActiveRunnable final : public BaseRunnable
+{
+ bool mActive;
+ bool mValueKnown;
+
+public:
+ IsActiveRunnable(nsPIDOMWindowInner* aParentWindow,
+ nsPIDOMWindowOuter* aFrameWindow,
+ DOMRequest* aRequest, AudioChannel aAudioChannel,
+ bool aActive)
+ : BaseRunnable(aParentWindow, aFrameWindow, aRequest, aAudioChannel)
+ , mActive(aActive)
+ , mValueKnown(true)
+ {}
+
+ IsActiveRunnable(nsPIDOMWindowInner* aParentWindow,
+ nsPIDOMWindowOuter* aFrameWindow,
+ DOMRequest* aRequest, AudioChannel aAudioChannel)
+ : BaseRunnable(aParentWindow, aFrameWindow, aRequest, aAudioChannel)
+ , mActive(true)
+ , mValueKnown(false)
+ {}
+
+protected:
+ virtual void DoWork(AudioChannelService* aService, JSContext* aCx) override
+ {
+ if (!mValueKnown) {
+ mActive = aService->IsAudioChannelActive(mFrameWindow, mAudioChannel);
+ }
+
+ JS::Rooted<JS::Value> value(aCx);
+ if (!ToJSValue(aCx, mActive, &value)) {
+ mRequest->FireError(NS_ERROR_FAILURE);
+ return;
+ }
+
+ mRequest->FireSuccess(value);
+ }
+};
+
+class FireSuccessRunnable final : public BaseRunnable
+{
+public:
+ FireSuccessRunnable(nsPIDOMWindowInner* aParentWindow,
+ nsPIDOMWindowOuter* aFrameWindow,
+ DOMRequest* aRequest, AudioChannel aAudioChannel)
+ : BaseRunnable(aParentWindow, aFrameWindow, aRequest, aAudioChannel)
+ {}
+
+protected:
+ virtual void DoWork(AudioChannelService* aService, JSContext* aCx) override
+ {
+ JS::Rooted<JS::Value> value(aCx);
+ mRequest->FireSuccess(value);
+ }
+};
+
+} // anonymous namespace
+
+already_AddRefed<dom::DOMRequest>
+BrowserElementAudioChannel::GetVolume(ErrorResult& aRv)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!mFrameWindow) {
+ nsCOMPtr<nsIDOMDOMRequest> request;
+ aRv = mBrowserElementAPI->GetAudioChannelVolume((uint32_t)mAudioChannel,
+ getter_AddRefs(request));
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+
+ return request.forget().downcast<DOMRequest>();
+ }
+
+ RefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
+
+ nsCOMPtr<nsIRunnable> runnable =
+ new GetVolumeRunnable(GetOwner(), mFrameWindow, domRequest, mAudioChannel);
+ NS_DispatchToMainThread(runnable);
+
+ return domRequest.forget();
+}
+
+already_AddRefed<dom::DOMRequest>
+BrowserElementAudioChannel::SetVolume(float aVolume, ErrorResult& aRv)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!mFrameWindow) {
+ nsCOMPtr<nsIDOMDOMRequest> request;
+ aRv = mBrowserElementAPI->SetAudioChannelVolume((uint32_t)mAudioChannel,
+ aVolume,
+ getter_AddRefs(request));
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+
+ return request.forget().downcast<DOMRequest>();
+ }
+
+ RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
+ if (service) {
+ service->SetAudioChannelVolume(mFrameWindow, mAudioChannel, aVolume);
+ }
+
+ RefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
+ nsCOMPtr<nsIRunnable> runnable = new FireSuccessRunnable(GetOwner(),
+ mFrameWindow,
+ domRequest,
+ mAudioChannel);
+ NS_DispatchToMainThread(runnable);
+
+ return domRequest.forget();
+}
+
+already_AddRefed<dom::DOMRequest>
+BrowserElementAudioChannel::GetMuted(ErrorResult& aRv)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!mFrameWindow) {
+ nsCOMPtr<nsIDOMDOMRequest> request;
+ aRv = mBrowserElementAPI->GetAudioChannelMuted((uint32_t)mAudioChannel,
+ getter_AddRefs(request));
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+
+ return request.forget().downcast<DOMRequest>();
+ }
+
+ RefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
+
+ nsCOMPtr<nsIRunnable> runnable =
+ new GetMutedRunnable(GetOwner(), mFrameWindow, domRequest, mAudioChannel);
+ NS_DispatchToMainThread(runnable);
+
+ return domRequest.forget();
+}
+
+already_AddRefed<dom::DOMRequest>
+BrowserElementAudioChannel::SetMuted(bool aMuted, ErrorResult& aRv)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!mFrameWindow) {
+ nsCOMPtr<nsIDOMDOMRequest> request;
+ aRv = mBrowserElementAPI->SetAudioChannelMuted((uint32_t)mAudioChannel,
+ aMuted,
+ getter_AddRefs(request));
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+
+ return request.forget().downcast<DOMRequest>();
+ }
+
+ RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
+ if (service) {
+ service->SetAudioChannelMuted(mFrameWindow, mAudioChannel, aMuted);
+ }
+
+ RefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
+ nsCOMPtr<nsIRunnable> runnable = new FireSuccessRunnable(GetOwner(),
+ mFrameWindow,
+ domRequest,
+ mAudioChannel);
+ NS_DispatchToMainThread(runnable);
+
+ return domRequest.forget();
+}
+
+already_AddRefed<dom::DOMRequest>
+BrowserElementAudioChannel::IsActive(ErrorResult& aRv)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (mState != eStateUnknown) {
+ RefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
+
+ nsCOMPtr<nsIRunnable> runnable =
+ new IsActiveRunnable(GetOwner(), mFrameWindow, domRequest, mAudioChannel,
+ mState == eStateActive);
+ NS_DispatchToMainThread(runnable);
+
+ return domRequest.forget();
+ }
+
+ if (!mFrameWindow) {
+ nsCOMPtr<nsIDOMDOMRequest> request;
+ aRv = mBrowserElementAPI->IsAudioChannelActive((uint32_t)mAudioChannel,
+ getter_AddRefs(request));
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+
+ return request.forget().downcast<DOMRequest>();
+ }
+
+ RefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
+
+ nsCOMPtr<nsIRunnable> runnable =
+ new IsActiveRunnable(GetOwner(), mFrameWindow, domRequest, mAudioChannel);
+ NS_DispatchToMainThread(runnable);
+
+ return domRequest.forget();
+}
+
+NS_IMETHODIMP
+BrowserElementAudioChannel::Observe(nsISupports* aSubject, const char* aTopic,
+ const char16_t* aData)
+{
+ nsAutoString name;
+ AudioChannelService::GetAudioChannelString(mAudioChannel, name);
+
+ nsAutoCString topic;
+ topic.Assign("audiochannel-activity-");
+ topic.Append(NS_ConvertUTF16toUTF8(name));
+
+ if (strcmp(topic.get(), aTopic)) {
+ return NS_OK;
+ }
+
+ // Message received from the child.
+ if (!mFrameWindow) {
+ if (mTabParent == aSubject) {
+ ProcessStateChanged(aData);
+ }
+
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
+ if (!wrapper) {
+ bool isNested = false;
+ nsresult rv = IsFromNestedFrame(aSubject, isNested);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ if (isNested) {
+ ProcessStateChanged(aData);
+ }
+
+ return NS_OK;
+ }
+
+ uint64_t windowID;
+ nsresult rv = wrapper->GetData(&windowID);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ if (windowID != mFrameWindow->WindowID()) {
+ return NS_OK;
+ }
+
+ ProcessStateChanged(aData);
+ return NS_OK;
+}
+
+void
+BrowserElementAudioChannel::ProcessStateChanged(const char16_t* aData)
+{
+ MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
+ ("BrowserElementAudioChannel, ProcessStateChanged, this = %p, "
+ "type = %d\n", this, mAudioChannel));
+
+ nsAutoString value(aData);
+ mState = value.EqualsASCII("active") ? eStateActive : eStateInactive;
+ DispatchTrustedEvent(NS_LITERAL_STRING("activestatechanged"));
+}
+
+bool
+BrowserElementAudioChannel::IsSystemAppWindow(nsPIDOMWindowOuter* aWindow) const
+{
+ nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
+ if (!doc) {
+ return false;
+ }
+
+ if (nsContentUtils::IsChromeDoc(doc)) {
+ return true;
+ }
+
+ nsAdoptingCString systemAppUrl =
+ mozilla::Preferences::GetCString("b2g.system_startup_url");
+ if (!systemAppUrl) {
+ return false;
+ }
+
+ nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
+ nsCOMPtr<nsIURI> uri;
+ principal->GetURI(getter_AddRefs(uri));
+
+ if (uri) {
+ nsAutoCString spec;
+ uri->GetSpec(spec);
+
+ if (spec.Equals(systemAppUrl)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+nsresult
+BrowserElementAudioChannel::IsFromNestedFrame(nsISupports* aSubject,
+ bool& aIsNested) const
+{
+ aIsNested = false;
+ nsCOMPtr<nsITabParent> iTabParent = do_QueryInterface(aSubject);
+ if (!iTabParent) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<TabParent> tabParent = TabParent::GetFrom(iTabParent);
+ if (!tabParent) {
+ return NS_ERROR_FAILURE;
+ }
+
+ Element* element = tabParent->GetOwnerElement();
+ if (!element) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // Since the normal OOP processes are opened out from b2g process, the owner
+ // of their tabParent are the same - system app window. Therefore, in order
+ // to find the case of nested MozFrame, we need to exclude this situation.
+ nsCOMPtr<nsPIDOMWindowOuter> window = element->OwnerDoc()->GetWindow();
+ if (window == mFrameWindow && !IsSystemAppWindow(window)) {
+ aIsNested = true;
+ return NS_OK;
+ }
+
+ return NS_OK;
+}
+
+} // dom namespace
+} // mozilla namespace
diff --git a/dom/browser-element/BrowserElementAudioChannel.h b/dom/browser-element/BrowserElementAudioChannel.h
new file mode 100644
index 000000000..237e5edc8
--- /dev/null
+++ b/dom/browser-element/BrowserElementAudioChannel.h
@@ -0,0 +1,97 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_BrowserElementAudioChannels_h
+#define mozilla_dom_BrowserElementAudioChannels_h
+
+#include "mozilla/dom/AudioChannelBinding.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/ErrorResult.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsIObserver.h"
+#include "nsIFrameLoader.h"
+#include "nsWeakReference.h"
+#include "nsWrapperCache.h"
+
+class nsIBrowserElementAPI;
+class nsITabParent;
+class nsPIDOMWindowOuter;
+
+namespace mozilla {
+namespace dom {
+
+class DOMRequest;
+
+class BrowserElementAudioChannel final : public DOMEventTargetHelper
+ , public nsSupportsWeakReference
+ , public nsIObserver
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIOBSERVER
+
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BrowserElementAudioChannel,
+ DOMEventTargetHelper)
+
+ static already_AddRefed<BrowserElementAudioChannel>
+ Create(nsPIDOMWindowInner* aWindow,
+ nsIFrameLoader* aFrameLoader,
+ nsIBrowserElementAPI* aAPI,
+ AudioChannel aAudioChannel,
+ ErrorResult& aRv);
+
+ // WebIDL methods
+
+ virtual JSObject* WrapObject(JSContext *aCx,
+ JS::Handle<JSObject*> aGivenProto) override;
+
+ AudioChannel Name() const;
+
+ already_AddRefed<dom::DOMRequest> GetVolume(ErrorResult& aRv);
+ already_AddRefed<dom::DOMRequest> SetVolume(float aVolume, ErrorResult& aRv);
+
+ already_AddRefed<dom::DOMRequest> GetMuted(ErrorResult& aRv);
+ already_AddRefed<dom::DOMRequest> SetMuted(bool aMuted, ErrorResult& aRv);
+
+ already_AddRefed<dom::DOMRequest> IsActive(ErrorResult& aRv);
+
+ IMPL_EVENT_HANDLER(activestatechanged);
+
+private:
+ BrowserElementAudioChannel(nsPIDOMWindowInner* aWindow,
+ nsIFrameLoader* aFrameLoader,
+ nsIBrowserElementAPI* aAPI,
+ AudioChannel aAudioChannel);
+
+ bool IsSystemAppWindow(nsPIDOMWindowOuter* aWindow) const;
+
+ // This method is used to check whether we're in the nested-mozbrower-frame
+ // situation, see bug1214148.
+ nsresult IsFromNestedFrame(nsISupports* aSubject,
+ bool& aIsNested) const;
+
+ ~BrowserElementAudioChannel();
+
+ nsresult Initialize();
+
+ void ProcessStateChanged(const char16_t* aData);
+
+ nsCOMPtr<nsIFrameLoader> mFrameLoader;
+ nsCOMPtr<nsIBrowserElementAPI> mBrowserElementAPI;
+ nsCOMPtr<nsITabParent> mTabParent;
+ nsCOMPtr<nsPIDOMWindowOuter> mFrameWindow;
+ AudioChannel mAudioChannel;
+
+ enum {
+ eStateActive,
+ eStateInactive,
+ eStateUnknown
+ } mState;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_BrowserElementAudioChannels_h
diff --git a/dom/browser-element/BrowserElementChild.js b/dom/browser-element/BrowserElementChild.js
new file mode 100644
index 000000000..066be66d2
--- /dev/null
+++ b/dom/browser-element/BrowserElementChild.js
@@ -0,0 +1,83 @@
+/* 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";
+
+var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
+Cu.import("resource://gre/modules/Services.jsm");
+
+function debug(msg) {
+ //dump("BrowserElementChild - " + msg + "\n");
+}
+
+// NB: this must happen before we process any messages from
+// mozbrowser API clients.
+docShell.isActive = true;
+
+function parentDocShell(docshell) {
+ if (!docshell) {
+ return null;
+ }
+ let treeitem = docshell.QueryInterface(Ci.nsIDocShellTreeItem);
+ return treeitem.parent ? treeitem.parent.QueryInterface(Ci.nsIDocShell) : null;
+}
+
+function isTopBrowserElement(docShell) {
+ while (docShell) {
+ docShell = parentDocShell(docShell);
+ if (docShell && docShell.isMozBrowserOrApp) {
+ return false;
+ }
+ }
+ return true;
+}
+
+var BrowserElementIsReady;
+
+debug(`Might load BE scripts: BEIR: ${BrowserElementIsReady}`);
+if (!BrowserElementIsReady) {
+ debug("Loading BE scripts")
+ if (!("BrowserElementIsPreloaded" in this)) {
+ if (isTopBrowserElement(docShell)) {
+ if (Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
+ try {
+ Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
+ } catch (e) {
+ }
+ }
+ }
+
+ if(Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
+ // general content apps
+ if (isTopBrowserElement(docShell)) {
+ Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementCopyPaste.js");
+ }
+ } else {
+ // rocketbar in system app and other in-process case (ex. B2G desktop client)
+ Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementCopyPaste.js");
+ }
+
+ Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js");
+ }
+
+ function onDestroy() {
+ removeMessageListener("browser-element-api:destroy", onDestroy);
+
+ if (api) {
+ api.destroy();
+ }
+ if ("CopyPasteAssistent" in this) {
+ CopyPasteAssistent.destroy();
+ }
+
+ BrowserElementIsReady = false;
+ }
+ addMessageListener("browser-element-api:destroy", onDestroy);
+
+ BrowserElementIsReady = true;
+} else {
+ debug("BE already loaded, abort");
+}
+
+sendAsyncMessage('browser-element-api:call', { 'msg_name': 'hello' });
diff --git a/dom/browser-element/BrowserElementChildPreload.js b/dom/browser-element/BrowserElementChildPreload.js
new file mode 100644
index 000000000..780dfa80e
--- /dev/null
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -0,0 +1,1823 @@
+/* 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 debug(msg) {
+ // dump("BrowserElementChildPreload - " + msg + "\n");
+}
+
+debug("loaded");
+
+var BrowserElementIsReady;
+
+var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/ExtensionContent.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "acs",
+ "@mozilla.org/audiochannel/service;1",
+ "nsIAudioChannelService");
+XPCOMUtils.defineLazyModuleGetter(this, "ManifestFinder",
+ "resource://gre/modules/ManifestFinder.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ManifestObtainer",
+ "resource://gre/modules/ManifestObtainer.jsm");
+
+
+var kLongestReturnedString = 128;
+
+var Timer = Components.Constructor("@mozilla.org/timer;1",
+ "nsITimer",
+ "initWithCallback");
+
+function sendAsyncMsg(msg, data) {
+ // Ensure that we don't send any messages before BrowserElementChild.js
+ // finishes loading.
+ if (!BrowserElementIsReady) {
+ return;
+ }
+
+ if (!data) {
+ data = { };
+ }
+
+ data.msg_name = msg;
+ sendAsyncMessage('browser-element-api:call', data);
+}
+
+function sendSyncMsg(msg, data) {
+ // Ensure that we don't send any messages before BrowserElementChild.js
+ // finishes loading.
+ if (!BrowserElementIsReady) {
+ return;
+ }
+
+ if (!data) {
+ data = { };
+ }
+
+ data.msg_name = msg;
+ return sendSyncMessage('browser-element-api:call', data);
+}
+
+var CERTIFICATE_ERROR_PAGE_PREF = 'security.alternate_certificate_error_page';
+
+var OBSERVED_EVENTS = [
+ 'xpcom-shutdown',
+ 'audio-playback',
+ 'activity-done',
+ 'will-launch-app'
+];
+
+var LISTENED_EVENTS = [
+ { type: "DOMTitleChanged", useCapture: true, wantsUntrusted: false },
+ { type: "DOMLinkAdded", useCapture: true, wantsUntrusted: false },
+ { type: "MozScrolledAreaChanged", useCapture: true, wantsUntrusted: false },
+ { type: "MozDOMFullscreen:Request", useCapture: true, wantsUntrusted: false },
+ { type: "MozDOMFullscreen:NewOrigin", useCapture: true, wantsUntrusted: false },
+ { type: "MozDOMFullscreen:Exit", useCapture: true, wantsUntrusted: false },
+ { type: "DOMMetaAdded", useCapture: true, wantsUntrusted: false },
+ { type: "DOMMetaChanged", useCapture: true, wantsUntrusted: false },
+ { type: "DOMMetaRemoved", useCapture: true, wantsUntrusted: false },
+ { type: "scrollviewchange", useCapture: true, wantsUntrusted: false },
+ { type: "click", useCapture: false, wantsUntrusted: false },
+ // This listens to unload events from our message manager, but /not/ from
+ // the |content| window. That's because the window's unload event doesn't
+ // bubble, and we're not using a capturing listener. If we'd used
+ // useCapture == true, we /would/ hear unload events from the window, which
+ // is not what we want!
+ { type: "unload", useCapture: false, wantsUntrusted: false },
+];
+
+// We are using the system group for those events so if something in the
+// content called .stopPropagation() this will still be called.
+var LISTENED_SYSTEM_EVENTS = [
+ { type: "DOMWindowClose", useCapture: false },
+ { type: "DOMWindowCreated", useCapture: false },
+ { type: "DOMWindowResize", useCapture: false },
+ { type: "contextmenu", useCapture: false },
+ { type: "scroll", useCapture: false },
+];
+
+/**
+ * The BrowserElementChild implements one half of <iframe mozbrowser>.
+ * (The other half is, unsurprisingly, BrowserElementParent.)
+ *
+ * This script is injected into an <iframe mozbrowser> via
+ * nsIMessageManager::LoadFrameScript().
+ *
+ * Our job here is to listen for events within this frame and bubble them up to
+ * the parent process.
+ */
+
+var global = this;
+
+function BrowserElementProxyForwarder() {
+}
+
+BrowserElementProxyForwarder.prototype = {
+ init: function() {
+ Services.obs.addObserver(this, "browser-element-api:proxy-call", false);
+ addMessageListener("browser-element-api:proxy", this);
+ },
+
+ uninit: function() {
+ Services.obs.removeObserver(this, "browser-element-api:proxy-call", false);
+ removeMessageListener("browser-element-api:proxy", this);
+ },
+
+ // Observer callback receives messages from BrowserElementProxy.js
+ observe: function(subject, topic, stringifedData) {
+ if (subject !== content) {
+ return;
+ }
+
+ // Forward it to BrowserElementParent.js
+ sendAsyncMessage(topic, JSON.parse(stringifedData));
+ },
+
+ // Message manager callback receives messages from BrowserElementParent.js
+ receiveMessage: function(mmMsg) {
+ // Forward it to BrowserElementProxy.js
+ Services.obs.notifyObservers(
+ content, mmMsg.name, JSON.stringify(mmMsg.json));
+ }
+};
+
+function BrowserElementChild() {
+ // Maps outer window id --> weak ref to window. Used by modal dialog code.
+ this._windowIDDict = {};
+
+ // _forcedVisible corresponds to the visibility state our owner has set on us
+ // (via iframe.setVisible). ownerVisible corresponds to whether the docShell
+ // whose window owns this element is visible.
+ //
+ // Our docShell is visible iff _forcedVisible and _ownerVisible are both
+ // true.
+ this._forcedVisible = true;
+ this._ownerVisible = true;
+
+ this._nextPaintHandler = null;
+
+ this._isContentWindowCreated = false;
+ this._pendingSetInputMethodActive = [];
+
+ this.forwarder = new BrowserElementProxyForwarder();
+
+ this._init();
+};
+
+BrowserElementChild.prototype = {
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+ Ci.nsISupportsWeakReference]),
+
+ _init: function() {
+ debug("Starting up.");
+
+ BrowserElementPromptService.mapWindowToBrowserElementChild(content, this);
+
+ docShell.QueryInterface(Ci.nsIWebProgress)
+ .addProgressListener(this._progressListener,
+ Ci.nsIWebProgress.NOTIFY_LOCATION |
+ Ci.nsIWebProgress.NOTIFY_SECURITY |
+ Ci.nsIWebProgress.NOTIFY_STATE_WINDOW);
+
+ let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation);
+ if (!webNavigation.sessionHistory) {
+ webNavigation.sessionHistory = Cc["@mozilla.org/browser/shistory;1"]
+ .createInstance(Ci.nsISHistory);
+ }
+
+ // This is necessary to get security web progress notifications.
+ var securityUI = Cc['@mozilla.org/secure_browser_ui;1']
+ .createInstance(Ci.nsISecureBrowserUI);
+ securityUI.init(content);
+
+ // A cache of the menuitem dom objects keyed by the id we generate
+ // and pass to the embedder
+ this._ctxHandlers = {};
+ // Counter of contextmenu events fired
+ this._ctxCounter = 0;
+
+ this._shuttingDown = false;
+
+ LISTENED_EVENTS.forEach(event => {
+ addEventListener(event.type, this, event.useCapture, event.wantsUntrusted);
+ });
+
+ // Registers a MozAfterPaint handler for the very first paint.
+ this._addMozAfterPaintHandler(function () {
+ sendAsyncMsg('firstpaint');
+ });
+
+ addMessageListener("browser-element-api:call", this);
+
+ let els = Cc["@mozilla.org/eventlistenerservice;1"]
+ .getService(Ci.nsIEventListenerService);
+ LISTENED_SYSTEM_EVENTS.forEach(event => {
+ els.addSystemEventListener(global, event.type, this, event.useCapture);
+ });
+
+ OBSERVED_EVENTS.forEach((aTopic) => {
+ Services.obs.addObserver(this, aTopic, false);
+ });
+
+ this.forwarder.init();
+ },
+
+ /**
+ * Shut down the frame's side of the browser API. This is called when:
+ * - our TabChildGlobal starts to die
+ * - the content is moved to frame without the browser API
+ * This is not called when the page inside |content| unloads.
+ */
+ destroy: function() {
+ debug("Destroying");
+ this._shuttingDown = true;
+
+ BrowserElementPromptService.unmapWindowToBrowserElementChild(content);
+
+ docShell.QueryInterface(Ci.nsIWebProgress)
+ .removeProgressListener(this._progressListener);
+
+ LISTENED_EVENTS.forEach(event => {
+ removeEventListener(event.type, this, event.useCapture, event.wantsUntrusted);
+ });
+
+ this._deactivateNextPaintListener();
+
+ removeMessageListener("browser-element-api:call", this);
+
+ let els = Cc["@mozilla.org/eventlistenerservice;1"]
+ .getService(Ci.nsIEventListenerService);
+ LISTENED_SYSTEM_EVENTS.forEach(event => {
+ els.removeSystemEventListener(global, event.type, this, event.useCapture);
+ });
+
+ OBSERVED_EVENTS.forEach((aTopic) => {
+ Services.obs.removeObserver(this, aTopic);
+ });
+
+ this.forwarder.uninit();
+ this.forwarder = null;
+ },
+
+ handleEvent: function(event) {
+ switch (event.type) {
+ case "DOMTitleChanged":
+ this._titleChangedHandler(event);
+ break;
+ case "DOMLinkAdded":
+ this._linkAddedHandler(event);
+ break;
+ case "MozScrolledAreaChanged":
+ this._mozScrollAreaChanged(event);
+ break;
+ case "MozDOMFullscreen:Request":
+ this._mozRequestedDOMFullscreen(event);
+ break;
+ case "MozDOMFullscreen:NewOrigin":
+ this._mozFullscreenOriginChange(event);
+ break;
+ case "MozDOMFullscreen:Exit":
+ this._mozExitDomFullscreen(event);
+ break;
+ case "DOMMetaAdded":
+ this._metaChangedHandler(event);
+ break;
+ case "DOMMetaChanged":
+ this._metaChangedHandler(event);
+ break;
+ case "DOMMetaRemoved":
+ this._metaChangedHandler(event);
+ break;
+ case "scrollviewchange":
+ this._ScrollViewChangeHandler(event);
+ break;
+ case "click":
+ this._ClickHandler(event);
+ break;
+ case "unload":
+ this.destroy(event);
+ break;
+ case "DOMWindowClose":
+ this._windowCloseHandler(event);
+ break;
+ case "DOMWindowCreated":
+ this._windowCreatedHandler(event);
+ break;
+ case "DOMWindowResize":
+ this._windowResizeHandler(event);
+ break;
+ case "contextmenu":
+ this._contextmenuHandler(event);
+ break;
+ case "scroll":
+ this._scrollEventHandler(event);
+ break;
+ }
+ },
+
+ receiveMessage: function(message) {
+ let self = this;
+
+ let mmCalls = {
+ "purge-history": this._recvPurgeHistory,
+ "get-screenshot": this._recvGetScreenshot,
+ "get-contentdimensions": this._recvGetContentDimensions,
+ "set-visible": this._recvSetVisible,
+ "get-visible": this._recvVisible,
+ "send-mouse-event": this._recvSendMouseEvent,
+ "send-touch-event": this._recvSendTouchEvent,
+ "get-can-go-back": this._recvCanGoBack,
+ "get-can-go-forward": this._recvCanGoForward,
+ "mute": this._recvMute,
+ "unmute": this._recvUnmute,
+ "get-muted": this._recvGetMuted,
+ "set-volume": this._recvSetVolume,
+ "get-volume": this._recvGetVolume,
+ "go-back": this._recvGoBack,
+ "go-forward": this._recvGoForward,
+ "reload": this._recvReload,
+ "stop": this._recvStop,
+ "zoom": this._recvZoom,
+ "unblock-modal-prompt": this._recvStopWaiting,
+ "fire-ctx-callback": this._recvFireCtxCallback,
+ "owner-visibility-change": this._recvOwnerVisibilityChange,
+ "entered-fullscreen": this._recvEnteredFullscreen,
+ "exit-fullscreen": this._recvExitFullscreen,
+ "activate-next-paint-listener": this._activateNextPaintListener,
+ "set-input-method-active": this._recvSetInputMethodActive,
+ "deactivate-next-paint-listener": this._deactivateNextPaintListener,
+ "find-all": this._recvFindAll,
+ "find-next": this._recvFindNext,
+ "clear-match": this._recvClearMatch,
+ "execute-script": this._recvExecuteScript,
+ "get-audio-channel-volume": this._recvGetAudioChannelVolume,
+ "set-audio-channel-volume": this._recvSetAudioChannelVolume,
+ "get-audio-channel-muted": this._recvGetAudioChannelMuted,
+ "set-audio-channel-muted": this._recvSetAudioChannelMuted,
+ "get-is-audio-channel-active": this._recvIsAudioChannelActive,
+ "get-web-manifest": this._recvGetWebManifest,
+ }
+
+ if (message.data.msg_name in mmCalls) {
+ return mmCalls[message.data.msg_name].apply(self, arguments);
+ }
+ },
+
+ _paintFrozenTimer: null,
+ observe: function(subject, topic, data) {
+ // Ignore notifications not about our document. (Note that |content| /can/
+ // be null; see bug 874900.)
+
+ if (topic !== 'activity-done' &&
+ topic !== 'audio-playback' &&
+ topic !== 'will-launch-app' &&
+ (!content || subject !== content.document)) {
+ return;
+ }
+ if (topic == 'activity-done' && docShell !== subject)
+ return;
+ switch (topic) {
+ case 'activity-done':
+ sendAsyncMsg('activitydone', { success: (data == 'activity-success') });
+ break;
+ case 'audio-playback':
+ if (subject === content) {
+ sendAsyncMsg('audioplaybackchange', { _payload_: data });
+ }
+ break;
+ case 'xpcom-shutdown':
+ this._shuttingDown = true;
+ break;
+ case 'will-launch-app':
+ // If the launcher is not visible, let's ignore the message.
+ if (!docShell.isActive) {
+ return;
+ }
+
+ // If this is not a content process, let's not freeze painting.
+ if (Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_CONTENT) {
+ return;
+ }
+
+ docShell.contentViewer.pausePainting();
+
+ this._paintFrozenTimer && this._paintFrozenTimer.cancel();
+ this._paintFrozenTimer = new Timer(this, 3000, Ci.nsITimer.TYPE_ONE_SHOT);
+ break;
+ }
+ },
+
+ notify: function(timer) {
+ docShell.contentViewer.resumePainting();
+ this._paintFrozenTimer.cancel();
+ this._paintFrozenTimer = null;
+ },
+
+ get _windowUtils() {
+ return content.document.defaultView
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ },
+
+ _tryGetInnerWindowID: function(win) {
+ let utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ try {
+ return utils.currentInnerWindowID;
+ }
+ catch(e) {
+ return null;
+ }
+ },
+
+ /**
+ * Show a modal prompt. Called by BrowserElementPromptService.
+ */
+ showModalPrompt: function(win, args) {
+ let utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+
+ args.windowID = { outer: utils.outerWindowID,
+ inner: this._tryGetInnerWindowID(win) };
+ sendAsyncMsg('showmodalprompt', args);
+
+ let returnValue = this._waitForResult(win);
+
+ if (args.promptType == 'prompt' ||
+ args.promptType == 'confirm' ||
+ args.promptType == 'custom-prompt') {
+ return returnValue;
+ }
+ },
+
+ /**
+ * Spin in a nested event loop until we receive a unblock-modal-prompt message for
+ * this window.
+ */
+ _waitForResult: function(win) {
+ debug("_waitForResult(" + win + ")");
+ let utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+
+ let outerWindowID = utils.outerWindowID;
+ let innerWindowID = this._tryGetInnerWindowID(win);
+ if (innerWindowID === null) {
+ // I have no idea what waiting for a result means when there's no inner
+ // window, so let's just bail.
+ debug("_waitForResult: No inner window. Bailing.");
+ return;
+ }
+
+ this._windowIDDict[outerWindowID] = Cu.getWeakReference(win);
+
+ debug("Entering modal state (outerWindowID=" + outerWindowID + ", " +
+ "innerWindowID=" + innerWindowID + ")");
+
+ utils.enterModalState();
+
+ // We'll decrement win.modalDepth when we receive a unblock-modal-prompt message
+ // for the window.
+ if (!win.modalDepth) {
+ win.modalDepth = 0;
+ }
+ win.modalDepth++;
+ let origModalDepth = win.modalDepth;
+
+ let thread = Services.tm.currentThread;
+ debug("Nested event loop - begin");
+ while (win.modalDepth == origModalDepth && !this._shuttingDown) {
+ // Bail out of the loop if the inner window changed; that means the
+ // window navigated. Bail out when we're shutting down because otherwise
+ // we'll leak our window.
+ if (this._tryGetInnerWindowID(win) !== innerWindowID) {
+ debug("_waitForResult: Inner window ID changed " +
+ "while in nested event loop.");
+ break;
+ }
+
+ thread.processNextEvent(/* mayWait = */ true);
+ }
+ debug("Nested event loop - finish");
+
+ if (win.modalDepth == 0) {
+ delete this._windowIDDict[outerWindowID];
+ }
+
+ // If we exited the loop because the inner window changed, then bail on the
+ // modal prompt.
+ if (innerWindowID !== this._tryGetInnerWindowID(win)) {
+ throw Components.Exception("Modal state aborted by navigation",
+ Cr.NS_ERROR_NOT_AVAILABLE);
+ }
+
+ let returnValue = win.modalReturnValue;
+ delete win.modalReturnValue;
+
+ if (!this._shuttingDown) {
+ utils.leaveModalState();
+ }
+
+ debug("Leaving modal state (outerID=" + outerWindowID + ", " +
+ "innerID=" + innerWindowID + ")");
+ return returnValue;
+ },
+
+ _recvStopWaiting: function(msg) {
+ let outerID = msg.json.windowID.outer;
+ let innerID = msg.json.windowID.inner;
+ let returnValue = msg.json.returnValue;
+ debug("recvStopWaiting(outer=" + outerID + ", inner=" + innerID +
+ ", returnValue=" + returnValue + ")");
+
+ if (!this._windowIDDict[outerID]) {
+ debug("recvStopWaiting: No record of outer window ID " + outerID);
+ return;
+ }
+
+ let win = this._windowIDDict[outerID].get();
+
+ if (!win) {
+ debug("recvStopWaiting, but window is gone\n");
+ return;
+ }
+
+ if (innerID !== this._tryGetInnerWindowID(win)) {
+ debug("recvStopWaiting, but inner ID has changed\n");
+ return;
+ }
+
+ debug("recvStopWaiting " + win);
+ win.modalReturnValue = returnValue;
+ win.modalDepth--;
+ },
+
+ _recvEnteredFullscreen: function() {
+ if (!this._windowUtils.handleFullscreenRequests() &&
+ !content.document.fullscreenElement) {
+ // If we don't actually have any pending fullscreen request
+ // to handle, neither we have been in fullscreen, tell the
+ // parent to just exit.
+ sendAsyncMsg("exit-dom-fullscreen");
+ }
+ },
+
+ _recvExitFullscreen: function() {
+ this._windowUtils.exitFullscreen();
+ },
+
+ _titleChangedHandler: function(e) {
+ debug("Got titlechanged: (" + e.target.title + ")");
+ var win = e.target.defaultView;
+
+ // Ignore titlechanges which don't come from the top-level
+ // <iframe mozbrowser> window.
+ if (win == content) {
+ sendAsyncMsg('titlechange', { _payload_: e.target.title });
+ }
+ else {
+ debug("Not top level!");
+ }
+ },
+
+ _maybeCopyAttribute: function(src, target, attribute) {
+ if (src.getAttribute(attribute)) {
+ target[attribute] = src.getAttribute(attribute);
+ }
+ },
+
+ _iconChangedHandler: function(e) {
+ debug('Got iconchanged: (' + e.target.href + ')');
+ let icon = { href: e.target.href };
+ this._maybeCopyAttribute(e.target, icon, 'sizes');
+ this._maybeCopyAttribute(e.target, icon, 'rel');
+ sendAsyncMsg('iconchange', icon);
+ },
+
+ _openSearchHandler: function(e) {
+ debug('Got opensearch: (' + e.target.href + ')');
+
+ if (e.target.type !== "application/opensearchdescription+xml") {
+ return;
+ }
+
+ sendAsyncMsg('opensearch', { title: e.target.title,
+ href: e.target.href });
+
+ },
+
+ _manifestChangedHandler: function(e) {
+ debug('Got manifestchanged: (' + e.target.href + ')');
+ let manifest = { href: e.target.href };
+ sendAsyncMsg('manifestchange', manifest);
+
+ },
+
+ // Processes the "rel" field in <link> tags and forward to specific handlers.
+ _linkAddedHandler: function(e) {
+ let win = e.target.ownerDocument.defaultView;
+ // Ignore links which don't come from the top-level
+ // <iframe mozbrowser> window.
+ if (win != content) {
+ debug('Not top level!');
+ return;
+ }
+
+ let handlers = {
+ 'icon': this._iconChangedHandler.bind(this),
+ 'apple-touch-icon': this._iconChangedHandler.bind(this),
+ 'apple-touch-icon-precomposed': this._iconChangedHandler.bind(this),
+ 'search': this._openSearchHandler,
+ 'manifest': this._manifestChangedHandler
+ };
+
+ debug('Got linkAdded: (' + e.target.href + ') ' + e.target.rel);
+ e.target.rel.split(' ').forEach(function(x) {
+ let token = x.toLowerCase();
+ if (handlers[token]) {
+ handlers[token](e);
+ }
+ }, this);
+ },
+
+ _metaChangedHandler: function(e) {
+ let win = e.target.ownerDocument.defaultView;
+ // Ignore metas which don't come from the top-level
+ // <iframe mozbrowser> window.
+ if (win != content) {
+ debug('Not top level!');
+ return;
+ }
+
+ var name = e.target.name;
+ var property = e.target.getAttributeNS(null, "property");
+
+ if (!name && !property) {
+ return;
+ }
+
+ debug('Got metaChanged: (' + (name || property) + ') ' +
+ e.target.content);
+
+ let handlers = {
+ 'viewmode': this._genericMetaHandler,
+ 'theme-color': this._genericMetaHandler,
+ 'theme-group': this._genericMetaHandler,
+ 'application-name': this._applicationNameChangedHandler
+ };
+ let handler = handlers[name];
+
+ if ((property || name).match(/^og:/)) {
+ name = property || name;
+ handler = this._genericMetaHandler;
+ }
+
+ if (handler) {
+ handler(name, e.type, e.target);
+ }
+ },
+
+ _applicationNameChangedHandler: function(name, eventType, target) {
+ if (eventType !== 'DOMMetaAdded') {
+ // Bug 1037448 - Decide what to do when <meta name="application-name">
+ // changes
+ return;
+ }
+
+ let meta = { name: name,
+ content: target.content };
+
+ let lang;
+ let elm;
+
+ for (elm = target;
+ !lang && elm && elm.nodeType == target.ELEMENT_NODE;
+ elm = elm.parentNode) {
+ if (elm.hasAttribute('lang')) {
+ lang = elm.getAttribute('lang');
+ continue;
+ }
+
+ if (elm.hasAttributeNS('http://www.w3.org/XML/1998/namespace', 'lang')) {
+ lang = elm.getAttributeNS('http://www.w3.org/XML/1998/namespace', 'lang');
+ continue;
+ }
+ }
+
+ // No lang has been detected.
+ if (!lang && elm.nodeType == target.DOCUMENT_NODE) {
+ lang = elm.contentLanguage;
+ }
+
+ if (lang) {
+ meta.lang = lang;
+ }
+
+ sendAsyncMsg('metachange', meta);
+ },
+
+ _ScrollViewChangeHandler: function(e) {
+ e.stopPropagation();
+ let detail = {
+ state: e.state,
+ };
+ sendAsyncMsg('scrollviewchange', detail);
+ },
+
+ _ClickHandler: function(e) {
+
+ let isHTMLLink = node =>
+ ((node instanceof Ci.nsIDOMHTMLAnchorElement && node.href) ||
+ (node instanceof Ci.nsIDOMHTMLAreaElement && node.href) ||
+ node instanceof Ci.nsIDOMHTMLLinkElement);
+
+ // Open in a new tab if middle click or ctrl/cmd-click,
+ // and e.target is a link or inside a link.
+ if ((Services.appinfo.OS == 'Darwin' && e.metaKey) ||
+ (Services.appinfo.OS != 'Darwin' && e.ctrlKey) ||
+ e.button == 1) {
+
+ let node = e.target;
+ while (node && !isHTMLLink(node)) {
+ node = node.parentNode;
+ }
+
+ if (node) {
+ sendAsyncMsg('opentab', {url: node.href});
+ }
+ }
+ },
+
+ _genericMetaHandler: function(name, eventType, target) {
+ let meta = {
+ name: name,
+ content: target.content,
+ type: eventType.replace('DOMMeta', '').toLowerCase()
+ };
+ sendAsyncMsg('metachange', meta);
+ },
+
+ _addMozAfterPaintHandler: function(callback) {
+ function onMozAfterPaint() {
+ let uri = docShell.QueryInterface(Ci.nsIWebNavigation).currentURI;
+ if (uri.spec != "about:blank") {
+ debug("Got afterpaint event: " + uri.spec);
+ removeEventListener('MozAfterPaint', onMozAfterPaint,
+ /* useCapture = */ true);
+ callback();
+ }
+ }
+
+ addEventListener('MozAfterPaint', onMozAfterPaint, /* useCapture = */ true);
+ return onMozAfterPaint;
+ },
+
+ _removeMozAfterPaintHandler: function(listener) {
+ removeEventListener('MozAfterPaint', listener,
+ /* useCapture = */ true);
+ },
+
+ _activateNextPaintListener: function(e) {
+ if (!this._nextPaintHandler) {
+ this._nextPaintHandler = this._addMozAfterPaintHandler(function () {
+ this._nextPaintHandler = null;
+ sendAsyncMsg('nextpaint');
+ }.bind(this));
+ }
+ },
+
+ _deactivateNextPaintListener: function(e) {
+ if (this._nextPaintHandler) {
+ this._removeMozAfterPaintHandler(this._nextPaintHandler);
+ this._nextPaintHandler = null;
+ }
+ },
+
+ _windowCloseHandler: function(e) {
+ let win = e.target;
+ if (win != content || e.defaultPrevented) {
+ return;
+ }
+
+ debug("Closing window " + win);
+ sendAsyncMsg('close');
+
+ // Inform the window implementation that we handled this close ourselves.
+ e.preventDefault();
+ },
+
+ _windowCreatedHandler: function(e) {
+ let targetDocShell = e.target.defaultView
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation);
+ if (targetDocShell != docShell) {
+ return;
+ }
+
+ let uri = docShell.QueryInterface(Ci.nsIWebNavigation).currentURI;
+ debug("Window created: " + uri.spec);
+ if (uri.spec != "about:blank") {
+ this._addMozAfterPaintHandler(function () {
+ sendAsyncMsg('documentfirstpaint');
+ });
+ this._isContentWindowCreated = true;
+ // Handle pending SetInputMethodActive request.
+ while (this._pendingSetInputMethodActive.length > 0) {
+ this._recvSetInputMethodActive(this._pendingSetInputMethodActive.shift());
+ }
+ }
+ },
+
+ _windowResizeHandler: function(e) {
+ let win = e.target;
+ if (win != content || e.defaultPrevented) {
+ return;
+ }
+
+ debug("resizing window " + win);
+ sendAsyncMsg('resize', { width: e.detail.width, height: e.detail.height });
+
+ // Inform the window implementation that we handled this resize ourselves.
+ e.preventDefault();
+ },
+
+ _contextmenuHandler: function(e) {
+ debug("Got contextmenu");
+
+ if (e.defaultPrevented) {
+ return;
+ }
+
+ this._ctxCounter++;
+ this._ctxHandlers = {};
+
+ var elem = e.target;
+ var menuData = {systemTargets: [], contextmenu: null};
+ var ctxMenuId = null;
+ var clipboardPlainTextOnly = Services.prefs.getBoolPref('clipboard.plainTextOnly');
+ var copyableElements = {
+ image: false,
+ link: false,
+ hasElements: function() {
+ return this.image || this.link;
+ }
+ };
+
+ // Set the event target as the copy image command needs it to
+ // determine what was context-clicked on.
+ docShell.contentViewer.QueryInterface(Ci.nsIContentViewerEdit).setCommandNode(elem);
+
+ while (elem && elem.parentNode) {
+ var ctxData = this._getSystemCtxMenuData(elem);
+ if (ctxData) {
+ menuData.systemTargets.push({
+ nodeName: elem.nodeName,
+ data: ctxData
+ });
+ }
+
+ if (!ctxMenuId && 'hasAttribute' in elem && elem.hasAttribute('contextmenu')) {
+ ctxMenuId = elem.getAttribute('contextmenu');
+ }
+
+ // Enable copy image/link option
+ if (elem.nodeName == 'IMG') {
+ copyableElements.image = !clipboardPlainTextOnly;
+ } else if (elem.nodeName == 'A') {
+ copyableElements.link = true;
+ }
+
+ elem = elem.parentNode;
+ }
+
+ if (ctxMenuId || copyableElements.hasElements()) {
+ var menu = null;
+ if (ctxMenuId) {
+ menu = e.target.ownerDocument.getElementById(ctxMenuId);
+ }
+ menuData.contextmenu = this._buildMenuObj(menu, '', copyableElements);
+ }
+
+ // Pass along the position where the context menu should be located
+ menuData.clientX = e.clientX;
+ menuData.clientY = e.clientY;
+ menuData.screenX = e.screenX;
+ menuData.screenY = e.screenY;
+
+ // The value returned by the contextmenu sync call is true if the embedder
+ // called preventDefault() on its contextmenu event.
+ //
+ // We call preventDefault() on our contextmenu event if the embedder called
+ // preventDefault() on /its/ contextmenu event. This way, if the embedder
+ // ignored the contextmenu event, TabChild will fire a click.
+ if (sendSyncMsg('contextmenu', menuData)[0]) {
+ e.preventDefault();
+ } else {
+ this._ctxHandlers = {};
+ }
+ },
+
+ _getSystemCtxMenuData: function(elem) {
+ let documentURI =
+ docShell.QueryInterface(Ci.nsIWebNavigation).currentURI.spec;
+ if ((elem instanceof Ci.nsIDOMHTMLAnchorElement && elem.href) ||
+ (elem instanceof Ci.nsIDOMHTMLAreaElement && elem.href)) {
+ return {uri: elem.href,
+ documentURI: documentURI,
+ text: elem.textContent.substring(0, kLongestReturnedString)};
+ }
+ if (elem instanceof Ci.nsIImageLoadingContent && elem.currentURI) {
+ return {uri: elem.currentURI.spec, documentURI: documentURI};
+ }
+ if (elem instanceof Ci.nsIDOMHTMLImageElement) {
+ return {uri: elem.src, documentURI: documentURI};
+ }
+ if (elem instanceof Ci.nsIDOMHTMLMediaElement) {
+ let hasVideo = !(elem.readyState >= elem.HAVE_METADATA &&
+ (elem.videoWidth == 0 || elem.videoHeight == 0));
+ return {uri: elem.currentSrc || elem.src,
+ hasVideo: hasVideo,
+ documentURI: documentURI};
+ }
+ if (elem instanceof Ci.nsIDOMHTMLInputElement &&
+ elem.hasAttribute("name")) {
+ // For input elements, we look for a parent <form> and if there is
+ // one we return the form's method and action uri.
+ let parent = elem.parentNode;
+ while (parent) {
+ if (parent instanceof Ci.nsIDOMHTMLFormElement &&
+ parent.hasAttribute("action")) {
+ let actionHref = docShell.QueryInterface(Ci.nsIWebNavigation)
+ .currentURI
+ .resolve(parent.getAttribute("action"));
+ let method = parent.hasAttribute("method")
+ ? parent.getAttribute("method").toLowerCase()
+ : "get";
+ return {
+ documentURI: documentURI,
+ action: actionHref,
+ method: method,
+ name: elem.getAttribute("name"),
+ }
+ }
+ parent = parent.parentNode;
+ }
+ }
+ return false;
+ },
+
+ _scrollEventHandler: function(e) {
+ let win = e.target.defaultView;
+ if (win != content) {
+ return;
+ }
+
+ debug("scroll event " + win);
+ sendAsyncMsg("scroll", { top: win.scrollY, left: win.scrollX });
+ },
+
+ _recvPurgeHistory: function(data) {
+ debug("Received purgeHistory message: (" + data.json.id + ")");
+
+ let history = docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory;
+
+ try {
+ if (history && history.count) {
+ history.PurgeHistory(history.count);
+ }
+ } catch(e) {}
+
+ sendAsyncMsg('got-purge-history', { id: data.json.id, successRv: true });
+ },
+
+ _recvGetScreenshot: function(data) {
+ debug("Received getScreenshot message: (" + data.json.id + ")");
+
+ let self = this;
+ let maxWidth = data.json.args.width;
+ let maxHeight = data.json.args.height;
+ let mimeType = data.json.args.mimeType;
+ let domRequestID = data.json.id;
+
+ let takeScreenshotClosure = function() {
+ self._takeScreenshot(maxWidth, maxHeight, mimeType, domRequestID);
+ };
+
+ let maxDelayMS = 2000;
+ try {
+ maxDelayMS = Services.prefs.getIntPref('dom.browserElement.maxScreenshotDelayMS');
+ }
+ catch(e) {}
+
+ // Try to wait for the event loop to go idle before we take the screenshot,
+ // but once we've waited maxDelayMS milliseconds, go ahead and take it
+ // anyway.
+ Cc['@mozilla.org/message-loop;1'].getService(Ci.nsIMessageLoop).postIdleTask(
+ takeScreenshotClosure, maxDelayMS);
+ },
+
+ _recvExecuteScript: function(data) {
+ debug("Received executeScript message: (" + data.json.id + ")");
+
+ let domRequestID = data.json.id;
+
+ let sendError = errorMsg => sendAsyncMsg("execute-script-done", {
+ errorMsg,
+ id: domRequestID
+ });
+
+ let sendSuccess = successRv => sendAsyncMsg("execute-script-done", {
+ successRv,
+ id: domRequestID
+ });
+
+ let isJSON = obj => {
+ try {
+ JSON.stringify(obj);
+ } catch(e) {
+ return false;
+ }
+ return true;
+ }
+
+ let expectedOrigin = data.json.args.options.origin;
+ let expectedUrl = data.json.args.options.url;
+
+ if (expectedOrigin) {
+ if (expectedOrigin != content.location.origin) {
+ sendError("Origin mismatches");
+ return;
+ }
+ }
+
+ if (expectedUrl) {
+ let expectedURI
+ try {
+ expectedURI = Services.io.newURI(expectedUrl, null, null);
+ } catch(e) {
+ sendError("Malformed URL");
+ return;
+ }
+ let currentURI = docShell.QueryInterface(Ci.nsIWebNavigation).currentURI;
+ if (!currentURI.equalsExceptRef(expectedURI)) {
+ sendError("URL mismatches");
+ return;
+ }
+ }
+
+ let sandbox = new Cu.Sandbox([content], {
+ sandboxPrototype: content,
+ sandboxName: "browser-api-execute-script",
+ allowWaivers: false,
+ sameZoneAs: content
+ });
+
+ try {
+ let sandboxRv = Cu.evalInSandbox(data.json.args.script, sandbox, "1.8");
+ if (sandboxRv instanceof sandbox.Promise) {
+ sandboxRv.then(rv => {
+ if (isJSON(rv)) {
+ sendSuccess(rv);
+ } else {
+ sendError("Value returned (resolve) by promise is not a valid JSON object");
+ }
+ }, error => {
+ if (isJSON(error)) {
+ sendError(error);
+ } else {
+ sendError("Value returned (reject) by promise is not a valid JSON object");
+ }
+ });
+ } else {
+ if (isJSON(sandboxRv)) {
+ sendSuccess(sandboxRv);
+ } else {
+ sendError("Script last expression must be a promise or a JSON object");
+ }
+ }
+ } catch(e) {
+ sendError(e.toString());
+ }
+ },
+
+ _recvGetContentDimensions: function(data) {
+ debug("Received getContentDimensions message: (" + data.json.id + ")");
+ sendAsyncMsg('got-contentdimensions', {
+ id: data.json.id,
+ successRv: this._getContentDimensions()
+ });
+ },
+
+ _mozScrollAreaChanged: function(e) {
+ sendAsyncMsg('scrollareachanged', {
+ width: e.width,
+ height: e.height
+ });
+ },
+
+ _mozRequestedDOMFullscreen: function(e) {
+ sendAsyncMsg("requested-dom-fullscreen");
+ },
+
+ _mozFullscreenOriginChange: function(e) {
+ sendAsyncMsg("fullscreen-origin-change", {
+ originNoSuffix: e.target.nodePrincipal.originNoSuffix
+ });
+ },
+
+ _mozExitDomFullscreen: function(e) {
+ sendAsyncMsg("exit-dom-fullscreen");
+ },
+
+ _getContentDimensions: function() {
+ return {
+ width: content.document.body.scrollWidth,
+ height: content.document.body.scrollHeight
+ }
+ },
+
+ /**
+ * Actually take a screenshot and foward the result up to our parent, given
+ * the desired maxWidth and maxHeight (in CSS pixels), and given the
+ * DOMRequest ID associated with the request from the parent.
+ */
+ _takeScreenshot: function(maxWidth, maxHeight, mimeType, domRequestID) {
+ // You can think of the screenshotting algorithm as carrying out the
+ // following steps:
+ //
+ // - Calculate maxWidth, maxHeight, and viewport's width and height in the
+ // dimension of device pixels by multiply the numbers with
+ // window.devicePixelRatio.
+ //
+ // - Let scaleWidth be the factor by which we'd need to downscale the
+ // viewport pixel width so it would fit within maxPixelWidth.
+ // (If the viewport's pixel width is less than maxPixelWidth, let
+ // scaleWidth be 1.) Compute scaleHeight the same way.
+ //
+ // - Scale the viewport by max(scaleWidth, scaleHeight). Now either the
+ // viewport's width is no larger than maxWidth, the viewport's height is
+ // no larger than maxHeight, or both.
+ //
+ // - Crop the viewport so its width is no larger than maxWidth and its
+ // height is no larger than maxHeight.
+ //
+ // - Set mozOpaque to true and background color to solid white
+ // if we are taking a JPEG screenshot, keep transparent if otherwise.
+ //
+ // - Return a screenshot of the page's viewport scaled and cropped per
+ // above.
+ debug("Taking a screenshot: maxWidth=" + maxWidth +
+ ", maxHeight=" + maxHeight +
+ ", mimeType=" + mimeType +
+ ", domRequestID=" + domRequestID + ".");
+
+ if (!content) {
+ // If content is not loaded yet, bail out since even sendAsyncMessage
+ // fails...
+ debug("No content yet!");
+ return;
+ }
+
+ let devicePixelRatio = content.devicePixelRatio;
+
+ let maxPixelWidth = Math.round(maxWidth * devicePixelRatio);
+ let maxPixelHeight = Math.round(maxHeight * devicePixelRatio);
+
+ let contentPixelWidth = content.innerWidth * devicePixelRatio;
+ let contentPixelHeight = content.innerHeight * devicePixelRatio;
+
+ let scaleWidth = Math.min(1, maxPixelWidth / contentPixelWidth);
+ let scaleHeight = Math.min(1, maxPixelHeight / contentPixelHeight);
+
+ let scale = Math.max(scaleWidth, scaleHeight);
+
+ let canvasWidth =
+ Math.min(maxPixelWidth, Math.round(contentPixelWidth * scale));
+ let canvasHeight =
+ Math.min(maxPixelHeight, Math.round(contentPixelHeight * scale));
+
+ let transparent = (mimeType !== 'image/jpeg');
+
+ var canvas = content.document
+ .createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+ if (!transparent)
+ canvas.mozOpaque = true;
+ canvas.width = canvasWidth;
+ canvas.height = canvasHeight;
+
+ let ctx = canvas.getContext("2d", { willReadFrequently: true });
+ ctx.scale(scale * devicePixelRatio, scale * devicePixelRatio);
+
+ let flags = ctx.DRAWWINDOW_DRAW_VIEW |
+ ctx.DRAWWINDOW_USE_WIDGET_LAYERS |
+ ctx.DRAWWINDOW_DO_NOT_FLUSH |
+ ctx.DRAWWINDOW_ASYNC_DECODE_IMAGES;
+ ctx.drawWindow(content, 0, 0, content.innerWidth, content.innerHeight,
+ transparent ? "rgba(255,255,255,0)" : "rgb(255,255,255)",
+ flags);
+
+ // Take a JPEG screenshot by default instead of PNG with alpha channel.
+ // This requires us to unpremultiply the alpha channel, which
+ // is expensive on ARM processors because they lack a hardware integer
+ // division instruction.
+ canvas.toBlob(function(blob) {
+ sendAsyncMsg('got-screenshot', {
+ id: domRequestID,
+ successRv: blob
+ });
+ }, mimeType);
+ },
+
+ _recvFireCtxCallback: function(data) {
+ debug("Received fireCtxCallback message: (" + data.json.menuitem + ")");
+
+ let doCommandIfEnabled = (command) => {
+ if (docShell.isCommandEnabled(command)) {
+ docShell.doCommand(command);
+ }
+ };
+
+ if (data.json.menuitem == 'copy-image') {
+ doCommandIfEnabled('cmd_copyImage');
+ } else if (data.json.menuitem == 'copy-link') {
+ doCommandIfEnabled('cmd_copyLink');
+ } else if (data.json.menuitem in this._ctxHandlers) {
+ this._ctxHandlers[data.json.menuitem].click();
+ this._ctxHandlers = {};
+ } else {
+ // We silently ignore if the embedder uses an incorrect id in the callback
+ debug("Ignored invalid contextmenu invocation");
+ }
+ },
+
+ _buildMenuObj: function(menu, idPrefix, copyableElements) {
+ var menuObj = {type: 'menu', customized: false, items: []};
+ // Customized context menu
+ if (menu) {
+ this._maybeCopyAttribute(menu, menuObj, 'label');
+
+ for (var i = 0, child; child = menu.children[i++];) {
+ if (child.nodeName === 'MENU') {
+ menuObj.items.push(this._buildMenuObj(child, idPrefix + i + '_', false));
+ } else if (child.nodeName === 'MENUITEM') {
+ var id = this._ctxCounter + '_' + idPrefix + i;
+ var menuitem = {id: id, type: 'menuitem'};
+ this._maybeCopyAttribute(child, menuitem, 'label');
+ this._maybeCopyAttribute(child, menuitem, 'icon');
+ this._ctxHandlers[id] = child;
+ menuObj.items.push(menuitem);
+ }
+ }
+
+ if (menuObj.items.length > 0) {
+ menuObj.customized = true;
+ }
+ }
+ // Note: Display "Copy Link" first in order to make sure "Copy Image" is
+ // put together with other image options if elem is an image link.
+ // "Copy Link" menu item
+ if (copyableElements.link) {
+ menuObj.items.push({id: 'copy-link'});
+ }
+ // "Copy Image" menu item
+ if (copyableElements.image) {
+ menuObj.items.push({id: 'copy-image'});
+ }
+
+ return menuObj;
+ },
+
+ _recvSetVisible: function(data) {
+ debug("Received setVisible message: (" + data.json.visible + ")");
+ if (this._forcedVisible == data.json.visible) {
+ return;
+ }
+
+ this._forcedVisible = data.json.visible;
+ this._updateVisibility();
+ },
+
+ _recvVisible: function(data) {
+ sendAsyncMsg('got-visible', {
+ id: data.json.id,
+ successRv: docShell.isActive
+ });
+ },
+
+ /**
+ * Called when the window which contains this iframe becomes hidden or
+ * visible.
+ */
+ _recvOwnerVisibilityChange: function(data) {
+ debug("Received ownerVisibilityChange: (" + data.json.visible + ")");
+ this._ownerVisible = data.json.visible;
+ this._updateVisibility();
+ },
+
+ _updateVisibility: function() {
+ var visible = this._forcedVisible && this._ownerVisible;
+ if (docShell && docShell.isActive !== visible) {
+ docShell.isActive = visible;
+ sendAsyncMsg('visibilitychange', {visible: visible});
+
+ // Ensure painting is not frozen if the app goes visible.
+ if (visible && this._paintFrozenTimer) {
+ this.notify();
+ }
+ }
+ },
+
+ _recvSendMouseEvent: function(data) {
+ let json = data.json;
+ let utils = content.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ utils.sendMouseEventToWindow(json.type, json.x, json.y, json.button,
+ json.clickCount, json.modifiers);
+ },
+
+ _recvSendTouchEvent: function(data) {
+ let json = data.json;
+ let utils = content.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ utils.sendTouchEventToWindow(json.type, json.identifiers, json.touchesX,
+ json.touchesY, json.radiisX, json.radiisY,
+ json.rotationAngles, json.forces, json.count,
+ json.modifiers);
+ },
+
+ _recvCanGoBack: function(data) {
+ var webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
+ sendAsyncMsg('got-can-go-back', {
+ id: data.json.id,
+ successRv: webNav.canGoBack
+ });
+ },
+
+ _recvCanGoForward: function(data) {
+ var webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
+ sendAsyncMsg('got-can-go-forward', {
+ id: data.json.id,
+ successRv: webNav.canGoForward
+ });
+ },
+
+ _recvMute: function(data) {
+ this._windowUtils.audioMuted = true;
+ },
+
+ _recvUnmute: function(data) {
+ this._windowUtils.audioMuted = false;
+ },
+
+ _recvGetMuted: function(data) {
+ sendAsyncMsg('got-muted', {
+ id: data.json.id,
+ successRv: this._windowUtils.audioMuted
+ });
+ },
+
+ _recvSetVolume: function(data) {
+ this._windowUtils.audioVolume = data.json.volume;
+ },
+
+ _recvGetVolume: function(data) {
+ sendAsyncMsg('got-volume', {
+ id: data.json.id,
+ successRv: this._windowUtils.audioVolume
+ });
+ },
+
+ _recvGoBack: function(data) {
+ try {
+ docShell.QueryInterface(Ci.nsIWebNavigation).goBack();
+ } catch(e) {
+ // Silently swallow errors; these happen when we can't go back.
+ }
+ },
+
+ _recvGoForward: function(data) {
+ try {
+ docShell.QueryInterface(Ci.nsIWebNavigation).goForward();
+ } catch(e) {
+ // Silently swallow errors; these happen when we can't go forward.
+ }
+ },
+
+ _recvReload: function(data) {
+ let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
+ let reloadFlags = data.json.hardReload ?
+ webNav.LOAD_FLAGS_BYPASS_PROXY | webNav.LOAD_FLAGS_BYPASS_CACHE :
+ webNav.LOAD_FLAGS_NONE;
+ try {
+ webNav.reload(reloadFlags);
+ } catch(e) {
+ // Silently swallow errors; these can happen if a used cancels reload
+ }
+ },
+
+ _recvStop: function(data) {
+ let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
+ webNav.stop(webNav.STOP_NETWORK);
+ },
+
+ _recvZoom: function(data) {
+ docShell.contentViewer.fullZoom = data.json.zoom;
+ },
+
+ _recvGetAudioChannelVolume: function(data) {
+ debug("Received getAudioChannelVolume message: (" + data.json.id + ")");
+
+ let volume = acs.getAudioChannelVolume(content,
+ data.json.args.audioChannel);
+ sendAsyncMsg('got-audio-channel-volume', {
+ id: data.json.id, successRv: volume
+ });
+ },
+
+ _recvSetAudioChannelVolume: function(data) {
+ debug("Received setAudioChannelVolume message: (" + data.json.id + ")");
+
+ acs.setAudioChannelVolume(content,
+ data.json.args.audioChannel,
+ data.json.args.volume);
+ sendAsyncMsg('got-set-audio-channel-volume', {
+ id: data.json.id, successRv: true
+ });
+ },
+
+ _recvGetAudioChannelMuted: function(data) {
+ debug("Received getAudioChannelMuted message: (" + data.json.id + ")");
+
+ let muted = acs.getAudioChannelMuted(content, data.json.args.audioChannel);
+ sendAsyncMsg('got-audio-channel-muted', {
+ id: data.json.id, successRv: muted
+ });
+ },
+
+ _recvSetAudioChannelMuted: function(data) {
+ debug("Received setAudioChannelMuted message: (" + data.json.id + ")");
+
+ acs.setAudioChannelMuted(content, data.json.args.audioChannel,
+ data.json.args.muted);
+ sendAsyncMsg('got-set-audio-channel-muted', {
+ id: data.json.id, successRv: true
+ });
+ },
+
+ _recvIsAudioChannelActive: function(data) {
+ debug("Received isAudioChannelActive message: (" + data.json.id + ")");
+
+ let active = acs.isAudioChannelActive(content, data.json.args.audioChannel);
+ sendAsyncMsg('got-is-audio-channel-active', {
+ id: data.json.id, successRv: active
+ });
+ },
+ _recvGetWebManifest: Task.async(function* (data) {
+ debug(`Received GetWebManifest message: (${data.json.id})`);
+ let manifest = null;
+ let hasManifest = ManifestFinder.contentHasManifestLink(content);
+ if (hasManifest) {
+ try {
+ manifest = yield ManifestObtainer.contentObtainManifest(content);
+ } catch (e) {
+ sendAsyncMsg('got-web-manifest', {
+ id: data.json.id,
+ errorMsg: `Error fetching web manifest: ${e}.`,
+ });
+ return;
+ }
+ }
+ sendAsyncMsg('got-web-manifest', {
+ id: data.json.id,
+ successRv: manifest
+ });
+ }),
+
+ _initFinder: function() {
+ if (!this._finder) {
+ let {Finder} = Components.utils.import("resource://gre/modules/Finder.jsm", {});
+ this._finder = new Finder(docShell);
+ }
+ let listener = {
+ onMatchesCountResult: (data) => {
+ sendAsyncMsg("findchange", {
+ active: true,
+ searchString: this._finder.searchString,
+ searchLimit: this._finder.matchesCountLimit,
+ activeMatchOrdinal: data.current,
+ numberOfMatches: data.total
+ });
+ this._finder.removeResultListener(listener);
+ }
+ };
+ this._finder.addResultListener(listener);
+ },
+
+ _recvFindAll: function(data) {
+ this._initFinder();
+ let searchString = data.json.searchString;
+ this._finder.caseSensitive = data.json.caseSensitive;
+ this._finder.fastFind(searchString, false, false);
+ this._finder.requestMatchesCount(searchString, this._finder.matchesCountLimit, false);
+ },
+
+ _recvFindNext: function(data) {
+ if (!this._finder) {
+ debug("findNext() called before findAll()");
+ return;
+ }
+ this._initFinder();
+ this._finder.findAgain(data.json.backward, false, false);
+ this._finder.requestMatchesCount(this._finder.searchString, this._finder.matchesCountLimit, false);
+ },
+
+ _recvClearMatch: function(data) {
+ if (!this._finder) {
+ debug("clearMach() called before findAll()");
+ return;
+ }
+ this._finder.removeSelection();
+ sendAsyncMsg("findchange", {active: false});
+ },
+
+ _recvSetInputMethodActive: function(data) {
+ let msgData = { id: data.json.id };
+ if (!this._isContentWindowCreated) {
+ if (data.json.args.isActive) {
+ // To activate the input method, we should wait before the content
+ // window is ready.
+ this._pendingSetInputMethodActive.push(data);
+ return;
+ }
+ msgData.successRv = null;
+ sendAsyncMsg('got-set-input-method-active', msgData);
+ return;
+ }
+ // Unwrap to access webpage content.
+ let nav = XPCNativeWrapper.unwrap(content.document.defaultView.navigator);
+ if (nav.mozInputMethod) {
+ // Wrap to access the chrome-only attribute setActive.
+ new XPCNativeWrapper(nav.mozInputMethod).setActive(data.json.args.isActive);
+ msgData.successRv = null;
+ } else {
+ msgData.errorMsg = 'Cannot access mozInputMethod.';
+ }
+ sendAsyncMsg('got-set-input-method-active', msgData);
+ },
+
+ // The docShell keeps a weak reference to the progress listener, so we need
+ // to keep a strong ref to it ourselves.
+ _progressListener: {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+ Ci.nsISupportsWeakReference]),
+ _seenLoadStart: false,
+
+ onLocationChange: function(webProgress, request, location, flags) {
+ // We get progress events from subshells here, which is kind of weird.
+ if (webProgress != docShell) {
+ return;
+ }
+
+ // Ignore locationchange events which occur before the first loadstart.
+ // These are usually about:blank loads we don't care about.
+ if (!this._seenLoadStart) {
+ return;
+ }
+
+ // Remove password and wyciwyg from uri.
+ location = Cc["@mozilla.org/docshell/urifixup;1"]
+ .getService(Ci.nsIURIFixup).createExposableURI(location);
+
+ var webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
+
+ sendAsyncMsg('locationchange', { url: location.spec,
+ canGoBack: webNav.canGoBack,
+ canGoForward: webNav.canGoForward });
+ },
+
+ onStateChange: function(webProgress, request, stateFlags, status) {
+ if (webProgress != docShell) {
+ return;
+ }
+
+ if (stateFlags & Ci.nsIWebProgressListener.STATE_START) {
+ this._seenLoadStart = true;
+ sendAsyncMsg('loadstart');
+ }
+
+ if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
+ let bgColor = 'transparent';
+ try {
+ bgColor = content.getComputedStyle(content.document.body)
+ .getPropertyValue('background-color');
+ } catch (e) {}
+ sendAsyncMsg('loadend', {backgroundColor: bgColor});
+
+ switch (status) {
+ case Cr.NS_OK :
+ case Cr.NS_BINDING_ABORTED :
+ // Ignoring NS_BINDING_ABORTED, which is set when loading page is
+ // stopped.
+ case Cr.NS_ERROR_PARSED_DATA_CACHED:
+ return;
+
+ // TODO See nsDocShell::DisplayLoadError to see what extra
+ // information we should be annotating this first block of errors
+ // with. Bug 1107091.
+ case Cr.NS_ERROR_UNKNOWN_PROTOCOL :
+ sendAsyncMsg('error', { type: 'unknownProtocolFound' });
+ return;
+ case Cr.NS_ERROR_FILE_NOT_FOUND :
+ sendAsyncMsg('error', { type: 'fileNotFound' });
+ return;
+ case Cr.NS_ERROR_UNKNOWN_HOST :
+ sendAsyncMsg('error', { type: 'dnsNotFound' });
+ return;
+ case Cr.NS_ERROR_CONNECTION_REFUSED :
+ sendAsyncMsg('error', { type: 'connectionFailure' });
+ return;
+ case Cr.NS_ERROR_NET_INTERRUPT :
+ sendAsyncMsg('error', { type: 'netInterrupt' });
+ return;
+ case Cr.NS_ERROR_NET_TIMEOUT :
+ sendAsyncMsg('error', { type: 'netTimeout' });
+ return;
+ case Cr.NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION :
+ sendAsyncMsg('error', { type: 'cspBlocked' });
+ return;
+ case Cr.NS_ERROR_PHISHING_URI :
+ sendAsyncMsg('error', { type: 'deceptiveBlocked' });
+ return;
+ case Cr.NS_ERROR_MALWARE_URI :
+ sendAsyncMsg('error', { type: 'malwareBlocked' });
+ return;
+ case Cr.NS_ERROR_UNWANTED_URI :
+ sendAsyncMsg('error', { type: 'unwantedBlocked' });
+ return;
+ case Cr.NS_ERROR_FORBIDDEN_URI :
+ sendAsyncMsg('error', { type: 'forbiddenBlocked' });
+ return;
+
+ case Cr.NS_ERROR_OFFLINE :
+ sendAsyncMsg('error', { type: 'offline' });
+ return;
+ case Cr.NS_ERROR_MALFORMED_URI :
+ sendAsyncMsg('error', { type: 'malformedURI' });
+ return;
+ case Cr.NS_ERROR_REDIRECT_LOOP :
+ sendAsyncMsg('error', { type: 'redirectLoop' });
+ return;
+ case Cr.NS_ERROR_UNKNOWN_SOCKET_TYPE :
+ sendAsyncMsg('error', { type: 'unknownSocketType' });
+ return;
+ case Cr.NS_ERROR_NET_RESET :
+ sendAsyncMsg('error', { type: 'netReset' });
+ return;
+ case Cr.NS_ERROR_DOCUMENT_NOT_CACHED :
+ sendAsyncMsg('error', { type: 'notCached' });
+ return;
+ case Cr.NS_ERROR_DOCUMENT_IS_PRINTMODE :
+ sendAsyncMsg('error', { type: 'isprinting' });
+ return;
+ case Cr.NS_ERROR_PORT_ACCESS_NOT_ALLOWED :
+ sendAsyncMsg('error', { type: 'deniedPortAccess' });
+ return;
+ case Cr.NS_ERROR_UNKNOWN_PROXY_HOST :
+ sendAsyncMsg('error', { type: 'proxyResolveFailure' });
+ return;
+ case Cr.NS_ERROR_PROXY_CONNECTION_REFUSED :
+ sendAsyncMsg('error', { type: 'proxyConnectFailure' });
+ return;
+ case Cr.NS_ERROR_INVALID_CONTENT_ENCODING :
+ sendAsyncMsg('error', { type: 'contentEncodingFailure' });
+ return;
+ case Cr.NS_ERROR_REMOTE_XUL :
+ sendAsyncMsg('error', { type: 'remoteXUL' });
+ return;
+ case Cr.NS_ERROR_UNSAFE_CONTENT_TYPE :
+ sendAsyncMsg('error', { type: 'unsafeContentType' });
+ return;
+ case Cr.NS_ERROR_CORRUPTED_CONTENT :
+ sendAsyncMsg('error', { type: 'corruptedContentErrorv2' });
+ return;
+
+ default:
+ // getErrorClass() will throw if the error code passed in is not a NSS
+ // error code.
+ try {
+ let nssErrorsService = Cc['@mozilla.org/nss_errors_service;1']
+ .getService(Ci.nsINSSErrorsService);
+ if (nssErrorsService.getErrorClass(status)
+ == Ci.nsINSSErrorsService.ERROR_CLASS_BAD_CERT) {
+ // XXX Is there a point firing the event if the error page is not
+ // certerror? If yes, maybe we should add a property to the
+ // event to to indicate whether there is a custom page. That would
+ // let the embedder have more control over the desired behavior.
+ let errorPage = null;
+ try {
+ errorPage = Services.prefs.getCharPref(CERTIFICATE_ERROR_PAGE_PREF);
+ } catch (e) {}
+
+ if (errorPage == 'certerror') {
+ sendAsyncMsg('error', { type: 'certerror' });
+ return;
+ }
+ }
+ } catch (e) {}
+
+ sendAsyncMsg('error', { type: 'other' });
+ return;
+ }
+ }
+ },
+
+ onSecurityChange: function(webProgress, request, state) {
+ if (webProgress != docShell) {
+ return;
+ }
+
+ var securityStateDesc;
+ if (state & Ci.nsIWebProgressListener.STATE_IS_SECURE) {
+ securityStateDesc = 'secure';
+ }
+ else if (state & Ci.nsIWebProgressListener.STATE_IS_BROKEN) {
+ securityStateDesc = 'broken';
+ }
+ else if (state & Ci.nsIWebProgressListener.STATE_IS_INSECURE) {
+ securityStateDesc = 'insecure';
+ }
+ else {
+ debug("Unexpected securitychange state!");
+ securityStateDesc = '???';
+ }
+
+ var trackingStateDesc;
+ if (state & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT) {
+ trackingStateDesc = 'loaded_tracking_content';
+ }
+ else if (state & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT) {
+ trackingStateDesc = 'blocked_tracking_content';
+ }
+
+ var mixedStateDesc;
+ if (state & Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT) {
+ mixedStateDesc = 'blocked_mixed_active_content';
+ }
+ else if (state & Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT) {
+ // Note that STATE_LOADED_MIXED_ACTIVE_CONTENT implies STATE_IS_BROKEN
+ mixedStateDesc = 'loaded_mixed_active_content';
+ }
+
+ var isEV = !!(state & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL);
+ var isTrackingContent = !!(state &
+ (Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT |
+ Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT));
+ var isMixedContent = !!(state &
+ (Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT |
+ Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT));
+
+ sendAsyncMsg('securitychange', {
+ state: securityStateDesc,
+ trackingState: trackingStateDesc,
+ mixedState: mixedStateDesc,
+ extendedValidation: isEV,
+ trackingContent: isTrackingContent,
+ mixedContent: isMixedContent,
+ });
+ },
+
+ onStatusChange: function(webProgress, request, status, message) {},
+ onProgressChange: function(webProgress, request, curSelfProgress,
+ maxSelfProgress, curTotalProgress, maxTotalProgress) {},
+ },
+
+ // Expose the message manager for WebApps and others.
+ _messageManagerPublic: {
+ sendAsyncMessage: global.sendAsyncMessage.bind(global),
+ sendSyncMessage: global.sendSyncMessage.bind(global),
+ addMessageListener: global.addMessageListener.bind(global),
+ removeMessageListener: global.removeMessageListener.bind(global)
+ },
+
+ get messageManager() {
+ return this._messageManagerPublic;
+ }
+};
+
+var api = null;
+if ('DoPreloadPostfork' in this && typeof this.DoPreloadPostfork === 'function') {
+ // If we are preloaded, instantiate BrowserElementChild after a content
+ // process is forked.
+ this.DoPreloadPostfork(function() {
+ api = new BrowserElementChild();
+ });
+} else {
+ api = new BrowserElementChild();
+}
diff --git a/dom/browser-element/BrowserElementCopyPaste.js b/dom/browser-element/BrowserElementCopyPaste.js
new file mode 100644
index 000000000..7aa7c5148
--- /dev/null
+++ b/dom/browser-element/BrowserElementCopyPaste.js
@@ -0,0 +1,125 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* 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 debug(msg) {
+ // dump("BrowserElementCopyPaste - " + msg + "\n");
+}
+
+debug("loaded");
+
+var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
+
+var CopyPasteAssistent = {
+ COMMAND_MAP: {
+ 'cut': 'cmd_cut',
+ 'copy': 'cmd_copyAndCollapseToEnd',
+ 'paste': 'cmd_paste',
+ 'selectall': 'cmd_selectAll'
+ },
+
+ init: function() {
+ addEventListener("mozcaretstatechanged", this,
+ /* useCapture = */ true, /* wantsUntrusted = */ false);
+ addMessageListener("browser-element-api:call", this);
+ },
+
+ destroy: function() {
+ removeEventListener("mozcaretstatechanged", this,
+ /* useCapture = */ true, /* wantsUntrusted = */ false);
+ removeMessageListener("browser-element-api:call", this);
+ },
+
+ handleEvent: function(event) {
+ switch (event.type) {
+ case "mozcaretstatechanged":
+ this._caretStateChangedHandler(event);
+ break;
+ }
+ },
+
+ receiveMessage: function(message) {
+ switch (message.name) {
+ case "browser-element-api:call":
+ this._browserAPIHandler(message);
+ break;
+ }
+ },
+
+ _browserAPIHandler: function(e) {
+ switch (e.data.msg_name) {
+ case 'copypaste-do-command':
+ if (this._isCommandEnabled(e.data.command)) {
+ docShell.doCommand(this.COMMAND_MAP[e.data.command]);
+ }
+ break;
+ }
+ },
+
+ _isCommandEnabled: function(cmd) {
+ let command = this.COMMAND_MAP[cmd];
+ if (!command) {
+ return false;
+ }
+
+ return docShell.isCommandEnabled(command);
+ },
+
+ _caretStateChangedHandler: function(e) {
+ e.stopPropagation();
+
+ let boundingClientRect = e.boundingClientRect;
+ let canPaste = this._isCommandEnabled("paste");
+ let zoomFactor = content.innerWidth == 0 ? 1 : content.screen.width / content.innerWidth;
+
+ let detail = {
+ rect: {
+ width: boundingClientRect ? boundingClientRect.width : 0,
+ height: boundingClientRect ? boundingClientRect.height : 0,
+ top: boundingClientRect ? boundingClientRect.top : 0,
+ bottom: boundingClientRect ? boundingClientRect.bottom : 0,
+ left: boundingClientRect ? boundingClientRect.left : 0,
+ right: boundingClientRect ? boundingClientRect.right : 0,
+ },
+ commands: {
+ canSelectAll: this._isCommandEnabled("selectall"),
+ canCut: this._isCommandEnabled("cut"),
+ canCopy: this._isCommandEnabled("copy"),
+ canPaste: this._isCommandEnabled("paste"),
+ },
+ zoomFactor: zoomFactor,
+ reason: e.reason,
+ collapsed: e.collapsed,
+ caretVisible: e.caretVisible,
+ selectionVisible: e.selectionVisible,
+ selectionEditable: e.selectionEditable,
+ selectedTextContent: e.selectedTextContent
+ };
+
+ // Get correct geometry information if we have nested iframe.
+ let currentWindow = e.target.defaultView;
+ while (currentWindow.realFrameElement) {
+ let currentRect = currentWindow.realFrameElement.getBoundingClientRect();
+ detail.rect.top += currentRect.top;
+ detail.rect.bottom += currentRect.top;
+ detail.rect.left += currentRect.left;
+ detail.rect.right += currentRect.left;
+ currentWindow = currentWindow.realFrameElement.ownerDocument.defaultView;
+
+ let targetDocShell = currentWindow
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation);
+ if(targetDocShell.isMozBrowserOrApp) {
+ break;
+ }
+ }
+
+ sendAsyncMsg('caretstatechanged', detail);
+ },
+};
+
+CopyPasteAssistent.init();
diff --git a/dom/browser-element/BrowserElementParent.cpp b/dom/browser-element/BrowserElementParent.cpp
new file mode 100644
index 000000000..fda9348fd
--- /dev/null
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -0,0 +1,317 @@
+/* -*- 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 "TabParent.h"
+
+// TabParent.h transitively includes <windows.h>, which does
+// #define CreateEvent CreateEventW
+// That messes up our call to EventDispatcher::CreateEvent below.
+
+#ifdef CreateEvent
+#undef CreateEvent
+#endif
+
+#include "BrowserElementParent.h"
+#include "BrowserElementAudioChannel.h"
+#include "mozilla/EventDispatcher.h"
+#include "mozilla/dom/HTMLIFrameElement.h"
+#include "mozilla/dom/ToJSValue.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsVariant.h"
+#include "mozilla/dom/BrowserElementDictionariesBinding.h"
+#include "mozilla/dom/CustomEvent.h"
+#include "mozilla/layout/RenderFrameParent.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+using namespace mozilla::layers;
+using namespace mozilla::layout;
+
+namespace {
+
+using mozilla::BrowserElementParent;
+/**
+ * Create an <iframe mozbrowser> owned by the same document as
+ * aOpenerFrameElement.
+ */
+already_AddRefed<HTMLIFrameElement>
+CreateIframe(Element* aOpenerFrameElement, const nsAString& aName, bool aRemote)
+{
+ nsNodeInfoManager *nodeInfoManager =
+ aOpenerFrameElement->OwnerDoc()->NodeInfoManager();
+
+ RefPtr<NodeInfo> nodeInfo =
+ nodeInfoManager->GetNodeInfo(nsGkAtoms::iframe,
+ /* aPrefix = */ nullptr,
+ kNameSpaceID_XHTML,
+ nsIDOMNode::ELEMENT_NODE);
+
+ RefPtr<HTMLIFrameElement> popupFrameElement =
+ static_cast<HTMLIFrameElement*>(
+ NS_NewHTMLIFrameElement(nodeInfo.forget(), mozilla::dom::NOT_FROM_PARSER));
+
+ popupFrameElement->SetMozbrowser(true);
+
+ // Copy the opener frame's mozapp attribute to the popup frame.
+ if (aOpenerFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozapp)) {
+ nsAutoString mozapp;
+ aOpenerFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapp, mozapp);
+ popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::mozapp,
+ mozapp, /* aNotify = */ false);
+ }
+
+ // Copy the opener frame's parentApp attribute to the popup frame.
+ if (aOpenerFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::parentapp)) {
+ nsAutoString parentApp;
+ aOpenerFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::parentapp,
+ parentApp);
+ popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::parentapp,
+ parentApp, /* aNotify = */ false);
+ }
+
+ // Copy the window name onto the iframe.
+ popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::name,
+ aName, /* aNotify = */ false);
+
+ // Indicate whether the iframe is should be remote.
+ popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::Remote,
+ aRemote ? NS_LITERAL_STRING("true") :
+ NS_LITERAL_STRING("false"),
+ /* aNotify = */ false);
+
+ // Copy the opener frame's mozprivatebrowsing attribute to the popup frame.
+ nsAutoString mozprivatebrowsing;
+ if (aOpenerFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::mozprivatebrowsing,
+ mozprivatebrowsing)) {
+ popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::mozprivatebrowsing,
+ mozprivatebrowsing, /* aNotify = */ false);
+ }
+
+ return popupFrameElement.forget();
+}
+
+bool
+DispatchCustomDOMEvent(Element* aFrameElement, const nsAString& aEventName,
+ JSContext* cx, JS::Handle<JS::Value> aDetailValue,
+ nsEventStatus *aStatus)
+{
+ NS_ENSURE_TRUE(aFrameElement, false);
+ nsIPresShell *shell = aFrameElement->OwnerDoc()->GetShell();
+ RefPtr<nsPresContext> presContext;
+ if (shell) {
+ presContext = shell->GetPresContext();
+ }
+
+ RefPtr<CustomEvent> event =
+ NS_NewDOMCustomEvent(aFrameElement, presContext, nullptr);
+
+ ErrorResult res;
+ event->InitCustomEvent(cx,
+ aEventName,
+ /* aCanBubble = */ true,
+ /* aCancelable = */ true,
+ aDetailValue,
+ res);
+ if (res.Failed()) {
+ return false;
+ }
+ event->SetTrusted(true);
+ // Dispatch the event.
+ // We don't initialize aStatus here, as our callers have already done so.
+ nsresult rv =
+ EventDispatcher::DispatchDOMEvent(aFrameElement, nullptr, event,
+ presContext, aStatus);
+ return NS_SUCCEEDED(rv);
+}
+
+} // namespace
+
+namespace mozilla {
+
+/**
+ * Dispatch a mozbrowseropenwindow event to the given opener frame element.
+ * The "popup iframe" (event.detail.frameElement) will be |aPopupFrameElement|.
+ *
+ * Returns true iff there were no unexpected failures and the window.open call
+ * was accepted by the embedder.
+ */
+/*static*/
+BrowserElementParent::OpenWindowResult
+BrowserElementParent::DispatchOpenWindowEvent(Element* aOpenerFrameElement,
+ Element* aPopupFrameElement,
+ const nsAString& aURL,
+ const nsAString& aName,
+ const nsAString& aFeatures)
+{
+ // Dispatch a CustomEvent at aOpenerFrameElement with a detail object
+ // (OpenWindowEventDetail) containing aPopupFrameElement, aURL, aName, and
+ // aFeatures.
+
+ // Create the event's detail object.
+ OpenWindowEventDetail detail;
+ if (aURL.IsEmpty()) {
+ // URL should never be empty. Assign about:blank as default.
+ detail.mUrl = NS_LITERAL_STRING("about:blank");
+ } else {
+ detail.mUrl = aURL;
+ }
+ detail.mName = aName;
+ detail.mFeatures = aFeatures;
+ detail.mFrameElement = aPopupFrameElement;
+
+ AutoJSContext cx;
+ JS::Rooted<JS::Value> val(cx);
+
+ nsIGlobalObject* sgo = aPopupFrameElement->OwnerDoc()->GetScopeObject();
+ if (!sgo) {
+ return BrowserElementParent::OPEN_WINDOW_IGNORED;
+ }
+
+ JS::Rooted<JSObject*> global(cx, sgo->GetGlobalJSObject());
+ JSAutoCompartment ac(cx, global);
+ if (!ToJSValue(cx, detail, &val)) {
+ MOZ_CRASH("Failed to convert dictionary to JS::Value due to OOM.");
+ return BrowserElementParent::OPEN_WINDOW_IGNORED;
+ }
+
+ nsEventStatus status = nsEventStatus_eIgnore;
+ bool dispatchSucceeded =
+ DispatchCustomDOMEvent(aOpenerFrameElement,
+ NS_LITERAL_STRING("mozbrowseropenwindow"),
+ cx,
+ val, &status);
+
+ if (dispatchSucceeded) {
+ if (aPopupFrameElement->IsInUncomposedDoc()) {
+ return BrowserElementParent::OPEN_WINDOW_ADDED;
+ } else if (status == nsEventStatus_eConsumeNoDefault) {
+ // If the frame was not added to a document, report to callers whether
+ // preventDefault was called on or not
+ return BrowserElementParent::OPEN_WINDOW_CANCELLED;
+ }
+ }
+
+ return BrowserElementParent::OPEN_WINDOW_IGNORED;
+}
+
+/*static*/
+BrowserElementParent::OpenWindowResult
+BrowserElementParent::OpenWindowOOP(TabParent* aOpenerTabParent,
+ TabParent* aPopupTabParent,
+ PRenderFrameParent* aRenderFrame,
+ const nsAString& aURL,
+ const nsAString& aName,
+ const nsAString& aFeatures,
+ TextureFactoryIdentifier* aTextureFactoryIdentifier,
+ uint64_t* aLayersId)
+{
+ // Create an iframe owned by the same document which owns openerFrameElement.
+ nsCOMPtr<Element> openerFrameElement = aOpenerTabParent->GetOwnerElement();
+ NS_ENSURE_TRUE(openerFrameElement,
+ BrowserElementParent::OPEN_WINDOW_IGNORED);
+ RefPtr<HTMLIFrameElement> popupFrameElement =
+ CreateIframe(openerFrameElement, aName, /* aRemote = */ true);
+
+ // Normally an <iframe> element will try to create a frameLoader when the
+ // page touches iframe.contentWindow or sets iframe.src.
+ //
+ // But in our case, we want to delay the creation of the frameLoader until
+ // we've verified that the popup has gone through successfully. If the popup
+ // is "blocked" by the embedder, we don't want to load the popup's url.
+ //
+ // Therefore we call DisallowCreateFrameLoader() on the element and call
+ // AllowCreateFrameLoader() only after we've verified that the popup was
+ // allowed.
+ popupFrameElement->DisallowCreateFrameLoader();
+
+ OpenWindowResult opened =
+ DispatchOpenWindowEvent(openerFrameElement, popupFrameElement,
+ aURL, aName, aFeatures);
+
+ if (opened != BrowserElementParent::OPEN_WINDOW_ADDED) {
+ return opened;
+ }
+
+ // The popup was not blocked, so hook up the frame element and the popup tab
+ // parent, and return success.
+ aPopupTabParent->SetOwnerElement(popupFrameElement);
+ popupFrameElement->AllowCreateFrameLoader();
+ popupFrameElement->CreateRemoteFrameLoader(aPopupTabParent);
+
+ RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
+ if (!aPopupTabParent->SetRenderFrame(rfp) ||
+ !aPopupTabParent->GetRenderFrameInfo(aTextureFactoryIdentifier, aLayersId)) {
+ return BrowserElementParent::OPEN_WINDOW_IGNORED;
+ }
+
+ return opened;
+}
+
+/* static */
+BrowserElementParent::OpenWindowResult
+BrowserElementParent::OpenWindowInProcess(nsPIDOMWindowOuter* aOpenerWindow,
+ nsIURI* aURI,
+ const nsAString& aName,
+ const nsACString& aFeatures,
+ bool aForceNoOpener,
+ mozIDOMWindowProxy** aReturnWindow)
+{
+ *aReturnWindow = nullptr;
+
+ // If we call window.open from an <iframe> inside an <iframe mozbrowser>,
+ // it's as though the top-level document inside the <iframe mozbrowser>
+ // called window.open. (Indeed, in the OOP case, the inner <iframe> lives
+ // out-of-process, so we couldn't touch it if we tried.)
+ //
+ // GetScriptableTop gets us the <iframe mozbrowser>'s window; we'll use its
+ // frame element, rather than aOpenerWindow's frame element, as our "opener
+ // frame element" below.
+ nsCOMPtr<nsPIDOMWindowOuter> win = aOpenerWindow->GetScriptableTop();
+
+ nsCOMPtr<Element> openerFrameElement = win->GetFrameElementInternal();
+ NS_ENSURE_TRUE(openerFrameElement, BrowserElementParent::OPEN_WINDOW_IGNORED);
+
+
+ RefPtr<HTMLIFrameElement> popupFrameElement =
+ CreateIframe(openerFrameElement, aName, /* aRemote = */ false);
+ NS_ENSURE_TRUE(popupFrameElement, BrowserElementParent::OPEN_WINDOW_IGNORED);
+
+ nsAutoCString spec;
+ if (aURI) {
+ aURI->GetSpec(spec);
+ }
+
+ if (!aForceNoOpener) {
+ ErrorResult res;
+ popupFrameElement->PresetOpenerWindow(aOpenerWindow, res);
+ MOZ_ASSERT(!res.Failed());
+ }
+
+ OpenWindowResult opened =
+ DispatchOpenWindowEvent(openerFrameElement, popupFrameElement,
+ NS_ConvertUTF8toUTF16(spec),
+ aName,
+ NS_ConvertUTF8toUTF16(aFeatures));
+
+ if (opened != BrowserElementParent::OPEN_WINDOW_ADDED) {
+ return opened;
+ }
+
+ // Return popupFrameElement's window.
+ RefPtr<nsFrameLoader> frameLoader = popupFrameElement->GetFrameLoader();
+ NS_ENSURE_TRUE(frameLoader, BrowserElementParent::OPEN_WINDOW_IGNORED);
+
+ nsCOMPtr<nsIDocShell> docshell;
+ frameLoader->GetDocShell(getter_AddRefs(docshell));
+ NS_ENSURE_TRUE(docshell, BrowserElementParent::OPEN_WINDOW_IGNORED);
+
+ nsCOMPtr<nsPIDOMWindowOuter> window = docshell->GetWindow();
+ window.forget(aReturnWindow);
+
+ return !!*aReturnWindow ? opened : BrowserElementParent::OPEN_WINDOW_CANCELLED;
+}
+
+} // namespace mozilla
diff --git a/dom/browser-element/BrowserElementParent.h b/dom/browser-element/BrowserElementParent.h
new file mode 100644
index 000000000..428884f97
--- /dev/null
+++ b/dom/browser-element/BrowserElementParent.h
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_BrowserElementHelpers_h
+#define mozilla_BrowserElementHelpers_h
+
+#include "nsAString.h"
+#include "mozilla/gfx/Point.h"
+#include "mozilla/gfx/Rect.h"
+#include "Units.h"
+#include "mozilla/dom/Element.h"
+
+class nsIDOMWindow;
+class nsIURI;
+
+namespace mozilla {
+
+namespace dom {
+class TabParent;
+} // namespace dom
+
+namespace layers {
+struct TextureFactoryIdentifier;
+} // namespace layers
+
+namespace layout {
+class PRenderFrameParent;
+} // namespace layout
+
+/**
+ * BrowserElementParent implements a portion of the parent-process side of
+ * <iframe mozbrowser>.
+ *
+ * Most of the parent-process side of <iframe mozbrowser> is implemented in
+ * BrowserElementParent.js. This file implements the few parts of this
+ * functionality which must be written in C++.
+ *
+ * We don't communicate with the JS code that lives in BrowserElementParent.js;
+ * the JS and C++ parts are completely separate.
+ */
+class BrowserElementParent
+{
+public:
+
+ /**
+ * Possible results from a window.open call.
+ * ADDED - The frame was added to a document (i.e. handled by the embedder).
+ * IGNORED - The frame was not added to a document and the embedder didn't
+ * call preventDefault() to prevent the platform from handling the call.
+ * CANCELLED - The frame was not added to a document, but the embedder still
+ * called preventDefault() to prevent the platform from handling the call.
+ */
+
+ enum OpenWindowResult {
+ OPEN_WINDOW_ADDED,
+ OPEN_WINDOW_IGNORED,
+ OPEN_WINDOW_CANCELLED
+ };
+
+ /**
+ * Handle a window.open call from an out-of-process <iframe mozbrowser>.
+ *
+ * window.open inside <iframe mozbrowser> doesn't actually open a new
+ * top-level window. Instead, the "embedder" (the document which contains
+ * the <iframe mozbrowser> whose content called window.open) gets the
+ * opportunity to place a new <iframe mozbrowser> in the DOM somewhere. This
+ * new "popup" iframe acts as the opened window.
+ *
+ * This method proceeds in three steps.
+ *
+ * 1) We fire a mozbrowseropenwindow CustomEvent on the opener
+ * iframe element. This event's detail is an instance of
+ * OpenWindowEventDetail.
+ *
+ * 2) The embedder (the document which contains the opener iframe) can accept
+ * the window.open request by inserting event.detail.frameElement (an iframe
+ * element) into the DOM somewhere.
+ *
+ * 3) If the embedder accepted the window.open request, we return true and
+ * set aPopupTabParent's frame element to event.detail.frameElement.
+ * Otherwise, we return false.
+ *
+ * @param aURL the URL the new window should load. The empty string is
+ * allowed.
+ * @param aOpenerTabParent the TabParent whose TabChild called window.open.
+ * @param aPopupTabParent the TabParent inside which the opened window will
+ * live.
+ * @return an OpenWindowresult that describes whether the embedder added the
+ * frame to a document and whether it called preventDefault to prevent
+ * the platform from handling the open request.
+ */
+ static OpenWindowResult
+ OpenWindowOOP(dom::TabParent* aOpenerTabParent,
+ dom::TabParent* aPopupTabParent,
+ layout::PRenderFrameParent* aRenderFrame,
+ const nsAString& aURL,
+ const nsAString& aName,
+ const nsAString& aFeatures,
+ layers::TextureFactoryIdentifier* aTextureFactoryIdentifier,
+ uint64_t* aLayersId);
+
+ /**
+ * Handle a window.open call from an in-process <iframe mozbrowser>.
+ *
+ * (These parameter types are silly, but they match what our caller has in
+ * hand. Feel free to add an override, if they are inconvenient to you.)
+ *
+ * @param aURI the URI the new window should load. May be null.
+ * @return an OpenWindowResult that describes whether the browser added the
+ * frame to a document or whether they called preventDefault to prevent
+ * the platform from handling the open request
+ */
+ static OpenWindowResult
+ OpenWindowInProcess(nsPIDOMWindowOuter* aOpenerWindow,
+ nsIURI* aURI,
+ const nsAString& aName,
+ const nsACString& aFeatures,
+ bool aForceNoOpener,
+ mozIDOMWindowProxy** aReturnWindow);
+
+private:
+ static OpenWindowResult
+ DispatchOpenWindowEvent(dom::Element* aOpenerFrameElement,
+ dom::Element* aPopupFrameElement,
+ const nsAString& aURL,
+ const nsAString& aName,
+ const nsAString& aFeatures);
+};
+
+} // namespace mozilla
+
+#endif
diff --git a/dom/browser-element/BrowserElementParent.js b/dom/browser-element/BrowserElementParent.js
new file mode 100644
index 000000000..67d05f0ab
--- /dev/null
+++ b/dom/browser-element/BrowserElementParent.js
@@ -0,0 +1,1202 @@
+/* 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";
+
+var Cu = Components.utils;
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+var Cr = Components.results;
+
+/* BrowserElementParent injects script to listen for certain events in the
+ * child. We then listen to messages from the child script and take
+ * appropriate action here in the parent.
+ */
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
+
+function debug(msg) {
+ //dump("BrowserElementParent - " + msg + "\n");
+}
+
+function getIntPref(prefName, def) {
+ try {
+ return Services.prefs.getIntPref(prefName);
+ }
+ catch(err) {
+ return def;
+ }
+}
+
+function handleWindowEvent(e) {
+ if (this._browserElementParents) {
+ let beps = ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(this._browserElementParents);
+ beps.forEach(bep => bep._handleOwnerEvent(e));
+ }
+}
+
+function defineNoReturnMethod(fn) {
+ return function method() {
+ if (!this._domRequestReady) {
+ // Remote browser haven't been created, we just queue the API call.
+ let args = Array.slice(arguments);
+ args.unshift(this);
+ this._pendingAPICalls.push(method.bind.apply(fn, args));
+ return;
+ }
+ if (this._isAlive()) {
+ fn.apply(this, arguments);
+ }
+ };
+}
+
+function defineDOMRequestMethod(msgName) {
+ return function() {
+ return this._sendDOMRequest(msgName);
+ };
+}
+
+function BrowserElementParentProxyCallHandler() {
+}
+
+BrowserElementParentProxyCallHandler.prototype = {
+ _frameElement: null,
+ _mm: null,
+
+ MOZBROWSER_EVENT_NAMES: Object.freeze([
+ "loadstart", "loadend", "close", "error", "firstpaint",
+ "documentfirstpaint", "audioplaybackchange",
+ "contextmenu", "securitychange", "locationchange",
+ "iconchange", "scrollareachanged", "titlechange",
+ "opensearch", "manifestchange", "metachange",
+ "resize", "scrollviewchange",
+ "caretstatechanged", "activitydone", "scroll", "opentab"]),
+
+ init: function(frameElement, mm) {
+ this._frameElement = frameElement;
+ this._mm = mm;
+ this.innerWindowIDSet = new Set();
+
+ mm.addMessageListener("browser-element-api:proxy-call", this);
+ },
+
+ // Message manager callback receives messages from BrowserElementProxy.js
+ receiveMessage: function(mmMsg) {
+ let data = mmMsg.json;
+
+ let mm;
+ try {
+ mm = mmMsg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
+ .frameLoader.messageManager;
+ } catch(e) {
+ mm = mmMsg.target;
+ }
+ if (!mm.assertPermission("browser:embedded-system-app")) {
+ dump("BrowserElementParent.js: Method call " + data.methodName +
+ " from a content process with no 'browser:embedded-system-app'" +
+ " privileges.\n");
+ return;
+ }
+
+ switch (data.methodName) {
+ case '_proxyInstanceInit':
+ if (!this.innerWindowIDSet.size) {
+ this._attachEventListeners();
+ }
+ this.innerWindowIDSet.add(data.innerWindowID);
+
+ break;
+
+ case '_proxyInstanceUninit':
+ this.innerWindowIDSet.delete(data.innerWindowID);
+ if (!this.innerWindowIDSet.size) {
+ this._detachEventListeners();
+ }
+
+ break;
+
+ // void methods
+ case 'setVisible':
+ case 'setActive':
+ case 'sendMouseEvent':
+ case 'sendTouchEvent':
+ case 'goBack':
+ case 'goForward':
+ case 'reload':
+ case 'stop':
+ case 'zoom':
+ case 'findAll':
+ case 'findNext':
+ case 'clearMatch':
+ case 'mute':
+ case 'unmute':
+ case 'setVolume':
+ this._frameElement[data.methodName]
+ .apply(this._frameElement, data.args);
+
+ break;
+
+ // DOMRequest methods
+ case 'getVisible':
+ case 'download':
+ case 'purgeHistory':
+ case 'getCanGoBack':
+ case 'getCanGoForward':
+ case 'getContentDimensions':
+ case 'setInputMethodActive':
+ case 'executeScript':
+ case 'getMuted':
+ case 'getVolume':
+ let req = this._frameElement[data.methodName]
+ .apply(this._frameElement, data.args);
+ req.onsuccess = () => {
+ this._sendToProxy({
+ domRequestId: data.domRequestId,
+ innerWindowID: data.innerWindowID,
+ result: req.result
+ });
+ };
+ req.onerror = () => {
+ this._sendToProxy({
+ domRequestId: data.domRequestId,
+ innerWindowID: data.innerWindowID,
+ err: req.error
+ });
+ };
+
+ break;
+
+ // Not implemented
+ case 'getActive': // Sync ???
+ case 'addNextPaintListener': // Takes a callback
+ case 'removeNextPaintListener': // Takes a callback
+ case 'getScreenshot': // Need to pass a blob back
+ dump("BrowserElementParentProxyCallHandler Error:" +
+ "Attempt to call unimplemented method " + data.methodName + ".\n");
+ break;
+
+ default:
+ dump("BrowserElementParentProxyCallHandler Error:" +
+ "Attempt to call non-exist method " + data.methodName + ".\n");
+ break;
+ }
+ },
+
+ // Receving events from the frame element and forward it.
+ handleEvent: function(evt) {
+ // Ignore the events from nested mozbrowser iframes
+ if (evt.target !== this._frameElement) {
+ return;
+ }
+
+ let detailString;
+ try {
+ detailString = JSON.stringify(evt.detail);
+ } catch (e) {
+ dump("BrowserElementParentProxyCallHandler Error:" +
+ "Event detail of " + evt.type + " can't be stingified.\n");
+ return;
+ }
+
+ this.innerWindowIDSet.forEach((innerWindowID) => {
+ this._sendToProxy({
+ eventName: evt.type,
+ innerWindowID: innerWindowID,
+ eventDetailString: detailString
+ });
+ });
+ },
+
+ _sendToProxy: function(data) {
+ this._mm.sendAsyncMessage("browser-element-api:proxy", data);
+ },
+
+ _attachEventListeners: function() {
+ this.MOZBROWSER_EVENT_NAMES.forEach(function(eventName) {
+ this._frameElement.addEventListener(
+ "mozbrowser" + eventName, this, true);
+ }, this);
+ },
+
+ _detachEventListeners: function() {
+ this.MOZBROWSER_EVENT_NAMES.forEach(function(eventName) {
+ this._frameElement.removeEventListener(
+ "mozbrowser" + eventName, this, true);
+ }, this);
+ }
+};
+
+function BrowserElementParent() {
+ debug("Creating new BrowserElementParent object");
+ this._domRequestCounter = 0;
+ this._domRequestReady = false;
+ this._pendingAPICalls = [];
+ this._pendingDOMRequests = {};
+ this._pendingSetInputMethodActive = [];
+ this._nextPaintListeners = [];
+ this._pendingDOMFullscreen = false;
+
+ Services.obs.addObserver(this, 'oop-frameloader-crashed', /* ownsWeak = */ true);
+ Services.obs.addObserver(this, 'ask-children-to-execute-copypaste-command', /* ownsWeak = */ true);
+ Services.obs.addObserver(this, 'back-docommand', /* ownsWeak = */ true);
+
+ this.proxyCallHandler = new BrowserElementParentProxyCallHandler();
+}
+
+BrowserElementParent.prototype = {
+
+ classDescription: "BrowserElementAPI implementation",
+ classID: Components.ID("{9f171ac4-0939-4ef8-b360-3408aedc3060}"),
+ contractID: "@mozilla.org/dom/browser-element-api;1",
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserElementAPI,
+ Ci.nsIObserver,
+ Ci.nsISupportsWeakReference]),
+
+ setFrameLoader: function(frameLoader) {
+ debug("Setting frameLoader");
+ this._frameLoader = frameLoader;
+ this._frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
+ if (!this._frameElement) {
+ debug("No frame element?");
+ return;
+ }
+ // Listen to visibilitychange on the iframe's owner window, and forward
+ // changes down to the child. We want to do this while registering as few
+ // visibilitychange listeners on _window as possible, because such a listener
+ // may live longer than this BrowserElementParent object.
+ //
+ // To accomplish this, we register just one listener on the window, and have
+ // it reference a WeakMap whose keys are all the BrowserElementParent objects
+ // on the window. Then when the listener fires, we iterate over the
+ // WeakMap's keys (which we can do, because we're chrome) to notify the
+ // BrowserElementParents.
+ if (!this._window._browserElementParents) {
+ this._window._browserElementParents = new WeakMap();
+ let handler = handleWindowEvent.bind(this._window);
+ let windowEvents = ['visibilitychange', 'fullscreenchange'];
+ let els = Cc["@mozilla.org/eventlistenerservice;1"]
+ .getService(Ci.nsIEventListenerService);
+ for (let event of windowEvents) {
+ els.addSystemEventListener(this._window, event, handler,
+ /* useCapture = */ true);
+ }
+ }
+
+ this._window._browserElementParents.set(this, null);
+
+ // Insert ourself into the prompt service.
+ BrowserElementPromptService.mapFrameToBrowserElementParent(this._frameElement, this);
+ this._setupMessageListener();
+
+ this.proxyCallHandler.init(
+ this._frameElement, this._frameLoader.messageManager);
+ },
+
+ destroyFrameScripts() {
+ debug("Destroying frame scripts");
+ this._mm.sendAsyncMessage("browser-element-api:destroy");
+ },
+
+ _runPendingAPICall: function() {
+ if (!this._pendingAPICalls) {
+ return;
+ }
+ for (let i = 0; i < this._pendingAPICalls.length; i++) {
+ try {
+ this._pendingAPICalls[i]();
+ } catch (e) {
+ // throw the expections from pending functions.
+ debug('Exception when running pending API call: ' + e);
+ }
+ }
+ delete this._pendingAPICalls;
+ },
+
+ _setupMessageListener: function() {
+ this._mm = this._frameLoader.messageManager;
+ this._mm.addMessageListener('browser-element-api:call', this);
+ this._mm.loadFrameScript("chrome://global/content/extensions.js", true);
+ },
+
+ receiveMessage: function(aMsg) {
+ if (!this._isAlive()) {
+ return;
+ }
+
+ // Messages we receive are handed to functions which take a (data) argument,
+ // where |data| is the message manager's data object.
+ // We use a single message and dispatch to various function based
+ // on data.msg_name
+ let mmCalls = {
+ "hello": this._recvHello,
+ "loadstart": this._fireProfiledEventFromMsg,
+ "loadend": this._fireProfiledEventFromMsg,
+ "close": this._fireEventFromMsg,
+ "error": this._fireEventFromMsg,
+ "firstpaint": this._fireProfiledEventFromMsg,
+ "documentfirstpaint": this._fireProfiledEventFromMsg,
+ "nextpaint": this._recvNextPaint,
+ "got-purge-history": this._gotDOMRequestResult,
+ "got-screenshot": this._gotDOMRequestResult,
+ "got-contentdimensions": this._gotDOMRequestResult,
+ "got-can-go-back": this._gotDOMRequestResult,
+ "got-can-go-forward": this._gotDOMRequestResult,
+ "got-muted": this._gotDOMRequestResult,
+ "got-volume": this._gotDOMRequestResult,
+ "requested-dom-fullscreen": this._requestedDOMFullscreen,
+ "fullscreen-origin-change": this._fullscreenOriginChange,
+ "exit-dom-fullscreen": this._exitDomFullscreen,
+ "got-visible": this._gotDOMRequestResult,
+ "visibilitychange": this._childVisibilityChange,
+ "got-set-input-method-active": this._gotDOMRequestResult,
+ "scrollviewchange": this._handleScrollViewChange,
+ "caretstatechanged": this._handleCaretStateChanged,
+ "findchange": this._handleFindChange,
+ "execute-script-done": this._gotDOMRequestResult,
+ "got-audio-channel-volume": this._gotDOMRequestResult,
+ "got-set-audio-channel-volume": this._gotDOMRequestResult,
+ "got-audio-channel-muted": this._gotDOMRequestResult,
+ "got-set-audio-channel-muted": this._gotDOMRequestResult,
+ "got-is-audio-channel-active": this._gotDOMRequestResult,
+ "got-web-manifest": this._gotDOMRequestResult,
+ };
+
+ let mmSecuritySensitiveCalls = {
+ "audioplaybackchange": this._fireEventFromMsg,
+ "showmodalprompt": this._handleShowModalPrompt,
+ "contextmenu": this._fireCtxMenuEvent,
+ "securitychange": this._fireEventFromMsg,
+ "locationchange": this._fireEventFromMsg,
+ "iconchange": this._fireEventFromMsg,
+ "scrollareachanged": this._fireEventFromMsg,
+ "titlechange": this._fireProfiledEventFromMsg,
+ "opensearch": this._fireEventFromMsg,
+ "manifestchange": this._fireEventFromMsg,
+ "metachange": this._fireEventFromMsg,
+ "resize": this._fireEventFromMsg,
+ "activitydone": this._fireEventFromMsg,
+ "scroll": this._fireEventFromMsg,
+ "opentab": this._fireEventFromMsg
+ };
+
+ if (aMsg.data.msg_name in mmCalls) {
+ return mmCalls[aMsg.data.msg_name].apply(this, arguments);
+ } else if (aMsg.data.msg_name in mmSecuritySensitiveCalls) {
+ return mmSecuritySensitiveCalls[aMsg.data.msg_name].apply(this, arguments);
+ }
+ },
+
+ _removeMessageListener: function() {
+ this._mm.removeMessageListener('browser-element-api:call', this);
+ },
+
+ /**
+ * You shouldn't touch this._frameElement or this._window if _isAlive is
+ * false. (You'll likely get an exception if you do.)
+ */
+ _isAlive: function() {
+ return !Cu.isDeadWrapper(this._frameElement) &&
+ !Cu.isDeadWrapper(this._frameElement.ownerDocument) &&
+ !Cu.isDeadWrapper(this._frameElement.ownerDocument.defaultView);
+ },
+
+ get _window() {
+ return this._frameElement.ownerDocument.defaultView;
+ },
+
+ get _windowUtils() {
+ return this._window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ },
+
+ promptAuth: function(authDetail, callback) {
+ let evt;
+ let self = this;
+ let callbackCalled = false;
+ let cancelCallback = function() {
+ if (!callbackCalled) {
+ callbackCalled = true;
+ callback(false, null, null);
+ }
+ };
+
+ // We don't handle password-only prompts.
+ if (authDetail.isOnlyPassword) {
+ cancelCallback();
+ return;
+ }
+
+ /* username and password */
+ let detail = {
+ host: authDetail.host,
+ path: authDetail.path,
+ realm: authDetail.realm,
+ isProxy: authDetail.isProxy
+ };
+
+ evt = this._createEvent('usernameandpasswordrequired', detail,
+ /* cancelable */ true);
+ Cu.exportFunction(function(username, password) {
+ if (callbackCalled)
+ return;
+ callbackCalled = true;
+ callback(true, username, password);
+ }, evt.detail, { defineAs: 'authenticate' });
+
+ Cu.exportFunction(cancelCallback, evt.detail, { defineAs: 'cancel' });
+
+ this._frameElement.dispatchEvent(evt);
+
+ if (!evt.defaultPrevented) {
+ cancelCallback();
+ }
+ },
+
+ _sendAsyncMsg: function(msg, data) {
+ try {
+ if (!data) {
+ data = { };
+ }
+
+ data.msg_name = msg;
+ this._mm.sendAsyncMessage('browser-element-api:call', data);
+ } catch (e) {
+ return false;
+ }
+ return true;
+ },
+
+ _recvHello: function() {
+ debug("recvHello");
+
+ // Inform our child if our owner element's document is invisible. Note
+ // that we must do so here, rather than in the BrowserElementParent
+ // constructor, because the BrowserElementChild may not be initialized when
+ // we run our constructor.
+ if (this._window.document.hidden) {
+ this._ownerVisibilityChange();
+ }
+
+ if (!this._domRequestReady) {
+ // At least, one message listener such as for hello is registered.
+ // So we can use sendAsyncMessage now.
+ this._domRequestReady = true;
+ this._runPendingAPICall();
+ }
+ },
+
+ _fireCtxMenuEvent: function(data) {
+ let detail = data.json;
+ let evtName = detail.msg_name;
+
+ debug('fireCtxMenuEventFromMsg: ' + evtName + ' ' + detail);
+ let evt = this._createEvent(evtName, detail, /* cancellable */ true);
+
+ if (detail.contextmenu) {
+ var self = this;
+ Cu.exportFunction(function(id) {
+ self._sendAsyncMsg('fire-ctx-callback', {menuitem: id});
+ }, evt.detail, { defineAs: 'contextMenuItemSelected' });
+ }
+
+ // The embedder may have default actions on context menu events, so
+ // we fire a context menu event even if the child didn't define a
+ // custom context menu
+ return !this._frameElement.dispatchEvent(evt);
+ },
+
+ /**
+ * add profiler marker for each event fired.
+ */
+ _fireProfiledEventFromMsg: function(data) {
+ if (Services.profiler !== undefined) {
+ Services.profiler.AddMarker(data.json.msg_name);
+ }
+ this._fireEventFromMsg(data);
+ },
+
+ /**
+ * Fire either a vanilla or a custom event, depending on the contents of
+ * |data|.
+ */
+ _fireEventFromMsg: function(data) {
+ let detail = data.json;
+ let name = detail.msg_name;
+
+ // For events that send a "_payload_" property, we just want to transmit
+ // this in the event.
+ if ("_payload_" in detail) {
+ detail = detail._payload_;
+ }
+
+ debug('fireEventFromMsg: ' + name + ', ' + JSON.stringify(detail));
+ let evt = this._createEvent(name, detail,
+ /* cancelable = */ false);
+ this._frameElement.dispatchEvent(evt);
+ },
+
+ _handleShowModalPrompt: function(data) {
+ // Fire a showmodalprmopt event on the iframe. When this method is called,
+ // the child is spinning in a nested event loop waiting for an
+ // unblock-modal-prompt message.
+ //
+ // If the embedder calls preventDefault() on the showmodalprompt event,
+ // we'll block the child until event.detail.unblock() is called.
+ //
+ // Otherwise, if preventDefault() is not called, we'll send the
+ // unblock-modal-prompt message to the child as soon as the event is done
+ // dispatching.
+
+ let detail = data.json;
+ debug('handleShowPrompt ' + JSON.stringify(detail));
+
+ // Strip off the windowID property from the object we send along in the
+ // event.
+ let windowID = detail.windowID;
+ delete detail.windowID;
+ debug("Event will have detail: " + JSON.stringify(detail));
+ let evt = this._createEvent('showmodalprompt', detail,
+ /* cancelable = */ true);
+
+ let self = this;
+ let unblockMsgSent = false;
+ function sendUnblockMsg() {
+ if (unblockMsgSent) {
+ return;
+ }
+ unblockMsgSent = true;
+
+ // We don't need to sanitize evt.detail.returnValue (e.g. converting the
+ // return value of confirm() to a boolean); Gecko does that for us.
+
+ let data = { windowID: windowID,
+ returnValue: evt.detail.returnValue };
+ self._sendAsyncMsg('unblock-modal-prompt', data);
+ }
+
+ Cu.exportFunction(sendUnblockMsg, evt.detail, { defineAs: 'unblock' });
+
+ this._frameElement.dispatchEvent(evt);
+
+ if (!evt.defaultPrevented) {
+ // Unblock the inner frame immediately. Otherwise we'll unblock upon
+ // evt.detail.unblock().
+ sendUnblockMsg();
+ }
+ },
+
+ // Called when state of accessible caret in child has changed.
+ // The fields of data is as following:
+ // - rect: Contains bounding rectangle of selection, Include width, height,
+ // top, bottom, left and right.
+ // - commands: Describe what commands can be executed in child. Include canSelectAll,
+ // canCut, canCopy and canPaste. For example: if we want to check if cut
+ // command is available, using following code, if (data.commands.canCut) {}.
+ // - zoomFactor: Current zoom factor in child frame.
+ // - reason: The reason causes the state changed. Include "visibilitychange",
+ // "updateposition", "longpressonemptycontent", "taponcaret", "presscaret",
+ // "releasecaret".
+ // - collapsed: Indicate current selection is collapsed or not.
+ // - caretVisible: Indicate the caret visiibility.
+ // - selectionVisible: Indicate current selection is visible or not.
+ // - selectionEditable: Indicate current selection is editable or not.
+ // - selectedTextContent: Contains current selected text content, which is
+ // equivalent to the string returned by Selection.toString().
+ _handleCaretStateChanged: function(data) {
+ let evt = this._createEvent('caretstatechanged', data.json,
+ /* cancelable = */ false);
+
+ let self = this;
+ function sendDoCommandMsg(cmd) {
+ let data = { command: cmd };
+ self._sendAsyncMsg('copypaste-do-command', data);
+ }
+ Cu.exportFunction(sendDoCommandMsg, evt.detail, { defineAs: 'sendDoCommandMsg' });
+
+ this._frameElement.dispatchEvent(evt);
+ },
+
+ _handleScrollViewChange: function(data) {
+ let evt = this._createEvent("scrollviewchange", data.json,
+ /* cancelable = */ false);
+ this._frameElement.dispatchEvent(evt);
+ },
+
+ _handleFindChange: function(data) {
+ let evt = this._createEvent("findchange", data.json,
+ /* cancelable = */ false);
+ this._frameElement.dispatchEvent(evt);
+ },
+
+ _createEvent: function(evtName, detail, cancelable) {
+ // This will have to change if we ever want to send a CustomEvent with null
+ // detail. For now, it's OK.
+ if (detail !== undefined && detail !== null) {
+ detail = Cu.cloneInto(detail, this._window);
+ return new this._window.CustomEvent('mozbrowser' + evtName,
+ { bubbles: true,
+ cancelable: cancelable,
+ detail: detail });
+ }
+
+ return new this._window.Event('mozbrowser' + evtName,
+ { bubbles: true,
+ cancelable: cancelable });
+ },
+
+ /**
+ * Kick off a DOMRequest in the child process.
+ *
+ * We'll fire an event called |msgName| on the child process, passing along
+ * an object with two fields:
+ *
+ * - id: the ID of this request.
+ * - arg: arguments to pass to the child along with this request.
+ *
+ * We expect the child to pass the ID back to us upon completion of the
+ * request. See _gotDOMRequestResult.
+ */
+ _sendDOMRequest: function(msgName, args) {
+ let id = 'req_' + this._domRequestCounter++;
+ let req = Services.DOMRequest.createRequest(this._window);
+ let self = this;
+ let send = function() {
+ if (!self._isAlive()) {
+ return;
+ }
+ if (self._sendAsyncMsg(msgName, {id: id, args: args})) {
+ self._pendingDOMRequests[id] = req;
+ } else {
+ Services.DOMRequest.fireErrorAsync(req, "fail");
+ }
+ };
+ if (this._domRequestReady) {
+ send();
+ } else {
+ // Child haven't been loaded.
+ this._pendingAPICalls.push(send);
+ }
+ return req;
+ },
+
+ /**
+ * Called when the child process finishes handling a DOMRequest. data.json
+ * must have the fields [id, successRv], if the DOMRequest was successful, or
+ * [id, errorMsg], if the request was not successful.
+ *
+ * The fields have the following meanings:
+ *
+ * - id: the ID of the DOM request (see _sendDOMRequest)
+ * - successRv: the request's return value, if the request succeeded
+ * - errorMsg: the message to pass to DOMRequest.fireError(), if the request
+ * failed.
+ *
+ */
+ _gotDOMRequestResult: function(data) {
+ let req = this._pendingDOMRequests[data.json.id];
+ delete this._pendingDOMRequests[data.json.id];
+
+ if ('successRv' in data.json) {
+ debug("Successful gotDOMRequestResult.");
+ let clientObj = Cu.cloneInto(data.json.successRv, this._window);
+ Services.DOMRequest.fireSuccess(req, clientObj);
+ }
+ else {
+ debug("Got error in gotDOMRequestResult.");
+ Services.DOMRequest.fireErrorAsync(req,
+ Cu.cloneInto(data.json.errorMsg, this._window));
+ }
+ },
+
+ setVisible: defineNoReturnMethod(function(visible) {
+ this._sendAsyncMsg('set-visible', {visible: visible});
+ this._frameLoader.visible = visible;
+ }),
+
+ getVisible: defineDOMRequestMethod('get-visible'),
+
+ setActive: defineNoReturnMethod(function(active) {
+ this._frameLoader.visible = active;
+ }),
+
+ getActive: function() {
+ if (!this._isAlive()) {
+ throw Components.Exception("Dead content process",
+ Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
+ }
+
+ return this._frameLoader.visible;
+ },
+
+ getChildProcessOffset: function() {
+ let offset = { x: 0, y: 0 };
+ let tabParent = this._frameLoader.tabParent;
+ if (tabParent) {
+ let offsetX = {};
+ let offsetY = {};
+ tabParent.getChildProcessOffset(offsetX, offsetY);
+ offset.x = offsetX.value;
+ offset.y = offsetY.value;
+ }
+ return offset;
+ },
+
+ sendMouseEvent: defineNoReturnMethod(function(type, x, y, button, clickCount, modifiers) {
+ let offset = this.getChildProcessOffset();
+ x += offset.x;
+ y += offset.y;
+
+ this._sendAsyncMsg("send-mouse-event", {
+ "type": type,
+ "x": x,
+ "y": y,
+ "button": button,
+ "clickCount": clickCount,
+ "modifiers": modifiers
+ });
+ }),
+
+ sendTouchEvent: defineNoReturnMethod(function(type, identifiers, touchesX, touchesY,
+ radiisX, radiisY, rotationAngles, forces,
+ count, modifiers) {
+
+ let offset = this.getChildProcessOffset();
+ for (var i = 0; i < touchesX.length; i++) {
+ touchesX[i] += offset.x;
+ }
+ for (var i = 0; i < touchesY.length; i++) {
+ touchesY[i] += offset.y;
+ }
+ this._sendAsyncMsg("send-touch-event", {
+ "type": type,
+ "identifiers": identifiers,
+ "touchesX": touchesX,
+ "touchesY": touchesY,
+ "radiisX": radiisX,
+ "radiisY": radiisY,
+ "rotationAngles": rotationAngles,
+ "forces": forces,
+ "count": count,
+ "modifiers": modifiers
+ });
+ }),
+
+ getCanGoBack: defineDOMRequestMethod('get-can-go-back'),
+ getCanGoForward: defineDOMRequestMethod('get-can-go-forward'),
+ getContentDimensions: defineDOMRequestMethod('get-contentdimensions'),
+
+ findAll: defineNoReturnMethod(function(searchString, caseSensitivity) {
+ return this._sendAsyncMsg('find-all', {
+ searchString,
+ caseSensitive: caseSensitivity == Ci.nsIBrowserElementAPI.FIND_CASE_SENSITIVE
+ });
+ }),
+
+ findNext: defineNoReturnMethod(function(direction) {
+ return this._sendAsyncMsg('find-next', {
+ backward: direction == Ci.nsIBrowserElementAPI.FIND_BACKWARD
+ });
+ }),
+
+ clearMatch: defineNoReturnMethod(function() {
+ return this._sendAsyncMsg('clear-match');
+ }),
+
+ mute: defineNoReturnMethod(function() {
+ this._sendAsyncMsg('mute');
+ }),
+
+ unmute: defineNoReturnMethod(function() {
+ this._sendAsyncMsg('unmute');
+ }),
+
+ getMuted: defineDOMRequestMethod('get-muted'),
+
+ getVolume: defineDOMRequestMethod('get-volume'),
+
+ setVolume: defineNoReturnMethod(function(volume) {
+ this._sendAsyncMsg('set-volume', {volume});
+ }),
+
+ goBack: defineNoReturnMethod(function() {
+ this._sendAsyncMsg('go-back');
+ }),
+
+ goForward: defineNoReturnMethod(function() {
+ this._sendAsyncMsg('go-forward');
+ }),
+
+ reload: defineNoReturnMethod(function(hardReload) {
+ this._sendAsyncMsg('reload', {hardReload: hardReload});
+ }),
+
+ stop: defineNoReturnMethod(function() {
+ this._sendAsyncMsg('stop');
+ }),
+
+ executeScript: function(script, options) {
+ if (!this._isAlive()) {
+ throw Components.Exception("Dead content process",
+ Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
+ }
+
+ // Enforcing options.url or options.origin
+ if (!options.url && !options.origin) {
+ throw Components.Exception("Invalid argument", Cr.NS_ERROR_INVALID_ARG);
+ }
+ return this._sendDOMRequest('execute-script', {script, options});
+ },
+
+ /*
+ * The valid range of zoom scale is defined in preference "zoom.maxPercent" and "zoom.minPercent".
+ */
+ zoom: defineNoReturnMethod(function(zoom) {
+ zoom *= 100;
+ zoom = Math.min(getIntPref("zoom.maxPercent", 300), zoom);
+ zoom = Math.max(getIntPref("zoom.minPercent", 50), zoom);
+ this._sendAsyncMsg('zoom', {zoom: zoom / 100.0});
+ }),
+
+ purgeHistory: defineDOMRequestMethod('purge-history'),
+
+
+ download: function(_url, _options) {
+ if (!this._isAlive()) {
+ return null;
+ }
+
+ let uri = Services.io.newURI(_url, null, null);
+ let url = uri.QueryInterface(Ci.nsIURL);
+
+ debug('original _options = ' + uneval(_options));
+
+ // Ensure we have _options, we always use it to send the filename.
+ _options = _options || {};
+ if (!_options.filename) {
+ _options.filename = url.fileName;
+ }
+
+ debug('final _options = ' + uneval(_options));
+
+ // Ensure we have a filename.
+ if (!_options.filename) {
+ throw Components.Exception("Invalid argument", Cr.NS_ERROR_INVALID_ARG);
+ }
+
+ let interfaceRequestor =
+ this._frameLoader.loadContext.QueryInterface(Ci.nsIInterfaceRequestor);
+ let req = Services.DOMRequest.createRequest(this._window);
+
+ function DownloadListener() {
+ debug('DownloadListener Constructor');
+ }
+ DownloadListener.prototype = {
+ extListener: null,
+ onStartRequest: function(aRequest, aContext) {
+ debug('DownloadListener - onStartRequest');
+ let extHelperAppSvc =
+ Cc['@mozilla.org/uriloader/external-helper-app-service;1'].
+ getService(Ci.nsIExternalHelperAppService);
+ let channel = aRequest.QueryInterface(Ci.nsIChannel);
+
+ // First, we'll ensure the filename doesn't have any leading
+ // periods. We have to do it here to avoid ending up with a filename
+ // that's only an extension with no extension (e.g. Sending in
+ // '.jpeg' without stripping the '.' would result in a filename of
+ // 'jpeg' where we want 'jpeg.jpeg'.
+ _options.filename = _options.filename.replace(/^\.+/, "");
+
+ let ext = null;
+ let mimeSvc = extHelperAppSvc.QueryInterface(Ci.nsIMIMEService);
+ try {
+ ext = '.' + mimeSvc.getPrimaryExtension(channel.contentType, '');
+ } catch (e) { ext = null; }
+
+ // Check if we need to add an extension to the filename.
+ if (ext && !_options.filename.endsWith(ext)) {
+ _options.filename += ext;
+ }
+ // Set the filename to use when saving to disk.
+ channel.contentDispositionFilename = _options.filename;
+
+ this.extListener =
+ extHelperAppSvc.doContent(
+ channel.contentType,
+ aRequest,
+ interfaceRequestor,
+ true);
+ this.extListener.onStartRequest(aRequest, aContext);
+ },
+ onStopRequest: function(aRequest, aContext, aStatusCode) {
+ debug('DownloadListener - onStopRequest (aStatusCode = ' +
+ aStatusCode + ')');
+ if (aStatusCode == Cr.NS_OK) {
+ // Everything looks great.
+ debug('DownloadListener - Download Successful.');
+ Services.DOMRequest.fireSuccess(req, aStatusCode);
+ }
+ else {
+ // In case of failure, we'll simply return the failure status code.
+ debug('DownloadListener - Download Failed!');
+ Services.DOMRequest.fireError(req, aStatusCode);
+ }
+
+ if (this.extListener) {
+ this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
+ }
+ },
+ onDataAvailable: function(aRequest, aContext, aInputStream,
+ aOffset, aCount) {
+ this.extListener.onDataAvailable(aRequest, aContext, aInputStream,
+ aOffset, aCount);
+ },
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener,
+ Ci.nsIRequestObserver])
+ };
+
+ let referrer = Services.io.newURI(_options.referrer, null, null);
+ let principal =
+ Services.scriptSecurityManager.createCodebasePrincipal(
+ referrer, this._frameLoader.loadContext.originAttributes);
+
+ let channel = NetUtil.newChannel({
+ uri: url,
+ loadingPrincipal: principal,
+ securityFlags: SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS,
+ contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER
+ });
+
+ // XXX We would set private browsing information prior to calling this.
+ channel.notificationCallbacks = interfaceRequestor;
+
+ // Since we're downloading our own local copy we'll want to bypass the
+ // cache and local cache if the channel let's us specify this.
+ let flags = Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS |
+ Ci.nsIChannel.LOAD_BYPASS_CACHE;
+ if (channel instanceof Ci.nsICachingChannel) {
+ debug('This is a caching channel. Forcing bypass.');
+ flags |= Ci.nsICachingChannel.LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
+ }
+
+ channel.loadFlags |= flags;
+
+ if (channel instanceof Ci.nsIHttpChannel) {
+ debug('Setting HTTP referrer = ' + (referrer && referrer.spec));
+ channel.referrer = referrer;
+ if (channel instanceof Ci.nsIHttpChannelInternal) {
+ channel.forceAllowThirdPartyCookie = true;
+ }
+ }
+
+ // Set-up complete, let's get things started.
+ channel.asyncOpen2(new DownloadListener());
+
+ return req;
+ },
+
+ getScreenshot: function(_width, _height, _mimeType) {
+ if (!this._isAlive()) {
+ throw Components.Exception("Dead content process",
+ Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
+ }
+
+ let width = parseInt(_width);
+ let height = parseInt(_height);
+ let mimeType = (typeof _mimeType === 'string') ?
+ _mimeType.trim().toLowerCase() : 'image/jpeg';
+ if (isNaN(width) || isNaN(height) || width < 0 || height < 0) {
+ throw Components.Exception("Invalid argument",
+ Cr.NS_ERROR_INVALID_ARG);
+ }
+
+ return this._sendDOMRequest('get-screenshot',
+ {width: width, height: height,
+ mimeType: mimeType});
+ },
+
+ _recvNextPaint: function(data) {
+ let listeners = this._nextPaintListeners;
+ this._nextPaintListeners = [];
+ for (let listener of listeners) {
+ try {
+ listener.recvNextPaint();
+ } catch (e) {
+ // If a listener throws we'll continue.
+ }
+ }
+ },
+
+ addNextPaintListener: function(listener) {
+ if (!this._isAlive()) {
+ throw Components.Exception("Dead content process",
+ Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
+ }
+
+ let self = this;
+ let run = function() {
+ if (self._nextPaintListeners.push(listener) == 1)
+ self._sendAsyncMsg('activate-next-paint-listener');
+ };
+ if (!this._domRequestReady) {
+ this._pendingAPICalls.push(run);
+ } else {
+ run();
+ }
+ },
+
+ removeNextPaintListener: function(listener) {
+ if (!this._isAlive()) {
+ throw Components.Exception("Dead content process",
+ Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
+ }
+
+ let self = this;
+ let run = function() {
+ for (let i = self._nextPaintListeners.length - 1; i >= 0; i--) {
+ if (self._nextPaintListeners[i] == listener) {
+ self._nextPaintListeners.splice(i, 1);
+ break;
+ }
+ }
+
+ if (self._nextPaintListeners.length == 0)
+ self._sendAsyncMsg('deactivate-next-paint-listener');
+ };
+ if (!this._domRequestReady) {
+ this._pendingAPICalls.push(run);
+ } else {
+ run();
+ }
+ },
+
+ setInputMethodActive: function(isActive) {
+ if (!this._isAlive()) {
+ throw Components.Exception("Dead content process",
+ Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
+ }
+
+ if (typeof isActive !== 'boolean') {
+ throw Components.Exception("Invalid argument",
+ Cr.NS_ERROR_INVALID_ARG);
+ }
+
+ return this._sendDOMRequest('set-input-method-active',
+ {isActive: isActive});
+ },
+
+ getAudioChannelVolume: function(aAudioChannel) {
+ return this._sendDOMRequest('get-audio-channel-volume',
+ {audioChannel: aAudioChannel});
+ },
+
+ setAudioChannelVolume: function(aAudioChannel, aVolume) {
+ return this._sendDOMRequest('set-audio-channel-volume',
+ {audioChannel: aAudioChannel,
+ volume: aVolume});
+ },
+
+ getAudioChannelMuted: function(aAudioChannel) {
+ return this._sendDOMRequest('get-audio-channel-muted',
+ {audioChannel: aAudioChannel});
+ },
+
+ setAudioChannelMuted: function(aAudioChannel, aMuted) {
+ return this._sendDOMRequest('set-audio-channel-muted',
+ {audioChannel: aAudioChannel,
+ muted: aMuted});
+ },
+
+ isAudioChannelActive: function(aAudioChannel) {
+ return this._sendDOMRequest('get-is-audio-channel-active',
+ {audioChannel: aAudioChannel});
+ },
+
+ getWebManifest: defineDOMRequestMethod('get-web-manifest'),
+ /**
+ * Called when the visibility of the window which owns this iframe changes.
+ */
+ _ownerVisibilityChange: function() {
+ this._sendAsyncMsg('owner-visibility-change',
+ {visible: !this._window.document.hidden});
+ },
+
+ /*
+ * Called when the child notices that its visibility has changed.
+ *
+ * This is sometimes redundant; for example, the child's visibility may
+ * change in response to a setVisible request that we made here! But it's
+ * not always redundant; for example, the child's visibility may change in
+ * response to its parent docshell being hidden.
+ */
+ _childVisibilityChange: function(data) {
+ debug("_childVisibilityChange(" + data.json.visible + ")");
+ this._frameLoader.visible = data.json.visible;
+
+ this._fireEventFromMsg(data);
+ },
+
+ _requestedDOMFullscreen: function() {
+ this._pendingDOMFullscreen = true;
+ this._windowUtils.remoteFrameFullscreenChanged(this._frameElement);
+ },
+
+ _fullscreenOriginChange: function(data) {
+ Services.obs.notifyObservers(
+ this._frameElement, "fullscreen-origin-change", data.json.originNoSuffix);
+ },
+
+ _exitDomFullscreen: function(data) {
+ this._windowUtils.remoteFrameFullscreenReverted();
+ },
+
+ _handleOwnerEvent: function(evt) {
+ switch (evt.type) {
+ case 'visibilitychange':
+ this._ownerVisibilityChange();
+ break;
+ case 'fullscreenchange':
+ if (!this._window.document.fullscreenElement) {
+ this._sendAsyncMsg('exit-fullscreen');
+ } else if (this._pendingDOMFullscreen) {
+ this._pendingDOMFullscreen = false;
+ this._sendAsyncMsg('entered-fullscreen');
+ }
+ break;
+ }
+ },
+
+ _fireFatalError: function() {
+ let evt = this._createEvent('error', {type: 'fatal'},
+ /* cancelable = */ false);
+ this._frameElement.dispatchEvent(evt);
+ },
+
+ observe: function(subject, topic, data) {
+ switch(topic) {
+ case 'oop-frameloader-crashed':
+ if (this._isAlive() && subject == this._frameLoader) {
+ this._fireFatalError();
+ }
+ break;
+ case 'ask-children-to-execute-copypaste-command':
+ if (this._isAlive() && this._frameElement == subject.wrappedJSObject) {
+ this._sendAsyncMsg('copypaste-do-command', { command: data });
+ }
+ break;
+ case 'back-docommand':
+ if (this._isAlive() && this._frameLoader.visible) {
+ this.goBack();
+ }
+ break;
+ default:
+ debug('Unknown topic: ' + topic);
+ break;
+ };
+ },
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementParent]);
diff --git a/dom/browser-element/BrowserElementParent.manifest b/dom/browser-element/BrowserElementParent.manifest
new file mode 100644
index 000000000..547ff7f3d
--- /dev/null
+++ b/dom/browser-element/BrowserElementParent.manifest
@@ -0,0 +1,2 @@
+component {9f171ac4-0939-4ef8-b360-3408aedc3060} BrowserElementParent.js
+contract @mozilla.org/dom/browser-element-api;1 {9f171ac4-0939-4ef8-b360-3408aedc3060}
diff --git a/dom/browser-element/BrowserElementPromptService.jsm b/dom/browser-element/BrowserElementPromptService.jsm
new file mode 100644
index 000000000..1442304db
--- /dev/null
+++ b/dom/browser-element/BrowserElementPromptService.jsm
@@ -0,0 +1,685 @@
+/* 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/. */
+/* vim: set ft=javascript : */
+
+"use strict";
+
+var Cu = Components.utils;
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+var Cr = Components.results;
+var Cm = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+
+this.EXPORTED_SYMBOLS = ["BrowserElementPromptService"];
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
+const BROWSER_FRAMES_ENABLED_PREF = "dom.mozBrowserFramesEnabled";
+
+function debug(msg) {
+ //dump("BrowserElementPromptService - " + msg + "\n");
+}
+
+function BrowserElementPrompt(win, browserElementChild) {
+ this._win = win;
+ this._browserElementChild = browserElementChild;
+}
+
+BrowserElementPrompt.prototype = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt]),
+
+ alert: function(title, text) {
+ this._browserElementChild.showModalPrompt(
+ this._win, {promptType: "alert", title: title, message: text, returnValue: undefined});
+ },
+
+ alertCheck: function(title, text, checkMsg, checkState) {
+ // Treat this like a normal alert() call, ignoring the checkState. The
+ // front-end can do its own suppression of the alert() if it wants.
+ this.alert(title, text);
+ },
+
+ confirm: function(title, text) {
+ return this._browserElementChild.showModalPrompt(
+ this._win, {promptType: "confirm", title: title, message: text, returnValue: undefined});
+ },
+
+ confirmCheck: function(title, text, checkMsg, checkState) {
+ return this.confirm(title, text);
+ },
+
+ // Each button is described by an object with the following schema
+ // {
+ // string messageType, // 'builtin' or 'custom'
+ // string message, // 'ok', 'cancel', 'yes', 'no', 'save', 'dontsave',
+ // // 'revert' or a string from caller if messageType was 'custom'.
+ // }
+ //
+ // Expected result from embedder:
+ // {
+ // int button, // Index of the button that user pressed.
+ // boolean checked, // True if the check box is checked.
+ // }
+ confirmEx: function(title, text, buttonFlags, button0Title, button1Title,
+ button2Title, checkMsg, checkState) {
+ let buttonProperties = this._buildConfirmExButtonProperties(buttonFlags,
+ button0Title,
+ button1Title,
+ button2Title);
+ let defaultReturnValue = { selectedButton: buttonProperties.defaultButton };
+ if (checkMsg) {
+ defaultReturnValue.checked = checkState.value;
+ }
+ let ret = this._browserElementChild.showModalPrompt(
+ this._win,
+ {
+ promptType: "custom-prompt",
+ title: title,
+ message: text,
+ defaultButton: buttonProperties.defaultButton,
+ buttons: buttonProperties.buttons,
+ showCheckbox: !!checkMsg,
+ checkboxMessage: checkMsg,
+ checkboxCheckedByDefault: !!checkState.value,
+ returnValue: defaultReturnValue
+ }
+ );
+ if (checkMsg) {
+ checkState.value = ret.checked;
+ }
+ return buttonProperties.indexToButtonNumberMap[ret.selectedButton];
+ },
+
+ prompt: function(title, text, value, checkMsg, checkState) {
+ let rv = this._browserElementChild.showModalPrompt(
+ this._win,
+ { promptType: "prompt",
+ title: title,
+ message: text,
+ initialValue: value.value,
+ returnValue: null });
+
+ value.value = rv;
+
+ // nsIPrompt::Prompt returns true if the user pressed "OK" at the prompt,
+ // and false if the user pressed "Cancel".
+ //
+ // BrowserElementChild returns null for "Cancel" and returns the string the
+ // user entered otherwise.
+ return rv !== null;
+ },
+
+ promptUsernameAndPassword: function(title, text, username, password, checkMsg, checkState) {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ promptPassword: function(title, text, password, checkMsg, checkState) {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ select: function(title, text, aCount, aSelectList, aOutSelection) {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ _buildConfirmExButtonProperties: function(buttonFlags, button0Title,
+ button1Title, button2Title) {
+ let r = {
+ defaultButton: -1,
+ buttons: [],
+ // This map is for translating array index to the button number that
+ // is recognized by Gecko. This shouldn't be exposed to embedder.
+ indexToButtonNumberMap: []
+ };
+
+ let defaultButton = 0; // Default to Button 0.
+ if (buttonFlags & Ci.nsIPrompt.BUTTON_POS_1_DEFAULT) {
+ defaultButton = 1;
+ } else if (buttonFlags & Ci.nsIPrompt.BUTTON_POS_2_DEFAULT) {
+ defaultButton = 2;
+ }
+
+ // Properties of each button.
+ let buttonPositions = [
+ Ci.nsIPrompt.BUTTON_POS_0,
+ Ci.nsIPrompt.BUTTON_POS_1,
+ Ci.nsIPrompt.BUTTON_POS_2
+ ];
+
+ function buildButton(buttonTitle, buttonNumber) {
+ let ret = {};
+ let buttonPosition = buttonPositions[buttonNumber];
+ let mask = 0xff * buttonPosition; // 8 bit mask
+ let titleType = (buttonFlags & mask) / buttonPosition;
+
+ ret.messageType = 'builtin';
+ switch(titleType) {
+ case Ci.nsIPrompt.BUTTON_TITLE_OK:
+ ret.message = 'ok';
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_CANCEL:
+ ret.message = 'cancel';
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_YES:
+ ret.message = 'yes';
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_NO:
+ ret.message = 'no';
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_SAVE:
+ ret.message = 'save';
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_DONT_SAVE:
+ ret.message = 'dontsave';
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_REVERT:
+ ret.message = 'revert';
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_IS_STRING:
+ ret.message = buttonTitle;
+ ret.messageType = 'custom';
+ break;
+ default:
+ // This button is not shown.
+ return;
+ }
+
+ // If this is the default button, set r.defaultButton to
+ // the index of this button in the array. This value is going to be
+ // exposed to the embedder.
+ if (defaultButton === buttonNumber) {
+ r.defaultButton = r.buttons.length;
+ }
+ r.buttons.push(ret);
+ r.indexToButtonNumberMap.push(buttonNumber);
+ }
+
+ buildButton(button0Title, 0);
+ buildButton(button1Title, 1);
+ buildButton(button2Title, 2);
+
+ // If defaultButton is still -1 here, it means the default button won't
+ // be shown.
+ if (r.defaultButton === -1) {
+ throw new Components.Exception("Default button won't be shown",
+ Cr.NS_ERROR_FAILURE);
+ }
+
+ return r;
+ },
+};
+
+
+function BrowserElementAuthPrompt() {
+}
+
+BrowserElementAuthPrompt.prototype = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIAuthPrompt2]),
+
+ promptAuth: function promptAuth(channel, level, authInfo) {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ asyncPromptAuth: function asyncPromptAuth(channel, callback, context, level, authInfo) {
+ debug("asyncPromptAuth");
+
+ // The cases that we don't support now.
+ if ((authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) &&
+ (authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD)) {
+ throw Cr.NS_ERROR_FAILURE;
+ }
+
+ let frame = this._getFrameFromChannel(channel);
+ if (!frame) {
+ debug("Cannot get frame, asyncPromptAuth fail");
+ throw Cr.NS_ERROR_FAILURE;
+ }
+
+ let browserElementParent =
+ BrowserElementPromptService.getBrowserElementParentForFrame(frame);
+
+ if (!browserElementParent) {
+ debug("Failed to load browser element parent.");
+ throw Cr.NS_ERROR_FAILURE;
+ }
+
+ let consumer = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+ callback: callback,
+ context: context,
+ cancel: function() {
+ this.callback.onAuthCancelled(this.context, false);
+ this.callback = null;
+ this.context = null;
+ }
+ };
+
+ let [hostname, httpRealm] = this._getAuthTarget(channel, authInfo);
+ let hashKey = level + "|" + hostname + "|" + httpRealm;
+ let asyncPrompt = this._asyncPrompts[hashKey];
+ if (asyncPrompt) {
+ asyncPrompt.consumers.push(consumer);
+ return consumer;
+ }
+
+ asyncPrompt = {
+ consumers: [consumer],
+ channel: channel,
+ authInfo: authInfo,
+ level: level,
+ inProgress: false,
+ browserElementParent: browserElementParent
+ };
+
+ this._asyncPrompts[hashKey] = asyncPrompt;
+ this._doAsyncPrompt();
+ return consumer;
+ },
+
+ // Utilities for nsIAuthPrompt2 ----------------
+
+ _asyncPrompts: {},
+ _asyncPromptInProgress: new WeakMap(),
+ _doAsyncPrompt: function() {
+ // Find the key of a prompt whose browser element parent does not have
+ // async prompt in progress.
+ let hashKey = null;
+ for (let key in this._asyncPrompts) {
+ let prompt = this._asyncPrompts[key];
+ if (!this._asyncPromptInProgress.get(prompt.browserElementParent)) {
+ hashKey = key;
+ break;
+ }
+ }
+
+ // Didn't find an available prompt, so just return.
+ if (!hashKey)
+ return;
+
+ let prompt = this._asyncPrompts[hashKey];
+ let [hostname, httpRealm] = this._getAuthTarget(prompt.channel,
+ prompt.authInfo);
+
+ this._asyncPromptInProgress.set(prompt.browserElementParent, true);
+ prompt.inProgress = true;
+
+ let self = this;
+ let callback = function(ok, username, password) {
+ debug("Async auth callback is called, ok = " +
+ ok + ", username = " + username);
+
+ // Here we got the username and password provided by embedder, or
+ // ok = false if the prompt was cancelled by embedder.
+ delete self._asyncPrompts[hashKey];
+ prompt.inProgress = false;
+ self._asyncPromptInProgress.delete(prompt.browserElementParent);
+
+ // Fill authentication information with username and password provided
+ // by user.
+ let flags = prompt.authInfo.flags;
+ if (username) {
+ if (flags & Ci.nsIAuthInformation.NEED_DOMAIN) {
+ // Domain is separated from username by a backslash
+ let idx = username.indexOf("\\");
+ if (idx == -1) {
+ prompt.authInfo.username = username;
+ } else {
+ prompt.authInfo.domain = username.substring(0, idx);
+ prompt.authInfo.username = username.substring(idx + 1);
+ }
+ } else {
+ prompt.authInfo.username = username;
+ }
+ }
+
+ if (password) {
+ prompt.authInfo.password = password;
+ }
+
+ for (let consumer of prompt.consumers) {
+ if (!consumer.callback) {
+ // Not having a callback means that consumer didn't provide it
+ // or canceled the notification.
+ continue;
+ }
+
+ try {
+ if (ok) {
+ debug("Ok, calling onAuthAvailable to finish auth");
+ consumer.callback.onAuthAvailable(consumer.context, prompt.authInfo);
+ } else {
+ debug("Cancelled, calling onAuthCancelled to finish auth.");
+ consumer.callback.onAuthCancelled(consumer.context, true);
+ }
+ } catch (e) { /* Throw away exceptions caused by callback */ }
+ }
+
+ // Process the next prompt, if one is pending.
+ self._doAsyncPrompt();
+ };
+
+ let runnable = {
+ run: function() {
+ // Call promptAuth of browserElementParent, to show the prompt.
+ prompt.browserElementParent.promptAuth(
+ self._createAuthDetail(prompt.channel, prompt.authInfo),
+ callback);
+ }
+ }
+
+ Services.tm.currentThread.dispatch(runnable, Ci.nsIThread.DISPATCH_NORMAL);
+ },
+
+ _getFrameFromChannel: function(channel) {
+ let loadContext = channel.notificationCallbacks.getInterface(Ci.nsILoadContext);
+ return loadContext.topFrameElement;
+ },
+
+ _createAuthDetail: function(channel, authInfo) {
+ let [hostname, httpRealm] = this._getAuthTarget(channel, authInfo);
+ return {
+ host: hostname,
+ path: channel.URI.path,
+ realm: httpRealm,
+ username: authInfo.username,
+ isProxy: !!(authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY),
+ isOnlyPassword: !!(authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD)
+ };
+ },
+
+ // The code is taken from nsLoginManagerPrompter.js, with slight
+ // modification for parameter name consistency here.
+ _getAuthTarget : function (channel, authInfo) {
+ let hostname, realm;
+
+ // If our proxy is demanding authentication, don't use the
+ // channel's actual destination.
+ if (authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) {
+ if (!(channel instanceof Ci.nsIProxiedChannel))
+ throw new Error("proxy auth needs nsIProxiedChannel");
+
+ let info = channel.proxyInfo;
+ if (!info)
+ throw new Error("proxy auth needs nsIProxyInfo");
+
+ // Proxies don't have a scheme, but we'll use "moz-proxy://"
+ // so that it's more obvious what the login is for.
+ var idnService = Cc["@mozilla.org/network/idn-service;1"].
+ getService(Ci.nsIIDNService);
+ hostname = "moz-proxy://" +
+ idnService.convertUTF8toACE(info.host) +
+ ":" + info.port;
+ realm = authInfo.realm;
+ if (!realm)
+ realm = hostname;
+
+ return [hostname, realm];
+ }
+
+ hostname = this._getFormattedHostname(channel.URI);
+
+ // If a HTTP WWW-Authenticate header specified a realm, that value
+ // will be available here. If it wasn't set or wasn't HTTP, we'll use
+ // the formatted hostname instead.
+ realm = authInfo.realm;
+ if (!realm)
+ realm = hostname;
+
+ return [hostname, realm];
+ },
+
+ /**
+ * Strip out things like userPass and path for display.
+ */
+ _getFormattedHostname : function(uri) {
+ return uri.scheme + "://" + uri.hostPort;
+ },
+};
+
+
+function AuthPromptWrapper(oldImpl, browserElementImpl) {
+ this._oldImpl = oldImpl;
+ this._browserElementImpl = browserElementImpl;
+}
+
+AuthPromptWrapper.prototype = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIAuthPrompt2]),
+ promptAuth: function(channel, level, authInfo) {
+ if (this._canGetParentElement(channel)) {
+ return this._browserElementImpl.promptAuth(channel, level, authInfo);
+ } else {
+ return this._oldImpl.promptAuth(channel, level, authInfo);
+ }
+ },
+
+ asyncPromptAuth: function(channel, callback, context, level, authInfo) {
+ if (this._canGetParentElement(channel)) {
+ return this._browserElementImpl.asyncPromptAuth(channel, callback, context, level, authInfo);
+ } else {
+ return this._oldImpl.asyncPromptAuth(channel, callback, context, level, authInfo);
+ }
+ },
+
+ _canGetParentElement: function(channel) {
+ try {
+ let context = channel.notificationCallbacks.getInterface(Ci.nsILoadContext);
+ let frame = context.topFrameElement;
+ if (!frame) {
+ // This function returns a boolean value
+ return !!context.nestedFrameId;
+ }
+
+ if (!BrowserElementPromptService.getBrowserElementParentForFrame(frame))
+ return false;
+
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+};
+
+function BrowserElementPromptFactory(toWrap) {
+ this._wrapped = toWrap;
+}
+
+BrowserElementPromptFactory.prototype = {
+ classID: Components.ID("{24f3d0cf-e417-4b85-9017-c9ecf8bb1299}"),
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIPromptFactory]),
+
+ _mayUseNativePrompt: function() {
+ try {
+ return Services.prefs.getBoolPref("browser.prompt.allowNative");
+ } catch (e) {
+ // This properity is default to true.
+ return true;
+ }
+ },
+
+ _getNativePromptIfAllowed: function(win, iid, err) {
+ if (this._mayUseNativePrompt())
+ return this._wrapped.getPrompt(win, iid);
+ else {
+ // Not allowed, throw an exception.
+ throw err;
+ }
+ },
+
+ getPrompt: function(win, iid) {
+ // It is possible for some object to get a prompt without passing
+ // valid reference of window, like nsNSSComponent. In such case, we
+ // should just fall back to the native prompt service
+ if (!win)
+ return this._getNativePromptIfAllowed(win, iid, Cr.NS_ERROR_INVALID_ARG);
+
+ if (iid.number != Ci.nsIPrompt.number &&
+ iid.number != Ci.nsIAuthPrompt2.number) {
+ debug("We don't recognize the requested IID (" + iid + ", " +
+ "allowed IID: " +
+ "nsIPrompt=" + Ci.nsIPrompt + ", " +
+ "nsIAuthPrompt2=" + Ci.nsIAuthPrompt2 + ")");
+ return this._getNativePromptIfAllowed(win, iid, Cr.NS_ERROR_INVALID_ARG);
+ }
+
+ // Try to find a BrowserElementChild for the window.
+ let browserElementChild =
+ BrowserElementPromptService.getBrowserElementChildForWindow(win);
+
+ if (iid.number === Ci.nsIAuthPrompt2.number) {
+ debug("Caller requests an instance of nsIAuthPrompt2.");
+
+ if (browserElementChild) {
+ // If we are able to get a BrowserElementChild, it means that
+ // the auth prompt is for a mozbrowser. Therefore we don't need to
+ // fall back.
+ return new BrowserElementAuthPrompt().QueryInterface(iid);
+ }
+
+ // Because nsIAuthPrompt2 is called in parent process. If caller
+ // wants nsIAuthPrompt2 and we cannot get BrowserElementchild,
+ // it doesn't mean that we should fallback. It is possible that we can
+ // get the BrowserElementParent from nsIChannel that passed to
+ // functions of nsIAuthPrompt2.
+ if (this._mayUseNativePrompt()) {
+ return new AuthPromptWrapper(
+ this._wrapped.getPrompt(win, iid),
+ new BrowserElementAuthPrompt().QueryInterface(iid))
+ .QueryInterface(iid);
+ } else {
+ // Falling back is not allowed, so we don't need wrap the
+ // BrowserElementPrompt.
+ return new BrowserElementAuthPrompt().QueryInterface(iid);
+ }
+ }
+
+ if (!browserElementChild) {
+ debug("We can't find a browserElementChild for " +
+ win + ", " + win.location);
+ return this._getNativePromptIfAllowed(win, iid, Cr.NS_ERROR_FAILURE);
+ }
+
+ debug("Returning wrapped getPrompt for " + win);
+ return new BrowserElementPrompt(win, browserElementChild)
+ .QueryInterface(iid);
+ }
+};
+
+this.BrowserElementPromptService = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+ Ci.nsISupportsWeakReference]),
+
+ _initialized: false,
+
+ _init: function() {
+ if (this._initialized) {
+ return;
+ }
+
+ // If the pref is disabled, do nothing except wait for the pref to change.
+ if (!this._browserFramesPrefEnabled()) {
+ var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+ prefs.addObserver(BROWSER_FRAMES_ENABLED_PREF, this, /* ownsWeak = */ true);
+ return;
+ }
+
+ this._initialized = true;
+ this._browserElementParentMap = new WeakMap();
+
+ var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+ os.addObserver(this, "outer-window-destroyed", /* ownsWeak = */ true);
+
+ // Wrap the existing @mozilla.org/prompter;1 implementation.
+ var contractID = "@mozilla.org/prompter;1";
+ var oldCID = Cm.contractIDToCID(contractID);
+ var newCID = BrowserElementPromptFactory.prototype.classID;
+ var oldFactory = Cm.getClassObject(Cc[contractID], Ci.nsIFactory);
+
+ if (oldCID == newCID) {
+ debug("WARNING: Wrapped prompt factory is already installed!");
+ return;
+ }
+
+ Cm.unregisterFactory(oldCID, oldFactory);
+
+ var oldInstance = oldFactory.createInstance(null, Ci.nsIPromptFactory);
+ var newInstance = new BrowserElementPromptFactory(oldInstance);
+
+ var newFactory = {
+ createInstance: function(outer, iid) {
+ if (outer != null) {
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ }
+ return newInstance.QueryInterface(iid);
+ }
+ };
+ Cm.registerFactory(newCID,
+ "BrowserElementPromptService's prompter;1 wrapper",
+ contractID, newFactory);
+
+ debug("Done installing new prompt factory.");
+ },
+
+ _getOuterWindowID: function(win) {
+ return win.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils)
+ .outerWindowID;
+ },
+
+ _browserElementChildMap: {},
+ mapWindowToBrowserElementChild: function(win, browserElementChild) {
+ this._browserElementChildMap[this._getOuterWindowID(win)] = browserElementChild;
+ },
+ unmapWindowToBrowserElementChild: function(win) {
+ delete this._browserElementChildMap[this._getOuterWindowID(win)];
+ },
+
+ getBrowserElementChildForWindow: function(win) {
+ // We only have a mapping for <iframe mozbrowser>s, not their inner
+ // <iframes>, so we look up win.top below. window.top (when called from
+ // script) respects <iframe mozbrowser> boundaries.
+ return this._browserElementChildMap[this._getOuterWindowID(win.top)];
+ },
+
+ mapFrameToBrowserElementParent: function(frame, browserElementParent) {
+ this._browserElementParentMap.set(frame, browserElementParent);
+ },
+
+ getBrowserElementParentForFrame: function(frame) {
+ return this._browserElementParentMap.get(frame);
+ },
+
+ _observeOuterWindowDestroyed: function(outerWindowID) {
+ let id = outerWindowID.QueryInterface(Ci.nsISupportsPRUint64).data;
+ debug("observeOuterWindowDestroyed " + id);
+ delete this._browserElementChildMap[outerWindowID.data];
+ },
+
+ _browserFramesPrefEnabled: function() {
+ var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+ try {
+ return prefs.getBoolPref(BROWSER_FRAMES_ENABLED_PREF);
+ }
+ catch(e) {
+ return false;
+ }
+ },
+
+ observe: function(subject, topic, data) {
+ switch(topic) {
+ case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
+ if (data == BROWSER_FRAMES_ENABLED_PREF) {
+ this._init();
+ }
+ break;
+ case "outer-window-destroyed":
+ this._observeOuterWindowDestroyed(subject);
+ break;
+ default:
+ debug("Observed unexpected topic " + topic);
+ }
+ }
+};
+
+BrowserElementPromptService._init();
diff --git a/dom/browser-element/BrowserElementProxy.js b/dom/browser-element/BrowserElementProxy.js
new file mode 100644
index 000000000..852b93358
--- /dev/null
+++ b/dom/browser-element/BrowserElementProxy.js
@@ -0,0 +1,219 @@
+/* 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';
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cr = Components.results;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://gre/modules/Services.jsm');
+
+function defineNoReturnMethod(methodName) {
+ return function noReturnMethod() {
+ let args = Array.slice(arguments);
+ this._sendToParent(methodName, args);
+ };
+}
+
+function defineDOMRequestMethod(methodName) {
+ return function domRequestMethod() {
+ let args = Array.slice(arguments);
+ return this._sendDOMRequest(methodName, args);
+ };
+}
+
+function defineUnimplementedMethod(methodName) {
+ return function unimplementedMethod() {
+ throw Components.Exception(
+ 'Unimplemented method: ' + methodName, Cr.NS_ERROR_FAILURE);
+ };
+}
+
+/**
+ * The BrowserElementProxy talks to the Browser IFrameElement instance on
+ * behave of the embedded document. It implements all the methods on
+ * the Browser IFrameElement and the methods will work if they are applicable.
+ *
+ * The message is forwarded to BrowserElementParent.js by creating an
+ * 'browser-element-api:proxy-call' observer message.
+ * BrowserElementChildPreload will get notified and send the message through
+ * to the main process through sendAsyncMessage with message of the same name.
+ *
+ * The return message will follow the same route. The message name on the
+ * return route is 'browser-element-api:proxy'.
+ *
+ * Both BrowserElementProxy and BrowserElementParent must be modified if there
+ * is a new method implemented, or a new event added to the Browser
+ * IFrameElement.
+ *
+ * Other details unmentioned here are checks of message sender and recipients
+ * to identify proxy instance on different innerWindows or ensure the content
+ * process has the right permission.
+ */
+function BrowserElementProxy() {
+ // Pad the 0th element so that DOMRequest ID will always be a truthy value.
+ this._pendingDOMRequests = [ undefined ];
+}
+
+BrowserElementProxy.prototype = {
+ classDescription: 'BrowserElementProxy allowed embedded frame to control ' +
+ 'it\'s own embedding browser element frame instance.',
+ classID: Components.ID('{7e95d54c-9930-49c8-9a10-44fe40fe8251}'),
+ contractID: '@mozilla.org/dom/browser-element-proxy;1',
+
+ QueryInterface: XPCOMUtils.generateQI([
+ Ci.nsIDOMGlobalPropertyInitializer,
+ Ci.nsIObserver]),
+
+ _window: null,
+ _innerWindowID: undefined,
+
+ get allowedAudioChannels() {
+ return this._window.navigator.mozAudioChannelManager ?
+ this._window.navigator.mozAudioChannelManager.allowedAudioChannels :
+ null;
+ },
+
+ init: function(win) {
+ this._window = win;
+ this._innerWindowID = win.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils)
+ .currentInnerWindowID;
+
+ this._sendToParent('_proxyInstanceInit');
+ Services.obs.addObserver(this, 'browser-element-api:proxy', false);
+ },
+
+ uninit: function(win) {
+ this._sendToParent('_proxyInstanceUninit');
+
+ this._window = null;
+ this._innerWindowID = undefined;
+
+ Services.obs.removeObserver(this, 'browser-element-api:proxy');
+ },
+
+ observe: function(subject, topic, stringifedData) {
+ let data = JSON.parse(stringifedData);
+
+ if (subject !== this._window ||
+ data.innerWindowID !== data.innerWindowID) {
+ return;
+ }
+
+ if (data.eventName) {
+ this._fireEvent(data.eventName, JSON.parse(data.eventDetailString));
+
+ return;
+ }
+
+ if ('domRequestId' in data) {
+ let req = this._pendingDOMRequests[data.domRequestId];
+ this._pendingDOMRequests[data.domRequestId] = undefined;
+
+ if (!req) {
+ dump('BrowserElementProxy Error: ' +
+ 'Multiple observer messages for the same DOMRequest result.\n');
+ return;
+ }
+
+ if ('result' in data) {
+ let clientObj = Cu.cloneInto(data.result, this._window);
+ Services.DOMRequest.fireSuccess(req, clientObj);
+ } else {
+ let clientObj = Cu.cloneInto(data.error, this._window);
+ Services.DOMRequest.fireSuccess(req, clientObj);
+ }
+
+ return;
+ }
+
+ dump('BrowserElementProxy Error: ' +
+ 'Received unhandled observer messages ' + stringifedData + '.\n');
+ },
+
+ _sendDOMRequest: function(methodName, args) {
+ let id = this._pendingDOMRequests.length;
+ let req = Services.DOMRequest.createRequest(this._window);
+
+ this._pendingDOMRequests.push(req);
+ this._sendToParent(methodName, args, id);
+
+ return req;
+ },
+
+ _sendToParent: function(methodName, args, domRequestId) {
+ let data = {
+ methodName: methodName,
+ args: args,
+ innerWindowID: this._innerWindowID
+ };
+
+ if (domRequestId) {
+ data.domRequestId = domRequestId;
+ }
+
+ Services.obs.notifyObservers(
+ this._window, 'browser-element-api:proxy-call', JSON.stringify(data));
+ },
+
+ _fireEvent: function(name, detail) {
+ let evt = this._createEvent(name, detail,
+ /* cancelable = */ false);
+ this.__DOM_IMPL__.dispatchEvent(evt);
+ },
+
+ _createEvent: function(evtName, detail, cancelable) {
+ // This will have to change if we ever want to send a CustomEvent with null
+ // detail. For now, it's OK.
+ if (detail !== undefined && detail !== null) {
+ detail = Cu.cloneInto(detail, this._window);
+ return new this._window.CustomEvent(evtName,
+ { bubbles: false,
+ cancelable: cancelable,
+ detail: detail });
+ }
+
+ return new this._window.Event(evtName,
+ { bubbles: false,
+ cancelable: cancelable });
+ },
+
+ setVisible: defineNoReturnMethod('setVisible'),
+ setActive: defineNoReturnMethod('setActive'),
+ sendMouseEvent: defineNoReturnMethod('sendMouseEvent'),
+ sendTouchEvent: defineNoReturnMethod('sendTouchEvent'),
+ goBack: defineNoReturnMethod('goBack'),
+ goForward: defineNoReturnMethod('goForward'),
+ reload: defineNoReturnMethod('reload'),
+ stop: defineNoReturnMethod('stop'),
+ zoom: defineNoReturnMethod('zoom'),
+ findAll: defineNoReturnMethod('findAll'),
+ findNext: defineNoReturnMethod('findNext'),
+ clearMatch: defineNoReturnMethod('clearMatch'),
+ mute: defineNoReturnMethod('mute'),
+ unmute: defineNoReturnMethod('unmute'),
+ setVolume: defineNoReturnMethod('setVolume'),
+
+ getVisible: defineDOMRequestMethod('getVisible'),
+ download: defineDOMRequestMethod('download'),
+ purgeHistory: defineDOMRequestMethod('purgeHistory'),
+ getCanGoBack: defineDOMRequestMethod('getCanGoBack'),
+ getCanGoForward: defineDOMRequestMethod('getCanGoForward'),
+ getContentDimensions: defineDOMRequestMethod('getContentDimensions'),
+ setInputMethodActive: defineDOMRequestMethod('setInputMethodActive'),
+ executeScript: defineDOMRequestMethod('executeScript'),
+ getMuted: defineDOMRequestMethod('getMuted'),
+ getVolume: defineDOMRequestMethod('getVolume'),
+
+ getActive: defineUnimplementedMethod('getActive'),
+ addNextPaintListener: defineUnimplementedMethod('addNextPaintListener'),
+ removeNextPaintListener: defineUnimplementedMethod('removeNextPaintListener'),
+ getScreenshot: defineUnimplementedMethod('getScreenshot')
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementProxy]);
diff --git a/dom/browser-element/BrowserElementProxy.manifest b/dom/browser-element/BrowserElementProxy.manifest
new file mode 100644
index 000000000..b26639523
--- /dev/null
+++ b/dom/browser-element/BrowserElementProxy.manifest
@@ -0,0 +1,2 @@
+component {7e95d54c-9930-49c8-9a10-44fe40fe8251} BrowserElementProxy.js
+contract @mozilla.org/dom/browser-element-proxy;1 {7e95d54c-9930-49c8-9a10-44fe40fe8251}
diff --git a/dom/browser-element/mochitest/async.js b/dom/browser-element/mochitest/async.js
new file mode 100644
index 000000000..d0007fa09
--- /dev/null
+++ b/dom/browser-element/mochitest/async.js
@@ -0,0 +1,78 @@
+/* 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/. */
+
+/*
+ * This is an approximate implementation of ES7's async-await pattern.
+ * see: https://github.com/tc39/ecmascript-asyncawait
+ *
+ * It allows for simple creation of async function and "tasks".
+ *
+ * For example:
+ *
+ * var myThinger = {
+ * doAsynThing: async(function*(url){
+ * var result = yield fetch(url);
+ * return process(result);
+ * });
+ * }
+ *
+ * And Task-like things can be created as follows:
+ *
+ * var myTask = async(function*{
+ * var result = yield fetch(url);
+ * return result;
+ * });
+ * //returns a promise
+ *
+ * myTask().then(doSomethingElse);
+ *
+ */
+
+(function(exports) {
+ "use strict";
+ function async(func, self) {
+ return function asyncFunction() {
+ const functionArgs = Array.from(arguments);
+ return new Promise(function(resolve, reject) {
+ var gen;
+ if (typeof func !== "function") {
+ reject(new TypeError("Expected a Function."));
+ }
+ //not a generator, wrap it.
+ if (func.constructor.name !== "GeneratorFunction") {
+ gen = (function*() {
+ return func.apply(self, functionArgs);
+ }());
+ } else {
+ gen = func.apply(self, functionArgs);
+ }
+ try {
+ step(gen.next(undefined));
+ } catch (err) {
+ reject(err);
+ }
+
+ function step({value, done}) {
+ if (done) {
+ return resolve(value);
+ }
+ if (value instanceof Promise) {
+ return value.then(
+ result => step(gen.next(result)),
+ error => {
+ try {
+ step(gen.throw(error));
+ } catch (err) {
+ throw err;
+ }
+ }
+ ).catch(err => reject(err));
+ }
+ step(gen.next(value));
+ }
+ });
+ };
+ }
+ exports.async = async;
+}(this || self));
diff --git a/dom/browser-element/mochitest/audio.ogg b/dom/browser-element/mochitest/audio.ogg
new file mode 100644
index 000000000..44ab64f81
--- /dev/null
+++ b/dom/browser-element/mochitest/audio.ogg
Binary files differ
diff --git a/dom/browser-element/mochitest/browserElementTestHelpers.js b/dom/browser-element/mochitest/browserElementTestHelpers.js
new file mode 100644
index 000000000..004b25333
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElementTestHelpers.js
@@ -0,0 +1,306 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Helpers for managing the browser frame preferences.
+"use strict";
+
+function _getPath() {
+ return window.location.pathname
+ .substring(0, window.location.pathname.lastIndexOf('/'))
+ .replace("/priority", "");
+}
+
+const browserElementTestHelpers = {
+ _getBoolPref: function(pref) {
+ try {
+ return SpecialPowers.getBoolPref(pref);
+ }
+ catch (e) {
+ return undefined;
+ }
+ },
+
+ _setPref: function(pref, value) {
+ this.lockTestReady();
+ if (value !== undefined && value !== null) {
+ SpecialPowers.pushPrefEnv({'set': [[pref, value]]}, this.unlockTestReady.bind(this));
+ } else {
+ SpecialPowers.pushPrefEnv({'clear': [[pref]]}, this.unlockTestReady.bind(this));
+ }
+ },
+
+ _setPrefs: function() {
+ this.lockTestReady();
+ SpecialPowers.pushPrefEnv({'set': Array.slice(arguments)}, this.unlockTestReady.bind(this));
+ },
+
+ _testReadyLockCount: 0,
+ _firedTestReady: false,
+ lockTestReady: function() {
+ this._testReadyLockCount++;
+ },
+
+ unlockTestReady: function() {
+ this._testReadyLockCount--;
+ if (this._testReadyLockCount == 0 && !this._firedTestReady) {
+ this._firedTestReady = true;
+ dispatchEvent(new Event("testready"));
+ }
+ },
+
+ enableProcessPriorityManager: function() {
+ this._setPrefs(
+ ['dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels', 2],
+ ['dom.ipc.processPriorityManager.BACKGROUND_PERCEIVABLE.LRUPoolLevels', 2],
+ ['dom.ipc.processPriorityManager.testMode', true],
+ ['dom.ipc.processPriorityManager.enabled', true]
+ );
+ },
+
+ setClipboardPlainTextOnlyPref: function(value) {
+ this._setPref('clipboard.plainTextOnly', value);
+ },
+
+ setEnabledPref: function(value) {
+ this._setPrefs(['dom.mozBrowserFramesEnabled', value],
+ ['network.disable.ipc.security', value]);
+ },
+
+ setupAccessibleCaretPref: function() {
+ this._setPref('layout.accessiblecaret.enabled', true);
+ // Disable hide carets for mouse input for select-all tests so that we can
+ // get mozbrowsercaretstatechanged events.
+ this._setPref('layout.accessiblecaret.hide_carets_for_mouse_input', false);
+ },
+
+ getOOPByDefaultPref: function() {
+ return this._getBoolPref("dom.ipc.browser_frames.oop_by_default");
+ },
+
+ addPermission: function() {
+ this.lockTestReady();
+ SpecialPowers.pushPermissions(
+ [{'type': "browser", 'allow': 1, 'context': document}],
+ this.unlockTestReady.bind(this));
+ },
+
+ _observers: [],
+
+ // This function is a wrapper which lets you register an observer to one of
+ // the process priority manager's test-only topics. observerFn should be a
+ // function which takes (subject, topic, data).
+ //
+ // We'll clean up any observers you add at the end of the test.
+ addProcessPriorityObserver: function(processPriorityTopic, observerFn) {
+ var topic = "process-priority-manager:TEST-ONLY:" + processPriorityTopic;
+
+ // SpecialPowers appears to require that the observer be an object, not a
+ // function.
+ var observer = {
+ observe: observerFn
+ };
+
+ SpecialPowers.addObserver(observer, topic, /* weak = */ false);
+ this._observers.push([observer, topic]);
+ },
+
+ cleanUp: function() {
+ for (var i = 0; i < this._observers.length; i++) {
+ SpecialPowers.removeObserver(this._observers[i][0],
+ this._observers[i][1]);
+ }
+ },
+
+ // Some basically-empty pages from different domains you can load.
+ 'emptyPage1': 'http://example.com' + _getPath() + '/file_empty.html',
+ 'fileEmptyPage1': 'file_empty.html',
+ 'emptyPage2': 'http://example.org' + _getPath() + '/file_empty.html',
+ 'emptyPage3': 'http://test1.example.org' + _getPath() + '/file_empty.html',
+ 'focusPage': 'http://example.org' + _getPath() + '/file_focus.html',
+};
+
+// Returns a promise which is resolved when a subprocess is created. The
+// argument to resolve() is the childID of the subprocess.
+function expectProcessCreated(/* optional */ initialPriority) {
+ return new Promise(function(resolve, reject) {
+ var observed = false;
+ browserElementTestHelpers.addProcessPriorityObserver(
+ "process-created",
+ function(subject, topic, data) {
+ // Don't run this observer twice, so we don't ok(true) twice. (It's fine
+ // to resolve a promise twice; the second resolve() call does nothing.)
+ if (observed) {
+ return;
+ }
+ observed = true;
+
+ var childID = parseInt(data);
+ ok(true, 'Got new process, id=' + childID);
+ if (initialPriority) {
+ expectPriorityChange(childID, initialPriority).then(function() {
+ resolve(childID);
+ });
+ } else {
+ resolve(childID);
+ }
+ }
+ );
+ });
+}
+
+// Just like expectProcessCreated(), except we'll call ok(false) if a second
+// process is created.
+function expectOnlyOneProcessCreated(/* optional */ initialPriority) {
+ var p = expectProcessCreated(initialPriority);
+ p.then(function() {
+ expectProcessCreated().then(function(childID) {
+ ok(false, 'Got unexpected process creation, childID=' + childID);
+ });
+ });
+ return p;
+}
+
+// Returns a promise which is resolved or rejected the next time the process
+// childID changes its priority. We resolve if the priority matches
+// expectedPriority, and we reject otherwise.
+
+function expectPriorityChange(childID, expectedPriority) {
+ return new Promise(function(resolve, reject) {
+ var observed = false;
+ browserElementTestHelpers.addProcessPriorityObserver(
+ 'process-priority-set',
+ function(subject, topic, data) {
+ if (observed) {
+ return;
+ }
+
+ var [id, priority] = data.split(":");
+ if (id != childID) {
+ return;
+ }
+
+ // Make sure we run the is() calls in this observer only once, otherwise
+ // we'll expect /every/ priority change to match expectedPriority.
+ observed = true;
+
+ is(priority, expectedPriority,
+ 'Expected priority of childID ' + childID +
+ ' to change to ' + expectedPriority);
+
+ if (priority == expectedPriority) {
+ resolve();
+ } else {
+ reject();
+ }
+ }
+ );
+ });
+}
+
+// Returns a promise which is resolved or rejected the next time the
+// process childID changes its priority. We resolve if the expectedPriority
+// matches the priority and the LRU parameter matches expectedLRU and we
+// reject otherwise.
+
+function expectPriorityWithLRUSet(childID, expectedPriority, expectedLRU) {
+ return new Promise(function(resolve, reject) {
+ var observed = false;
+ browserElementTestHelpers.addProcessPriorityObserver(
+ 'process-priority-with-LRU-set',
+ function(subject, topic, data) {
+ if (observed) {
+ return;
+ }
+
+ var [id, priority, lru] = data.split(":");
+ if (id != childID) {
+ return;
+ }
+
+ // Make sure we run the is() calls in this observer only once,
+ // otherwise we'll expect /every/ priority/LRU change to match
+ // expectedPriority/expectedLRU.
+ observed = true;
+
+ is(lru, expectedLRU,
+ 'Expected LRU ' + lru +
+ ' of childID ' + childID +
+ ' to change to ' + expectedLRU);
+
+ if ((priority == expectedPriority) && (lru == expectedLRU)) {
+ resolve();
+ } else {
+ reject();
+ }
+ }
+ );
+ });
+}
+
+// Returns a promise which is resolved the first time the given iframe fires
+// the mozbrowser##eventName event.
+function expectMozbrowserEvent(iframe, eventName) {
+ return new Promise(function(resolve, reject) {
+ iframe.addEventListener('mozbrowser' + eventName, function handler(e) {
+ iframe.removeEventListener('mozbrowser' + eventName, handler);
+ resolve(e);
+ });
+ });
+}
+
+// Set some prefs:
+//
+// * browser.pagethumbnails.capturing_disabled: true
+//
+// Disable tab view; it seriously messes us up.
+//
+// * dom.ipc.browser_frames.oop_by_default
+//
+// Enable or disable OOP-by-default depending on the test's filename. You
+// can still force OOP on or off with <iframe mozbrowser remote=true/false>,
+// at least until bug 756376 lands.
+//
+// * dom.ipc.tabs.disabled: false
+//
+// Allow us to create OOP frames. Even if they're not the default, some
+// "in-process" tests create OOP frames.
+//
+// * network.disable.ipc.security: true
+//
+// Disable the networking security checks; our test harness just tests
+// browser elements without sticking them in apps, and the security checks
+// dislike that.
+//
+// Unfortunately setting network.disable.ipc.security to false before the
+// child process(es) created by this test have shut down can cause us to
+// assert and kill the child process. That doesn't cause the tests to fail,
+// but it's still scary looking. So we just set the pref to true and never
+// pop that value. We'll rely on the tests which test IPC security to set
+// it to false.
+//
+// * security.mixed_content.block_active_content: false
+//
+// Disable mixed active content blocking, so that tests can confirm that mixed
+// content results in a broken security state.
+
+(function() {
+ var oop = location.pathname.indexOf('_inproc_') == -1;
+
+ browserElementTestHelpers.lockTestReady();
+ SpecialPowers.setBoolPref("network.disable.ipc.security", true);
+ SpecialPowers.pushPrefEnv({set: [["browser.pagethumbnails.capturing_disabled", true],
+ ["dom.ipc.browser_frames.oop_by_default", oop],
+ ["dom.ipc.tabs.disabled", false],
+ ["security.mixed_content.block_active_content", false]]},
+ browserElementTestHelpers.unlockTestReady.bind(browserElementTestHelpers));
+})();
+
+addEventListener('unload', function() {
+ browserElementTestHelpers.cleanUp();
+});
+
+// Wait for the load event before unlocking the test-ready event.
+browserElementTestHelpers.lockTestReady();
+addEventListener('load', function() {
+ SimpleTest.executeSoon(browserElementTestHelpers.unlockTestReady.bind(browserElementTestHelpers));
+});
diff --git a/dom/browser-element/mochitest/browserElement_ActiveStateChange.js b/dom/browser-element/mochitest/browserElement_ActiveStateChange.js
new file mode 100644
index 000000000..cfbc1cb1e
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_ActiveStateChange.js
@@ -0,0 +1,108 @@
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+var fileURL = 'chrome://mochitests/content/chrome/dom/browser-element/mochitest/file_browserElement_ActiveStateChange.html';
+var generator = runTests();
+var testFrame;
+var ac;
+
+function assert(aVal, aMessage) {
+ return (!aVal) ? error(aMessage) : 0;
+}
+
+function error(aMessage) {
+ ok(false, "Error : " + aMessage);
+ finish();
+}
+
+function continueTest() {
+ try {
+ generator.next();
+ } catch (e if e instanceof StopIteration) {
+ error("Stop test because of exception!");
+ }
+}
+
+function finish() {
+ document.body.removeChild(testFrame);
+ SimpleTest.finish();
+}
+
+function setCommand(aArg) {
+ assert(!!ac, "Audio channel doesn't exist!");
+ info("# Command = " + aArg);
+
+ testFrame.src = fileURL + '#' + aArg;
+ var expectedActive = false;
+ switch (aArg) {
+ case 'play':
+ expectedActive = true;
+ break;
+ case 'pause':
+ expectedActive = false;
+ break;
+ default :
+ error("Undefined command!");
+ }
+
+ ac.onactivestatechanged = () => {
+ ac.onactivestatechanged = null;
+ ac.isActive().onsuccess = (e) => {
+ is(expectedActive, e.target.result,
+ "Correct active state = " + expectedActive);
+ continueTest();
+ }
+ };
+}
+
+function runTests() {
+ setCommand('play');
+ yield undefined;
+
+ setCommand('pause');
+ yield undefined;
+
+ finish();
+ yield undefined;
+}
+
+function setupTestFrame() {
+ testFrame = document.createElement('iframe');
+ testFrame.setAttribute('mozbrowser', 'true');
+ testFrame.src = fileURL;
+
+ function loadend() {
+ testFrame.removeEventListener('mozbrowserloadend', loadend);
+ ok("allowedAudioChannels" in testFrame, "allowedAudioChannels exist");
+ var channels = testFrame.allowedAudioChannels;
+ is(channels.length, 9, "9 audio channel by default");
+
+ ac = channels[0];
+
+ ok(ac instanceof BrowserElementAudioChannel, "Correct class");
+ ok("isActive" in ac, "isActive exists");
+ ok("onactivestatechanged" in ac, "onactivestatechanged exists");
+
+ generator.next();
+ }
+
+ function alertError(e) {
+ testFrame.removeEventListener('mozbrowsershowmodalprompt', alertError);
+ var message = e.detail.message
+ error(message);
+ }
+
+ testFrame.addEventListener('mozbrowserloadend', loadend);
+ testFrame.addEventListener('mozbrowsershowmodalprompt', alertError);
+ document.body.appendChild(testFrame);
+}
+
+addEventListener('testready', function() {
+ SpecialPowers.pushPrefEnv({'set': [["b2g.system_startup_url", window.location.href]]},
+ function() {
+ SimpleTest.executeSoon(setupTestFrame);
+ });
+});
+
diff --git a/dom/browser-element/mochitest/browserElement_Alert.js b/dom/browser-element/mochitest/browserElement_Alert.js
new file mode 100644
index 000000000..3c7c50720
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Alert.js
@@ -0,0 +1,304 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that alert works.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+var numPendingChildTests = 0;
+var iframe;
+var mm;
+
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+
+ mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+ mm.addMessageListener('test-success', function(msg) {
+ numPendingChildTests--;
+ ok(true, SpecialPowers.wrap(msg).json);
+ });
+ mm.addMessageListener('test-fail', function(msg) {
+ numPendingChildTests--;
+ ok(false, SpecialPowers.wrap(msg).json);
+ });
+
+ // Wait for the initial load to finish, then navigate the page, then wait
+ // for that load to finish, then start test1.
+ iframe.addEventListener('mozbrowserloadend', function loadend() {
+ iframe.removeEventListener('mozbrowserloadend', loadend);
+ iframe.src = browserElementTestHelpers.emptyPage1;
+
+ iframe.addEventListener('mozbrowserloadend', function loadend2() {
+ iframe.removeEventListener('mozbrowserloadend', loadend2);
+ SimpleTest.executeSoon(test1);
+ });
+ });
+
+}
+
+function test1() {
+ iframe.addEventListener('mozbrowsershowmodalprompt', test2);
+
+ // Do window.alert within the iframe, then modify the global |testState|
+ // after the alert.
+ var script = 'data:,\
+ this.testState = 0; \
+ content.alert("Hello, world!"); \
+ this.testState = 1; \
+ ';
+
+ mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
+
+ // Triggers a mozbrowsershowmodalprompt event, which sends us down to test2.
+}
+
+// test2 is a mozbrowsershowmodalprompt listener.
+function test2(e) {
+ iframe.removeEventListener("mozbrowsershowmodalprompt", test2);
+
+ is(e.detail.message, 'Hello, world!');
+ e.preventDefault(); // cause the alert to block.
+
+ SimpleTest.executeSoon(function() { test2a(e); });
+}
+
+function test2a(e) {
+ // The iframe should be blocked on the alert call at the moment, so testState
+ // should still be 0.
+ var script = 'data:,\
+ if (this.testState === 0) { \
+ sendAsyncMessage("test-success", "1: Correct testState"); \
+ } \
+ else { \
+ sendAsyncMessage("test-fail", "1: Wrong testState: " + this.testState); \
+ }';
+
+ mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
+ numPendingChildTests++;
+
+ waitForPendingTests(function() { test3(e); });
+}
+
+function test3(e) {
+ // Now unblock the iframe and check that the script completed.
+ e.detail.unblock();
+
+ var script2 = 'data:,\
+ if (this.testState === 1) { \
+ sendAsyncMessage("test-success", "2: Correct testState"); \
+ } \
+ else { \
+ sendAsyncMessage("test-try-again", "2: Wrong testState (for now): " + this.testState); \
+ }';
+
+ // Urgh. e.unblock() didn't necessarily unblock us immediately, so we have
+ // to spin and wait.
+ function onTryAgain() {
+ SimpleTest.executeSoon(function() {
+ //dump('onTryAgain\n');
+ mm.loadFrameScript(script2, /* allowDelayedLoad = */ false);
+ });
+ }
+
+ mm.addMessageListener('test-try-again', onTryAgain);
+ numPendingChildTests++;
+
+ onTryAgain();
+ waitForPendingTests(function() {
+ mm.removeMessageListener('test-try-again', onTryAgain);
+ test4();
+ });
+}
+
+function test4() {
+ // Navigate the iframe while an alert is pending. This shouldn't screw
+ // things up.
+
+ iframe.addEventListener("mozbrowsershowmodalprompt", test5);
+
+ var script = 'data:,content.alert("test4");';
+ mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
+}
+
+// test4 is a mozbrowsershowmodalprompt listener.
+function test5(e) {
+ iframe.removeEventListener('mozbrowsershowmodalprompt', test5);
+
+ is(e.detail.message, 'test4');
+ e.preventDefault(); // cause the page to block.
+
+ SimpleTest.executeSoon(test5a);
+}
+
+function test5a() {
+ iframe.addEventListener('mozbrowserloadend', test5b);
+ iframe.src = browserElementTestHelpers.emptyPage2;
+}
+
+function test5b() {
+ iframe.removeEventListener('mozbrowserloadend', test5b);
+ SimpleTest.executeSoon(test6);
+}
+
+// Test nested alerts
+var promptBlockers = [];
+function test6() {
+ iframe.addEventListener("mozbrowsershowmodalprompt", test6a);
+
+ var script = 'data:,\
+ this.testState = 0; \
+ content.alert(1); \
+ this.testState = 3; \
+ ';
+ mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
+}
+
+function test6a(e) {
+ iframe.removeEventListener("mozbrowsershowmodalprompt", test6a);
+
+ is(e.detail.message, '1');
+ e.preventDefault(); // cause the alert to block.
+ promptBlockers.push(e);
+
+ SimpleTest.executeSoon(test6b);
+}
+
+function test6b() {
+ var script = 'data:,\
+ if (this.testState === 0) { \
+ sendAsyncMessage("test-success", "1: Correct testState"); \
+ } \
+ else { \
+ sendAsyncMessage("test-fail", "1: Wrong testState: " + this.testState); \
+ }';
+ mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
+ numPendingChildTests++;
+
+ waitForPendingTests(test6c);
+}
+
+function test6c() {
+ iframe.addEventListener("mozbrowsershowmodalprompt", test6d);
+
+ var script = 'data:,\
+ this.testState = 1; \
+ content.alert(2); \
+ this.testState = 2; \
+ ';
+ mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
+}
+
+function test6d(e) {
+ iframe.removeEventListener("mozbrowsershowmodalprompt", test6d);
+
+ is(e.detail.message, '2');
+ e.preventDefault(); // cause the alert to block.
+ promptBlockers.push(e);
+
+ SimpleTest.executeSoon(test6e);
+}
+
+function test6e() {
+ var script = 'data:,\
+ if (this.testState === 1) { \
+ sendAsyncMessage("test-success", "2: Correct testState"); \
+ } \
+ else { \
+ sendAsyncMessage("test-fail", "2: Wrong testState: " + this.testState); \
+ }';
+ mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
+ numPendingChildTests++;
+
+ waitForPendingTests(test6f);
+}
+
+function test6f() {
+ var e = promptBlockers.pop();
+ // Now unblock the iframe and check that the script completed.
+ e.detail.unblock();
+
+ var script2 = 'data:,\
+ if (this.testState === 2) { \
+ sendAsyncMessage("test-success", "3: Correct testState"); \
+ } \
+ else { \
+ sendAsyncMessage("test-try-again", "3: Wrong testState (for now): " + this.testState); \
+ }';
+
+ // Urgh. e.unblock() didn't necessarily unblock us immediately, so we have
+ // to spin and wait.
+ function onTryAgain() {
+ SimpleTest.executeSoon(function() {
+ //dump('onTryAgain\n');
+ mm.loadFrameScript(script2, /* allowDelayedLoad = */ false);
+ });
+ }
+
+ mm.addMessageListener('test-try-again', onTryAgain);
+ numPendingChildTests++;
+
+ onTryAgain();
+ waitForPendingTests(function() {
+ mm.removeMessageListener('test-try-again', onTryAgain);
+ test6g();
+ });
+}
+
+function test6g() {
+ var e = promptBlockers.pop();
+ // Now unblock the iframe and check that the script completed.
+ e.detail.unblock();
+
+ var script2 = 'data:,\
+ if (this.testState === 3) { \
+ sendAsyncMessage("test-success", "4: Correct testState"); \
+ } \
+ else { \
+ sendAsyncMessage("test-try-again", "4: Wrong testState (for now): " + this.testState); \
+ }';
+
+ // Urgh. e.unblock() didn't necessarily unblock us immediately, so we have
+ // to spin and wait.
+ function onTryAgain() {
+ SimpleTest.executeSoon(function() {
+ //dump('onTryAgain\n');
+ mm.loadFrameScript(script2, /* allowDelayedLoad = */ false);
+ });
+ }
+
+ mm.addMessageListener('test-try-again', onTryAgain);
+ numPendingChildTests++;
+
+ onTryAgain();
+ waitForPendingTests(function() {
+ mm.removeMessageListener('test-try-again', onTryAgain);
+ test6h();
+ });
+}
+
+function test6h() {
+ SimpleTest.finish();
+}
+
+var prevNumPendingTests = null;
+function waitForPendingTests(next) {
+ if (numPendingChildTests !== prevNumPendingTests) {
+ dump("Waiting for end; " + numPendingChildTests + " pending tests\n");
+ prevNumPendingTests = numPendingChildTests;
+ }
+
+ if (numPendingChildTests > 0) {
+ SimpleTest.executeSoon(function() { waitForPendingTests(next); });
+ return;
+ }
+
+ prevNumPendingTests = null;
+ next();
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_AlertInFrame.js b/dom/browser-element/mochitest/browserElement_AlertInFrame.js
new file mode 100644
index 000000000..e9b606154
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_AlertInFrame.js
@@ -0,0 +1,24 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that alert works from inside an <iframe> inside an <iframe mozbrowser>.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ is(e.detail.message, 'Hello');
+ SimpleTest.finish();
+ });
+
+ iframe.src = 'file_browserElement_AlertInFrame.html';
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_AudioChannel.js b/dom/browser-element/mochitest/browserElement_AudioChannel.js
new file mode 100644
index 000000000..20f7b4e47
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_AudioChannel.js
@@ -0,0 +1,199 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 1113086 - tests for AudioChannel API into BrowserElement
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+function noaudio() {
+ info("Test : no-audio");
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ iframe.src = 'chrome://mochitests/content/chrome/dom/browser-element/mochitest/file_empty.html';
+
+ function noaudio_loadend() {
+ ok("mute" in iframe, "iframe.mute exists");
+ ok("unmute" in iframe, "iframe.unmute exists");
+ ok("getMuted" in iframe, "iframe.getMuted exists");
+ ok("getVolume" in iframe, "iframe.getVolume exists");
+ ok("setVolume" in iframe, "iframe.setVolume exists");
+
+ ok("allowedAudioChannels" in iframe, "allowedAudioChannels exist");
+ var channels = iframe.allowedAudioChannels;
+ is(channels.length, 9, "9 audio channel by default");
+
+ var ac = channels[0];
+
+ ok(ac instanceof BrowserElementAudioChannel, "Correct class");
+ ok("getVolume" in ac, "ac.getVolume exists");
+ ok("setVolume" in ac, "ac.setVolume exists");
+ ok("getMuted" in ac, "ac.getMuted exists");
+ ok("setMuted" in ac, "ac.setMuted exists");
+ ok("isActive" in ac, "ac.isActive exists");
+
+ new Promise(function(r, rr) {
+ var req = ac.getVolume();
+ ok(req instanceof DOMRequest, "This is a domRequest.");
+ req.onsuccess = function(e) {
+ is(e.target.result, 1.0, "The default volume should be 1.0");
+ r();
+ }
+ })
+
+ .then(function() {
+ return new Promise(function(resolve) {
+ iframe.mute();
+ iframe.getMuted()
+ .then(result => is(result, true, "iframe.getMuted should be true."))
+ .then(resolve);
+ });
+ })
+
+ .then(function() {
+ return new Promise(function(resolve) {
+ iframe.unmute();
+ iframe.getMuted()
+ .then(result => is(result, false, "iframe.getMuted should be false."))
+ .then(resolve);
+ });
+ })
+
+ .then(function() {
+ return new Promise(function(resolve) {
+ iframe.setVolume(0);
+ iframe.getVolume()
+ .then(result => is(result, 0, "iframe.getVolume should be 0."))
+ .then(resolve);
+ });
+ })
+
+ .then(function() {
+ return new Promise(function(resolve) {
+ iframe.setVolume(1);
+ iframe.getVolume()
+ .then(result => is(result, 1, "iframe.getVolume should be 1."))
+ .then(resolve);
+ });
+ })
+
+ .then(function() {
+ return new Promise(function(r, rr) {
+ ac.getMuted().onsuccess = function(e) {
+ is(e.target.result, false, "The default muted value should be false");
+ r();
+ }
+ });
+ })
+
+ .then(function() {
+ return new Promise(function(r, rr) {
+ ac.setVolume(0.8).onsuccess = function() { r(); }
+ });
+ })
+
+ .then(function() {
+ return new Promise(function(r, rr) {
+ ac.getVolume().onsuccess = function(e) {
+ // the actual value is 0.800000011920929..
+ ok(Math.abs(0.8 - e.target.result) < 0.01, "The new volume should be 0.8: " + e.target.result);
+ r();
+ }
+ });
+ })
+
+ .then(function() {
+ return new Promise(function(r, rr) {
+ ac.setVolume(1.0).onsuccess = function() { r(); }
+ });
+ })
+
+ .then(function() {
+ return new Promise(function(r, rr) {
+ ac.setMuted(true).onsuccess = function() { r(); }
+ });
+ })
+
+ .then(function() {
+ return new Promise(function(r, rr) {
+ ac.getMuted().onsuccess = function(e) {
+ is(e.target.result, true, "The new muted value should be true");
+ r();
+ }
+ });
+ })
+
+ .then(function() {
+ return new Promise(function(r, rr) {
+ ac.isActive().onsuccess = function(e) {
+ is(e.target.result, false, "ac.isActive is false: no audio element active.");
+ r();
+ }
+ });
+ })
+
+ .then(runTests);
+ }
+
+ iframe.addEventListener('mozbrowserloadend', noaudio_loadend);
+ document.body.appendChild(iframe);
+}
+
+function audio() {
+ info("Test : audio");
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ iframe.src = 'chrome://mochitests/content/chrome/dom/browser-element/mochitest/iframe_file_audio.html';
+
+ function audio_loadend() {
+ ok("mute" in iframe, "iframe.mute exists");
+ ok("unmute" in iframe, "iframe.unmute exists");
+ ok("getMuted" in iframe, "iframe.getMuted exists");
+ ok("getVolume" in iframe, "iframe.getVolume exists");
+ ok("setVolume" in iframe, "iframe.setVolume exists");
+
+ ok("allowedAudioChannels" in iframe, "allowedAudioChannels exist");
+ var channels = iframe.allowedAudioChannels;
+ is(channels.length, 9, "9 audio channel by default");
+
+ var ac = channels[0];
+
+ ok(ac instanceof BrowserElementAudioChannel, "Correct class");
+ ok("getVolume" in ac, "ac.getVolume exists");
+ ok("setVolume" in ac, "ac.setVolume exists");
+ ok("getMuted" in ac, "ac.getMuted exists");
+ ok("setMuted" in ac, "ac.setMuted exists");
+ ok("isActive" in ac, "ac.isActive exists");
+
+ ac.onactivestatechanged = function() {
+ ok(true, "activestatechanged event received.");
+ ac.onactivestatechanged = null;
+ document.body.removeChild(iframe);
+ runTests();
+ }
+ }
+
+ iframe.addEventListener('mozbrowserloadend', audio_loadend);
+ document.body.appendChild(iframe);
+}
+
+var tests = [ noaudio, audio ];
+
+function runTests() {
+ if (tests.length == 0) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+addEventListener('testready', function() {
+ SpecialPowers.pushPrefEnv({'set': [["b2g.system_startup_url", window.location.href]]},
+ function() {
+ SimpleTest.executeSoon(runTests);
+ });
+});
diff --git a/dom/browser-element/mochitest/browserElement_AudioChannelMutedByDefault.js b/dom/browser-element/mochitest/browserElement_AudioChannelMutedByDefault.js
new file mode 100644
index 000000000..897c4318a
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_AudioChannelMutedByDefault.js
@@ -0,0 +1,103 @@
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+var fileURL = 'chrome://mochitests/content/chrome/dom/browser-element/mochitest/file_browserElement_AudioChannelMutedByDefault.html';
+var testFrame;
+var ac;
+
+function alertListener(e) {
+ var message = e.detail.message
+ if (/^OK/.exec(message)) {
+ ok(true, "Message from file : " + message);
+ } else if (/^KO/.exec(message)) {
+ error(message);
+ } else if (/DONE/.exec(message)) {
+ ok(true, "Audio playback success!");
+ finish();
+ } else {
+ error("Undefined event.");
+ }
+}
+
+function assert(aVal, aMessage) {
+ return (!aVal) ? error(aMessage) : 0;
+}
+
+function error(aMessage) {
+ ok(false, "Error : " + aMessage);
+ finish();
+}
+
+function finish() {
+ testFrame.removeEventListener('mozbrowsershowmodalprompt', alertListener);
+ document.body.removeChild(testFrame);
+ SimpleTest.finish();
+}
+
+function setCommand(aArg) {
+ assert(!!ac, "Audio channel doesn't exist!");
+ info("# Command = " + aArg);
+ testFrame.src = fileURL + '#' + aArg;
+
+ switch (aArg) {
+ case 'play':
+ ac.onactivestatechanged = () => {
+ ac.onactivestatechanged = null;
+ ok(true, "activestatechanged event received.");
+
+ new Promise(function(r, rr) {
+ ac.getMuted().onsuccess = function(e) {
+ is(e.target.result, true, "Muted channel by default");
+ r();
+ }
+ }).then(function() {
+ ac.setMuted(false).onsuccess = function(e) {
+ ok(true, "Unmuted the channel.");
+ }
+ });
+ };
+ break;
+ default :
+ error("Undefined command!");
+ }
+}
+
+function runTests() {
+ setCommand('play');
+}
+
+function setupTestFrame() {
+ testFrame = document.createElement('iframe');
+ testFrame.setAttribute('mozbrowser', 'true');
+ testFrame.src = fileURL;
+
+ function loadend() {
+ testFrame.removeEventListener('mozbrowserloadend', loadend);
+ ok("allowedAudioChannels" in testFrame, "allowedAudioChannels exist");
+ var channels = testFrame.allowedAudioChannels;
+ is(channels.length, 9, "9 audio channel by default");
+
+ ac = channels[0];
+ ok(ac instanceof BrowserElementAudioChannel, "Correct class");
+ ok("getMuted" in ac, "ac.getMuted exists");
+ ok("setMuted" in ac, "ac.setMuted exists");
+ ok("onactivestatechanged" in ac, "onactivestatechanged exists");
+
+ runTests();
+ }
+
+ info("Set EventListeners.");
+ testFrame.addEventListener('mozbrowsershowmodalprompt', alertListener);
+ testFrame.addEventListener('mozbrowserloadend', loadend);
+ document.body.appendChild(testFrame);
+}
+
+addEventListener('testready', function() {
+ SpecialPowers.pushPrefEnv({'set': [["b2g.system_startup_url", window.location.href],
+ ["dom.audiochannel.mutedByDefault", true]]},
+ function() {
+ SimpleTest.executeSoon(setupTestFrame);
+ });
+});
diff --git a/dom/browser-element/mochitest/browserElement_AudioChannelSeeking.js b/dom/browser-element/mochitest/browserElement_AudioChannelSeeking.js
new file mode 100644
index 000000000..f354a9d82
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_AudioChannelSeeking.js
@@ -0,0 +1,128 @@
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+var fileURL = 'chrome://mochitests/content/chrome/dom/browser-element/mochitest/file_browserElement_AudioChannelSeeking.html';
+var generator = runTests();
+var testFrame;
+var ac;
+
+function alertListener(e) {
+ var message = e.detail.message
+ if (/^OK/.exec(message)) {
+ ok(true, "Message from file : " + message);
+ continueTest();
+ } else if (/^KO/.exec(message)) {
+ error(message);
+ } else if (/^INFO/.exec(message)) {
+ info("Message from file : " + message);
+ } else {
+ error("Undefined event.");
+ }
+}
+
+function assert(aVal, aMessage) {
+ return (!aVal) ? error(aMessage) : 0;
+}
+
+function error(aMessage) {
+ ok(false, "Error : " + aMessage);
+ finish();
+}
+
+function continueTest() {
+ try {
+ generator.next();
+ } catch (e if e instanceof StopIteration) {
+ error("Stop test because of exception!");
+ }
+}
+
+function finish() {
+ testFrame.removeEventListener('mozbrowsershowmodalprompt', alertListener);
+ ok(true, "Remove event-listener.");
+ document.body.removeChild(testFrame);
+ ok(true, "Remove test-frame from document.");
+ SimpleTest.finish();
+}
+
+function setCommand(aArg) {
+ assert(!!ac, "Audio channel doesn't exist!");
+ info("# Command = " + aArg);
+ testFrame.src = fileURL + '#' + aArg;
+
+ switch (aArg) {
+ case 'play':
+ ac.onactivestatechanged = () => {
+ ac.onactivestatechanged = null;
+ ok(true, "Receive onactivestatechanged after audio started.");
+ continueTest();
+ };
+ break;
+ case 'seeking':
+ ac.onactivestatechanged = () => {
+ ac.onactivestatechanged = null;
+ error("Should not receive onactivestatechanged during seeking!");
+ };
+ break;
+ case 'pause':
+ ac.onactivestatechanged = null;
+ break;
+ default :
+ error("Undefined command!");
+ }
+}
+
+function runTests() {
+ setCommand('play');
+ yield undefined;
+
+ setCommand('seeking');
+ yield undefined;
+
+ setCommand('seeking');
+ yield undefined;
+
+ setCommand('seeking');
+ yield undefined;
+
+ setCommand('pause');
+ yield undefined;
+
+ finish();
+ yield undefined;
+}
+
+function setupTestFrame() {
+ testFrame = document.createElement('iframe');
+ testFrame.setAttribute('mozbrowser', 'true');
+ testFrame.src = fileURL;
+
+ function loadend() {
+ testFrame.removeEventListener('mozbrowserloadend', loadend);
+ ok("allowedAudioChannels" in testFrame, "allowedAudioChannels exist");
+ var channels = testFrame.allowedAudioChannels;
+ is(channels.length, 9, "9 audio channel by default");
+
+ ac = channels[0];
+ ok(ac instanceof BrowserElementAudioChannel, "Correct class");
+ ok("onactivestatechanged" in ac, "onactivestatechanged exists");
+
+ continueTest();
+ }
+
+ testFrame.addEventListener('mozbrowsershowmodalprompt', alertListener);
+ testFrame.addEventListener('mozbrowserloadend', loadend);
+ ok(true, "Add event-listeners.");
+
+ document.body.appendChild(testFrame);
+ ok(true, "Append test-frame to document.");
+}
+
+addEventListener('testready', function() {
+ SpecialPowers.pushPrefEnv({'set': [["b2g.system_startup_url", window.location.href]]},
+ function() {
+ SimpleTest.executeSoon(setupTestFrame);
+ });
+});
diff --git a/dom/browser-element/mochitest/browserElement_AudioChannel_nested.js b/dom/browser-element/mochitest/browserElement_AudioChannel_nested.js
new file mode 100644
index 000000000..2ed432b2a
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_AudioChannel_nested.js
@@ -0,0 +1,69 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 1113086 - tests for AudioChannel API into BrowserElement
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+function runTests() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ var listener = function(e) {
+ var message = e.detail.message;
+ if (/^OK/.exec(message)) {
+ ok(true, "Message from app: " + message);
+ } else if (/^KO/.exec(message)) {
+ ok(false, "Message from app: " + message);
+ } else if (/DONE/.exec(message)) {
+ ok(true, "Messaging from app complete");
+ iframe.removeEventListener('mozbrowsershowmodalprompt', listener);
+ SimpleTest.finish();
+ }
+ }
+
+ function audio_loadend() {
+ ok("mute" in iframe, "iframe.mute exists");
+ ok("unmute" in iframe, "iframe.unmute exists");
+ ok("getMuted" in iframe, "iframe.getMuted exists");
+ ok("getVolume" in iframe, "iframe.getVolume exists");
+ ok("setVolume" in iframe, "iframe.setVolume exists");
+
+ ok("allowedAudioChannels" in iframe, "allowedAudioChannels exist");
+ var channels = iframe.allowedAudioChannels;
+ is(channels.length, 9, "9 audio channel by default");
+
+ var ac = channels[0];
+
+ ok(ac instanceof BrowserElementAudioChannel, "Correct class");
+ ok("getVolume" in ac, "ac.getVolume exists");
+ ok("setVolume" in ac, "ac.setVolume exists");
+ ok("getMuted" in ac, "ac.getMuted exists");
+ ok("setMuted" in ac, "ac.setMuted exists");
+ ok("isActive" in ac, "ac.isActive exists");
+
+ info("Setting the volume...");
+ ac.setVolume(0.5);
+
+ ac.onactivestatechanged = function() {
+ ok(true, "activestatechanged event received.");
+ ac.onactivestatechanged = null;
+ }
+ }
+
+ iframe.addEventListener('mozbrowserloadend', audio_loadend);
+ iframe.addEventListener('mozbrowsershowmodalprompt', listener, false);
+ document.body.appendChild(iframe);
+
+ iframe.src = 'chrome://mochitests/content/chrome/dom/browser-element/mochitest/file_browserElement_AudioChannel_nested.html';
+}
+
+addEventListener('testready', function() {
+ SpecialPowers.pushPrefEnv({'set': [["b2g.system_startup_url", window.location.href]]},
+ function() {
+ SimpleTest.executeSoon(runTests);
+ });
+});
diff --git a/dom/browser-element/mochitest/browserElement_AudioPlayback.js b/dom/browser-element/mochitest/browserElement_AudioPlayback.js
new file mode 100644
index 000000000..bcbe89cb1
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_AudioPlayback.js
@@ -0,0 +1,75 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the mozbrowseraudioplaybackchange event is fired correctly.
+'use strict';
+
+const { Services } = SpecialPowers.Cu.import('resource://gre/modules/Services.jsm');
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+/**
+ * Content script passed to the child iframe
+ */
+function playAudioScript() {
+ var audio = new content.Audio();
+ content.document.body.appendChild(audio);
+ audio.oncanplay = function() {
+ audio.play();
+ };
+ audio.src = 'audio.ogg';
+}
+
+/**
+ * Creates a simple mozbrowser frame
+ */
+function createFrame() {
+ let iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+ return iframe;
+}
+
+function runTest() {
+ SimpleTest.waitForExplicitFinish();
+
+ let iframe = createFrame();
+ let iframe2 = createFrame();
+
+ // When the first iframe is finished loading inject a script to create
+ // an audio element and play it.
+ iframe.addEventListener('mozbrowserloadend', () => {
+ let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+ mm.loadFrameScript('data:,(' + playAudioScript.toString() + ')();', false);
+ });
+
+ // Two events should come in, when the audio starts, and stops playing.
+ // The first one should have a detail of 'active' and the second one
+ // should have a detail of 'inactive-pause'.
+ let expectedNextData = 'active';
+ iframe.addEventListener('mozbrowseraudioplaybackchange', (e) => {
+ is(e.detail, expectedNextData, 'Audio detail should be correct')
+ is(e.target, iframe, 'event target should be the first iframe')
+ if (e.detail === 'inactive-pause') {
+ SimpleTest.finish();
+ }
+ expectedNextData = 'inactive-pause';
+ });
+
+ // Make sure an event only goes to the first iframe.
+ iframe2.addEventListener('mozbrowseraudioplaybackchange', (e) => {
+ ok(false,
+ 'mozbrowseraudioplaybackchange should dispatch to the correct browser');
+ });
+
+ // Load a simple page to get the process started.
+ iframe.src = browserElementTestHelpers.fileEmptyPage1;
+}
+
+addEventListener('testready', function() {
+ SpecialPowers.pushPrefEnv({'set': [["b2g.system_startup_url", window.location.href]]},
+ function() {
+ SimpleTest.executeSoon(runTest);
+ });
+});
diff --git a/dom/browser-element/mochitest/browserElement_Auth.js b/dom/browser-element/mochitest/browserElement_Auth.js
new file mode 100644
index 000000000..ef95409be
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Auth.js
@@ -0,0 +1,246 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that auth prompt works.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+const { NetUtil } = SpecialPowers.Cu.import('resource://gre/modules/NetUtil.jsm');
+
+function testFail(msg) {
+ ok(false, JSON.stringify(msg));
+}
+
+var iframe;
+
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+
+ // Wait for the initial load to finish, then navigate the page, then start test
+ // by loading SJS with http 401 response.
+ iframe.addEventListener('mozbrowserloadend', function loadend() {
+ iframe.removeEventListener('mozbrowserloadend', loadend);
+ iframe.addEventListener('mozbrowserusernameandpasswordrequired', testHttpAuthCancel);
+ SimpleTest.executeSoon(function() {
+ // Use absolute path because we need to specify host.
+ iframe.src = 'http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs';
+ });
+ });
+}
+
+function testHttpAuthCancel(e) {
+ iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testHttpAuthCancel);
+ // Will cancel authentication, but prompt should not be shown again. Instead,
+ // we will be led to fail message
+ iframe.addEventListener("mozbrowserusernameandpasswordrequired", testFail);
+ iframe.addEventListener("mozbrowsertitlechange", function onTitleChange(e) {
+ iframe.removeEventListener("mozbrowsertitlechange", onTitleChange);
+ iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testFail);
+ is(e.detail, 'http auth failed', 'expected authentication to fail');
+ iframe.addEventListener('mozbrowserusernameandpasswordrequired', testHttpAuth);
+ SimpleTest.executeSoon(function() {
+ // Use absolute path because we need to specify host.
+ iframe.src = 'http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs';
+ });
+ });
+
+ is(e.detail.realm, 'http_realm', 'expected realm matches');
+ is(e.detail.host, 'http://test', 'expected host matches');
+ is(e.detail.path,
+ '/tests/dom/browser-element/mochitest/file_http_401_response.sjs',
+ 'expected path matches');
+ e.preventDefault();
+
+ SimpleTest.executeSoon(function() {
+ e.detail.cancel();
+ });
+}
+
+function testHttpAuth(e) {
+ iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testHttpAuth);
+
+ // Will authenticate with correct password, prompt should not be
+ // called again.
+ iframe.addEventListener("mozbrowserusernameandpasswordrequired", testFail);
+ iframe.addEventListener("mozbrowsertitlechange", function onTitleChange(e) {
+ iframe.removeEventListener("mozbrowsertitlechange", onTitleChange);
+ iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testFail);
+ is(e.detail, 'http auth success', 'expect authentication to succeed');
+ SimpleTest.executeSoon(testProxyAuth);
+ });
+
+ is(e.detail.realm, 'http_realm', 'expected realm matches');
+ is(e.detail.host, 'http://test', 'expected host matches');
+ is(e.detail.path,
+ '/tests/dom/browser-element/mochitest/file_http_401_response.sjs',
+ 'expected path matches');
+ is(e.detail.isProxy, false, 'expected isProxy is false');
+ e.preventDefault();
+
+ SimpleTest.executeSoon(function() {
+ e.detail.authenticate("httpuser", "httppass");
+ });
+}
+
+function testProxyAuth(e) {
+ // The testingSJS simulates the 407 proxy authentication required response
+ // for proxy server, which will trigger the browser element to send prompt
+ // event with proxy infomation.
+ var testingSJS = 'http://test/tests/dom/browser-element/mochitest/file_http_407_response.sjs';
+ var mozproxy;
+
+ function onUserNameAndPasswordRequired(e) {
+ iframe.removeEventListener("mozbrowserusernameandpasswordrequired",
+ onUserNameAndPasswordRequired);
+ iframe.addEventListener("mozbrowsertitlechange", function onTitleChange(e) {
+ iframe.removeEventListener("mozbrowsertitlechange", onTitleChange);
+ iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testFail);
+ is(e.detail, 'http auth success', 'expect authentication to succeed');
+ SimpleTest.executeSoon(testAuthJarNoInterfere);
+ });
+
+ is(e.detail.realm, 'http_realm', 'expected realm matches');
+ is(e.detail.host, mozproxy, 'expected host matches');
+ is(e.detail.path,
+ '/tests/dom/browser-element/mochitest/file_http_407_response.sjs',
+ 'expected path matches');
+ is(e.detail.isProxy, true, 'expected isProxy is true');
+ e.preventDefault();
+
+ SimpleTest.executeSoon(function() {
+ e.detail.authenticate("proxyuser", "proxypass");
+ });
+ }
+
+ // Resolve proxy information used by the test suite, we need it to validate
+ // whether the proxy information delivered with the prompt event is correct.
+ var resolveCallback = SpecialPowers.wrapCallbackObject({
+ QueryInterface: function (iid) {
+ const interfaces = [Ci.nsIProtocolProxyCallback, Ci.nsISupports];
+
+ if (!interfaces.some( function(v) { return iid.equals(v) } )) {
+ throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE;
+ }
+ return this;
+ },
+
+ onProxyAvailable: function (req, channel, pi, status) {
+ isnot(pi, null, 'expected proxy information available');
+ if (pi) {
+ mozproxy = "moz-proxy://" + pi.host + ":" + pi.port;
+ }
+ iframe.addEventListener("mozbrowserusernameandpasswordrequired",
+ onUserNameAndPasswordRequired);
+
+ iframe.src = testingSJS;
+ }
+ });
+
+ var channel = NetUtil.newChannel({
+ uri: testingSJS,
+ loadUsingSystemPrincipal: true
+ });
+
+ var pps = SpecialPowers.Cc["@mozilla.org/network/protocol-proxy-service;1"]
+ .getService();
+
+ pps.asyncResolve(channel, 0, resolveCallback);
+}
+
+function testAuthJarNoInterfere(e) {
+ var authMgr = SpecialPowers.Cc['@mozilla.org/network/http-auth-manager;1']
+ .getService(SpecialPowers.Ci.nsIHttpAuthManager);
+ var secMan = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"]
+ .getService(SpecialPowers.Ci.nsIScriptSecurityManager);
+ var ioService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
+ .getService(SpecialPowers.Ci.nsIIOService);
+ var uri = ioService.newURI("http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs", null, null);
+
+ // Set a bunch of auth data that should not conflict with the correct auth data already
+ // stored in the cache.
+ var attrs = {appId: 1};
+ var principal = secMan.createCodebasePrincipal(uri, attrs);
+ authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
+ 'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
+ '', 'httpuser', 'wrongpass', false, principal);
+ attrs = {appId: 1, inIsolatedMozBrowser: true};
+ principal = secMan.createCodebasePrincipal(uri, attrs);
+ authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
+ 'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
+ '', 'httpuser', 'wrongpass', false, principal);
+ principal = secMan.createCodebasePrincipal(uri, {});
+ authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
+ 'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
+ '', 'httpuser', 'wrongpass', false, principal);
+
+ // Will authenticate with correct password, prompt should not be
+ // called again.
+ iframe.addEventListener("mozbrowserusernameandpasswordrequired", testFail);
+ iframe.addEventListener("mozbrowsertitlechange", function onTitleChange(e) {
+ iframe.removeEventListener("mozbrowsertitlechange", onTitleChange);
+ iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testFail);
+ is(e.detail, 'http auth success', 'expected authentication success');
+ SimpleTest.executeSoon(testAuthJarInterfere);
+ });
+
+ // Once more with feeling. Ensure that our new auth data doesn't interfere with this mozbrowser's
+ // auth data.
+ iframe.src = 'http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs';
+}
+
+function testAuthJarInterfere(e) {
+ var authMgr = SpecialPowers.Cc['@mozilla.org/network/http-auth-manager;1']
+ .getService(SpecialPowers.Ci.nsIHttpAuthManager);
+ var secMan = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"]
+ .getService(SpecialPowers.Ci.nsIScriptSecurityManager);
+ var ioService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
+ .getService(SpecialPowers.Ci.nsIIOService);
+ var uri = ioService.newURI("http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs", null, null);
+
+ // Set some auth data that should overwrite the successful stored details.
+ var principal = secMan.createCodebasePrincipal(uri, {inIsolatedMozBrowser: true});
+ authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
+ 'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
+ '', 'httpuser', 'wrongpass', false, principal);
+
+ // Will authenticate with correct password, prompt should not be
+ // called again.
+ var gotusernamepasswordrequired = false;
+ function onUserNameAndPasswordRequired() {
+ gotusernamepasswordrequired = true;
+ }
+ iframe.addEventListener("mozbrowserusernameandpasswordrequired",
+ onUserNameAndPasswordRequired);
+ iframe.addEventListener("mozbrowsertitlechange", function onTitleChange(e) {
+ iframe.removeEventListener("mozbrowsertitlechange", onTitleChange);
+ iframe.removeEventListener("mozbrowserusernameandpasswordrequired",
+ onUserNameAndPasswordRequired);
+ ok(gotusernamepasswordrequired,
+ "Should have dispatched mozbrowserusernameandpasswordrequired event");
+ testFinish();
+ });
+
+ // Once more with feeling. Ensure that our new auth data interferes with this mozbrowser's
+ // auth data.
+ iframe.src = 'http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs';
+}
+
+function testFinish() {
+ // Clear login information stored in password manager.
+ var authMgr = SpecialPowers.Cc['@mozilla.org/network/http-auth-manager;1']
+ .getService(SpecialPowers.Ci.nsIHttpAuthManager);
+ authMgr.clearAll();
+
+ var pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"]
+ .getService(SpecialPowers.Ci.nsILoginManager);
+ pwmgr.removeAllLogins();
+
+ SimpleTest.finish();
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_BackForward.js b/dom/browser-element/mochitest/browserElement_BackForward.js
new file mode 100644
index 000000000..26b6344c4
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_BackForward.js
@@ -0,0 +1,104 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 741755 - Test that canGo{Back,Forward} and go{Forward,Back} work with
+// <iframe mozbrowser>.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+var iframe;
+function addOneShotIframeEventListener(event, fn) {
+ function wrapper(e) {
+ iframe.removeEventListener(event, wrapper);
+ fn(e);
+ };
+
+ iframe.addEventListener(event, wrapper);
+}
+
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ addOneShotIframeEventListener('mozbrowserloadend', function() {
+ SimpleTest.executeSoon(test2);
+ });
+
+ iframe.src = browserElementTestHelpers.emptyPage1;
+ document.body.appendChild(iframe);
+}
+
+function checkCanGoBackAndForward(canGoBack, canGoForward, nextTest) {
+ var seenCanGoBackResult = false;
+ iframe.getCanGoBack().onsuccess = function(e) {
+ is(seenCanGoBackResult, false, "onsuccess handler shouldn't be called twice.");
+ seenCanGoBackResult = true;
+ is(e.target.result, canGoBack);
+ maybeRunNextTest();
+ };
+
+ var seenCanGoForwardResult = false;
+ iframe.getCanGoForward().onsuccess = function(e) {
+ is(seenCanGoForwardResult, false, "onsuccess handler shouldn't be called twice.");
+ seenCanGoForwardResult = true;
+ is(e.target.result, canGoForward);
+ maybeRunNextTest();
+ };
+
+ function maybeRunNextTest() {
+ if (seenCanGoBackResult && seenCanGoForwardResult) {
+ nextTest();
+ }
+ }
+}
+
+function test2() {
+ checkCanGoBackAndForward(false, false, test3);
+}
+
+function test3() {
+ addOneShotIframeEventListener('mozbrowserloadend', function() {
+ checkCanGoBackAndForward(true, false, test4);
+ });
+
+ SimpleTest.executeSoon(function() {
+ iframe.src = browserElementTestHelpers.emptyPage2;
+ });
+}
+
+function test4() {
+ addOneShotIframeEventListener('mozbrowserlocationchange', function(e) {
+ is(e.detail.url, browserElementTestHelpers.emptyPage3);
+ is(e.detail.canGoBack, true);
+ is(e.detail.canGoForward, false);
+ checkCanGoBackAndForward(true, false, test5);
+ });
+
+ SimpleTest.executeSoon(function() {
+ iframe.src = browserElementTestHelpers.emptyPage3;
+ });
+}
+
+function test5() {
+ addOneShotIframeEventListener('mozbrowserlocationchange', function(e) {
+ is(e.detail.url, browserElementTestHelpers.emptyPage2);
+ is(e.detail.canGoBack, true);
+ is(e.detail.canGoForward, true);
+ checkCanGoBackAndForward(true, true, test6);
+ });
+ iframe.goBack();
+}
+
+function test6() {
+ addOneShotIframeEventListener('mozbrowserlocationchange', function(e) {
+ is(e.detail.url, browserElementTestHelpers.emptyPage1);
+ is(e.detail.canGoBack, false);
+ is(e.detail.canGoForward, true);
+ checkCanGoBackAndForward(false, true, SimpleTest.finish);
+ });
+ iframe.goBack();
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_BadScreenshot.js b/dom/browser-element/mochitest/browserElement_BadScreenshot.js
new file mode 100644
index 000000000..7b194da86
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_BadScreenshot.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 800170 - Test that we get errors when we pass bad arguments to
+// mozbrowser's getScreenshot.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+var iframe;
+var numPendingTests = 0;
+
+// Call iframe.getScreenshot with the given args. If expectSuccess is true, we
+// expect the screenshot's onsuccess handler to fire. Otherwise, we expect
+// getScreenshot() to throw an exception.
+function checkScreenshotResult(expectSuccess, args) {
+ var req;
+ try {
+ req = iframe.getScreenshot.apply(iframe, args);
+ }
+ catch(e) {
+ ok(!expectSuccess, "getScreenshot(" + JSON.stringify(args) + ") threw an exception.");
+ return;
+ }
+
+ numPendingTests++;
+ req.onsuccess = function() {
+ ok(expectSuccess, "getScreenshot(" + JSON.stringify(args) + ") succeeded.");
+ numPendingTests--;
+ if (numPendingTests == 0) {
+ SimpleTest.finish();
+ }
+ };
+
+ // We never expect to see onerror.
+ req.onerror = function() {
+ ok(false, "getScreenshot(" + JSON.stringify(args) + ") ran onerror.");
+ numPendingTests--;
+ if (numPendingTests == 0) {
+ SimpleTest.finish();
+ }
+ };
+}
+
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+ iframe.src = 'data:text/html,<html>' +
+ '<body style="background:green">hello</body></html>';
+
+ iframe.addEventListener('mozbrowserfirstpaint', function() {
+ // This one should succeed.
+ checkScreenshotResult(true, [100, 100]);
+
+ // These should fail.
+ checkScreenshotResult(false, []);
+ checkScreenshotResult(false, [100]);
+ checkScreenshotResult(false, ['a', 100]);
+ checkScreenshotResult(false, [100, 'a']);
+ checkScreenshotResult(false, [-1, 100]);
+ checkScreenshotResult(false, [100, -1]);
+
+ if (numPendingTests == 0) {
+ SimpleTest.finish();
+ }
+ });
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_BrowserWindowNamespace.js b/dom/browser-element/mochitest/browserElement_BrowserWindowNamespace.js
new file mode 100644
index 000000000..87c4a216c
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_BrowserWindowNamespace.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 780351 - Test that mozbrowser does /not/ divide the window name namespace.
+// Multiple mozbrowsers inside the same app are like multiple browser tabs;
+// they share a window name namespace.
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+
+ // Two mozbrowser frames with the same code both do the same
+ // window.open("foo", "bar") call. We should only get one
+ // mozbrowseropenwindow event.
+
+ iframe1.addEventListener('mozbrowseropenwindow', function(e) {
+ ok(true, "Got first mozbrowseropenwindow event.");
+ document.body.appendChild(e.detail.frameElement);
+
+ e.detail.frameElement.addEventListener('mozbrowserlocationchange', function(e) {
+ if (e.detail.url == "http://example.com/#2") {
+ ok(true, "Got locationchange to http://example.com/#2");
+ SimpleTest.finish();
+ }
+ else {
+ ok(true, "Got locationchange to " + e.detail.url);
+ }
+ });
+
+ SimpleTest.executeSoon(function() {
+ var iframe2 = document.createElement('iframe');
+ // Make sure that iframe1 and iframe2 are in the same TabGroup by linking
+ // them through opener. Right now this API requires chrome privileges, as
+ // it is on MozFrameLoaderOwner.
+ SpecialPowers.wrap(iframe2).presetOpenerWindow(iframe1.contentWindow);
+ iframe2.setAttribute('mozbrowser', 'true');
+
+ iframe2.addEventListener('mozbrowseropenwindow', function(e) {
+ ok(false, "Got second mozbrowseropenwindow event.");
+ });
+
+ document.body.appendChild(iframe2);
+ iframe2.src = 'file_browserElement_BrowserWindowNamespace.html#2';
+ });
+ });
+
+ document.body.appendChild(iframe1);
+ iframe1.src = 'file_browserElement_BrowserWindowNamespace.html#1';
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_BrowserWindowResize.js b/dom/browser-element/mochitest/browserElement_BrowserWindowResize.js
new file mode 100644
index 000000000..420b4bc34
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_BrowserWindowResize.js
@@ -0,0 +1,51 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 891763 - Test the mozbrowserresize event
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var srcResizeTo = "data:text/html, \
+ <script type='application/javascript'> \
+ window.resizeTo(300, 300); \
+ <\/script> \
+ ";
+
+ var srcResizeBy = "data:text/html, \
+ <script type='application/javascript'> \
+ window.resizeBy(-100, -100); \
+ <\/script> \
+ ";
+
+ var count = 0;
+ function checkSize(iframe) {
+ count++;
+ is(iframe.clientWidth, 400, "iframe width does not change");
+ is(iframe.clientHeight, 400, "iframe height does not change");
+ if (count == 2) {
+ SimpleTest.finish();
+ }
+ }
+
+ function testIFrameWithSrc(src) {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ iframe.style = "border:none; width:400px; height:400px;";
+ iframe.src = src;
+ iframe.addEventListener("mozbrowserresize", function (e) {
+ is(e.detail.width, 300, "Received correct resize event width");
+ is(e.detail.height, 300, "Received correct resize event height");
+ SimpleTest.executeSoon(checkSize.bind(undefined, iframe));
+ });
+ document.body.appendChild(iframe);
+ }
+
+ testIFrameWithSrc(srcResizeTo);
+ testIFrameWithSrc(srcResizeBy);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_Close.js b/dom/browser-element/mochitest/browserElement_Close.js
new file mode 100644
index 000000000..57bdf384d
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Close.js
@@ -0,0 +1,24 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that window.close() works.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+
+ iframe.addEventListener("mozbrowserclose", function(e) {
+ ok(true, "got mozbrowserclose event.");
+ SimpleTest.finish();
+ });
+
+ iframe.src = "data:text/html,<html><body><script>window.close()</scr"+"ipt></body></html>";
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_CloseFromOpener.js b/dom/browser-element/mochitest/browserElement_CloseFromOpener.js
new file mode 100644
index 000000000..65ea4d1b7
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_CloseFromOpener.js
@@ -0,0 +1,33 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 764718 - Test that window.close() works from the opener window.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ ok(true, "got openwindow event.");
+ document.body.appendChild(e.detail.frameElement);
+
+ e.detail.frameElement.addEventListener("mozbrowserclose", function(e) {
+ ok(true, "got mozbrowserclose event.");
+ SimpleTest.finish();
+ });
+ });
+
+
+ document.body.appendChild(iframe);
+
+ // file_browserElement_CloseFromOpener opens a new window and then calls
+ // close() on it.
+ iframe.src = "file_browserElement_CloseFromOpener.html";
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_ContextmenuEvents.js b/dom/browser-element/mochitest/browserElement_ContextmenuEvents.js
new file mode 100644
index 000000000..66aa8e015
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_ContextmenuEvents.js
@@ -0,0 +1,351 @@
+'use strict';
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.setClipboardPlainTextOnlyPref(false);
+browserElementTestHelpers.addPermission();
+
+var audioUrl = 'http://mochi.test:8888/tests/dom/browser-element/mochitest/audio.ogg';
+var videoUrl = 'http://mochi.test:8888/tests/dom/browser-element/mochitest/short-video.ogv';
+
+function runTests() {
+ createIframe(function onIframeLoaded() {
+ checkEmptyContextMenu();
+ });
+}
+
+function checkEmptyContextMenu() {
+ sendContextMenuTo('body', function onContextMenu(detail) {
+ is(detail.contextmenu, null, 'Body context clicks have no context menu');
+
+ checkInnerContextMenu();
+ });
+}
+
+function checkInnerContextMenu() {
+ sendContextMenuTo('#inner-link', function onContextMenu(detail) {
+ is(detail.systemTargets.length, 1, 'Includes anchor data');
+ is(detail.contextmenu.items.length, 3, 'Inner clicks trigger correct customized menu');
+ is(detail.contextmenu.items[0].label, 'foo', 'Customized menu has a "foo" menu item');
+ is(detail.contextmenu.items[1].label, 'bar', 'Customized menu has a "bar" menu item');
+ is(detail.contextmenu.items[2].id, 'copy-link', '#inner-link has a copy-link menu item');
+ is(detail.contextmenu.customized, true, 'Make sure contextmenu has customized items');
+
+ var target = detail.systemTargets[0];
+ is(target.nodeName, 'A', 'Reports correct nodeName');
+ is(target.data.uri, 'foo.html', 'Reports correct uri');
+ is(target.data.text, 'Menu 1', 'Reports correct link text');
+
+ checkCustomContextMenu();
+ });
+}
+
+function checkCustomContextMenu() {
+ sendContextMenuTo('#menu1-trigger', function onContextMenu(detail) {
+ is(detail.contextmenu.items.length, 2, 'trigger custom contextmenu');
+
+ checkNestedContextMenu();
+ });
+}
+
+function checkNestedContextMenu() {
+ sendContextMenuTo('#menu2-trigger', function onContextMenu(detail) {
+ var innerMenu = detail.contextmenu.items.filter(function(x) {
+ return x.type === 'menu';
+ });
+ is(detail.systemTargets.length, 2, 'Includes two systemTargets');
+ is(detail.systemTargets[0].nodeName, 'IMG', 'Includes "IMG" node');
+ is(detail.systemTargets[0].data.uri, 'example.png', 'Img data has the correct uri');
+ is(detail.systemTargets[1].nodeName, 'A', 'Includes "A" node');
+ is(detail.systemTargets[1].data.uri, 'bar.html', 'Anchor has the correct uri');
+ ok(innerMenu.length > 0, 'Menu contains a nested menu');
+
+ is(detail.contextmenu.items.length, 4, 'We have correct # of menu items')
+ is(detail.contextmenu.customized, true, 'Make sure contextmenu has customized items');
+ is(detail.contextmenu.items[0].label, 'outer', 'Customized menu has an "outer" menu item');
+ is(detail.contextmenu.items[1].label, 'submenu', 'Customized menu has an "submenu" menu item');
+ is(detail.contextmenu.items[2].id, 'copy-link', 'Has a copy-link menu item');
+ is(detail.contextmenu.items[3].id, 'copy-image', 'Has a copy-image menu item');
+ checkPreviousContextMenuHandler();
+ });
+}
+
+ // Finished testing the data passed to the contextmenu handler,
+ // now we start selecting contextmenu items
+function checkPreviousContextMenuHandler() {
+ // This is previously triggered contextmenu data, since we have
+ // fired subsequent contextmenus this should not be mistaken
+ // for a current menuitem
+ var detail = previousContextMenuDetail;
+ var previousId = detail.contextmenu.items[0].id;
+ checkContextMenuCallbackForId(detail, previousId, function onCallbackFired(label) {
+ is(label, null, 'Callback label should be empty since this handler is old');
+
+ checkCurrentContextMenuHandler();
+ });
+}
+
+function checkCurrentContextMenuHandler() {
+ // This triggers a current menuitem
+ var detail = currentContextMenuDetail;
+
+ var innerMenu = detail.contextmenu.items.filter(function(x) {
+ return x.type === 'menu';
+ });
+
+ var currentId = innerMenu[0].items[1].id;
+ checkContextMenuCallbackForId(detail, currentId, function onCallbackFired(label) {
+ is(label, 'inner 2', 'Callback label should be set correctly');
+
+ checkAgainCurrentContextMenuHandler();
+ });
+}
+
+function checkAgainCurrentContextMenuHandler() {
+ // Once an item it selected, subsequent selections are ignored
+ var detail = currentContextMenuDetail;
+
+ var innerMenu = detail.contextmenu.items.filter(function(x) {
+ return x.type === 'menu';
+ });
+
+ var currentId = innerMenu[0].items[1].id;
+ checkContextMenuCallbackForId(detail, currentId, function onCallbackFired(label) {
+ is(label, null, 'Callback label should be empty since this handler has already been used');
+
+ checkCallbackWithPreventDefault();
+ });
+};
+
+// Finished testing callbacks if the embedder calls preventDefault() on the
+// mozbrowsercontextmenu event, now we start checking for some cases where the embedder
+// does not want to call preventDefault() for some reasons.
+function checkCallbackWithPreventDefault() {
+ sendContextMenuTo('#menu1-trigger', function onContextMenu(detail) {
+ var id = detail.contextmenu.items[0].id;
+ checkContextMenuCallbackForId(detail, id, function onCallbackFired(label) {
+ is(label, 'foo', 'Callback label should be set correctly');
+
+ checkCallbackWithoutPreventDefault();
+ });
+ });
+}
+
+function checkCallbackWithoutPreventDefault() {
+ sendContextMenuTo('#menu1-trigger', function onContextMenu(detail) {
+ var id = detail.contextmenu.items[0].id;
+ checkContextMenuCallbackForId(detail, id, function onCallbackFired(label) {
+ is(label, null, 'Callback label should be null');
+
+ checkImageContextMenu();
+ });
+ }, /* ignorePreventDefault */ true);
+}
+
+function checkImageContextMenu() {
+ sendContextMenuTo('#menu3-trigger', function onContextMenu(detail) {
+ var target = detail.systemTargets[0];
+ is(target.nodeName, 'IMG', 'Reports correct nodeName');
+ is(target.data.uri, 'example.png', 'Reports correct uri');
+ is(detail.contextmenu.items.length, 1, 'Reports correct # of menu items');
+ is(detail.contextmenu.items[0].id, 'copy-image', 'IMG has a copy-image menu item');
+ is(detail.contextmenu.customized, false, 'Make sure we do not have customized items');
+
+ checkVideoContextMenu();
+ }, /* ignorePreventDefault */ true);
+}
+
+function checkVideoContextMenu() {
+ sendContextMenuTo('#menu4-trigger', function onContextMenu(detail) {
+ var target = detail.systemTargets[0];
+ is(target.nodeName, 'VIDEO', 'Reports correct nodeName');
+ is(target.data.uri, videoUrl, 'Reports uri correctly in data');
+ is(target.data.hasVideo, true, 'Video data in video tag does "hasVideo"');
+
+ checkAudioContextMenu();
+ }, /* ignorePreventDefault */ true);
+}
+
+function checkAudioContextMenu() {
+ sendContextMenuTo('#menu6-trigger', function onContextMenu(detail) {
+ var target = detail.systemTargets[0];
+ is(target.nodeName, 'AUDIO', 'Reports correct nodeName');
+ is(target.data.uri, audioUrl, 'Reports uri correctly in data');
+
+ checkAudioinVideoContextMenu();
+ }, /* ignorePreventDefault */ true);
+}
+
+function checkAudioinVideoContextMenu() {
+ sendSrcTo('#menu5-trigger', audioUrl, function onSrcSet() {
+ sendContextMenuTo('#menu5-trigger', function onContextMenu(detail) {
+ var target = detail.systemTargets[0];
+ is(target.nodeName, 'VIDEO', 'Reports correct nodeName');
+ is(target.data.uri, audioUrl, 'Reports uri correctly in data');
+ is(target.data.hasVideo, false, 'Audio data in video tag reports no "hasVideo"');
+
+ checkFormNoMethod();
+ }, /* ignorePreventDefault */ true);
+ });
+}
+
+function checkFormNoMethod() {
+ sendContextMenuTo('#menu7-trigger', function onContextMenu(detail) {
+ var target = detail.systemTargets[0];
+ is(target.nodeName, 'INPUT', 'Reports correct nodeName');
+ is(target.data.method, 'get', 'Reports correct method');
+ is(target.data.action, 'no_method', 'Reports correct action url');
+ is(target.data.name, 'input1', 'Reports correct input name');
+
+ checkFormGetMethod();
+ }, /* ignorePreventDefault */ true);
+}
+
+function checkFormGetMethod() {
+ sendContextMenuTo('#menu8-trigger', function onContextMenu(detail) {
+ var target = detail.systemTargets[0];
+ is(target.nodeName, 'INPUT', 'Reports correct nodeName');
+ is(target.data.method, 'get', 'Reports correct method');
+ is(target.data.action, 'http://example.com/get_method', 'Reports correct action url');
+ is(target.data.name, 'input2', 'Reports correct input name');
+
+ checkFormPostMethod();
+ }, /* ignorePreventDefault */ true);
+}
+
+function checkFormPostMethod() {
+ sendContextMenuTo('#menu9-trigger', function onContextMenu(detail) {
+ var target = detail.systemTargets[0];
+ is(target.nodeName, 'INPUT', 'Reports correct nodeName');
+ is(target.data.method, 'post', 'Reports correct method');
+ is(target.data.action, 'post_method', 'Reports correct action url');
+ is(target.data.name, 'input3', 'Reports correct input name');
+
+ SimpleTest.finish();
+ }, /* ignorePreventDefault */ true);
+}
+
+/* Helpers */
+var mm = null;
+var previousContextMenuDetail = null;
+var currentContextMenuDetail = null;
+
+function sendSrcTo(selector, src, callback) {
+ mm.sendAsyncMessage('setsrc', { 'selector': selector, 'src': src });
+ mm.addMessageListener('test:srcset', function onSrcSet(msg) {
+ mm.removeMessageListener('test:srcset', onSrcSet);
+ callback();
+ });
+}
+
+function sendContextMenuTo(selector, callback, ignorePreventDefault) {
+ iframe.addEventListener('mozbrowsercontextmenu', function oncontextmenu(e) {
+ iframe.removeEventListener(e.type, oncontextmenu);
+
+ // The embedder should call preventDefault() on the event if it will handle
+ // it. Not calling preventDefault() means it won't handle the event and
+ // should not be able to deal with context menu callbacks.
+ if (ignorePreventDefault !== true) {
+ e.preventDefault();
+ }
+
+ // Keep a reference to previous/current contextmenu event details.
+ previousContextMenuDetail = currentContextMenuDetail;
+ currentContextMenuDetail = e.detail;
+
+ setTimeout(function() { callback(e.detail); });
+ });
+
+ mm.sendAsyncMessage('contextmenu', { 'selector': selector });
+}
+
+function checkContextMenuCallbackForId(detail, id, callback) {
+ mm.addMessageListener('test:callbackfired', function onCallbackFired(msg) {
+ mm.removeMessageListener('test:callbackfired', onCallbackFired);
+
+ msg = SpecialPowers.wrap(msg);
+ setTimeout(function() { callback(msg.data.label); });
+ });
+
+ detail.contextMenuItemSelected(id);
+}
+
+
+var iframe = null;
+function createIframe(callback) {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ iframe.src = 'data:text/html,<html>' +
+ '<body>' +
+ '<menu type="context" id="menu1" label="firstmenu">' +
+ '<menuitem label="foo" onclick="window.onContextMenuCallbackFired(event)"></menuitem>' +
+ '<menuitem label="bar" onclick="window.onContextMenuCallbackFired(event)"></menuitem>' +
+ '</menu>' +
+ '<menu type="context" id="menu2" label="secondmenu">' +
+ '<menuitem label="outer" onclick="window.onContextMenuCallbackFired(event)"></menuitem>' +
+ '<menu label="submenu">' +
+ '<menuitem label="inner 1"></menuitem>' +
+ '<menuitem label="inner 2" onclick="window.onContextMenuCallbackFired(event)"></menuitem>' +
+ '</menu>' +
+ '</menu>' +
+ '<div id="menu1-trigger" contextmenu="menu1"><a id="inner-link" href="foo.html">Menu 1</a></div>' +
+ '<a href="bar.html" contextmenu="menu2"><img id="menu2-trigger" src="example.png" /></a>' +
+ '<img id="menu3-trigger" src="example.png" />' +
+ '<video id="menu4-trigger" src="' + videoUrl + '"></video>' +
+ '<video id="menu5-trigger" preload="metadata"></video>' +
+ '<audio id="menu6-trigger" src="' + audioUrl + '"></audio>' +
+ '<form action="no_method"><input id="menu7-trigger" name="input1"></input></form>' +
+ '<form action="http://example.com/get_method" method="get"><input id="menu8-trigger" name="input2"></input></form>' +
+ '<form action="post_method" method="post"><input id="menu9-trigger" name="input3"></input></form>' +
+ '</body></html>';
+ document.body.appendChild(iframe);
+
+ // The following code will be included in the child
+ // =========================================================================
+ function iframeScript() {
+ addMessageListener('contextmenu', function onContextMenu(msg) {
+ var document = content.document;
+ var evt = document.createEvent('HTMLEvents');
+ evt.initEvent('contextmenu', true, true);
+ document.querySelector(msg.data.selector).dispatchEvent(evt);
+ });
+
+ addMessageListener('setsrc', function onContextMenu(msg) {
+ var wrappedTarget = content.document.querySelector(msg.data.selector);
+ var target = XPCNativeWrapper.unwrap(wrappedTarget);
+ target.addEventListener('loadedmetadata', function() {
+ sendAsyncMessage('test:srcset');
+ });
+ target.src = msg.data.src;
+ });
+
+ addMessageListener('browser-element-api:call', function onCallback(msg) {
+ if (msg.data.msg_name != 'fire-ctx-callback')
+ return;
+
+ /* Use setTimeout in order to react *after* the platform */
+ content.setTimeout(function() {
+ sendAsyncMessage('test:callbackfired', { label: label });
+ label = null;
+ });
+ });
+
+ var label = null;
+ XPCNativeWrapper.unwrap(content).onContextMenuCallbackFired = function(e) {
+ label = e.target.getAttribute('label');
+ };
+ }
+ // =========================================================================
+
+ iframe.addEventListener('mozbrowserloadend', function onload(e) {
+ iframe.removeEventListener(e.type, onload);
+ mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+ mm.loadFrameScript('data:,(' + iframeScript.toString() + ')();', false);
+
+ // Now we're ready, let's start testing.
+ callback();
+ });
+}
+
+addEventListener('testready', runTests);
diff --git a/dom/browser-element/mochitest/browserElement_CookiesNotThirdParty.js b/dom/browser-element/mochitest/browserElement_CookiesNotThirdParty.js
new file mode 100644
index 000000000..32f877786
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_CookiesNotThirdParty.js
@@ -0,0 +1,51 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 806127 - Test that cookies set by <iframe mozbrowser> are not considered
+// third-party.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ const innerPage = 'http://example.com/tests/dom/browser-element/mochitest/file_browserElement_CookiesNotThirdParty.html';
+
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ if (e.detail.message == 'next') {
+ iframe.src = innerPage + '?step=2';
+ return;
+ }
+
+ if (e.detail.message.startsWith('success:')) {
+ ok(true, e.detail.message);
+ return;
+ }
+
+ if (e.detail.message.startsWith('failure:')) {
+ ok(false, e.detail.message);
+ return;
+ }
+
+ if (e.detail.message == 'finish') {
+ SimpleTest.finish();
+ }
+ });
+
+ // innerPage will set a cookie and then alert('next'). We'll load
+ // innerPage?step=2. That page will check that the cooke exists (despite the
+ // fact that we've disabled third-party cookies) and alert('success:') or
+ // alert('failure:'), as appropriate. Finally, the page will
+ // alert('finish');
+ iframe.src = innerPage;
+ document.body.appendChild(iframe);
+}
+
+// Disable third-party cookies for this test.
+addEventListener('testready', function() {
+ SpecialPowers.pushPrefEnv({'set': [['network.cookie.cookieBehavior', 1]]}, runTest);
+});
diff --git a/dom/browser-element/mochitest/browserElement_CopyPaste.js b/dom/browser-element/mochitest/browserElement_CopyPaste.js
new file mode 100644
index 000000000..b23feef59
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_CopyPaste.js
@@ -0,0 +1,339 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that "cut, copy, paste, selectall" and caretstatechanged event works from inside an <iframe mozbrowser>.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.setupAccessibleCaretPref();
+browserElementTestHelpers.addPermission();
+const { Services } = SpecialPowers.Cu.import('resource://gre/modules/Services.jsm');
+
+var gTextarea = null;
+var mm;
+var iframeOuter;
+var iframeInner;
+var state = 0;
+var stateMeaning;
+var defaultData;
+var pasteData;
+var focusScript;
+var createEmbededFrame = false;
+var testSelectionChange = false;
+
+function copyToClipboard(str) {
+ gTextarea.value = str;
+ SpecialPowers.wrap(gTextarea).editor.selectAll();
+ SpecialPowers.wrap(gTextarea).editor.copy();
+}
+
+function getScriptForGetContent() {
+ var script = 'data:,\
+ var elt = content.document.getElementById("text"); \
+ var txt = ""; \
+ if (elt) { \
+ if (elt.tagName === "DIV" || elt.tagName === "BODY") { \
+ txt = elt.textContent; \
+ } else { \
+ txt = elt.value; \
+ } \
+ } \
+ sendAsyncMessage("content-text", txt);';
+ return script;
+}
+
+function getScriptForSetFocus() {
+ var script = 'data:,' + focusScript + 'sendAsyncMessage("content-focus")';
+ return script;
+}
+
+function runTest() {
+ iframeOuter = document.createElement('iframe');
+ iframeOuter.setAttribute('mozbrowser', 'true');
+ if (createEmbededFrame) {
+ iframeOuter.src = "file_empty.html";
+ }
+ document.body.appendChild(iframeOuter);
+
+ gTextarea = document.createElement('textarea');
+ document.body.appendChild(gTextarea);
+
+ iframeOuter.addEventListener("mozbrowserloadend", function onloadend(e) {
+ iframeOuter.removeEventListener("mozbrowserloadend", onloadend);
+
+ if (createEmbededFrame) {
+ var contentWin = SpecialPowers.wrap(iframeOuter)
+ .QueryInterface(SpecialPowers.Ci.nsIFrameLoaderOwner)
+ .frameLoader.docShell.contentViewer.DOMDocument.defaultView;
+ var contentDoc = contentWin.document;
+ iframeInner = contentDoc.createElement('iframe');
+ iframeInner.setAttribute('mozbrowser', true);
+ iframeInner.setAttribute('remote', 'false');
+ contentDoc.body.appendChild(iframeInner);
+ iframeInner.addEventListener("mozbrowserloadend", function onloadendinner(e) {
+ iframeInner.removeEventListener("mozbrowserloadend", onloadendinner);
+ mm = SpecialPowers.getBrowserFrameMessageManager(iframeInner);
+ dispatchTest(e);
+ });
+ } else {
+ iframeInner = iframeOuter;
+ mm = SpecialPowers.getBrowserFrameMessageManager(iframeInner);
+ dispatchTest(e);
+ }
+ });
+}
+
+function doCommand(cmd) {
+ var COMMAND_MAP = {
+ 'cut': 'cmd_cut',
+ 'copy': 'cmd_copyAndCollapseToEnd',
+ 'paste': 'cmd_paste',
+ 'selectall': 'cmd_selectAll'
+ };
+ var script = 'data:,docShell.doCommand("' + COMMAND_MAP[cmd] + '");';
+ mm.loadFrameScript(script, false);
+}
+
+function dispatchTest(e) {
+ iframeInner.addEventListener("mozbrowserloadend", function onloadend2(e) {
+ iframeInner.removeEventListener("mozbrowserloadend", onloadend2);
+ iframeInner.focus();
+ SimpleTest.executeSoon(function() { testSelectAll(e); });
+ });
+
+ switch (state) {
+ case 0: // test for textarea
+ defaultData = "Test for selection change event";
+ pasteData = "from parent ";
+ iframeInner.src = "data:text/html,<html><body>" +
+ "<textarea id='text'>" + defaultData + "</textarea>" +
+ "</body>" +
+ "</html>";
+ stateMeaning = " (test: textarea)";
+ focusScript = "var elt=content.document.getElementById('text');elt.focus();elt.select();";
+ break;
+ case 1: // test for input text
+ defaultData = "Test for selection change event";
+ pasteData = "from parent ";
+ iframeInner.src = "data:text/html,<html><body>" +
+ "<input type='text' id='text' value='" + defaultData + "'>" +
+ "</body>" +
+ "</html>";
+ stateMeaning = " (test: <input type=text>)";
+ focusScript = "var elt=content.document.getElementById('text');elt.focus();elt.select();";
+ break;
+ case 2: // test for input number
+ defaultData = "12345";
+ pasteData = "67890";
+ iframeInner.src = "data:text/html,<html><body>" +
+ "<input type='number' id='text' value='" + defaultData + "'>" +
+ "</body>" +
+ "</html>";
+ stateMeaning = " (test: <input type=number>)";
+ focusScript = "var elt=content.document.getElementById('text');elt.focus();elt.select();";
+ break;
+ case 3: // test for div contenteditable
+ defaultData = "Test for selection change event";
+ pasteData = "from parent ";
+ iframeInner.src = "data:text/html,<html><body>" +
+ "<div contenteditable='true' id='text'>" + defaultData + "</div>" +
+ "</body>" +
+ "</html>";
+ stateMeaning = " (test: content editable div)";
+ focusScript = "var elt=content.document.getElementById('text');elt.focus();";
+ break;
+ case 4: // test for normal div
+ defaultData = "Test for selection change event";
+ pasteData = "from parent ";
+ iframeInner.src = "data:text/html,<html><body>" +
+ "<div id='text'>" + defaultData + "</div>" +
+ "</body>" +
+ "</html>";
+ stateMeaning = " (test: normal div)";
+ focusScript = "var elt=content.document.getElementById('text');elt.focus();";
+ break;
+ case 5: // test for normal div with designMode:on
+ defaultData = "Test for selection change event";
+ pasteData = "from parent ";
+ iframeInner.src = "data:text/html,<html><body id='text'>" +
+ defaultData +
+ "</body>" +
+ "<script>document.designMode='on';</script>" +
+ "</html>";
+ stateMeaning = " (test: normal div with designMode:on)";
+ focusScript = "var elt=content.document.getElementById('text');elt.focus();";
+ break;
+ default:
+ if (createEmbededFrame || browserElementTestHelpers.getOOPByDefaultPref()) {
+ SimpleTest.finish();
+ } else {
+ createEmbededFrame = true;
+
+ // clean up and run test again.
+ document.body.removeChild(iframeOuter);
+ document.body.removeChild(gTextarea);
+ state = 0;
+ runTest();
+ }
+ break;
+ }
+}
+
+function isChildProcess() {
+ return SpecialPowers.Cc["@mozilla.org/xre/app-info;1"]
+ .getService(SpecialPowers.Ci.nsIXULRuntime)
+ .processType != SpecialPowers.Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
+}
+
+function testSelectAll(e) {
+ // Skip mozbrowser test if we're at child process.
+ if (!isChildProcess()) {
+ let eventName = "mozbrowsercaretstatechanged";
+ iframeOuter.addEventListener(eventName, function caretchangeforselectall(e) {
+ iframeOuter.removeEventListener(eventName, caretchangeforselectall, true);
+ ok(true, "got mozbrowsercaretstatechanged event." + stateMeaning);
+ ok(e.detail, "event.detail is not null." + stateMeaning);
+ ok(e.detail.width != 0, "event.detail.width is not zero" + stateMeaning);
+ ok(e.detail.height != 0, "event.detail.height is not zero" + stateMeaning);
+ SimpleTest.executeSoon(function() { testCopy1(e); });
+ }, true);
+ }
+
+ mm.addMessageListener('content-focus', function messageforfocus(msg) {
+ mm.removeMessageListener('content-focus', messageforfocus);
+ // test selectall command, after calling this the caretstatechanged event should be fired.
+ doCommand('selectall');
+ if (isChildProcess()) {
+ SimpleTest.executeSoon(function() { testCopy1(e); });
+ }
+ });
+
+ mm.loadFrameScript(getScriptForSetFocus(), false);
+}
+
+function testCopy1(e) {
+ // Right now we're at "selectall" state, so we can test copy commnad by
+ // calling doCommand
+ copyToClipboard("");
+ let setup = function() {
+ doCommand("copy");
+ };
+
+ let nextTest = function(success) {
+ ok(success, "copy command works" + stateMeaning);
+ SimpleTest.executeSoon(function() { testPaste1(e); });
+ };
+
+ let success = function() {
+ nextTest(true);
+ }
+
+ let fail = function() {
+ nextTest(false);
+ }
+
+ let compareData = defaultData;
+ SimpleTest.waitForClipboard(compareData, setup, success, fail);
+}
+
+function testPaste1(e) {
+ // Next test paste command, first we copy to global clipboard in parent side.
+ // Then paste it to child side.
+ copyToClipboard(pasteData);
+
+ doCommand('selectall');
+ doCommand("paste");
+ SimpleTest.executeSoon(function() { testPaste2(e); });
+}
+
+function testPaste2(e) {
+ mm.addMessageListener('content-text', function messageforpaste(msg) {
+ mm.removeMessageListener('content-text', messageforpaste);
+ if (state == 4) {
+ // normal div cannot paste, so the content remain unchange
+ ok(SpecialPowers.wrap(msg).json === defaultData, "paste command works" + stateMeaning);
+ } else if (state == 3 && browserElementTestHelpers.getOOPByDefaultPref()) {
+ // Something weird when we doCommand with content editable element in OOP. Mark this case as todo
+ todo(false, "paste command works" + stateMeaning);
+ } else {
+ ok(SpecialPowers.wrap(msg).json === pasteData, "paste command works" + stateMeaning);
+ }
+ SimpleTest.executeSoon(function() { testCut1(e); });
+ });
+
+ mm.loadFrameScript(getScriptForGetContent(), false);
+}
+
+function testCut1(e) {
+ // Clean clipboard first
+ copyToClipboard("");
+ let setup = function() {
+ doCommand("selectall");
+ doCommand("cut");
+ };
+
+ let nextTest = function(success) {
+ if (state == 3 && browserElementTestHelpers.getOOPByDefaultPref()) {
+ // Something weird when we doCommand with content editable element in OOP.
+ todo(false, "cut function works" + stateMeaning);
+ } else {
+ ok(success, "cut function works" + stateMeaning);
+ }
+ SimpleTest.executeSoon(function() { testCut2(e); });
+ };
+
+ let success = function() {
+ nextTest(true);
+ }
+
+ let fail = function() {
+ nextTest(false);
+ }
+
+ let compareData = pasteData;
+ // Something weird when we doCommand with content editable element in OOP.
+ // Always true in this case
+ // Normal div case cannot cut, always true as well.
+ if ((state == 3 && browserElementTestHelpers.getOOPByDefaultPref()) ||
+ state == 4) {
+ compareData = function() { return true; }
+ }
+
+ SimpleTest.waitForClipboard(compareData, setup, success, fail);
+}
+
+function testCut2(e) {
+ mm.addMessageListener('content-text', function messageforcut(msg) {
+ mm.removeMessageListener('content-text', messageforcut);
+ // normal div cannot cut
+ if (state == 4) {
+ ok(SpecialPowers.wrap(msg).json !== "", "cut command works" + stateMeaning);
+ } else if (state == 3 && browserElementTestHelpers.getOOPByDefaultPref()) {
+ // Something weird when we doCommand with content editable element in OOP. Mark this case as todo
+ todo(false, "cut command works" + stateMeaning);
+ } else {
+ ok(SpecialPowers.wrap(msg).json === "", "cut command works" + stateMeaning);
+ }
+
+ state++;
+ dispatchTest(e);
+ });
+
+ mm.loadFrameScript(getScriptForGetContent(), false);
+}
+
+// Give our origin permission to open browsers, and remove it when the test is complete.
+var principal = SpecialPowers.wrap(document).nodePrincipal;
+var context = { url: SpecialPowers.wrap(principal.URI).spec,
+ originAttributes: {
+ appId: principal.appId,
+ inIsolatedMozBrowser: true }};
+
+addEventListener('testready', function() {
+ SpecialPowers.pushPermissions([
+ {type: 'browser', allow: 1, context: context}
+ ], runTest);
+});
+
diff --git a/dom/browser-element/mochitest/browserElement_DOMRequestError.js b/dom/browser-element/mochitest/browserElement_DOMRequestError.js
new file mode 100644
index 000000000..040cb81fd
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_DOMRequestError.js
@@ -0,0 +1,62 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test if DOMRequest returned by an iframe gets an error callback when
+// the iframe is not in the DOM.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+function runTest() {
+ var iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+ iframe1.src = 'data:text/html,<html>' +
+ '<body style="background:green">hello</body></html>';
+ document.body.appendChild(iframe1);
+
+ function testIframe(beforeRun, isErrorExpected, nextTest) {
+ return function() {
+ var error = false;
+ if (beforeRun)
+ beforeRun();
+ function testEnd() {
+ is(isErrorExpected, error);
+ SimpleTest.executeSoon(nextTest);
+ }
+
+ var domRequest = iframe1.getScreenshot(1000, 1000);
+ domRequest.onsuccess = function(e) {
+ testEnd();
+ }
+ domRequest.onerror = function(e) {
+ error = true;
+ testEnd();
+ }
+ };
+ }
+
+ function iframeLoadedHandler() {
+ iframe1.removeEventListener('mozbrowserloadend', iframeLoadedHandler);
+ // Test 1: iframe is in the DOM.
+ // Test 2: iframe is removed from the DOM.
+ // Test 3: iframe is added back into the DOM.
+ var test3 = testIframe(
+ function() {
+ document.body.appendChild(iframe1);
+ }, false,
+ function() {
+ SimpleTest.finish();
+ })
+ ;
+ var test2 = testIframe(function() {
+ document.body.removeChild(iframe1);
+ }, true, test3);
+ var test1 = testIframe(null, false, test2);
+ SimpleTest.executeSoon(test1);
+ }
+
+ iframe1.addEventListener('mozbrowserloadend', iframeLoadedHandler);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_DataURI.js b/dom/browser-element/mochitest/browserElement_DataURI.js
new file mode 100644
index 000000000..f57f4566a
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_DataURI.js
@@ -0,0 +1,68 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that data: URIs work with mozbrowserlocationchange events.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+ iframe1.id = 'iframe1';
+ iframe1.addEventListener('mozbrowserloadend', function if1_loadend() {
+ iframe1.removeEventListener('mozbrowserloadend', if1_loadend);
+ ok(true, 'Got first loadend event.');
+ SimpleTest.executeSoon(runTest2);
+ });
+ iframe1.src = browserElementTestHelpers.emptyPage1;
+ document.body.appendChild(iframe1);
+
+ var iframe2 = document.createElement('iframe');
+ iframe2.id = 'iframe2';
+ document.body.appendChild(iframe2);
+}
+
+function runTest2() {
+ var iframe1 = document.getElementById('iframe1');
+ var iframe2 = document.getElementById('iframe2');
+
+ var sawLoadEnd = false;
+ var sawLocationChange = false;
+
+ iframe1.addEventListener('mozbrowserlocationchange', function(e) {
+ ok(e.isTrusted, 'Event should be trusted.');
+ ok(!sawLocationChange, 'Just one locationchange event.');
+ ok(!sawLoadEnd, 'locationchange before load.');
+ is(e.detail.url, 'data:text/html,1', "event's reported location");
+ sawLocationChange = true;
+ });
+
+ iframe1.addEventListener('mozbrowserloadend', function() {
+ ok(sawLocationChange, 'Loadend after locationchange.');
+ ok(!sawLoadEnd, 'Just one loadend event.');
+ sawLoadEnd = true;
+ });
+
+ function iframe2Load() {
+ if (!sawLoadEnd || !sawLocationChange) {
+ // Spin if iframe1 hasn't loaded yet.
+ SimpleTest.executeSoon(iframe2Load);
+ return;
+ }
+ ok(true, 'Got iframe2 load.');
+ SimpleTest.finish();
+ }
+ iframe2.addEventListener('load', iframe2Load);
+
+
+ iframe1.src = 'data:text/html,1';
+
+ // Load something into iframe2 to check that it doesn't trigger a
+ // locationchange for our iframe1 listener.
+ iframe2.src = browserElementTestHelpers.emptyPage2;
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_DocumentFirstPaint.js b/dom/browser-element/mochitest/browserElement_DocumentFirstPaint.js
new file mode 100644
index 000000000..16618829e
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_DocumentFirstPaint.js
@@ -0,0 +1,69 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 829486 - Add mozdocumentbrowserfirstpaint event.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+var iframe;
+
+function runTestQueue(queue) {
+ if (queue.length == 0) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var gotFirstPaint = false;
+ var gotFirstLocationChange = false;
+ var test = queue.shift();
+
+ function runNext() {
+ iframe.removeEventListener('mozbrowserdocumentfirstpaint', documentfirstpainthandler);
+ iframe.removeEventListener('mozbrowserloadend', loadendhandler);
+ runTestQueue(queue);
+ }
+
+ function documentfirstpainthandler(e) {
+ ok(!gotFirstPaint, "Got firstpaint only once");
+ gotFirstPaint = true;
+ if (gotFirstLocationChange) {
+ runNext();
+ }
+ }
+
+ function loadendhandler(e) {
+ gotFirstLocationChange = true;
+ if (gotFirstPaint) {
+ runNext();
+ }
+ }
+
+ iframe.addEventListener('mozbrowserdocumentfirstpaint', documentfirstpainthandler);
+ iframe.addEventListener('mozbrowserloadend', loadendhandler);
+
+ test();
+}
+
+function testChangeLocation() {
+ iframe.src = browserElementTestHelpers.emptyPage1 + "?2";
+}
+
+function testReload() {
+ iframe.reload();
+}
+
+function testFirstLoad() {
+ document.body.appendChild(iframe);
+ iframe.src = browserElementTestHelpers.emptyPage1;
+}
+
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ runTestQueue([testFirstLoad, testReload, testChangeLocation]);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_Download.js b/dom/browser-element/mochitest/browserElement_Download.js
new file mode 100644
index 000000000..965387657
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Download.js
@@ -0,0 +1,37 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 983747 - Test 'download' method on iframe.
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+var iframe;
+var downloadURL = 'http://test/tests/dom/browser-element/mochitest/file_download_bin.sjs';
+
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ iframe.addEventListener('mozbrowserloadend', loadend);
+ iframe.src = 'data:text/html,<html><body>hello</body></html>';
+ iframe.setAttribute('remote', 'true');
+
+ document.body.appendChild(iframe);
+}
+
+function loadend() {
+ var req = iframe.download(downloadURL, { filename: 'test.bin' });
+ req.onsuccess = function() {
+ ok(true, 'Download finished as expected.');
+ SimpleTest.finish();
+ }
+ req.onerror = function() {
+ ok(false, 'Expected no error, got ' + req.error);
+ }
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_ErrorSecurity.js b/dom/browser-element/mochitest/browserElement_ErrorSecurity.js
new file mode 100644
index 000000000..c13a37140
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_ErrorSecurity.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 764718 - Test that mozbrowsererror works for a security error.
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+var iframe = null;
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+
+ checkForDnsError();
+}
+
+function checkForDnsError() {
+ iframe.addEventListener("mozbrowsererror", function onDnsError(e) {
+ iframe.removeEventListener(e.type, onDnsError);
+ ok(true, "Got mozbrowsererror event.");
+ ok(e.detail.type == "dnsNotFound", "Event's detail has a |type| param with the value '" + e.detail.type + "'.");
+
+ checkForExpiredCertificateError();
+ });
+
+ iframe.src = "http://this_is_not_a_domain.example.com";
+}
+
+function checkForExpiredCertificateError() {
+ iframe.addEventListener("mozbrowsererror", function onCertError(e) {
+ iframe.removeEventListener(e.type, onCertError);
+ ok(true, "Got mozbrowsererror event.");
+ ok(e.detail.type == "certerror", "Event's detail has a |type| param with the value '" + e.detail.type + "'.");
+
+ checkForNoCertificateError();
+ });
+
+ iframe.src = "https://expired.example.com";
+}
+
+
+function checkForNoCertificateError() {
+ iframe.addEventListener("mozbrowsererror", function onCertError(e) {
+ iframe.removeEventListener(e.type, onCertError);
+ ok(true, "Got mozbrowsererror event.");
+ ok(e.detail.type == "certerror", "Event's detail has a |type| param with the value '" + e.detail.type + "'.");
+
+ SimpleTest.finish();
+ });
+
+ iframe.src = "https://nocert.example.com";
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_ExecuteScript.js b/dom/browser-element/mochitest/browserElement_ExecuteScript.js
new file mode 100644
index 000000000..901964999
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_ExecuteScript.js
@@ -0,0 +1,119 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 1174733 - Browser API: iframe.executeScript
+
+'use strict';
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+function runTest() {
+
+ const origin = 'http://example.org';
+ const url = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_ExecuteScript.html';
+
+ // Test if all key=>value pairs in o1 are present in o2.
+ const c = (o1, o2) => Object.keys(o1).every(k => o1[k] == o2[k]);
+
+ let scriptId = 0;
+
+ const bail = () => {
+ ok(false, `scriptId: ${scriptId++}`);
+ }
+
+ SpecialPowers.pushPermissions([
+ {type: 'browser', allow: 1, context: document},
+ {type: 'browser:universalxss', allow: 1, context: document}
+ ], function() {
+ let iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ iframe.addEventListener('mozbrowserloadend', function onload() {
+ iframe.removeEventListener('mozbrowserloadend', onload);
+ onReady(iframe);
+ });
+ iframe.src = url;
+ document.body.appendChild(iframe);
+ });
+
+
+ function onReady(iframe) {
+ iframe.executeScript('4 + 4', {url}).then(rv => {
+ is(rv, 8, `scriptId: ${scriptId++}`);
+ return iframe.executeScript('(() => {return {a:42}})()', {url})
+ }, bail).then(rv => {
+ ok(c(rv, {a:42}), `scriptId: ${scriptId++}`);
+ return iframe.executeScript('(() => {return {a:42}})()', {origin})
+ }, bail).then(rv => {
+ ok(c(rv, {a:42}), `scriptId: ${scriptId++}`);
+ return iframe.executeScript('(() => {return {a:42}})()', {origin, url})
+ }, bail).then(rv => {
+ ok(c(rv, {a:42}), `scriptId: ${scriptId++}`);
+ return iframe.executeScript(`
+ new Promise((resolve, reject) => {
+ resolve(document.body.textContent.trim());
+ });
+ `, {url})
+ }, bail).then(rv => {
+ is(rv, 'foo', `scriptId: ${scriptId++}`);
+ return iframe.executeScript(`
+ new Promise((resolve, reject) => {
+ resolve({a:43,b:34});
+ });
+ `, {url})
+ }, bail).then(rv => {
+ ok(c(rv, {a:43,b:34}), `scriptId: ${scriptId++}`);
+ return iframe.executeScript(`
+ … syntax error
+ `, {url});
+ }, bail).then(bail, (error) => {
+ is(error.name, 'SyntaxError: illegal character', `scriptId: ${scriptId++}`);
+ return iframe.executeScript(`
+ window
+ `, {url});
+ }).then(bail, (error) => {
+ is(error.name, 'Script last expression must be a promise or a JSON object', `scriptId: ${scriptId++}`);
+ return iframe.executeScript(`
+ new Promise((resolve, reject) => {
+ reject('BOOM');
+ });
+ `, {url});
+ }).then(bail, (error) => {
+ is(error.name, 'BOOM', `scriptId: ${scriptId++}`);
+ return iframe.executeScript(`
+ new Promise((resolve, reject) => {
+ resolve(window);
+ });
+ `, {url});
+ }).then(bail, (error) => {
+ is(error.name, 'Value returned (resolve) by promise is not a valid JSON object', `scriptId: ${scriptId++}`);
+ return iframe.executeScript('window.btoa("a")', {url})
+ }, bail).then(rv => {
+ ok(c(rv, 'YQ=='), `scriptId: ${scriptId++}`);
+ return iframe.executeScript('window.wrappedJSObject.btoa("a")', {url})
+ }, bail).then(bail, (error) => {
+ is(error.name, 'TypeError: window.wrappedJSObject is undefined', `scriptId: ${scriptId++}`);
+ return iframe.executeScript('42', {})
+ }).then(bail, error => {
+ is(error.name, 'InvalidAccessError', `scriptId: ${scriptId++}`);
+ return iframe.executeScript('42');
+ }).then(bail, error => {
+ is(error.name, 'InvalidAccessError', `scriptId: ${scriptId++}`);
+ return iframe.executeScript('43', { url: 'http://foo.com' });
+ }).then(bail, (error) => {
+ is(error.name, 'URL mismatches', `scriptId: ${scriptId++}`);
+ return iframe.executeScript('43', { url: '_' });
+ }, bail).then(bail, (error) => {
+ is(error.name, 'Malformed URL', `scriptId: ${scriptId++}`);
+ return iframe.executeScript('43', { origin: 'http://foo.com' });
+ }, bail).then(bail, (error) => {
+ is(error.name, 'Origin mismatches', `scriptId: ${scriptId++}`);
+ return iframe.executeScript('43', { origin: 'https://example.org' });
+ }, bail).then(bail, (error) => {
+ is(error.name, 'Origin mismatches', `scriptId: ${scriptId++}`);
+ SimpleTest.finish();
+ });
+ }
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_ExposableURI.js b/dom/browser-element/mochitest/browserElement_ExposableURI.js
new file mode 100644
index 000000000..435e11a80
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_ExposableURI.js
@@ -0,0 +1,55 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 795317: Test that the browser element sanitizes its URIs by removing the
+// "unexposable" parts before sending them in the locationchange event.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+var iframe;
+
+function testPassword() {
+ function locationchange(e) {
+ var uri = e.detail.url;
+ is(uri, 'http://mochi.test:8888/tests/dom/browser-element/mochitest/file_empty.html',
+ "Username and password shouldn't be exposed in uri.");
+ SimpleTest.finish();
+ }
+
+ iframe.addEventListener('mozbrowserlocationchange', locationchange);
+ iframe.src = "http://iamuser:iampassword@mochi.test:8888/tests/dom/browser-element/mochitest/file_empty.html";
+}
+
+function testWyciwyg() {
+ var locationChangeCount = 0;
+
+ function locationchange(e) {
+ // locationChangeCount:
+ // 0 - the first load.
+ // 1 - after document.write().
+ if (locationChangeCount == 0) {
+ locationChangeCount ++;
+ } else if (locationChangeCount == 1) {
+ var uri = e.detail.url;
+ is(uri, 'http://mochi.test:8888/tests/dom/browser-element/mochitest/file_wyciwyg.html', "Scheme in string shouldn't be wyciwyg");
+ iframe.removeEventListener('mozbrowserlocationchange', locationchange);
+ SimpleTest.executeSoon(testPassword);
+ }
+ }
+
+ // file_wyciwyg.html calls document.write() to create a wyciwyg channel.
+ iframe.src = 'file_wyciwyg.html';
+ iframe.addEventListener('mozbrowserlocationchange', locationchange);
+}
+
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+ testWyciwyg();
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_Find.js b/dom/browser-element/mochitest/browserElement_Find.js
new file mode 100644
index 000000000..3a4968119
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Find.js
@@ -0,0 +1,145 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 1163961 - Test search API
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+function runTest() {
+
+ let iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ iframe.src = 'data:text/html,foo bar foo XXX Foo BAR foobar foobar';
+
+ const once = (eventName) => {
+ return new Promise((resolve) => {
+ iframe.addEventListener(eventName, function onEvent(...args) {
+ iframe.removeEventListener(eventName, onEvent);
+ resolve(...args);
+ });
+ });
+ }
+
+ // Test if all key=>value pairs in o1 are present in o2.
+ const c = (o1, o2) => Object.keys(o1).every(k => o1[k] == o2[k]);
+
+ let testCount = 0;
+
+ once('mozbrowserloadend').then(() => {
+ iframe.findAll('foo', 'case-insensitive');
+ return once('mozbrowserfindchange');
+ }).then(({detail}) => {
+ ok(c(detail, {
+ msg_name: "findchange",
+ active: true,
+ searchString: 'foo',
+ searchLimit: 1000,
+ activeMatchOrdinal: 1,
+ numberOfMatches: 5,
+ }), `test ${testCount++}`);
+ iframe.findNext('forward');
+ return once('mozbrowserfindchange');
+ }).then(({detail}) => {
+ ok(c(detail, {
+ msg_name: "findchange",
+ active: true,
+ searchString: 'foo',
+ searchLimit: 1000,
+ activeMatchOrdinal: 2,
+ numberOfMatches: 5,
+ }), `test ${testCount++}`);
+ iframe.findNext('backward');
+ return once('mozbrowserfindchange');
+ }).then(({detail}) => {
+ ok(c(detail, {
+ msg_name: "findchange",
+ active: true,
+ searchString: 'foo',
+ searchLimit: 1000,
+ activeMatchOrdinal: 1,
+ numberOfMatches: 5,
+ }), `test ${testCount++}`);
+ iframe.findAll('xxx', 'case-sensitive');
+ return once('mozbrowserfindchange');
+ }).then(({detail}) => {
+ ok(c(detail, {
+ msg_name: "findchange",
+ active: true,
+ searchString: 'xxx',
+ searchLimit: 1000,
+ activeMatchOrdinal: 0,
+ numberOfMatches: 0,
+ }), `test ${testCount++}`);
+ iframe.findAll('bar', 'case-insensitive');
+ return once('mozbrowserfindchange');
+ }).then(({detail}) => {
+ ok(c(detail, {
+ msg_name: "findchange",
+ active: true,
+ searchString: 'bar',
+ searchLimit: 1000,
+ activeMatchOrdinal: 1,
+ numberOfMatches: 4,
+ }), `test ${testCount++}`);
+ iframe.findNext('forward');
+ return once('mozbrowserfindchange');
+ }).then(({detail}) => {
+ ok(c(detail, {
+ msg_name: "findchange",
+ active: true,
+ searchString: 'bar',
+ searchLimit: 1000,
+ activeMatchOrdinal: 2,
+ numberOfMatches: 4,
+ }), `test ${testCount++}`);
+ iframe.findNext('forward');
+ return once('mozbrowserfindchange');
+ }).then(({detail}) => {
+ ok(c(detail, {
+ msg_name: "findchange",
+ active: true,
+ searchString: 'bar',
+ searchLimit: 1000,
+ activeMatchOrdinal: 3,
+ numberOfMatches: 4,
+ }), `test ${testCount++}`);
+ iframe.findNext('forward');
+ return once('mozbrowserfindchange');
+ }).then(({detail}) => {
+ ok(c(detail, {
+ msg_name: "findchange",
+ active: true,
+ searchString: 'bar',
+ searchLimit: 1000,
+ activeMatchOrdinal: 4,
+ numberOfMatches: 4,
+ }), `test ${testCount++}`);
+ iframe.findNext('forward');
+ return once('mozbrowserfindchange');
+ }).then(({detail}) => {
+ ok(c(detail, {
+ msg_name: "findchange",
+ active: true,
+ searchString: 'bar',
+ searchLimit: 1000,
+ activeMatchOrdinal: 1,
+ numberOfMatches: 4,
+ }), `test ${testCount++}`);
+ iframe.clearMatch();
+ return once('mozbrowserfindchange');
+ }).then(({detail}) => {
+ ok(c(detail, {
+ msg_name: "findchange",
+ active: false
+ }), `test ${testCount++}`);
+ SimpleTest.finish();
+ });
+
+ document.body.appendChild(iframe);
+
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_FirstPaint.js b/dom/browser-element/mochitest/browserElement_FirstPaint.js
new file mode 100644
index 000000000..ad67abc3a
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_FirstPaint.js
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 787378 - Add mozbrowserfirstpaint event.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ var gotFirstPaint = false;
+ var gotFirstLocationChange = false;
+ iframe.addEventListener('mozbrowserfirstpaint', function(e) {
+ ok(!gotFirstPaint, "Got only one first paint.");
+ gotFirstPaint = true;
+
+ if (gotFirstLocationChange) {
+ iframe.src = browserElementTestHelpers.emptyPage1 + '?2';
+ }
+ });
+
+ iframe.addEventListener('mozbrowserlocationchange', function(e) {
+ if (e.detail.url == browserElementTestHelpers.emptyPage1) {
+ gotFirstLocationChange = true;
+ if (gotFirstPaint) {
+ iframe.src = browserElementTestHelpers.emptyPage1 + '?2';
+ }
+ }
+ else if (e.detail.url.endsWith('?2')) {
+ SimpleTest.finish();
+ }
+ });
+
+ document.body.appendChild(iframe);
+
+ iframe.src = browserElementTestHelpers.emptyPage1;
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_ForwardName.js b/dom/browser-element/mochitest/browserElement_ForwardName.js
new file mode 100644
index 000000000..326c1ef24
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_ForwardName.js
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 781320 - Test that the name in <iframe mozbrowser name="foo"> is
+// forwarded down to remote mozbrowsers.
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ iframe.setAttribute('name', 'foo');
+
+ iframe.addEventListener("mozbrowseropenwindow", function(e) {
+ ok(false, 'Got mozbrowseropenwindow, but should not have.');
+ });
+
+ iframe.addEventListener('mozbrowserlocationchange', function(e) {
+ ok(true, "Got locationchange to " + e.detail.url);
+ if (e.detail.url.endsWith("ForwardName.html#finish")) {
+ SimpleTest.finish();
+ }
+ });
+
+ // The file sends us messages via alert() that start with "success:" or
+ // "failure:".
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ ok(e.detail.message.startsWith('success:'), e.detail.message);
+ });
+
+ document.body.appendChild(iframe);
+
+ // This file does window.open('file_browserElement_ForwardName.html#finish',
+ // 'foo'); That should open in the curent window, because the window should
+ // be named foo.
+ iframe.src = 'file_browserElement_ForwardName.html';
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_FrameWrongURI.js b/dom/browser-element/mochitest/browserElement_FrameWrongURI.js
new file mode 100644
index 000000000..c3f37b4c8
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_FrameWrongURI.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 804446 - Test that window.open(javascript:..) works with <iframe mozbrowser>.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframeJS = document.createElement('iframe');
+ iframeJS.setAttribute('mozbrowser', 'true');
+
+ iframeJS.addEventListener('mozbrowserloadstart', function(e) {
+ ok(false, "This should not happen!");
+ });
+
+ iframeJS.addEventListener('mozbrowserloadend', function(e) {
+ ok(false, "This should not happen!");
+ });
+
+ iframeJS.src = 'javascript:alert("Foo");';
+ document.body.appendChild(iframeJS);
+
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ var gotPopup = false;
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ is(gotPopup, false, 'Should get just one popup.');
+ gotPopup = true;
+
+ document.body.appendChild(e.detail.frameElement);
+ });
+
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ ok(gotPopup, 'Got mozbrowseropenwindow event before showmodalprompt event.');
+ if (e.detail.message.indexOf("success") == 0) {
+ ok(true, e.detail.message);
+ SimpleTest.finish();
+ }
+ else {
+ ok(false, "Got invalid message: " + e.detail.message);
+ }
+ });
+
+ iframe.src = 'file_browserElement_FrameWrongURI.html';
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_GetContentDimensions.js b/dom/browser-element/mochitest/browserElement_GetContentDimensions.js
new file mode 100644
index 000000000..722c42b77
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_GetContentDimensions.js
@@ -0,0 +1,66 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 757859 - Test the getContentDimensions functionality of mozbrowser
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+var resizeContent = function() {
+ var innerBox = content.document.getElementById('abox');
+ innerBox.style.width = '800px';
+ innerBox.style.height = '800px';
+}
+
+function runTest() {
+
+ var iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+
+ var iframeWidth = 400;
+ var iframeHeight = 400;
+ var numIframeLoaded = 0;
+ var numResizeEvents = 0;
+ var mm;
+
+ iframe1.src = 'data:text/html,<html><body><div id=\'abox\' ' +
+ 'style=\'background:blue;width:200px;height:200px\'>test</div></body></html>';
+ iframe1.style.width = iframeWidth + 'px';
+ iframe1.style.height = iframeHeight + 'px';
+ document.body.appendChild(iframe1);
+
+ function iframeScrollAreaChanged(e) {
+ numResizeEvents++;
+ if (numResizeEvents === 1) {
+ ok(true, 'Resize event when changing content size');
+ ok(e.detail.width > iframeWidth, 'Iframes content is larger than iframe');
+ ok(e.detail.height > iframeHeight, 'Iframes content is larger than iframe');
+ iframe1.src = 'data:text/html,<html><body><div id=\'abox\' ' +
+ 'style=\'background:blue;width:200px;height:200px\'>test</div></body></html>';
+ } else if (numResizeEvents === 2) {
+ ok(true, 'Resize event when changing src');
+ iframe1.removeEventListener('mozbrowserresize', iframeScrollAreaChanged);
+ SimpleTest.finish();
+ }
+ }
+
+ function iframeLoadedHandler() {
+ iframe1.removeEventListener('mozbrowserloadend', iframeLoadedHandler);
+ mm = SpecialPowers.getBrowserFrameMessageManager(iframe1);
+ iframe1.getContentDimensions().onsuccess = function(e) {
+ ok(typeof e.target.result.width === 'number', 'Received width');
+ ok(typeof e.target.result.height === 'number', 'Received height');
+ ok(e.target.result.height <= iframeHeight, 'Iframes content is smaller than iframe');
+ ok(e.target.result.width <= iframeWidth, 'Iframes content is smaller than iframe');
+ iframe1.addEventListener('mozbrowserscrollareachanged', iframeScrollAreaChanged);
+ mm.loadFrameScript('data:,(' + resizeContent.toString() + ')();', false);
+ }
+ }
+
+ iframe1.addEventListener('mozbrowserloadend', iframeLoadedHandler);
+}
+
+addEventListener('load', function() {
+ SimpleTest.executeSoon(runTest);
+});
diff --git a/dom/browser-element/mochitest/browserElement_GetScreenshot.js b/dom/browser-element/mochitest/browserElement_GetScreenshot.js
new file mode 100644
index 000000000..75d70f04c
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_GetScreenshot.js
@@ -0,0 +1,117 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the getScreenshot property for mozbrowser
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+function runTest() {
+ var iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+
+ iframe1.src = 'data:text/html,<html>' +
+ '<body style="background:green">hello</body></html>';
+ document.body.appendChild(iframe1);
+
+ var screenshotImageDatas = [];
+
+ function screenshotTaken(aScreenshotImageData) {
+ screenshotImageDatas.push(aScreenshotImageData);
+
+ if (screenshotImageDatas.length === 1) {
+ ok(true, 'Got initial non blank screenshot');
+
+ var view = aScreenshotImageData.data;
+ if (view[3] !== 255) {
+ ok(false, 'The first pixel of initial screenshot is not opaque');
+ SimpleTest.finish();
+ return;
+ }
+ ok(true, 'Verified the first pixel of initial screenshot is opaque');
+
+ iframe1.src = 'data:text/html,<html>' +
+ '<body style="background:transparent">hello</body></html>';
+
+ iframe1.addEventListener('mozbrowserloadend', ()=>takeScreenshot('image/png'));
+
+ }
+ else if (screenshotImageDatas.length === 2) {
+ ok(true, 'Got updated screenshot after source page changed');
+
+ var view = aScreenshotImageData.data;
+ if (view[3] !== 0) {
+ // The case here will always fail when oop'd on Firefox Desktop,
+ // but not on B2G Emulator
+ // See https://bugzil.la/878003#c20
+
+ var isB2G = (navigator.platform === '');
+ info('navigator.platform: ' + navigator.platform);
+ if (!isB2G && browserElementTestHelpers.getOOPByDefaultPref()) {
+ todo(false, 'The first pixel of updated screenshot is not transparent');
+ } else {
+ ok(false, 'The first pixel of updated screenshot is not transparent');
+ }
+ SimpleTest.finish();
+ return;
+ }
+
+ ok(true, 'Verified the first pixel of updated screenshot is transparent');
+ SimpleTest.finish();
+ }
+ }
+
+ // We continually take screenshots until we get one that we are
+ // happy with.
+ function takeScreenshot(mimeType) {
+ function gotImage(e) {
+ // |this| is the Image.
+
+ URL.revokeObjectURL(this.src);
+
+ if (e.type === 'error' || !this.width || !this.height) {
+ ok(false, "load image error");
+ SimpleTest.finish();
+ return;
+ }
+
+ var canvas = document.createElement('canvas');
+ canvas.width = canvas.height = 1000;
+ var ctx = canvas.getContext('2d');
+ ctx.drawImage(this, 0, 0);
+ var imageData = ctx.getImageData(0, 0, 1000, 1000);
+
+ screenshotTaken(imageData);
+ }
+
+ function getScreenshotImageData(e) {
+ var blob = e.target.result;
+ if (blob.type !== mimeType) {
+ ok(false, 'MIME type of screenshot taken incorrect');
+ SimpleTest.finish();
+ }
+
+ if (blob.size === 0) {
+ ok(false, "get screenshot image error");
+ SimpleTest.finish();
+ }
+
+ var img = new Image();
+ img.src = URL.createObjectURL(blob);
+ img.onload = img.onerror = gotImage;
+ }
+
+ iframe1.getScreenshot(1000, 1000, mimeType).onsuccess =
+ getScreenshotImageData;
+ }
+
+ function iframeLoadedHandler(e) {
+ iframe1.removeEventListener('mozbrowserloadend', iframeLoadedHandler);
+ takeScreenshot('image/jpeg');
+ }
+
+ iframe1.addEventListener('mozbrowserloadend', iframeLoadedHandler);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_GetScreenshotDppx.js b/dom/browser-element/mochitest/browserElement_GetScreenshotDppx.js
new file mode 100644
index 000000000..1d61f6afc
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_GetScreenshotDppx.js
@@ -0,0 +1,107 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the getScreenshot property for mozbrowser
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+function runTest() {
+ var dppxPref = 'layout.css.devPixelsPerPx';
+ var cssPixelWidth = 600;
+ var cssPixelHeight = 400;
+
+ var iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('width', cssPixelWidth);
+ iframe1.setAttribute('height', cssPixelHeight);
+ iframe1.setAttribute('mozbrowser', 'true');
+
+ iframe1.src = 'data:text/html,<html><body>hello</body></html>';
+ document.body.appendChild(iframe1);
+
+ var images = [];
+
+ function screenshotTaken(image) {
+ images.push(image);
+ if (images.length === 1) {
+ ok(true, 'Got initial non blank screenshot');
+
+ if (image.width !== cssPixelWidth || image.height !== cssPixelHeight) {
+ ok(false, 'The pixel width of the image received is not correct');
+ SimpleTest.finish();
+ return;
+ }
+ ok(true, 'The pixel width of the image received is correct');
+
+ SpecialPowers.pushPrefEnv(
+ {'set': [['layout.css.devPixelsPerPx', 2]]}, takeScreenshot);
+ }
+ else if (images.length === 2) {
+ ok(true, 'Got updated screenshot after source page changed');
+
+ if (image.width !== cssPixelWidth * 2 ||
+ image.height !== cssPixelHeight * 2) {
+ ok(false, 'The pixel width of the 2dppx image received is not correct');
+ SimpleTest.finish();
+ return;
+ }
+ ok(true, 'The pixel width of the 2dppx image received is correct');
+ SimpleTest.finish();
+ }
+ }
+
+ function takeScreenshot() {
+ function gotImage(e) {
+ // |this| is the Image.
+
+ URL.revokeObjectURL(this.src);
+
+ if (e.type === 'error' || !this.width || !this.height) {
+ tryAgain();
+
+ return;
+ }
+
+ screenshotTaken(this);
+ }
+
+ function tryAgain() {
+ if (--attempts === 0) {
+ ok(false, 'Timed out waiting for correct screenshot');
+ SimpleTest.finish();
+ } else {
+ setTimeout(function() {
+ iframe1.getScreenshot(cssPixelWidth, cssPixelHeight).onsuccess =
+ getScreenshotImageData;
+ }, 200);
+ }
+ }
+
+ function getScreenshotImageData(e) {
+ var blob = e.target.result;
+ if (blob.size === 0) {
+ tryAgain();
+
+ return;
+ }
+
+ var img = new Image();
+ img.src = URL.createObjectURL(blob);
+ img.onload = img.onerror = gotImage;
+ }
+
+ var attempts = 10;
+ iframe1.getScreenshot(cssPixelWidth, cssPixelHeight).onsuccess =
+ getScreenshotImageData;
+ }
+
+ function iframeLoadedHandler() {
+ SpecialPowers.pushPrefEnv(
+ {'set': [['layout.css.devPixelsPerPx', 1]]}, takeScreenshot);
+ }
+
+ iframe1.addEventListener('mozbrowserloadend', iframeLoadedHandler);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_Iconchange.js b/dom/browser-element/mochitest/browserElement_Iconchange.js
new file mode 100644
index 000000000..367a2de15
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Iconchange.js
@@ -0,0 +1,129 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the onmozbrowsericonchange event works.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function createHtml(link) {
+ return 'data:text/html,<html><head>' + link + '<body></body></html>';
+}
+
+function createLink(name, sizes, rel) {
+ var s = sizes ? 'sizes="' + sizes + '"' : '';
+ if (!rel) {
+ rel = 'icon';
+ }
+ return '<link rel="' + rel + '" type="image/png" ' + s +
+ ' href="http://example.com/' + name + '.png">';
+}
+
+function runTest() {
+ var iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe1);
+
+ // iframe2 is a red herring; we modify its favicon but don't listen for
+ // iconchanges; we want to make sure that its iconchange events aren't
+ // picked up by the listener on iframe1.
+ var iframe2 = document.createElement('iframe');
+ iframe2.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe2);
+
+ // iframe3 is another red herring. It's not a mozbrowser, so we shouldn't
+ // get any iconchange events on it.
+ var iframe3 = document.createElement('iframe');
+ document.body.appendChild(iframe3);
+
+ var numIconChanges = 0;
+
+ iframe1.addEventListener('mozbrowsericonchange', function(e) {
+
+ numIconChanges++;
+
+ if (numIconChanges == 1) {
+ is(e.detail.href, 'http://example.com/myicon.png');
+
+ // We should recieve iconchange events when the user creates new links
+ // to a favicon, but only when we listen for them
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.title='New title';",
+ /* allowDelayedLoad = */ false);
+
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=ICON href=http://example.com/newicon.png>')",
+ /* allowDelayedLoad = */ false);
+
+ SpecialPowers.getBrowserFrameMessageManager(iframe2)
+ .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=ICON href=http://example.com/newicon.png>')",
+ /* allowDelayedLoad = */ false);
+ }
+ else if (numIconChanges == 2) {
+ is(e.detail.href, 'http://example.com/newicon.png');
+
+ // Full new pages should trigger iconchange events
+ iframe1.src = createHtml(createLink('3rdicon'));
+ }
+ else if (numIconChanges == 3) {
+ is(e.detail.href, 'http://example.com/3rdicon.png');
+
+ // the rel attribute can have various space seperated values, make
+ // sure we only pick up correct values for 'icon'
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=shortcuticon href=http://example.com/newicon.png>')",
+ /* allowDelayedLoad = */ false);
+ // Test setting a page with multiple links elements
+ iframe1.src = createHtml(createLink('another') + createLink('icon'));
+ }
+ else if (numIconChanges == 4) {
+ is(e.detail.href, 'http://example.com/another.png');
+ // 2 events will be triggered by previous test, wait for next
+ }
+ else if (numIconChanges == 5) {
+ is(e.detail.href, 'http://example.com/icon.png');
+
+ // Make sure icon check is case insensitive
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=ICON href=http://example.com/ucaseicon.png>')",
+ /* allowDelayedLoad = */ false);
+ }
+ else if (numIconChanges == 6) {
+ is(e.detail.href, 'http://example.com/ucaseicon.png');
+ iframe1.src = createHtml(createLink('testsize', '50x50', 'icon'));
+ }
+ else if (numIconChanges == 7) {
+ is(e.detail.href, 'http://example.com/testsize.png');
+ is(e.detail.sizes, '50x50');
+ iframe1.src = createHtml(createLink('testapple1', '100x100', 'apple-touch-icon'));
+ } else if (numIconChanges == 8) {
+ is(e.detail.href, 'http://example.com/testapple1.png');
+ is(e.detail.rel, 'apple-touch-icon');
+ is(e.detail.sizes, '100x100');
+
+ iframe1.src = createHtml(createLink('testapple2', '100x100', 'apple-touch-icon-precomposed'));
+ } else if (numIconChanges == 9) {
+ is(e.detail.href, 'http://example.com/testapple2.png');
+ is(e.detail.rel, 'apple-touch-icon-precomposed');
+ is(e.detail.sizes, '100x100');
+ SimpleTest.finish();
+ } else {
+ ok(false, 'Too many iconchange events.');
+ }
+ });
+
+ iframe3.addEventListener('mozbrowsericonchange', function(e) {
+ ok(false, 'Should not get a iconchange event for iframe3.');
+ });
+
+
+ iframe1.src = createHtml(createLink('myicon'));
+ // We should not recieve icon change events for either of the below iframes
+ iframe2.src = createHtml(createLink('myicon'));
+ iframe3.src = createHtml(createLink('myicon'));
+
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_LoadEvents.js b/dom/browser-element/mochitest/browserElement_LoadEvents.js
new file mode 100644
index 000000000..8b43d8e75
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_LoadEvents.js
@@ -0,0 +1,120 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that an iframe with the |mozbrowser| attribute emits mozbrowserloadX
+// events when this page is in the whitelist.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ // Load emptypage1 into the iframe, wait for that to finish loading, then
+ // call runTest2.
+ //
+ // This should trigger loadstart, locationchange, and loadend events.
+
+ var seenLoadEnd = false;
+ var seenLoadStart = false;
+ var seenLocationChange = false;
+
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ iframe.id = 'iframe';
+ iframe.src = 'http://example.com/tests/dom/browser-element/mochitest/file_browserElement_LoadEvents.html';
+
+ function loadstart(e) {
+ ok(e.isTrusted, 'Event should be trusted.');
+ ok(!seenLoadEnd, 'loadstart before loadend.');
+ ok(!seenLoadStart, 'Just one loadstart event.');
+ ok(!seenLocationChange, 'loadstart before locationchange.');
+ seenLoadStart = true;
+ }
+
+ function locationchange(e) {
+ ok(e.isTrusted, 'Event should be trusted.');
+ ok(!seenLocationChange, 'Just one locationchange event.');
+ seenLocationChange = true;
+ ok(seenLoadStart, 'Location change after load start.');
+ ok(!seenLoadEnd, 'Location change before load end.');
+ ok(e.detail.url, browserElementTestHelpers.emptyPage1, "event's reported location");
+ }
+
+ function loadend(e) {
+ ok(e.isTrusted, 'Event should be trusted.');
+ ok(seenLoadStart, 'loadend after loadstart.');
+ ok(!seenLoadEnd, 'Just one loadend event.');
+ ok(seenLocationChange, 'loadend after locationchange.');
+ is(e.detail.backgroundColor, 'rgb(0, 128, 0)', 'Expected background color reported')
+ seenLoadEnd = true;
+ }
+
+ iframe.addEventListener('mozbrowserloadstart', loadstart);
+ iframe.addEventListener('mozbrowserlocationchange', locationchange);
+ iframe.addEventListener('mozbrowserloadend', loadend);
+
+ function waitForAllCallbacks() {
+ if (!seenLoadStart || !seenLoadEnd) {
+ SimpleTest.executeSoon(waitForAllCallbacks);
+ return;
+ }
+
+ iframe.removeEventListener('mozbrowserloadstart', loadstart);
+ iframe.removeEventListener('mozbrowserlocationchange', locationchange);
+ iframe.removeEventListener('mozbrowserloadend', loadend);
+ runTest2();
+ }
+
+ document.body.appendChild(iframe);
+ waitForAllCallbacks();
+}
+
+function runTest2() {
+ var seenLoadStart = false;
+ var seenLoadEnd = false;
+ var seenLocationChange = false;
+
+ // Add this event listener to the document; the events should bubble.
+ document.addEventListener('mozbrowserloadstart', function(e) {
+ ok(e.isTrusted, 'Event should be trusted.');
+ ok(!seenLoadStart, 'Just one loadstart event.');
+ seenLoadStart = true;
+ ok(!seenLoadEnd, 'Got mozbrowserloadstart before loadend.');
+ ok(!seenLocationChange, 'Got mozbrowserloadstart before locationchange.');
+ });
+
+ var iframe = document.getElementById('iframe');
+ iframe.addEventListener('mozbrowserlocationchange', function(e) {
+ ok(e.isTrusted, 'Event should be trusted.');
+ ok(!seenLocationChange, 'Just one locationchange event.');
+ seenLocationChange = true;
+ ok(seenLoadStart, 'Location change after load start.');
+ ok(!seenLoadEnd, 'Location change before load end.');
+ ok(e.detail.url, browserElementTestHelpers.emptyPage2, "event's reported location");
+ });
+
+ iframe.addEventListener('mozbrowserloadend', function(e) {
+ ok(e.isTrusted, 'Event should be trusted.');
+ ok(!seenLoadEnd, 'Just one load end event.');
+ seenLoadEnd = true;
+ ok(seenLoadStart, 'Load end after load start.');
+ ok(seenLocationChange, 'Load end after location change.');
+ is(e.detail.backgroundColor, 'transparent', 'Expected background color reported')
+ });
+
+ iframe.src = browserElementTestHelpers.emptyPage2;
+
+ function waitForAllCallbacks() {
+ if (!seenLoadStart || !seenLoadEnd || !seenLocationChange) {
+ SimpleTest.executeSoon(waitForAllCallbacks);
+ return;
+ }
+
+ SimpleTest.finish();
+ }
+
+ waitForAllCallbacks();
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_Manifestchange.js b/dom/browser-element/mochitest/browserElement_Manifestchange.js
new file mode 100644
index 000000000..22cf8fe7c
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Manifestchange.js
@@ -0,0 +1,96 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the onmozbrowsermanifestchange event works.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function createHtml(manifest) {
+ return 'data:text/html,<html xmlns:xml="http://www.w3.org/XML/1998/namespace"><head>' + manifest + '<body></body></html>';
+}
+
+function createManifest(href) {
+ return '<link rel="manifest" href="' + href + '">';
+}
+
+function runTest() {
+ var iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe1);
+
+ // iframe2 is a red herring; we modify its manifest link elements but don't
+ // listen for manifestchanges; we want to make sure that its manifestchange
+ // events aren't picked up by the listener on iframe1.
+ var iframe2 = document.createElement('iframe');
+ iframe2.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe2);
+
+ // iframe3 is another red herring. It's not a mozbrowser, so we shouldn't
+ // get any manifestchange events on it.
+ var iframe3 = document.createElement('iframe');
+ document.body.appendChild(iframe3);
+
+ var numManifestChanges = 0;
+
+ iframe1.addEventListener('mozbrowsermanifestchange', function(e) {
+
+ numManifestChanges++;
+
+ if (numManifestChanges == 1) {
+ is(e.detail.href, 'manifest.1', 'manifest.1 matches');
+
+ // We should receive manifestchange events when the user creates new
+ // manifests
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.title='New title';",
+ /* allowDelayedLoad = */ false);
+
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=manifest href=manifest.2>')",
+ /* allowDelayedLoad = */ false);
+
+ SpecialPowers.getBrowserFrameMessageManager(iframe2)
+ .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=manifest href=manifest.2>')",
+ /* allowDelayedLoad = */ false);
+ }
+ else if (numManifestChanges == 2) {
+ is(e.detail.href, 'manifest.2', 'manifest.2 matches');
+
+ // Full new pages should trigger manifestchange events
+ iframe1.src = createHtml(createManifest('manifest.3'));
+ }
+ else if (numManifestChanges == 3) {
+ is(e.detail.href, 'manifest.3', 'manifest.3 matches');
+
+ // Test setting a page with multiple manifest link elements
+ iframe1.src = createHtml(createManifest('manifest.4a') + createManifest('manifest.4b'));
+ }
+ else if (numManifestChanges == 4) {
+ is(e.detail.href, 'manifest.4a', 'manifest.4a matches');
+ // 2 events will be triggered by previous test, wait for next
+ }
+ else if (numManifestChanges == 5) {
+ is(e.detail.href, 'manifest.4b', 'manifest.4b matches');
+ SimpleTest.finish();
+ } else {
+ ok(false, 'Too many manifestchange events.');
+ }
+ });
+
+ iframe3.addEventListener('mozbrowsermanifestchange', function(e) {
+ ok(false, 'Should not get a manifestchange event for iframe3.');
+ });
+
+
+ iframe1.src = createHtml(createManifest('manifest.1'));
+ // We should not receive manifest change events for either of the below iframes
+ iframe2.src = createHtml(createManifest('manifest.1'));
+ iframe3.src = createHtml(createManifest('manifest.1'));
+
+}
+
+addEventListener('testready', runTest);
+
diff --git a/dom/browser-element/mochitest/browserElement_Metachange.js b/dom/browser-element/mochitest/browserElement_Metachange.js
new file mode 100644
index 000000000..7789a3e18
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Metachange.js
@@ -0,0 +1,177 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the onmozbrowsermetachange event works.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function createHtml(meta) {
+ return 'data:text/html,<html xmlns:xml="http://www.w3.org/XML/1998/namespace"><head>' + meta + '<body></body></html>';
+}
+
+function createHtmlWithLang(meta, lang) {
+ return 'data:text/html,<html xmlns:xml="http://www.w3.org/XML/1998/namespace" lang="' + lang + '"><head>' + meta + '<body></body></html>';
+}
+
+function createMeta(name, content) {
+ return '<meta name="' + name + '" content="' + content + '">';
+}
+
+function createMetaWithLang(name, content, lang) {
+ return '<meta name="' + name + '" content="' + content + '" lang="' + lang + '">';
+}
+
+function createMetaWithProperty(property, content) {
+ return '<meta property="' + property + '" content="' + content + '">';
+}
+
+function runTest() {
+ var iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe1);
+
+ // iframe2 is a red herring; we modify its meta elements but don't listen for
+ // metachanges; we want to make sure that its metachange events aren't
+ // picked up by the listener on iframe1.
+ var iframe2 = document.createElement('iframe');
+ iframe2.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe2);
+
+ // iframe3 is another red herring. It's not a mozbrowser, so we shouldn't
+ // get any metachange events on it.
+ var iframe3 = document.createElement('iframe');
+ document.body.appendChild(iframe3);
+
+ var numMetaChanges = 0;
+
+ iframe1.addEventListener('mozbrowsermetachange', function(e) {
+
+ numMetaChanges++;
+
+ if (numMetaChanges == 1) {
+ is(e.detail.name, 'application-name');
+ is(e.detail.content, 'foobar');
+
+ // We should recieve metachange events when the user creates new metas
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.title='New title';",
+ /* allowDelayedLoad = */ false);
+
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<meta name=application-name content=new_foobar>')",
+ /* allowDelayedLoad = */ false);
+
+ SpecialPowers.getBrowserFrameMessageManager(iframe2)
+ .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<meta name=application-name content=new_foobar>')",
+ /* allowDelayedLoad = */ false);
+ }
+ else if (numMetaChanges == 2) {
+ is(e.detail.name, 'application-name', 'name matches');
+ is(e.detail.content, 'new_foobar', 'content matches');
+ ok(!("lang" in e.detail), 'lang not present');
+
+ // Full new pages should trigger metachange events
+ iframe1.src = createHtml(createMeta('application-name', '3rd_foobar'));
+ }
+ else if (numMetaChanges == 3) {
+ is(e.detail.name, 'application-name', 'name matches');
+ is(e.detail.content, '3rd_foobar', 'content matches');
+ ok(!("lang" in e.detail), 'lang not present');
+
+ // Test setting a page with multiple meta elements
+ iframe1.src = createHtml(createMeta('application-name', 'foobar_1') + createMeta('application-name', 'foobar_2'));
+ }
+ else if (numMetaChanges == 4) {
+ is(e.detail.name, 'application-name', 'name matches');
+ is(e.detail.content, 'foobar_1', 'content matches');
+ ok(!("lang" in e.detail), 'lang not present');
+ // 2 events will be triggered by previous test, wait for next
+ }
+ else if (numMetaChanges == 5) {
+ is(e.detail.name, 'application-name', 'name matches');
+ is(e.detail.content, 'foobar_2', 'content matches');
+ ok(!("lang" in e.detail), 'lang not present');
+
+ // Test the language
+ iframe1.src = createHtml(createMetaWithLang('application-name', 'foobar_lang_1', 'en'));
+ }
+ else if (numMetaChanges == 6) {
+ is(e.detail.name, 'application-name', 'name matches');
+ is(e.detail.content, 'foobar_lang_1', 'content matches');
+ is(e.detail.lang, 'en', 'language matches');
+
+ // Test the language in the ancestor element
+ iframe1.src = createHtmlWithLang(createMeta('application-name', 'foobar_lang_2'), 'es');
+ }
+ else if (numMetaChanges == 7) {
+ is(e.detail.name, 'application-name', 'name matches');
+ is(e.detail.content, 'foobar_lang_2', 'content matches');
+ is(e.detail.lang, 'es', 'language matches');
+
+ // Test the language in the ancestor element
+ iframe1.src = createHtmlWithLang(createMetaWithLang('application-name', 'foobar_lang_3', 'it'), 'fi');
+ }
+ else if (numMetaChanges == 8) {
+ is(e.detail.name, 'application-name', 'name matches');
+ is(e.detail.content, 'foobar_lang_3', 'content matches');
+ is(e.detail.lang, 'it', 'language matches');
+
+ // Test the content-language
+ iframe1.src = "http://test/tests/dom/browser-element/mochitest/file_browserElement_Metachange.sjs?ru";
+ }
+ else if (numMetaChanges == 9) {
+ is(e.detail.name, 'application-name', 'name matches');
+ is(e.detail.content, 'sjs', 'content matches');
+ is(e.detail.lang, 'ru', 'language matches');
+
+ // Test the content-language
+ iframe1.src = "http://test/tests/dom/browser-element/mochitest/file_browserElement_Metachange.sjs?ru|dk";
+ }
+ else if (numMetaChanges == 10) {
+ is(e.detail.name, 'application-name', 'name matches');
+ is(e.detail.content, 'sjs', 'content matches');
+ is(e.detail.lang, 'dk', 'language matches');
+
+ // Test Open Graph property
+ iframe1.src = createHtml(createMetaWithProperty('og:description', 'Fascinating article'));
+
+ // We should not get event if property doesn't start with 'og:'
+ iframe3.src = createHtml(createMetaWithProperty('go:description', 'Fascinating article'));
+ }
+ else if (numMetaChanges == 11) {
+ is(e.detail.name, 'og:description', 'property name matches');
+ is(e.detail.content, 'Fascinating article', 'content matches');
+
+ // Sometimes 'name' is used instead of 'property'. Verify that works.
+ iframe1.src = createHtml(createMeta('og:title', 'One weird trick!'));
+
+ // We should not get event if property doesn't start with 'og:'
+ iframe3.src = createHtml(createMeta('go:title', 'One weird trick!'));
+ }
+ else if (numMetaChanges == 12) {
+ is(e.detail.name, 'og:title', 'property name matches');
+ is(e.detail.content, 'One weird trick!', 'content matches');
+
+ // Test the language
+ SimpleTest.finish();
+ } else {
+ ok(false, 'Too many metachange events.');
+ }
+ });
+
+ iframe3.addEventListener('mozbrowsermetachange', function(e) {
+ ok(false, 'Should not get a metachange event for iframe3.');
+ });
+
+
+ iframe1.src = createHtml(createMeta('application-name', 'foobar'));
+ // We should not recieve meta change events for either of the below iframes
+ iframe2.src = createHtml(createMeta('application-name', 'foobar'));
+ iframe3.src = createHtml(createMeta('application-name', 'foobar'));
+
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_NextPaint.js b/dom/browser-element/mochitest/browserElement_NextPaint.js
new file mode 100644
index 000000000..749a8efe3
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_NextPaint.js
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 808231 - Add mozbrowsernextpaint event.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+
+ // Add a first listener that we'll remove shortly after.
+ iframe.addNextPaintListener(wrongListener);
+
+ var gotFirstNextPaintEvent = false;
+ iframe.addNextPaintListener(function () {
+ ok(!gotFirstNextPaintEvent, 'got the first nextpaint event');
+
+ // Make sure we're only called once.
+ gotFirstNextPaintEvent = true;
+
+ iframe.addNextPaintListener(function () {
+ info('got the second nextpaint event');
+ SimpleTest.finish();
+ });
+
+ // Force the iframe to repaint.
+ SimpleTest.executeSoon(() => iframe.src += '#next');
+ });
+
+ // Remove the first listener to make sure it's not called.
+ iframe.removeNextPaintListener(wrongListener);
+ iframe.src = 'file_browserElement_NextPaint.html';
+}
+
+function wrongListener() {
+ ok(false, 'first listener should have been removed');
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_NoAudioTrack.js b/dom/browser-element/mochitest/browserElement_NoAudioTrack.js
new file mode 100644
index 000000000..47f0fd524
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_NoAudioTrack.js
@@ -0,0 +1,96 @@
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+var fileURL = 'chrome://mochitests/content/chrome/dom/browser-element/mochitest/file_browserElement_NoAudioTrack.html';
+var generator = runTests();
+var testFrame;
+
+function alertListener(e) {
+ var message = e.detail.message;
+ if (/^OK/.exec(message)) {
+ ok(true, "Message from file : " + message);
+ continueTest();
+ } else if (/^KO/.exec(message)) {
+ error(message);
+ } else {
+ error("Undefined event.");
+ }
+}
+
+function error(aMessage) {
+ ok(false, "Error : " + aMessage);
+ finish();
+}
+
+function continueTest() {
+ try {
+ generator.next();
+ } catch (e if e instanceof StopIteration) {
+ error("Stop test because of exception!");
+ }
+}
+
+function finish() {
+ testFrame.removeEventListener('mozbrowsershowmodalprompt', alertListener);
+ ok(true, "Remove event-listener.");
+ document.body.removeChild(testFrame);
+ ok(true, "Remove test-frame from document.");
+ SimpleTest.finish();
+}
+
+function setCommand(aArg) {
+ info("# Command = " + aArg);
+ testFrame.src = fileURL + '#' + aArg;
+}
+
+function runTests() {
+ setCommand('play');
+ yield undefined;
+
+ // wait a second to make sure that onactivestatechanged isn't dispatched.
+ setCommand('idle');
+ yield undefined;
+
+ finish();
+ yield undefined;
+}
+
+function setupTestFrame() {
+ testFrame = document.createElement('iframe');
+ testFrame.setAttribute('mozbrowser', 'true');
+ testFrame.src = fileURL;
+
+ function loadend() {
+ testFrame.removeEventListener('mozbrowserloadend', loadend);
+ ok("allowedAudioChannels" in testFrame, "allowedAudioChannels exist");
+ var channels = testFrame.allowedAudioChannels;
+ is(channels.length, 9, "9 audio channel by default");
+
+ var ac = channels[0];
+ ok(ac instanceof BrowserElementAudioChannel, "Correct class");
+ ok("onactivestatechanged" in ac, "onactivestatechanged exists");
+
+ ac.onactivestatechanged = () => {
+ ac.onactivestatechanged = null;
+ ok(true, "Should receive onactivestatechanged!");
+ };
+
+ continueTest();
+ }
+
+ testFrame.addEventListener('mozbrowserloadend', loadend);
+ testFrame.addEventListener('mozbrowsershowmodalprompt', alertListener);
+ ok(true, "Add event-listeners.");
+
+ document.body.appendChild(testFrame);
+ ok(true, "Append test-frame to document.");
+}
+
+addEventListener('testready', function() {
+ SpecialPowers.pushPrefEnv({'set': [["b2g.system_startup_url", window.location.href]]},
+ function() {
+ SimpleTest.executeSoon(setupTestFrame);
+ });
+});
diff --git a/dom/browser-element/mochitest/browserElement_OpenMixedProcess.js b/dom/browser-element/mochitest/browserElement_OpenMixedProcess.js
new file mode 100644
index 000000000..c5cde7f50
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_OpenMixedProcess.js
@@ -0,0 +1,105 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 776129 - If a window w calls window.open, the resultant window should be
+// remote iff w is remote.
+//
+// <iframe mozbrowser> can be default-OOP or default-in-process. But we can
+// override this default by setting remote=true or remote=false on the iframe.
+//
+// This bug arises when we are default-in-process and a OOP iframe calls
+// window.open, or when we're default-OOP and an in-process iframe calls
+// window.open. In either case, if the opened iframe gets the default
+// remotness, it will not match its opener's remoteness, which is bad.
+//
+// Since the name of the test determines the OOP-by-default pref, the "inproc"
+// version of this test opens an OOP frame, and the "oop" version opens an
+// in-process frame. Enjoy. :)
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+function runTest() {
+ // We're going to open a remote frame if OOP off by default. If OOP is on by
+ // default, we're going to open an in-process frame.
+ var remote = !browserElementTestHelpers.getOOPByDefaultPref();
+
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ iframe.setAttribute('remote', remote);
+
+ // The page we load does window.open, then checks some things and reports
+ // back using alert(). Finally, it calls alert('finish').
+ //
+ // Bug 776129 in particular manifests itself such that the popup frame loads
+ // and the tests in file_browserElement_OpenMixedProcess pass, but the
+ // content of the frame is invisible. To catch this case, we take a
+ // screenshot after we load the content into the popup, and ensure that it's
+ // not blank.
+ var popup;
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ popup = document.body.appendChild(e.detail.frameElement);
+ });
+
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ if (e.detail.message.startsWith('pass')) {
+ ok(true, e.detail.message);
+ }
+ else if (e.detail.message.startsWith('fail')) {
+ ok(false, e.detail.message);
+ }
+ else if (e.detail.message == 'finish') {
+ // We assume here that iframe is completely blank, and spin until popup's
+ // screenshot is not the same as iframe.
+ iframe.getScreenshot(1000, 1000).onsuccess = function(e) {
+ var fr = new FileReader();
+ fr.onloadend = function() { test2(popup, fr.result); };
+ fr.readAsArrayBuffer(e.target.result);
+ };
+ }
+ else {
+ ok(false, e.detail.message, "Unexpected message!");
+ }
+ });
+
+ document.body.appendChild(iframe);
+ iframe.src = 'file_browserElement_OpenMixedProcess.html';
+}
+
+function arrayBuffersEqual(a, b) {
+ var x = new Int8Array(a);
+ var y = new Int8Array(b);
+ if (x.length != y.length) {
+ return false;
+ }
+
+ for (var i = 0; i < x.length; i++) {
+ if (x[i] != y[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function test2(popup, blankScreenshotArrayBuffer) {
+ // Take screenshots of popup until it doesn't equal blankScreenshot (or we
+ // time out).
+ popup.getScreenshot(1000, 1000).onsuccess = function(e) {
+ var fr = new FileReader();
+ fr.onloadend = function() {
+ if (!arrayBuffersEqual(blankScreenshotArrayBuffer, fr.result)) {
+ ok(true, "Finally got a non-blank screenshot.");
+ SimpleTest.finish();
+ return;
+ }
+
+ SimpleTest.executeSoon(function() { test2(popup, blankScreenshot) });
+ };
+ fr.readAsArrayBuffer(e.target.result);
+ };
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_OpenNamed.js b/dom/browser-element/mochitest/browserElement_OpenNamed.js
new file mode 100644
index 000000000..aed5617e9
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_OpenNamed.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 742944 - In <iframe mozbrowser>, test that if we call window.open twice
+// with the same name, we get only one mozbrowseropenwindow event.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+var iframe;
+var popupFrame;
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ var gotPopup = false;
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ is(gotPopup, false, 'Should get just one popup.');
+ gotPopup = true;
+ popupFrame = e.detail.frameElement;
+ is(popupFrame.getAttribute('name'), 'OpenNamed');
+
+ // Called when file_browserElement_OpenNamed2.html loads into popupFrame.
+ popupFrame.addEventListener('mozbrowsershowmodalprompt', function promptlistener(e) {
+ popupFrame.removeEventListener('mozbrowsershowmodalprompt', promptlistener);
+
+ ok(gotPopup, 'Got openwindow event before showmodalprompt event.');
+ is(e.detail.message, 'success: loaded');
+ SimpleTest.executeSoon(test2);
+ });
+
+ document.body.appendChild(popupFrame);
+ });
+
+ // OpenNamed.html will call
+ //
+ // window.open('file_browserElement_OpenNamed2.html', 'OpenNamed').
+ //
+ // Once that popup loads, we reload OpenNamed.html. That will call
+ // window.open again, but we shouldn't get another openwindow event, because
+ // we're opening into the same named window.
+ iframe.src = 'file_browserElement_OpenNamed.html';
+ document.body.appendChild(iframe);
+}
+
+function test2() {
+ popupFrame.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ is(e.detail.message, 'success: loaded');
+ SimpleTest.finish();
+ });
+
+ iframe.src = 'file_browserElement_OpenNamed.html?test2';
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_OpenTab.js b/dom/browser-element/mochitest/browserElement_OpenTab.js
new file mode 100644
index 000000000..d01927e9b
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_OpenTab.js
@@ -0,0 +1,69 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 1144015 - test middle/ctrl/cmd-click on a link.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ let iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+
+ let x = 2;
+ let y = 2;
+ // First we force a reflow so that getChildProcessOffset actually returns
+ // meaningful data.
+ iframe.getBoundingClientRect();
+ // We need to make sure the event coordinates are actually inside the iframe,
+ // relative to the chome window.
+ let tabParent = SpecialPowers.wrap(iframe)
+ .QueryInterface(SpecialPowers.Ci.nsIFrameLoaderOwner)
+ .frameLoader.tabParent;
+ if (tabParent) {
+ let offsetX = {};
+ let offsetY = {};
+ tabParent.getChildProcessOffset(offsetX, offsetY);
+ x -= offsetX.value;
+ y -= offsetY.value;
+ }
+
+ let sendCtrlClick = () => {
+ let nsIDOMWindowUtils = SpecialPowers.Ci.nsIDOMWindowUtils;
+ let mod = nsIDOMWindowUtils.MODIFIER_META |
+ nsIDOMWindowUtils.MODIFIER_CONTROL;
+ iframe.sendMouseEvent('mousedown', x, y, 0, 1, mod);
+ iframe.sendMouseEvent('mouseup', x, y, 0, 1, mod);
+ }
+
+ let onCtrlClick = e => {
+ is(e.detail.url, 'http://example.com/', 'URL matches');
+ iframe.removeEventListener('mozbrowseropentab', onCtrlClick);
+ iframe.addEventListener('mozbrowseropentab', onMiddleClick);
+ sendMiddleClick();
+ }
+
+ let sendMiddleClick = () => {
+ iframe.sendMouseEvent('mousedown', x, y, 1, 1, 0);
+ iframe.sendMouseEvent('mouseup', x, y, 1, 1, 0);
+ }
+
+ let onMiddleClick = e => {
+ is(e.detail.url, 'http://example.com/', 'URL matches');
+ iframe.removeEventListener('mozbrowseropentab', onMiddleClick);
+ SimpleTest.finish();
+ }
+
+ iframe.addEventListener('mozbrowserloadend', e => {
+ iframe.addEventListener('mozbrowseropentab', onCtrlClick);
+ sendCtrlClick();
+ });
+
+
+ iframe.src = 'data:text/html,<body style="margin:0"><a href="http://example.com"><span>click here</span></a></body>';
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_OpenWindow.js b/dom/browser-element/mochitest/browserElement_OpenWindow.js
new file mode 100644
index 000000000..65de11a26
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_OpenWindow.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 742944 - Test that window.open works with <iframe mozbrowser>.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ var gotPopup = false;
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ is(gotPopup, false, 'Should get just one popup.');
+ gotPopup = true;
+
+ document.body.appendChild(e.detail.frameElement);
+
+ ok(/file_browserElement_Open2\.html$/.test(e.detail.url),
+ "Popup's URL (got " + e.detail.url + ")");
+ is(e.detail.name, "name");
+ is(e.detail.features, "dialog=1");
+ });
+
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ ok(gotPopup, 'Got mozbrowseropenwindow event before showmodalprompt event.');
+ if (e.detail.message.indexOf("success:") == 0) {
+ ok(true, e.detail.message);
+ }
+ else if (e.detail.message.indexOf("failure:") == 0) {
+ ok(false, e.detail.message);
+ }
+ else if (e.detail.message == "finish") {
+ SimpleTest.finish();
+ }
+ else {
+ ok(false, "Got invalid message: " + e.detail.message);
+ }
+ });
+
+ /**
+ * file_browserElementOpen1 does
+ *
+ * window.open('file_browserElement_Open2.html', 'name', 'dialog=1')
+ *
+ * then adds an event listener to the opened window and waits for onload.
+ *
+ * Onload, we fire a few alerts saying "success:REASON" or "failure:REASON".
+ * Finally, we fire a "finish" alert, which ends the test.
+ */
+ iframe.src = 'file_browserElement_Open1.html';
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_OpenWindowDifferentOrigin.js b/dom/browser-element/mochitest/browserElement_OpenWindowDifferentOrigin.js
new file mode 100644
index 000000000..650ef17f5
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_OpenWindowDifferentOrigin.js
@@ -0,0 +1,41 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 769182 - window.open to a different origin should load the page.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ ok(true, 'Got first window.open call');
+
+ e.detail.frameElement.addEventListener('mozbrowseropenwindow', function(e) {
+ ok(true, 'Got second window.open call');
+ document.body.appendChild(e.detail.frameElement);
+ });
+
+ e.detail.frameElement.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ ok(true, 'Got alert from second window.');
+ SimpleTest.finish();
+ });
+
+ document.body.appendChild(e.detail.frameElement);
+ });
+
+ // DifferentOrigin.html?1 calls
+ //
+ // window.open('http://example.com/.../DifferentOrigin.html?2'),
+ //
+ // which calls alert().
+
+ iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_OpenWindowDifferentOrigin.html?1';
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_OpenWindowEmpty.js b/dom/browser-element/mochitest/browserElement_OpenWindowEmpty.js
new file mode 100644
index 000000000..6b8dd0340
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_OpenWindowEmpty.js
@@ -0,0 +1,31 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 1216937 - Test that window.open with null/empty URL should use
+// about:blank as default
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ var gotPopup = false;
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ is(gotPopup, false, 'Should get just one popup.');
+ gotPopup = true;
+
+ is(e.detail.url, 'about:blank', "Popup's has correct URL");
+ e.preventDefault();
+
+ SimpleTest.finish();
+ });
+
+ iframe.src = 'file_browserElement_OpenWindowEmpty.html';
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_OpenWindowInFrame.js b/dom/browser-element/mochitest/browserElement_OpenWindowInFrame.js
new file mode 100644
index 000000000..5559bbcb8
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_OpenWindowInFrame.js
@@ -0,0 +1,65 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 766871 - Test that window.open works from an <iframe> within <iframe mozbrowser>.
+//
+// This is basically the same as browserElement_OpenWindow, except that instead
+// of loading file_browserElement_Open1.html directly inside the <iframe
+// mozbrowser>, we load file_browserElement_OpenWindowInFrame.html into the
+// mozbrowser. OpenWindowInFrame loads file_browserElement_Open1.html inside
+// an iframe.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ var gotPopup = false;
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ is(gotPopup, false, 'Should get just one popup.');
+ gotPopup = true;
+
+ document.body.appendChild(e.detail.frameElement);
+
+ ok(/file_browserElement_Open2\.html$/.test(e.detail.url),
+ "Popup's URL (got " + e.detail.url + ")");
+ is(e.detail.name, "name");
+ is(e.detail.features, "dialog=1");
+ });
+
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ ok(gotPopup, 'Got mozbrowseropenwindow event before showmodalprompt event.');
+ if (e.detail.message.indexOf("success:") == 0) {
+ ok(true, e.detail.message);
+ }
+ else if (e.detail.message.indexOf("failure:") == 0) {
+ ok(false, e.detail.message);
+ }
+ else if (e.detail.message == "finish") {
+ SimpleTest.finish();
+ }
+ else {
+ ok(false, "Got invalid message: " + e.detail.message);
+ }
+ });
+
+ /**
+ * file_browserElement_OpenWindowInFrame.html loads
+ * file_browserElement_Open1.html in an iframe. Open1.html does
+ *
+ * window.open('file_browserElement_Open2.html', 'name', 'dialog=1')
+ *
+ * then adds an event listener to the opened window and waits for onload.
+ *
+ * Onload, we fire a few alerts saying "success:REASON" or "failure:REASON".
+ * Finally, we fire a "finish" alert, which ends the test.
+ */
+ iframe.src = 'file_browserElement_OpenWindowInFrame.html';
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_OpenWindowRejected.js b/dom/browser-element/mochitest/browserElement_OpenWindowRejected.js
new file mode 100644
index 000000000..f5ef97260
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_OpenWindowRejected.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 742944 - Do window.open from inside <iframe mozbrowser>. But then
+// reject the call. This shouldn't cause problems (crashes, leaks).
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ ok(e.detail.url.indexOf('does_not_exist.html') != -1,
+ 'Opened URL; got ' + e.detail.url);
+ is(e.detail.name, '');
+ is(e.detail.features, '');
+
+ // Don't add e.detail.frameElement to the DOM, so the window.open is
+ // effectively blocked.
+ e.preventDefault();
+ });
+
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ var msg = e.detail.message;
+ if (msg.indexOf('success:') == 0) {
+ ok(true, msg);
+ }
+ else if (msg == 'finish') {
+ SimpleTest.finish();
+ }
+ else {
+ ok(false, msg);
+ }
+ });
+
+ iframe.src = 'file_browserElement_OpenWindowRejected.html';
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_OpenWindowRejected2.js b/dom/browser-element/mochitest/browserElement_OpenWindowRejected2.js
new file mode 100644
index 000000000..acea6813e
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_OpenWindowRejected2.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 742944 - Do window.open from inside <iframe mozbrowser>. But then
+// reject the call. This shouldn't cause problems (crashes, leaks).
+//
+// This is the same as OpenWindowRejected, except we "reject" the popup by not
+// adding the iframe element to our DOM, instead of by not calling
+// preventDefault() on the event.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ ok(e.detail.url.indexOf('does_not_exist.html') != -1,
+ 'Opened URL; got ' + e.detail.url);
+ is(e.detail.name, '');
+ is(e.detail.features, '');
+
+ // Call preventDefault, but don't add the iframe to the DOM. This still
+ // amounts to rejecting the popup.
+ e.preventDefault();
+ });
+
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ var msg = e.detail.message;
+ if (msg.indexOf('success:') == 0) {
+ ok(true, msg);
+ }
+ else if (msg == 'finish') {
+ SimpleTest.finish();
+ }
+ else {
+ ok(false, msg);
+ }
+ });
+
+ iframe.src = 'file_browserElement_OpenWindowRejected.html';
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_Opensearch.js b/dom/browser-element/mochitest/browserElement_Opensearch.js
new file mode 100644
index 000000000..8df44d2a9
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Opensearch.js
@@ -0,0 +1,109 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the onmozbrowseropensearch event works.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function createHtml(link) {
+ return 'data:text/html,<html><head>' + link + '<body></body></html>';
+}
+
+function createLink(name) {
+ return '<link rel="search" title="Test OpenSearch" type="application/opensearchdescription+xml" href="http://example.com/' + name + '.xml">';
+}
+
+function runTest() {
+ var iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe1);
+
+ // iframe2 is a red herring; we modify its link but don't listen for
+ // opensearch; we want to make sure that its opensearch events aren't
+ // picked up by the listener on iframe1.
+ var iframe2 = document.createElement('iframe');
+ iframe2.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe2);
+
+ // iframe3 is another red herring. It's not a mozbrowser, so we shouldn't
+ // get any opensearch events on it.
+ var iframe3 = document.createElement('iframe');
+ document.body.appendChild(iframe3);
+
+ var numLinkChanges = 0;
+
+ iframe1.addEventListener('mozbrowseropensearch', function(e) {
+
+ numLinkChanges++;
+
+ if (numLinkChanges == 1) {
+ is(e.detail.title, 'Test OpenSearch');
+ is(e.detail.href, 'http://example.com/mysearch.xml');
+
+ // We should recieve opensearch events when the user creates new links
+ // to a search engine, but only when we listen for them
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.title='New title';",
+ /* allowDelayedLoad = */ false);
+
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=SEARCH type=application/opensearchdescription+xml href=http://example.com/newsearch.xml>')",
+ /* allowDelayedLoad = */ false);
+
+ SpecialPowers.getBrowserFrameMessageManager(iframe2)
+ .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=SEARCH type=application/opensearchdescription+xml href=http://example.com/newsearch.xml>')",
+ /* allowDelayedLoad = */ false);
+ }
+ else if (numLinkChanges == 2) {
+ is(e.detail.href, 'http://example.com/newsearch.xml');
+
+ // Full new pages should trigger opensearch events
+ iframe1.src = createHtml(createLink('3rdsearch'));
+ }
+ else if (numLinkChanges == 3) {
+ is(e.detail.href, 'http://example.com/3rdsearch.xml');
+
+ // the rel attribute can have various space seperated values, make
+ // sure we only pick up correct values for 'opensearch'
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=someopensearch type=application/opensearchdescription+xml href=http://example.com/newsearch.xml>')",
+ /* allowDelayedLoad = */ false);
+ // Test setting a page with multiple links elements
+ iframe1.src = createHtml(createLink('another') + createLink('search'));
+ }
+ else if (numLinkChanges == 4) {
+ is(e.detail.href, 'http://example.com/another.xml');
+ // 2 events will be triggered by previous test, wait for next
+ }
+ else if (numLinkChanges == 5) {
+ is(e.detail.href, 'http://example.com/search.xml');
+
+ // Make sure opensearch check is case insensitive
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=SEARCH type=application/opensearchdescription+xml href=http://example.com/ucasesearch.xml>')",
+ /* allowDelayedLoad = */ false);
+ }
+ else if (numLinkChanges == 6) {
+ is(e.detail.href, 'http://example.com/ucasesearch.xml');
+ SimpleTest.finish();
+ } else {
+ ok(false, 'Too many opensearch events.');
+ }
+ });
+
+ iframe3.addEventListener('mozbrowseropensearch', function(e) {
+ ok(false, 'Should not get a opensearch event for iframe3.');
+ });
+
+
+ iframe1.src = createHtml(createLink('mysearch'));
+ // We should not recieve opensearch change events for either of the below iframes
+ iframe2.src = createHtml(createLink('mysearch'));
+ iframe3.src = createHtml(createLink('mysearch'));
+
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_PrivateBrowsing.js b/dom/browser-element/mochitest/browserElement_PrivateBrowsing.js
new file mode 100644
index 000000000..c32edcc37
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_PrivateBrowsing.js
@@ -0,0 +1,49 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the mozprivatebrowsing attribute works.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function createFrame(aIsPrivate) {
+ var iframe = document.createElement("iframe");
+ iframe.setAttribute('mozbrowser', 'true');
+ if (aIsPrivate) {
+ iframe.setAttribute("mozprivatebrowsing", "true");
+ }
+ return iframe;
+}
+
+function createTest(aIsPrivate, aExpected, aClearStorage) {
+ info("createTest " + aIsPrivate + " " + aExpected);
+ return new Promise(function(resolve, reject) {
+ var iframe = createFrame(aIsPrivate);
+ document.body.appendChild(iframe);
+
+ iframe.addEventListener("mozbrowsershowmodalprompt", function(e) {
+ is(e.detail.message, aExpected, "Checking localstorage");
+ resolve();
+ });
+
+ var src = "file_browserElement_PrivateBrowsing.html";
+ iframe.src = aClearStorage ? src + "?clear=true" : src;
+
+ });
+}
+
+function runTest() {
+ // We first create a iframe in non private browsing mode, set up some
+ // localstorage, reopen it to check that we get the previously set value.
+ // Finally, open it in private browsing mode and check that localstorage
+ // is clear.
+ createTest(false, "CLEAR", true)
+ .then(() => { return createTest(false, "EMPTY", false); })
+ .then(() => { return createTest(false, "bar", false); })
+ .then(() => { return createTest(true, "EMPTY", false); })
+ .then(SimpleTest.finish);
+}
+
+addEventListener("testready", runTest);
diff --git a/dom/browser-element/mochitest/browserElement_PromptCheck.js b/dom/browser-element/mochitest/browserElement_PromptCheck.js
new file mode 100644
index 000000000..d6edde09f
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_PromptCheck.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that alertCheck (i.e., alert with the opportunity to opt out of future
+// alerts), promptCheck, and confirmCheck work. We do this by spamming
+// alerts/prompts/confirms from inside an <iframe mozbrowser>.
+//
+// At the moment, we treat alertCheck/promptCheck/confirmCheck just like a
+// normal alert. But it's different to nsIPrompt!
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest()
+{
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+
+ var numPrompts = 0;
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ is(e.detail.message, String(numPrompts), "prompt message");
+ if (numPrompts / 10 < 1) {
+ is(e.detail.promptType, 'alert');
+ }
+ else if (numPrompts / 10 < 2) {
+ is(e.detail.promptType, 'confirm');
+ }
+ else {
+ is(e.detail.promptType, 'prompt');
+ }
+
+ numPrompts++;
+ if (numPrompts == 30) {
+ SimpleTest.finish();
+ }
+ });
+
+ iframe.src =
+ 'data:text/html,<html><body><script>\
+ addEventListener("load", function() { \
+ setTimeout(function() { \
+ var i = 0; \
+ for (; i < 10; i++) { alert(i); } \
+ for (; i < 20; i++) { confirm(i); } \
+ for (; i < 30; i++) { prompt(i); } \
+ }); \
+ }); \
+ </scr' + 'ipt></body></html>';
+}
+
+// The test harness sets dom.successive_dialog_time_limit to 0 for some bizarre
+// reason. That's not normal usage, and it keeps us from testing alertCheck!
+addEventListener('testready', function() {
+ SpecialPowers.pushPrefEnv({'set': [['dom.successive_dialog_time_limit', 10]]}, runTest);
+});
diff --git a/dom/browser-element/mochitest/browserElement_PromptConfirm.js b/dom/browser-element/mochitest/browserElement_PromptConfirm.js
new file mode 100644
index 000000000..c01836a25
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_PromptConfirm.js
@@ -0,0 +1,87 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that prompt and confirm work. In particular, we're concerned that we
+// get correct return values out of them.
+//
+// We use alert() to communicate the return values of prompt/confirm back to
+// ourselves.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+
+ var prompts = [
+ {msg: '1', type: 'alert', rv: 42, expected: 'undefined'},
+ {msg: '2', type: 'confirm', rv: true, expected: 'true'},
+ {msg: '3', type: 'confirm', rv: false, expected: 'false'},
+
+ // rv == 42 should be coerced to 'true' for confirm.
+ {msg: '4', type: 'confirm', rv: 42, expected: 'true'},
+ {msg: '5', type: 'prompt', rv: 'worked', expected: 'worked'},
+ {msg: '6', type: 'prompt', rv: null, expected: 'null'},
+ {msg: '7', type: 'prompt', rv: '', expected: ''}
+ ];
+
+ iframe.addEventListener("mozbrowsershowmodalprompt", function(e) {
+ var curPrompt = prompts[0];
+ if (!curPrompt.waitingForResponse) {
+ curPrompt.waitingForResponse = true;
+
+ is(e.detail.message, curPrompt.msg, "prompt message");
+ is(e.detail.promptType, curPrompt.type, "prompt type");
+
+ if (e.detail.promptType == 'prompt') {
+ ok(e.detail.returnValue === null, "prompt's returnValue should be null");
+ is(e.detail.initialValue, "initial", "prompt's initial value.");
+ }
+ else {
+ ok(e.detail.returnValue === undefined,
+ "Other than for prompt, shouldn't have initial value.");
+ }
+
+ // Block the child until we call e.detail.unblock().
+ e.preventDefault();
+
+ SimpleTest.executeSoon(function() {
+ e.detail.returnValue = curPrompt.rv;
+ e.detail.unblock();
+ });
+ }
+ else {
+ prompts.shift();
+
+ // |e| now corresponds to an alert() containing the return value we just
+ // sent for this prompt.
+
+ is(e.detail.message, 'RESULT:' + curPrompt.expected,
+ "expected rv for msg " + curPrompt.msg);
+
+ if (prompts.length == 0) {
+ SimpleTest.finish();
+ }
+ }
+ });
+
+ iframe.src =
+ 'data:text/html,<html><body><script>\
+ function sendVal(val) { \
+ alert("RESULT:" + val); \
+ } \
+ sendVal(alert("1")); \
+ sendVal(confirm("2")); \
+ sendVal(confirm("3")); \
+ sendVal(confirm("4")); \
+ sendVal(prompt("5", "initial")); \
+ sendVal(prompt("6", "initial")); \
+ sendVal(prompt("7", "initial")); \
+ </scr' + 'ipt></body></html>';
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_Proxy.js b/dom/browser-element/mochitest/browserElement_Proxy.js
new file mode 100644
index 000000000..227b40c5f
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Proxy.js
@@ -0,0 +1,163 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ let frameUrl = SimpleTest.getTestFileURL('/file_empty.html');
+ SpecialPowers.pushPermissions([{
+ type: 'browser:embedded-system-app',
+ allow: true,
+ context: {
+ url: frameUrl,
+ originAttributes: {
+ inIsolatedMozBrowser: true
+ }
+ }
+ },{
+ type: 'browser',
+ allow: true,
+ context: {
+ url: frameUrl,
+ originAttributes: {
+ inIsolatedMozBrowser: true
+ }
+ }
+ }], createFrame);
+}
+
+var frame;
+var mm;
+
+function createFrame() {
+ let loadEnd = function() {
+ // The frame script running in the frame where the input is hosted.
+ let appFrameScript = function appFrameScript() {
+ let i = 1;
+
+ addMessageListener('test:next', function() {
+ try {
+ switch (i) {
+ case 1:
+ content.document.addEventListener(
+ 'visibilitychange', function fn() {
+ content.document.removeEventListener('visibilitychange', fn);
+ sendAsyncMessage('test:done', {
+ ok: true,
+ msg: 'setVisible()'
+ });
+ });
+
+ // Test a no return method
+ content.navigator.mozBrowserElementProxy.setVisible(false);
+
+ break;
+ case 2:
+ // Test a DOMRequest method
+ var req = content.navigator.mozBrowserElementProxy.getVisible();
+ req.onsuccess = function() {
+ sendAsyncMessage('test:done', {
+ ok: true,
+ msg: 'getVisible()'
+ });
+ };
+
+ req.onerror = function() {
+ sendAsyncMessage('test:done', {
+ ok: false,
+ msg: 'getVisible() DOMRequest return error.'
+ });
+ };
+
+ break;
+ case 3:
+ // Test an unimplemented method
+ try {
+ content.navigator.mozBrowserElementProxy.getActive();
+ sendAsyncMessage('test:done', {
+ ok: false,
+ msg: 'getActive() should throw.'
+ });
+
+ } catch (e) {
+ sendAsyncMessage('test:done', {
+ ok: true,
+ msg: 'getActive() throws.'
+ });
+ }
+
+ break;
+ case 4:
+ content.navigator.mozBrowserElementProxy
+ .addEventListener(
+ 'mozbrowserlocationchange',
+ function() {
+ content.navigator.mozBrowserElementProxy
+ .onmozbrowserlocationchange = null;
+
+ sendAsyncMessage('test:done', {
+ ok: true,
+ msg: 'mozbrowserlocationchange'
+ });
+ });
+
+ // Test event
+ content.location.hash = '#foo';
+
+ break;
+ }
+ } catch (e) {
+ sendAsyncMessage('test:done', {
+ ok: false, msg: 'thrown: ' + e.toString() });
+ }
+
+ i++;
+ });
+
+ sendAsyncMessage('test:done', {});
+ }
+
+ mm = SpecialPowers.getBrowserFrameMessageManager(frame);
+ mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
+ mm.addMessageListener("test:done", next);
+ };
+
+ frame = document.createElement('iframe');
+ frame.setAttribute('mozbrowser', 'true');
+ frame.src = 'file_empty.html';
+ document.body.appendChild(frame);
+ frame.addEventListener('mozbrowserloadend', loadEnd);
+}
+
+var i = 0;
+function next(msg) {
+ let wrappedMsg = SpecialPowers.wrap(msg);
+ let isOK = wrappedMsg.data.ok;
+ let msgString = wrappedMsg.data.msg;
+
+ switch (i) {
+ case 0:
+ mm.sendAsyncMessage('test:next');
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ ok(isOK, msgString);
+ mm.sendAsyncMessage('test:next');
+ break;
+
+ case 4:
+ ok(isOK, msgString);
+ SimpleTest.finish();
+ break;
+ }
+
+ i++;
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_PurgeHistory.js b/dom/browser-element/mochitest/browserElement_PurgeHistory.js
new file mode 100644
index 000000000..4815f03e7
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_PurgeHistory.js
@@ -0,0 +1,87 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 807056 - [Browser] Clear History doesn't clear back/forward history in open tabs
+// <iframe mozbrowser>.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+var iframe;
+function addOneShotIframeEventListener(event, fn) {
+ function wrapper(e) {
+ iframe.removeEventListener(event, wrapper);
+ fn(e);
+ };
+
+ iframe.addEventListener(event, wrapper);
+}
+
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ // FIXME: Bug 1270790
+ iframe.setAttribute('remote', 'true');
+
+ addOneShotIframeEventListener('mozbrowserloadend', function() {
+ SimpleTest.executeSoon(test2);
+ });
+
+ iframe.src = browserElementTestHelpers.emptyPage1;
+ document.body.appendChild(iframe);
+}
+
+function purgeHistory(nextTest) {
+ var seenCanGoBackResult = false;
+ var seenCanGoForwardResult = false;
+
+ iframe.purgeHistory().onsuccess = function(e) {
+ ok(true, "The history has been purged");
+
+ iframe.getCanGoBack().onsuccess = function(e) {
+ is(e.target.result, false, "Iframe cannot go back");
+ seenCanGoBackResult = true;
+ maybeRunNextTest();
+ };
+
+ iframe.getCanGoForward().onsuccess = function(e) {
+ is(e.target.result, false, "Iframe cannot go forward");
+ seenCanGoForwardResult = true;
+ maybeRunNextTest();
+ };
+ };
+
+ function maybeRunNextTest() {
+ if (seenCanGoBackResult && seenCanGoForwardResult) {
+ nextTest();
+ }
+ }
+}
+
+function test2() {
+ purgeHistory(test3);
+}
+
+function test3() {
+ addOneShotIframeEventListener('mozbrowserloadend', function() {
+ purgeHistory(test4);
+ });
+
+ SimpleTest.executeSoon(function() {
+ iframe.src = browserElementTestHelpers.emptyPage2;
+ });
+}
+
+function test4() {
+ addOneShotIframeEventListener('mozbrowserlocationchange', function(e) {
+ is(e.detail.url, browserElementTestHelpers.emptyPage3);
+ purgeHistory(SimpleTest.finish);
+ });
+
+ SimpleTest.executeSoon(function() {
+ iframe.src = browserElementTestHelpers.emptyPage3;
+ });
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_Reload.js b/dom/browser-element/mochitest/browserElement_Reload.js
new file mode 100644
index 000000000..9ef6d8e7e
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Reload.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 741717 - Test the reload ability of <iframe mozbrowser>.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+var iframeScript = function() {
+ sendAsyncMessage('test:innerHTML', {
+ data: XPCNativeWrapper.unwrap(content).document.body.innerHTML
+ });
+}
+
+var mm;
+var iframe;
+var loadedEvents = 0;
+var countAcc;
+
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ iframe.addEventListener('mozbrowserloadend', mozbrowserLoaded);
+
+ iframe.src = 'file_bug741717.sjs';
+ document.body.appendChild(iframe);
+}
+
+function iframeBodyRecv(data) {
+ data = SpecialPowers.wrap(data);
+ var previousCount = countAcc;
+ var currentCount = parseInt(data.json.data, 10);
+ countAcc = currentCount;
+ switch (loadedEvents) {
+ case 1:
+ iframe.reload();
+ break;
+ case 2:
+ ok(true, 'reload was triggered');
+ ok(previousCount === currentCount, 'reload was a soft reload');
+ iframe.reload(true);
+ break;
+ case 3:
+ ok(currentCount > previousCount, 'reload was a hard reload');
+ SimpleTest.finish();
+ }
+}
+
+function mozbrowserLoaded() {
+ loadedEvents++;
+ mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+ mm.addMessageListener('test:innerHTML', iframeBodyRecv);
+ mm.loadFrameScript('data:,(' + iframeScript.toString() + ')();', false);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_ReloadPostRequest.js b/dom/browser-element/mochitest/browserElement_ReloadPostRequest.js
new file mode 100644
index 000000000..614ed7c49
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_ReloadPostRequest.js
@@ -0,0 +1,116 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 793644, fire an event when attempting to reloads browser element after
+// POST respest.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+browserElementTestHelpers.setEnabledPref(true);
+
+var iframe;
+var gotConfirmRepost = false;
+var doRepost = true;
+var timer;
+var isPostRequestSubmitted;
+
+function getExpectedStrings() {
+ let result = {};
+ let bundleService = SpecialPowers.Cc['@mozilla.org/intl/stringbundle;1'].
+ getService(SpecialPowers.Ci.nsIStringBundleService);
+ let appBundle = bundleService.createBundle("chrome://global/locale/appstrings.properties");
+ let brandBundle = bundleService.createBundle("chrome://branding/locale/brand.properties");
+ try {
+ let brandName = brandBundle.GetStringFromName("brandShortName");
+ result.message = appBundle.formatStringFromName("confirmRepostPrompt",
+ [brandName], 1);
+ } catch (e) {
+ // for the case that we don't have brandShortName
+ result.message = appBundle.GetStringFromName("confirmRepostPrompt");
+ }
+ result.resend = appBundle.GetStringFromName("resendButton.label");
+
+ return result;
+}
+
+function failBecauseReloaded() {
+ window.clearTimeout(timer);
+ timer = null;
+ iframe.removeEventListener('mozbrowserloadend', failBecauseReloaded);
+ ok(false, "We don't expect browser element to reload, but it did");
+ SimpleTest.finish();
+};
+
+function reloadDone() {
+ iframe.removeEventListener('mozbrowserloadend', reloadDone);
+ ok(gotConfirmRepost, "Didn't get confirmEx prompt before reload");
+
+ // Run again, with repost disallowed.
+ doRepost = false;
+ isPostRequestSubmitted = false;
+ iframe.src = 'file_post_request.html';
+ iframe.addEventListener('mozbrowserloadend', pageLoadDone);
+}
+
+function pageLoadDone() {
+ if (!isPostRequestSubmitted) {
+ // This loadend is done by setting url in address bar, so we don't need to
+ // do anything. The test page will submit a POST request.
+ isPostRequestSubmitted = true;
+ return;
+ }
+
+ gotConfirmRepost = false;
+ iframe.removeEventListener('mozbrowserloadend', pageLoadDone);
+ if (doRepost) {
+ iframe.addEventListener('mozbrowserloadend', reloadDone);
+ } else {
+ // We don't expect browserelement to reload; use a timer to make sure
+ // it is not reloaded.
+ iframe.addEventListener('mozbrowserloadend', failBecauseReloaded);
+ }
+ iframe.reload();
+}
+
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ isPostRequestSubmitted = false;
+ iframe.src = 'file_post_request.html';
+ document.body.appendChild(iframe);
+
+ iframe.addEventListener('mozbrowserloadend', pageLoadDone);
+
+ let expectedMessage = getExpectedStrings();
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ if (e.detail.promptType == 'custom-prompt') {
+ gotConfirmRepost = true;
+ e.preventDefault();
+ e.detail.returnValue = {
+ selectedButton: doRepost ? 0 : 1,
+ };
+ is(e.detail.returnValue.checked, undefined);
+ is(e.detail.buttons[0].messageType, 'custom');
+ is(e.detail.buttons[0].message, expectedMessage.resend);
+ is(e.detail.buttons[1].messageType, 'builtin');
+ is(e.detail.buttons[1].message, 'cancel');
+ is(e.detail.message, expectedMessage.message);
+ is(e.detail.buttons.length, 2);
+ is(e.detail.showCheckbox, false);
+ is(e.detail.checkboxMessage, null);
+ e.detail.unblock();
+
+ if (!doRepost) {
+ // To make sure the page doesn't reload in 1 sec.
+ timer = window.setTimeout(function() {
+ iframe.removeEventListener('mozbrowserloadend', failBecauseReloaded);
+ SimpleTest.finish();
+ }, 1000);
+ }
+ }
+ });
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_RemoveBrowserElement.js b/dom/browser-element/mochitest/browserElement_RemoveBrowserElement.js
new file mode 100644
index 000000000..583d58734
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_RemoveBrowserElement.js
@@ -0,0 +1,30 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 787517: Remove iframe in the handler of showmodalprompt. This shouldn't
+// cause an exception to be thrown.
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+
+ iframe.addEventListener("mozbrowsershowmodalprompt", function(e) {
+ document.body.removeChild(iframe);
+ SimpleTest.executeSoon(function() {
+ ok(true);
+ SimpleTest.finish();
+ });
+ });
+
+ iframe.src = "data:text/html,<html><body><script>alert(\"test\")</script>" +
+ "</body></html>";
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_ScrollEvent.js b/dom/browser-element/mochitest/browserElement_ScrollEvent.js
new file mode 100644
index 000000000..5c4b4dcf9
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_ScrollEvent.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that scroll event bubbles up.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+
+ iframe.addEventListener("mozbrowserscroll", function(e) {
+ ok(true, "got mozbrowserscroll event.");
+ ok(e.detail, "event.detail is not null.");
+ ok(e.detail.top === 4000, "top position is correct.");
+ ok(e.detail.left === 4000, "left position is correct.");
+ SimpleTest.finish();
+ });
+
+ iframe.src = "data:text/html,<html><body style='min-height: 5000px; min-width: 5000px;'></body><script>window.scrollTo(4000, 4000);</script></html>";
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_SecurityChange.js b/dom/browser-element/mochitest/browserElement_SecurityChange.js
new file mode 100644
index 000000000..0ef64b3fa
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_SecurityChange.js
@@ -0,0 +1,82 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 763694 - Test that <iframe mozbrowser> delivers proper
+// mozbrowsersecuritychange events.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+const { Services } = SpecialPowers.Cu.import('resource://gre/modules/Services.jsm');
+const { UrlClassifierTestUtils } = SpecialPowers.Cu.import('resource://testing-common/UrlClassifierTestUtils.jsm', {});
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ var lastSecurityState;
+ iframe.addEventListener('mozbrowsersecuritychange', function(e) {
+ lastSecurityState = e.detail;
+ });
+
+ var filepath = 'tests/dom/browser-element/mochitest/file_browserElement_SecurityChange.html';
+
+ var count = 0;
+ iframe.addEventListener('mozbrowserloadend', function(e) {
+ count++;
+ switch (count) {
+ case 1:
+ is(lastSecurityState.state, 'secure');
+ is(lastSecurityState.extendedValidation, false);
+ is(lastSecurityState.trackingContent, false);
+ is(lastSecurityState.mixedContent, false);
+ iframe.src = "http://example.com/" + filepath;
+ break;
+ case 2:
+ is(lastSecurityState.state, 'insecure');
+ is(lastSecurityState.extendedValidation, false);
+ is(lastSecurityState.trackingContent, false);
+ is(lastSecurityState.mixedContent, false);
+ iframe.src = 'https://example.com:443/' + filepath + '?broken';
+ break;
+ case 3:
+ is(lastSecurityState.state, 'broken');
+ is(lastSecurityState.extendedValidation, false);
+ is(lastSecurityState.trackingContent, false);
+ is(lastSecurityState.mixedContent, true);
+ iframe.src = "http://example.com/" + filepath + '?tracking';
+ break;
+ case 4:
+ is(lastSecurityState.state, 'insecure');
+ is(lastSecurityState.extendedValidation, false);
+ // TODO: I'm having trouble getting the tracking protection
+ // test changes to be enabled in the child process, so this
+ // isn't currently blocked in tests, but it works when
+ // manually testing.
+ // is(lastSecurityState.trackingContent, true);
+ is(lastSecurityState.mixedContent, false);
+ SimpleTest.finish();
+ }
+ });
+
+ iframe.src = "https://example.com/" + filepath;
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', function() {
+ SimpleTest.registerCleanupFunction(UrlClassifierTestUtils.cleanupTestTrackers);
+ SpecialPowers.pushPrefEnv({"set" : [
+ ["privacy.trackingprotection.enabled", true],
+ ["privacy.trackingprotection.pbmode.enabled", false],
+ ["browser.safebrowsing.phishing.enabled", false],
+ ["browser.safebrowsing.malware.enabled", false],
+ ]}, () => {
+ SimpleTest.registerCleanupFunction(UrlClassifierTestUtils.cleanupTestTrackers);
+ UrlClassifierTestUtils.addTestTrackers().then(() => {
+ runTest();
+ });
+ });
+});
+
diff --git a/dom/browser-element/mochitest/browserElement_SendEvent.js b/dom/browser-element/mochitest/browserElement_SendEvent.js
new file mode 100644
index 000000000..a65d6f24f
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_SendEvent.js
@@ -0,0 +1,85 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that sendMouseEvent dispatch events.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+function runTest() {
+ var iframe = document.createElement("iframe");
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+ var x = 10;
+ var y = 10;
+ // First we force a reflow so that getChildProcessOffset actually returns
+ // meaningful data.
+ iframe.getBoundingClientRect();
+ // We need to make sure the event coordinates are actually inside the iframe,
+ // relative to the chome window.
+ var tabParent = SpecialPowers.wrap(iframe)
+ .QueryInterface(SpecialPowers.Ci.nsIFrameLoaderOwner)
+ .frameLoader.tabParent;
+ if (tabParent) {
+ let offsetX = {};
+ let offsetY = {};
+ tabParent.getChildProcessOffset(offsetX, offsetY);
+ x -= offsetX.value;
+ y -= offsetY.value;
+ }
+
+ iframe.addEventListener("mozbrowserloadend", function onloadend(e) {
+ iframe.sendMouseEvent("mousedown", x, y, 0, 1, 0);
+ });
+
+ iframe.addEventListener("mozbrowserlocationchange", function onlocchange(e) {
+ var a = document.createElement("a");
+ a.href = e.detail.url;
+
+ switch (a.hash) {
+ case "#mousedown":
+ ok(true, "Receive a mousedown event.");
+ iframe.sendMouseEvent("mousemove", x, y, 0, 0, 0);
+ break;
+ case "#mousemove":
+ ok(true, "Receive a mousemove event.");
+ iframe.sendMouseEvent("mouseup", x, y, 0, 1, 0);
+ break;
+ case "#mouseup":
+ ok(true, "Receive a mouseup event.");
+ break;
+ case "#click":
+ ok(true, "Receive a click event.");
+ if (SpecialPowers.getIntPref("dom.w3c_touch_events.enabled") != 0) {
+ iframe.sendTouchEvent("touchstart", [1], [x], [y], [2], [2],
+ [20], [0.5], 1, 0);
+ } else {
+ iframe.removeEventListener('mozbrowserlocationchange', onlocchange);
+ SimpleTest.finish();
+ }
+ break;
+ case "#touchstart":
+ ok(true, "Receive a touchstart event.");
+ iframe.sendTouchEvent("touchmove", [1], [x], [y], [2], [2],
+ [20], [0.5], 1, 0);
+ case "#touchmove":
+ ok(true, "Receive a touchmove event.");
+ iframe.sendTouchEvent("touchend", [1], [x], [y], [2], [2],
+ [20], [0.5], 1, 0);
+ break;
+ case "#touchend":
+ ok(true, "Receive a touchend event.");
+ iframe.sendTouchEvent("touchcancel", [1], [x], [y], [2], [2],
+ [20], [0.5], 1, 0);
+ iframe.removeEventListener('mozbrowserlocationchange', onlocchange);
+ SimpleTest.finish();
+ break;
+ }
+ });
+
+ iframe.src = "file_browserElement_SendEvent.html";
+
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_SetInputMethodActive.js b/dom/browser-element/mochitest/browserElement_SetInputMethodActive.js
new file mode 100644
index 000000000..2b94f5cda
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_SetInputMethodActive.js
@@ -0,0 +1,323 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 905573 - Add setInputMethodActive to browser elements to allow gaia
+// system set the active IME app.
+'use strict';
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+// We'll need to get the appId from the current document,
+// it's either SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID when
+// we are not running inside an app (e.g. Firefox Desktop),
+// or the appId of Mochitest app when we are running inside that app
+// (e.g. Emulator).
+var currentAppId = SpecialPowers.wrap(document).nodePrincipal.appId;
+var inApp =
+ currentAppId !== SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID;
+// We will also need the manifest URL and set it on iframes.
+var currentAppManifestURL;
+
+if (inApp) {
+ let appsService = SpecialPowers.Cc["@mozilla.org/AppsService;1"]
+ .getService(SpecialPowers.Ci.nsIAppsService);
+
+ currentAppManifestURL = appsService.getManifestURLByLocalId(currentAppId);
+};
+
+info('appId=' + currentAppId);
+info('manifestURL=' + currentAppManifestURL);
+
+function setup() {
+ let appInfo = SpecialPowers.Cc['@mozilla.org/xre/app-info;1']
+ .getService(SpecialPowers.Ci.nsIXULAppInfo);
+ if (appInfo.name != 'B2G') {
+ SpecialPowers.Cu.import("resource://gre/modules/Keyboard.jsm", window);
+ }
+
+ SpecialPowers.setBoolPref("dom.mozInputMethod.enabled", true);
+ SpecialPowers.addPermission('input-manage', true, document);
+}
+
+function tearDown() {
+ SpecialPowers.setBoolPref("dom.mozInputMethod.enabled", false);
+ SpecialPowers.removePermission('input-manage', document);
+ SimpleTest.finish();
+}
+
+function runTest() {
+ createFrames();
+}
+
+var gInputMethodFrames = [];
+var gInputFrame;
+
+function createFrames() {
+ // Create two input method iframes.
+ let loadendCount = 0;
+ let countLoadend = function() {
+ loadendCount++;
+ if (loadendCount === 3) {
+ setPermissions();
+ }
+ };
+
+ // Create an input field to receive string from input method iframes.
+ gInputFrame = document.createElement('iframe');
+ gInputFrame.setAttribute('mozbrowser', 'true');
+ gInputFrame.src = 'file_browserElement_SetInputMethodActive.html';
+ document.body.appendChild(gInputFrame);
+ gInputFrame.addEventListener('mozbrowserloadend', countLoadend);
+
+ for (let i = 0; i < 2; i++) {
+ let frame = gInputMethodFrames[i] = document.createElement('iframe');
+ frame.setAttribute('mozbrowser', 'true');
+ if (currentAppManifestURL) {
+ frame.setAttribute('mozapp', currentAppManifestURL);
+ }
+ frame.addEventListener('mozbrowserloadend', countLoadend);
+ frame.src = 'file_empty.html#' + i;
+ document.body.appendChild(frame);
+ }
+ }
+
+function setPermissions() {
+ let permissions = [{
+ type: 'input',
+ allow: true,
+ context: {
+ url: SimpleTest.getTestFileURL('/file_empty.html'),
+ originAttributes: {
+ appId: currentAppId,
+ inIsolatedMozBrowser: true
+ }
+ }
+ }];
+
+ if (inApp) {
+ // The current document would also need to be given access for IPC to
+ // recognize our permission (why)?
+ permissions.push({
+ type: 'input', allow: true, context: document });
+ }
+
+ SpecialPowers.pushPermissions(permissions,
+ SimpleTest.waitForFocus.bind(SimpleTest, startTest));
+}
+
+ function startTest() {
+ // The frame script running in the frame where the input is hosted.
+ let appFrameScript = function appFrameScript() {
+ let input = content.document.body.firstElementChild;
+ input.oninput = function() {
+ sendAsyncMessage('test:InputMethod:oninput', {
+ from: 'input',
+ value: this.value
+ });
+ };
+
+ input.onblur = function() {
+ // "Expected" lost of focus since the test is finished.
+ if (input.value === 'hello#0#1') {
+ return;
+ }
+
+ sendAsyncMessage('test:InputMethod:oninput', {
+ from: 'input',
+ error: true,
+ value: 'Unexpected lost of focus on the input frame!'
+ });
+ };
+
+ input.focus();
+ };
+
+ // Inject frame script to receive input.
+ let mm = SpecialPowers.getBrowserFrameMessageManager(gInputFrame);
+ mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
+ mm.addMessageListener("test:InputMethod:oninput", next);
+
+ gInputMethodFrames.forEach((frame) => {
+ ok(frame.setInputMethodActive, 'Can access setInputMethodActive.');
+
+ // The frame script running in the input method frames.
+ let appFrameScript = function appFrameScript() {
+ let im = content.navigator.mozInputMethod;
+ im.oninputcontextchange = function() {
+ let ctx = im.inputcontext;
+ // Report back to parent frame on status of ctx gotten.
+ // (A setTimeout() here to ensure this always happens after
+ // DOMRequest succeed.)
+ content.setTimeout(() => {
+ sendAsyncMessage('test:InputMethod:imFrameMessage', {
+ from: 'im',
+ value: content.location.hash + !!ctx
+ });
+ });
+
+ // If there is a context, send out the hash.
+ if (ctx) {
+ ctx.replaceSurroundingText(content.location.hash);
+ }
+ };
+ };
+
+ // Inject frame script to receive message.
+ let mm = SpecialPowers.getBrowserFrameMessageManager(frame);
+ mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
+ mm.addMessageListener("test:InputMethod:imFrameMessage", next);
+ });
+
+ // Set focus to the input field and wait for input methods' inputting.
+ SpecialPowers.DOMWindowUtils.focus(gInputFrame);
+
+ let req0 = gInputMethodFrames[0].setInputMethodActive(true);
+ req0.onsuccess = function() {
+ ok(true, 'setInputMethodActive succeeded (0).');
+ };
+
+ req0.onerror = function() {
+ ok(false, 'setInputMethodActive failed (0): ' + this.error.name);
+ };
+}
+
+var gCount = 0;
+
+var gFrameMsgCounts = {
+ 'input': 0,
+ 'im0': 0,
+ 'im1': 0
+};
+
+function next(msg) {
+ let wrappedMsg = SpecialPowers.wrap(msg);
+ let from = wrappedMsg.data.from;
+ let value = wrappedMsg.data.value;
+
+ if (wrappedMsg.data.error) {
+ ok(false, wrappedMsg.data.value);
+
+ return;
+ }
+
+ let fromId = from;
+ if (from === 'im') {
+ fromId += value[1];
+ }
+ gFrameMsgCounts[fromId]++;
+
+ // The texts sent from the first and the second input method are '#0' and
+ // '#1' respectively.
+ switch (gCount) {
+ case 0:
+ switch (fromId) {
+ case 'im0':
+ if (gFrameMsgCounts.im0 === 1) {
+ is(value, '#0true', 'First frame should get the context first.');
+ } else {
+ ok(false, 'Unexpected multiple messages from im0.')
+ }
+
+ break;
+
+ case 'im1':
+ is(false, 'Shouldn\'t be hearing anything from second frame.');
+
+ break;
+
+ case 'input':
+ if (gFrameMsgCounts.input === 1) {
+ is(value, '#0hello',
+ 'Failed to get correct input from the first iframe.');
+ } else {
+ ok(false, 'Unexpected multiple messages from input.')
+ }
+
+ break;
+ }
+
+ if (gFrameMsgCounts.input !== 1 ||
+ gFrameMsgCounts.im0 !== 1 ||
+ gFrameMsgCounts.im1 !== 0) {
+ return;
+ }
+
+ gCount++;
+
+ let req0 = gInputMethodFrames[0].setInputMethodActive(false);
+ req0.onsuccess = function() {
+ ok(true, 'setInputMethodActive succeeded (0).');
+ };
+ req0.onerror = function() {
+ ok(false, 'setInputMethodActive failed (0): ' + this.error.name);
+ };
+ let req1 = gInputMethodFrames[1].setInputMethodActive(true);
+ req1.onsuccess = function() {
+ ok(true, 'setInputMethodActive succeeded (1).');
+ };
+ req1.onerror = function() {
+ ok(false, 'setInputMethodActive failed (1): ' + this.error.name);
+ };
+
+ break;
+
+ case 1:
+ switch (fromId) {
+ case 'im0':
+ if (gFrameMsgCounts.im0 === 2) {
+ is(value, '#0false', 'First frame should have the context removed.');
+ } else {
+ ok(false, 'Unexpected multiple messages from im0.')
+ }
+ break;
+
+ case 'im1':
+ if (gFrameMsgCounts.im1 === 1) {
+ is(value, '#1true', 'Second frame should get the context.');
+ } else {
+ ok(false, 'Unexpected multiple messages from im0.')
+ }
+
+ break;
+
+ case 'input':
+ if (gFrameMsgCounts.input === 2) {
+ is(value, '#0#1hello',
+ 'Failed to get correct input from the second iframe.');
+ } else {
+ ok(false, 'Unexpected multiple messages from input.')
+ }
+ break;
+ }
+
+ if (gFrameMsgCounts.input !== 2 ||
+ gFrameMsgCounts.im0 !== 2 ||
+ gFrameMsgCounts.im1 !== 1) {
+ return;
+ }
+
+ gCount++;
+
+ // Receive the second input from the second iframe.
+ // Deactive the second iframe.
+ let req3 = gInputMethodFrames[1].setInputMethodActive(false);
+ req3.onsuccess = function() {
+ ok(true, 'setInputMethodActive(false) succeeded (2).');
+ };
+ req3.onerror = function() {
+ ok(false, 'setInputMethodActive(false) failed (2): ' + this.error.name);
+ };
+ break;
+
+ case 2:
+ is(fromId, 'im1', 'Message sequence unexpected (3).');
+ is(value, '#1false', 'Second frame should have the context removed.');
+
+ tearDown();
+ break;
+ }
+}
+
+setup();
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_SetVisible.js b/dom/browser-element/mochitest/browserElement_SetVisible.js
new file mode 100644
index 000000000..dac8d7e42
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_SetVisible.js
@@ -0,0 +1,75 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the setVisible property for mozbrowser
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+browserElementTestHelpers.setEnabledPref(true);
+
+var iframeScript = function() {
+ content.document.addEventListener("visibilitychange", function() {
+ sendAsyncMessage('test:visibilitychange', {
+ hidden: content.document.hidden
+ });
+ }, false);
+}
+
+function runTest() {
+ var mm;
+ var numEvents = 0;
+ var iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+ iframe1.src = 'data:text/html,1';
+
+ document.body.appendChild(iframe1);
+
+ function recvVisibilityChanged(msg) {
+ msg = SpecialPowers.wrap(msg);
+ numEvents++;
+ if (numEvents === 1) {
+ ok(true, 'iframe recieved visibility changed');
+ ok(msg.json.hidden === true, 'hidden attribute correctly set');
+ iframe1.setVisible(false);
+ iframe1.setVisible(true);
+ } else if (numEvents === 2) {
+ ok(msg.json.hidden === false, 'hidden attribute correctly set');
+ // Allow some time in case we generate too many events
+ setTimeout(function() {
+ mm.removeMessageListener('test:visibilitychange', recvVisibilityChanged);
+ SimpleTest.finish();
+ }, 100);
+ } else {
+ ok(false, 'Too many visibilitychange events');
+ }
+ }
+
+ function iframeLoaded() {
+ testGetVisible();
+ }
+
+ function testGetVisible() {
+ iframe1.setVisible(false);
+ iframe1.getVisible().onsuccess = function(evt) {
+ ok(evt.target.result === false, 'getVisible() responds false after setVisible(false)');
+
+ iframe1.setVisible(true);
+ iframe1.getVisible().onsuccess = function(evt) {
+ ok(evt.target.result === true, 'getVisible() responds true after setVisible(true)');
+ testVisibilityChanges();
+ };
+ };
+ }
+
+ function testVisibilityChanges() {
+ mm = SpecialPowers.getBrowserFrameMessageManager(iframe1);
+ mm.addMessageListener('test:visibilitychange', recvVisibilityChanged);
+ mm.loadFrameScript('data:,(' + iframeScript.toString() + ')();', false);
+ iframe1.setVisible(false);
+ }
+
+ iframe1.addEventListener('mozbrowserloadend', iframeLoaded);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_SetVisibleFrames.js b/dom/browser-element/mochitest/browserElement_SetVisibleFrames.js
new file mode 100644
index 000000000..721248ab9
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_SetVisibleFrames.js
@@ -0,0 +1,89 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 762939 - Test that visibility propagates down properly through
+// hierarchies of <iframe mozbrowser>.
+//
+// In this test, we modify the parent's visibility and check that the child's
+// visibility is changed as appopriate. We test modifying the child's
+// visibility in a separate testcase.
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+var iframe;
+
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ // Our test involves three <iframe mozbrowser>'s, parent, child1, and child2.
+ // child1 and child2 are contained inside parent. child1 is visibile, and
+ // child2 is not.
+ //
+ // For the purposes of this test, we want there to be a process barrier
+ // between child{1,2} and parent. Therefore parent must be a non-remote
+ // <iframe mozbrowser>, until bug 761935 is resolved and we can have nested
+ // content processes.
+ iframe.remote = false;
+
+ iframe.addEventListener('mozbrowsershowmodalprompt', checkMessage);
+ expectMessage('parent:ready', test1);
+
+ document.body.appendChild(iframe);
+ iframe.src = 'file_browserElement_SetVisibleFrames_Outer.html';
+}
+
+function test1() {
+ expectMessage('child1:hidden', getVisibleTest1);
+ iframe.setVisible(false);
+}
+
+function getVisibleTest1() {
+ iframe.getVisible().onsuccess = function(evt) {
+ ok(evt.target.result === false, 'getVisible shows a hidden frame');
+ test2();
+ };
+}
+
+function test2() {
+ expectMessage('child1:visible', getVisibleTest2);
+ iframe.setVisible(true);
+}
+
+function getVisibleTest2() {
+ iframe.getVisible().onsuccess = function(evt) {
+ ok(evt.target.result === true, 'getVisible shows a displayed frame');
+ finish();
+ };
+}
+
+function finish() {
+ // We need to remove this listener because when this test finishes and the
+ // iframe containing this document is navigated, we'll fire a
+ // visibilitychange(false) event on all child iframes. That's OK and
+ // expected, but if we don't remove our listener, then we'll end up causing
+ // the /next/ test to fail!
+ iframe.removeEventListener('mozbrowsershowmodalprompt', checkMessage);
+ SimpleTest.finish();
+}
+
+var expectedMsg = null;
+var expectedMsgCallback = null;
+function expectMessage(msg, next) {
+ expectedMsg = msg;
+ expectedMsgCallback = next;
+}
+
+function checkMessage(e) {
+ var msg = e.detail.message;
+ is(msg, expectedMsg);
+ if (msg == expectedMsg) {
+ expectedMsg = null;
+ SimpleTest.executeSoon(function() { expectedMsgCallback() });
+ }
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js b/dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js
new file mode 100644
index 000000000..cf841a470
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js
@@ -0,0 +1,55 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 762939 - Test that setting a <iframe mozbrowser> to invisible / visible
+// inside an invisible <iframe mozbrowser> doesn't trigger any events.
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ // We need remote = false here until bug 761935 is fixed; see
+ // SetVisibleFrames.js for an explanation.
+ iframe.remote = false;
+
+ iframe.addEventListener('mozbrowserloadend', function loadEnd(e) {
+ iframe.removeEventListener('mozbrowserloadend', loadEnd);
+ iframe.setVisible(false);
+ iframe.src = 'file_browserElement_SetVisibleFrames2_Outer.html';
+ });
+
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ if (e.detail.message == 'parent:finish') {
+ ok(true, "Got parent:finish");
+
+ // Give any extra events a chance to fire, then end the test.
+ SimpleTest.executeSoon(function() {
+ SimpleTest.executeSoon(function() {
+ SimpleTest.executeSoon(function() {
+ SimpleTest.executeSoon(function() {
+ SimpleTest.executeSoon(function() {
+ finish();
+ });
+ });
+ });
+ });
+ });
+ }
+ else {
+ ok(false, "Got unexpected message: " + e.detail.message);
+ }
+ });
+
+ document.body.appendChild(iframe);
+}
+
+function finish() {
+ SimpleTest.finish();
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_Stop.js b/dom/browser-element/mochitest/browserElement_Stop.js
new file mode 100644
index 000000000..67720c148
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Stop.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 709759 - Test the stop ability of <iframe mozbrowser>.
+
+// The img that is loaded will never be returned and will block
+// the page from loading, the timeout ensures that the page is
+// actually blocked from loading, once stop is called the
+// image load will be cancaelled and mozbrowserloadend should be called.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+browserElementTestHelpers.setEnabledPref(true);
+
+var iframe;
+var stopped = false;
+var imgSrc = 'http://test/tests/dom/browser-element/mochitest/file_bug709759.sjs';
+
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ // FIXME: Bug 1270790
+ iframe.setAttribute('remote', 'true');
+ iframe.addEventListener('mozbrowserloadend', loadend);
+ iframe.src = 'data:text/html,<html>' +
+ '<body><img src="' + imgSrc + '" /></body></html>';
+
+ document.body.appendChild(iframe);
+
+ setTimeout(function() {
+ stopped = true;
+ iframe.stop();
+ }, 200);
+}
+
+function loadend() {
+ ok(stopped, 'Iframes network connections were stopped');
+
+ // Wait 1 second and make sure there isn't a mozbrowsererror after stop();
+ iframe.addEventListener('mozbrowsererror', handleError);
+ window.setTimeout(function() {
+ iframe.removeEventListener('mozbrowsererror', handleError);
+ SimpleTest.finish();
+ }, 1000);
+}
+
+function handleError() {
+ ok(false, "mozbrowsererror should not be fired");
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_TargetBlank.js b/dom/browser-element/mochitest/browserElement_TargetBlank.js
new file mode 100644
index 000000000..89c2f33c1
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_TargetBlank.js
@@ -0,0 +1,26 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 764718 - Test that clicking a link with _target=blank works.
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ is(e.detail.url, 'http://example.com/');
+ e.preventDefault();
+ SimpleTest.finish();
+ });
+
+ iframe.src = "file_browserElement_TargetBlank.html";
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_TargetTop.js b/dom/browser-element/mochitest/browserElement_TargetTop.js
new file mode 100644
index 000000000..54bad9c42
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_TargetTop.js
@@ -0,0 +1,31 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 771273 - Check that window.open(url, '_top') works properly with <iframe
+// mozbrowser>.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ ok(false, 'Not expecting an openwindow event.');
+ });
+
+ iframe.addEventListener('mozbrowserlocationchange', function(e) {
+ if (/file_browserElement_TargetTop.html\?2$/.test(e.detail.url)) {
+ ok(true, 'Got the locationchange we were looking for.');
+ SimpleTest.finish();
+ }
+ });
+
+ document.body.appendChild(iframe);
+ iframe.src = 'file_browserElement_TargetTop.html';
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_ThemeColor.js b/dom/browser-element/mochitest/browserElement_ThemeColor.js
new file mode 100644
index 000000000..01e9c5c36
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_ThemeColor.js
@@ -0,0 +1,85 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the onmozbrowsermetachange event for theme-color works.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ function loadFrameScript(script) {
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:," + script,
+ /* allowDelayedLoad = */ false);
+ }
+
+ let iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+ iframe1.src = "http://test/tests/dom/browser-element/mochitest/file_browserElement_ThemeColor.html";
+ iframe1.addEventListener('mozbrowsermetachange', tests);
+ document.body.appendChild(iframe1);
+
+ let numMetaChanges = 0;
+ function tests(e) {
+ let detail = e.detail;
+
+ switch (numMetaChanges++) {
+ case 0: {
+ is(detail.name, 'theme-color', 'name matches');
+ is(detail.content, 'pink', 'content matches');
+ is(detail.type, 'added', 'type matches');
+
+ let script =
+ "var meta = content.document.head.querySelector('meta');" +
+ "meta.content = 'green';";
+ loadFrameScript(script);
+ break;
+ }
+
+ case 1: {
+ is(detail.name, 'theme-color', 'name matches');
+ is(detail.content, 'green', 'content matches');
+ is(detail.type, 'changed', 'type matches');
+
+ let script =
+ "var meta = content.document.createElement('meta');" +
+ "meta.name = 'theme-group';" +
+ "meta.content = 'theme-productivity';" +
+ "content.document.head.appendChild(meta)";
+ loadFrameScript(script);
+ break;
+ }
+
+ case 2: {
+ is(detail.name, 'theme-group', 'name matches');
+ is(detail.content, 'theme-productivity', 'content matches');
+ is(detail.type, 'added', 'type matches');
+
+ let script =
+ "var meta = content.document.head.querySelector('meta');" +
+ "meta.parentNode.removeChild(meta);";
+ loadFrameScript(script);
+ break;
+ }
+
+ case 3: {
+ is(detail.name, 'theme-color', 'name matches');
+ is(detail.content, 'green', 'content matches');
+ is(detail.type, 'removed', 'type matches');
+
+ SimpleTest.finish();
+ break;
+ }
+
+ default: {
+ ok(false, 'Too many metachange events.');
+ break;
+ }
+ }
+ };
+}
+
+window.addEventListener('testready', runTest);
+
diff --git a/dom/browser-element/mochitest/browserElement_Titlechange.js b/dom/browser-element/mochitest/browserElement_Titlechange.js
new file mode 100644
index 000000000..78c939ad8
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Titlechange.js
@@ -0,0 +1,68 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the onmozbrowsertitlechange event works.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe1);
+
+ // iframe2 is a red herring; we modify its title but don't listen for
+ // titlechanges; we want to make sure that its titlechange events aren't
+ // picked up by the listener on iframe1.
+ var iframe2 = document.createElement('iframe');
+ iframe2.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe2);
+
+ // iframe3 is another red herring. It's not a mozbrowser, so we shouldn't
+ // get any titlechange events on it.
+ var iframe3 = document.createElement('iframe');
+ document.body.appendChild(iframe3);
+
+ var numTitleChanges = 0;
+
+ iframe1.addEventListener('mozbrowsertitlechange', function(e) {
+ // Ignore empty titles; these come from about:blank.
+ if (e.detail == '')
+ return;
+
+ numTitleChanges++;
+
+ if (numTitleChanges == 1) {
+ is(e.detail, 'Title');
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript("data:,content.document.title='New title';",
+ /* allowDelayedLoad = */ false);
+ SpecialPowers.getBrowserFrameMessageManager(iframe2)
+ .loadFrameScript("data:,content.document.title='BAD TITLE 2';",
+ /* allowDelayedLoad = */ false);
+ }
+ else if (numTitleChanges == 2) {
+ is(e.detail, 'New title');
+ iframe1.src = 'data:text/html,<html><head><title>Title 3</title></head><body></body></html>';
+ }
+ else if (numTitleChanges == 3) {
+ is(e.detail, 'Title 3');
+ SimpleTest.finish();
+ }
+ else {
+ ok(false, 'Too many titlechange events.');
+ }
+ });
+
+ iframe3.addEventListener('mozbrowsertitlechange', function(e) {
+ ok(false, 'Should not get a titlechange event for iframe3.');
+ });
+
+ iframe1.src = 'data:text/html,<html><head><title>Title</title></head><body></body></html>';
+ iframe2.src = 'data:text/html,<html><head><title>BAD TITLE</title></head><body></body></html>';
+ iframe3.src = 'data:text/html,<html><head><title>SHOULD NOT GET EVENT</title></head><body></body></html>';
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_TopBarrier.js b/dom/browser-element/mochitest/browserElement_TopBarrier.js
new file mode 100644
index 000000000..3bd68854c
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_TopBarrier.js
@@ -0,0 +1,81 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that an <iframe mozbrowser> is a window.{top,parent,frameElement} barrier.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+var iframe;
+function runTest() {
+ iframe = document.createElement('iframe');
+ iframe.addEventListener('mozbrowserloadend', function() {
+ try {
+ outerIframeLoaded();
+ } catch(e) {
+ dump("Got error: " + e + '\n');
+ }
+ });
+ iframe.setAttribute('mozbrowser', 'true');
+ iframe.src = 'data:text/html,Outer iframe <iframe id="inner-iframe"></iframe>';
+ // For kicks, this test uses a display:none iframe. This shouldn't make a
+ // difference in anything.
+ iframe.style.display = 'none';
+ document.body.appendChild(iframe);
+}
+
+var numMsgReceived = 0;
+function outerIframeLoaded() {
+ // If you're changing the amount of is() calls in injectedScript,
+ // also change the number in waitForMessages accordingly
+ var injectedScript =
+ "data:,function is(a, b, desc) { \
+ if (a == b) { \
+ sendAsyncMessage('test:test-pass', desc); \
+ } else { \
+ sendAsyncMessage('test:test-fail', desc + ' ' + a + ' != ' + b); \
+ } \
+ } \
+ is(content.window.top, content.window, 'top'); \
+ is(content.window.content, content.window, 'content'); \
+ is(content.window.parent, content.window, 'parent'); \
+ is(content.window.frameElement, null, 'frameElement'); \
+ var innerIframe = content.document.getElementById('inner-iframe'); \
+ var innerWindow = innerIframe.contentWindow; \
+ is(innerWindow.top, content.window, 'inner top'); \
+ is(innerWindow.content, content.window, 'inner content'); \
+ is(innerWindow.parent, content.window, 'inner parent'); \
+ is(innerWindow.frameElement, innerIframe, 'inner frameElement');"
+
+ var mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+
+ function onRecvTestPass(msg) {
+ numMsgReceived++;
+ ok(true, msg.json);
+ }
+ mm.addMessageListener('test:test-pass', onRecvTestPass);
+
+ function onRecvTestFail(msg) {
+ numMsgReceived++;
+ ok(false, msg.json);
+ }
+ mm.addMessageListener('test:test-fail', onRecvTestFail);
+
+ mm.loadFrameScript(injectedScript, /* allowDelayedLoad = */ false);
+
+ // 8 is the number of is() calls in injectedScript
+ waitForMessages(8);
+}
+
+function waitForMessages(num) {
+ if (numMsgReceived < num) {
+ SimpleTest.executeSoon(function() { waitForMessages(num); });
+ return;
+ }
+
+ SimpleTest.finish();
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_Viewmode.js b/dom/browser-element/mochitest/browserElement_Viewmode.js
new file mode 100644
index 000000000..51627d9a8
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Viewmode.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the onmozbrowsermetachange event for viewmode works.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ function loadFrameScript(script) {
+ SpecialPowers.getBrowserFrameMessageManager(iframe1)
+ .loadFrameScript('data:,' + script,
+ /* allowDelayedLoad = */ false);
+ }
+
+ let iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+ iframe1.src = "http://test/tests/dom/browser-element/mochitest/file_browserElement_Viewmode.html";
+ iframe1.addEventListener('mozbrowsermetachange', tests);
+ document.body.appendChild(iframe1);
+
+ let numMetaChanges = 0;
+ function tests(e) {
+ let detail = e.detail;
+
+ switch (numMetaChanges++) {
+ case 0: {
+ is(detail.name, 'viewmode', 'name matches');
+ is(detail.content, 'projection=stereo', 'content matches');
+ is(detail.type, 'added', 'type matches');
+
+ let script =
+ "var meta = content.document.head.querySelector('meta');" +
+ "meta.content = 'projection=mono';";
+ loadFrameScript(script);
+ break;
+ }
+
+ case 1: {
+ is(detail.name, 'viewmode', 'name matches');
+ is(detail.content, 'projection=mono', 'content matches');
+ is(detail.type, 'changed', 'type matches');
+
+ let script =
+ "var meta = content.document.head.querySelector('meta');" +
+ "meta.parentNode.removeChild(meta);";
+ loadFrameScript(script);
+ break;
+ }
+
+ case 2: {
+ is(detail.name, 'viewmode', 'name matches');
+ is(detail.content, 'projection=mono', 'content matches');
+ is(detail.type, 'removed', 'type matches');
+
+ SimpleTest.finish();
+ break;
+ }
+
+ default: {
+ ok(false, 'Too many metachange events.');
+ break;
+ }
+ }
+ };
+}
+
+window.addEventListener('testready', runTest);
+
diff --git a/dom/browser-element/mochitest/browserElement_VisibilityChange.js b/dom/browser-element/mochitest/browserElement_VisibilityChange.js
new file mode 100644
index 000000000..d7db5f45d
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_VisibilityChange.js
@@ -0,0 +1,42 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the onmozbrowservisibilitychange event works.
+'use strict';
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+var iframe1 = null;
+function runTest() {
+ iframe1 = document.createElement('iframe');
+ iframe1.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe1);
+
+ iframe1.src = 'data:text/html,<html><head><title>Title</title></head><body></body></html>';
+ checkVisibilityFalse();
+}
+
+function checkVisibilityFalse() {
+ iframe1.addEventListener('mozbrowservisibilitychange', function onvisibilitychange(e) {
+ iframe1.removeEventListener(e.type, onvisibilitychange);
+
+ is(e.detail.visible, false, 'Visibility should be false');
+ checkVisibilityTrue();
+ });
+
+ iframe1.setVisible(false);
+}
+
+function checkVisibilityTrue() {
+ iframe1.addEventListener('mozbrowservisibilitychange', function onvisibilitychange(e) {
+ iframe1.removeEventListener(e.type, onvisibilitychange);
+
+ is(e.detail.visible, true, 'Visibility should be true');
+ SimpleTest.finish();
+ });
+
+ iframe1.setVisible(true);
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_XFrameOptions.js b/dom/browser-element/mochitest/browserElement_XFrameOptions.js
new file mode 100644
index 000000000..391c2cb95
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_XFrameOptions.js
@@ -0,0 +1,26 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 770239 - Test that we can load pages with X-Frame-Options: Deny inside
+// <iframe mozbrowser>.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ // The page we load will fire an alert when it successfully loads.
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ ok(true, "Got alert");
+ SimpleTest.finish();
+ });
+
+ document.body.appendChild(iframe);
+ iframe.src = 'file_browserElement_XFrameOptions.sjs?DENY';
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_XFrameOptionsAllowFrom.js b/dom/browser-element/mochitest/browserElement_XFrameOptionsAllowFrom.js
new file mode 100644
index 000000000..3657d9732
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_XFrameOptionsAllowFrom.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 690168 - Support Allow-From notation for X-Frame-Options header.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+var initialScreenshotArrayBuffer = null;
+
+function arrayBuffersEqual(a, b) {
+ var x = new Int8Array(a);
+ var y = new Int8Array(b);
+ if (x.length != y.length) {
+ return false;
+ }
+
+ for (var i = 0; i < x.length; i++) {
+ if (x[i] != y[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function runTest() {
+ var count = 0;
+
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ iframe.height = '1000px';
+
+ var step1, stepfinish;
+ // The innermost page we load will fire an alert when it successfully loads.
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ switch (e.detail.message) {
+ case 'step 1':
+ step1 = SpecialPowers.snapshotWindow(iframe.contentWindow);
+ break;
+ case 'step 2':
+ ok(false, 'cross origin page loaded');
+ break;
+ case 'finish':
+ // The page has now attempted to load the X-Frame-Options page; take
+ // another screenshot.
+ stepfinish = SpecialPowers.snapshotWindow(iframe.contentWindow);
+ ok(step1.toDataURL() == stepfinish.toDataURL(), "Screenshots should be identical");
+ SimpleTest.finish();
+ }
+ });
+
+ document.body.appendChild(iframe);
+
+ iframe.src = 'http://example.com/tests/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.html';
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_XFrameOptionsDeny.js b/dom/browser-element/mochitest/browserElement_XFrameOptionsDeny.js
new file mode 100644
index 000000000..bf307cc19
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_XFrameOptionsDeny.js
@@ -0,0 +1,63 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 770239 - Test that X-Frame-Options will correctly block a page inside a
+// subframe of <iframe mozbrowser>.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+var initialScreenshotArrayBuffer;
+
+function arrayBuffersEqual(a, b) {
+ var x = new Int8Array(a);
+ var y = new Int8Array(b);
+ if (x.length != y.length) {
+ return false;
+ }
+
+ for (var i = 0; i < x.length; i++) {
+ if (x[i] != y[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ // Our child will create two iframes, so make sure this iframe is big enough
+ // to show both of them without scrolling, so taking a screenshot gets both
+ // frames.
+ iframe.height = '1000px';
+
+ var step1, stepfinish;
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ switch (e.detail.message) {
+ case 'step 1':
+ step1 = SpecialPowers.snapshotWindow(iframe.contentWindow);
+ break;
+ case 'step 2':
+ // The page has now attempted to load the X-Frame-Options page; take
+ // another screenshot.
+ stepfinish = SpecialPowers.snapshotWindow(iframe.contentWindow);
+ ok(step1.toDataURL() == stepfinish.toDataURL(), "Screenshots should be identical");
+ SimpleTest.finish();
+ break;
+ }
+ });
+
+ document.body.appendChild(iframe);
+
+ // Load this page from a different origin than ourselves. This page will, in
+ // turn, load a child from mochi.test:8888, our origin, with X-Frame-Options:
+ // SAMEORIGIN. That load should be denied.
+ iframe.src = 'http://example.com/tests/dom/browser-element/mochitest/file_browserElement_XFrameOptionsDeny.html';
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_XFrameOptionsSameOrigin.js b/dom/browser-element/mochitest/browserElement_XFrameOptionsSameOrigin.js
new file mode 100644
index 000000000..35e4ca8f0
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_XFrameOptionsSameOrigin.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 770239 - Load an X-Frame-Options: SAMEORIGIN page inside an <iframe>
+// inside <iframe mozbrowser>. The two iframes will have the same origin, but
+// this page will be of a different origin. The load should succeed.
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ // The innermost page we load will fire an alert when it successfully loads.
+ iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ ok(true, "Got alert");
+ SimpleTest.finish();
+ });
+
+ document.body.appendChild(iframe);
+ iframe.src = 'http://example.com/tests/dom/browser-element/mochitest/file_browserElement_XFrameOptionsSameOrigin.html';
+}
+
+addEventListener('testready', runTest);
diff --git a/dom/browser-element/mochitest/browserElement_getWebManifest.js b/dom/browser-element/mochitest/browserElement_getWebManifest.js
new file mode 100644
index 000000000..c2b8f96f3
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_getWebManifest.js
@@ -0,0 +1,64 @@
+/* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+/*globals async, ok, is, SimpleTest, browserElementTestHelpers*/
+
+// Bug 1169633 - getWebManifest tests
+'use strict';
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+
+// request to load a manifest from a page that doesn't have a manifest.
+// The expected result to be null.
+var test1 = async(function* () {
+ var manifest = yield requestManifest('file_empty.html');
+ is(manifest, null, 'it should be null.');
+});
+
+// request to load a manifest from a page that has a manifest.
+// The expected manifest to have a property name whose value is 'pass'.
+var test2 = async(function* () {
+ var manifest = yield requestManifest('file_web_manifest.html');
+ is(manifest && manifest.name, 'pass', 'it should return a manifest with name pass.');
+});
+
+// Cause an exception by attempting to fetch a file URL,
+// expect onerror to be called.
+var test3 = async(function* () {
+ var gotError = false;
+ try {
+ yield requestManifest('file_illegal_web_manifest.html');
+ } catch (err) {
+ gotError = true;
+ }
+ ok(gotError, 'onerror was called on the DOMRequest.');
+});
+
+// Run the tests
+addEventListener('testready', () => {
+ Promise
+ .all([test1(), test2(), test3()])
+ .then(SimpleTest.finish);
+});
+
+function requestManifest(url) {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ iframe.src = url;
+ document.body.appendChild(iframe);
+ return new Promise((resolve, reject) => {
+ iframe.addEventListener('mozbrowserloadend', function loadend() {
+ iframe.removeEventListener('mozbrowserloadend', loadend);
+ SimpleTest.executeSoon(() => {
+ var req = iframe.getWebManifest();
+ req.onsuccess = () => {
+ document.body.removeChild(iframe);
+ resolve(req.result);
+ };
+ req.onerror = () => {
+ document.body.removeChild(iframe);
+ reject(new Error(req.error));
+ };
+ });
+ });
+ });
+}
diff --git a/dom/browser-element/mochitest/chrome.ini b/dom/browser-element/mochitest/chrome.ini
new file mode 100644
index 000000000..2b0561df8
--- /dev/null
+++ b/dom/browser-element/mochitest/chrome.ini
@@ -0,0 +1,92 @@
+[DEFAULT]
+skip-if = e10s || toolkit == 'android' # Bug 1287720: takes too long on android
+
+support-files =
+ audio.ogg
+ async.js
+ browserElementTestHelpers.js
+ browserElement_ActiveStateChange.js
+ browserElement_AudioChannelSeeking.js
+ browserElement_AudioChannelMutedByDefault.js
+ browserElement_AudioPlayback.js
+ browserElement_AudioChannel.js
+ browserElement_AudioChannel_nested.js
+ browserElement_BackForward.js
+ browserElement_BadScreenshot.js
+ browserElement_DocumentFirstPaint.js
+ browserElement_DOMRequestError.js
+ browserElement_ExecuteScript.js
+ browserElement_Find.js
+ browserElement_GetContentDimensions.js
+ browserElement_GetScreenshot.js
+ browserElement_GetScreenshotDppx.js
+ browserElement_getWebManifest.js
+ browserElement_NextPaint.js
+ browserElement_NoAudioTrack.js
+ browserElement_PurgeHistory.js
+ browserElement_ReloadPostRequest.js
+ browserElement_SendEvent.js
+ browserElement_SetInputMethodActive.js
+ browserElement_SetVisible.js
+ browserElement_SetVisibleFrames.js
+ browserElement_SetVisibleFrames2.js
+ browserElement_Stop.js
+ browserElement_VisibilityChange.js
+ file_audio.html
+ file_browserElement_ActiveStateChange.html
+ file_browserElement_AudioChannelSeeking.html
+ file_browserElement_AudioChannel_nested.html
+ file_browserElement_AudioChannelMutedByDefault.html
+ file_browserElement_ExecuteScript.html
+ file_browserElement_NextPaint.html
+ file_browserElement_NoAudioTrack.html
+ file_browserElement_SendEvent.html
+ file_browserElement_SetInputMethodActive.html
+ file_browserElement_SetVisibleFrames2_Outer.html
+ file_browserElement_SetVisibleFrames_Inner.html
+ file_browserElement_SetVisibleFrames_Outer.html
+ file_bug709759.sjs
+ file_empty.html
+ file_post_request.html
+ file_web_manifest.html
+ file_web_manifest.json
+ file_illegal_web_manifest.html
+ iframe_file_audio.html
+
+[test_browserElement_inproc_ActiveStateChange.html]
+tags = audiochannel
+[test_browserElement_inproc_AudioChannelMutedByDefault.html]
+tags = audiochannel
+skip-if = toolkit == 'android'
+[test_browserElement_inproc_AudioChannelSeeking.html]
+tags = audiochannel
+[test_browserElement_inproc_AudioPlayback.html]
+[test_browserElement_inproc_AudioChannel.html]
+tags = audiochannel
+[test_browserElement_inproc_AudioChannel_nested.html]
+tags = audiochannel
+[test_browserElement_inproc_BackForward.html]
+[test_browserElement_inproc_BadScreenshot.html]
+[test_browserElement_inproc_DocumentFirstPaint.html]
+[test_browserElement_inproc_DOMRequestError.html]
+[test_browserElement_inproc_ExecuteScript.html]
+[test_browserElement_inproc_Find.html]
+[test_browserElement_inproc_GetContentDimensions.html]
+[test_browserElement_inproc_GetScreenshot.html]
+[test_browserElement_inproc_GetScreenshotDppx.html]
+[test_browserElement_inproc_getWebManifest.html]
+[test_browserElement_inproc_NextPaint.html]
+[test_browserElement_inproc_NoAudioTrack.html]
+tags = audiochannel
+[test_browserElement_inproc_PurgeHistory.html]
+[test_browserElement_inproc_ReloadPostRequest.html]
+disabled = no modal prompt on POST reload for chrome window
+[test_browserElement_inproc_SendEvent.html]
+# The setInputMethodActive() tests will timed out on Android
+[test_browserElement_inproc_SetInputMethodActive.html]
+skip-if = true
+[test_browserElement_inproc_SetVisible.html]
+[test_browserElement_inproc_SetVisibleFrames.html]
+[test_browserElement_inproc_SetVisibleFrames2.html]
+[test_browserElement_inproc_Stop.html]
+[test_browserElement_inproc_VisibilityChange.html]
diff --git a/dom/browser-element/mochitest/createNewTest.py b/dom/browser-element/mochitest/createNewTest.py
new file mode 100644
index 000000000..309ff9534
--- /dev/null
+++ b/dom/browser-element/mochitest/createNewTest.py
@@ -0,0 +1,126 @@
+"""A script to generate the browser-element test boilerplate.
+
+This script requires Python 2.7."""
+
+from __future__ import print_function
+
+import sys
+import os
+import stat
+import argparse
+import textwrap
+import subprocess
+
+html_template = textwrap.dedent("""\
+ <!DOCTYPE HTML>
+ <html>
+ <head>
+ <title>Test for Bug {bug}</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ </head>
+ <body>
+ <script type="application/javascript;version=1.7" src="browserElement_{test}.js">
+ </script>
+ </body>
+ </html>""")
+
+# Note: Curly braces are escaped as "{{".
+js_template = textwrap.dedent("""\
+ /* Any copyright is dedicated to the public domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+ // Bug {bug} - FILL IN TEST DESCRIPTION
+ "use strict";
+
+ SimpleTest.waitForExplicitFinish();
+ browserElementTestHelpers.setEnabledPref(true);
+ browserElementTestHelpers.addPermission();
+
+ function runTest() {{
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+
+ // FILL IN TEST
+
+ document.body.appendChild(iframe);
+ }}
+
+ addEventListener('testready', runTest);
+ """)
+
+def print_fill(s):
+ print(textwrap.fill(textwrap.dedent(s)))
+
+def add_to_ini(filename, test, support_file=None):
+ """Add test to mochitest config {filename}, then open
+ $EDITOR and let the user move the filenames to their appropriate
+ places in the file.
+
+ """
+ lines_to_write = ['[{0}]'.format(test)]
+ if support_file:
+ lines_to_write += ['support-files = {0}'.format(support_file)]
+ lines_to_write += ['']
+ with open(filename, 'a') as f:
+ f.write('\n'.join(lines_to_write))
+
+ if 'EDITOR' not in os.environ or not os.environ['EDITOR']:
+ print_fill("""\
+ Now open {filename} and move the filenames to their correct places.")
+ (Define $EDITOR and I'll open your editor for you next time.)""".format(filename=filename))
+ return
+
+ # Count the number of lines in the file
+ with open(filename, 'r') as f:
+ num_lines = len(f.readlines())
+
+ try:
+ subprocess.call([os.environ['EDITOR'],
+ '+%d' % (num_lines - len(lines_to_write) + 2),
+ filename])
+ except Exception as e:
+ print_fill("Error opening $EDITOR: {0}.".format(e))
+ print()
+ print_fill("""\
+ Please open {filename} and move the filenames at the bottom of the
+ file to their correct places.""".format(filename=filename))
+
+def main(test_name, bug_number):
+ global html_template, js_template
+
+ def format(str):
+ return str.format(bug=bug_number, test=test_name)
+
+ def create_file(filename, template):
+ path = os.path.join(os.path.dirname(sys.argv[0]), format(filename))
+ # Create a new file, bailing with an error if the file exists.
+ fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
+
+ try:
+ # This file has 777 permission when created, for whatever reason. Make it rw-rw-r---.
+ os.fchmod(fd, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH)
+ except:
+ # fchmod doesn't work on Windows.
+ pass
+
+ with os.fdopen(fd, 'w') as file:
+ file.write(format(template))
+
+ create_file('browserElement_{test}.js', js_template)
+ create_file('test_browserElement_inproc_{test}.html', html_template)
+ create_file('test_browserElement_oop_{test}.html', html_template)
+
+ add_to_ini('mochitest.ini',
+ format('test_browserElement_inproc_{test}.html'),
+ format('browserElement_{test}.js'))
+ add_to_ini('mochitest-oop.ini',
+ format('test_browserElement_oop_{test}.html'))
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description="Create a new browser-element testcase.")
+ parser.add_argument('test_name')
+ parser.add_argument('bug_number', type=int)
+ args = parser.parse_args()
+ main(args.test_name, args.bug_number)
diff --git a/dom/browser-element/mochitest/file_audio.html b/dom/browser-element/mochitest/file_audio.html
new file mode 100644
index 000000000..0e4a8d7c6
--- /dev/null
+++ b/dom/browser-element/mochitest/file_audio.html
@@ -0,0 +1,15 @@
+<html>
+<body>
+<audio src="chrome://mochitests/content/chrome/dom/browser-element/mochitest/audio.ogg" id="audio" />
+<script>
+var audio = document.getElementById('audio');
+audio.play();
+audio.onended = function() {
+ setTimeout(function() {
+ audio.play();
+ }, 0);
+}
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_ActiveStateChange.html b/dom/browser-element/mochitest/file_browserElement_ActiveStateChange.html
new file mode 100644
index 000000000..5228d67bf
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_ActiveStateChange.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<script type="application/javascript;version=1.7">
+var audio = new Audio();
+audio.src = "audio.ogg";
+audio.loop = true;
+
+function runCommands()
+{
+ switch(location.hash) {
+ case '#play':
+ audio.play();
+ break;
+ case '#pause':
+ audio.pause();
+ break;
+ default :
+ alert("Undefined command!");
+ }
+}
+window.addEventListener('hashchange', runCommands);
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/file_browserElement_AlertInFrame.html b/dom/browser-element/mochitest/file_browserElement_AlertInFrame.html
new file mode 100644
index 000000000..8bdac1d25
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_AlertInFrame.html
@@ -0,0 +1,6 @@
+<html>
+<body>
+I'm file_browserElement_AlertInFrame.html.
+<iframe src='file_browserElement_AlertInFrame_Inner.html'></iframe>
+<body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_AlertInFrame_Inner.html b/dom/browser-element/mochitest/file_browserElement_AlertInFrame_Inner.html
new file mode 100644
index 000000000..958413f2d
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_AlertInFrame_Inner.html
@@ -0,0 +1,12 @@
+<html>
+<body>
+I'm file_browserElement_AlertInFrame_Inner.html.
+
+<script>
+addEventListener('load', function() {
+ alert("Hello");
+});
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_AudioChannelMutedByDefault.html b/dom/browser-element/mochitest/file_browserElement_AudioChannelMutedByDefault.html
new file mode 100644
index 000000000..ea4f3bde1
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_AudioChannelMutedByDefault.html
@@ -0,0 +1,65 @@
+<html>
+<body>
+<script>
+var audio = new Audio("audio.ogg");
+var context = new AudioContext();
+var node = context.createMediaElementSource(audio);
+var sp = context.createScriptProcessor(2048, 1);
+node.connect(sp);
+var expectedSamplesCount;
+var nonzeroSamplesCount = 0;
+var isStarted = false;
+
+function ok(aVal, aMsg) {
+ alert((!!aVal ? "OK" : "KO") + ", " + aMsg);
+}
+
+function finish() {
+ audio.onended = null;
+ audio.pause();
+ alert("DONE");
+}
+
+function processSamples(e) {
+ var buf = e.inputBuffer.getChannelData(0);
+ for (var i = 0; i < buf.length; ++i) {
+ if (buf[i] != 0) {
+ if (!isStarted) {
+ isStarted = true;
+ ok(true, "Start process audio sample.");
+ }
+ nonzeroSamplesCount++;
+ }
+ }
+
+ if (nonzeroSamplesCount >= expectedSamplesCount) {
+ finish();
+ }
+}
+
+audio.oncanplaythrough = function() {
+ var testDuration = audio.duration > 1.0 ? 1.0 : audio.duration * 0.5;
+ expectedSamplesCount = Math.floor(testDuration * context.sampleRate);
+ sp.onaudioprocess = processSamples;
+};
+
+function runCommands()
+{
+ switch(location.hash) {
+ case '#play':
+ ok(true, "Audio starts playing.")
+ audio.play();
+ audio.onended = () => {
+ audio.onended = null;
+ ok(false, "Audio shouldn't go ended in this test!")
+ };
+ break;
+ default :
+ ok(false, "Undefined command!");
+ }
+}
+
+window.addEventListener('hashchange', runCommands);
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_AudioChannelSeeking.html b/dom/browser-element/mochitest/file_browserElement_AudioChannelSeeking.html
new file mode 100644
index 000000000..293f6cadc
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_AudioChannelSeeking.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<script type="application/javascript;version=1.7">
+var audio = new Audio();
+audio.src = "audio.ogg";
+audio.loop = true;
+
+function assert(aVal, aMessage) {
+ return (!aVal) ? ok(false, aMessage) : 0;
+}
+
+function ok(aVal, aMsg) {
+ alert((!!aVal ? "OK" : "KO") + ", " + aMsg);
+}
+
+function info(aMsg) {
+ alert("INFO" + ", " + aMsg);
+}
+
+function randomSeeking() {
+ var seekingPosition = Math.random() * audio.duration;
+ assert(seekingPosition < audio.duration, "Seeking position out of range!")
+ audio.currentTime = seekingPosition;
+ audio.onseeked = () => {
+ audio.onseeked = null;
+ location.hash = '#idle';
+ ok(true, "Seeking complete, position = " + seekingPosition);
+ };
+}
+
+function runCommands()
+{
+ switch(location.hash) {
+ case '#play':
+ audio.play();
+ audio.onplay = () => {
+ audio.onplay = null;
+ info("Start playing, duration = " + audio.duration);
+ };
+ break;
+ case '#seeking':
+ randomSeeking();
+ break;
+ case '#pause':
+ audio.pause();
+ audio.onpause = () => {
+ audio.onpause = null;
+ ok(true, "Stop playing.");
+ };
+ break;
+ case '#idle':
+ break;
+ default :
+ ok(false, "Undefined command!");
+ }
+}
+
+window.addEventListener('hashchange', runCommands);
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/file_browserElement_AudioChannel_nested.html b/dom/browser-element/mochitest/file_browserElement_AudioChannel_nested.html
new file mode 100644
index 000000000..c37a642e2
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_AudioChannel_nested.html
@@ -0,0 +1,63 @@
+<html>
+<head>
+<script type="text/javascript">
+
+ function ok(a, msg) {
+ alert((!!a ? "OK" : "KO") + " " + msg);
+ }
+
+ function is(a, b, msg) {
+ ok(a === b, msg);
+ }
+
+ function finish(a, b, msg) {
+ alert("DONE");
+ }
+
+ addEventListener('load', function(e) {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ // set 'remote' to true here will make the the iframe remote in _inproc_
+ // test and in-process in _oop_ test.
+ iframe.setAttribute('remote', 'true');
+ iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
+
+ iframe.addEventListener('mozbrowserloadend', function(e) {
+ ok("mute" in iframe, "iframe.mute exists");
+ ok("unmute" in iframe, "iframe.unmute exists");
+ ok("getMuted" in iframe, "iframe.getMuted exists");
+ ok("getVolume" in iframe, "iframe.getVolume exists");
+ ok("setVolume" in iframe, "iframe.setVolume exists");
+
+ ok("allowedAudioChannels" in iframe, "allowedAudioChannels exist");
+ var channels = iframe.allowedAudioChannels;
+ is(channels.length, 9, "9 audio channel by default");
+
+ var ac = channels[0];
+
+ ok(ac instanceof BrowserElementAudioChannel, "Correct class");
+ ok("getVolume" in ac, "ac.getVolume exists");
+ ok("setVolume" in ac, "ac.setVolume exists");
+ ok("getMuted" in ac, "ac.getMuted exists");
+ ok("setMuted" in ac, "ac.setMuted exists");
+ ok("isActive" in ac, "ac.isActive exists");
+
+ ac.onactivestatechanged = function() {
+ ok(true, "activestatechanged event received.");
+
+ ac.getVolume().onsuccess = function(e) {
+ ok(e.target.result, 1, "Default volume is 1");
+ };
+
+ finish();
+ }
+ });
+
+ document.body.appendChild(iframe);
+ iframe.src = 'chrome://mochitests/content/chrome/dom/browser-element/mochitest/file_audio.html';
+ });
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_BrowserWindowNamespace.html b/dom/browser-element/mochitest/file_browserElement_BrowserWindowNamespace.html
new file mode 100644
index 000000000..7903a63b8
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_BrowserWindowNamespace.html
@@ -0,0 +1,9 @@
+<html>
+<body>
+<script>
+addEventListener('load', function() {
+ window.open("http://example.com/" + location.hash, "foo");
+});
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_CloseFromOpener.html b/dom/browser-element/mochitest/file_browserElement_CloseFromOpener.html
new file mode 100644
index 000000000..4a08c2792
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_CloseFromOpener.html
@@ -0,0 +1,8 @@
+<html>
+<body>
+<script>
+var win = window.open('file_empty.html');
+win.close();
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_CookiesNotThirdParty.html b/dom/browser-element/mochitest/file_browserElement_CookiesNotThirdParty.html
new file mode 100644
index 000000000..62f39d8ff
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_CookiesNotThirdParty.html
@@ -0,0 +1,25 @@
+<html>
+<body>
+file_browserElement_CookiesNotThirdParty.html
+
+<script type='text/javascript;version=1.7'>
+if (location.search != '?step=2') {
+ // Step 1: Set a cookie.
+ document.cookie = 'file_browserElement_CookiesNotThirdParty';
+ alert('next');
+}
+else {
+ // Step 2: Read the cookie.
+ if (document.cookie == 'file_browserElement_CookiesNotThirdParty') {
+ alert('success: got the correct cookie');
+ }
+ else {
+ alert('failure: got unexpected cookie: "' + document.cookie + '"');
+ }
+
+ alert('finish');
+}
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_ExecuteScript.html b/dom/browser-element/mochitest/file_browserElement_ExecuteScript.html
new file mode 100644
index 000000000..d2c364aeb
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_ExecuteScript.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+ <script>
+window.btoa = () => "fake btoa";
+ </script>
+</head>
+<body>foo</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_ForwardName.html b/dom/browser-element/mochitest/file_browserElement_ForwardName.html
new file mode 100644
index 000000000..60b41bbc6
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_ForwardName.html
@@ -0,0 +1,15 @@
+<html>
+<body>
+<script>
+
+if (window.name == 'foo') {
+ alert("success:window.name == 'foo'");
+}
+else {
+ alert("failure:window.name == '" + window.name + "', expected 'foo'");
+}
+
+window.open('file_browserElement_ForwardName.html#finish', 'foo');
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_FrameWrongURI.html b/dom/browser-element/mochitest/file_browserElement_FrameWrongURI.html
new file mode 100644
index 000000000..1a6cfde0a
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_FrameWrongURI.html
@@ -0,0 +1,5 @@
+<script>
+ function testSucceeded() { alert("success"); }
+ function callback() { return "<script>opener.testSucceeded()</" + "script>"; }
+ var w = window.open("javascript:opener.callback();");
+</script>
diff --git a/dom/browser-element/mochitest/file_browserElement_LoadEvents.html b/dom/browser-element/mochitest/file_browserElement_LoadEvents.html
new file mode 100644
index 000000000..7e0705e9d
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_LoadEvents.html
@@ -0,0 +1,14 @@
+<html>
+<body style="background-color:green;">
+
+<!-- Tests rely on the fact that there's an element in here called 'url' and
+ that there's visible text on the page. -->
+
+Aloha! My URL is <span id='url'></span>.
+
+<script>
+document.getElementById('url').innerHTML = window.location;
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_Metachange.sjs b/dom/browser-element/mochitest/file_browserElement_Metachange.sjs
new file mode 100644
index 000000000..c63a047f7
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_Metachange.sjs
@@ -0,0 +1,7 @@
+function handleRequest(request, response)
+{
+ var p = request.queryString.split('|');
+ response.setHeader('Content-Language', p[0], false);
+ response.write('<html><head><meta name="application-name" content="sjs"' +
+ (p.length > 1 ? (' lang="' + p[1] + '"') : '') + '></head><body></body></html>');
+}
diff --git a/dom/browser-element/mochitest/file_browserElement_NextPaint.html b/dom/browser-element/mochitest/file_browserElement_NextPaint.html
new file mode 100644
index 000000000..d460fc5b9
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_NextPaint.html
@@ -0,0 +1,9 @@
+<html>
+<body>
+<script>
+addEventListener("hashchange", function () {
+ document.body.style.backgroundColor = "red";
+});
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_NoAudioTrack.html b/dom/browser-element/mochitest/file_browserElement_NoAudioTrack.html
new file mode 100644
index 000000000..14304e469
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_NoAudioTrack.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<script type="application/javascript;version=1.7">
+var audio = new Audio();
+audio.src = "noaudio.webm";
+audio.preload = "none";
+audio.loop = true;
+
+function ok(aVal, aMsg) {
+ alert((!!aVal ? "OK" : "KO") + ", " + aMsg);
+}
+
+function runCommands()
+{
+ switch(location.hash) {
+ case '#play':
+ audio.play();
+ ok(true, "Start playing a video without audio track!");
+ break;
+ case '#idle':
+ ok(!audio.paused, "Video is still playing!");
+ break;
+ default :
+ ok(false, "Undefined command!");
+ }
+}
+
+window.addEventListener('hashchange', runCommands);
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/file_browserElement_Open1.html b/dom/browser-element/mochitest/file_browserElement_Open1.html
new file mode 100644
index 000000000..c74415e2e
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_Open1.html
@@ -0,0 +1,34 @@
+<html>
+<body>
+<script>
+
+// Because this file is inside <iframe mozbrowser>, the alert() calls below
+// don't trigger actual dialogs. Instead, the document which contans the
+// iframe receives mozbrowsershowmodalprompt events, which the document uses
+// to determine test success/failure.
+
+function is(x, y, reason) {
+ if (x === y) {
+ alert("success: " + x + " === " + y + ", " + reason);
+ }
+ else {
+ alert("failure: " + x + " !== " + y + ", " + reason);
+ }
+}
+
+function ok(bool, reason) {
+ alert((bool ? "success: " : "failure: ") + reason);
+}
+
+// Send "dialog=1" as a test for bug 783644. It shouldn't have any effect.
+var w = window.open("file_browserElement_Open2.html", "name", "dialog=1");
+w.addEventListener("load", function() {
+ ok(true, "got load");
+ is(w.opener, window, 'opener property');
+ is(w.location.href, location.href.replace('Open1', 'Open2'), 'correct location');
+ is(w.document.getElementById('testElem').innerHTML, 'test', 'elem innerHTML');
+ alert("finish");
+});
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_Open2.html b/dom/browser-element/mochitest/file_browserElement_Open2.html
new file mode 100644
index 000000000..af9d2b6cd
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_Open2.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<div id='testElem'>test</div>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_OpenMixedProcess.html b/dom/browser-element/mochitest/file_browserElement_OpenMixedProcess.html
new file mode 100644
index 000000000..873a99f1a
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_OpenMixedProcess.html
@@ -0,0 +1,22 @@
+<html>
+<body>
+
+<!-- The test relies on the fact that this file is completely empty. -->
+
+<script>
+
+function ok(b, msg)
+{
+ alert((b ? 'pass:' : 'fail:') + msg);
+}
+
+var w = window.open("file_empty.html");
+w.addEventListener('load', function() {
+ ok(true, 'Got load.');
+ ok(w.document.getElementById('url'), 'Found element with id "url"');
+ alert('finish');
+});
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_OpenNamed.html b/dom/browser-element/mochitest/file_browserElement_OpenNamed.html
new file mode 100644
index 000000000..7d2a7661c
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_OpenNamed.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<script>
+window.open('file_browserElement_OpenNamed2.html', 'OpenNamed');
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_OpenNamed2.html b/dom/browser-element/mochitest/file_browserElement_OpenNamed2.html
new file mode 100644
index 000000000..6bf37bb53
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_OpenNamed2.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<script>
+alert('success: loaded');
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_OpenWindowDifferentOrigin.html b/dom/browser-element/mochitest/file_browserElement_OpenWindowDifferentOrigin.html
new file mode 100644
index 000000000..dc08f341c
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_OpenWindowDifferentOrigin.html
@@ -0,0 +1,18 @@
+<html>
+<body>
+
+<div id='name'></div>
+
+<script>
+if (location.search == "?1") {
+ open("http://example.com/tests/dom/browser-element/mochitest/file_browserElement_OpenWindowDifferentOrigin.html?2");
+}
+else if (location.search == "?2") {
+ alert("finish");
+}
+
+document.getElementById('name').innerHTML = location.search;
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_OpenWindowEmpty.html b/dom/browser-element/mochitest/file_browserElement_OpenWindowEmpty.html
new file mode 100644
index 000000000..fefd6f6ca
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_OpenWindowEmpty.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<script>
+window.open();
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_OpenWindowInFrame.html b/dom/browser-element/mochitest/file_browserElement_OpenWindowInFrame.html
new file mode 100644
index 000000000..c1c1cecd3
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_OpenWindowInFrame.html
@@ -0,0 +1,6 @@
+<html>
+<body>
+I'm file_browserElement_OpenInFrame.html.
+<iframe src='file_browserElement_Open1.html'></iframe>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_OpenWindowRejected.html b/dom/browser-element/mochitest/file_browserElement_OpenWindowRejected.html
new file mode 100644
index 000000000..eb6786979
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_OpenWindowRejected.html
@@ -0,0 +1,16 @@
+<html>
+<body>
+
+<script>
+var w = window.open('does_not_exist.html');
+if (!w) {
+ alert("success:w is null");
+}
+else {
+ alert("failure:w is not null -- " + w);
+}
+alert("finish");
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_PrivateBrowsing.html b/dom/browser-element/mochitest/file_browserElement_PrivateBrowsing.html
new file mode 100644
index 000000000..40ff9d8af
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_PrivateBrowsing.html
@@ -0,0 +1,15 @@
+<html>
+<body>
+<script>
+
+if (location.href.indexOf("clear=true") != -1) {
+ localStorage.removeItem("foo");
+ alert("CLEAR");
+} else {
+ var initialValue = localStorage.getItem("foo") || "EMPTY";
+ localStorage.setItem("foo", "bar");
+ alert(initialValue);
+}
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_SecurityChange.html b/dom/browser-element/mochitest/file_browserElement_SecurityChange.html
new file mode 100644
index 000000000..09c006e7c
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_SecurityChange.html
@@ -0,0 +1,21 @@
+<html>
+<head>
+
+<script>
+if (location.search === '?broken') {
+ // Load something non-https.
+ var s = document.createElement('script');
+ s.src = 'http://example.com/dom/browser-element/mochitest/file_empty_script.js';
+ document.head.appendChild(s);
+} else if (location.search === '?tracking') {
+ var img = document.createElement('img');
+ img.src = 'http://tracking.example.com/tests/toolkit/components/url-classifier/tests/mochitest/raptor.jpg';
+ document.body.appendChild(img);
+}
+</script>
+</head>
+
+<body>
+file_browserElement_SecurityChange.html.
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_SendEvent.html b/dom/browser-element/mochitest/file_browserElement_SendEvent.html
new file mode 100644
index 000000000..3c510180d
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_SendEvent.html
@@ -0,0 +1,15 @@
+<html><body>
+<button>send[Mouse|Touch]Event</button>
+</body><script>
+function changeHash(e) {
+ document.location.hash = e.type;
+};
+window.addEventListener('mousedown', changeHash);
+window.addEventListener('mousemove', changeHash);
+window.addEventListener('mouseup', changeHash);
+window.addEventListener('click', changeHash, true);
+window.addEventListener('touchstart', changeHash);
+window.addEventListener('touchmove', changeHash);
+window.addEventListener('touchend', changeHash);
+window.addEventListener('touchcancel', changeHash);
+</script></html>
diff --git a/dom/browser-element/mochitest/file_browserElement_SetInputMethodActive.html b/dom/browser-element/mochitest/file_browserElement_SetInputMethodActive.html
new file mode 100644
index 000000000..5eb17e5f1
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_SetInputMethodActive.html
@@ -0,0 +1,2 @@
+<input autofocus value="hello" />
+<p>This is targetted mozbrowser frame.</p>
diff --git a/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames2_Outer.html b/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames2_Outer.html
new file mode 100644
index 000000000..c4fa25d26
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames2_Outer.html
@@ -0,0 +1,25 @@
+<html>
+<body>
+<script>
+
+var iframe = document.createElement('iframe');
+iframe.setAttribute("mozbrowser", "true");
+
+iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+ if (e.detail.message == 'child:ready') {
+ setTimeout(function() {
+ iframe.setVisible(false);
+ iframe.setVisible(true);
+ setTimeout(function() {
+ alert('parent:finish');
+ }, 0);
+ }, 0);
+ }
+});
+
+document.body.appendChild(iframe);
+iframe.src = 'file_browserElement_SetVisibleFrames_Inner.html?child';
+
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames_Inner.html b/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames_Inner.html
new file mode 100644
index 000000000..8f9b871d6
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames_Inner.html
@@ -0,0 +1,18 @@
+<html>
+<body>
+<script>
+
+var name = location.search.substring(1);
+addEventListener('load', function() {
+ setTimeout(function() {
+ alert(name + ':ready');
+ }, 0);
+});
+
+addEventListener('visibilitychange', function() {
+ alert(name + ':' + (document.hidden ? 'hidden' : 'visible'));
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames_Outer.html b/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames_Outer.html
new file mode 100644
index 000000000..6abcc6b0c
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_SetVisibleFrames_Outer.html
@@ -0,0 +1,45 @@
+<html>
+<body>
+
+<script>
+
+var numPrompts = 0;
+function handlePrompt(e) {
+ numPrompts++;
+
+ // The first two prompts should be "child1:ready" and "child2:ready". Once
+ // we get both of these, forward the child's prompt up to our parent.
+ if (numPrompts == 2) {
+ // This has to happen here, because setVisibile doesn't exist on the iframe
+ // until BrowserElementChild.js is loaded in it. (That's pretty broken...)
+ iframe2.setVisible(false);
+ }
+ else if (numPrompts == 3) {
+ if (e.detail.message != 'child2:hidden') {
+ alert("parent:fail Didn't get expected 'child2:hidden'.");
+ }
+
+ alert('parent:ready');
+ }
+ else if (numPrompts == 4 || numPrompts == 5) {
+ alert(e.detail.message);
+ }
+}
+
+var iframe1 = document.createElement('iframe');
+iframe1.setAttribute("mozbrowser", "true");
+iframe1.addEventListener('mozbrowsershowmodalprompt', handlePrompt);
+
+var iframe2 = document.createElement('iframe');
+iframe2.setAttribute("mozbrowser", "true");
+iframe2.addEventListener('mozbrowsershowmodalprompt', handlePrompt);
+
+iframe1.src = 'file_browserElement_SetVisibleFrames_Inner.html?child1';
+iframe2.src = 'file_browserElement_SetVisibleFrames_Inner.html?child2';
+document.body.appendChild(iframe1);
+document.body.appendChild(iframe2);
+
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_TargetBlank.html b/dom/browser-element/mochitest/file_browserElement_TargetBlank.html
new file mode 100644
index 000000000..860573a3e
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_TargetBlank.html
@@ -0,0 +1,18 @@
+<html>
+<body>
+<a id='link' target='_blank' href="http://example.com">Click me</a>
+
+<script>
+function clickLink() {
+ // See testcase in bug 666604.
+ var e = document.createEvent("MouseEvent");
+ e.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0,
+ false, false, false, false, 0, null);
+ document.getElementById('link').dispatchEvent(e);
+}
+
+addEventListener('load', function() { setTimeout(clickLink, 0) });
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_TargetTop.html b/dom/browser-element/mochitest/file_browserElement_TargetTop.html
new file mode 100644
index 000000000..aad06361d
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_TargetTop.html
@@ -0,0 +1,12 @@
+<html>
+<body>
+<div id='url'></div>
+
+<script>
+if (location.search == '') {
+ window.open('file_browserElement_TargetTop.html?2', '_top');
+}
+document.getElementById('url').innerHTML = document.location.href;
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_ThemeColor.html b/dom/browser-element/mochitest/file_browserElement_ThemeColor.html
new file mode 100644
index 000000000..f8fb9f116
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_ThemeColor.html
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <meta name="theme-color" content="pink">
+ </head>
+
+ <body>
+ </body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_Viewmode.html b/dom/browser-element/mochitest/file_browserElement_Viewmode.html
new file mode 100644
index 000000000..422279e0a
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_Viewmode.html
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <meta name="viewmode" content="projection=stereo">
+ </head>
+
+ <body>
+ </body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_XFrameOptions.sjs b/dom/browser-element/mochitest/file_browserElement_XFrameOptions.sjs
new file mode 100644
index 000000000..7e2375680
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_XFrameOptions.sjs
@@ -0,0 +1,9 @@
+function handleRequest(request, response)
+{
+ response.setHeader("X-Frame-Options", request.queryString, false);
+ response.setHeader("Content-Type", "text/html", false);
+
+ // Tests rely on this page not being entirely blank, because they take
+ // screenshots to determine whether this page was loaded.
+ response.write("<html><body>XFrameOptions test<script>alert('finish')</script></body></html>");
+}
diff --git a/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.html b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.html
new file mode 100644
index 000000000..12a6fd31e
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.html
@@ -0,0 +1,43 @@
+<html>
+<body>
+
+ <!-- Try to load in a frame a cross-origin page which sends:
+ "X-Frame-Options: Allow-From http://mochi.test:8888/",
+ and a cross-origin page which sends
+ "X-Frame-Options: Allow-From http://example.com/". -->
+
+<script>
+
+// Make sure these iframes aren't too tall; they both need to fit inside the
+// iframe this page is contained in, without scrolling, in order for the test's
+// screenshots to work properly.
+
+var frame_src = 'http://example.com/tests/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.sjs';
+
+var iframe1 = document.createElement('iframe');
+iframe1.height = '300px';
+var iframe2 = document.createElement('iframe');
+iframe2.height = '300px';
+document.body.appendChild(iframe1);
+
+iframe1.addEventListener('load', function iframe1Load() {
+ iframe1.removeEventListener('load', iframe1Load);
+ // This causes our embedder to take a screenshot (and blocks until the
+ // screenshot is completed).
+ var iframe2Loaded = false;
+ iframe2.addEventListener('load', function iframe2Load() {
+ iframe2.removeEventListener('load', iframe2Load);
+ iframe2Loaded = true;
+ alert('finish');
+ });
+
+ document.body.appendChild(iframe2);
+ iframe2.src = frame_src;
+});
+
+
+iframe1.src = frame_src + '?iframe1';
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.sjs b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.sjs
new file mode 100644
index 000000000..4a5dbaace
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.sjs
@@ -0,0 +1,16 @@
+function handleRequest(request, response)
+{
+ var content = 'step 1';
+ if (request.queryString == "iframe1") {
+ response.setHeader("X-Frame-Options", "Allow-From http://mochi.test:8888/")
+ content = 'finish';
+ } else {
+ response.setHeader("X-Frame-Options", "Allow-From http://example.com")
+ }
+
+ response.setHeader("Content-Type", "text/html", false);
+
+ // Tests rely on this page not being entirely blank, because they take
+ // screenshots to determine whether this page was loaded.
+ response.write("<html><body>XFrameOptions test<script>alert('" + content + "')</script></body></html>");
+}
diff --git a/dom/browser-element/mochitest/file_browserElement_XFrameOptionsDeny.html b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsDeny.html
new file mode 100644
index 000000000..338275aa3
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsDeny.html
@@ -0,0 +1,57 @@
+<html>
+<body>
+
+<!-- Try to load in a frame a page which sends "X-Frame-Options: DENY", and a
+ cross-origin page which sends "X-Frame-Options: SAMEORIGIN". -->
+
+<script>
+
+// Make sure these iframes aren't too tall; they both need to fit inside the
+// iframe this page is contained in, without scrolling, in order for the test's
+// screenshots to work properly.
+
+var iframe1 = document.createElement('iframe');
+iframe1.height = '300px';
+var iframe2 = document.createElement('iframe');
+iframe2.height = '300px';
+document.body.appendChild(iframe1);
+document.body.appendChild(iframe2);
+
+// This causes our embedder to take a screenshot (and blocks until the
+// screenshot is completed).
+alert('step 1');
+
+// Wait for both iframes to load.
+
+var iframe1Loaded = false;
+iframe1.addEventListener('load', function iframe1Load() {
+ iframe1.removeEventListener('load', iframe1Load);
+ iframe1Loaded = true;
+ waitForBothLoads();
+});
+
+var iframe2Loaded = false;
+iframe2.addEventListener('load', function iframe2Load() {
+ iframe2.removeEventListener('load', iframe2Load);
+ iframe2Loaded = true;
+ waitForBothLoads();
+});
+
+function waitForBothLoads() {
+ if (iframe1Loaded && iframe2Loaded) {
+ setTimeout(function() {
+ // This causes our embedder to take another screenshot.
+ alert('step 2');
+ }, 0);
+ }
+}
+
+iframe1.src = 'file_browserElement_XFrameOptions.sjs?DENY';
+
+// Load iframe2 with the origin of our parent. Since we have a different
+// origin and are inside <iframe mozbrowser>, this should not load.
+iframe2.src = 'http://mochi.test:8888/tests/dom/browser-element/mochitest/file_browserElement_XFrameOptions.sjs?SAMEORIGIN';
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_browserElement_XFrameOptionsSameOrigin.html b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsSameOrigin.html
new file mode 100644
index 000000000..11e75f141
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsSameOrigin.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<iframe src='file_browserElement_XFrameOptions.sjs?SAMEORIGIN'></iframe>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_bug709759.sjs b/dom/browser-element/mochitest/file_bug709759.sjs
new file mode 100644
index 000000000..ce78b188b
--- /dev/null
+++ b/dom/browser-element/mochitest/file_bug709759.sjs
@@ -0,0 +1,5 @@
+function handleRequest(request, response)
+{
+ response.processAsync();
+ response.setHeader("Content-Type", "image/jpeg", false);
+} \ No newline at end of file
diff --git a/dom/browser-element/mochitest/file_bug741717.sjs b/dom/browser-element/mochitest/file_bug741717.sjs
new file mode 100644
index 000000000..bde9ddfae
--- /dev/null
+++ b/dom/browser-element/mochitest/file_bug741717.sjs
@@ -0,0 +1,27 @@
+function handleRequest(request, response)
+{
+ function etag(count) {
+ return '"anetag' + count + '"';
+ }
+
+ var count = parseInt(getState('count'));
+ if (!count)
+ count = 0;
+
+ // reload(false) will make a request with If-None-Match headers
+ var ifNoneMatch = request.hasHeader("If-None-Match") ?
+ request.getHeader("If-None-Match") : "";
+
+ if (ifNoneMatch === etag(count)) {
+ response.setStatusLine(request.httpVersion, "304", "Not Modified");
+ return;
+ }
+
+ count++;
+ setState('count', count + '');
+
+ response.setHeader('Content-Type', 'text/html', false);
+ response.setHeader('Cache-Control', 'public, max-age=3600', false);
+ response.setHeader("ETag", etag(count), false);
+ response.write('<html><body>' + count + '</body></html>');
+}
diff --git a/dom/browser-element/mochitest/file_download_bin.sjs b/dom/browser-element/mochitest/file_download_bin.sjs
new file mode 100644
index 000000000..fd394ea0a
--- /dev/null
+++ b/dom/browser-element/mochitest/file_download_bin.sjs
@@ -0,0 +1,4 @@
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "application/octet-stream", false);
+ response.write("BIN");
+} \ No newline at end of file
diff --git a/dom/browser-element/mochitest/file_empty.html b/dom/browser-element/mochitest/file_empty.html
new file mode 100644
index 000000000..ed21305b9
--- /dev/null
+++ b/dom/browser-element/mochitest/file_empty.html
@@ -0,0 +1,14 @@
+<html>
+<body>
+
+<!-- Tests rely on the fact that there's an element in here called 'url' and
+ that there's visible text on the page. -->
+
+Aloha! My URL is <span id='url'></span>.
+
+<script>
+document.getElementById('url').innerHTML = window.location;
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_empty_script.js b/dom/browser-element/mochitest/file_empty_script.js
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/dom/browser-element/mochitest/file_empty_script.js
diff --git a/dom/browser-element/mochitest/file_focus.html b/dom/browser-element/mochitest/file_focus.html
new file mode 100644
index 000000000..0bd3f7aa4
--- /dev/null
+++ b/dom/browser-element/mochitest/file_focus.html
@@ -0,0 +1,24 @@
+<html>
+<body>
+
+Aloha! My URL is <span id='url'></span>.
+<script>
+document.getElementById('url').innerHTML = window.location;
+</script>
+
+<script>
+ // The input element is getting synthesized key events and will prevent
+ // default on the first ESC keydown event.
+
+ var alreadyBlocked = false;
+
+ addEventListener('keydown', function(e) {
+ if (e.keyCode == SpecialPowers.Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE &&
+ alreadyBlocked == false) {
+ alreadyBlocked = true;
+ e.preventDefault();
+ }
+ });
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_http_401_response.sjs b/dom/browser-element/mochitest/file_http_401_response.sjs
new file mode 100644
index 000000000..c40a252c3
--- /dev/null
+++ b/dom/browser-element/mochitest/file_http_401_response.sjs
@@ -0,0 +1,16 @@
+function handleRequest(request, response)
+{
+ var auth = "";
+ try {
+ auth = request.getHeader("Authorization");
+ } catch(e) {}
+
+ if (auth == "Basic aHR0cHVzZXI6aHR0cHBhc3M=") {
+ response.setStatusLine("1.1", 200, "OK");
+ response.write("<html><head><title>http auth success</title></head><html>");
+ } else {
+ response.setStatusLine("1.1", 401, "Http authentication required");
+ response.setHeader("WWW-Authenticate", "Basic realm=\"http_realm\"");
+ response.write("<html><head><title>http auth failed</title></head><html>");
+ }
+} \ No newline at end of file
diff --git a/dom/browser-element/mochitest/file_http_407_response.sjs b/dom/browser-element/mochitest/file_http_407_response.sjs
new file mode 100644
index 000000000..da2f27620
--- /dev/null
+++ b/dom/browser-element/mochitest/file_http_407_response.sjs
@@ -0,0 +1,16 @@
+function handleRequest(request, response)
+{
+ var auth = "";
+ try {
+ auth = request.getHeader("Proxy-Authorization");
+ } catch(e) {}
+
+ if (auth == "Basic cHJveHl1c2VyOnByb3h5cGFzcw==") {
+ response.setStatusLine("1.1", 200, "OK");
+ response.write("<html><head><title>http auth success</title></head><html>");
+ } else {
+ response.setStatusLine("1.1", 407, "Proxy Authentication Required");
+ response.setHeader("Proxy-Authenticate", "Basic realm=\"http_realm\"");
+ response.write("<html><head><title>http auth failed</title></head><html>");
+ }
+}
diff --git a/dom/browser-element/mochitest/file_illegal_web_manifest.html b/dom/browser-element/mochitest/file_illegal_web_manifest.html
new file mode 100644
index 000000000..d9075b3fc
--- /dev/null
+++ b/dom/browser-element/mochitest/file_illegal_web_manifest.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<meta charset=utf-8>
+<head>
+<!-- FIXME: we should keep file:// here ... -->
+<link rel="manifest" href="sshfs://this_is_not_allowed!">
+</head>
+<h1>Support Page for Web Manifest Tests</h1>
diff --git a/dom/browser-element/mochitest/file_post_request.html b/dom/browser-element/mochitest/file_post_request.html
new file mode 100644
index 000000000..773193067
--- /dev/null
+++ b/dom/browser-element/mochitest/file_post_request.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+ <script>
+ addEventListener('load', function() {
+ document.getElementsByTagName('form')[0].submit();
+ });
+ </script>
+</head>
+<body>
+ <form action="file_empty.html" method="POST">
+ <input type="text" name="postvalue" value="I am a test string!!" />
+ <input type="submit" />
+ </form>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/file_web_manifest.html b/dom/browser-element/mochitest/file_web_manifest.html
new file mode 100644
index 000000000..783da0f47
--- /dev/null
+++ b/dom/browser-element/mochitest/file_web_manifest.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<meta charset=utf-8>
+<head>
+<link rel="manifest" href="file_web_manifest.json">
+</head>
+<h1>Support Page for Web Manifest Tests</h1>
diff --git a/dom/browser-element/mochitest/file_web_manifest.json b/dom/browser-element/mochitest/file_web_manifest.json
new file mode 100644
index 000000000..57d0c3d42
--- /dev/null
+++ b/dom/browser-element/mochitest/file_web_manifest.json
@@ -0,0 +1 @@
+{"name": "pass"}
diff --git a/dom/browser-element/mochitest/file_wyciwyg.html b/dom/browser-element/mochitest/file_wyciwyg.html
new file mode 100644
index 000000000..f53216144
--- /dev/null
+++ b/dom/browser-element/mochitest/file_wyciwyg.html
@@ -0,0 +1,14 @@
+<html>
+<head>
+<title>test</title>
+<script type="text/javascript">
+addEventListener('load', function() {
+ window.setTimeout(function() {
+ document.write("test");
+ }, 0);
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/iframe_file_audio.html b/dom/browser-element/mochitest/iframe_file_audio.html
new file mode 100644
index 000000000..605ce2870
--- /dev/null
+++ b/dom/browser-element/mochitest/iframe_file_audio.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<iframe src="file_audio.html"></iframe>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/mochitest-oop.ini b/dom/browser-element/mochitest/mochitest-oop.ini
new file mode 100644
index 000000000..70d38c532
--- /dev/null
+++ b/dom/browser-element/mochitest/mochitest-oop.ini
@@ -0,0 +1,135 @@
+[DEFAULT]
+# Both the "inproc" and "oop" versions of OpenMixedProcess open remote frames,
+# so we don't run that test on platforms which don't support OOP tests.
+skip-if = os == "android" || e10s
+support-files =
+ browserElement_OpenMixedProcess.js
+ file_browserElement_ExecuteScript.html
+ file_browserElement_OpenMixedProcess.html
+ browserElement_ExecuteScript.js
+ browserElement_Find.js
+ browserElement_OpenTab.js
+
+[test_browserElement_oop_AudioChannelSeeking.html]
+tags = audiochannel
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_Viewmode.html]
+[test_browserElement_oop_ThemeColor.html]
+[test_browserElement_inproc_ErrorSecurity.html]
+[test_browserElement_inproc_OpenMixedProcess.html]
+disabled = disabled for bug 1266035
+[test_browserElement_oop_Alert.html]
+[test_browserElement_oop_AlertInFrame.html]
+[test_browserElement_oop_AudioChannelMutedByDefault.html]
+tags = audiochannel
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_Auth.html]
+[test_browserElement_oop_BackForward.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_BadScreenshot.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_BrowserWindowResize.html]
+[test_browserElement_oop_Close.html]
+[test_browserElement_oop_CookiesNotThirdParty.html]
+[test_browserElement_oop_CopyPaste.html]
+subsuite = clipboard
+[test_browserElement_oop_DOMRequestError.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_DataURI.html]
+[test_browserElement_oop_DocumentFirstPaint.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_Download.html]
+disabled = bug 1022281
+[test_browserElement_oop_ErrorSecurity.html]
+[test_browserElement_oop_ExecuteScript.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_Find.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_FirstPaint.html]
+[test_browserElement_oop_ForwardName.html]
+[test_browserElement_oop_FrameWrongURI.html]
+[test_browserElement_oop_GetScreenshot.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_GetScreenshotDppx.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_Iconchange.html]
+[test_browserElement_oop_LoadEvents.html]
+[test_browserElement_oop_Manifestchange.html]
+[test_browserElement_oop_Metachange.html]
+[test_browserElement_oop_NoAudioTrack.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_AudioPlayback.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_OpenMixedProcess.html]
+disabled = disabled for bug 1266035
+[test_browserElement_oop_OpenNamed.html]
+[test_browserElement_oop_OpenWindow.html]
+[test_browserElement_oop_OpenWindowDifferentOrigin.html]
+[test_browserElement_oop_OpenWindowInFrame.html]
+[test_browserElement_oop_OpenWindowRejected.html]
+[test_browserElement_oop_Opensearch.html]
+[test_browserElement_oop_OpenTab.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_PrivateBrowsing.html]
+[test_browserElement_oop_PromptCheck.html]
+[test_browserElement_oop_PromptConfirm.html]
+[test_browserElement_oop_Proxy.html]
+[test_browserElement_oop_PurgeHistory.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_Reload.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_ReloadPostRequest.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_RemoveBrowserElement.html]
+[test_browserElement_oop_ScrollEvent.html]
+[test_browserElement_oop_SecurityChange.html]
+skip-if = toolkit == 'android' #TIMED_OUT, bug 766586
+[test_browserElement_oop_SendEvent.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_SetInputMethodActive.html]
+# skip-if = (os == "android")
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_SetVisible.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_SetVisibleFrames.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_SetVisibleFrames2.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_Stop.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_TargetBlank.html]
+[test_browserElement_oop_TargetTop.html]
+[test_browserElement_oop_Titlechange.html]
+[test_browserElement_oop_TopBarrier.html]
+[test_browserElement_oop_VisibilityChange.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_XFrameOptions.html]
+[test_browserElement_oop_XFrameOptionsAllowFrom.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+# bug 1189592
+skip-if = asan
+[test_browserElement_oop_XFrameOptionsDeny.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_XFrameOptionsSameOrigin.html]
+# Disabled until bug 930449 makes it stop timing out
+[test_browserElement_oop_ContextmenuEvents.html]
+disabled = bug 930449
+# Disabled until bug 924771 makes them stop timing out
+[test_browserElement_oop_CloseFromOpener.html]
+disabled = bug 924771
+[test_browserElement_oop_ExposableURI.html]
+disabled = bug 924771
+[test_browserElement_oop_GetContentDimensions.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_AudioChannel.html]
+tags = audiochannel
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_AudioChannel_nested.html]
+tags = audiochannel
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_getWebManifest.html]
+disabled = Disabling some OOP tests for WebIDL scope changes
+[test_browserElement_oop_OpenWindowEmpty.html]
+[test_browserElement_oop_ActiveStateChange.html]
+tags = audiochannel
+disabled = Disabling some OOP tests for WebIDL scope changes
diff --git a/dom/browser-element/mochitest/mochitest.ini b/dom/browser-element/mochitest/mochitest.ini
new file mode 100644
index 000000000..e1799f93f
--- /dev/null
+++ b/dom/browser-element/mochitest/mochitest.ini
@@ -0,0 +1,159 @@
+[DEFAULT]
+skip-if = e10s
+support-files =
+ audio.ogg
+ ../../../dom/media/test/short-video.ogv
+ async.js
+ browserElementTestHelpers.js
+ browserElement_Alert.js
+ browserElement_AlertInFrame.js
+ browserElement_Auth.js
+ browserElement_Viewmode.js
+ browserElement_ThemeColor.js
+ browserElement_BrowserWindowNamespace.js
+ browserElement_BrowserWindowResize.js
+ browserElement_Close.js
+ browserElement_CloseFromOpener.js
+ browserElement_ContextmenuEvents.js
+ browserElement_CookiesNotThirdParty.js
+ browserElement_CopyPaste.js
+ browserElement_DataURI.js
+ browserElement_Download.js
+ browserElement_ErrorSecurity.js
+ browserElement_ExposableURI.js
+ browserElement_FirstPaint.js
+ browserElement_ForwardName.js
+ browserElement_FrameWrongURI.js
+ browserElement_Iconchange.js
+ browserElement_LoadEvents.js
+ browserElement_Manifestchange.js
+ browserElement_Metachange.js
+ browserElement_NextPaint.js
+ browserElement_OpenNamed.js
+ browserElement_OpenTab.js
+ browserElement_OpenWindow.js
+ browserElement_OpenWindowDifferentOrigin.js
+ browserElement_OpenWindowEmpty.js
+ browserElement_OpenWindowInFrame.js
+ browserElement_OpenWindowRejected.js
+ browserElement_Opensearch.js
+ browserElement_PrivateBrowsing.js
+ browserElement_PromptCheck.js
+ browserElement_PromptConfirm.js
+ browserElement_Proxy.js
+ browserElement_Reload.js
+ browserElement_RemoveBrowserElement.js
+ browserElement_ScrollEvent.js
+ browserElement_SecurityChange.js
+ browserElement_TargetBlank.js
+ browserElement_TargetTop.js
+ browserElement_Titlechange.js
+ browserElement_TopBarrier.js
+ browserElement_XFrameOptions.js
+ browserElement_XFrameOptionsAllowFrom.js
+ browserElement_XFrameOptionsDeny.js
+ browserElement_XFrameOptionsSameOrigin.js
+ file_browserElement_AlertInFrame.html
+ file_browserElement_AlertInFrame_Inner.html
+ file_browserElement_Viewmode.html
+ file_browserElement_ThemeColor.html
+ file_browserElement_BrowserWindowNamespace.html
+ file_browserElement_CloseFromOpener.html
+ file_browserElement_CookiesNotThirdParty.html
+ file_browserElement_ForwardName.html
+ file_browserElement_FrameWrongURI.html
+ file_browserElement_LoadEvents.html
+ file_browserElement_Metachange.sjs
+ file_browserElement_NextPaint.html
+ file_browserElement_Open1.html
+ file_browserElement_Open2.html
+ file_browserElement_OpenNamed.html
+ file_browserElement_OpenNamed2.html
+ file_browserElement_OpenWindowDifferentOrigin.html
+ file_browserElement_OpenWindowEmpty.html
+ file_browserElement_OpenWindowInFrame.html
+ file_browserElement_OpenWindowRejected.html
+ file_browserElement_PrivateBrowsing.html
+ file_browserElement_SecurityChange.html
+ file_browserElement_TargetBlank.html
+ file_browserElement_TargetTop.html
+ file_browserElement_XFrameOptions.sjs
+ file_browserElement_XFrameOptionsAllowFrom.html
+ file_browserElement_XFrameOptionsAllowFrom.sjs
+ file_browserElement_XFrameOptionsDeny.html
+ file_browserElement_XFrameOptionsSameOrigin.html
+ file_bug741717.sjs
+ file_download_bin.sjs
+ file_empty.html
+ file_empty_script.js
+ file_focus.html
+ file_http_401_response.sjs
+ file_http_407_response.sjs
+ file_wyciwyg.html
+ file_audio.html
+ iframe_file_audio.html
+ file_web_manifest.html
+ file_web_manifest.json
+ file_illegal_web_manifest.html
+ noaudio.webm
+
+# Note: browserElementTestHelpers.js looks at the test's filename to determine
+# whether the test should be OOP. "_oop_" signals OOP, "_inproc_" signals in
+# process. Default is OOP.
+[test_browserElement_NoAttr.html]
+[test_browserElement_NoPref.html]
+[test_browserElement_NoPermission.html]
+[test_browserElement_inproc_Alert.html]
+[test_browserElement_inproc_Viewmode.html]
+[test_browserElement_inproc_ThemeColor.html]
+[test_browserElement_inproc_AlertInFrame.html]
+[test_browserElement_inproc_Auth.html]
+[test_browserElement_inproc_BrowserWindowNamespace.html]
+[test_browserElement_inproc_BrowserWindowResize.html]
+[test_browserElement_inproc_Close.html]
+[test_browserElement_inproc_CloseFromOpener.html]
+[test_browserElement_inproc_ContextmenuEvents.html]
+[test_browserElement_inproc_CookiesNotThirdParty.html]
+[test_browserElement_inproc_CopyPaste.html]
+subsuite = clipboard
+skip-if = (os == "android") # Disabled on Android, see bug 1230421
+[test_browserElement_inproc_DataURI.html]
+[test_browserElement_inproc_Download.html]
+disabled = bug 1022281
+[test_browserElement_inproc_ExposableURI.html]
+[test_browserElement_inproc_FirstPaint.html]
+[test_browserElement_inproc_ForwardName.html]
+[test_browserElement_inproc_FrameWrongURI.html]
+[test_browserElement_inproc_Iconchange.html]
+[test_browserElement_inproc_LoadEvents.html]
+[test_browserElement_inproc_Manifestchange.html]
+[test_browserElement_inproc_Metachange.html]
+[test_browserElement_inproc_OpenNamed.html]
+[test_browserElement_inproc_OpenTab.html]
+disabled = won't work as Firefox desktop will intercept ctrl-click
+[test_browserElement_inproc_OpenWindow.html]
+[test_browserElement_inproc_OpenWindowDifferentOrigin.html]
+[test_browserElement_inproc_OpenWindowInFrame.html]
+[test_browserElement_inproc_OpenWindowRejected.html]
+[test_browserElement_inproc_Opensearch.html]
+[test_browserElement_inproc_PrivateBrowsing.html]
+[test_browserElement_inproc_PromptCheck.html]
+[test_browserElement_inproc_PromptConfirm.html]
+[test_browserElement_inproc_Proxy.html]
+[test_browserElement_inproc_RemoveBrowserElement.html]
+[test_browserElement_inproc_ScrollEvent.html]
+[test_browserElement_inproc_SecurityChange.html]
+[test_browserElement_inproc_TargetBlank.html]
+[test_browserElement_inproc_TargetTop.html]
+[test_browserElement_inproc_Titlechange.html]
+[test_browserElement_inproc_TopBarrier.html]
+[test_browserElement_inproc_XFrameOptions.html]
+[test_browserElement_inproc_XFrameOptionsAllowFrom.html]
+[test_browserElement_inproc_XFrameOptionsDeny.html]
+[test_browserElement_inproc_XFrameOptionsSameOrigin.html]
+[test_browserElement_oop_NextPaint.html]
+# Disabled due to https://bugzilla.mozilla.org/show_bug.cgi?id=774100
+disabled = temp disabling some OOP tests for WebIDL scope changes
+[test_browserElement_inproc_Reload.html]
+disabled = bug 774100
+[test_browserElement_inproc_OpenWindowEmpty.html]
diff --git a/dom/browser-element/mochitest/noaudio.webm b/dom/browser-element/mochitest/noaudio.webm
new file mode 100644
index 000000000..9207017fb
--- /dev/null
+++ b/dom/browser-element/mochitest/noaudio.webm
Binary files differ
diff --git a/dom/browser-element/mochitest/priority/chrome.ini b/dom/browser-element/mochitest/priority/chrome.ini
new file mode 100644
index 000000000..e1852f6ff
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/chrome.ini
@@ -0,0 +1,19 @@
+[DEFAULT]
+# Good luck running these tests on anything but desktop Linux.
+run-if = os == 'linux' && buildapp == 'browser' && !e10s
+support-files =
+ file_Audio.html
+ file_MultipleFrames.html
+ file_NestedFramesOuter.html
+ file_WebGLContextLost.html
+ silence.ogg
+ !/dom/browser-element/mochitest/browserElementTestHelpers.js
+ !/dom/browser-element/mochitest/file_empty.html
+
+[test_Activity.html]
+[test_Audio.html]
+[test_Background.html]
+[test_Keyboard.html]
+[test_MultipleFrames.html]
+[test_NestedFrames.html]
+[test_Visibility.html]
diff --git a/dom/browser-element/mochitest/priority/file_Audio.html b/dom/browser-element/mochitest/priority/file_Audio.html
new file mode 100644
index 000000000..97f4dc64d
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/file_Audio.html
@@ -0,0 +1,19 @@
+<html>
+<body>
+
+<script>
+addEventListener('load', function() {
+ setTimeout(function() {
+ var a = document.getElementById('audio');
+ a.onplay = function() {
+ alert('onplay');
+ };
+ a.play();
+ }, 0);
+});
+</script>
+
+<audio id='audio' loop src='silence.ogg'>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/file_HighPriority.html b/dom/browser-element/mochitest/priority/file_HighPriority.html
new file mode 100644
index 000000000..dc7197bba
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/file_HighPriority.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+
+<script>
+var lock = navigator.requestWakeLock('high-priority');
+alert('step0');
+
+lock.unlock();
+alert('step1');
+
+lock = navigator.requestWakeLock('cpu');
+alert('step2');
+
+lock.unlock();
+alert('step3');
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/file_MultipleFrames.html b/dom/browser-element/mochitest/priority/file_MultipleFrames.html
new file mode 100644
index 000000000..b3b56f560
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/file_MultipleFrames.html
@@ -0,0 +1,14 @@
+<html>
+<body>
+<p>file_MultipleFrames.html</p>
+
+<script>
+addEventListener('load', function() {
+ setTimeout(function() {
+ window.open('../file_empty.html');
+ }, 0);
+});
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/file_NestedFramesOuter.html b/dom/browser-element/mochitest/priority/file_NestedFramesOuter.html
new file mode 100644
index 000000000..e4378935f
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/file_NestedFramesOuter.html
@@ -0,0 +1,20 @@
+<html>
+<body>
+<p>file_NestedFramesOuter.html</p>
+<script>
+
+addEventListener('load', function() {
+ setTimeout(createIframe, 0);
+});
+
+function createIframe()
+{
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', true);
+ iframe.src = location.hash.substr(1);
+ document.body.appendChild(iframe);
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/file_WebGLContextLost.html b/dom/browser-element/mochitest/priority/file_WebGLContextLost.html
new file mode 100644
index 000000000..bd5c84f11
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/file_WebGLContextLost.html
@@ -0,0 +1,22 @@
+<html>
+<body>
+file_WebGLContextLost.html
+<canvas id='canvas'></canvas>
+
+<script>
+function runTest()
+{
+ var canvas = document.getElementById('canvas');
+ canvas.addEventListener('webglcontextlost', function() {
+ alert('webglcontextlost');
+ });
+
+ var context = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
+ context.viewport(0, 0, 10, 10);
+ alert('ready');
+}
+
+addEventListener('load', function() { setTimeout(runTest, 0) });
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/mochitest.ini b/dom/browser-element/mochitest/priority/mochitest.ini
new file mode 100644
index 000000000..8118aedd7
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/mochitest.ini
@@ -0,0 +1,19 @@
+[DEFAULT]
+# Good luck running these tests on anything but desktop Linux.
+run-if = os == 'linux' && buildapp == 'browser' && !e10s
+support-files =
+ file_HighPriority.html
+ silence.ogg
+ !/dom/browser-element/mochitest/browserElementTestHelpers.js
+ !/dom/browser-element/mochitest/file_empty.html
+
+# Note: ../browserElementTestHelpers.js makes all tests in this directory OOP,
+# because testing the process-priority manager without OOP frames does not make
+# much sense.
+
+[test_Simple.html]
+[test_HighPriority.html]
+[test_Preallocated.html]
+disabled = bug 968604, bug 987164
+[test_WebGLContextLost.html]
+disabled = bug 865844
diff --git a/dom/browser-element/mochitest/priority/silence.ogg b/dom/browser-element/mochitest/priority/silence.ogg
new file mode 100644
index 000000000..6e0b352a3
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/silence.ogg
Binary files differ
diff --git a/dom/browser-element/mochitest/priority/test_Activity.html b/dom/browser-element/mochitest/priority/test_Activity.html
new file mode 100644
index 000000000..ae4049d96
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/test_Activity.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that calling setVisible("false") on an iframe that has an open activity
+causes its priority to change.
+-->
+<head>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.enableProcessPriorityManager();
+
+function runTest() {
+ var os = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
+ .getService(SpecialPowers.Ci.nsIObserverService);
+ var iframe = document.createElement("iframe");
+ iframe.setAttribute("mozbrowser", true);
+
+ iframe.src = browserElementTestHelpers.emptyPage1;
+
+ var childID = null;
+ Promise.all([
+ expectOnlyOneProcessCreated("FOREGROUND").then(function(chid) {
+ childID = chid;
+ }),
+ expectMozbrowserEvent(iframe, "loadend")
+ ]).then(function() {
+ var p = expectPriorityChange(childID, "BACKGROUND_PERCEIVABLE");
+
+ // We simulate opening an activity
+ os.notifyObservers(null, "activity-opened", childID);
+
+ // We wait until mozbrowserloadend before calling setVisible, because
+ // setVisible isn't available until mozbrowser has loaded. In practice, that
+ // means we can call setVisible once we've gotten /any/ mozbrowser event.
+ iframe.setVisible(false);
+ return p;
+ }).then(function() {
+ var p = expectPriorityChange(childID, "BACKGROUND");
+
+ // Now we simulate closing an activity
+ os.notifyObservers(null, "activity-closed", childID);
+
+ return p;
+ }).then(SimpleTest.finish);
+
+ document.body.appendChild(iframe);
+}
+
+addEventListener("testready", runTest);
+
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/test_Audio.html b/dom/browser-element/mochitest/priority/test_Audio.html
new file mode 100644
index 000000000..d39b1c9f3
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/test_Audio.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that frames playing audio get BACKGROUND_PERCEIVABLE priority.
+-->
+<head>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.enableProcessPriorityManager();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', true);
+ iframe.src = 'file_Audio.html';
+
+ var childID = null;
+ Promise.all([
+ expectOnlyOneProcessCreated("FOREGROUND").then(function(chid) {
+ childID = chid;
+ }),
+ expectMozbrowserEvent(iframe, 'loadend'),
+ expectMozbrowserEvent(iframe, 'showmodalprompt').then(function(e) {
+ is(e.detail.message, 'onplay', 'showmodalprompt message');
+ })
+ ]).then(function() {
+ // Send the child process into the background. Because it's playing audio,
+ // it should get priority BACKGROUND_PERCEIVABLE, not vanilla BACKGROUND.
+ var p = expectPriorityChange(childID, 'BACKGROUND_PERCEIVABLE');
+ iframe.setVisible(false);
+ return p;
+ }).then(function() {
+ var p = expectPriorityChange(childID, 'FOREGROUND');
+ iframe.setVisible(true);
+ return p;
+ }).then(SimpleTest.finish);
+
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
+
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/test_Background.html b/dom/browser-element/mochitest/priority/test_Background.html
new file mode 100644
index 000000000..59eb16863
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/test_Background.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that calling setVisible('false') on an iframe causes its visibility to
+change.
+-->
+<head>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.enableProcessPriorityManager();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', true);
+
+ iframe.src = browserElementTestHelpers.emptyPage1;
+
+ var childID = null;
+ Promise.all([
+ expectOnlyOneProcessCreated('FOREGROUND').then(function(chid) {
+ childID = chid;
+ }),
+ expectMozbrowserEvent(iframe, 'loadend')
+ ]).then(function() {
+ var p = expectPriorityChange(childID, 'BACKGROUND');
+
+ // We wait until mozbrowserloadend before calling setVisible, because
+ // setVisible isn't available until mozbrowser has loaded. In practice, that
+ // means we can call setVisible once we've gotten /any/ mozbrowser event.
+ iframe.setVisible(false);
+ return p;
+ }).then(function() {
+ var p = expectPriorityChange(childID, 'FOREGROUND');
+ iframe.setVisible(true);
+ }).then(SimpleTest.finish);
+
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
+
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/test_HighPriority.html b/dom/browser-element/mochitest/priority/test_HighPriority.html
new file mode 100644
index 000000000..d3396d65b
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/test_HighPriority.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that frames with mozapptype=critical which hold the "high-priority" or
+"cpu" wake locks get elevated process priority.
+-->
+<head>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+browserElementTestHelpers.enableProcessPriorityManager();
+
+function runTest() {
+ // To test bug 870480, run this test while holding the CPU and high-priority
+ // wake locks. Without the fix for bug 870480, we won't set the priority of
+ // the child process if the main process holds these wake locks and the test
+ // will hang.
+ navigator.requestWakeLock('cpu');
+ navigator.requestWakeLock('high-priority');
+
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', true);
+ iframe.setAttribute('mozapptype', 'critical');
+ iframe.src = 'file_HighPriority.html';
+
+ // We expect the following to happen:
+ //
+ // - Process is created.
+ // - Its priority is set to FOREGROUND (when the process starts).
+ // - wait_alert('step0', FOREGROUND_HIGH)
+ // - wait_alert('step1', FOREGROUND)
+ // - wait_alert('step2', FOREGROUND_HIGH)
+ //
+ // Where wait_alert(M, P) means that we expect the subprocess to
+ // * do alert(M) and
+ // * be set to priority P
+ // in some order. If the alert occurs before the priority change, we block
+ // the alert until we observe the priority change. So the subprocess only
+ // has to do
+ //
+ // // set priority to FOREGROUND_HIGH
+ // alert('step0');
+ // // set priority to FOREGROUND
+ // alert('step1');
+ //
+ // etc.
+
+ var childID = null;
+ var alertTimes = [];
+
+ // Return a promise that's resolved once the child process calls alert() and
+ // we get a priority change, in some order.
+ //
+ // We check that the text of the alert is |"step" + index|.
+ //
+ // If gracePeriod is given, we check that the priority change occurred at
+ // least gracePeriod ms since the alert from the previous step (with a fudge
+ // factor to account for inaccurate timers).
+ function expectAlertAndPriorityChange(index, priority, /* optional */ gracePeriod) {
+ function checkAlertInfo(e) {
+ is(e.detail.message, 'step' + index, 'alert() number ' + index);
+ alertTimes.push(new Date());
+
+ // Block the alert; we'll unblock it by calling e.detail.unblock() later.
+ e.preventDefault();
+ return Promise.resolve(e.detail.unblock);
+ }
+
+ function checkGracePeriod() {
+ if (gracePeriod) {
+ var msSinceLastAlert = (new Date()) - alertTimes[index - 1];
+
+ // 50ms fudge factor. This test is set up so that, if nsITimers are
+ // accurate, we don't need any fudge factor. Unfortunately our timers
+ // are not accurate! There's little we can do here except fudge.
+ // Thankfully all we're trying to test is that we get /some/ delay; the
+ // exact amount of delay isn't so important.
+ ok(msSinceLastAlert + 50 >= gracePeriod,
+ msSinceLastAlert + "ms since last alert >= (" + gracePeriod + " - 50ms)");
+ }
+ }
+
+ return Promise.all([
+ new Promise(function(resolve, reject) {
+ iframe.addEventListener('mozbrowsershowmodalprompt', function check(e) {
+ iframe.removeEventListener('mozbrowsershowmodalprompt', check);
+ resolve(checkAlertInfo(e));
+ });
+ }),
+ expectPriorityChange(childID, priority).then(checkGracePeriod)
+ ]).then(function(results) {
+ // checkAlertInfo returns the function to call to unblock the alert.
+ // It comes to us as the first element of the results array.
+ results[0]();
+ });
+ }
+
+ expectProcessCreated('FOREGROUND').then(function(chid) {
+ childID = chid;
+ }).then(function() {
+ return expectAlertAndPriorityChange(0, 'FOREGROUND_HIGH');
+ }).then(function() {
+ return expectAlertAndPriorityChange(1, 'FOREGROUND', priorityChangeGracePeriod);
+ }).then(function() {
+ return expectAlertAndPriorityChange(2, 'FOREGROUND_HIGH');
+ }).then(function() {
+ return expectAlertAndPriorityChange(3, 'FOREGROUND', priorityChangeGracePeriod);
+ }).then(SimpleTest.finish);
+
+ document.body.appendChild(iframe);
+}
+
+const priorityChangeGracePeriod = 100;
+addEventListener('testready', function() {
+ SpecialPowers.pushPrefEnv(
+ {set: [['dom.ipc.processPriorityManager.backgroundGracePeriodMS',
+ priorityChangeGracePeriod],
+ ['dom.wakelock.enabled', true]]},
+ runTest);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/test_Keyboard.html b/dom/browser-element/mochitest/priority/test_Keyboard.html
new file mode 100644
index 000000000..a36f954ba
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/test_Keyboard.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that frames with mozapptype=inputmethod gets the keyboard-specific
+priority level when in the foreground.
+-->
+<head>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.enableProcessPriorityManager();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', true);
+ iframe.setAttribute('mozapptype', 'inputmethod');
+ iframe.src = browserElementTestHelpers.emptyPage1;
+
+ var childID = null;
+ Promise.all([
+ expectOnlyOneProcessCreated('FOREGROUND_KEYBOARD').then(function(chid) {
+ childID = chid;
+ }),
+ expectMozbrowserEvent(iframe, 'loadend')
+ ]).then(function() {
+ var p = expectPriorityChange(childID, 'BACKGROUND');
+
+ /* We wait until mozbrowserloadend before calling setVisible, because
+ * setVisible isn't available until mozbrowser has loaded. In practice,
+ * that means we can call setVisible once we've gotten /any/ mozbrowser
+ * event. */
+ iframe.setVisible(false);
+ return p;
+ }).then(function() {
+ var p = expectPriorityChange(childID, 'FOREGROUND_KEYBOARD');
+ iframe.setVisible(true);
+ }).then(SimpleTest.finish);
+
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
+
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/test_MultipleFrames.html b/dom/browser-element/mochitest/priority/test_MultipleFrames.html
new file mode 100644
index 000000000..57d9563e7
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/test_MultipleFrames.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that when we remove one of a process's frames from the DOM, the process's
+priority is recomputed.
+-->
+<head>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.enableProcessPriorityManager();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', true);
+ iframe.src = 'file_MultipleFrames.html';
+
+ var childID = null;
+ var iframe2;
+ Promise.all([
+ expectProcessCreated('FOREGROUND').then(function(chid) {
+ childID = chid;
+ }),
+ new Promise(function(resolve, reject) {
+ iframe.addEventListener('mozbrowseropenwindow', function(e) {
+ iframe2 = e.detail.frameElement;
+ var p = expectMozbrowserEvent(iframe2, 'loadend');
+ document.body.appendChild(iframe2);
+ resolve(p);
+ });
+ })
+ ]).then(function() {
+ // At this point, the child process has been set to FOREGROUND, and the popup
+ // opened by file_MultipleFrames has finished loading.
+ //
+ // Now setVisible(false) the popup frame and remove the popup frame from the
+ // DOM. This should cause the process to take on BACKGROUND priority.
+ var p = expectPriorityChange(childID, 'BACKGROUND');
+ iframe.setVisible(false);
+ document.body.removeChild(iframe2);
+ return p;
+ }).then(SimpleTest.finish);
+
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/test_NestedFrames.html b/dom/browser-element/mochitest/priority/test_NestedFrames.html
new file mode 100644
index 000000000..e5381bcc5
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/test_NestedFrames.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test changing the visibility of an <iframe mozbrowser> changes the visibility
+(and thus the priority) of any <iframe mozbrowser>s it contains.
+-->
+<head>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.enableProcessPriorityManager();
+
+function runTest() {
+ // Set up the following hierarchy of frames:
+ //
+ // <iframe mozbrowser remote=false src='file_NestedFramesOuter.html'>
+ // <iframe mozbrowser remote=true src='file_empty.html'>
+ //
+ // When we change the visibility of the outer iframe, it should change the
+ // priority of the inner one.
+
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', true);
+ iframe.setAttribute('remote', false);
+ iframe.src = 'file_NestedFramesOuter.html#' + browserElementTestHelpers.emptyPage1;
+
+ // Note that this is the process corresponding to the /inner/ iframe. The
+ // outer iframe runs in-process (because it has remote=false).
+ var childID = null;
+ Promise.all(
+ [expectOnlyOneProcessCreated('FOREGROUND').then(function(child) {
+ childID = child;
+ }),
+ expectMozbrowserEvent(iframe, 'loadend')]
+ ).then(function() {
+ // Send the outer iframe into the background. This should change the
+ // priority of the inner frame's process to BACKGROUND.
+ var p = expectPriorityChange(childID, 'BACKGROUND');
+ iframe.setVisible(false);
+ return p;
+ }).then(function() {
+ var p = expectPriorityChange(childID, 'FOREGROUND');
+ iframe.setVisible(true);
+ return p;
+ }).then(SimpleTest.finish);
+
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
+
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/test_Preallocated.html b/dom/browser-element/mochitest/priority/test_Preallocated.html
new file mode 100644
index 000000000..b2cb0335e
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/test_Preallocated.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that the preallocated process starts up with priority BACKGROUND.
+-->
+<head>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+browserElementTestHelpers.enableProcessPriorityManager();
+
+var preallocationEnabledPref = null;
+try {
+ preallocationEnabledPref = SpecialPowers.getBoolPref('dom.ipc.processPrelaunch.enabled');
+}
+catch(e) {
+ preallocationEnabledPref = null;
+}
+
+var childID = null;
+
+var cleanedUp = false;
+function cleanUp()
+{
+ if (cleanedUp) {
+ return;
+ }
+
+ cleanedUp = true;
+}
+
+// Even if this test times out, we still want to run cleanUp so as to set the
+// pref back.
+addEventListener('unload', cleanUp);
+
+function runTest()
+{
+ if (preallocationEnabledPref) {
+ ok(false, "dom.ipc.processPrelaunch.enabled must be " +
+ "false for this test to work.");
+ SimpleTest.finish();
+ return;
+ }
+
+ // Ensure that the preallocated process initially gets BACKGROUND priority.
+ // That's it.
+ expectProcessCreated('PREALLOC').then(function() {
+ // We need to set the pref asynchoronously or the preallocated process won't
+ // be shut down.
+ SimpleTest.executeSoon(function(){
+ cleanUp();
+ SimpleTest.finish();
+ });
+ });
+}
+// Setting this pref to true should cause us to prelaunch a process.
+addEventListener('testready', function() {
+ SpecialPowers.pushPrefEnv({'set':[["dom.ipc.processPrelaunch.enabled",true]]},runTest);
+});
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/test_Simple.html b/dom/browser-element/mochitest/priority/test_Simple.html
new file mode 100644
index 000000000..7cc801e54
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/test_Simple.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+A simple test of the process priority manager.
+
+https://bugzilla.mozilla.org/show_bug.cgi?id=844323
+
+Note: If you run this test alone (i.e. not as part of the larger mochitest
+suite), you may see some IPC assertions, e.g. "Can't allocate graphics
+resources."
+
+What appears to be happening is that we close the Firefox window before the
+frame we create in this tab finishes starting up. Then the frame finishes
+loading, and it tries to show itself. But it's too late to show a remote frame
+at that point, so we kill the child process.
+
+In other words, I think these errors are nothing to worry about.
+-->
+<head>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+browserElementTestHelpers.enableProcessPriorityManager();
+
+var allCompleted = 0;
+var allExpected = 2;
+function finish() {
+ allCompleted++;
+ if (allCompleted === allExpected) {
+ SimpleTest.finish();
+ }
+}
+
+function runTest() {
+ var iframeLoaded = false;
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', true);
+ iframe.src = browserElementTestHelpers.emptyPage1;
+
+ iframe.addEventListener('mozbrowserloadend', finish);
+ expectProcessCreated('FOREGROUND').then(finish);
+
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
+
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/test_Visibility.html b/dom/browser-element/mochitest/priority/test_Visibility.html
new file mode 100644
index 000000000..58648b99f
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/test_Visibility.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that setVisible() changes a process's priority.
+-->
+<head>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.enableProcessPriorityManager();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', true);
+ iframe.src = browserElementTestHelpers.emptyPage1;
+
+ var childID = null;
+ Promise.all([
+ expectOnlyOneProcessCreated('FOREGROUND').then(function(chid) {
+ childID = chid;
+ }),
+ expectMozbrowserEvent(iframe, 'loadend')
+ ]).then(function() {
+ // Mark the frame as not visible. This should cause its priority to drop
+ // to BACKGROUND.
+ var p = expectPriorityChange(childID, 'BACKGROUND');
+ iframe.setVisible(false);
+ return p;
+ }).then(function() {
+ // Mark the frame as visible again. This should cause its priority change
+ // back to FOREGROUND.
+ var p = expectPriorityChange(childID, 'FOREGROUND');
+ iframe.setVisible(true);
+ return p;
+ }).then(SimpleTest.finish);
+
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', runTest);
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/priority/test_WebGLContextLost.html b/dom/browser-element/mochitest/priority/test_WebGLContextLost.html
new file mode 100644
index 000000000..383506ec6
--- /dev/null
+++ b/dom/browser-element/mochitest/priority/test_WebGLContextLost.html
@@ -0,0 +1,99 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test that calling setVisible('false') and then sending a low-memory
+notification causes a WebGL context loss event.
+-->
+<head>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="../browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+browserElementTestHelpers.enableProcessPriorityManager();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', true);
+ iframe.src = 'file_WebGLContextLost.html';
+
+ // We use this to ensure that we don't call SimpleTest.finish() twice.
+ var finished = false;
+ function finishOnce() {
+ if (!finished) {
+ SimpleTest.finish();
+ finished = true;
+ }
+ }
+
+ expectMozbrowserEvent(iframe, 'error').then(function(e) {
+ if (finished) {
+ // We don't care if the frame dies after the test finishes.
+ return;
+ }
+ todo(false, "child process is crashing; this probably indicates that " +
+ "something is wrong with WebGL in child processes on your machine.");
+ is(e.detail.type, 'fatal');
+ }).then(finishOnce);
+
+ var childID = null;
+ Promise.all([
+ expectOnlyOneProcessCreated('FOREGROUND').then(function(chid) {
+ childID = chid;
+ }),
+ expectMozbrowserEvent(iframe, 'loadend'),
+ expectMozbrowserEvent(iframe, 'showmodalprompt').then(function(e) {
+ is(e.detail.message, 'ready');
+ })
+ ]).then(function() {
+ // Fire a low-memory notification once the process goes into the background
+ // due to the setVisible(false) call below.
+ expectPriorityChange(childID, 'BACKGROUND').then(function() {
+ SimpleTest.executeSoon(function() {
+ var os = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
+ .getService(SpecialPowers.Ci.nsIObserverService);
+ os.notifyObservers(null, "memory-pressure", "low-memory");
+ ok(true, 'Successfully notified observers.');
+ });
+ });
+
+ // This test isn't the only possible source of a low-memory notification; the
+ // browser can fire one whenever it likes. So it's fine if we lose the
+ // WebGL context before we fire the low-memory notification ourself.
+
+ var p = expectMozbrowserEvent(iframe, 'showmodalprompt').then(function(e) {
+ is(e.detail.message, 'webglcontextlost');
+ });
+
+ iframe.setVisible(false);
+ return p;
+ }).then(finishOnce);
+
+ document.body.appendChild(iframe);
+}
+
+addEventListener('testready', function() {
+ // At the time this test was written, webgl was blocklisted inside child
+ // processes on desktop Linux. The issue is that we spawn a child process to
+ // read driver info, but we only did this on the main prrocess. Child
+ // processes never read the driver info themselves, nor do they get it from
+ // their parent, so they refuse to start up WebGL.
+ //
+ // This isn't a problem on B2G because we force WebGL on there. But it
+ // obviously makes this test difficult. bjacob says forcing WebGL on here
+ // shouldn't hurt things, and anyway this setting mirrors what we do on B2G,
+ // which is what we're trying to test!
+ SpecialPowers.pushPrefEnv({set: [["webgl.force-enabled", true]]},
+ runTest);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_NoAttr.html b/dom/browser-element/mochitest/test_browserElement_NoAttr.html
new file mode 100644
index 000000000..070aee19f
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_NoAttr.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=710231
+-->
+<head>
+ <title>Test for Bug 710231</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=710231">Mozilla Bug 710231</a>
+
+<!--
+ Test that an iframe without the |mozbrowser| attribute does not emit
+ mozbrowserX events.
+-->
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+ var iframe = document.getElementById('iframe');
+ iframe.addEventListener('mozbrowserloadstart', function() {
+ ok(false, 'Should not send mozbrowserloadstart event.');
+ });
+
+ iframe.addEventListener('load', function() {
+ ok(true, 'Got iframe load event.');
+ SimpleTest.finish();
+ });
+
+ iframe.src = browserElementTestHelpers.emptyPage1;
+}
+
+addEventListener('load', function() { SimpleTest.executeSoon(runTest); });
+
+</script>
+
+<iframe id='iframe'></iframe>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_NoPermission.html b/dom/browser-element/mochitest/test_browserElement_NoPermission.html
new file mode 100644
index 000000000..4e1d88072
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_NoPermission.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=710231
+-->
+<head>
+ <title>Test for Bug 710231</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=710231">Mozilla Bug 710231</a>
+
+<!--
+ Test that an iframe with the |mozbrowser| attribute does not emit
+ mozbrowserX events when this page does not have the "browser" permission.
+-->
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+
+ iframe.addEventListener('mozbrowserloadstart', function() {
+ ok(false, 'Should not send mozbrowserloadstart event.');
+ });
+
+ iframe.addEventListener('load', function() {
+ ok(true, 'Got iframe load event.');
+ SimpleTest.finish();
+ });
+
+ iframe.src = browserElementTestHelpers.emptyPage1;
+}
+
+browserElementTestHelpers.setEnabledPref(true);
+SpecialPowers.removePermission("browser", document);
+addEventListener('testready', runTest);
+
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_NoPref.html b/dom/browser-element/mochitest/test_browserElement_NoPref.html
new file mode 100644
index 000000000..df69e4c43
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_NoPref.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=710231
+-->
+<head>
+ <title>Test for Bug 710231</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=710231">Mozilla Bug 710231</a>
+
+<!--
+ Test that an iframe with the |mozbrowser| attribute does not emit
+ mozbrowserX events when they're globally pref'ed off.
+-->
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('mozbrowser', 'true');
+ document.body.appendChild(iframe);
+
+ iframe.addEventListener('mozbrowserloadstart', function() {
+ ok(false, 'Should not send mozbrowserloadstart event.');
+ });
+
+ iframe.addEventListener('load', function() {
+ ok(true, 'Got iframe load event.');
+ SimpleTest.finish();
+ });
+
+ iframe.src = browserElementTestHelpers.emptyPage1;
+}
+
+browserElementTestHelpers.setEnabledPref(false);
+addEventListener('testready', runTest);
+
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_ActiveStateChange.html b/dom/browser-element/mochitest/test_browserElement_inproc_ActiveStateChange.html
new file mode 100644
index 000000000..4a14ad7cb
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_ActiveStateChange.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test ActiveStateChangeOnChangingMutedOrVolume</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_ActiveStateChange.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Alert.html b/dom/browser-element/mochitest/test_browserElement_inproc_Alert.html
new file mode 100644
index 000000000..03d03135d
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Alert.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=741587
+-->
+<head>
+ <title>Test for Bug 741587</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=741587">Mozilla Bug 741587</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Alert.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_AlertInFrame.html b/dom/browser-element/mochitest/test_browserElement_inproc_AlertInFrame.html
new file mode 100644
index 000000000..d797a1a3a
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_AlertInFrame.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for iframe mozbrowser</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_AlertInFrame.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_AudioChannel.html b/dom/browser-element/mochitest/test_browserElement_inproc_AudioChannel.html
new file mode 100644
index 000000000..6bba008d7
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_AudioChannel.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element audioChannel.</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_AudioChannel.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_AudioChannelMutedByDefault.html b/dom/browser-element/mochitest/test_browserElement_inproc_AudioChannelMutedByDefault.html
new file mode 100644
index 000000000..304b1b8b4
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_AudioChannelMutedByDefault.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1235535 - Audio Channel Muted-By-Default.</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_AudioChannelMutedByDefault.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_AudioChannelSeeking.html b/dom/browser-element/mochitest/test_browserElement_inproc_AudioChannelSeeking.html
new file mode 100644
index 000000000..a7834e929
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_AudioChannelSeeking.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1225425 - Do not unregister the AudioChannelAgent during seeking</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_AudioChannelSeeking.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_AudioChannel_nested.html b/dom/browser-element/mochitest/test_browserElement_inproc_AudioChannel_nested.html
new file mode 100644
index 000000000..2ee58002c
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_AudioChannel_nested.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element audioChannel in nested mozbrowser iframes.</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_AudioChannel_nested.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_AudioPlayback.html b/dom/browser-element/mochitest/test_browserElement_inproc_AudioPlayback.html
new file mode 100644
index 000000000..364eeff68
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_AudioPlayback.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1180824
+-->
+<head>
+ <title>Test for Bug 1180824</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.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=1180824">Mozilla Bug 1180824</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_AudioPlayback.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Auth.html b/dom/browser-element/mochitest/test_browserElement_inproc_Auth.html
new file mode 100644
index 000000000..0dd60f8c6
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Auth.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=741587
+-->
+<head>
+ <title>Test for Bug 775464</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=775464">Mozilla Bug 775464</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Auth.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_BackForward.html b/dom/browser-element/mochitest/test_browserElement_inproc_BackForward.html
new file mode 100644
index 000000000..d841cc3e0
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_BackForward.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_BackForward.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_BadScreenshot.html b/dom/browser-element/mochitest/test_browserElement_inproc_BadScreenshot.html
new file mode 100644
index 000000000..8e4b61b33
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_BadScreenshot.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 800170</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_BadScreenshot.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_BrowserWindowNamespace.html b/dom/browser-element/mochitest/test_browserElement_inproc_BrowserWindowNamespace.html
new file mode 100644
index 000000000..3fafbe646
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_BrowserWindowNamespace.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 780351</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_BrowserWindowNamespace.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_BrowserWindowResize.html b/dom/browser-element/mochitest/test_browserElement_inproc_BrowserWindowResize.html
new file mode 100644
index 000000000..bcc86b872
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_BrowserWindowResize.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 891763</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_BrowserWindowResize.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Close.html b/dom/browser-element/mochitest/test_browserElement_inproc_Close.html
new file mode 100644
index 000000000..76d203f9d
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Close.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=757182
+-->
+<head>
+ <title>Test for Bug 757182</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=757182">Mozilla Bug 757182</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Close.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_CloseFromOpener.html b/dom/browser-element/mochitest/test_browserElement_inproc_CloseFromOpener.html
new file mode 100644
index 000000000..3c7ee4d87
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_CloseFromOpener.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=757182
+-->
+<head>
+ <title>Test for Bug 757182</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=757182">Mozilla Bug 757182</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_CloseFromOpener.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_ContextmenuEvents.html b/dom/browser-element/mochitest/test_browserElement_inproc_ContextmenuEvents.html
new file mode 100644
index 000000000..a43f7dbef
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_ContextmenuEvents.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Contextmenu Events</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_ContextmenuEvents.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_CookiesNotThirdParty.html b/dom/browser-element/mochitest/test_browserElement_inproc_CookiesNotThirdParty.html
new file mode 100644
index 000000000..37ea16fb0
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_CookiesNotThirdParty.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 806127</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_CookiesNotThirdParty.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_CopyPaste.html b/dom/browser-element/mochitest/test_browserElement_inproc_CopyPaste.html
new file mode 100644
index 000000000..892245d4f
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_CopyPaste.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=987040
+-->
+<head>
+ <title>Test for Bug 987040</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=987040">Mozilla Bug 987040</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_CopyPaste.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_DOMRequestError.html b/dom/browser-element/mochitest/test_browserElement_inproc_DOMRequestError.html
new file mode 100644
index 000000000..6a9e5bbba
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_DOMRequestError.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=787519
+-->
+<head>
+ <title>Test for Bug 787519</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.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=787519">Mozilla Bug 787519</a>
+
+<script type="application/javascript;version=1.7" src='browserElement_DOMRequestError.js'>
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_DataURI.html b/dom/browser-element/mochitest/test_browserElement_inproc_DataURI.html
new file mode 100644
index 000000000..2ceb49cd0
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_DataURI.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=720157
+-->
+<head>
+ <title>Test for Bug 720157</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=720157">Mozilla Bug 720157</a>
+
+<script type='application/javascript;version=1.7' src='browserElement_DataURI.js'></script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_DocumentFirstPaint.html b/dom/browser-element/mochitest/test_browserElement_inproc_DocumentFirstPaint.html
new file mode 100644
index 000000000..3197adf66
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_DocumentFirstPaint.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 829486</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_DocumentFirstPaint.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Download.html b/dom/browser-element/mochitest/test_browserElement_inproc_Download.html
new file mode 100644
index 000000000..c2e5e2ed3
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Download.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 983747</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_Download.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_ErrorSecurity.html b/dom/browser-element/mochitest/test_browserElement_inproc_ErrorSecurity.html
new file mode 100644
index 000000000..318d29831
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_ErrorSecurity.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for mozbrowser</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_ErrorSecurity.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_ExecuteScript.html b/dom/browser-element/mochitest/test_browserElement_inproc_ExecuteScript.html
new file mode 100644
index 000000000..f63f31d42
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_ExecuteScript.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1174733
+-->
+<head>
+ <title>Test for Bug 1163961</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.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=1174733">Mozilla Bug 1174733</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_ExecuteScript.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_ExposableURI.html b/dom/browser-element/mochitest/test_browserElement_inproc_ExposableURI.html
new file mode 100644
index 000000000..089e5db44
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_ExposableURI.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=795317
+-->
+<head>
+ <title>Test for Bug 795317</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=795317">Mozilla Bug 795317</a>
+
+<script type="application/javascript;version1.7" src="browserElement_ExposableURI.js"></script>
+
+</body>
+</html>
+
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Find.html b/dom/browser-element/mochitest/test_browserElement_inproc_Find.html
new file mode 100644
index 000000000..386bc7882
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Find.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1163961
+-->
+<head>
+ <title>Test for Bug 1163961</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.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=1163961">Mozilla Bug 1163961</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Find.js">
+</script>
+</body>
+</html>
+
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_FirstPaint.html b/dom/browser-element/mochitest/test_browserElement_inproc_FirstPaint.html
new file mode 100644
index 000000000..ee013860c
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_FirstPaint.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 787378</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_FirstPaint.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_ForwardName.html b/dom/browser-element/mochitest/test_browserElement_inproc_ForwardName.html
new file mode 100644
index 000000000..f24691ff1
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_ForwardName.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 781320</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_ForwardName.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_FrameWrongURI.html b/dom/browser-element/mochitest/test_browserElement_inproc_FrameWrongURI.html
new file mode 100644
index 000000000..f0e6e6c20
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_FrameWrongURI.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_FrameWrongURI.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_GetContentDimensions.html b/dom/browser-element/mochitest/test_browserElement_inproc_GetContentDimensions.html
new file mode 100644
index 000000000..73b59800d
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_GetContentDimensions.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_GetContentDimensions.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_GetScreenshot.html b/dom/browser-element/mochitest/test_browserElement_inproc_GetScreenshot.html
new file mode 100644
index 000000000..cb246fc06
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_GetScreenshot.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=753595
+-->
+<head>
+ <title>Test for Bug 753595</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.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=753595">Mozilla Bug 753595</a>
+
+<script type="application/javascript;version=1.7" src='browserElement_GetScreenshot.js'>
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_GetScreenshotDppx.html b/dom/browser-element/mochitest/test_browserElement_inproc_GetScreenshotDppx.html
new file mode 100644
index 000000000..dfc10d102
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_GetScreenshotDppx.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=959066
+-->
+<head>
+ <title>Test for Bug 959066</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.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=959066">Mozilla Bug 959066</a>
+
+<script type="application/javascript;version=1.7" src='browserElement_GetScreenshotDppx.js'>
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Iconchange.html b/dom/browser-element/mochitest/test_browserElement_inproc_Iconchange.html
new file mode 100644
index 000000000..2f17287de
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Iconchange.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=719461
+-->
+<head>
+ <title>Test for Bug 719461</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=719461">Mozilla Bug 719461</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Iconchange.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_LoadEvents.html b/dom/browser-element/mochitest/test_browserElement_inproc_LoadEvents.html
new file mode 100644
index 000000000..3370ff874
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_LoadEvents.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=710231
+-->
+<head>
+ <title>Test for Bug 710231</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=710231">Mozilla Bug 710231</a>
+
+<script type="application/javascript;version1.7" src="browserElement_LoadEvents.js"></script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Manifestchange.html b/dom/browser-element/mochitest/test_browserElement_inproc_Manifestchange.html
new file mode 100644
index 000000000..64200bd48
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Manifestchange.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=982800
+-->
+<head>
+ <title>Test for Bug 982800</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=982800">Mozilla Bug 982800</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Manifestchange.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Metachange.html b/dom/browser-element/mochitest/test_browserElement_inproc_Metachange.html
new file mode 100644
index 000000000..d799a52e4
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Metachange.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=962626
+-->
+<head>
+ <title>Test for Bug 962626</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=962626">Mozilla Bug 962626</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Metachange.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_NextPaint.html b/dom/browser-element/mochitest/test_browserElement_inproc_NextPaint.html
new file mode 100644
index 000000000..d9250a8db
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_NextPaint.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 808231</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_NextPaint.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_NoAudioTrack.html b/dom/browser-element/mochitest/test_browserElement_inproc_NoAudioTrack.html
new file mode 100644
index 000000000..77e33befa
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_NoAudioTrack.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1227051 - No audio track video shouldn't register the AudioChannelAgent</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_NoAudioTrack.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_OpenMixedProcess.html b/dom/browser-element/mochitest/test_browserElement_inproc_OpenMixedProcess.html
new file mode 100644
index 000000000..1248c1772
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_OpenMixedProcess.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 776129</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenMixedProcess.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_OpenNamed.html b/dom/browser-element/mochitest/test_browserElement_inproc_OpenNamed.html
new file mode 100644
index 000000000..bbe12545c
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_OpenNamed.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenNamed.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_OpenTab.html b/dom/browser-element/mochitest/test_browserElement_inproc_OpenTab.html
new file mode 100644
index 000000000..85b979bd0
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_OpenTab.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1144015
+-->
+<head>
+ <title>Test for Bug 1144015</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1144015">Mozilla Bug 1144015</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_OpenTab.js">
+</script>
+</body>
+</html>
+
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindow.html b/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindow.html
new file mode 100644
index 000000000..7c249792f
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindow.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenWindow.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowDifferentOrigin.html b/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowDifferentOrigin.html
new file mode 100644
index 000000000..327ff8960
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowDifferentOrigin.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenWindowDifferentOrigin.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowEmpty.html b/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowEmpty.html
new file mode 100644
index 000000000..03738de71
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowEmpty.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 1216937</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenWindowEmpty.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowInFrame.html b/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowInFrame.html
new file mode 100644
index 000000000..e2c02d4a9
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowInFrame.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenWindowInFrame.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowRejected.html b/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowRejected.html
new file mode 100644
index 000000000..a96b378f6
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowRejected.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenWindowRejected.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowRejected2.html b/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowRejected2.html
new file mode 100644
index 000000000..a96b378f6
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_OpenWindowRejected2.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenWindowRejected.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Opensearch.html b/dom/browser-element/mochitest/test_browserElement_inproc_Opensearch.html
new file mode 100644
index 000000000..23f21ed83
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Opensearch.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=883002
+-->
+<head>
+ <title>Test for Bug 883002</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=883002">Mozilla Bug 883002</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Opensearch.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_PrivateBrowsing.html b/dom/browser-element/mochitest/test_browserElement_inproc_PrivateBrowsing.html
new file mode 100644
index 000000000..0947fd7c7
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_PrivateBrowsing.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=832700
+-->
+<head>
+ <title>Test for Bug 832700</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=832700">Mozilla Bug 832700</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_PrivateBrowsing.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_PromptCheck.html b/dom/browser-element/mochitest/test_browserElement_inproc_PromptCheck.html
new file mode 100644
index 000000000..476c7e2c2
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_PromptCheck.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=741587
+-->
+<head>
+ <title>Test for Bug 741587</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=741587">Mozilla Bug 741587</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_PromptCheck.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_PromptConfirm.html b/dom/browser-element/mochitest/test_browserElement_inproc_PromptConfirm.html
new file mode 100644
index 000000000..b29a52025
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_PromptConfirm.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=741587
+-->
+<head>
+ <title>Test for Bug 741587</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=741587">Mozilla Bug 741587</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_PromptConfirm.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Proxy.html b/dom/browser-element/mochitest/test_browserElement_inproc_Proxy.html
new file mode 100644
index 000000000..05a416eee
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Proxy.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1196654
+-->
+<head>
+ <title>Test for Bug 1196654</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1196654">Mozilla Bug 1196654</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Proxy.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_PurgeHistory.html b/dom/browser-element/mochitest/test_browserElement_inproc_PurgeHistory.html
new file mode 100644
index 000000000..1c052996c
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_PurgeHistory.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_PurgeHistory.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Reload.html b/dom/browser-element/mochitest/test_browserElement_inproc_Reload.html
new file mode 100644
index 000000000..75b912b19
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Reload.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_Reload.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_ReloadPostRequest.html b/dom/browser-element/mochitest/test_browserElement_inproc_ReloadPostRequest.html
new file mode 100644
index 000000000..d26e7a0b5
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_ReloadPostRequest.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_ReloadPostRequest.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_RemoveBrowserElement.html b/dom/browser-element/mochitest/test_browserElement_inproc_RemoveBrowserElement.html
new file mode 100644
index 000000000..8ccbe09a7
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_RemoveBrowserElement.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=787517
+-->
+<head>
+ <title>Test for Bug 787517</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=787517">Mozilla Bug 787517</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_RemoveBrowserElement.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_ScrollEvent.html b/dom/browser-element/mochitest/test_browserElement_inproc_ScrollEvent.html
new file mode 100644
index 000000000..e87792243
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_ScrollEvent.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=770847
+-->
+<head>
+ <title>Test for Bug 770847</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=770847">Mozilla Bug 770847</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_ScrollEvent.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_SecurityChange.html b/dom/browser-element/mochitest/test_browserElement_inproc_SecurityChange.html
new file mode 100644
index 000000000..ceaa6a40e
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_SecurityChange.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_SecurityChange.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_SendEvent.html b/dom/browser-element/mochitest/test_browserElement_inproc_SendEvent.html
new file mode 100644
index 000000000..5eee91ed7
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_SendEvent.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=774809
+-->
+<head>
+ <title>Test for Bug 774809</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.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=774809">Mozilla Bug 774809</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_SendEvent.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_SetInputMethodActive.html b/dom/browser-element/mochitest/test_browserElement_inproc_SetInputMethodActive.html
new file mode 100644
index 000000000..957bf82fc
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_SetInputMethodActive.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 905573</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_SetInputMethodActive.js">
+</script>
+</body>
+</html>
+
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_SetVisible.html b/dom/browser-element/mochitest/test_browserElement_inproc_SetVisible.html
new file mode 100644
index 000000000..6241d4b1f
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_SetVisible.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=702880
+-->
+ <head>
+ <title>Test for Bug 702880</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.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=753595">Mozilla Bug 702880</a>
+
+<script type="application/javascript;version=1.7" src='browserElement_SetVisible.js'>
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames.html b/dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames.html
new file mode 100644
index 000000000..8ae182285
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 762939</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_SetVisibleFrames.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames2.html b/dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames2.html
new file mode 100644
index 000000000..17d161a95
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_SetVisibleFrames2.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 762939</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_SetVisibleFrames2.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Stop.html b/dom/browser-element/mochitest/test_browserElement_inproc_Stop.html
new file mode 100644
index 000000000..42c32da7e
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Stop.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_Stop.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_TargetBlank.html b/dom/browser-element/mochitest/test_browserElement_inproc_TargetBlank.html
new file mode 100644
index 000000000..916ed312b
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_TargetBlank.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for mozbrowser</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_TargetBlank.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_TargetTop.html b/dom/browser-element/mochitest/test_browserElement_inproc_TargetTop.html
new file mode 100644
index 000000000..6c99f1c21
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_TargetTop.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 771273</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_TargetTop.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_ThemeColor.html b/dom/browser-element/mochitest/test_browserElement_inproc_ThemeColor.html
new file mode 100644
index 000000000..4075ce58d
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_ThemeColor.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1013913
+-->
+<head>
+ <title>Test for Bug 1013913</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1013913">Mozilla Bug 1013913</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_ThemeColor.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Titlechange.html b/dom/browser-element/mochitest/test_browserElement_inproc_Titlechange.html
new file mode 100644
index 000000000..1fdde48c1
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Titlechange.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=720157
+-->
+<head>
+ <title>Test for Bug 720157</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=720157">Mozilla Bug 720157</a>
+
+<script type="application/javascript;version=1.7" src='browserElement_Titlechange.js'>
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_TopBarrier.html b/dom/browser-element/mochitest/test_browserElement_inproc_TopBarrier.html
new file mode 100644
index 000000000..c77a7a9ec
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_TopBarrier.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=725796
+-->
+<head>
+ <title>Test for Bug 725796</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=725796">Mozilla Bug 725796</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_TopBarrier.js">
+</script>
+
+</body>
+</html>
+
+
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_Viewmode.html b/dom/browser-element/mochitest/test_browserElement_inproc_Viewmode.html
new file mode 100644
index 000000000..286dd3989
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Viewmode.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1162844
+-->
+<head>
+ <title>Test for Bug 1162844</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1162844">Mozilla Bug 1162844</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Viewmode.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_VisibilityChange.html b/dom/browser-element/mochitest/test_browserElement_inproc_VisibilityChange.html
new file mode 100644
index 000000000..ce4251a42
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_VisibilityChange.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=868816
+-->
+<head>
+ <title>Test for Bug 868816</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.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=868816">Mozilla Bug 868816</a>
+
+<script type="application/javascript;version=1.7" src='browserElement_VisibilityChange.js'>
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptions.html b/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptions.html
new file mode 100644
index 000000000..36479ee06
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptions.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 770239</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_XFrameOptions.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsAllowFrom.html b/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsAllowFrom.html
new file mode 100644
index 000000000..801c7879f
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsAllowFrom.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 690168</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_XFrameOptionsAllowFrom.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsDeny.html b/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsDeny.html
new file mode 100644
index 000000000..edd91dbd7
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsDeny.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 770239</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_XFrameOptionsDeny.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsSameOrigin.html b/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsSameOrigin.html
new file mode 100644
index 000000000..e0ecbabc4
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsSameOrigin.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 770239</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_XFrameOptionsSameOrigin.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_getWebManifest.html b/dom/browser-element/mochitest/test_browserElement_inproc_getWebManifest.html
new file mode 100644
index 000000000..1252de5e5
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_getWebManifest.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 1169633</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.8"
+ src="async.js">
+</script>
+<script type="application/javascript;version=1.8"
+ src="browserElement_getWebManifest.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_ActiveStateChange.html b/dom/browser-element/mochitest/test_browserElement_oop_ActiveStateChange.html
new file mode 100644
index 000000000..4a14ad7cb
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_ActiveStateChange.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test ActiveStateChangeOnChangingMutedOrVolume</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_ActiveStateChange.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Alert.html b/dom/browser-element/mochitest/test_browserElement_oop_Alert.html
new file mode 100644
index 000000000..03d03135d
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Alert.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=741587
+-->
+<head>
+ <title>Test for Bug 741587</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=741587">Mozilla Bug 741587</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Alert.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_AlertInFrame.html b/dom/browser-element/mochitest/test_browserElement_oop_AlertInFrame.html
new file mode 100644
index 000000000..d797a1a3a
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_AlertInFrame.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for iframe mozbrowser</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_AlertInFrame.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_AudioChannel.html b/dom/browser-element/mochitest/test_browserElement_oop_AudioChannel.html
new file mode 100644
index 000000000..34909e904
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_AudioChannel.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element audioChannel.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_AudioChannel.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_AudioChannelMutedByDefault.html b/dom/browser-element/mochitest/test_browserElement_oop_AudioChannelMutedByDefault.html
new file mode 100644
index 000000000..60bead59f
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_AudioChannelMutedByDefault.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1235535 - Audio Channel Muted-By-Default.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_AudioChannelMutedByDefault.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_AudioChannelSeeking.html b/dom/browser-element/mochitest/test_browserElement_oop_AudioChannelSeeking.html
new file mode 100644
index 000000000..54c3a1fb4
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_AudioChannelSeeking.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1225425 - Do not unregister the AudioChannelAgent during seeking</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_AudioChannelSeeking.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_AudioChannel_nested.html b/dom/browser-element/mochitest/test_browserElement_oop_AudioChannel_nested.html
new file mode 100644
index 000000000..d189a7ca4
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_AudioChannel_nested.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element audioChannel.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_AudioChannel_nested.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_AudioPlayback.html b/dom/browser-element/mochitest/test_browserElement_oop_AudioPlayback.html
new file mode 100644
index 000000000..bb3a1c2d6
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_AudioPlayback.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1180824
+-->
+<head>
+ <title>Test for Bug 1180824</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1180824">Mozilla Bug 1180824</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_AudioPlayback.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Auth.html b/dom/browser-element/mochitest/test_browserElement_oop_Auth.html
new file mode 100644
index 000000000..0dd60f8c6
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Auth.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=741587
+-->
+<head>
+ <title>Test for Bug 775464</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=775464">Mozilla Bug 775464</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Auth.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_BackForward.html b/dom/browser-element/mochitest/test_browserElement_oop_BackForward.html
new file mode 100644
index 000000000..e5d753b5e
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_BackForward.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_BackForward.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_BadScreenshot.html b/dom/browser-element/mochitest/test_browserElement_oop_BadScreenshot.html
new file mode 100644
index 000000000..5713b512e
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_BadScreenshot.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 800170</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_BadScreenshot.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_BrowserWindowResize.html b/dom/browser-element/mochitest/test_browserElement_oop_BrowserWindowResize.html
new file mode 100644
index 000000000..bcc86b872
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_BrowserWindowResize.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 891763</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_BrowserWindowResize.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Close.html b/dom/browser-element/mochitest/test_browserElement_oop_Close.html
new file mode 100644
index 000000000..76d203f9d
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Close.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=757182
+-->
+<head>
+ <title>Test for Bug 757182</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=757182">Mozilla Bug 757182</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Close.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_CloseFromOpener.html b/dom/browser-element/mochitest/test_browserElement_oop_CloseFromOpener.html
new file mode 100644
index 000000000..3c7ee4d87
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_CloseFromOpener.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=757182
+-->
+<head>
+ <title>Test for Bug 757182</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=757182">Mozilla Bug 757182</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_CloseFromOpener.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_ContextmenuEvents.html b/dom/browser-element/mochitest/test_browserElement_oop_ContextmenuEvents.html
new file mode 100644
index 000000000..a43f7dbef
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_ContextmenuEvents.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Contextmenu Events</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_ContextmenuEvents.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_CookiesNotThirdParty.html b/dom/browser-element/mochitest/test_browserElement_oop_CookiesNotThirdParty.html
new file mode 100644
index 000000000..37ea16fb0
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_CookiesNotThirdParty.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 806127</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_CookiesNotThirdParty.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_CopyPaste.html b/dom/browser-element/mochitest/test_browserElement_oop_CopyPaste.html
new file mode 100644
index 000000000..892245d4f
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_CopyPaste.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=987040
+-->
+<head>
+ <title>Test for Bug 987040</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=987040">Mozilla Bug 987040</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_CopyPaste.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_DOMRequestError.html b/dom/browser-element/mochitest/test_browserElement_oop_DOMRequestError.html
new file mode 100644
index 000000000..48d404cc3
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_DOMRequestError.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=787519
+-->
+<head>
+ <title>Test for Bug 787519</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=787519">Mozilla Bug 787519</a>
+
+<script type="application/javascript;version=1.7" src='browserElement_DOMRequestError.js'>
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_DataURI.html b/dom/browser-element/mochitest/test_browserElement_oop_DataURI.html
new file mode 100644
index 000000000..2ceb49cd0
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_DataURI.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=720157
+-->
+<head>
+ <title>Test for Bug 720157</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=720157">Mozilla Bug 720157</a>
+
+<script type='application/javascript;version=1.7' src='browserElement_DataURI.js'></script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_DocumentFirstPaint.html b/dom/browser-element/mochitest/test_browserElement_oop_DocumentFirstPaint.html
new file mode 100644
index 000000000..6667a76eb
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_DocumentFirstPaint.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 829486</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_DocumentFirstPaint.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Download.html b/dom/browser-element/mochitest/test_browserElement_oop_Download.html
new file mode 100644
index 000000000..c2e5e2ed3
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Download.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 983747</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_Download.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_ErrorSecurity.html b/dom/browser-element/mochitest/test_browserElement_oop_ErrorSecurity.html
new file mode 100644
index 000000000..318d29831
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_ErrorSecurity.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for mozbrowser</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_ErrorSecurity.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_ExecuteScript.html b/dom/browser-element/mochitest/test_browserElement_oop_ExecuteScript.html
new file mode 100644
index 000000000..e3bbabfa0
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_ExecuteScript.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1174733
+-->
+<head>
+ <title>Test for Bug 1163961</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1174733">Mozilla Bug 1174733</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_ExecuteScript.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_ExposableURI.html b/dom/browser-element/mochitest/test_browserElement_oop_ExposableURI.html
new file mode 100644
index 000000000..089e5db44
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_ExposableURI.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=795317
+-->
+<head>
+ <title>Test for Bug 795317</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=795317">Mozilla Bug 795317</a>
+
+<script type="application/javascript;version1.7" src="browserElement_ExposableURI.js"></script>
+
+</body>
+</html>
+
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Find.html b/dom/browser-element/mochitest/test_browserElement_oop_Find.html
new file mode 100644
index 000000000..e0333a6bb
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Find.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1163961
+-->
+<head>
+ <title>Test for Bug 1163961</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1163961">Mozilla Bug 1163961</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Find.js">
+</script>
+</body>
+</html>
+
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_FirstPaint.html b/dom/browser-element/mochitest/test_browserElement_oop_FirstPaint.html
new file mode 100644
index 000000000..ee013860c
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_FirstPaint.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 787378</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_FirstPaint.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_ForwardName.html b/dom/browser-element/mochitest/test_browserElement_oop_ForwardName.html
new file mode 100644
index 000000000..f24691ff1
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_ForwardName.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 781320</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_ForwardName.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_FrameWrongURI.html b/dom/browser-element/mochitest/test_browserElement_oop_FrameWrongURI.html
new file mode 100644
index 000000000..f0e6e6c20
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_FrameWrongURI.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_FrameWrongURI.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_GetContentDimensions.html b/dom/browser-element/mochitest/test_browserElement_oop_GetContentDimensions.html
new file mode 100644
index 000000000..067615c1b
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_GetContentDimensions.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_GetContentDimensions.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_GetScreenshot.html b/dom/browser-element/mochitest/test_browserElement_oop_GetScreenshot.html
new file mode 100644
index 000000000..81d3e1993
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_GetScreenshot.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=753595
+-->
+<head>
+ <title>Test for Bug 753595</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=753595">Mozilla Bug 753595</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=878003">Mozilla Bug 878003</a>
+
+<script type="application/javascript;version=1.7" src='browserElement_GetScreenshot.js'>
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_GetScreenshotDppx.html b/dom/browser-element/mochitest/test_browserElement_oop_GetScreenshotDppx.html
new file mode 100644
index 000000000..9d30fc541
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_GetScreenshotDppx.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=959066
+-->
+<head>
+ <title>Test for Bug 959066</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=959066">Mozilla Bug 959066</a>
+
+<script type="application/javascript;version=1.7" src='browserElement_GetScreenshotDppx.js'>
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Iconchange.html b/dom/browser-element/mochitest/test_browserElement_oop_Iconchange.html
new file mode 100644
index 000000000..2f17287de
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Iconchange.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=719461
+-->
+<head>
+ <title>Test for Bug 719461</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=719461">Mozilla Bug 719461</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Iconchange.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_LoadEvents.html b/dom/browser-element/mochitest/test_browserElement_oop_LoadEvents.html
new file mode 100644
index 000000000..c6daf805e
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_LoadEvents.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=710231
+-->
+<head>
+ <title>Test for Bug 710231</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=710231">Mozilla Bug 710231</a>
+
+<script type="application/javascript;version1.7" src="browserElement_LoadEvents.js"></script>
+
+</body>
+</html>
+
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Manifestchange.html b/dom/browser-element/mochitest/test_browserElement_oop_Manifestchange.html
new file mode 100644
index 000000000..64200bd48
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Manifestchange.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=982800
+-->
+<head>
+ <title>Test for Bug 982800</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=982800">Mozilla Bug 982800</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Manifestchange.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Metachange.html b/dom/browser-element/mochitest/test_browserElement_oop_Metachange.html
new file mode 100644
index 000000000..d799a52e4
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Metachange.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=962626
+-->
+<head>
+ <title>Test for Bug 962626</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=962626">Mozilla Bug 962626</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Metachange.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_NextPaint.html b/dom/browser-element/mochitest/test_browserElement_oop_NextPaint.html
new file mode 100644
index 000000000..8144819f2
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_NextPaint.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 808231</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_NextPaint.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_NoAudioTrack.html b/dom/browser-element/mochitest/test_browserElement_oop_NoAudioTrack.html
new file mode 100644
index 000000000..90782bc63
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_NoAudioTrack.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1227051 - No audio track video shouldn't register the AudioChannelAgent</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_NoAudioTrack.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_OpenMixedProcess.html b/dom/browser-element/mochitest/test_browserElement_oop_OpenMixedProcess.html
new file mode 100644
index 000000000..cefe06c3e
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_OpenMixedProcess.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 776129</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenMixedProcess.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_OpenNamed.html b/dom/browser-element/mochitest/test_browserElement_oop_OpenNamed.html
new file mode 100644
index 000000000..bbe12545c
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_OpenNamed.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenNamed.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_OpenTab.html b/dom/browser-element/mochitest/test_browserElement_oop_OpenTab.html
new file mode 100644
index 000000000..85b979bd0
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_OpenTab.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1144015
+-->
+<head>
+ <title>Test for Bug 1144015</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1144015">Mozilla Bug 1144015</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_OpenTab.js">
+</script>
+</body>
+</html>
+
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_OpenWindow.html b/dom/browser-element/mochitest/test_browserElement_oop_OpenWindow.html
new file mode 100644
index 000000000..7c249792f
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_OpenWindow.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenWindow.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowDifferentOrigin.html b/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowDifferentOrigin.html
new file mode 100644
index 000000000..327ff8960
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowDifferentOrigin.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenWindowDifferentOrigin.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowEmpty.html b/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowEmpty.html
new file mode 100644
index 000000000..03738de71
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowEmpty.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 1216937</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenWindowEmpty.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowInFrame.html b/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowInFrame.html
new file mode 100644
index 000000000..e2c02d4a9
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowInFrame.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenWindowInFrame.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowRejected.html b/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowRejected.html
new file mode 100644
index 000000000..a96b378f6
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowRejected.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenWindowRejected.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowRejected2.html b/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowRejected2.html
new file mode 100644
index 000000000..a96b378f6
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_OpenWindowRejected2.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenWindowRejected.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Opensearch.html b/dom/browser-element/mochitest/test_browserElement_oop_Opensearch.html
new file mode 100644
index 000000000..23f21ed83
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Opensearch.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=883002
+-->
+<head>
+ <title>Test for Bug 883002</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=883002">Mozilla Bug 883002</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Opensearch.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_PrivateBrowsing.html b/dom/browser-element/mochitest/test_browserElement_oop_PrivateBrowsing.html
new file mode 100644
index 000000000..0947fd7c7
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_PrivateBrowsing.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=832700
+-->
+<head>
+ <title>Test for Bug 832700</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=832700">Mozilla Bug 832700</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_PrivateBrowsing.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_PromptCheck.html b/dom/browser-element/mochitest/test_browserElement_oop_PromptCheck.html
new file mode 100644
index 000000000..476c7e2c2
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_PromptCheck.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=741587
+-->
+<head>
+ <title>Test for Bug 741587</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=741587">Mozilla Bug 741587</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_PromptCheck.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_PromptConfirm.html b/dom/browser-element/mochitest/test_browserElement_oop_PromptConfirm.html
new file mode 100644
index 000000000..b29a52025
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_PromptConfirm.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=741587
+-->
+<head>
+ <title>Test for Bug 741587</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=741587">Mozilla Bug 741587</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_PromptConfirm.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Proxy.html b/dom/browser-element/mochitest/test_browserElement_oop_Proxy.html
new file mode 100644
index 000000000..05a416eee
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Proxy.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1196654
+-->
+<head>
+ <title>Test for Bug 1196654</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1196654">Mozilla Bug 1196654</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Proxy.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_PurgeHistory.html b/dom/browser-element/mochitest/test_browserElement_oop_PurgeHistory.html
new file mode 100644
index 000000000..cf606fd80
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_PurgeHistory.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_PurgeHistory.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Reload.html b/dom/browser-element/mochitest/test_browserElement_oop_Reload.html
new file mode 100644
index 000000000..75b912b19
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Reload.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_Reload.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_ReloadPostRequest.html b/dom/browser-element/mochitest/test_browserElement_oop_ReloadPostRequest.html
new file mode 100644
index 000000000..d26e7a0b5
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_ReloadPostRequest.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_ReloadPostRequest.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_RemoveBrowserElement.html b/dom/browser-element/mochitest/test_browserElement_oop_RemoveBrowserElement.html
new file mode 100644
index 000000000..8ccbe09a7
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_RemoveBrowserElement.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=787517
+-->
+<head>
+ <title>Test for Bug 787517</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=787517">Mozilla Bug 787517</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_RemoveBrowserElement.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_ScrollEvent.html b/dom/browser-element/mochitest/test_browserElement_oop_ScrollEvent.html
new file mode 100644
index 000000000..e87792243
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_ScrollEvent.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=770847
+-->
+<head>
+ <title>Test for Bug 770847</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=770847">Mozilla Bug 770847</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_ScrollEvent.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_SecurityChange.html b/dom/browser-element/mochitest/test_browserElement_oop_SecurityChange.html
new file mode 100644
index 000000000..ceaa6a40e
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_SecurityChange.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_SecurityChange.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_SendEvent.html b/dom/browser-element/mochitest/test_browserElement_oop_SendEvent.html
new file mode 100644
index 000000000..38d16a9da
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_SendEvent.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=774809
+-->
+<head>
+ <title>Test for Bug 774809</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=774809">Mozilla Bug 774809</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_SendEvent.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_SetInputMethodActive.html b/dom/browser-element/mochitest/test_browserElement_oop_SetInputMethodActive.html
new file mode 100644
index 000000000..5d4b45bc8
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_SetInputMethodActive.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 905573</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_SetInputMethodActive.js">
+</script>
+</body>
+</html>
+
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_SetVisible.html b/dom/browser-element/mochitest/test_browserElement_oop_SetVisible.html
new file mode 100644
index 000000000..a2220d1b3
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_SetVisible.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=702880
+-->
+ <head>
+ <title>Test for Bug 702880</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=753595">Mozilla Bug 702880</a>
+
+<script type="application/javascript;version=1.7" src='browserElement_SetVisible.js'>
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames.html b/dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames.html
new file mode 100644
index 000000000..b6477c870
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 762939</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_SetVisibleFrames.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames2.html b/dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames2.html
new file mode 100644
index 000000000..108080f50
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_SetVisibleFrames2.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 762939</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_SetVisibleFrames2.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Stop.html b/dom/browser-element/mochitest/test_browserElement_oop_Stop.html
new file mode 100644
index 000000000..3425944e8
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Stop.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test of browser element.</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_Stop.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_TargetBlank.html b/dom/browser-element/mochitest/test_browserElement_oop_TargetBlank.html
new file mode 100644
index 000000000..916ed312b
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_TargetBlank.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for mozbrowser</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_TargetBlank.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_TargetTop.html b/dom/browser-element/mochitest/test_browserElement_oop_TargetTop.html
new file mode 100644
index 000000000..6c99f1c21
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_TargetTop.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 771273</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_TargetTop.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_ThemeColor.html b/dom/browser-element/mochitest/test_browserElement_oop_ThemeColor.html
new file mode 100644
index 000000000..4075ce58d
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_ThemeColor.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1013913
+-->
+<head>
+ <title>Test for Bug 1013913</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1013913">Mozilla Bug 1013913</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_ThemeColor.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Titlechange.html b/dom/browser-element/mochitest/test_browserElement_oop_Titlechange.html
new file mode 100644
index 000000000..1fdde48c1
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Titlechange.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=720157
+-->
+<head>
+ <title>Test for Bug 720157</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=720157">Mozilla Bug 720157</a>
+
+<script type="application/javascript;version=1.7" src='browserElement_Titlechange.js'>
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_TopBarrier.html b/dom/browser-element/mochitest/test_browserElement_oop_TopBarrier.html
new file mode 100644
index 000000000..8756b4455
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_TopBarrier.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=725796
+-->
+<head>
+ <title>Test for Bug 725796</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=725796">Mozilla Bug 725796</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_TopBarrier.js">
+</script>
+
+</body>
+</html>
+
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_Viewmode.html b/dom/browser-element/mochitest/test_browserElement_oop_Viewmode.html
new file mode 100644
index 000000000..286dd3989
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Viewmode.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1162844
+-->
+<head>
+ <title>Test for Bug 1162844</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1162844">Mozilla Bug 1162844</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Viewmode.js">
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_VisibilityChange.html b/dom/browser-element/mochitest/test_browserElement_oop_VisibilityChange.html
new file mode 100644
index 000000000..546882c1c
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_VisibilityChange.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=868816
+-->
+<head>
+ <title>Test for Bug 868816</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=868816">Mozilla Bug 868816</a>
+
+<script type="application/javascript;version=1.7" src='browserElement_VisibilityChange.js'>
+</script>
+
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptions.html b/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptions.html
new file mode 100644
index 000000000..36479ee06
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptions.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 770239</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_XFrameOptions.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsAllowFrom.html b/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsAllowFrom.html
new file mode 100644
index 000000000..801c7879f
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsAllowFrom.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 690168</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_XFrameOptionsAllowFrom.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsDeny.html b/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsDeny.html
new file mode 100644
index 000000000..edd91dbd7
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsDeny.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 770239</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_XFrameOptionsDeny.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsSameOrigin.html b/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsSameOrigin.html
new file mode 100644
index 000000000..e0ecbabc4
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsSameOrigin.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 770239</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_XFrameOptionsSameOrigin.js">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/browser-element/mochitest/test_browserElement_oop_getWebManifest.html b/dom/browser-element/mochitest/test_browserElement_oop_getWebManifest.html
new file mode 100644
index 000000000..4ee13d924
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_getWebManifest.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 1169633</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/dom/browser-element/mochitest/browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.8"
+ src="async.js"></script>
+<script type="application/javascript;version=1.8"
+ src="browserElement_getWebManifest.js">
+</script>
+</body>
+</html>
diff --git a/dom/browser-element/moz.build b/dom/browser-element/moz.build
new file mode 100644
index 000000000..0b00a2e06
--- /dev/null
+++ b/dom/browser-element/moz.build
@@ -0,0 +1,60 @@
+# -*- 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/.
+
+EXPORTS.mozilla += [
+ 'BrowserElementParent.h',
+]
+
+EXPORTS.mozilla.dom += [
+ 'BrowserElementAudioChannel.h',
+]
+
+SOURCES += [
+ 'BrowserElementAudioChannel.cpp',
+ 'BrowserElementParent.cpp',
+]
+
+XPIDL_SOURCES += [
+ 'nsIBrowserElementAPI.idl',
+]
+
+XPIDL_MODULE = 'browser-element'
+
+EXTRA_COMPONENTS += [
+ 'BrowserElementParent.js',
+ 'BrowserElementParent.manifest',
+ 'BrowserElementProxy.js',
+ 'BrowserElementProxy.manifest',
+]
+
+EXTRA_JS_MODULES += [
+ 'BrowserElementPromptService.jsm',
+]
+
+LOCAL_INCLUDES += [
+ '/dom/html',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
+LOCAL_INCLUDES += [
+ '/dom/',
+ '/dom/base',
+ '/dom/ipc',
+]
+
+MOCHITEST_MANIFESTS += [
+ 'mochitest/mochitest-oop.ini',
+ 'mochitest/mochitest.ini',
+ 'mochitest/priority/mochitest.ini',
+]
+
+MOCHITEST_CHROME_MANIFESTS += [
+ 'mochitest/chrome.ini',
+ 'mochitest/priority/chrome.ini',
+]
diff --git a/dom/browser-element/nsIBrowserElementAPI.idl b/dom/browser-element/nsIBrowserElementAPI.idl
new file mode 100644
index 000000000..0833d53b0
--- /dev/null
+++ b/dom/browser-element/nsIBrowserElementAPI.idl
@@ -0,0 +1,112 @@
+/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=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 "nsISupports.idl"
+
+interface nsIDOMDOMRequest;
+interface nsIFrameLoader;
+
+[scriptable, function, uuid(00d0e19d-bd67-491f-8e85-b9905224d3bb)]
+interface nsIBrowserElementNextPaintListener : nsISupports
+{
+ void recvNextPaint();
+};
+
+%{C++
+#define BROWSER_ELEMENT_API_CONTRACTID "@mozilla.org/dom/browser-element-api;1"
+#define BROWSER_ELEMENT_API_CID \
+ { 0x651db7e3, 0x1734, 0x4536, \
+ { 0xb1, 0x5a, 0x5b, 0x3a, 0xe6, 0x44, 0x13, 0x4c } }
+%}
+
+/**
+ * Interface to the BrowserElementParent implementation. All methods
+ * but setFrameLoader throw when the remote process is dead.
+ */
+[scriptable, uuid(57758c10-6036-11e5-a837-0800200c9a66)]
+interface nsIBrowserElementAPI : nsISupports
+{
+ const long FIND_CASE_SENSITIVE = 0;
+ const long FIND_CASE_INSENSITIVE = 1;
+
+ const long FIND_FORWARD = 0;
+ const long FIND_BACKWARD = 1;
+
+ /**
+ * Notify frame scripts that support the API to destroy.
+ */
+ void destroyFrameScripts();
+
+ void setFrameLoader(in nsIFrameLoader frameLoader);
+
+ void setVisible(in boolean visible);
+ nsIDOMDOMRequest getVisible();
+ void setActive(in boolean active);
+ boolean getActive();
+
+ void sendMouseEvent(in DOMString type,
+ in uint32_t x,
+ in uint32_t y,
+ in uint32_t button,
+ in uint32_t clickCount,
+ in uint32_t mifiers);
+ void sendTouchEvent(in DOMString aType,
+ [const, array, size_is(count)] in uint32_t aIdentifiers,
+ [const, array, size_is(count)] in int32_t aXs,
+ [const, array, size_is(count)] in int32_t aYs,
+ [const, array, size_is(count)] in uint32_t aRxs,
+ [const, array, size_is(count)] in uint32_t aRys,
+ [const, array, size_is(count)] in float aRotationAngles,
+ [const, array, size_is(count)] in float aForces,
+ in uint32_t count,
+ in long aModifiers);
+ void goBack();
+ void goForward();
+ void reload(in boolean hardReload);
+ void stop();
+ nsIDOMDOMRequest download(in DOMString url,
+ [optional] in jsval options);
+ nsIDOMDOMRequest purgeHistory();
+ nsIDOMDOMRequest getScreenshot(in uint32_t width,
+ in uint32_t height,
+ [optional] in DOMString mimeType);
+ void zoom(in float zoom);
+ nsIDOMDOMRequest getCanGoBack();
+ nsIDOMDOMRequest getCanGoForward();
+ nsIDOMDOMRequest getContentDimensions();
+
+ void findAll(in DOMString searchString, in long caseSensitivity);
+ void findNext(in long direction);
+ void clearMatch();
+
+ void mute();
+ void unmute();
+ nsIDOMDOMRequest getMuted();
+
+ void setVolume(in float volume);
+ nsIDOMDOMRequest getVolume();
+
+ void addNextPaintListener(in nsIBrowserElementNextPaintListener listener);
+ void removeNextPaintListener(in nsIBrowserElementNextPaintListener listener);
+
+ nsIDOMDOMRequest setInputMethodActive(in boolean isActive);
+
+ nsIDOMDOMRequest getAudioChannelVolume(in uint32_t audioChannel);
+ nsIDOMDOMRequest setAudioChannelVolume(in uint32_t audioChannel, in float volume);
+
+ nsIDOMDOMRequest getAudioChannelMuted(in uint32_t audioChannel);
+ nsIDOMDOMRequest setAudioChannelMuted(in uint32_t audioChannel, in bool muted);
+
+ nsIDOMDOMRequest isAudioChannelActive(in uint32_t audioChannel);
+
+ nsIDOMDOMRequest executeScript(in DOMString script, in jsval options);
+
+ /**
+ * Returns an object that represents a Web Manifest:
+ * http://w3c.github.io/manifest/
+ */
+ nsIDOMDOMRequest getWebManifest();
+};