summaryrefslogtreecommitdiffstats
path: root/dom
diff options
context:
space:
mode:
Diffstat (limited to 'dom')
-rw-r--r--dom/asmjscache/AsmJSCache.cpp348
-rw-r--r--dom/asmjscache/test/test_cachingBasic.html2
-rw-r--r--dom/asmjscache/test/test_cachingMulti.html2
-rw-r--r--dom/asmjscache/test/test_workers.html2
-rw-r--r--dom/base/Element.cpp29
-rw-r--r--dom/base/Element.h18
-rwxr-xr-x[-rw-r--r--]dom/base/File.cpp3
-rw-r--r--dom/base/FileReader.cpp4
-rw-r--r--dom/base/FragmentOrElement.cpp8
-rw-r--r--dom/base/FragmentOrElement.h6
-rw-r--r--dom/base/IdleRequest.cpp119
-rw-r--r--dom/base/IdleRequest.h40
-rw-r--r--dom/base/Location.cpp21
-rwxr-xr-x[-rw-r--r--]dom/base/MultipartBlobImpl.cpp4
-rw-r--r--dom/base/Navigator.cpp18
-rw-r--r--dom/base/Navigator.h4
-rw-r--r--dom/base/Timeout.h8
-rw-r--r--dom/base/TimeoutHandler.cpp43
-rw-r--r--dom/base/TimeoutHandler.h50
-rwxr-xr-xdom/base/TimerClamping.cpp35
-rwxr-xr-xdom/base/TimerClamping.h22
-rwxr-xr-x[-rw-r--r--]dom/base/moz.build8
-rw-r--r--dom/base/nsContentList.cpp143
-rw-r--r--dom/base/nsContentList.h40
-rw-r--r--dom/base/nsContentListDeclarations.h8
-rw-r--r--dom/base/nsContentPolicy.cpp6
-rw-r--r--dom/base/nsContentSink.cpp5
-rw-r--r--dom/base/nsContentUtils.cpp38
-rw-r--r--dom/base/nsContentUtils.h29
-rw-r--r--dom/base/nsDOMNavigationTiming.cpp138
-rw-r--r--dom/base/nsDOMNavigationTiming.h125
-rw-r--r--dom/base/nsDocument.cpp51
-rw-r--r--dom/base/nsDocument.h3
-rw-r--r--dom/base/nsDocumentEncoder.cpp2
-rw-r--r--dom/base/nsFrameMessageManager.cpp4
-rw-r--r--dom/base/nsGkAtomList.h7
-rw-r--r--dom/base/nsGlobalWindow.cpp392
-rw-r--r--dom/base/nsGlobalWindow.h45
-rw-r--r--dom/base/nsIContent.h19
-rw-r--r--dom/base/nsIDocument.h31
-rw-r--r--dom/base/nsINode.cpp4
-rw-r--r--dom/base/nsPluginArray.cpp18
-rw-r--r--dom/base/nsRange.cpp2
-rw-r--r--dom/base/nsTreeSanitizer.cpp2
-rwxr-xr-x[-rw-r--r--]dom/base/nsXHTMLContentSerializer.cpp2
-rw-r--r--dom/base/test/mochitest.ini1
-rw-r--r--dom/base/test/test_bug1375050.html33
-rw-r--r--dom/base/test/test_bug403852.html7
-rw-r--r--dom/base/test/test_file_negative_date.html6
-rw-r--r--dom/base/test/test_viewport_scroll.html4
-rw-r--r--dom/bindings/BindingUtils.cpp20
-rw-r--r--dom/bindings/Codegen.py14
-rw-r--r--dom/bindings/ErrorResult.h2
-rw-r--r--dom/bindings/moz.build2
-rw-r--r--dom/bindings/test/test_promise_rejections_from_jsimplemented.html2
-rw-r--r--dom/browser-element/mochitest/browserElement_ScrollEvent.js4
-rw-r--r--dom/cache/Cache.cpp2
-rw-r--r--dom/canvas/CanvasRenderingContext2D.cpp28
-rw-r--r--dom/canvas/CanvasRenderingContext2D.h4
-rw-r--r--dom/canvas/DocumentRendererChild.cpp94
-rw-r--r--dom/canvas/DocumentRendererChild.h37
-rw-r--r--dom/canvas/DocumentRendererParent.cpp63
-rw-r--r--dom/canvas/DocumentRendererParent.h44
-rw-r--r--dom/canvas/WebGL2ContextState.cpp1
-rw-r--r--dom/canvas/WebGLContextDraw.cpp1
-rw-r--r--dom/canvas/WebGLContextExtensions.cpp4
-rw-r--r--dom/canvas/WebGLFramebuffer.cpp3
-rw-r--r--dom/canvas/WebGLObjectModel.h12
-rw-r--r--dom/canvas/WebGLProgram.cpp1
-rw-r--r--dom/canvas/WebGLTransformFeedback.cpp1
-rw-r--r--dom/canvas/moz.build9
-rw-r--r--dom/canvas/test/webgl-mochitest/mochitest.ini2
-rwxr-xr-x[-rw-r--r--]dom/console/Console.cpp6
-rw-r--r--dom/console/Console.h10
-rw-r--r--dom/crypto/WebCryptoTask.cpp5
-rwxr-xr-x[-rw-r--r--]dom/events/Event.cpp48
-rwxr-xr-x[-rw-r--r--]dom/events/Event.h5
-rw-r--r--dom/events/EventDispatcher.cpp5
-rw-r--r--dom/events/EventListenerManager.cpp5
-rw-r--r--dom/events/EventNameList.h4
-rw-r--r--dom/events/EventStateManager.cpp59
-rw-r--r--dom/events/PointerEvent.cpp14
-rw-r--r--dom/events/PointerEvent.h2
-rw-r--r--dom/events/test/pointerevents/mochitest.ini17
-rw-r--r--dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html65
-rw-r--r--dom/events/test/pointerevents/test_bug1285128.html7
-rw-r--r--dom/events/test/pointerevents/test_bug1323158.html93
-rw-r--r--dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html3
-rw-r--r--dom/events/test/pointerevents/test_pointerevent_releasepointercapture_events_to_original_target-manual.html27
-rw-r--r--dom/events/test/pointerevents/test_pointerevent_setpointercapture_relatedtarget-manual.html4
-rw-r--r--dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html57
-rw-r--r--dom/events/test/pointerevents/test_trigger_popup_by_pointer_events.html76
-rw-r--r--dom/events/test/test_eventTimeStamp.html48
-rw-r--r--dom/fetch/InternalHeaders.cpp58
-rw-r--r--dom/fetch/InternalHeaders.h31
-rw-r--r--dom/fetch/Response.cpp8
-rw-r--r--dom/fetch/Response.h2
-rw-r--r--dom/html/HTMLAllCollection.cpp7
-rw-r--r--dom/html/HTMLDataListElement.cpp6
-rw-r--r--dom/html/HTMLDataListElement.h4
-rw-r--r--dom/html/HTMLFieldSetElement.cpp4
-rw-r--r--dom/html/HTMLFieldSetElement.h4
-rw-r--r--dom/html/HTMLInputElement.cpp453
-rw-r--r--dom/html/HTMLInputElement.h98
-rw-r--r--dom/html/HTMLLabelElement.cpp23
-rw-r--r--dom/html/HTMLMediaElement.cpp48
-rw-r--r--dom/html/HTMLMediaElement.h10
-rw-r--r--dom/html/HTMLSelectElement.cpp4
-rw-r--r--dom/html/HTMLSelectElement.h2
-rw-r--r--dom/html/HTMLTableRowElement.cpp4
-rw-r--r--dom/html/crashtests/1350972.html22
-rw-r--r--dom/html/crashtests/crashtests.list1
-rw-r--r--dom/html/nsGenericHTMLElement.cpp40
-rw-r--r--dom/html/nsGenericHTMLElement.h6
-rw-r--r--dom/html/nsHTMLDocument.cpp76
-rw-r--r--dom/html/nsHTMLDocument.h12
-rw-r--r--dom/html/nsIFormControl.h2
-rw-r--r--dom/html/nsTextEditorState.cpp31
-rw-r--r--dom/html/nsTextEditorState.h2
-rw-r--r--dom/html/test/forms/mochitest.ini8
-rw-r--r--dom/html/test/forms/test_button_attributes_reflection.html9
-rw-r--r--dom/html/test/forms/test_input_date_key_events.html228
-rw-r--r--dom/html/test/forms/test_input_datetime_focus_blur.html28
-rw-r--r--dom/html/test/forms/test_input_datetime_focus_blur_events.html90
-rw-r--r--dom/html/test/forms/test_input_datetime_input_change_events.html88
-rw-r--r--dom/html/test/forms/test_input_datetime_tabindex.html47
-rw-r--r--dom/html/test/forms/test_input_time_focus_blur_events.html82
-rw-r--r--dom/html/test/forms/test_input_types_pref.html48
-rw-r--r--dom/html/test/forms/test_input_typing_sanitization.html28
-rw-r--r--dom/html/test/forms/test_max_attribute.html47
-rw-r--r--dom/html/test/forms/test_min_attribute.html49
-rw-r--r--dom/html/test/forms/test_step_attribute.html102
-rw-r--r--dom/html/test/forms/test_stepup_stepdown.html174
-rw-r--r--dom/html/test/forms/test_valueAsDate_pref.html8
-rw-r--r--dom/html/test/forms/test_valueasdate_attribute.html108
-rw-r--r--dom/html/test/forms/test_valueasnumber_attribute.html123
-rw-r--r--dom/html/test/test_bug558788-1.html5
-rw-r--r--dom/indexedDB/ActorsParent.cpp108
-rw-r--r--dom/indexedDB/test/browser_forgetThisSite.js7
-rw-r--r--dom/interfaces/security/nsIContentSecurityPolicy.idl6
-rw-r--r--dom/ipc/ContentChild.cpp39
-rw-r--r--dom/ipc/ContentParent.cpp86
-rw-r--r--dom/ipc/ContentProcess.cpp9
-rw-r--r--dom/ipc/CrashReporterParent.cpp83
-rw-r--r--dom/ipc/CrashReporterParent.h236
-rw-r--r--dom/ipc/DatePickerParent.cpp87
-rw-r--r--dom/ipc/DatePickerParent.h61
-rw-r--r--dom/ipc/PBrowser.ipdl28
-rw-r--r--dom/ipc/PDatePicker.ipdl27
-rw-r--r--dom/ipc/PDocumentRenderer.ipdl25
-rw-r--r--dom/ipc/ProcessHangMonitor.cpp36
-rw-r--r--dom/ipc/TabChild.cpp75
-rw-r--r--dom/ipc/TabChild.h25
-rw-r--r--dom/ipc/TabMessageUtils.h8
-rw-r--r--dom/ipc/TabParent.cpp34
-rw-r--r--dom/ipc/TabParent.h15
-rw-r--r--dom/ipc/moz.build3
-rw-r--r--dom/locales/en-US/chrome/layout/HtmlForm.properties1
-rw-r--r--dom/locales/en-US/chrome/plugins.properties3
-rw-r--r--dom/locales/en-US/chrome/security/csp.properties11
-rw-r--r--dom/locales/en-US/chrome/security/security.properties3
-rw-r--r--dom/media/AudioConverter.cpp8
-rw-r--r--dom/media/Benchmark.cpp2
-rwxr-xr-x[-rw-r--r--]dom/media/DOMMediaStream.cpp5
-rw-r--r--dom/media/DecoderDoctorDiagnostics.cpp13
-rw-r--r--dom/media/GraphDriver.cpp1
-rw-r--r--dom/media/MediaData.cpp2
-rw-r--r--dom/media/MediaDecoderOwner.h2
-rw-r--r--dom/media/MediaFormatReader.cpp12
-rw-r--r--dom/media/MediaManager.cpp36
-rw-r--r--dom/media/MediaPrefs.h4
-rw-r--r--dom/media/MediaStreamGraph.cpp4
-rw-r--r--dom/media/MediaStreamTrack.cpp12
-rw-r--r--dom/media/eme/MediaKeySystemAccess.cpp14
-rw-r--r--dom/media/fmp4/MP4Decoder.cpp8
-rw-r--r--dom/media/gmp/GMPChild.cpp4
-rw-r--r--dom/media/gmp/GMPParent.cpp154
-rw-r--r--dom/media/gmp/GMPParent.h15
-rw-r--r--dom/media/gmp/GMPServiceParent.cpp109
-rw-r--r--dom/media/gmp/GMPServiceParent.h18
-rw-r--r--dom/media/gtest/TestGMPCrossOrigin.cpp5
-rw-r--r--dom/media/gtest/moz.build4
-rw-r--r--dom/media/mediasource/TrackBuffersManager.cpp4
-rw-r--r--dom/media/platforms/PDMFactory.cpp15
-rw-r--r--dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp4
-rw-r--r--dom/media/platforms/wmf/WMF.h18
-rw-r--r--dom/media/platforms/wmf/WMFUtils.cpp16
-rw-r--r--dom/media/systemservices/MediaParent.cpp34
-rwxr-xr-x[-rw-r--r--]dom/media/test/test_background_video_suspend.html4
-rwxr-xr-x[-rw-r--r--]dom/media/test/test_streams_element_capture.html3
-rwxr-xr-x[-rw-r--r--]dom/media/test/test_streams_element_capture_createObjectURL.html3
-rwxr-xr-x[-rw-r--r--]dom/media/webaudio/AudioContext.cpp5
-rw-r--r--dom/media/webrtc/MediaEngineWebRTC.cpp4
-rwxr-xr-x[-rw-r--r--]dom/performance/Performance.cpp54
-rw-r--r--dom/performance/Performance.h36
-rw-r--r--dom/performance/PerformanceEntry.h21
-rw-r--r--dom/performance/PerformanceMainThread.cpp104
-rw-r--r--dom/performance/PerformanceMainThread.h21
-rw-r--r--dom/performance/PerformanceNavigationTiming.cpp96
-rw-r--r--dom/performance/PerformanceNavigationTiming.h71
-rw-r--r--dom/performance/PerformanceObserver.cpp14
-rw-r--r--dom/performance/PerformanceObserverEntryList.cpp15
-rw-r--r--dom/performance/PerformanceResourceTiming.cpp49
-rw-r--r--dom/performance/PerformanceResourceTiming.h18
-rw-r--r--dom/performance/PerformanceService.cpp46
-rw-r--r--dom/performance/PerformanceService.h48
-rwxr-xr-x[-rw-r--r--]dom/performance/PerformanceTiming.cpp128
-rwxr-xr-x[-rw-r--r--]dom/performance/PerformanceTiming.h48
-rw-r--r--dom/performance/PerformanceWorker.cpp35
-rw-r--r--dom/performance/PerformanceWorker.h14
-rw-r--r--dom/performance/moz.build4
-rw-r--r--dom/performance/tests/mochitest.ini3
-rw-r--r--dom/performance/tests/performance_observer.html74
-rw-r--r--dom/performance/tests/test_performance_observer.html52
-rw-r--r--dom/performance/tests/test_performance_user_timing.js23
-rw-r--r--dom/performance/tests/test_timeOrigin.html68
-rw-r--r--dom/performance/tests/test_worker_observer.html13
-rw-r--r--dom/performance/tests/test_worker_performance_now.js48
-rw-r--r--dom/performance/tests/worker_performance_observer.html32
-rw-r--r--dom/plugins/base/nsPluginHost.cpp78
-rw-r--r--dom/plugins/base/nsPluginsDirDarwin.cpp19
-rw-r--r--dom/plugins/ipc/PluginMessageUtils.h3
-rw-r--r--dom/plugins/ipc/PluginModuleChild.cpp4
-rwxr-xr-xdom/plugins/ipc/PluginModuleParent.cpp528
-rw-r--r--dom/plugins/ipc/PluginModuleParent.h44
-rw-r--r--dom/plugins/ipc/hangui/plugin-hang-ui.exe.manifest1
-rw-r--r--dom/plugins/test/mochitest/test_crash_notify_no_report.xul11
-rw-r--r--dom/plugins/test/mochitest/test_crash_submit.xul12
-rw-r--r--dom/plugins/test/mochitest/test_hang_submit.xul11
-rw-r--r--dom/plugins/test/unit/xpcshell.ini2
-rw-r--r--dom/promise/Promise.cpp30
-rw-r--r--dom/promise/Promise.h19
-rw-r--r--dom/push/moz.build2
-rw-r--r--dom/security/nsCSPContext.cpp38
-rw-r--r--dom/security/nsCSPParser.cpp54
-rw-r--r--dom/security/nsCSPParser.h23
-rw-r--r--dom/security/nsCSPUtils.cpp108
-rw-r--r--dom/security/nsCSPUtils.h57
-rw-r--r--dom/security/nsContentSecurityManager.cpp140
-rw-r--r--dom/security/nsContentSecurityManager.h2
-rw-r--r--dom/security/nsMixedContentBlocker.cpp7
-rw-r--r--dom/security/test/csp/file_child-src_worker-redirect.html7
-rw-r--r--dom/security/test/csp/file_frame_ancestors_ro.html1
-rw-r--r--dom/security/test/csp/file_frame_ancestors_ro.html^headers^1
-rw-r--r--dom/security/test/csp/file_frame_src.js14
-rw-r--r--dom/security/test/csp/file_frame_src_child_governs.html10
-rw-r--r--dom/security/test/csp/file_frame_src_frame_governs.html10
-rw-r--r--dom/security/test/csp/file_frame_src_inner.html5
-rw-r--r--dom/security/test/csp/file_ignore_xfo.html10
-rw-r--r--dom/security/test/csp/file_ignore_xfo.html^headers^3
-rw-r--r--dom/security/test/csp/file_image_nonce.html39
-rw-r--r--dom/security/test/csp/file_image_nonce.html^headers^2
-rw-r--r--dom/security/test/csp/file_punycode_host_src.js2
-rw-r--r--dom/security/test/csp/file_punycode_host_src.sjs45
-rw-r--r--dom/security/test/csp/file_ro_ignore_xfo.html10
-rw-r--r--dom/security/test/csp/file_ro_ignore_xfo.html^headers^3
-rw-r--r--dom/security/test/csp/file_spawn_service_worker.js1
-rw-r--r--dom/security/test/csp/file_spawn_shared_worker.js7
-rw-r--r--dom/security/test/csp/file_spawn_worker.js1
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_navigation.sjs79
-rw-r--r--dom/security/test/csp/file_websocket_explicit.html31
-rw-r--r--dom/security/test/csp/file_websocket_self.html31
-rw-r--r--dom/security/test/csp/file_websocket_self_wsh.py7
-rw-r--r--dom/security/test/csp/file_worker_src.js52
-rw-r--r--dom/security/test/csp/file_worker_src_child_governs.html9
-rw-r--r--dom/security/test/csp/file_worker_src_script_governs.html9
-rw-r--r--dom/security/test/csp/file_worker_src_worker_governs.html9
-rw-r--r--dom/security/test/csp/mochitest.ini36
-rw-r--r--dom/security/test/csp/test_child-src_worker.html6
-rw-r--r--dom/security/test/csp/test_frame_ancestors_ro.html69
-rw-r--r--dom/security/test/csp/test_frame_src.html84
-rw-r--r--dom/security/test/csp/test_ignore_xfo.html59
-rw-r--r--dom/security/test/csp/test_image_nonce.html60
-rw-r--r--dom/security/test/csp/test_punycode_host_src.html81
-rw-r--r--dom/security/test/csp/test_upgrade_insecure_navigation.html103
-rw-r--r--dom/security/test/csp/test_websocket_self.html61
-rw-r--r--dom/security/test/csp/test_worker_src.html94
-rw-r--r--dom/security/test/general/browser.ini14
-rw-r--r--dom/security/test/general/browser_test_data_download.js37
-rw-r--r--dom/security/test/general/browser_test_data_text_csv.js37
-rw-r--r--dom/security/test/general/browser_test_toplevel_data_navigations.js54
-rw-r--r--dom/security/test/general/browser_test_view_image_data_navigation.js30
-rw-r--r--dom/security/test/general/file_block_toplevel_data_navigation.html14
-rw-r--r--dom/security/test/general/file_block_toplevel_data_navigation2.html29
-rw-r--r--dom/security/test/general/file_block_toplevel_data_navigation3.html13
-rw-r--r--dom/security/test/general/file_block_toplevel_data_redirect.sjs14
-rw-r--r--dom/security/test/general/file_data_download.html14
-rw-r--r--dom/security/test/general/file_data_text_csv.html14
-rw-r--r--dom/security/test/general/file_toplevel_data_meta_redirect.html10
-rw-r--r--dom/security/test/general/file_toplevel_data_navigations.sjs14
-rw-r--r--dom/security/test/general/file_view_image_data_navigation.html12
-rw-r--r--dom/security/test/general/mochitest.ini12
-rw-r--r--dom/security/test/general/test_allow_opening_data_json.html39
-rw-r--r--dom/security/test/general/test_allow_opening_data_pdf.html41
-rw-r--r--dom/security/test/general/test_block_script_wrong_mime.html6
-rw-r--r--dom/security/test/general/test_block_toplevel_data_img_navigation.html53
-rw-r--r--dom/security/test/general/test_block_toplevel_data_navigation.html86
-rw-r--r--dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html1
-rw-r--r--dom/security/test/gtest/TestCSPParser.cpp6
-rw-r--r--dom/security/test/moz.build1
-rw-r--r--dom/svg/DOMSVGPathSegList.cpp21
-rw-r--r--dom/svg/SVGClipPathElement.cpp7
-rw-r--r--dom/svg/SVGClipPathElement.h4
-rw-r--r--dom/svg/SVGGradientElement.cpp9
-rw-r--r--dom/svg/SVGGradientElement.h7
-rw-r--r--dom/svg/SVGTextContentElement.h1
-rwxr-xr-x[-rw-r--r--]dom/tests/browser/browser.ini2
-rwxr-xr-xdom/tests/browser/browser_performanceAPI.js139
-rwxr-xr-xdom/tests/browser/file_workerPerformance.js65
-rw-r--r--dom/tests/mochitest/fetch/test_headers_common.js10
-rwxr-xr-x[-rw-r--r--]dom/tests/mochitest/general/mochitest.ini3
-rw-r--r--dom/tests/mochitest/general/test_domWindowUtils_scrollXY.html12
-rw-r--r--dom/tests/mochitest/general/test_interfaces.html6
-rwxr-xr-xdom/tests/mochitest/general/test_reduce_time_precision.html143
-rwxr-xr-xdom/tests/mochitest/general/worker_child.js28
-rwxr-xr-xdom/tests/mochitest/general/worker_grandchild.js10
-rw-r--r--dom/url/URL.cpp40
-rw-r--r--dom/url/URL.h6
-rw-r--r--dom/url/tests/test_url.html18
-rw-r--r--dom/webidl/CSPDictionaries.webidl1
-rw-r--r--dom/webidl/CanvasRenderingContext2D.webidl3
-rw-r--r--dom/webidl/Document.webidl9
-rw-r--r--dom/webidl/HTMLButtonElement.webidl3
-rw-r--r--dom/webidl/HTMLDocument.webidl4
-rw-r--r--dom/webidl/HTMLInputElement.webidl21
-rw-r--r--dom/webidl/HTMLMediaElement.webidl2
-rw-r--r--dom/webidl/HTMLMeterElement.webidl5
-rw-r--r--dom/webidl/HTMLOutputElement.webidl3
-rw-r--r--dom/webidl/HTMLProgressElement.webidl6
-rw-r--r--dom/webidl/HTMLSelectElement.webidl2
-rw-r--r--dom/webidl/HTMLTextAreaElement.webidl2
-rw-r--r--dom/webidl/Navigator.webidl2
-rw-r--r--dom/webidl/Performance.webidl3
-rw-r--r--dom/webidl/PerformanceNavigationTiming.webidl33
-rw-r--r--dom/webidl/PerformanceObserver.webidl1
-rw-r--r--dom/webidl/PerformanceResourceTiming.webidl8
-rw-r--r--dom/webidl/PerformanceTiming.webidl9
-rw-r--r--dom/webidl/PointerEvent.webidl4
-rw-r--r--dom/webidl/Response.webidl2
-rw-r--r--dom/webidl/SVGRadialGradientElement.webidl4
-rw-r--r--dom/webidl/Selection.webidl3
-rw-r--r--dom/webidl/URL.webidl5
-rw-r--r--dom/webidl/Window.webidl12
-rw-r--r--dom/webidl/moz.build15
-rw-r--r--dom/workers/RuntimeService.cpp4
-rw-r--r--dom/workers/ServiceWorkerEvents.cpp14
-rw-r--r--dom/workers/ServiceWorkerPrivate.cpp45
-rw-r--r--dom/workers/ServiceWorkerPrivate.h1
-rw-r--r--dom/workers/WorkerPrivate.cpp147
-rw-r--r--dom/workers/WorkerPrivate.h16
-rw-r--r--dom/workers/WorkerScope.cpp7
-rw-r--r--dom/workers/Workers.h8
-rw-r--r--dom/workers/test/serviceworkers/chrome.ini3
-rw-r--r--dom/workers/test/serviceworkers/test_devtools_serviceworker_interception.html168
-rw-r--r--dom/workers/test/serviceworkers/test_serviceworker_interfaces.js4
-rw-r--r--dom/workers/test/test_404.html1
-rw-r--r--dom/workers/test/test_bug1036484.html1
-rw-r--r--dom/workers/test/test_loadError.html8
-rw-r--r--dom/workers/test/test_worker_interfaces.js4
-rw-r--r--dom/xhr/XMLHttpRequestMainThread.cpp69
-rw-r--r--dom/xhr/XMLHttpRequestMainThread.h5
-rw-r--r--dom/xhr/XMLHttpRequestWorker.cpp11
-rw-r--r--dom/xhr/XMLHttpRequestWorker.h7
-rw-r--r--dom/xslt/xpath/txXPCOMExtensionFunction.cpp2
-rw-r--r--dom/xul/XULDocument.cpp14
-rw-r--r--dom/xul/XULDocument.h2
366 files changed, 7657 insertions, 4164 deletions
diff --git a/dom/asmjscache/AsmJSCache.cpp b/dom/asmjscache/AsmJSCache.cpp
index 4afcc6d6b..be54987a1 100644
--- a/dom/asmjscache/AsmJSCache.cpp
+++ b/dom/asmjscache/AsmJSCache.cpp
@@ -69,13 +69,19 @@ namespace asmjscache {
namespace {
+class ParentRunnable;
+
// Anything smaller should compile fast enough that caching will just add
// overhead.
-// static const size_t sMinCachedModuleLength = 10000;
+static const size_t sMinCachedModuleLength = 10000;
// The number of characters to hash into the Metadata::Entry::mFastHash.
static const unsigned sNumFastHashChars = 4096;
+// Track all live parent actors.
+typedef nsTArray<const ParentRunnable*> ParentActorArray;
+StaticAutoPtr<ParentActorArray> sLiveParentActors;
+
nsresult
WriteMetadataFile(nsIFile* aMetadataFile, const Metadata& aMetadata)
{
@@ -236,6 +242,94 @@ EvictEntries(nsIFile* aDirectory, const nsACString& aGroup,
}
}
+/*******************************************************************************
+ * Client
+ ******************************************************************************/
+
+class Client
+ : public quota::Client
+{
+ static Client* sInstance;
+
+ bool mShutdownRequested;
+
+public:
+ Client();
+
+ static bool
+ IsShuttingDownOnBackgroundThread()
+ {
+ AssertIsOnBackgroundThread();
+
+ if (sInstance) {
+ return sInstance->IsShuttingDown();
+ }
+
+ return QuotaManager::IsShuttingDown();
+ }
+
+ static bool
+ IsShuttingDownOnNonBackgroundThread()
+ {
+ MOZ_ASSERT(!IsOnBackgroundThread());
+
+ return QuotaManager::IsShuttingDown();
+ }
+
+ bool
+ IsShuttingDown() const
+ {
+ AssertIsOnBackgroundThread();
+
+ return mShutdownRequested;
+ }
+
+ NS_INLINE_DECL_REFCOUNTING(Client, override)
+
+ virtual Type
+ GetType() override;
+
+ virtual nsresult
+ InitOrigin(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ const AtomicBool& aCanceled,
+ UsageInfo* aUsageInfo) override;
+
+ virtual nsresult
+ GetUsageForOrigin(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ const AtomicBool& aCanceled,
+ UsageInfo* aUsageInfo) override;
+
+ virtual void
+ OnOriginClearCompleted(PersistenceType aPersistenceType,
+ const nsACString& aOrigin)
+ override;
+
+ virtual void
+ ReleaseIOThreadObjects() override;
+
+ virtual void
+ AbortOperations(const nsACString& aOrigin) override;
+
+ virtual void
+ AbortOperationsForProcess(ContentParentId aContentParentId) override;
+
+ virtual void
+ StartIdleMaintenance() override;
+
+ virtual void
+ StopIdleMaintenance() override;
+
+ virtual void
+ ShutdownWorkThreads() override;
+
+private:
+ ~Client();
+};
+
// FileDescriptorHolder owns a file descriptor and its memory mapping.
// FileDescriptorHolder is derived by two runnable classes (that is,
// (Parent|Child)Runnable.
@@ -897,6 +991,13 @@ ParentRunnable::FinishOnOwningThread()
FileDescriptorHolder::Finish();
mDirectoryLock = nullptr;
+
+ MOZ_ASSERT(sLiveParentActors);
+ sLiveParentActors->RemoveElement(this);
+
+ if (sLiveParentActors->IsEmpty()) {
+ sLiveParentActors = nullptr;
+ }
}
NS_IMETHODIMP
@@ -1140,6 +1241,10 @@ AllocEntryParent(OpenMode aOpenMode,
{
AssertIsOnBackgroundThread();
+ if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread())) {
+ return nullptr;
+ }
+
if (NS_WARN_IF(aPrincipalInfo.type() == PrincipalInfo::TNullPrincipalInfo)) {
MOZ_ASSERT(false);
return nullptr;
@@ -1148,6 +1253,12 @@ AllocEntryParent(OpenMode aOpenMode,
RefPtr<ParentRunnable> runnable =
new ParentRunnable(aPrincipalInfo, aOpenMode, aWriteParams);
+ if (!sLiveParentActors) {
+ sLiveParentActors = new ParentActorArray();
+ }
+
+ sLiveParentActors->AppendElement(runnable);
+
nsresult rv = NS_DispatchToMainThread(runnable);
NS_ENSURE_SUCCESS(rv, nullptr);
@@ -1520,7 +1631,6 @@ DeallocEntryChild(PAsmJSCacheEntryChild* aActor)
static_cast<ChildRunnable*>(aActor)->Release();
}
-/*
namespace {
JS::AsmJSCacheResult
@@ -1583,7 +1693,6 @@ OpenFile(nsIPrincipal* aPrincipal,
}
} // namespace
-*/
typedef uint32_t AsmJSCookieType;
static const uint32_t sAsmJSCookie = 0x600d600d;
@@ -1596,9 +1705,6 @@ OpenEntryForRead(nsIPrincipal* aPrincipal,
const uint8_t** aMemory,
intptr_t* aHandle)
{
- return false;
-
-/*
if (size_t(aLimit - aBegin) < sMinCachedModuleLength) {
return false;
}
@@ -1638,7 +1744,6 @@ OpenEntryForRead(nsIPrincipal* aPrincipal,
// failure) at which point the file will be closed.
childRunnable.Forget(reinterpret_cast<ChildRunnable**>(aHandle));
return true;
-*/
}
void
@@ -1663,9 +1768,6 @@ OpenEntryForWrite(nsIPrincipal* aPrincipal,
uint8_t** aMemory,
intptr_t* aHandle)
{
- return JS::AsmJSCache_ESR52;
-
-/*
if (size_t(aEnd - aBegin) < sMinCachedModuleLength) {
return JS::AsmJSCache_ModuleTooSmall;
}
@@ -1699,7 +1801,6 @@ OpenEntryForWrite(nsIPrincipal* aPrincipal,
// failure) at which point the file will be closed
childRunnable.Forget(reinterpret_cast<ChildRunnable**>(aHandle));
return JS::AsmJSCache_Success;
-*/
}
void
@@ -1722,128 +1823,163 @@ CloseEntryForWrite(size_t aSize,
}
}
-class Client : public quota::Client
+/*******************************************************************************
+ * Client
+ ******************************************************************************/
+
+Client* Client::sInstance = nullptr;
+
+Client::Client()
+ : mShutdownRequested(false)
{
- ~Client() {}
+ AssertIsOnBackgroundThread();
+ MOZ_ASSERT(!sInstance, "We expect this to be a singleton!");
-public:
- NS_IMETHOD_(MozExternalRefCountType)
- AddRef() override;
+ sInstance = this;
+}
- NS_IMETHOD_(MozExternalRefCountType)
- Release() override;
+Client::~Client()
+{
+ AssertIsOnBackgroundThread();
+ MOZ_ASSERT(sInstance == this, "We expect this to be a singleton!");
- virtual Type
- GetType() override
- {
- return ASMJS;
- }
+ sInstance = nullptr;
+}
- virtual nsresult
- InitOrigin(PersistenceType aPersistenceType,
- const nsACString& aGroup,
- const nsACString& aOrigin,
- const AtomicBool& aCanceled,
- UsageInfo* aUsageInfo) override
- {
- if (!aUsageInfo) {
- return NS_OK;
- }
- return GetUsageForOrigin(aPersistenceType,
- aGroup,
- aOrigin,
- aCanceled,
- aUsageInfo);
- }
+Client::Type
+Client::GetType()
+{
+ return ASMJS;
+}
- virtual nsresult
- GetUsageForOrigin(PersistenceType aPersistenceType,
- const nsACString& aGroup,
- const nsACString& aOrigin,
- const AtomicBool& aCanceled,
- UsageInfo* aUsageInfo) override
- {
- QuotaManager* qm = QuotaManager::Get();
- MOZ_ASSERT(qm, "We were being called by the QuotaManager");
+nsresult
+Client::InitOrigin(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ const AtomicBool& aCanceled,
+ UsageInfo* aUsageInfo)
+{
+ if (!aUsageInfo) {
+ return NS_OK;
+ }
+ return GetUsageForOrigin(aPersistenceType,
+ aGroup,
+ aOrigin,
+ aCanceled,
+ aUsageInfo);
+}
- nsCOMPtr<nsIFile> directory;
- nsresult rv = qm->GetDirectoryForOrigin(aPersistenceType, aOrigin,
- getter_AddRefs(directory));
- NS_ENSURE_SUCCESS(rv, rv);
- MOZ_ASSERT(directory, "We're here because the origin directory exists");
+nsresult
+Client::GetUsageForOrigin(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ const AtomicBool& aCanceled,
+ UsageInfo* aUsageInfo)
+{
+ QuotaManager* qm = QuotaManager::Get();
+ MOZ_ASSERT(qm, "We were being called by the QuotaManager");
- rv = directory->Append(NS_LITERAL_STRING(ASMJSCACHE_DIRECTORY_NAME));
- NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIFile> directory;
+ nsresult rv = qm->GetDirectoryForOrigin(aPersistenceType, aOrigin,
+ getter_AddRefs(directory));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
- DebugOnly<bool> exists;
- MOZ_ASSERT(NS_SUCCEEDED(directory->Exists(&exists)) && exists);
+ MOZ_ASSERT(directory, "We're here because the origin directory exists");
- nsCOMPtr<nsISimpleEnumerator> entries;
- rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = directory->Append(NS_LITERAL_STRING(ASMJSCACHE_DIRECTORY_NAME));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
- bool hasMore;
- while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
- hasMore && !aCanceled) {
- nsCOMPtr<nsISupports> entry;
- rv = entries->GetNext(getter_AddRefs(entry));
- NS_ENSURE_SUCCESS(rv, rv);
+ DebugOnly<bool> exists;
+ MOZ_ASSERT(NS_SUCCEEDED(directory->Exists(&exists)) && exists);
- nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
- NS_ENSURE_TRUE(file, NS_NOINTERFACE);
+ nsCOMPtr<nsISimpleEnumerator> entries;
+ rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
- int64_t fileSize;
- rv = file->GetFileSize(&fileSize);
- NS_ENSURE_SUCCESS(rv, rv);
+ bool hasMore;
+ while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
+ hasMore && !aCanceled) {
+ nsCOMPtr<nsISupports> entry;
+ rv = entries->GetNext(getter_AddRefs(entry));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
- MOZ_ASSERT(fileSize >= 0, "Negative size?!");
+ nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
+ if (NS_WARN_IF(!file)) {
+ return NS_NOINTERFACE;
+ }
- // Since the client is not explicitly storing files, append to database
- // usage which represents implicit storage allocation.
- aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
+ int64_t fileSize;
+ rv = file->GetFileSize(&fileSize);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
}
- NS_ENSURE_SUCCESS(rv, rv);
- return NS_OK;
+ MOZ_ASSERT(fileSize >= 0, "Negative size?!");
+
+ // Since the client is not explicitly storing files, append to database
+ // usage which represents implicit storage allocation.
+ aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
}
- virtual void
- OnOriginClearCompleted(PersistenceType aPersistenceType,
- const nsACString& aOrigin)
- override
- { }
+ return NS_OK;
+}
- virtual void
- ReleaseIOThreadObjects() override
- { }
+void
+Client::OnOriginClearCompleted(PersistenceType aPersistenceType,
+ const nsACString& aOrigin)
+{
+}
- virtual void
- AbortOperations(const nsACString& aOrigin) override
- { }
+void
+Client::ReleaseIOThreadObjects()
+{
+}
- virtual void
- AbortOperationsForProcess(ContentParentId aContentParentId) override
- { }
+void
+Client::AbortOperations(const nsACString& aOrigin)
+{
+}
- virtual void
- StartIdleMaintenance() override
- { }
+void
+Client::AbortOperationsForProcess(ContentParentId aContentParentId)
+{
+}
- virtual void
- StopIdleMaintenance() override
- { }
+void
+Client::StartIdleMaintenance()
+{
+}
- virtual void
- ShutdownWorkThreads() override
- { }
+void
+Client::StopIdleMaintenance()
+{
+}
-private:
- nsAutoRefCnt mRefCnt;
- NS_DECL_OWNINGTHREAD
-};
+void
+Client::ShutdownWorkThreads()
+{
+ AssertIsOnBackgroundThread();
+
+ if (sLiveParentActors) {
+ nsIThread* currentThread = NS_GetCurrentThread();
+ MOZ_ASSERT(currentThread);
-NS_IMPL_ADDREF(asmjscache::Client)
-NS_IMPL_RELEASE(asmjscache::Client)
+ do {
+ MOZ_ALWAYS_TRUE(NS_ProcessNextEvent(currentThread));
+ } while (!sLiveParentActors);
+ }
+}
quota::Client*
CreateClient()
diff --git a/dom/asmjscache/test/test_cachingBasic.html b/dom/asmjscache/test/test_cachingBasic.html
index e84fdba8b..f491fe9fa 100644
--- a/dom/asmjscache/test/test_cachingBasic.html
+++ b/dom/asmjscache/test/test_cachingBasic.html
@@ -44,7 +44,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=929236
evalAsync(code);
break;
case 1:
- ok(!jsFuns.isAsmJSModuleLoadedFromCache(module), 'module not loaded from cache');
+ ok(jsFuns.isAsmJSModuleLoadedFromCache(module), 'module loaded from cache');
SimpleTest.finish();
break;
default:
diff --git a/dom/asmjscache/test/test_cachingMulti.html b/dom/asmjscache/test/test_cachingMulti.html
index ca092fda0..ceaf75812 100644
--- a/dom/asmjscache/test/test_cachingMulti.html
+++ b/dom/asmjscache/test/test_cachingMulti.html
@@ -36,7 +36,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=944821
code2 += "return g" + i + ";\n";
code2 += "}\n";
code2 += "ok(jsFuns.isAsmJSModule(f), 'f is an asm.js module')\n";
- code2 += "if (assertCacheHit) ok(!jsFuns.isAsmJSModuleLoadedFromCache(f), 'cache disabled');\n";
+ code2 += "if (assertCacheHit) ok(jsFuns.isAsmJSModuleLoadedFromCache(f), 'cache hit');\n";
code2 += "var gX = f();\n";
code2 += "ok(jsFuns.isAsmJSFunction(gX), 'gX is an asm.js function')\n";
code2 += "ok(gX() === " + i + ", 'gX returns the correct result')\n";
diff --git a/dom/asmjscache/test/test_workers.html b/dom/asmjscache/test/test_workers.html
index 992ed785b..6704459f6 100644
--- a/dom/asmjscache/test/test_workers.html
+++ b/dom/asmjscache/test/test_workers.html
@@ -31,7 +31,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=941830
var workerBlob = new Blob([workerCode], {type:"application/javascript"});
var mainCode = asmjsCode;
- mainCode += "ok(!jsFuns.isAsmJSModuleLoadedFromCache(f), 'f is not a cache hit')\n";
+ mainCode += "ok(jsFuns.isAsmJSModuleLoadedFromCache(f), 'f is a cache hit')\n";
mainCode += "var g42 = f();\n";
mainCode += "ok(jsFuns.isAsmJSFunction(g42), 'g42 is an asm.js function');\n";
mainCode += "ok(g42() === 42, 'g42 returns the correct result');\n";
diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp
index 886acc670..092755590 100644
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -165,10 +165,9 @@ nsIContent::DoGetID() const
}
const nsAttrValue*
-nsIContent::DoGetClasses() const
+Element::DoGetClasses() const
{
MOZ_ASSERT(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call");
- MOZ_ASSERT(IsElement(), "Only elements can have classes");
if (IsSVGElement()) {
const nsAttrValue* animClass =
@@ -178,12 +177,18 @@ nsIContent::DoGetClasses() const
}
}
- return AsElement()->GetParsedAttr(nsGkAtoms::_class);
+ return GetParsedAttr(nsGkAtoms::_class);
}
NS_IMETHODIMP
Element::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
+ if (aIID.Equals(NS_GET_IID(Element))) {
+ NS_ADDREF_THIS();
+ *aInstancePtr = this;
+ return NS_OK;
+ }
+
NS_ASSERTION(aInstancePtr,
"QueryInterface requires a non-NULL destination!");
nsresult rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr);
@@ -1839,6 +1844,24 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
SetParentIsContent(false);
}
+#ifdef DEBUG
+ // If we can get access to the PresContext, then we sanity-check that
+ // we're not leaving behind a pointer to ourselves as the PresContext's
+ // cached provider of the viewport's scrollbar styles.
+ if (document) {
+ nsIPresShell* presShell = document->GetShell();
+ if (presShell) {
+ nsPresContext* presContext = presShell->GetPresContext();
+ if (presContext) {
+ MOZ_ASSERT(this !=
+ presContext->GetViewportScrollbarStylesOverrideNode(),
+ "Leaving behind a raw pointer to this node (as having "
+ "propagated scrollbar styles) - that's dangerous...");
+ }
+ }
+ }
+#endif
+
// Ensure that CSS transitions don't continue on an element at a
// different place in the tree (even if reinserted before next
// animation refresh).
diff --git a/dom/base/Element.h b/dom/base/Element.h
index 5d878df60..cf1d197e2 100644
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -544,6 +544,18 @@ public:
virtual uint32_t GetAttrCount() const override;
virtual bool IsNodeOfType(uint32_t aFlags) const override;
+ /**
+ * Get the class list of this element (this corresponds to the value of the
+ * class attribute). This may be null if there are no classes, but that's not
+ * guaranteed (e.g. we could have class="").
+ */
+ const nsAttrValue* GetClasses() const {
+ if (HasFlag(NODE_MAY_HAVE_CLASS)) {
+ return DoGetClasses();
+ }
+ return nullptr;
+ }
+
#ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override
{
@@ -1372,6 +1384,12 @@ protected:
private:
/**
+ * Hook for implementing GetClasses. This is guaranteed to only be
+ * called if the NODE_MAY_HAVE_CLASS flag is set.
+ */
+ const nsAttrValue* DoGetClasses() const;
+
+ /**
* Get this element's client area rect in app units.
* @return the frame's client area
*/
diff --git a/dom/base/File.cpp b/dom/base/File.cpp
index 46b37b976..8602a3064 100644..100755
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -29,6 +29,7 @@
#include "nsStringStream.h"
#include "nsJSUtils.h"
#include "nsPrintfCString.h"
+#include "mozilla/TimerClamping.h"
#include "mozilla/SHA1.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/Preferences.h"
@@ -727,7 +728,7 @@ BlobImplBase::GetLastModified(ErrorResult& aRv)
mLastModificationDate = PR_Now();
}
- return mLastModificationDate / PR_USEC_PER_MSEC;
+ return TimerClamping::ReduceUsTimeValue(mLastModificationDate) / PR_USEC_PER_MSEC;
}
void
diff --git a/dom/base/FileReader.cpp b/dom/base/FileReader.cpp
index 003edc61f..63a0ef2ee 100644
--- a/dom/base/FileReader.cpp
+++ b/dom/base/FileReader.cpp
@@ -452,8 +452,8 @@ FileReader::GetAsText(Blob *aBlob,
}
}
- nsDependentCSubstring data(aFileData, aDataLen);
- return nsContentUtils::ConvertStringFromEncoding(encoding, data, aResult);
+ return nsContentUtils::ConvertStringFromEncoding(
+ encoding, aFileData, aDataLen, aResult);
}
nsresult
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
index 293177ce7..b22a0d4ff 100644
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -574,6 +574,9 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb,
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList");
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList));
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mLabelsList");
+ cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mLabelsList));
+
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList");
cb.NoteXPCOMChild(mClassList.get());
@@ -602,6 +605,7 @@ FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL)
mShadowRoot = nullptr;
mContainingShadow = nullptr;
mChildrenList = nullptr;
+ mLabelsList = nullptr;
mCustomElementData = nullptr;
mClassList = nullptr;
}
@@ -1827,7 +1831,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement)
}
nsAutoString classes;
- const nsAttrValue* classAttrValue = tmp->GetClasses();
+ const nsAttrValue* classAttrValue = tmp->IsElement() ?
+ tmp->AsElement()->GetClasses() : nullptr;
if (classAttrValue) {
classes.AppendLiteral(" class='");
nsAutoString classString;
@@ -1932,7 +1937,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN(FragmentOrElement)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(FragmentOrElement)
- NS_INTERFACE_MAP_ENTRY(Element)
NS_INTERFACE_MAP_ENTRY(nsIContent)
NS_INTERFACE_MAP_ENTRY(nsINode)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h
index 3cb5575fe..1cd8033bb 100644
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -24,6 +24,7 @@
class ContentUnbinder;
class nsContentList;
+class nsLabelsNodeList;
class nsDOMAttributeMap;
class nsDOMTokenList;
class nsIControllers;
@@ -313,6 +314,11 @@ public:
*/
RefPtr<nsDOMTokenList> mClassList;
+ /*
+ * An object implementing the .labels property for this element.
+ */
+ RefPtr<nsLabelsNodeList> mLabelsList;
+
/**
* ShadowRoot bound to the element.
*/
diff --git a/dom/base/IdleRequest.cpp b/dom/base/IdleRequest.cpp
index 26190f98b..fb3983d37 100644
--- a/dom/base/IdleRequest.cpp
+++ b/dom/base/IdleRequest.cpp
@@ -9,7 +9,6 @@
#include "mozilla/Function.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/IdleDeadline.h"
-#include "mozilla/dom/Performance.h"
#include "mozilla/dom/PerformanceTiming.h"
#include "mozilla/dom/WindowBinding.h"
#include "nsComponentManagerUtils.h"
@@ -20,138 +19,56 @@
namespace mozilla {
namespace dom {
-IdleRequest::IdleRequest(JSContext* aCx, nsPIDOMWindowInner* aWindow,
- IdleRequestCallback& aCallback, uint32_t aHandle)
- : mWindow(aWindow)
- , mCallback(&aCallback)
+IdleRequest::IdleRequest(IdleRequestCallback* aCallback, uint32_t aHandle)
+ : mCallback(aCallback)
, mHandle(aHandle)
, mTimeoutHandle(Nothing())
{
- MOZ_ASSERT(aWindow);
-
- // Get the calling location.
- nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn);
+ MOZ_DIAGNOSTIC_ASSERT(mCallback);
}
IdleRequest::~IdleRequest()
{
}
-NS_IMPL_CYCLE_COLLECTION_CLASS(IdleRequest)
+NS_IMPL_CYCLE_COLLECTION(IdleRequest, mCallback)
NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequest)
NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequest)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IdleRequest)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IdleRequest)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequest)
- NS_INTERFACE_MAP_ENTRY(nsIRunnable)
- NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable)
- NS_INTERFACE_MAP_ENTRY(nsIIncrementalRunnable)
- NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler)
- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimeoutHandler)
NS_INTERFACE_MAP_END
-nsresult
-IdleRequest::SetTimeout(uint32_t aTimeout)
-{
- int32_t handle;
- nsresult rv = nsGlobalWindow::Cast(mWindow)->SetTimeoutOrInterval(
- this, aTimeout, false, Timeout::Reason::eIdleCallbackTimeout, &handle);
- mTimeoutHandle = Some(handle);
-
- return rv;
-}
-
-nsresult
-IdleRequest::Run()
-{
- if (mCallback) {
- RunIdleRequestCallback(false);
- }
-
- return NS_OK;
-}
-
-nsresult
-IdleRequest::Cancel()
+void
+IdleRequest::SetTimeoutHandle(int32_t aHandle)
{
- mCallback = nullptr;
- CancelTimeout();
- if (isInList()) {
- remove();
- }
- Release();
-
- return NS_OK;
+ mTimeoutHandle = Some(aHandle);
}
-void
-IdleRequest::SetDeadline(TimeStamp aDeadline)
+uint32_t
+IdleRequest::GetTimeoutHandle() const
{
- mozilla::dom::Performance* perf = mWindow->GetPerformance();
- mDeadline =
- perf ? perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline) : 0.0;
+ MOZ_DIAGNOSTIC_ASSERT(mTimeoutHandle.isSome());
+ return mTimeoutHandle.value();
}
nsresult
-IdleRequest::RunIdleRequestCallback(bool aDidTimeout)
+IdleRequest::IdleRun(nsPIDOMWindowInner* aWindow,
+ DOMHighResTimeStamp aDeadline,
+ bool aDidTimeout)
{
MOZ_ASSERT(NS_IsMainThread());
+ MOZ_DIAGNOSTIC_ASSERT(mCallback);
- if (!aDidTimeout) {
- CancelTimeout();
- }
-
- remove();
ErrorResult error;
RefPtr<IdleDeadline> deadline =
- new IdleDeadline(mWindow, aDidTimeout, mDeadline);
+ new IdleDeadline(aWindow, aDidTimeout, aDeadline);
mCallback->Call(*deadline, error, "requestIdleCallback handler");
- mCallback = nullptr;
- Release();
+ mCallback = nullptr;
+ error.SuppressException();
return error.StealNSResult();
}
-void
-IdleRequest::CancelTimeout()
-{
- if (mTimeoutHandle.isSome()) {
- nsGlobalWindow::Cast(mWindow)->ClearTimeoutOrInterval(
- mTimeoutHandle.value(), Timeout::Reason::eIdleCallbackTimeout);
- }
-}
-
-nsresult
-IdleRequest::Call()
-{
- SetDeadline(TimeStamp::Now());
- return RunIdleRequestCallback(true);
-}
-
-void
-IdleRequest::GetLocation(const char** aFileName, uint32_t* aLineNo,
- uint32_t* aColumn)
-{
- *aFileName = mFileName.get();
- *aLineNo = mLineNo;
- *aColumn = mColumn;
-}
-
-void
-IdleRequest::MarkForCC()
-{
- mCallback->MarkForCC();
-}
-
} // namespace dom
} // namespace mozilla
diff --git a/dom/base/IdleRequest.h b/dom/base/IdleRequest.h
index cb234430a..acf56f852 100644
--- a/dom/base/IdleRequest.h
+++ b/dom/base/IdleRequest.h
@@ -12,7 +12,6 @@
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDOMNavigationTiming.h"
-#include "nsITimeoutHandler.h"
class nsPIDOMWindowInner;
@@ -21,28 +20,19 @@ namespace dom {
class IdleRequestCallback;
-class IdleRequest final : public nsITimeoutHandler
- , public nsIRunnable
- , public nsICancelableRunnable
- , public nsIIncrementalRunnable
- , public LinkedListElement<IdleRequest>
+class IdleRequest final : public nsISupports,
+ public LinkedListElement<IdleRequest>
{
public:
- IdleRequest(JSContext* aCx, nsPIDOMWindowInner* aWindow,
- IdleRequestCallback& aCallback, uint32_t aHandle);
+ IdleRequest(IdleRequestCallback* aCallback, uint32_t aHandle);
- virtual nsresult Call() override;
- virtual void GetLocation(const char** aFileName, uint32_t* aLineNo,
- uint32_t* aColumn) override;
- virtual void MarkForCC() override;
+ nsresult IdleRun(nsPIDOMWindowInner* aWindow,
+ DOMHighResTimeStamp aDeadline,
+ bool aDidTimeout);
- nsresult SetTimeout(uint32_t aTimout);
- nsresult RunIdleRequestCallback(bool aDidTimeout);
- void CancelTimeout();
-
- NS_DECL_NSIRUNNABLE;
- virtual nsresult Cancel() override;
- virtual void SetDeadline(mozilla::TimeStamp aDeadline) override;
+ void SetTimeoutHandle(int32_t aHandle);
+ bool HasTimeout() const { return mTimeoutHandle.isSome(); }
+ uint32_t GetTimeoutHandle() const;
uint32_t Handle() const
{
@@ -50,22 +40,14 @@ public:
}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequest, nsITimeoutHandler)
+ NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequest)
private:
~IdleRequest();
- // filename, line number and JS language version string of the
- // caller of setTimeout()
- nsCString mFileName;
- uint32_t mLineNo;
- uint32_t mColumn;
-
- nsCOMPtr<nsPIDOMWindowInner> mWindow;
RefPtr<IdleRequestCallback> mCallback;
- uint32_t mHandle;
+ const uint32_t mHandle;
mozilla::Maybe<int32_t> mTimeoutHandle;
- DOMHighResTimeStamp mDeadline;
};
} // namespace dom
diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp
index e3b614931..b6b95aaa6 100644
--- a/dom/base/Location.cpp
+++ b/dom/base/Location.cpp
@@ -577,19 +577,17 @@ Location::GetPathname(nsAString& aPathname)
aPathname.Truncate();
nsCOMPtr<nsIURI> uri;
- nsresult result = NS_OK;
+ nsresult result = GetURI(getter_AddRefs(uri));
+ if (NS_FAILED(result) || !uri) {
+ return result;
+ }
- result = GetURI(getter_AddRefs(uri));
+ nsAutoCString file;
- nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(uri));
- if (url) {
- nsAutoCString file;
+ result = uri->GetFilePath(file);
- result = url->GetFilePath(file);
-
- if (NS_SUCCEEDED(result)) {
- AppendUTF8toUTF16(file, aPathname);
- }
+ if (NS_SUCCEEDED(result)) {
+ AppendUTF8toUTF16(file, aPathname);
}
return result;
@@ -604,8 +602,7 @@ Location::SetPathname(const nsAString& aPathname)
return rv;
}
- nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(uri));
- if (url && NS_SUCCEEDED(url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)))) {
+ if (NS_SUCCEEDED(uri->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)))) {
return SetURI(uri);
}
diff --git a/dom/base/MultipartBlobImpl.cpp b/dom/base/MultipartBlobImpl.cpp
index ba26d07f9..03bb62add 100644..100755
--- a/dom/base/MultipartBlobImpl.cpp
+++ b/dom/base/MultipartBlobImpl.cpp
@@ -17,6 +17,7 @@
#include "nsContentUtils.h"
#include "nsIScriptError.h"
#include "nsIXPConnect.h"
+#include "mozilla/TimerClamping.h"
#include <algorithm>
using namespace mozilla;
@@ -270,8 +271,7 @@ MultipartBlobImpl::SetLengthAndModifiedDate(ErrorResult& aRv)
// var x = new Date(); var f = new File(...);
// x.getTime() < f.dateModified.getTime()
// could fail.
- mLastModificationDate =
- lastModifiedSet ? lastModified * PR_USEC_PER_MSEC : JS_Now();
+ mLastModificationDate = TimerClamping::ReduceUsTimeValue(lastModifiedSet ? lastModified * PR_USEC_PER_MSEC : JS_Now());
}
}
diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp
index 290af152b..5c315517c 100644
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -97,8 +97,10 @@
#endif
#include "mozilla/dom/ContentChild.h"
+#ifdef MOZ_EME
#include "mozilla/EMEUtils.h"
#include "mozilla/DetailedPromise.h"
+#endif
namespace mozilla {
namespace dom {
@@ -214,7 +216,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
+#ifdef MOZ_EME
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeySystemAccessManager)
+#endif
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresentation)
#ifdef MOZ_GAMEPAD
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepadServiceTest)
@@ -288,10 +292,12 @@ Navigator::Invalidate()
mServiceWorkerContainer = nullptr;
+#ifdef MOZ_EME
if (mMediaKeySystemAccessManager) {
mMediaKeySystemAccessManager->Shutdown();
mMediaKeySystemAccessManager = nullptr;
}
+#endif
#ifdef MOZ_GAMEPAD
if (mGamepadServiceTest) {
@@ -1854,16 +1860,6 @@ Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow, nsIURI* aURI,
{
MOZ_ASSERT(NS_IsMainThread());
- if (!aIsCallerChrome) {
- const nsAdoptingString& override =
- mozilla::Preferences::GetString("general.useragent.override");
-
- if (override) {
- aUserAgent = override;
- return NS_OK;
- }
- }
-
nsresult rv;
nsCOMPtr<nsIHttpProtocolHandler>
service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
@@ -1894,6 +1890,7 @@ Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow, nsIURI* aURI,
return siteSpecificUA->GetUserAgentForURIAndWindow(aURI, aWindow, aUserAgent);
}
+#ifdef MOZ_EME
static nsCString
ToCString(const nsString& aString)
{
@@ -2019,6 +2016,7 @@ Navigator::RequestMediaKeySystemAccess(const nsAString& aKeySystem,
mMediaKeySystemAccessManager->Request(promise, aKeySystem, aConfigs);
return promise.forget();
}
+#endif
Presentation*
Navigator::GetPresentation(ErrorResult& aRv)
diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h
index 4b4ae6759..d47a80bc1 100644
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -18,7 +18,9 @@
#include "nsString.h"
#include "nsTArray.h"
#include "nsWeakPtr.h"
+#ifdef MOZ_EME
#include "mozilla/dom/MediaKeySystemAccessManager.h"
+#endif
class nsPluginArray;
class nsMimeTypeArray;
@@ -258,12 +260,14 @@ public:
// any, else null.
static already_AddRefed<nsPIDOMWindowInner> GetWindowFromGlobal(JSObject* aGlobal);
+#ifdef MOZ_EME
already_AddRefed<Promise>
RequestMediaKeySystemAccess(const nsAString& aKeySystem,
const Sequence<MediaKeySystemConfiguration>& aConfig,
ErrorResult& aRv);
private:
RefPtr<MediaKeySystemAccessManager> mMediaKeySystemAccessManager;
+#endif
public:
void NotifyVRDisplaysUpdated();
diff --git a/dom/base/Timeout.h b/dom/base/Timeout.h
index e929f3dd1..42e2f57f5 100644
--- a/dom/base/Timeout.h
+++ b/dom/base/Timeout.h
@@ -41,7 +41,11 @@ public:
// default main thread being used.
nsresult InitTimer(nsIEventTarget* aTarget, uint32_t aDelay);
- enum class Reason { eTimeoutOrInterval, eIdleCallbackTimeout };
+ enum class Reason
+ {
+ eTimeoutOrInterval,
+ eIdleCallbackTimeout,
+ };
#ifdef DEBUG
bool HasRefCntOne() const;
@@ -62,6 +66,8 @@ public:
// True if this is a repeating/interval timer
bool mIsInterval;
+ // Used to allow several reasons for setting a timeout, where each
+ // 'Reason' value is using a possibly overlapping set of id:s.
Reason mReason;
// Returned as value of setTimeout()
diff --git a/dom/base/TimeoutHandler.cpp b/dom/base/TimeoutHandler.cpp
new file mode 100644
index 000000000..78c3f16dd
--- /dev/null
+++ b/dom/base/TimeoutHandler.cpp
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TimeoutHandler.h"
+
+namespace mozilla {
+namespace dom {
+
+TimeoutHandler::TimeoutHandler(JSContext* aCx)
+ : TimeoutHandler()
+{
+ nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn);
+}
+
+nsresult
+TimeoutHandler::Call()
+{
+ return NS_OK;
+}
+
+void
+TimeoutHandler::GetLocation(const char** aFileName, uint32_t* aLineNo,
+ uint32_t* aColumn)
+{
+ *aFileName = mFileName.get();
+ *aLineNo = mLineNo;
+ *aColumn = mColumn;
+}
+
+NS_IMPL_CYCLE_COLLECTION_0(TimeoutHandler)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TimeoutHandler)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TimeoutHandler)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TimeoutHandler)
+ NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler)
+NS_INTERFACE_MAP_END
+
+} // namespace dom
+} // namespace mozilla
diff --git a/dom/base/TimeoutHandler.h b/dom/base/TimeoutHandler.h
new file mode 100644
index 000000000..cb0a0ce94
--- /dev/null
+++ b/dom/base/TimeoutHandler.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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_timeout_handler_h
+#define mozilla_dom_timeout_handler_h
+
+#include "nsCOMPtr.h"
+#include "nsISupports.h"
+#include "nsITimeoutHandler.h"
+
+namespace mozilla {
+namespace dom {
+
+/**
+ * Utility class for implementing nsITimeoutHandlers, designed to be subclassed.
+ */
+class TimeoutHandler : public nsITimeoutHandler
+{
+public:
+ // TimeoutHandler doesn't actually contain cycles, but subclasses
+ // probably will.
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_CLASS(TimeoutHandler)
+
+ virtual nsresult Call() override;
+ virtual void GetLocation(const char** aFileName, uint32_t* aLineNo,
+ uint32_t* aColumn) override;
+ virtual void MarkForCC() override {}
+protected:
+ TimeoutHandler() : mFileName(""), mLineNo(0), mColumn(0) {}
+ explicit TimeoutHandler(JSContext *aCx);
+
+ virtual ~TimeoutHandler() {}
+private:
+ TimeoutHandler(const TimeoutHandler&) = delete;
+ TimeoutHandler& operator=(const TimeoutHandler&) = delete;
+ TimeoutHandler& operator=(const TimeoutHandler&&) = delete;
+
+ nsCString mFileName;
+ uint32_t mLineNo;
+ uint32_t mColumn;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_timeout_handler_h
diff --git a/dom/base/TimerClamping.cpp b/dom/base/TimerClamping.cpp
new file mode 100755
index 000000000..70639686b
--- /dev/null
+++ b/dom/base/TimerClamping.cpp
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TimerClamping.h"
+
+namespace mozilla {
+
+/* static */
+double
+TimerClamping::ReduceSTimeValue(double aTime)
+{
+ static const double maxResolutionS = .002;
+ return floor(aTime / maxResolutionS) * maxResolutionS;
+}
+
+/* static */
+double
+TimerClamping::ReduceMsTimeValue(double aTime)
+{
+ static const double maxResolutionMs = 2;
+ return floor(aTime / maxResolutionMs) * maxResolutionMs;
+}
+
+/* static */
+double
+TimerClamping::ReduceUsTimeValue(double aTime)
+{
+ static const double maxResolutionUs = 2000;
+ return floor(aTime / maxResolutionUs) * maxResolutionUs;
+}
+
+} \ No newline at end of file
diff --git a/dom/base/TimerClamping.h b/dom/base/TimerClamping.h
new file mode 100755
index 000000000..2ffd6add5
--- /dev/null
+++ b/dom/base/TimerClamping.h
@@ -0,0 +1,22 @@
+/* -*- 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 TimerClamping_h___
+#define TimerClamping_h___
+
+namespace mozilla {
+
+class TimerClamping
+{
+public:
+ static double ReduceSTimeValue(double aTime);
+ static double ReduceMsTimeValue(double aTime);
+ static double ReduceUsTimeValue(double aTime);
+};
+
+}
+
+#endif /* TimerClamping_h___ */ \ No newline at end of file
diff --git a/dom/base/moz.build b/dom/base/moz.build
index d237acb03..76c765b1c 100644..100755
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -143,6 +143,7 @@ EXPORTS.mozilla += [
'CORSMode.h',
'FeedWriterEnabled.h',
'TextInputProcessor.h',
+ 'TimerClamping.h',
'UseCounter.h',
]
@@ -216,6 +217,7 @@ EXPORTS.mozilla.dom += [
'TabGroup.h',
'Text.h',
'Timeout.h',
+ 'TimeoutHandler.h',
'TreeWalker.h',
'WebKitCSSMatrix.h',
'WebSocket.h',
@@ -363,6 +365,8 @@ UNIFIED_SOURCES += [
'TextInputProcessor.cpp',
'ThirdPartyUtil.cpp',
'Timeout.cpp',
+ 'TimeoutHandler.cpp',
+ 'TimerClamping.cpp',
'TreeWalker.cpp',
'WebKitCSSMatrix.cpp',
'WebSocket.cpp',
@@ -411,7 +415,7 @@ EXTRA_COMPONENTS += [
]
# Firefox for Android provides an alternate version of this component
-if CONFIG['MOZ_BUILD_APP'] != 'mobile/android':
+if not CONFIG['MOZ_FENNEC']:
EXTRA_COMPONENTS += [
'SiteSpecificUserAgent.js',
'SiteSpecificUserAgent.manifest',
@@ -472,7 +476,7 @@ include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
-if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']:
+if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_FENNEC'] or CONFIG['MOZ_XULRUNNER']:
DEFINES['HAVE_SIDEBAR'] = True
if CONFIG['MOZ_X11']:
diff --git a/dom/base/nsContentList.cpp b/dom/base/nsContentList.cpp
index 09e949009..43e65777d 100644
--- a/dom/base/nsContentList.cpp
+++ b/dom/base/nsContentList.cpp
@@ -254,19 +254,6 @@ const nsCacheableFuncStringContentList::ContentListType
nsCacheableFuncStringHTMLCollection::sType = nsCacheableFuncStringContentList::eHTMLCollection;
#endif
-JSObject*
-nsCacheableFuncStringNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
-{
- return NodeListBinding::Wrap(cx, this, aGivenProto);
-}
-
-
-JSObject*
-nsCacheableFuncStringHTMLCollection::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
-{
- return HTMLCollectionBinding::Wrap(cx, this, aGivenProto);
-}
-
// Hashtable for storing nsCacheableFuncStringContentList
static PLDHashTable* gFuncStringContentListHashTable;
@@ -379,6 +366,7 @@ NS_GetFuncStringHTMLCollection(nsINode* aRootNode,
aString);
}
+//-----------------------------------------------------
// nsContentList implementation
nsContentList::nsContentList(nsINode* aRootNode,
@@ -660,7 +648,7 @@ nsContentList::AttributeChanged(nsIDocument *aDocument, Element* aElement,
const nsAttrValue* aOldValue)
{
NS_PRECONDITION(aElement, "Must have a content node to work with");
-
+
if (!mFunc || !mFuncMayDependOnAttr || mState == LIST_DIRTY ||
!MayContainRelevantNodes(aElement->GetParentNode()) ||
!nsContentUtils::IsInSameAnonymousTree(mRootNode, aElement)) {
@@ -806,7 +794,7 @@ nsContentList::ContentInserted(nsIDocument *aDocument,
ASSERT_IN_SYNC;
}
-
+
void
nsContentList::ContentRemoved(nsIDocument *aDocument,
nsIContent* aContainer,
@@ -1075,3 +1063,128 @@ nsContentList::AssertInSync()
NS_ASSERTION(cnt == mElements.Length(), "Too few elements");
}
#endif
+
+//-----------------------------------------------------
+// nsCacheableFuncStringNodeList
+
+JSObject*
+nsCacheableFuncStringNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
+{
+ return NodeListBinding::Wrap(cx, this, aGivenProto);
+}
+
+//-----------------------------------------------------
+// nsCacheableFuncStringHTMLCollection
+
+JSObject*
+nsCacheableFuncStringHTMLCollection::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
+{
+ return HTMLCollectionBinding::Wrap(cx, this, aGivenProto);
+}
+
+//-----------------------------------------------------
+// nsLabelsNodeList
+
+JSObject*
+nsLabelsNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
+{
+ return NodeListBinding::Wrap(cx, this, aGivenProto);
+}
+
+void
+nsLabelsNodeList::AttributeChanged(nsIDocument* aDocument, Element* aElement,
+ int32_t aNameSpaceID, nsIAtom* aAttribute,
+ int32_t aModType,
+ const nsAttrValue* aOldValue)
+{
+ MOZ_ASSERT(aElement, "Must have a content node to work with");
+ if (mState == LIST_DIRTY ||
+ !nsContentUtils::IsInSameAnonymousTree(mRootNode, aElement)) {
+ return;
+ }
+
+ // We need to handle input type changes to or from "hidden".
+ if (aElement->IsHTMLElement(nsGkAtoms::input) &&
+ aAttribute == nsGkAtoms::type && aNameSpaceID == kNameSpaceID_None) {
+ SetDirty();
+ return;
+ }
+}
+
+void
+nsLabelsNodeList::ContentAppended(nsIDocument* aDocument,
+ nsIContent* aContainer,
+ nsIContent* aFirstNewContent,
+ int32_t aNewIndexInContainer)
+{
+ // If a labelable element is moved to outside or inside of
+ // nested associated labels, we're gonna have to modify
+ // the content list.
+ if (mState != LIST_DIRTY ||
+ nsContentUtils::IsInSameAnonymousTree(mRootNode, aContainer)) {
+ SetDirty();
+ return;
+ }
+}
+
+void
+nsLabelsNodeList::ContentInserted(nsIDocument* aDocument,
+ nsIContent* aContainer,
+ nsIContent* aChild,
+ int32_t aIndexInContainer)
+{
+ // If a labelable element is moved to outside or inside of
+ // nested associated labels, we're gonna have to modify
+ // the content list.
+ if (mState != LIST_DIRTY ||
+ nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild)) {
+ SetDirty();
+ return;
+ }
+}
+
+void
+nsLabelsNodeList::ContentRemoved(nsIDocument* aDocument,
+ nsIContent* aContainer,
+ nsIContent* aChild,
+ int32_t aIndexInContainer,
+ nsIContent* aPreviousSibling)
+{
+ // If a labelable element is removed, we're gonna have to clean
+ // the content list.
+ if (mState != LIST_DIRTY ||
+ nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild)) {
+ SetDirty();
+ return;
+ }
+}
+
+void
+nsLabelsNodeList::MaybeResetRoot(nsINode* aRootNode)
+{
+ MOZ_ASSERT(aRootNode, "Must have root");
+ if (mRootNode == aRootNode) {
+ return;
+ }
+
+ if (mRootNode) {
+ mRootNode->RemoveMutationObserver(this);
+ }
+ mRootNode = aRootNode;
+ mRootNode->AddMutationObserver(this);
+ SetDirty();
+}
+
+void
+nsLabelsNodeList::PopulateSelf(uint32_t aNeededLength)
+{
+ MOZ_ASSERT(mRootNode, "Must have root");
+
+ // Start searching at the root.
+ nsINode* cur = mRootNode;
+ if (mElements.IsEmpty() && cur->IsElement() && Match(cur->AsElement())) {
+ mElements.AppendElement(cur->AsElement());
+ }
+
+ nsContentList::PopulateSelf(aNeededLength);
+}
diff --git a/dom/base/nsContentList.h b/dom/base/nsContentList.h
index 3878074b2..83d27da95 100644
--- a/dom/base/nsContentList.h
+++ b/dom/base/nsContentList.h
@@ -371,9 +371,9 @@ protected:
* traversed the whole document (or both).
*
* @param aNeededLength the length the list should have when we are
- * done (unless it exhausts the document)
+ * done (unless it exhausts the document)
*/
- void PopulateSelf(uint32_t aNeededLength);
+ virtual void PopulateSelf(uint32_t aNeededLength);
/**
* @param aContainer a content node which must be a descendant of
@@ -584,4 +584,40 @@ public:
#endif
};
+class nsLabelsNodeList final : public nsContentList
+{
+public:
+ nsLabelsNodeList(nsINode* aRootNode,
+ nsContentListMatchFunc aFunc,
+ nsContentListDestroyFunc aDestroyFunc,
+ void* aData)
+ : nsContentList(aRootNode, aFunc, aDestroyFunc, aData)
+ {
+ }
+
+ NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
+ NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
+ NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
+ NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
+
+ virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
+
+ /**
+ * Reset root, mutation observer, and clear content list
+ * if the root has been changed.
+ *
+ * @param aRootNode The node under which to limit our search.
+ */
+ void MaybeResetRoot(nsINode* aRootNode);
+
+private:
+ /**
+ * Start searching at the last one if we already have nodes, otherwise
+ * start searching at the root.
+ *
+ * @param aNeededLength The list of length should have when we are
+ * done (unless it exhausts the document).
+ */
+ void PopulateSelf(uint32_t aNeededLength) override;
+};
#endif // nsContentList_h___
diff --git a/dom/base/nsContentListDeclarations.h b/dom/base/nsContentListDeclarations.h
index db3a09036..a5e0e3691 100644
--- a/dom/base/nsContentListDeclarations.h
+++ b/dom/base/nsContentListDeclarations.h
@@ -18,6 +18,12 @@ class nsINode;
class nsString;
class nsAString;
+namespace mozilla {
+namespace dom {
+class Element;
+} // namespace dom
+} // namespace mozilla
+
// Magic namespace id that means "match all namespaces". This is
// negative so it won't collide with actual namespace constants.
#define kNameSpaceID_Wildcard INT32_MIN
@@ -26,7 +32,7 @@ class nsAString;
// arbitrary matching algorithm. aContent is the content that may
// match the list, while aNamespaceID, aAtom, and aData are whatever
// was passed to the list's constructor.
-typedef bool (*nsContentListMatchFunc)(nsIContent* aContent,
+typedef bool (*nsContentListMatchFunc)(mozilla::dom::Element* aElement,
int32_t aNamespaceID,
nsIAtom* aAtom,
void* aData);
diff --git a/dom/base/nsContentPolicy.cpp b/dom/base/nsContentPolicy.cpp
index 337debcea..5511b9086 100644
--- a/dom/base/nsContentPolicy.cpp
+++ b/dom/base/nsContentPolicy.cpp
@@ -20,6 +20,7 @@
#include "nsIDOMElement.h"
#include "nsIDOMNode.h"
#include "nsIDOMWindow.h"
+#include "nsITabChild.h"
#include "nsIContent.h"
#include "nsILoadContext.h"
#include "nsCOMArray.h"
@@ -89,8 +90,9 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
{
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(requestingContext));
nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(requestingContext));
- NS_ASSERTION(!requestingContext || node || window,
- "Context should be a DOM node or a DOM window!");
+ nsCOMPtr<nsITabChild> tabChild(do_QueryInterface(requestingContext));
+ NS_ASSERTION(!requestingContext || node || window || tabChild,
+ "Context should be a DOM node, DOM window or a tabChild!");
}
#endif
diff --git a/dom/base/nsContentSink.cpp b/dom/base/nsContentSink.cpp
index 3d6f069d2..85b3d07bf 100644
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -305,6 +305,11 @@ nsContentSink::ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue,
mDocument->SetHeaderData(aHeader, aValue);
if (aHeader == nsGkAtoms::setcookie) {
+ // Don't allow setting cookies in cookie-averse documents.
+ if (mDocument->IsCookieAverse()) {
+ return NS_OK;
+ }
+
// Note: Necko already handles cookies set via the channel. We can't just
// call SetCookie on the channel because we want to do some security checks
// here.
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 29d28f8ce..bc8cea35a 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -281,6 +281,7 @@ bool nsContentUtils::sIsCutCopyAllowed = true;
bool nsContentUtils::sIsFrameTimingPrefEnabled = false;
bool nsContentUtils::sIsPerformanceTimingEnabled = false;
bool nsContentUtils::sIsResourceTimingEnabled = false;
+bool nsContentUtils::sIsPerformanceNavigationTimingEnabled = false;
bool nsContentUtils::sIsUserTimingLoggingEnabled = false;
bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false;
bool nsContentUtils::sEncodeDecodeURLHash = false;
@@ -571,6 +572,9 @@ nsContentUtils::Init()
Preferences::AddBoolVarCache(&sIsResourceTimingEnabled,
"dom.enable_resource_timing", true);
+ Preferences::AddBoolVarCache(&sIsPerformanceNavigationTimingEnabled,
+ "dom.enable_performance_navigation_timing", true);
+
Preferences::AddBoolVarCache(&sIsUserTimingLoggingEnabled,
"dom.performance.enable_user_timing_logging", false);
@@ -3717,11 +3721,15 @@ nsContentUtils::IsChildOfSameType(nsIDocument* aDoc)
}
bool
-nsContentUtils::IsScriptType(const nsACString& aContentType)
+nsContentUtils::IsPlainTextType(const nsACString& aContentType)
{
// NOTE: if you add a type here, add it to the CONTENTDLF_CATEGORIES
// define in nsContentDLF.h as well.
- return aContentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
+ return aContentType.EqualsLiteral(TEXT_PLAIN) ||
+ aContentType.EqualsLiteral(TEXT_CSS) ||
+ aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) ||
+ aContentType.EqualsLiteral(TEXT_VTT) ||
+ aContentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
aContentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
aContentType.EqualsLiteral(TEXT_ECMASCRIPT) ||
aContentType.EqualsLiteral(APPLICATION_ECMASCRIPT) ||
@@ -3731,18 +3739,6 @@ nsContentUtils::IsScriptType(const nsACString& aContentType)
}
bool
-nsContentUtils::IsPlainTextType(const nsACString& aContentType)
-{
- // NOTE: if you add a type here, add it to the CONTENTDLF_CATEGORIES
- // define in nsContentDLF.h as well.
- return aContentType.EqualsLiteral(TEXT_PLAIN) ||
- aContentType.EqualsLiteral(TEXT_CSS) ||
- aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) ||
- aContentType.EqualsLiteral(TEXT_VTT) ||
- IsScriptType(aContentType);
-}
-
-bool
nsContentUtils::GetWrapperSafeScriptFilename(nsIDocument* aDocument,
nsIURI* aURI,
nsACString& aScriptURI,
@@ -4128,9 +4124,15 @@ nsContentUtils::GetSubdocumentWithOuterWindowId(nsIDocument *aDocument,
/* static */
nsresult
nsContentUtils::ConvertStringFromEncoding(const nsACString& aEncoding,
- const nsACString& aInput,
+ const char* aInput,
+ uint32_t aInputLen,
nsAString& aOutput)
{
+ CheckedInt32 len = aInputLen;
+ if (!len.isValid()) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
nsAutoCString encoding;
if (aEncoding.IsEmpty()) {
encoding.AssignLiteral("UTF-8");
@@ -4142,7 +4144,7 @@ nsContentUtils::ConvertStringFromEncoding(const nsACString& aEncoding,
nsAutoPtr<TextDecoder> decoder(new TextDecoder());
decoder->InitWithEncoding(encoding, false);
- decoder->Decode(aInput.BeginReading(), aInput.Length(), false,
+ decoder->Decode(aInput, len.value(), false,
aOutput, rv);
return rv.StealNSResult();
}
@@ -6281,11 +6283,11 @@ struct ClassMatchingInfo {
// static
bool
-nsContentUtils::MatchClassNames(nsIContent* aContent, int32_t aNamespaceID,
+nsContentUtils::MatchClassNames(Element* aElement, int32_t aNamespaceID,
nsIAtom* aAtom, void* aData)
{
// We can't match if there are no class names
- const nsAttrValue* classAttr = aContent->GetClasses();
+ const nsAttrValue* classAttr = aElement->GetClasses();
if (!classAttr) {
return false;
}
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 278fbd008..9ae6d2155 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -554,9 +554,17 @@ public:
* string (meaning UTF-8)
*/
static nsresult ConvertStringFromEncoding(const nsACString& aEncoding,
- const nsACString& aInput,
+ const char* aInput,
+ uint32_t aInputLen,
nsAString& aOutput);
+ static nsresult ConvertStringFromEncoding(const nsACString& aEncoding,
+ const nsACString& aInput,
+ nsAString& aOutput) {
+ return ConvertStringFromEncoding(
+ aEncoding, aInput.BeginReading(), aInput.Length(), aOutput);
+ }
+
/**
* Determine whether a buffer begins with a BOM for UTF-8, UTF-16LE,
* UTF-16BE
@@ -1010,12 +1018,7 @@ public:
static bool IsChildOfSameType(nsIDocument* aDoc);
/**
- '* Returns true if the content-type is any of the supported script types.
- */
- static bool IsScriptType(const nsACString& aContentType);
-
- /**
- '* Returns true if the content-type will be rendered as plain-text.
+ * Returns true if the content-type will be rendered as plain-text.
*/
static bool IsPlainTextType(const nsACString& aContentType);
@@ -2030,6 +2033,14 @@ public:
}
/*
+ * Returns true if the performance timing APIs are enabled.
+ */
+ static bool IsPerformanceNavigationTimingEnabled()
+ {
+ return sIsPerformanceNavigationTimingEnabled;
+ }
+
+ /*
* Returns true if notification should be sent for peformance timing events.
*/
static bool SendPerformanceTimingNotifications()
@@ -2745,7 +2756,8 @@ private:
static void DropFragmentParsers();
- static bool MatchClassNames(nsIContent* aContent, int32_t aNamespaceID,
+ static bool MatchClassNames(mozilla::dom::Element* aElement,
+ int32_t aNamespaceID,
nsIAtom* aAtom, void* aData);
static void DestroyClassNameArray(void* aData);
static void* AllocClassMatchingInfo(nsINode* aRootNode,
@@ -2821,6 +2833,7 @@ private:
static uint32_t sHandlingInputTimeout;
static bool sIsPerformanceTimingEnabled;
static bool sIsResourceTimingEnabled;
+ static bool sIsPerformanceNavigationTimingEnabled;
static bool sIsUserTimingLoggingEnabled;
static bool sIsFrameTimingPrefEnabled;
static bool sIsExperimentalAutocompleteEnabled;
diff --git a/dom/base/nsDOMNavigationTiming.cpp b/dom/base/nsDOMNavigationTiming.cpp
index 31b2932fb..32ce8a8cb 100644
--- a/dom/base/nsDOMNavigationTiming.cpp
+++ b/dom/base/nsDOMNavigationTiming.cpp
@@ -15,6 +15,9 @@
#include "nsPrintfCString.h"
#include "mozilla/dom/PerformanceNavigation.h"
#include "mozilla/TimeStamp.h"
+#include "mozilla/Telemetry.h"
+
+using namespace mozilla;
nsDOMNavigationTiming::nsDOMNavigationTiming()
{
@@ -30,47 +33,36 @@ nsDOMNavigationTiming::Clear()
{
mNavigationType = TYPE_RESERVED;
mNavigationStartHighRes = 0;
- mBeforeUnloadStart = 0;
- mUnloadStart = 0;
- mUnloadEnd = 0;
- mLoadEventStart = 0;
- mLoadEventEnd = 0;
- mDOMLoading = 0;
- mDOMInteractive = 0;
- mDOMContentLoadedEventStart = 0;
- mDOMContentLoadedEventEnd = 0;
- mDOMComplete = 0;
-
- mLoadEventStartSet = false;
- mLoadEventEndSet = false;
- mDOMLoadingSet = false;
- mDOMInteractiveSet = false;
- mDOMContentLoadedEventStartSet = false;
- mDOMContentLoadedEventEndSet = false;
- mDOMCompleteSet = false;
+ mBeforeUnloadStart = TimeStamp();
+ mUnloadStart = TimeStamp();
+ mUnloadEnd = TimeStamp();
+ mLoadEventStart = TimeStamp();
+ mLoadEventEnd = TimeStamp();
+ mDOMLoading = TimeStamp();
+ mDOMInteractive = TimeStamp();
+ mDOMContentLoadedEventStart = TimeStamp();
+ mDOMContentLoadedEventEnd = TimeStamp();
+ mDOMComplete = TimeStamp();
+
mDocShellHasBeenActiveSinceNavigationStart = false;
}
DOMTimeMilliSec
-nsDOMNavigationTiming::TimeStampToDOM(mozilla::TimeStamp aStamp) const
+nsDOMNavigationTiming::TimeStampToDOM(TimeStamp aStamp) const
{
if (aStamp.IsNull()) {
return 0;
}
- mozilla::TimeDuration duration = aStamp - mNavigationStartTimeStamp;
- return GetNavigationStart() + static_cast<int64_t>(duration.ToMilliseconds());
-}
-DOMTimeMilliSec nsDOMNavigationTiming::DurationFromStart()
-{
- return TimeStampToDOM(mozilla::TimeStamp::Now());
+ TimeDuration duration = aStamp - mNavigationStart;
+ return GetNavigationStart() + static_cast<int64_t>(duration.ToMilliseconds());
}
void
nsDOMNavigationTiming::NotifyNavigationStart(DocShellState aDocShellState)
{
mNavigationStartHighRes = (double)PR_Now() / PR_USEC_PER_MSEC;
- mNavigationStartTimeStamp = mozilla::TimeStamp::Now();
+ mNavigationStart = TimeStamp::Now();
mDocShellHasBeenActiveSinceNavigationStart = (aDocShellState == DocShellState::eActive);
}
@@ -86,7 +78,7 @@ nsDOMNavigationTiming::NotifyFetchStart(nsIURI* aURI, Type aNavigationType)
void
nsDOMNavigationTiming::NotifyBeforeUnload()
{
- mBeforeUnloadStart = DurationFromStart();
+ mBeforeUnloadStart = TimeStamp::Now();
}
void
@@ -99,105 +91,107 @@ nsDOMNavigationTiming::NotifyUnloadAccepted(nsIURI* aOldURI)
void
nsDOMNavigationTiming::NotifyUnloadEventStart()
{
- mUnloadStart = DurationFromStart();
+ mUnloadStart = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyUnloadEventEnd()
{
- mUnloadEnd = DurationFromStart();
+ mUnloadEnd = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyLoadEventStart()
{
- if (!mLoadEventStartSet) {
- mLoadEventStart = DurationFromStart();
- mLoadEventStartSet = true;
+ if (!mLoadEventStart.IsNull()) {
+ return;
}
+ mLoadEventStart = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyLoadEventEnd()
{
- if (!mLoadEventEndSet) {
- mLoadEventEnd = DurationFromStart();
- mLoadEventEndSet = true;
+ if (!mLoadEventEnd.IsNull()) {
+ return;
}
+ mLoadEventEnd = TimeStamp::Now();
}
void
-nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI, mozilla::TimeStamp aValue)
+nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI, TimeStamp aValue)
{
- if (!mDOMLoadingSet) {
- mLoadedURI = aURI;
- mDOMLoading = TimeStampToDOM(aValue);
- mDOMLoadingSet = true;
+ if (!mDOMLoading.IsNull()) {
+ return;
}
+ mLoadedURI = aURI;
+ mDOMLoading = aValue;
}
void
nsDOMNavigationTiming::NotifyDOMLoading(nsIURI* aURI)
{
- if (!mDOMLoadingSet) {
- mLoadedURI = aURI;
- mDOMLoading = DurationFromStart();
- mDOMLoadingSet = true;
+ if (!mDOMLoading.IsNull()) {
+ return;
}
+ mLoadedURI = aURI;
+ mDOMLoading = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyDOMInteractive(nsIURI* aURI)
{
- if (!mDOMInteractiveSet) {
- mLoadedURI = aURI;
- mDOMInteractive = DurationFromStart();
- mDOMInteractiveSet = true;
+ if (!mDOMInteractive.IsNull()) {
+ return;
}
+ mLoadedURI = aURI;
+ mDOMInteractive = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyDOMComplete(nsIURI* aURI)
{
- if (!mDOMCompleteSet) {
- mLoadedURI = aURI;
- mDOMComplete = DurationFromStart();
- mDOMCompleteSet = true;
+ if (!mDOMComplete.IsNull()) {
+ return;
}
+ mLoadedURI = aURI;
+ mDOMComplete = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyDOMContentLoadedStart(nsIURI* aURI)
{
- if (!mDOMContentLoadedEventStartSet) {
- mLoadedURI = aURI;
- mDOMContentLoadedEventStart = DurationFromStart();
- mDOMContentLoadedEventStartSet = true;
+ if (!mDOMContentLoadedEventStart.IsNull()) {
+ return;
}
+
+ mLoadedURI = aURI;
+ mDOMContentLoadedEventStart = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyDOMContentLoadedEnd(nsIURI* aURI)
{
- if (!mDOMContentLoadedEventEndSet) {
- mLoadedURI = aURI;
- mDOMContentLoadedEventEnd = DurationFromStart();
- mDOMContentLoadedEventEndSet = true;
+ if (!mDOMContentLoadedEventEnd.IsNull()) {
+ return;
}
+
+ mLoadedURI = aURI;
+ mDOMContentLoadedEventEnd = TimeStamp::Now();
}
void
nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument()
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!mNavigationStartTimeStamp.IsNull());
+ MOZ_ASSERT(!mNavigationStart.IsNull());
- if (!mNonBlankPaintTimeStamp.IsNull()) {
+ if (!mNonBlankPaint.IsNull()) {
return;
}
- mNonBlankPaintTimeStamp = TimeStamp::Now();
- TimeDuration elapsed = mNonBlankPaintTimeStamp - mNavigationStartTimeStamp;
+ mNonBlankPaint = TimeStamp::Now();
+ TimeDuration elapsed = mNonBlankPaint - mNavigationStart;
if (profiler_is_active()) {
nsAutoCString spec;
@@ -212,8 +206,8 @@ nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument()
if (mDocShellHasBeenActiveSinceNavigationStart) {
Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_NON_BLANK_PAINT_MS,
- mNavigationStartTimeStamp,
- mNonBlankPaintTimeStamp);
+ mNavigationStart,
+ mNonBlankPaint);
}
}
@@ -224,24 +218,24 @@ nsDOMNavigationTiming::NotifyDocShellStateChanged(DocShellState aDocShellState)
(aDocShellState == DocShellState::eActive);
}
-DOMTimeMilliSec
-nsDOMNavigationTiming::GetUnloadEventStart()
+mozilla::TimeStamp
+nsDOMNavigationTiming::GetUnloadEventStartTimeStamp() const
{
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false);
if (NS_SUCCEEDED(rv)) {
return mUnloadStart;
}
- return 0;
+ return mozilla::TimeStamp();
}
-DOMTimeMilliSec
-nsDOMNavigationTiming::GetUnloadEventEnd()
+mozilla::TimeStamp
+nsDOMNavigationTiming::GetUnloadEventEndTimeStamp() const
{
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false);
if (NS_SUCCEEDED(rv)) {
return mUnloadEnd;
}
- return 0;
+ return mozilla::TimeStamp();
}
diff --git a/dom/base/nsDOMNavigationTiming.h b/dom/base/nsDOMNavigationTiming.h
index 9babece96..3be2527ca 100644
--- a/dom/base/nsDOMNavigationTiming.h
+++ b/dom/base/nsDOMNavigationTiming.h
@@ -47,38 +47,91 @@ public:
mozilla::TimeStamp GetNavigationStartTimeStamp() const
{
- return mNavigationStartTimeStamp;
+ return mNavigationStart;
+ }
+
+ DOMTimeMilliSec GetUnloadEventStart()
+ {
+ return TimeStampToDOM(GetUnloadEventStartTimeStamp());
+ }
+
+ DOMTimeMilliSec GetUnloadEventEnd()
+ {
+ return TimeStampToDOM(GetUnloadEventEndTimeStamp());
}
- DOMTimeMilliSec GetUnloadEventStart();
- DOMTimeMilliSec GetUnloadEventEnd();
DOMTimeMilliSec GetDomLoading() const
{
- return mDOMLoading;
+ return TimeStampToDOM(mDOMLoading);
}
DOMTimeMilliSec GetDomInteractive() const
{
- return mDOMInteractive;
+ return TimeStampToDOM(mDOMInteractive);
}
DOMTimeMilliSec GetDomContentLoadedEventStart() const
{
- return mDOMContentLoadedEventStart;
+ return TimeStampToDOM(mDOMContentLoadedEventStart);
}
DOMTimeMilliSec GetDomContentLoadedEventEnd() const
{
- return mDOMContentLoadedEventEnd;
+ return TimeStampToDOM(mDOMContentLoadedEventEnd);
}
DOMTimeMilliSec GetDomComplete() const
{
- return mDOMComplete;
+ return TimeStampToDOM(mDOMComplete);
}
DOMTimeMilliSec GetLoadEventStart() const
{
- return mLoadEventStart;
+ return TimeStampToDOM(mLoadEventStart);
}
DOMTimeMilliSec GetLoadEventEnd() const
{
- return mLoadEventEnd;
+ return TimeStampToDOM(mLoadEventEnd);
+ }
+ DOMTimeMilliSec GetTimeToNonBlankPaint() const
+ {
+ return TimeStampToDOM(mNonBlankPaint);
+ }
+
+ DOMHighResTimeStamp GetUnloadEventStartHighRes()
+ {
+ mozilla::TimeStamp stamp = GetUnloadEventStartTimeStamp();
+ if (stamp.IsNull()) {
+ return 0;
+ }
+ return TimeStampToDOMHighRes(stamp);
+ }
+ DOMHighResTimeStamp GetUnloadEventEndHighRes()
+ {
+ mozilla::TimeStamp stamp = GetUnloadEventEndTimeStamp();
+ if (stamp.IsNull()) {
+ return 0;
+ }
+ return TimeStampToDOMHighRes(stamp);
+ }
+ DOMHighResTimeStamp GetDomInteractiveHighRes() const
+ {
+ return TimeStampToDOMHighRes(mDOMInteractive);
+ }
+ DOMHighResTimeStamp GetDomContentLoadedEventStartHighRes() const
+ {
+ return TimeStampToDOMHighRes(mDOMContentLoadedEventStart);
+ }
+ DOMHighResTimeStamp GetDomContentLoadedEventEndHighRes() const
+ {
+ return TimeStampToDOMHighRes(mDOMContentLoadedEventEnd);
+ }
+ DOMHighResTimeStamp GetDomCompleteHighRes() const
+ {
+ return TimeStampToDOMHighRes(mDOMComplete);
+ }
+ DOMHighResTimeStamp GetLoadEventStartHighRes() const
+ {
+ return TimeStampToDOMHighRes(mLoadEventStart);
+ }
+ DOMHighResTimeStamp GetLoadEventEndHighRes() const
+ {
+ return TimeStampToDOMHighRes(mLoadEventEnd);
}
enum class DocShellState : uint8_t {
@@ -108,9 +161,13 @@ public:
DOMTimeMilliSec TimeStampToDOM(mozilla::TimeStamp aStamp) const;
- inline DOMHighResTimeStamp TimeStampToDOMHighRes(mozilla::TimeStamp aStamp)
+ inline DOMHighResTimeStamp TimeStampToDOMHighRes(mozilla::TimeStamp aStamp) const
{
- mozilla::TimeDuration duration = aStamp - mNavigationStartTimeStamp;
+ MOZ_ASSERT(!aStamp.IsNull(), "The timestamp should not be null");
+ if (aStamp.IsNull()) {
+ return 0;
+ }
+ mozilla::TimeDuration duration = aStamp - mNavigationStart;
return duration.ToMilliseconds();
}
@@ -120,37 +177,29 @@ private:
void Clear();
+ mozilla::TimeStamp GetUnloadEventStartTimeStamp() const;
+ mozilla::TimeStamp GetUnloadEventEndTimeStamp() const;
+
nsCOMPtr<nsIURI> mUnloadedURI;
nsCOMPtr<nsIURI> mLoadedURI;
Type mNavigationType;
DOMHighResTimeStamp mNavigationStartHighRes;
- mozilla::TimeStamp mNavigationStartTimeStamp;
- mozilla::TimeStamp mNonBlankPaintTimeStamp;
- DOMTimeMilliSec DurationFromStart();
-
- DOMTimeMilliSec mBeforeUnloadStart;
- DOMTimeMilliSec mUnloadStart;
- DOMTimeMilliSec mUnloadEnd;
- DOMTimeMilliSec mLoadEventStart;
- DOMTimeMilliSec mLoadEventEnd;
-
- DOMTimeMilliSec mDOMLoading;
- DOMTimeMilliSec mDOMInteractive;
- DOMTimeMilliSec mDOMContentLoadedEventStart;
- DOMTimeMilliSec mDOMContentLoadedEventEnd;
- DOMTimeMilliSec mDOMComplete;
-
- // Booleans to keep track of what things we've already been notified
- // about. We don't update those once we've been notified about them
- // once.
- bool mLoadEventStartSet : 1;
- bool mLoadEventEndSet : 1;
- bool mDOMLoadingSet : 1;
- bool mDOMInteractiveSet : 1;
- bool mDOMContentLoadedEventStartSet : 1;
- bool mDOMContentLoadedEventEndSet : 1;
- bool mDOMCompleteSet : 1;
+ mozilla::TimeStamp mNavigationStart;
+ mozilla::TimeStamp mNonBlankPaint;
+
+ mozilla::TimeStamp mBeforeUnloadStart;
+ mozilla::TimeStamp mUnloadStart;
+ mozilla::TimeStamp mUnloadEnd;
+ mozilla::TimeStamp mLoadEventStart;
+ mozilla::TimeStamp mLoadEventEnd;
+
+ mozilla::TimeStamp mDOMLoading;
+ mozilla::TimeStamp mDOMInteractive;
+ mozilla::TimeStamp mDOMContentLoadedEventStart;
+ mozilla::TimeStamp mDOMContentLoadedEventEnd;
+ mozilla::TimeStamp mDOMComplete;
+
bool mDocShellHasBeenActiveSinceNavigationStart : 1;
};
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index 8e6920a0e..fd3b52948 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -61,6 +61,7 @@
#include "nsGenericHTMLElement.h"
#include "mozilla/dom/CDATASection.h"
#include "mozilla/dom/ProcessingInstruction.h"
+#include "nsDSURIContentListener.h"
#include "nsDOMString.h"
#include "nsNodeUtils.h"
#include "nsLayoutUtils.h" // for GetFrameForPoint
@@ -2053,10 +2054,17 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
mFirstChild = content->GetNextSibling();
}
mChildren.RemoveChildAt(i);
+ if (content == mCachedRootElement) {
+ // Immediately clear mCachedRootElement, now that it's been removed
+ // from mChildren, so that GetRootElement() will stop returning this
+ // now-stale value.
+ mCachedRootElement = nullptr;
+ }
nsNodeUtils::ContentRemoved(this, content, i, previousSibling);
content->UnbindFromTree();
}
- mCachedRootElement = nullptr;
+ MOZ_ASSERT(!mCachedRootElement,
+ "After removing all children, there should be no root elem");
}
mInUnlinkOrDeletion = oldVal;
@@ -2456,6 +2464,15 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
NS_ENSURE_SUCCESS(rv, rv);
}
+ // XFO needs to be checked after CSP because it is ignored if
+ // the CSP defines frame-ancestors.
+ if (!nsDSURIContentListener::CheckFrameOptions(aChannel, docShell, NodePrincipal())) {
+ MOZ_LOG(gCspPRLog, LogLevel::Debug,
+ ("XFO doesn't like frame's ancestry, not loading."));
+ // stop! ERROR page!
+ aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
+ }
+
return NS_OK;
}
@@ -3903,8 +3920,18 @@ nsDocument::RemoveChildAt(uint32_t aIndex, bool aNotify)
DestroyElementMaps();
}
- doRemoveChildAt(aIndex, aNotify, oldKid, mChildren);
+ // Preemptively clear mCachedRootElement, since we may be about to remove it
+ // from our child list, and we don't want to return this maybe-obsolete value
+ // from any GetRootElement() calls that happen inside of doRemoveChildAt().
+ // (NOTE: for this to be useful, doRemoveChildAt() must NOT trigger any
+ // GetRootElement() calls until after it's removed the child from mChildren.
+ // Any call before that point would restore this soon-to-be-obsolete cached
+ // answer, and our clearing here would be fruitless.)
mCachedRootElement = nullptr;
+ doRemoveChildAt(aIndex, aNotify, oldKid, mChildren);
+ MOZ_ASSERT(mCachedRootElement != oldKid,
+ "Stale pointer in mCachedRootElement, after we tried to clear it "
+ "(maybe somebody called GetRootElement() too early?)");
}
void
@@ -4330,6 +4357,7 @@ nsDocument::SetScopeObject(nsIGlobalObject* aGlobal)
}
}
+#ifdef MOZ_EME
static void
CheckIfContainsEMEContent(nsISupports* aSupports, void* aContainsEME)
{
@@ -4353,6 +4381,7 @@ nsDocument::ContainsEMEContent()
static_cast<void*>(&containsEME));
return containsEME;
}
+#endif // MOZ_EME
static void
CheckIfContainsMSEContent(nsISupports* aSupports, void* aContainsMSE)
@@ -8380,11 +8409,13 @@ nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
}
#endif // MOZ_WEBRTC
+#ifdef MOZ_EME
// Don't save presentations for documents containing EME content, so that
// CDMs reliably shutdown upon user navigation.
if (ContainsEMEContent()) {
return false;
}
+#endif
// Don't save presentations for documents containing MSE content, to
// reduce memory usage.
@@ -12832,3 +12863,19 @@ nsDocument::CheckCustomElementName(const ElementCreationOptions& aOptions,
return is;
}
+
+Selection*
+nsIDocument::GetSelection(ErrorResult& aRv)
+{
+ nsCOMPtr<nsPIDOMWindowInner> window = GetInnerWindow();
+ if (!window) {
+ return nullptr;
+ }
+
+ NS_ASSERTION(window->IsInnerWindow(), "Should have inner window here!");
+ if (!window->IsCurrentInnerWindow()) {
+ return nullptr;
+ }
+
+ return nsGlobalWindow::Cast(window)->GetSelection(aRv);
+}
diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h
index 17d936055..3725b3c18 100644
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1267,7 +1267,9 @@ public:
js::ExpandoAndGeneration mExpandoAndGeneration;
+#ifdef MOZ_EME
bool ContainsEMEContent();
+#endif
bool ContainsMSEContent();
@@ -1491,7 +1493,6 @@ private:
void PostUnblockOnloadEvent();
void DoUnblockOnload();
- nsresult CheckFrameOptions();
nsresult InitCSP(nsIChannel* aChannel);
/**
diff --git a/dom/base/nsDocumentEncoder.cpp b/dom/base/nsDocumentEncoder.cpp
index 0a3570962..84b128b15 100644
--- a/dom/base/nsDocumentEncoder.cpp
+++ b/dom/base/nsDocumentEncoder.cpp
@@ -481,7 +481,7 @@ nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
}
if (!aDontSerializeRoot) {
- rv = SerializeNodeEnd(node, aStr);
+ rv = SerializeNodeEnd(maybeFixedNode, aStr);
NS_ENSURE_SUCCESS(rv, rv);
}
diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp
index a4bba4856..049bc0a1a 100644
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -51,10 +51,6 @@
#include <algorithm>
#include "chrome/common/ipc_channel.h" // for IPC::Channel::kMaximumMessageSize
-#ifdef MOZ_CRASHREPORTER
-#include "nsExceptionHandler.h"
-#endif
-
#ifdef ANDROID
#include <android/log.h>
#endif
diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h
index 5ece68634..aa4ef2ca3 100644
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -526,6 +526,7 @@ GK_ATOM(keytext, "keytext")
GK_ATOM(keyup, "keyup")
GK_ATOM(kind, "kind")
GK_ATOM(label, "label")
+GK_ATOM(labels, "labels")
GK_ATOM(lang, "lang")
GK_ATOM(language, "language")
GK_ATOM(last, "last")
@@ -951,6 +952,7 @@ GK_ATOM(onupdateready, "onupdateready")
GK_ATOM(onupgradeneeded, "onupgradeneeded")
GK_ATOM(onussdreceived, "onussdreceived")
GK_ATOM(onversionchange, "onversionchange")
+GK_ATOM(onvisibilitychange, "onvisibilitychange")
GK_ATOM(onvoicechange, "onvoicechange")
GK_ATOM(onvoiceschanged, "onvoiceschanged")
GK_ATOM(onvrdisplayconnect, "onvrdisplayconnect")
@@ -1450,6 +1452,7 @@ GK_ATOM(font_style, "font-style")
GK_ATOM(font_variant, "font-variant")
GK_ATOM(foreignObject, "foreignObject")
GK_ATOM(fractalNoise, "fractalNoise")
+GK_ATOM(fr, "fr")
GK_ATOM(fx, "fx")
GK_ATOM(fy, "fy")
GK_ATOM(G, "G")
@@ -2231,6 +2234,8 @@ GK_ATOM(scrollbar_end_backward, "scrollbar-end-backward")
GK_ATOM(scrollbar_end_forward, "scrollbar-end-forward")
GK_ATOM(scrollbar_thumb_proportional, "scrollbar-thumb-proportional")
GK_ATOM(overlay_scrollbars, "overlay-scrollbars")
+GK_ATOM(windows_accent_color_applies, "windows-accent-color-applies")
+GK_ATOM(windows_accent_color_is_dark, "windows-accent-color-is-dark")
GK_ATOM(windows_default_theme, "windows-default-theme")
GK_ATOM(mac_graphite_theme, "mac-graphite-theme")
GK_ATOM(mac_yosemite_theme, "mac-yosemite-theme")
@@ -2260,6 +2265,8 @@ GK_ATOM(_moz_scrollbar_end_backward, "-moz-scrollbar-end-backward")
GK_ATOM(_moz_scrollbar_end_forward, "-moz-scrollbar-end-forward")
GK_ATOM(_moz_scrollbar_thumb_proportional, "-moz-scrollbar-thumb-proportional")
GK_ATOM(_moz_overlay_scrollbars, "-moz-overlay-scrollbars")
+GK_ATOM(_moz_windows_accent_color_applies, "-moz-windows-accent-color-applies")
+GK_ATOM(_moz_windows_accent_color_is_dark, "-moz-windows-accent-color-is-dark")
GK_ATOM(_moz_windows_default_theme, "-moz-windows-default-theme")
GK_ATOM(_moz_mac_graphite_theme, "-moz-mac-graphite-theme")
GK_ATOM(_moz_mac_yosemite_theme, "-moz-mac-yosemite-theme")
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index 8ff4b84ce..738703ef1 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -23,6 +23,7 @@
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
#include "mozilla/dom/Timeout.h"
+#include "mozilla/dom/TimeoutHandler.h"
#include "mozilla/IntegerPrintfMacros.h"
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
#include "mozilla/dom/WindowOrientationObserver.h"
@@ -552,29 +553,284 @@ DialogValueHolder::Get(JSContext* aCx, JS::Handle<JSObject*> aScope,
}
}
+class IdleRequestExecutor final : public nsIRunnable
+ , public nsICancelableRunnable
+ , public nsIIncrementalRunnable
+{
+public:
+ explicit IdleRequestExecutor(nsGlobalWindow* aWindow)
+ : mDispatched(false)
+ , mDeadline(TimeStamp::Now())
+ , mWindow(aWindow)
+ {
+ MOZ_DIAGNOSTIC_ASSERT(mWindow);
+ MOZ_DIAGNOSTIC_ASSERT(mWindow->IsInnerWindow());
+ }
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequestExecutor, nsIRunnable)
+
+ NS_DECL_NSIRUNNABLE
+ nsresult Cancel() override;
+ void SetDeadline(TimeStamp aDeadline) override;
+
+ void MaybeDispatch();
+private:
+ ~IdleRequestExecutor() {}
+
+ bool mDispatched;
+ TimeStamp mDeadline;
+ RefPtr<nsGlobalWindow> mWindow;
+};
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(IdleRequestExecutor)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutor)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutor)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IdleRequestExecutor)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IdleRequestExecutor)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutor)
+ NS_INTERFACE_MAP_ENTRY(nsIRunnable)
+ NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable)
+ NS_INTERFACE_MAP_ENTRY(nsIIncrementalRunnable)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRunnable)
+NS_INTERFACE_MAP_END
+
+NS_IMETHODIMP
+IdleRequestExecutor::Run()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ mDispatched = false;
+ if (mWindow) {
+ return mWindow->ExecuteIdleRequest(mDeadline);
+ }
+
+ return NS_OK;
+}
+
+nsresult
+IdleRequestExecutor::Cancel()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ mWindow = nullptr;
+ return NS_OK;
+}
+
void
-nsGlobalWindow::PostThrottledIdleCallback()
+IdleRequestExecutor::SetDeadline(TimeStamp aDeadline)
{
- AssertIsOnMainThread();
+ MOZ_ASSERT(NS_IsMainThread());
- if (mThrottledIdleRequestCallbacks.isEmpty())
+ if (!mWindow) {
return;
+ }
+
+ mDeadline = aDeadline;
+}
- RefPtr<IdleRequest> request(mThrottledIdleRequestCallbacks.popFirst());
- // ownership transferred from mThrottledIdleRequestCallbacks to
- // mIdleRequestCallbacks
- mIdleRequestCallbacks.insertBack(request);
+void
+IdleRequestExecutor::MaybeDispatch()
+{
+ // If we've already dispatched the executor we don't want to do it
+ // again. Also, if we've called IdleRequestExecutor::Cancel mWindow
+ // will be null, which indicates that we shouldn't dispatch this
+ // executor either.
+ if (mDispatched || !mWindow) {
+ return;
+ }
+
+ mDispatched = true;
+ RefPtr<IdleRequestExecutor> request = this;
NS_IdleDispatchToCurrentThread(request.forget());
}
-/* static */ void
-nsGlobalWindow::InsertIdleCallbackIntoList(IdleRequest* aRequest,
- IdleRequests& aList)
+class IdleRequestExecutorTimeoutHandler final : public TimeoutHandler
+{
+public:
+ explicit IdleRequestExecutorTimeoutHandler(IdleRequestExecutor* aExecutor)
+ : mExecutor(aExecutor)
+ {
+ }
+
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestExecutorTimeoutHandler,
+ TimeoutHandler)
+
+ nsresult Call() override
+ {
+ mExecutor->MaybeDispatch();
+ return NS_OK;
+ }
+private:
+ ~IdleRequestExecutorTimeoutHandler() {}
+ RefPtr<IdleRequestExecutor> mExecutor;
+};
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler, mExecutor)
+
+NS_IMPL_ADDREF_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler)
+NS_IMPL_RELEASE_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler)
+ NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler)
+NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler)
+
+void
+nsGlobalWindow::ScheduleIdleRequestDispatch()
+{
+ AssertIsOnMainThread();
+
+ if (mIdleRequestCallbacks.isEmpty()) {
+ if (mIdleRequestExecutor) {
+ mIdleRequestExecutor->Cancel();
+ mIdleRequestExecutor = nullptr;
+ }
+
+ return;
+ }
+
+ if (!mIdleRequestExecutor) {
+ mIdleRequestExecutor = new IdleRequestExecutor(this);
+ }
+
+ nsPIDOMWindowOuter* outer = GetOuterWindow();
+ if (outer && outer->AsOuter()->IsBackground()) {
+ nsCOMPtr<nsITimeoutHandler> handler = new IdleRequestExecutorTimeoutHandler(mIdleRequestExecutor);
+ int32_t dummy;
+ // Set a timeout handler with a timeout of 0 ms to throttle idle
+ // callback requests coming from a backround window using
+ // background timeout throttling.
+ SetTimeoutOrInterval(handler, 0, false,
+ Timeout::Reason::eIdleCallbackTimeout, &dummy);
+ return;
+ }
+
+ mIdleRequestExecutor->MaybeDispatch();
+}
+
+void
+nsGlobalWindow::SuspendIdleRequests()
+{
+ if (mIdleRequestExecutor) {
+ mIdleRequestExecutor->Cancel();
+ mIdleRequestExecutor = nullptr;
+ }
+}
+
+void
+nsGlobalWindow::ResumeIdleRequests()
+{
+ MOZ_ASSERT(!mIdleRequestExecutor);
+
+ ScheduleIdleRequestDispatch();
+}
+
+void
+nsGlobalWindow::InsertIdleCallback(IdleRequest* aRequest)
{
- aList.insertBack(aRequest);
+ AssertIsOnMainThread();
+ mIdleRequestCallbacks.insertBack(aRequest);
aRequest->AddRef();
}
+void
+nsGlobalWindow::RemoveIdleCallback(mozilla::dom::IdleRequest* aRequest)
+{
+ AssertIsOnMainThread();
+
+ if (aRequest->HasTimeout()) {
+ ClearTimeoutOrInterval(aRequest->GetTimeoutHandle(),
+ Timeout::Reason::eIdleCallbackTimeout);
+ }
+
+ aRequest->removeFrom(mIdleRequestCallbacks);
+ aRequest->Release();
+}
+
+nsresult
+nsGlobalWindow::RunIdleRequest(IdleRequest* aRequest,
+ DOMHighResTimeStamp aDeadline,
+ bool aDidTimeout)
+{
+ AssertIsOnMainThread();
+ RefPtr<IdleRequest> request(aRequest);
+ RemoveIdleCallback(request);
+ return request->IdleRun(AsInner(), aDeadline, aDidTimeout);
+}
+
+nsresult
+nsGlobalWindow::ExecuteIdleRequest(TimeStamp aDeadline)
+{
+ AssertIsOnMainThread();
+ RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst();
+
+ if (!request) {
+ // There are no more idle requests, so stop scheduling idle
+ // request callbacks.
+ return NS_OK;
+ }
+
+ DOMHighResTimeStamp deadline = 0.0;
+
+ if (Performance* perf = GetPerformance()) {
+ deadline = perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline);
+ }
+
+ nsresult result = RunIdleRequest(request, deadline, false);
+
+ ScheduleIdleRequestDispatch();
+ return result;
+}
+
+class IdleRequestTimeoutHandler final : public TimeoutHandler
+{
+public:
+ IdleRequestTimeoutHandler(JSContext* aCx,
+ IdleRequest* aIdleRequest,
+ nsPIDOMWindowInner* aWindow)
+ : TimeoutHandler(aCx)
+ , mIdleRequest(aIdleRequest)
+ , mWindow(aWindow)
+ {
+ }
+
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestTimeoutHandler,
+ TimeoutHandler)
+
+ nsresult Call() override
+ {
+ return nsGlobalWindow::Cast(mWindow)->RunIdleRequest(mIdleRequest, 0.0, true);
+ }
+
+private:
+ ~IdleRequestTimeoutHandler() {}
+
+ RefPtr<IdleRequest> mIdleRequest;
+ nsCOMPtr<nsPIDOMWindowInner> mWindow;
+};
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(IdleRequestTimeoutHandler,
+ TimeoutHandler,
+ mIdleRequest,
+ mWindow)
+
+NS_IMPL_ADDREF_INHERITED(IdleRequestTimeoutHandler, TimeoutHandler)
+NS_IMPL_RELEASE_INHERITED(IdleRequestTimeoutHandler, TimeoutHandler)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestTimeoutHandler)
+ NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler)
+NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler)
+
uint32_t
nsGlobalWindow::RequestIdleCallback(JSContext* aCx,
IdleRequestCallback& aCallback,
@@ -584,33 +840,36 @@ nsGlobalWindow::RequestIdleCallback(JSContext* aCx,
MOZ_RELEASE_ASSERT(IsInnerWindow());
AssertIsOnMainThread();
- uint32_t handle = ++mIdleRequestCallbackCounter;
+ uint32_t handle = mIdleRequestCallbackCounter++;
RefPtr<IdleRequest> request =
- new IdleRequest(aCx, AsInner(), aCallback, handle);
+ new IdleRequest(&aCallback, handle);
if (aOptions.mTimeout.WasPassed()) {
- aError = request->SetTimeout(aOptions.mTimeout.Value());
- if (NS_WARN_IF(aError.Failed())) {
+ int32_t timeoutHandle;
+ nsCOMPtr<nsITimeoutHandler> handler(new IdleRequestTimeoutHandler(aCx, request, AsInner()));
+
+ nsresult rv = SetTimeoutOrInterval(
+ handler, aOptions.mTimeout.Value(), false,
+ Timeout::Reason::eIdleCallbackTimeout, &timeoutHandle);
+
+ if (NS_WARN_IF(NS_FAILED(rv))) {
return 0;
}
- }
- nsGlobalWindow* outer = GetOuterWindowInternal();
- if (outer && outer->AsOuter()->IsBackground()) {
- // mThrottledIdleRequestCallbacks now owns request
- InsertIdleCallbackIntoList(request, mThrottledIdleRequestCallbacks);
-
- NS_DelayedDispatchToCurrentThread(
- NewRunnableMethod(this, &nsGlobalWindow::PostThrottledIdleCallback),
- 10000);
- } else {
- MOZ_ASSERT(mThrottledIdleRequestCallbacks.isEmpty());
+ request->SetTimeoutHandle(timeoutHandle);
+ }
- // mIdleRequestCallbacks now owns request
- InsertIdleCallbackIntoList(request, mIdleRequestCallbacks);
+ // If the list of idle callback requests is not empty it means that
+ // we've already dispatched the first idle request. If we're
+ // suspended we should only queue the idle callback and not schedule
+ // it to run, that will be done in ResumeIdleRequest.
+ bool needsScheduling = !IsSuspended() && mIdleRequestCallbacks.isEmpty();
+ // mIdleRequestCallbacks now owns request
+ InsertIdleCallback(request);
- NS_IdleDispatchToCurrentThread(request.forget());
+ if (needsScheduling) {
+ ScheduleIdleRequestDispatch();
}
return handle;
@@ -623,7 +882,7 @@ nsGlobalWindow::CancelIdleCallback(uint32_t aHandle)
for (IdleRequest* r : mIdleRequestCallbacks) {
if (r->Handle() == aHandle) {
- r->Cancel();
+ RemoveIdleCallback(r);
break;
}
}
@@ -632,29 +891,17 @@ nsGlobalWindow::CancelIdleCallback(uint32_t aHandle)
void
nsGlobalWindow::DisableIdleCallbackRequests()
{
- while (!mIdleRequestCallbacks.isEmpty()) {
- RefPtr<IdleRequest> request = mIdleRequestCallbacks.popFirst();
- request->Cancel();
+ if (mIdleRequestExecutor) {
+ mIdleRequestExecutor->Cancel();
+ mIdleRequestExecutor = nullptr;
}
- while (!mThrottledIdleRequestCallbacks.isEmpty()) {
- RefPtr<IdleRequest> request = mThrottledIdleRequestCallbacks.popFirst();
- request->Cancel();
- }
-}
-
-void nsGlobalWindow::UnthrottleIdleCallbackRequests()
-{
- AssertIsOnMainThread();
-
- while (!mThrottledIdleRequestCallbacks.isEmpty()) {
- RefPtr<IdleRequest> request(mThrottledIdleRequestCallbacks.popFirst());
- mIdleRequestCallbacks.insertBack(request);
- NS_IdleDispatchToCurrentThread(request.forget());
+ while (!mIdleRequestCallbacks.isEmpty()) {
+ RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst();
+ RemoveIdleCallback(request);
}
}
-
namespace mozilla {
namespace dom {
extern uint64_t
@@ -1306,6 +1553,7 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
mSerial(0),
mIdleCallbackTimeoutCounter(1),
mIdleRequestCallbackCounter(1),
+ mIdleRequestExecutor(nullptr),
#ifdef DEBUG
mSetOpenerWindowCalled(false),
#endif
@@ -2033,14 +2281,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor)
for (IdleRequest* request : tmp->mIdleRequestCallbacks) {
cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest));
}
- for (IdleRequest* request : tmp->mThrottledIdleRequestCallbacks) {
- cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest));
- }
-
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
#ifdef MOZ_GAMEPAD
@@ -2147,6 +2392,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
tmp->UnlinkHostObjectURIs();
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor)
tmp->DisableIdleCallbackRequests();
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
@@ -2878,8 +3124,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
newInnerWindow->mPerformance =
Performance::CreateForMainThread(newInnerWindow->AsInner(),
currentInner->mPerformance->GetDOMTiming(),
- currentInner->mPerformance->GetChannel(),
- currentInner->mPerformance->GetParentPerformance());
+ currentInner->mPerformance->GetChannel());
}
}
@@ -4093,22 +4338,7 @@ nsPIDOMWindowInner::CreatePerformanceObjectIfNeeded()
timedChannel = nullptr;
}
if (timing) {
- // If we are dealing with an iframe, we will need the parent's performance
- // object (so we can add the iframe as a resource of that page).
- Performance* parentPerformance = nullptr;
- nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetScriptableParentOrNull();
- if (parentWindow) {
- nsPIDOMWindowInner* parentInnerWindow = nullptr;
- if (parentWindow) {
- parentInnerWindow = parentWindow->GetCurrentInnerWindow();
- }
- if (parentInnerWindow) {
- parentPerformance = parentInnerWindow->GetPerformance();
- }
- }
- mPerformance =
- Performance::CreateForMainThread(this, timing, timedChannel,
- parentPerformance);
+ mPerformance = Performance::CreateForMainThread(this, timing, timedChannel);
}
}
@@ -6187,7 +6417,7 @@ nsGlobalWindow::GetScrollMaxY(ErrorResult& aError)
FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideBottom), aError, 0);
}
-CSSIntPoint
+CSSPoint
nsGlobalWindow::GetScrollXY(bool aDoFlush)
{
MOZ_ASSERT(IsOuterWindow());
@@ -6211,30 +6441,30 @@ nsGlobalWindow::GetScrollXY(bool aDoFlush)
return GetScrollXY(true);
}
- return sf->GetScrollPositionCSSPixels();
+ return CSSPoint::FromAppUnits(scrollPos);
}
-int32_t
+double
nsGlobalWindow::GetScrollXOuter()
{
MOZ_RELEASE_ASSERT(IsOuterWindow());
return GetScrollXY(false).x;
}
-int32_t
+double
nsGlobalWindow::GetScrollX(ErrorResult& aError)
{
FORWARD_TO_OUTER_OR_THROW(GetScrollXOuter, (), aError, 0);
}
-int32_t
+double
nsGlobalWindow::GetScrollYOuter()
{
MOZ_RELEASE_ASSERT(IsOuterWindow());
return GetScrollXY(false).y;
}
-int32_t
+double
nsGlobalWindow::GetScrollY(ErrorResult& aError)
{
FORWARD_TO_OUTER_OR_THROW(GetScrollYOuter, (), aError, 0);
@@ -10237,12 +10467,6 @@ void nsGlobalWindow::SetIsBackground(bool aIsBackground)
ResetTimersForThrottleReduction(gMinBackgroundTimeoutValue);
}
- if (!aIsBackground) {
- nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
- if (inner) {
- inner->UnthrottleIdleCallbackRequests();
- }
- }
#ifdef MOZ_GAMEPAD
if (!aIsBackground) {
nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
@@ -12036,6 +12260,8 @@ nsGlobalWindow::Suspend()
mozilla::dom::workers::SuspendWorkersForWindow(AsInner());
+ SuspendIdleRequests();
+
for (Timeout* t = mTimeouts.getFirst(); t; t = t->getNext()) {
// Leave the timers with the current time remaining. This will
// cause the timers to potentially fire when the window is
@@ -12146,6 +12372,8 @@ nsGlobalWindow::Resume()
t->AddRef();
}
+ ResumeIdleRequests();
+
// Resume all of the workers for this window. We must do this
// after timeouts since workers may have queued events that can trigger
// a setTimeout().
diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h
index eab91c2e4..78bee63a1 100644
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -102,6 +102,8 @@ struct nsRect;
class nsWindowSizes;
+class IdleRequestExecutor;
+
namespace mozilla {
class DOMEventTargetHelper;
class ThrottledEventQueue;
@@ -118,6 +120,7 @@ class Gamepad;
enum class ImageBitmapFormat : uint32_t;
class IdleRequest;
class IdleRequestCallback;
+class IncrementalRunnable;
class Location;
class MediaQueryList;
class MozSelfSupport;
@@ -1050,15 +1053,15 @@ public:
void SetInnerHeight(JSContext* aCx, JS::Handle<JS::Value> aValue,
mozilla::dom::CallerType aCallerType,
mozilla::ErrorResult& aError);
- int32_t GetScrollXOuter();
- int32_t GetScrollX(mozilla::ErrorResult& aError);
- int32_t GetPageXOffset(mozilla::ErrorResult& aError)
+ double GetScrollXOuter();
+ double GetScrollX(mozilla::ErrorResult& aError);
+ double GetPageXOffset(mozilla::ErrorResult& aError)
{
return GetScrollX(aError);
}
- int32_t GetScrollYOuter();
- int32_t GetScrollY(mozilla::ErrorResult& aError);
- int32_t GetPageYOffset(mozilla::ErrorResult& aError)
+ double GetScrollYOuter();
+ double GetScrollY(mozilla::ErrorResult& aError);
+ double GetPageYOffset(mozilla::ErrorResult& aError)
{
return GetScrollY(aError);
}
@@ -1097,7 +1100,6 @@ public:
mozilla::ErrorResult& aError);
void CancelIdleCallback(uint32_t aHandle);
-
#ifdef MOZ_WEBSPEECH
mozilla::dom::SpeechSynthesis*
GetSpeechSynthesis(mozilla::ErrorResult& aError);
@@ -1579,7 +1581,7 @@ public:
// If aDoFlush is true, we'll flush our own layout; otherwise we'll try to
// just flush our parent and only flush ourselves if we think we need to.
// Outer windows only.
- mozilla::CSSIntPoint GetScrollXY(bool aDoFlush);
+ mozilla::CSSPoint GetScrollXY(bool aDoFlush);
int32_t GetScrollBoundaryOuter(mozilla::Side aSide);
@@ -1762,6 +1764,21 @@ private:
mozilla::dom::TabGroup* TabGroupInner();
mozilla::dom::TabGroup* TabGroupOuter();
+public:
+ void DisableIdleCallbackRequests();
+ uint32_t IdleRequestHandle() const { return mIdleRequestCallbackCounter; }
+ nsresult RunIdleRequest(mozilla::dom::IdleRequest* aRequest,
+ DOMHighResTimeStamp aDeadline, bool aDidTimeout);
+ nsresult ExecuteIdleRequest(TimeStamp aDeadline);
+ void ScheduleIdleRequestDispatch();
+ void SuspendIdleRequests();
+ void ResumeIdleRequests();
+
+ typedef mozilla::LinkedList<mozilla::dom::IdleRequest> IdleRequests;
+ void InsertIdleCallback(mozilla::dom::IdleRequest* aRequest);
+
+ void RemoveIdleCallback(mozilla::dom::IdleRequest* aRequest);
+
protected:
// These members are only used on outer window objects. Make sure
// you never set any of these on an inner object!
@@ -1912,21 +1929,12 @@ protected:
uint32_t mSerial;
- void DisableIdleCallbackRequests();
- void UnthrottleIdleCallbackRequests();
-
- void PostThrottledIdleCallback();
-
- typedef mozilla::LinkedList<mozilla::dom::IdleRequest> IdleRequests;
- static void InsertIdleCallbackIntoList(mozilla::dom::IdleRequest* aRequest,
- IdleRequests& aList);
-
// The current idle request callback timeout handle
uint32_t mIdleCallbackTimeoutCounter;
// The current idle request callback handle
uint32_t mIdleRequestCallbackCounter;
IdleRequests mIdleRequestCallbacks;
- IdleRequests mThrottledIdleRequestCallbacks;
+ RefPtr<IdleRequestExecutor> mIdleRequestExecutor;
#ifdef DEBUG
bool mSetOpenerWindowCalled;
@@ -2002,6 +2010,7 @@ protected:
friend class nsDOMWindowUtils;
friend class mozilla::dom::PostMessageEvent;
friend class DesktopNotification;
+ friend class IdleRequestExecutor;
static WindowByIdTable* sWindowsById;
static bool sWarnedAboutWindowInternal;
diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h
index f05c47a61..405090865 100644
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -862,18 +862,6 @@ public:
}
/**
- * Get the class list of this content node (this corresponds to the
- * value of the class attribute). This may be null if there are no
- * classes, but that's not guaranteed.
- */
- const nsAttrValue* GetClasses() const {
- if (HasFlag(NODE_MAY_HAVE_CLASS)) {
- return DoGetClasses();
- }
- return nullptr;
- }
-
- /**
* Walk aRuleWalker over the content style rules (presentational
* hint rules) for this content node.
*/
@@ -990,13 +978,6 @@ protected:
*/
nsIAtom* DoGetID() const;
-private:
- /**
- * Hook for implementing GetClasses. This is guaranteed to only be
- * called if the NODE_MAY_HAVE_CLASS flag is set.
- */
- const nsAttrValue* DoGetClasses() const;
-
public:
#ifdef DEBUG
/**
diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
index 5b10c9914..1e0c9562e 100644
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -151,6 +151,7 @@ class NodeIterator;
enum class OrientationType : uint32_t;
class ProcessingInstruction;
class Promise;
+class Selection;
class StyleSheetList;
class SVGDocument;
class SVGSVGElement;
@@ -898,6 +899,8 @@ public:
*/
Element* GetRootElement() const;
+ mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aRv);
+
/**
* Retrieve information about the viewport as a data structure.
* This will return information in the viewport META data section
@@ -1923,6 +1926,34 @@ public:
return mMarkedCCGeneration;
}
+ /**
+ * Returns whether this document is cookie-averse. See
+ * https://html.spec.whatwg.org/multipage/dom.html#cookie-averse-document-object
+ */
+ bool IsCookieAverse() const
+ {
+ // If we are a document that "has no browsing context."
+ if (!GetInnerWindow()) {
+ return true;
+ }
+
+ // If we are a document "whose URL's scheme is not a network scheme."
+ // NB: Explicitly allow file: URIs to store cookies.
+ nsCOMPtr<nsIURI> codebaseURI;
+ NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
+
+ if (!codebaseURI) {
+ return true;
+ }
+
+ nsAutoCString scheme;
+ codebaseURI->GetScheme(scheme);
+ return !scheme.EqualsLiteral("http") &&
+ !scheme.EqualsLiteral("https") &&
+ !scheme.EqualsLiteral("ftp") &&
+ !scheme.EqualsLiteral("file");
+ }
+
bool IsLoadedAsData()
{
return mLoadedAsData;
diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp
index 3a649a61d..715ca93ea 100644
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1907,6 +1907,10 @@ void
nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify,
nsIContent* aKid, nsAttrAndChildArray& aChildArray)
{
+ // NOTE: This function must not trigger any calls to
+ // nsIDocument::GetRootElement() calls until *after* it has removed aKid from
+ // aChildArray. Any calls before then could potentially restore a stale
+ // value for our cached root element, per note in nsDocument::RemoveChildAt().
NS_PRECONDITION(aKid && aKid->GetParentNode() == this &&
aKid == GetChildAt(aIndex) &&
IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid");
diff --git a/dom/base/nsPluginArray.cpp b/dom/base/nsPluginArray.cpp
index b9c946ca3..5b9378ae0 100644
--- a/dom/base/nsPluginArray.cpp
+++ b/dom/base/nsPluginArray.cpp
@@ -372,9 +372,21 @@ nsPluginArray::EnsurePlugins()
nsCString permString;
nsresult rv = pluginHost->GetPermissionStringForTag(pluginTag, 0, permString);
if (rv == NS_OK) {
- nsIPrincipal* principal = mWindow->GetExtantDoc()->NodePrincipal();
- nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
- permMgr->TestPermissionFromPrincipal(principal, permString.get(), &permission);
+ nsCOMPtr<nsIDocument> currentDoc = mWindow->GetExtantDoc();
+
+ // The top-level content document gets the final say on whether or not
+ // a plugin is going to be hidden or not, regardless of the origin
+ // that a subframe is hosted at. This is to avoid spamming the user
+ // with the hidden plugin notification bar when third-party iframes
+ // attempt to access navigator.plugins after the user has already
+ // expressed that the top-level document has this permission.
+ nsCOMPtr<nsIDocument> topDoc = currentDoc->GetTopLevelContentDocument();
+
+ if (topDoc) {
+ nsIPrincipal* principal = topDoc->NodePrincipal();
+ nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
+ permMgr->TestPermissionFromPrincipal(principal, permString.get(), &permission);
+ }
}
}
}
diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp
index 37ba147af..4b4ce7885 100644
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -3194,7 +3194,7 @@ nsRange::AutoInvalidateSelection::~AutoInvalidateSelection()
mIsNested = false;
::InvalidateAllFrames(mCommonAncestor);
nsINode* commonAncestor = mRange->GetRegisteredCommonAncestor();
- if (commonAncestor != mCommonAncestor) {
+ if (commonAncestor && commonAncestor != mCommonAncestor) {
::InvalidateAllFrames(commonAncestor);
}
}
diff --git a/dom/base/nsTreeSanitizer.cpp b/dom/base/nsTreeSanitizer.cpp
index dc53ea5fa..323c851c1 100644
--- a/dom/base/nsTreeSanitizer.cpp
+++ b/dom/base/nsTreeSanitizer.cpp
@@ -169,6 +169,7 @@ nsIAtom** const kAttributesHTML[] = {
&nsGkAtoms::contextmenu,
&nsGkAtoms::controls,
&nsGkAtoms::coords,
+ &nsGkAtoms::crossorigin,
&nsGkAtoms::datetime,
&nsGkAtoms::dir,
&nsGkAtoms::disabled,
@@ -185,6 +186,7 @@ nsIAtom** const kAttributesHTML[] = {
&nsGkAtoms::hreflang,
&nsGkAtoms::icon,
&nsGkAtoms::id,
+ &nsGkAtoms::integrity,
&nsGkAtoms::ismap,
&nsGkAtoms::itemid,
&nsGkAtoms::itemprop,
diff --git a/dom/base/nsXHTMLContentSerializer.cpp b/dom/base/nsXHTMLContentSerializer.cpp
index 0dc31d7ae..111ed46c7 100644..100755
--- a/dom/base/nsXHTMLContentSerializer.cpp
+++ b/dom/base/nsXHTMLContentSerializer.cpp
@@ -306,7 +306,7 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent,
continue;
}
- BorrowedAttrInfo info = aContent->GetAttrInfoAt(index);
+ mozilla::dom::BorrowedAttrInfo info = aContent->GetAttrInfoAt(index);
const nsAttrName* name = info.mName;
int32_t namespaceID = name->NamespaceID();
diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini
index ea86290d9..ddfd57443 100644
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -609,6 +609,7 @@ skip-if = toolkit == 'android'
[test_bug1307730.html]
[test_bug1308069.html]
[test_bug1314032.html]
+[test_bug1375050.html]
[test_caretPositionFromPoint.html]
[test_change_policy.html]
[test_classList.html]
diff --git a/dom/base/test/test_bug1375050.html b/dom/base/test/test_bug1375050.html
new file mode 100644
index 000000000..b91b859d0
--- /dev/null
+++ b/dom/base/test/test_bug1375050.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1375050
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1375050</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ try { o1 = document.createElement('input'); } catch(e) { console.log(e); };
+ try { o2 = document.createElement('col'); } catch(e) { console.log(e); };
+ try { o4 = document.createRange(); } catch(e) { console.log(e); };
+ try { document.documentElement.appendChild(o1); } catch(e) { console.log(e); };
+ try { for (let p in o1) { let x = o1[p] }; } catch(e) { console.log(e); };
+ try { o4.selectNode(o1); } catch(e) { console.log(e); };
+ try { o6 = document.createComment(" x"); } catch(e) { console.log(e); }
+ try { o4.surroundContents(o6); } catch(e) { console.log(e); }
+ try { o7 = document.implementation.createDocument('', '', null).adoptNode(o1); } catch(e) { console.log(e);};
+ try { o2.appendChild(o1); } catch(e) { console.log(e); };
+ ok(true, "Didn't crash.");
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1375050">Mozilla Bug 1375050</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug403852.html b/dom/base/test/test_bug403852.html
index 30192cb1b..592711500 100644
--- a/dom/base/test/test_bug403852.html
+++ b/dom/base/test/test_bug403852.html
@@ -38,7 +38,8 @@ function onOpened(message) {
ok("lastModifiedDate" in domFile, "lastModifiedDate must be present");
var d = new Date(message.mtime);
- is(d.getTime(), domFile.lastModifiedDate.getTime(), "lastModifiedDate should be the same");
+ // Commented out: lastModifiedDate is rounded because it is a DOM API, message is a special-powers Chrome thing
+ // is(d.getTime(), domFile.lastModifiedDate.getTime(), "lastModifiedDate should be the same");
var x = new Date();
@@ -53,8 +54,8 @@ function onOpened(message) {
ok((x.getTime() <= y.getTime()) && (y.getTime() <= z.getTime()), "lastModifiedDate of file which does not have last modified date should be current time");
- var d = new Date(message.fileDate);
- is(d.getTime(), message.fileWithDate.lastModifiedDate.getTime(), "lastModifiedDate should be the same when lastModified is set: " + message.fileWithDate.lastModified);
+ // var d = new Date(message.fileDate);
+ // is(d.getTime(), message.fileWithDate.lastModifiedDate.getTime(), "lastModifiedDate should be the same when lastModified is set: " + message.fileWithDate.lastModified);
script.destroy();
SimpleTest.finish();
diff --git a/dom/base/test/test_file_negative_date.html b/dom/base/test/test_file_negative_date.html
index ebfa9bd0d..26cf3b82e 100644
--- a/dom/base/test/test_file_negative_date.html
+++ b/dom/base/test/test_file_negative_date.html
@@ -22,13 +22,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1158437
var blob = new Blob(['hello world']);
var f1 = new File([blob], 'f1.txt', { lastModified: 0 });
-var f2 = new File([blob], 'f2.txt', { lastModified: -1 });
+var f2 = new File([blob], 'f2.txt', { lastModified: -2 });
var f3 = new File([blob], 'f3.txt', { lastModified: -1000 });
is(f1.lastModified, 0, "lastModified == 0 is supported");
ok(f1.lastModifiedDate.toString(), (new Date(0)).toString(), "Correct f1.lastModifiedDate value");
-is(f2.lastModified, -1, "lastModified == -1 is supported");
-ok(f2.lastModifiedDate.toString(), (new Date(-1)).toString(), "Correct f2.lastModifiedDate value");
+is(f2.lastModified, -2, "lastModified == -2 is supported");
+ok(f2.lastModifiedDate.toString(), (new Date(-2)).toString(), "Correct f2.lastModifiedDate value");
is(f3.lastModified, -1000, "lastModified == -1000 is supported");
ok(f3.lastModifiedDate.toString(), (new Date(-1000)).toString(), "Correct f3.lastModifiedDate value");
diff --git a/dom/base/test/test_viewport_scroll.html b/dom/base/test/test_viewport_scroll.html
index 9b812360b..7db02b781 100644
--- a/dom/base/test/test_viewport_scroll.html
+++ b/dom/base/test/test_viewport_scroll.html
@@ -28,10 +28,10 @@ function subtest(winProp, elemProp, win, correctElement, elemToSet, otherElem1,
win.scrollTo(50, 50);
elemToSet[elemProp] = 100;
if (elemToSet == correctElement) {
- is(win[winProp], 100, "Setting " + elemToSet.name + "." + elemProp + " should scroll");
+ is(Math.round(win[winProp]), 100, "Setting " + elemToSet.name + "." + elemProp + " should scroll");
is(elemToSet[elemProp], 100, "Reading back " + elemToSet.name + "." + elemProp + " after scrolling");
} else {
- is(win[winProp], 50, "Setting " + elemToSet.name + "." + elemProp + " should not scroll");
+ is(Math.round(win[winProp]), 50, "Setting " + elemToSet.name + "." + elemProp + " should not scroll");
is(elemToSet[elemProp], 0, "Reading back " + elemToSet.name + "." + elemProp + " after not scrolling");
}
if (otherElem1 == correctElement) {
diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp
index 33f5f7a44..7056658a7 100644
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -259,8 +259,8 @@ TErrorResult<CleanupPolicy>::ThrowJSException(JSContext* cx, JS::Handle<JS::Valu
// Make sure mJSException is initialized _before_ we try to root it. But
// don't set it to exn yet, because we don't want to do that until after we
// root.
- mJSException.setUndefined();
- if (!js::AddRawValueRoot(cx, &mJSException, "TErrorResult::mJSException")) {
+ mJSException.asValueRef().setUndefined();
+ if (!js::AddRawValueRoot(cx, &mJSException.asValueRef(), "TErrorResult::mJSException")) {
// Don't use NS_ERROR_DOM_JS_EXCEPTION, because that indicates we have
// in fact rooted mJSException.
mResult = NS_ERROR_OUT_OF_MEMORY;
@@ -289,7 +289,7 @@ TErrorResult<CleanupPolicy>::SetPendingJSException(JSContext* cx)
mJSException = exception;
// If JS_WrapValue failed, not much we can do about it... No matter
// what, go ahead and unroot mJSException.
- js::RemoveRawValueRoot(cx, &mJSException);
+ js::RemoveRawValueRoot(cx, &mJSException.asValueRef());
mResult = NS_OK;
#ifdef DEBUG
@@ -395,8 +395,8 @@ TErrorResult<CleanupPolicy>::ClearUnionData()
if (IsJSException()) {
JSContext* cx = dom::danger::GetJSContext();
MOZ_ASSERT(cx);
- mJSException.setUndefined();
- js::RemoveRawValueRoot(cx, &mJSException);
+ mJSException.asValueRef().setUndefined();
+ js::RemoveRawValueRoot(cx, &mJSException.asValueRef());
#ifdef DEBUG
mUnionState = HasNothing;
#endif // DEBUG
@@ -439,13 +439,13 @@ TErrorResult<CleanupPolicy>::operator=(TErrorResult<CleanupPolicy>&& aRHS)
} else if (aRHS.IsJSException()) {
JSContext* cx = dom::danger::GetJSContext();
MOZ_ASSERT(cx);
- mJSException.setUndefined();
- if (!js::AddRawValueRoot(cx, &mJSException, "TErrorResult::mJSException")) {
+ mJSException.asValueRef().setUndefined();
+ if (!js::AddRawValueRoot(cx, &mJSException.asValueRef(), "TErrorResult::mJSException")) {
MOZ_CRASH("Could not root mJSException, we're about to OOM");
}
mJSException = aRHS.mJSException;
- aRHS.mJSException.setUndefined();
- js::RemoveRawValueRoot(cx, &aRHS.mJSException);
+ aRHS.mJSException.asValueRef().setUndefined();
+ js::RemoveRawValueRoot(cx, &aRHS.mJSException.asValueRef());
} else if (aRHS.IsDOMException()) {
mDOMExceptionInfo = aRHS.mDOMExceptionInfo;
aRHS.mDOMExceptionInfo = nullptr;
@@ -497,7 +497,7 @@ TErrorResult<CleanupPolicy>::CloneTo(TErrorResult& aRv) const
aRv.mUnionState = HasJSException;
#endif
JSContext* cx = dom::danger::GetJSContext();
- JS::Rooted<JS::Value> exception(cx, mJSException);
+ JS::Rooted<JS::Value> exception(cx, mJSException.asValueRef());
aRv.ThrowJSException(cx, exception);
}
}
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index 3174c37dd..7a6668687 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1069,6 +1069,20 @@ class CGHeaders(CGWrapper):
if parent:
ancestors.append(parent)
interfaceDeps.extend(ancestors)
+
+ # Include parent interface headers needed for jsonifier code.
+ jsonInterfaceParents = []
+ for desc in descriptors:
+ if not desc.operations['Jsonifier']:
+ continue
+ parent = desc.interface.parent
+ while parent:
+ parentDesc = desc.getDescriptor(parent.identifier.name)
+ if parentDesc.operations['Jsonifier']:
+ jsonInterfaceParents.append(parentDesc.interface)
+ parent = parent.parent
+ interfaceDeps.extend(jsonInterfaceParents)
+
bindingIncludes = set(self.getDeclarationFilename(d) for d in interfaceDeps)
# Grab all the implementation declaration files we need.
diff --git a/dom/bindings/ErrorResult.h b/dom/bindings/ErrorResult.h
index c45e7ea3b..7c3fc9e2f 100644
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -461,7 +461,7 @@ private:
// (and deallocated) by SetPendingDOMException.
union {
Message* mMessage; // valid when IsErrorWithMessage()
- JS::Value mJSException; // valid when IsJSException()
+ JS::UninitializedValue mJSException; // valid when IsJSException()
DOMExceptionInfo* mDOMExceptionInfo; // valid when IsDOMException()
};
diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build
index fadaac69b..f1ce9e276 100644
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -139,7 +139,7 @@ FINAL_LIBRARY = 'xul'
SPHINX_TREES['webidl'] = 'docs'
SPHINX_PYTHON_PACKAGE_DIRS += ['mozwebidlcodegen']
-if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']:
+if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_FENNEC'] or CONFIG['MOZ_XULRUNNER']:
# This is needed for Window.webidl
DEFINES['HAVE_SIDEBAR'] = True
diff --git a/dom/bindings/test/test_promise_rejections_from_jsimplemented.html b/dom/bindings/test/test_promise_rejections_from_jsimplemented.html
index 5428030c5..68de079ed 100644
--- a/dom/bindings/test/test_promise_rejections_from_jsimplemented.html
+++ b/dom/bindings/test/test_promise_rejections_from_jsimplemented.html
@@ -93,7 +93,7 @@ doTest@${ourFile}:56:7
checkExn.bind(null, 90, "ReferenceError",
"thereIsNoSuchContentFunction3 is not defined",
undefined, ourFile, 6,
- `doTest/<.then@${ourFile}:90:32
+ `then@${ourFile}:90:32
` + (asyncStack ? `Async*doTest@${ourFile}:89:7\n` + parentFrame : ""))),
t.testPromiseWithDOMExceptionThrowingPromiseInit().then(
ensurePromiseFail.bind(null, 7),
diff --git a/dom/browser-element/mochitest/browserElement_ScrollEvent.js b/dom/browser-element/mochitest/browserElement_ScrollEvent.js
index 5c4b4dcf9..06dc91b86 100644
--- a/dom/browser-element/mochitest/browserElement_ScrollEvent.js
+++ b/dom/browser-element/mochitest/browserElement_ScrollEvent.js
@@ -16,8 +16,8 @@ function runTest() {
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.");
+ ok(Math.round(e.detail.top) == 4000, "top position is correct.");
+ ok(Math.round(e.detail.left) == 4000, "left position is correct.");
SimpleTest.finish();
});
diff --git a/dom/cache/Cache.cpp b/dom/cache/Cache.cpp
index 0d5815edb..b183bf387 100644
--- a/dom/cache/Cache.cpp
+++ b/dom/cache/Cache.cpp
@@ -618,7 +618,7 @@ Cache::AddAll(const GlobalObject& aGlobal,
new FetchHandler(mActor->GetWorkerHolder(), this,
Move(aRequestList), promise);
- RefPtr<Promise> fetchPromise = Promise::All(aGlobal, fetchList, aRv);
+ RefPtr<Promise> fetchPromise = Promise::All(aGlobal.Context(), fetchList, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp
index b0a430fe4..a38c38293 100644
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -92,8 +92,6 @@
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/gfx/PatternHelpers.h"
-#include "mozilla/ipc/DocumentRendererParent.h"
-#include "mozilla/ipc/PDocumentRendererParent.h"
#include "mozilla/layers/PersistentBufferProvider.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Preferences.h"
@@ -107,6 +105,7 @@
#include "mozilla/dom/CanvasPath.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/HTMLVideoElement.h"
+#include "mozilla/dom/SVGImageElement.h"
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/dom/TextMetrics.h"
#include "mozilla/dom/SVGMatrix.h"
@@ -2479,10 +2478,10 @@ CanvasRenderingContext2D::CreatePattern(const CanvasImageSource& aSource,
return nullptr;
}
- Element* htmlElement;
+ Element* element;
if (aSource.IsHTMLCanvasElement()) {
HTMLCanvasElement* canvas = &aSource.GetAsHTMLCanvasElement();
- htmlElement = canvas;
+ element = canvas;
nsIntSize size = canvas->GetSize();
if (size.width == 0 || size.height == 0) {
@@ -2507,7 +2506,7 @@ CanvasRenderingContext2D::CreatePattern(const CanvasImageSource& aSource,
}
RefPtr<CanvasPattern> pat =
- new CanvasPattern(this, srcSurf, repeatMode, htmlElement->NodePrincipal(), canvas->IsWriteOnly(), false);
+ new CanvasPattern(this, srcSurf, repeatMode, element->NodePrincipal(), canvas->IsWriteOnly(), false);
return pat.forget();
}
@@ -2518,11 +2517,19 @@ CanvasRenderingContext2D::CreatePattern(const CanvasImageSource& aSource,
return nullptr;
}
- htmlElement = img;
+ element = img;
+ } else if (aSource.IsSVGImageElement()) {
+ SVGImageElement* img = &aSource.GetAsSVGImageElement();
+ if (img->IntrinsicState().HasState(NS_EVENT_STATE_BROKEN)) {
+ aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return nullptr;
+ }
+
+ element = img;
} else if (aSource.IsHTMLVideoElement()) {
auto& video = aSource.GetAsHTMLVideoElement();
video.MarkAsContentSource(mozilla::dom::HTMLVideoElement::CallerAPI::CREATE_PATTERN);
- htmlElement = &video;
+ element = &video;
} else {
// Special case for ImageBitmap
ImageBitmap& imgBitmap = aSource.GetAsImageBitmap();
@@ -2561,7 +2568,7 @@ CanvasRenderingContext2D::CreatePattern(const CanvasImageSource& aSource,
// The canvas spec says that createPattern should use the first frame
// of animated images
nsLayoutUtils::SurfaceFromElementResult res =
- nsLayoutUtils::SurfaceFromElement(htmlElement,
+ nsLayoutUtils::SurfaceFromElement(element,
nsLayoutUtils::SFE_WANT_FIRST_FRAME, mTarget);
if (!res.GetSourceSurface()) {
@@ -4951,6 +4958,9 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
if (aImage.IsHTMLImageElement()) {
HTMLImageElement* img = &aImage.GetAsHTMLImageElement();
element = img;
+ } else if (aImage.IsSVGImageElement()) {
+ SVGImageElement* img = &aImage.GetAsSVGImageElement();
+ element = img;
} else {
HTMLVideoElement* video = &aImage.GetAsHTMLVideoElement();
video->MarkAsContentSource(mozilla::dom::HTMLVideoElement::CallerAPI::DRAW_IMAGE);
@@ -4977,10 +4987,12 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
return;
}
+#ifdef MOZ_EME
if (video->ContainsRestrictedContent()) {
aError.Throw(NS_ERROR_NOT_AVAILABLE);
return;
}
+#endif
uint16_t readyState;
if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h
index c3ee3bdcb..d5dff8f3b 100644
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -38,8 +38,8 @@ class SourceSurface;
} // namespace gl
namespace dom {
-class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
-typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap CanvasImageSource;
+class HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
+typedef HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap CanvasImageSource;
class ImageData;
class StringOrCanvasGradientOrCanvasPattern;
class OwningStringOrCanvasGradientOrCanvasPattern;
diff --git a/dom/canvas/DocumentRendererChild.cpp b/dom/canvas/DocumentRendererChild.cpp
deleted file mode 100644
index 15dd5fc52..000000000
--- a/dom/canvas/DocumentRendererChild.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/ipc/DocumentRendererChild.h"
-
-#include "base/basictypes.h"
-
-#include "gfx2DGlue.h"
-#include "gfxPattern.h"
-#include "mozilla/gfx/2D.h"
-#include "mozilla/RefPtr.h"
-#include "nsPIDOMWindow.h"
-#include "nsIDOMWindow.h"
-#include "nsIDocShell.h"
-#include "nsIInterfaceRequestorUtils.h"
-#include "nsComponentManagerUtils.h"
-#include "nsCSSParser.h"
-#include "nsPresContext.h"
-#include "nsCOMPtr.h"
-#include "nsColor.h"
-#include "gfxContext.h"
-#include "nsLayoutUtils.h"
-#include "nsContentUtils.h"
-#include "nsCSSValue.h"
-#include "nsRuleNode.h"
-#include "mozilla/gfx/Matrix.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::ipc;
-
-DocumentRendererChild::DocumentRendererChild()
-{}
-
-DocumentRendererChild::~DocumentRendererChild()
-{}
-
-bool
-DocumentRendererChild::RenderDocument(nsPIDOMWindowOuter* window,
- const nsRect& documentRect,
- const mozilla::gfx::Matrix& transform,
- const nsString& aBGColor,
- uint32_t renderFlags,
- bool flushLayout,
- const nsIntSize& renderSize,
- nsCString& data)
-{
- if (flushLayout)
- nsContentUtils::FlushLayoutForTree(window);
-
- RefPtr<nsPresContext> presContext;
- if (window) {
- nsIDocShell* docshell = window->GetDocShell();
- if (docshell) {
- docshell->GetPresContext(getter_AddRefs(presContext));
- }
- }
- if (!presContext)
- return false;
-
- nsCSSParser parser;
- nsCSSValue bgColorValue;
- if (!parser.ParseColorString(aBGColor, nullptr, 0, bgColorValue)) {
- return false;
- }
-
- nscolor bgColor;
- if (!nsRuleNode::ComputeColor(bgColorValue, presContext, nullptr, bgColor)) {
- return false;
- }
-
- // Draw directly into the output array.
- data.SetLength(renderSize.width * renderSize.height * 4);
-
- RefPtr<DrawTarget> dt =
- Factory::CreateDrawTargetForData(BackendType::CAIRO,
- reinterpret_cast<uint8_t*>(data.BeginWriting()),
- IntSize(renderSize.width, renderSize.height),
- 4 * renderSize.width,
- SurfaceFormat::B8G8R8A8);
- if (!dt || !dt->IsValid()) {
- gfxWarning() << "DocumentRendererChild::RenderDocument failed to Factory::CreateDrawTargetForData";
- return false;
- }
- RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
- MOZ_ASSERT(ctx); // already checked the draw target above
- ctx->SetMatrix(mozilla::gfx::ThebesMatrix(transform));
-
- nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
- shell->RenderDocument(documentRect, renderFlags, bgColor, ctx);
-
- return true;
-}
diff --git a/dom/canvas/DocumentRendererChild.h b/dom/canvas/DocumentRendererChild.h
deleted file mode 100644
index 463ba2707..000000000
--- a/dom/canvas/DocumentRendererChild.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_DocumentRendererChild
-#define mozilla_dom_DocumentRendererChild
-
-#include "mozilla/ipc/PDocumentRendererChild.h"
-#include "nsString.h"
-#include "gfxContext.h"
-
-class nsIDOMWindow;
-
-namespace mozilla {
-namespace ipc {
-
-class DocumentRendererChild : public PDocumentRendererChild
-{
-public:
- DocumentRendererChild();
- virtual ~DocumentRendererChild();
-
- bool RenderDocument(nsPIDOMWindowOuter* window,
- const nsRect& documentRect, const gfx::Matrix& transform,
- const nsString& bgcolor,
- uint32_t renderFlags, bool flushLayout,
- const nsIntSize& renderSize, nsCString& data);
-
-private:
-
- DISALLOW_EVIL_CONSTRUCTORS(DocumentRendererChild);
-};
-
-} // namespace ipc
-} // namespace mozilla
-
-#endif
diff --git a/dom/canvas/DocumentRendererParent.cpp b/dom/canvas/DocumentRendererParent.cpp
deleted file mode 100644
index d9578ac4e..000000000
--- a/dom/canvas/DocumentRendererParent.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/ipc/DocumentRendererParent.h"
-
-#include "gfx2DGlue.h"
-#include "mozilla/gfx/2D.h"
-#include "mozilla/gfx/PathHelpers.h"
-#include "mozilla/RefPtr.h"
-#include "nsICanvasRenderingContextInternal.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::ipc;
-
-DocumentRendererParent::DocumentRendererParent()
-{}
-
-DocumentRendererParent::~DocumentRendererParent()
-{}
-
-void DocumentRendererParent::SetCanvasContext(nsICanvasRenderingContextInternal* aCanvas,
- gfxContext* ctx)
-{
- mCanvas = aCanvas;
- mCanvasContext = ctx;
-}
-
-void DocumentRendererParent::DrawToCanvas(const nsIntSize& aSize,
- const nsCString& aData)
-{
- if (!mCanvas || !mCanvasContext)
- return;
-
- DrawTarget* drawTarget = mCanvasContext->GetDrawTarget();
- Rect rect(0, 0, aSize.width, aSize.height);
- MaybeSnapToDevicePixels(rect, *drawTarget, true);
- RefPtr<DataSourceSurface> dataSurface =
- Factory::CreateWrappingDataSourceSurface(reinterpret_cast<uint8_t*>(const_cast<nsCString&>(aData).BeginWriting()),
- aSize.width * 4,
- IntSize(aSize.width, aSize.height),
- SurfaceFormat::B8G8R8A8);
- SurfacePattern pattern(dataSurface, ExtendMode::CLAMP);
- drawTarget->FillRect(rect, pattern);
-
- gfxRect damageRect = mCanvasContext->UserToDevice(ThebesRect(rect));
- mCanvas->Redraw(damageRect);
-}
-
-void
-DocumentRendererParent::ActorDestroy(ActorDestroyReason aWhy)
-{
- // Implement me! Bug 1005139
-}
-
-bool
-DocumentRendererParent::Recv__delete__(const nsIntSize& renderedSize,
- const nsCString& data)
-{
- DrawToCanvas(renderedSize, data);
- return true;
-}
diff --git a/dom/canvas/DocumentRendererParent.h b/dom/canvas/DocumentRendererParent.h
deleted file mode 100644
index 432aa8264..000000000
--- a/dom/canvas/DocumentRendererParent.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_DocumentRendererParent
-#define mozilla_dom_DocumentRendererParent
-
-#include "mozilla/ipc/PDocumentRendererParent.h"
-#include "nsCOMPtr.h"
-#include "nsString.h"
-#include "gfxContext.h"
-
-class nsICanvasRenderingContextInternal;
-
-namespace mozilla {
-namespace ipc {
-
-class DocumentRendererParent : public PDocumentRendererParent
-{
-public:
- DocumentRendererParent();
- virtual ~DocumentRendererParent();
-
- void SetCanvasContext(nsICanvasRenderingContextInternal* aCanvas,
- gfxContext* ctx);
- void DrawToCanvas(const nsIntSize& renderedSize,
- const nsCString& aData);
-
- virtual void ActorDestroy(ActorDestroyReason aWhy) override;
-
- virtual bool Recv__delete__(const nsIntSize& renderedSize,
- const nsCString& data) override;
-
-private:
- nsCOMPtr<nsICanvasRenderingContextInternal> mCanvas;
- RefPtr<gfxContext> mCanvasContext;
-
- DISALLOW_EVIL_CONSTRUCTORS(DocumentRendererParent);
-};
-
-} // namespace ipc
-} // namespace mozilla
-
-#endif
diff --git a/dom/canvas/WebGL2ContextState.cpp b/dom/canvas/WebGL2ContextState.cpp
index be0a7a3cb..e6283b12d 100644
--- a/dom/canvas/WebGL2ContextState.cpp
+++ b/dom/canvas/WebGL2ContextState.cpp
@@ -7,6 +7,7 @@
#include "WebGL2Context.h"
#include "GLContext.h"
+#include "GLScreenBuffer.h"
#include "WebGLBuffer.h"
#include "WebGLContextUtils.h"
#include "WebGLFramebuffer.h"
diff --git a/dom/canvas/WebGLContextDraw.cpp b/dom/canvas/WebGLContextDraw.cpp
index 66fca7689..867e47cbd 100644
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -16,6 +16,7 @@
#include "WebGLRenderbuffer.h"
#include "WebGLShader.h"
#include "WebGLTexture.h"
+#include "WebGLTransformFeedback.h"
#include "WebGLVertexArray.h"
#include "WebGLVertexAttribData.h"
diff --git a/dom/canvas/WebGLContextExtensions.cpp b/dom/canvas/WebGLContextExtensions.cpp
index 28ba14fa2..4a5a23274 100644
--- a/dom/canvas/WebGLContextExtensions.cpp
+++ b/dom/canvas/WebGLContextExtensions.cpp
@@ -89,6 +89,8 @@ bool WebGLContext::IsExtensionSupported(dom::CallerType callerType,
if (allowPrivilegedExts) {
switch (ext) {
+ case WebGLExtensionID::EXT_disjoint_timer_query:
+ return WebGLExtensionDisjointTimerQuery::IsSupported(this);
case WebGLExtensionID::WEBGL_debug_renderer_info:
return true;
case WebGLExtensionID::WEBGL_debug_shaders:
@@ -112,8 +114,6 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
switch (ext) {
// In alphabetical order
// EXT_
- case WebGLExtensionID::EXT_disjoint_timer_query:
- return WebGLExtensionDisjointTimerQuery::IsSupported(this);
case WebGLExtensionID::EXT_texture_filter_anisotropic:
return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic);
diff --git a/dom/canvas/WebGLFramebuffer.cpp b/dom/canvas/WebGLFramebuffer.cpp
index 35efa4f16..0abaf3dd7 100644
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -17,7 +17,9 @@
#include "WebGLContextUtils.h"
#include "WebGLExtensions.h"
#include "WebGLRenderbuffer.h"
+#include "WebGLShader.h"
#include "WebGLTexture.h"
+#include "WebGLObjectModel.h"
namespace mozilla {
@@ -1940,6 +1942,7 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
}
}
+
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLFramebuffer,
mDepthAttachment,
mStencilAttachment,
diff --git a/dom/canvas/WebGLObjectModel.h b/dom/canvas/WebGLObjectModel.h
index e19d2fd8e..b18b790c0 100644
--- a/dom/canvas/WebGLObjectModel.h
+++ b/dom/canvas/WebGLObjectModel.h
@@ -15,6 +15,7 @@ namespace mozilla {
template<typename> class LinkedList;
class WebGLContext;
+
////
// This class is a mixin for objects that are tied to a specific
@@ -355,6 +356,16 @@ ImplCycleCollectionUnlink(mozilla::WebGLRefPtr<T>& field)
template <typename T>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
+ mozilla::WebGLRefPtr<T>& field,
+ const char* name,
+ uint32_t flags = 0)
+{
+ CycleCollectionNoteChild(callback, field.get(), name, flags);
+}
+
+template <typename T>
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
const mozilla::WebGLRefPtr<T>& field,
const char* name,
uint32_t flags = 0)
@@ -362,4 +373,5 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
CycleCollectionNoteChild(callback, field.get(), name, flags);
}
+
#endif
diff --git a/dom/canvas/WebGLProgram.cpp b/dom/canvas/WebGLProgram.cpp
index fa7997f22..9b204358b 100644
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -17,6 +17,7 @@
#include "WebGLTransformFeedback.h"
#include "WebGLUniformLocation.h"
#include "WebGLValidateStrings.h"
+#include "WebGLObjectModel.h"
namespace mozilla {
diff --git a/dom/canvas/WebGLTransformFeedback.cpp b/dom/canvas/WebGLTransformFeedback.cpp
index feec581ea..78e366531 100644
--- a/dom/canvas/WebGLTransformFeedback.cpp
+++ b/dom/canvas/WebGLTransformFeedback.cpp
@@ -8,6 +8,7 @@
#include "GLContext.h"
#include "mozilla/dom/WebGL2RenderingContextBinding.h"
#include "WebGL2Context.h"
+#include "WebGLProgram.h"
namespace mozilla {
diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build
index 2b2ceba52..f7555b33d 100644
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -25,11 +25,6 @@ EXPORTS += [
'nsICanvasRenderingContextInternal.h',
]
-EXPORTS.mozilla.ipc += [
- 'DocumentRendererChild.h',
- 'DocumentRendererParent.h',
-]
-
EXPORTS.mozilla.dom += [
'CanvasGradient.h',
'CanvasPath.h',
@@ -52,8 +47,6 @@ UNIFIED_SOURCES += [
'CanvasRenderingContext2D.cpp',
'CanvasRenderingContextHelper.cpp',
'CanvasUtils.cpp',
- 'DocumentRendererChild.cpp',
- 'DocumentRendererParent.cpp',
'ImageBitmap.cpp',
'ImageBitmapColorUtils.cpp',
'ImageBitmapRenderingContext.cpp',
@@ -162,7 +155,7 @@ SOURCES += [
]
# Suppress warnings from third-party code.
-if CONFIG['CLANG_CXX']:
+if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']:
SOURCES['MurmurHash3.cpp'].flags += ['-Wno-implicit-fallthrough']
LOCAL_INCLUDES += [
diff --git a/dom/canvas/test/webgl-mochitest/mochitest.ini b/dom/canvas/test/webgl-mochitest/mochitest.ini
index d5bc8701d..ddd0dd762 100644
--- a/dom/canvas/test/webgl-mochitest/mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest/mochitest.ini
@@ -14,7 +14,7 @@ fail-if = (os == 'android')
[ensure-exts/test_EXT_color_buffer_half_float.html]
fail-if = (os == 'android')
[ensure-exts/test_EXT_disjoint_timer_query.html]
-fail-if = (os == 'android') || (os == 'mac') || (os == 'win' && os_version == '5.1')
+fail-if = 1
[ensure-exts/test_EXT_frag_depth.html]
fail-if = (os == 'android')
[ensure-exts/test_EXT_sRGB.html]
diff --git a/dom/console/Console.cpp b/dom/console/Console.cpp
index 9ede26501..ff5a92167 100644..100755
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -30,6 +30,7 @@
#include "nsContentUtils.h"
#include "nsDocShell.h"
#include "nsProxyRelease.h"
+#include "mozilla/TimerClamping.h"
#include "mozilla/ConsoleTimelineMarker.h"
#include "mozilla/TimestampTimelineMarker.h"
@@ -1335,10 +1336,7 @@ Console::MethodInternal(JSContext* aCx, MethodName aMethodName,
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
- TimeDuration duration =
- mozilla::TimeStamp::Now() - workerPrivate->NowBaseTimeStamp();
-
- monotonicTimer = duration.ToMilliseconds();
+ monotonicTimer = workerPrivate->TimeStampToDOMHighRes(TimeStamp::Now());
}
}
diff --git a/dom/console/Console.h b/dom/console/Console.h
index b334d79f9..2f375c8eb 100644
--- a/dom/console/Console.h
+++ b/dom/console/Console.h
@@ -258,9 +258,8 @@ private:
// the max number of timers is reached.
// * aCx - the JSContext rooting aName.
// * aName - this is (should be) the name of the timer as JS::Value.
- // * aTimestamp - the monotonicTimer for this context (taken from
- // window->performance.now() or from Now() -
- // workerPrivate->NowBaseTimeStamp() in workers.
+ // * aTimestamp - the monotonicTimer for this context taken from
+ // performance.now().
// * aTimerLabel - This label will be populated with the aName converted to a
// string.
// * aTimerValue - the StartTimer value stored into (or taken from)
@@ -290,9 +289,8 @@ private:
// the aName timer doesn't exist in the mTimerRegistry.
// * aCx - the JSContext rooting aName.
// * aName - this is (should be) the name of the timer as JS::Value.
- // * aTimestamp - the monotonicTimer for this context (taken from
- // window->performance.now() or from Now() -
- // workerPrivate->NowBaseTimeStamp() in workers.
+ // * aTimestamp - the monotonicTimer for this context taken from
+ // performance.now().
// * aTimerLabel - This label will be populated with the aName converted to a
// string.
// * aTimerDuration - the difference between aTimestamp and when the timer
diff --git a/dom/crypto/WebCryptoTask.cpp b/dom/crypto/WebCryptoTask.cpp
index 57a7da186..f5fc7b5bc 100644
--- a/dom/crypto/WebCryptoTask.cpp
+++ b/dom/crypto/WebCryptoTask.cpp
@@ -716,6 +716,11 @@ private:
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
}
+ // Check whether the integer addition would overflow.
+ if (std::numeric_limits<CryptoBuffer::size_type>::max() - 16 < mData.Length()) {
+ return NS_ERROR_DOM_DATA_ERR;
+ }
+
// Initialize the output buffer (enough space for padding / a full tag)
uint32_t dataLen = mData.Length();
uint32_t maxLen = dataLen + 16;
diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp
index a85a0d66b..4b9776c0a 100644..100755
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -32,6 +32,7 @@
#include "nsJSEnvironment.h"
#include "nsLayoutUtils.h"
#include "nsPIWindowRoot.h"
+#include "mozilla/TimerClamping.h"
#include "WorkerPrivate.h"
namespace mozilla {
@@ -411,8 +412,17 @@ Event::Constructor(const GlobalObject& aGlobal,
ErrorResult& aRv)
{
nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
- RefPtr<Event> e = new Event(t, nullptr, nullptr);
- bool trusted = e->Init(t);
+ return Constructor(t, aType, aParam);
+}
+
+// static
+already_AddRefed<Event>
+Event::Constructor(EventTarget* aEventTarget,
+ const nsAString& aType,
+ const EventInit& aParam)
+{
+ RefPtr<Event> e = new Event(aEventTarget, nullptr, nullptr);
+ bool trusted = e->Init(aEventTarget);
e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
e->SetTrusted(trusted);
e->SetComposed(aParam.mComposed);
@@ -845,6 +855,25 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
}
}
break;
+ case ePointerEventClass:
+ if (aEvent->IsTrusted() &&
+ aEvent->AsPointerEvent()->button == WidgetMouseEvent::eLeftButton) {
+ switch(aEvent->mMessage) {
+ case ePointerUp:
+ if (PopupAllowedForEvent("pointerup")) {
+ abuse = openControlled;
+ }
+ break;
+ case ePointerDown:
+ if (PopupAllowedForEvent("pointerdown")) {
+ abuse = openControlled;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
case eFormEventClass:
// For these following events only allow popups if they're
// triggered while handling user input. See
@@ -1085,6 +1114,12 @@ Event::DefaultPrevented(JSContext* aCx) const
double
Event::TimeStamp() const
{
+ return TimerClamping::ReduceMsTimeValue(TimeStampImpl());
+}
+
+double
+Event::TimeStampImpl() const
+{
if (!sReturnHighResTimeStamp) {
return static_cast<double>(mEvent->mTime);
}
@@ -1111,16 +1146,11 @@ Event::TimeStamp() const
return perf->GetDOMTiming()->TimeStampToDOMHighRes(mEvent->mTimeStamp);
}
- // For dedicated workers, we should make times relative to the navigation
- // start of the document that created the worker, which is the same as the
- // timebase for performance.now().
workers::WorkerPrivate* workerPrivate =
workers::GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
- TimeDuration duration =
- mEvent->mTimeStamp - workerPrivate->NowBaseTimeStamp();
- return duration.ToMilliseconds();
+ return workerPrivate->TimeStampToDOMHighRes(mEvent->mTimeStamp);
}
bool
@@ -1202,7 +1232,7 @@ Event::Deserialize(const IPC::Message* aMsg, PickleIterator* aIter)
}
NS_IMETHODIMP_(void)
-Event::SetOwner(mozilla::dom::EventTarget* aOwner)
+Event::SetOwner(EventTarget* aOwner)
{
mOwner = nullptr;
diff --git a/dom/events/Event.h b/dom/events/Event.h
index 4ac6a68d5..0817aa809 100644..100755
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -62,6 +62,7 @@ private:
void ConstructorInit(EventTarget* aOwner,
nsPresContext* aPresContext,
WidgetEvent* aEvent);
+ double TimeStampImpl() const;
public:
static Event* FromSupports(nsISupports* aSupports)
@@ -141,6 +142,10 @@ public:
LayoutDeviceIntPoint aPoint,
CSSIntPoint aDefaultPoint);
+ static already_AddRefed<Event> Constructor(EventTarget* aEventTarget,
+ const nsAString& aType,
+ const EventInit& aParam);
+
static already_AddRefed<Event> Constructor(const GlobalObject& aGlobal,
const nsAString& aType,
const EventInit& aParam,
diff --git a/dom/events/EventDispatcher.cpp b/dom/events/EventDispatcher.cpp
index a1d0675ae..65f01844b 100644
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -1056,6 +1056,11 @@ EventDispatcher::CreateEvent(EventTarget* aOwner,
LOG_EVENT_CREATION(STORAGEEVENT);
return NS_NewDOMStorageEvent(aOwner);
}
+ if (aEventType.LowerCaseEqualsLiteral("focusevent")) {
+ RefPtr<Event> event = NS_NewDOMFocusEvent(aOwner, aPresContext, nullptr);
+ event->MarkUninitialized();
+ return event.forget();
+ }
#undef LOG_EVENT_CREATION
diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp
index c8db4f2a1..a8c48ede8 100644
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -996,14 +996,12 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
}
aListener = nullptr;
- uint32_t lineNo = 0;
nsAutoCString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
MOZ_ASSERT(body);
MOZ_ASSERT(aElement);
nsIURI *uri = aElement->OwnerDoc()->GetDocumentURI();
if (uri) {
uri->GetSpec(url);
- lineNo = 1;
}
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mTarget);
@@ -1073,8 +1071,9 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
return NS_ERROR_FAILURE;
}
JS::CompileOptions options(cx);
+ // Use line 0 to make the function body starts from line 1.
options.setIntroductionType("eventHandler")
- .setFileAndLine(url.get(), lineNo)
+ .setFileAndLine(url.get(), 0)
.setVersion(JSVERSION_DEFAULT)
.setElement(&v.toObject())
.setElementAttributeName(jsStr);
diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h
index d66c20b4b..891035c43 100644
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -678,6 +678,10 @@ DOCUMENT_ONLY_EVENT(selectionchange,
eSelectionChange,
EventNameType_HTMLXUL,
eBasicEventClass)
+DOCUMENT_ONLY_EVENT(visibilitychange,
+ eVisibilityChange,
+ EventNameType_HTMLXUL,
+ eBasicEventClass)
NON_IDL_EVENT(MozMouseHittest,
eMouseHitTest,
diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp
index 25bf96078..7bbfe21b7 100644
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -732,6 +732,9 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
FlushPendingEvents(aPresContext);
break;
}
+ case ePointerGotCapture:
+ GenerateMouseEnterExit(mouseEvent);
+ break;
case eDragStart:
if (Prefs::ClickHoldContextMenu()) {
// an external drag gesture event came in, not generated internally
@@ -3891,10 +3894,7 @@ CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
newPointerEvent->mWidth = sourcePointer->mWidth;
newPointerEvent->mHeight = sourcePointer->mHeight;
newPointerEvent->inputSource = sourcePointer->inputSource;
- newPointerEvent->relatedTarget =
- nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId)
- ? nullptr
- : aRelatedContent;
+ newPointerEvent->relatedTarget = aRelatedContent;
aNewEvent = newPointerEvent.forget();
} else {
aNewEvent =
@@ -4035,7 +4035,7 @@ public:
}
}
- ~EnterLeaveDispatcher()
+ void Dispatch()
{
if (mEventMessage == eMouseEnter || mEventMessage == ePointerEnter) {
for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
@@ -4107,19 +4107,14 @@ EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
SetContentState(nullptr, NS_EVENT_STATE_HOVER);
}
- // In case we go out from capturing element (retargetedByPointerCapture is true)
- // we should dispatch ePointerLeave event and only for capturing element.
- RefPtr<nsIContent> movingInto = aMouseEvent->retargetedByPointerCapture
- ? wrapper->mLastOverElement->GetParent()
- : aMovingInto;
-
EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement,
- movingInto, aMouseEvent,
+ aMovingInto, aMouseEvent,
isPointer ? ePointerLeave : eMouseLeave);
// Fire mouseout
DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? ePointerOut : eMouseOut,
wrapper->mLastOverElement, aMovingInto);
+ leaveDispatcher.Dispatch();
wrapper->mLastOverFrame = nullptr;
wrapper->mLastOverElement = nullptr;
@@ -4134,13 +4129,9 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
{
NS_ASSERTION(aContent, "Mouse must be over something");
- // If pointer capture is set, we should suppress pointerover/pointerenter events
- // for all elements except element which have pointer capture.
- bool dispatch = !aMouseEvent->retargetedByPointerCapture;
-
OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
- if (wrapper->mLastOverElement == aContent && dispatch)
+ if (wrapper->mLastOverElement == aContent)
return;
// Before firing mouseover, check for recursion
@@ -4152,9 +4143,10 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
// content associated with our subdocument.
EnsureDocument(mPresContext);
if (nsIDocument *parentDoc = mDocument->GetParentDocument()) {
- if (nsIContent *docContent = parentDoc->FindContentForSubDocument(mDocument)) {
+ if (nsCOMPtr<nsIContent> docContent =
+ parentDoc->FindContentForSubDocument(mDocument)) {
if (nsIPresShell *parentShell = parentDoc->GetShell()) {
- EventStateManager* parentESM =
+ RefPtr<EventStateManager> parentESM =
parentShell->GetPresContext()->EventStateManager();
parentESM->NotifyMouseOver(aMouseEvent, docContent);
}
@@ -4162,7 +4154,7 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
}
// Firing the DOM event in the parent document could cause all kinds
// of havoc. Reverify and take care.
- if (wrapper->mLastOverElement == aContent && dispatch)
+ if (wrapper->mLastOverElement == aContent)
return;
// Remember mLastOverElement as the related content for the
@@ -4171,11 +4163,9 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
bool isPointer = aMouseEvent->mClass == ePointerEventClass;
- Maybe<EnterLeaveDispatcher> enterDispatcher;
- if (dispatch) {
- enterDispatcher.emplace(this, aContent, lastOverElement, aMouseEvent,
- isPointer ? ePointerEnter : eMouseEnter);
- }
+ EnterLeaveDispatcher enterDispatcher(this, aContent, lastOverElement,
+ aMouseEvent,
+ isPointer ? ePointerEnter : eMouseEnter);
NotifyMouseOut(aMouseEvent, aContent);
@@ -4187,17 +4177,13 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
SetContentState(aContent, NS_EVENT_STATE_HOVER);
}
- if (dispatch) {
- // Fire mouseover
- wrapper->mLastOverFrame =
- DispatchMouseOrPointerEvent(aMouseEvent,
- isPointer ? ePointerOver : eMouseOver,
- aContent, lastOverElement);
- wrapper->mLastOverElement = aContent;
- } else {
- wrapper->mLastOverFrame = nullptr;
- wrapper->mLastOverElement = nullptr;
- }
+ // Fire mouseover
+ wrapper->mLastOverFrame =
+ DispatchMouseOrPointerEvent(aMouseEvent,
+ isPointer ? ePointerOver : eMouseOver,
+ aContent, lastOverElement);
+ enterDispatcher.Dispatch();
+ wrapper->mLastOverElement = aContent;
// Turn recursion protection back off
wrapper->mFirstOverEventElement = nullptr;
@@ -4290,6 +4276,7 @@ EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent)
MOZ_FALLTHROUGH;
case ePointerMove:
case ePointerDown:
+ case ePointerGotCapture:
{
// Get the target content target (mousemove target == mouseover target)
nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
diff --git a/dom/events/PointerEvent.cpp b/dom/events/PointerEvent.cpp
index f53739863..fbaa0f737 100644
--- a/dom/events/PointerEvent.cpp
+++ b/dom/events/PointerEvent.cpp
@@ -93,8 +93,10 @@ PointerEvent::Constructor(EventTarget* aOwner,
widgetEvent->mWidth = aParam.mWidth;
widgetEvent->mHeight = aParam.mHeight;
widgetEvent->pressure = aParam.mPressure;
+ widgetEvent->tangentialPressure = aParam.mTangentialPressure;
widgetEvent->tiltX = aParam.mTiltX;
widgetEvent->tiltY = aParam.mTiltY;
+ widgetEvent->twist = aParam.mTwist;
widgetEvent->inputSource = ConvertStringToPointerType(aParam.mPointerType);
widgetEvent->mIsPrimary = aParam.mIsPrimary;
widgetEvent->buttons = aParam.mButtons;
@@ -145,6 +147,12 @@ PointerEvent::Pressure()
return mEvent->AsPointerEvent()->pressure;
}
+float
+PointerEvent::TangentialPressure()
+{
+ return mEvent->AsPointerEvent()->tangentialPressure;
+}
+
int32_t
PointerEvent::TiltX()
{
@@ -157,6 +165,12 @@ PointerEvent::TiltY()
return mEvent->AsPointerEvent()->tiltY;
}
+int32_t
+PointerEvent::Twist()
+{
+ return mEvent->AsPointerEvent()->twist;
+}
+
bool
PointerEvent::IsPrimary()
{
diff --git a/dom/events/PointerEvent.h b/dom/events/PointerEvent.h
index 62c5a0c36..12d4941dc 100644
--- a/dom/events/PointerEvent.h
+++ b/dom/events/PointerEvent.h
@@ -44,8 +44,10 @@ public:
int32_t Width();
int32_t Height();
float Pressure();
+ float TangentialPressure();
int32_t TiltX();
int32_t TiltY();
+ int32_t Twist();
bool IsPrimary();
void GetPointerType(nsAString& aPointerType);
};
diff --git a/dom/events/test/pointerevents/mochitest.ini b/dom/events/test/pointerevents/mochitest.ini
index 58eae12fe..af762feb2 100644
--- a/dom/events/test/pointerevents/mochitest.ini
+++ b/dom/events/test/pointerevents/mochitest.ini
@@ -6,6 +6,14 @@ support-files =
pointerevent_styles.css
pointerevent_support.js
+[test_bug1285128.html]
+[test_bug1293174_implicit_pointer_capture_for_touch_1.html]
+ support-files = bug1293174_implicit_pointer_capture_for_touch_1.html
+[test_bug1293174_implicit_pointer_capture_for_touch_2.html]
+ support-files = bug1293174_implicit_pointer_capture_for_touch_2.html
+[test_bug1323158.html]
+[test_empty_file.html]
+ disabled = disabled # Bug 1150091 - Issue with support-files
[test_pointerevent_attributes_mouse-manual.html]
support-files = pointerevent_attributes_mouse-manual.html
[test_pointerevent_capture_mouse-manual.html]
@@ -143,10 +151,5 @@ support-files =
pointerevent_touch-action-span-test_touch-manual.html
pointerevent_touch-action-svg-test_touch-manual.html
pointerevent_touch-action-table-test_touch-manual.html
-[test_bug1285128.html]
-[test_bug1293174_implicit_pointer_capture_for_touch_1.html]
- support-files = bug1293174_implicit_pointer_capture_for_touch_1.html
-[test_bug1293174_implicit_pointer_capture_for_touch_2.html]
- support-files = bug1293174_implicit_pointer_capture_for_touch_2.html
-[test_empty_file.html]
- disabled = disabled # Bug 1150091 - Issue with support-files
+[test_trigger_fullscreen_by_pointer_events.html]
+[test_trigger_popup_by_pointer_events.html]
diff --git a/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html b/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html
index f4d5573ed..2614790f3 100644
--- a/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html
+++ b/dom/events/test/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!doctype html>
<html>
<head>
<title>Pointer Event: releasePointerCapture() - subsequent events follow normal hitting testing mechanisms</title>
@@ -12,19 +12,27 @@
<script type="text/javascript" src="pointerevent_support.js"></script>
<script type="text/javascript" src="mochitest_support_internal.js"></script>
<script type="text/javascript">
+ var test_pointerEvent;
var detected_pointertypes = {};
- var test_pointerEvent = async_test("lostpointercapture: subsequent events to target."); // set up test harness
- var suppressedEventsFail = false;
- // showPointerTypes is defined in pointerevent_support.js
- // Requirements: the callback function will reference the test_pointerEvent object and
- // will fail unless the async_test is created with the var name "test_pointerEvent".
- add_completion_callback(showPointerTypes);
-
- var captured_event;
+ var captured_event = null;
+ var test_done = false;
+ var overEnterEventsFail = false;
+ var outLeaveEventsFail = false;
var f_gotPointerCapture = false;
var f_lostPointerCapture = false;
+ function resetTestState() {
+ captured_event = null;
+ test_done = false;
+ overEnterEventsFail = false;
+ outLeaveEventsFail = false;
+ f_gotPointerCapture = false;
+ f_lostPointerCapture = false;
+ }
+
function listenerEventHandler(event) {
+ if (test_done)
+ return;
detected_pointertypes[event.pointerType] = true;
if (event.type == "gotpointercapture") {
f_gotPointerCapture = true;
@@ -35,12 +43,20 @@
f_gotPointerCapture = false;
check_PointerEvent(event);
}
- else if(event.type == "pointerover" || event.type == "pointerenter" || event.type == "pointerout" || event.type == "pointerleave") {
- if(!suppressedEventsFail) {
+ else if(event.type == "pointerover" || event.type == "pointerenter") {
+ if(captured_event && !overEnterEventsFail) {
+ test(function() {
+ assert_false(f_gotPointerCapture, "pointerover/enter should be received before the target receives gotpointercapture even when the pointer is not over it.");
+ }, expectedPointerType + " pointerover/enter should be received before the target receives gotpointercapture even when the pointer is not over it.");
+ overEnterEventsFail = true;
+ }
+ }
+ else if(event.type == "pointerout" || event.type == "pointerleave") {
+ if(!outLeaveEventsFail) {
test(function() {
- assert_true(false, "Suppressed events were received");
- }, "Suppressed events were received");
- suppressedEventsFail = true;
+ assert_true(f_lostPointerCapture, "pointerout/leave should not be received unless the target just lost the capture.");
+ }, expectedPointerType + " pointerout/leave should not be received unless the target just lost the capture.");
+ outLeaveEventsFail = true;
}
}
else if (event.pointerId == captured_event.pointerId) {
@@ -50,19 +66,21 @@
}
else {
// if any other events are received after releaseCapture, then the test fails
- test_pointerEvent.step(function () {
- assert_true(false, event.target.id + "-" + event.type + " should be handled by target element handler");
- });
+ test(function () {
+ assert_unreached(event.target.id + "-" + event.type + " should be handled by target element handler");
+ }, expectedPointerType + " No other events should be recieved by capturing node after release");
}
}
}
function targetEventHandler(event) {
+ if (test_done)
+ return;
if (f_gotPointerCapture) {
if(event.type != "pointerout" && event.type != "pointerleave") {
- test_pointerEvent.step(function () {
- assert_true(false, "The Target element should not have received any events while capture is active. Event recieved:" + event.type + ". ");
- });
+ test(function () {
+ assert_unreached("The Target element should not have received any events while capture is active. Event recieved:" + event.type + ". ");
+ }, expectedPointerType + " The target element should not receive any events while capture is active");
}
}
@@ -77,12 +95,14 @@
assert_equals(event.pointerId, captured_event.pointerId, "pointerID is same for event captured and after release");
});
if (event.type == "pointerup") {
+ test_done = true;
test_pointerEvent.done(); // complete test
}
}
}
function run() {
+ test_pointerEvent = setup_pointerevent_test("got/lost pointercapture: subsequent events to target", ALL_POINTERS); // set up test harness
var listener = document.getElementById("listener");
var target0 = document.getElementById("target0");
target0.style["touchAction"] = "none";
@@ -96,18 +116,19 @@
</script>
</head>
<body onload="run()">
+ <h2 id="pointerTypeDescription"></h2>
<div id="listener"></div>
<h1>Pointer Event: releasePointerCapture() - subsequent events follow normal hitting testing mechanisms</h1>
<!--
<h4>
Test Description:
+ Use your pointer and press down in the black box. Then move around in the box and release your pointer.
After invoking the releasePointerCapture method on an element, subsequent events for the specified
- pointer must follow normal hit testing mechanisms for determining the event target
+ pointer must follow normal hit testing mechanisms for determining the event target.
</h4>
<br />
-->
<div id="target0">
- Use mouse, touch or pen to contact here and move around.
</div>
<div id="complete-notice">
<p>Test complete: Scroll to Summary to view Pass/Fail Results.</p>
diff --git a/dom/events/test/pointerevents/test_bug1285128.html b/dom/events/test/pointerevents/test_bug1285128.html
index f7f1eb698..9577940c1 100644
--- a/dom/events/test/pointerevents/test_bug1285128.html
+++ b/dom/events/test/pointerevents/test_bug1285128.html
@@ -13,7 +13,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1285128
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1285128">Mozilla Bug 1285128</a>
<p id="display"></p>
-<div id="target0" style="width: 200px; height: 200px; background: green"></div>
+<div id="target0" style="width: 50px; height: 50px; background: green"></div>
+<div id="target1" style="width: 50px; height: 50px; background: red"></div>
<script type="text/javascript">
/** Test for Bug 1285128 **/
@@ -31,7 +32,7 @@ function runTests() {
}, false);
});
- target0.addEventListener("mouseenter", () => {
+ target1.addEventListener("mouseup", () => {
ok(!receivedPointerEvents, "synthesized mousemove should not trigger any pointer events");
SimpleTest.finish();
});
@@ -39,6 +40,8 @@ function runTests() {
synthesizeMouseAtCenter(target0, { type: "mousemove",
inputSource: SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE,
isWidgetEventSynthesized: true });
+ synthesizeMouseAtCenter(target1, { type: "mousedown" });
+ synthesizeMouseAtCenter(target1, { type: "mouseup" });
}
SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true]]}, runTests);
diff --git a/dom/events/test/pointerevents/test_bug1323158.html b/dom/events/test/pointerevents/test_bug1323158.html
new file mode 100644
index 000000000..fac96c97a
--- /dev/null
+++ b/dom/events/test/pointerevents/test_bug1323158.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1323158
+-->
+<head>
+ <meta charset="utf-8">
+ <title>This is a test to check if target and relatedTarget of mouse events are the same as pointer events</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="content"></p>
+<script type="text/javascript">
+
+/** Test for Bug 1323158 **/
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ let content = document.getElementById('content');
+ let iframe = document.createElement('iframe');
+ iframe.width = 500;
+ iframe.height = 500;
+ content.appendChild(iframe);
+ iframe.contentDocument.body.innerHTML =
+ "<br><div id='target0' style='width: 30px; height: 30px; background: black;'></div>" +
+ "<br><div id='target1' style='width: 30px; height: 30px; background: red;'></div>" +
+ "<br><div id='done' style='width: 30px; height: 30px; background: green;'></div>";
+
+ let target0 = iframe.contentDocument.getElementById("target0");
+ let target1 = iframe.contentDocument.getElementById("target1");
+ let done = iframe.contentDocument.getElementById("done");
+ let pointerBoundaryEvents = ["pointerover", "pointerenter", "pointerleave", "pointerout"];
+ let mouseBoundaryEvents = ["mouseover", "mouseenter", "mouseleave", "mouseout"];
+ let receivedPointerBoundaryEvents = {};
+ let mouseEvent2pointerEvent = {"mouseover": "pointerover",
+ "mouseenter": "pointerenter",
+ "mouseleave": "pointerleave",
+ "mouseout": "pointerout"
+ };
+
+ pointerBoundaryEvents.forEach((event) => {
+ target1.addEventListener(event, (e) => {
+ receivedPointerBoundaryEvents[event] = e;
+ });
+ });
+
+ let attributes = ["target", "relatedTarget"];
+ mouseBoundaryEvents.forEach((event) => {
+ target1.addEventListener(event, (e) => {
+ let correspondingPointerEv = receivedPointerBoundaryEvents[mouseEvent2pointerEvent[event]];
+ ok(correspondingPointerEv, "Should receive " + mouseEvent2pointerEvent[event] + " before " + e.type);
+ if (correspondingPointerEv) {
+ attributes.forEach((attr) => {
+ ok(correspondingPointerEv[attr] == e[attr],
+ attr + " of " + e.type + " should be the same as the correcponding pointer event expect " +
+ correspondingPointerEv[attr] + " got " + e[attr]);
+ });
+ }
+ receivedPointerBoundaryEvents[mouseEvent2pointerEvent[event]] = null;
+ });
+ });
+ target0.addEventListener("pointerdown", (e) => {
+ target1.setPointerCapture(e.pointerId);
+ });
+ done.addEventListener("mouseup", () => {
+ SimpleTest.finish();
+ });
+ let source = SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE;
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(done, 5, 5, { type: "mousedown", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(done, 5, 5, { type: "mouseup", inputSource: source },
+ iframe.contentWindow);
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true]]}, runTests);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html b/dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html
index dc3903592..2b08e2bb8 100644
--- a/dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html
@@ -19,7 +19,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
function executeTest(int_win) {
sendMouseEvent(int_win, "target0", "mousemove");
sendMouseEvent(int_win, "target1", "mousemove");
- sendMouseEvent(int_win, "btnCapture", "mousedown", {button:1});
+ sendMouseEvent(int_win, "btnCapture", "mousemove");
+ sendMouseEvent(int_win, "btnCapture", "mousedown");
sendMouseEvent(int_win, "target1", "mousemove");
sendMouseEvent(int_win, "target0", "mousemove");
sendMouseEvent(int_win, "target1", "mousemove");
diff --git a/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_events_to_original_target-manual.html b/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_events_to_original_target-manual.html
index cbf91df74..35350e016 100644
--- a/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_events_to_original_target-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_events_to_original_target-manual.html
@@ -17,9 +17,30 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
runTestInNewWindow("pointerevent_releasepointercapture_events_to_original_target-manual.html");
}
function executeTest(int_win) {
- sendTouchEvent(int_win, "target0", "touchstart");
- sendTouchEvent(int_win, "target0", "touchmove");
- sendTouchEvent(int_win, "target0", "touchend");
+ // Synthesize mouse events to run this test.
+ sendMouseEvent(int_win, "target0", "mousemove");
+ sendMouseEvent(int_win, "target0", "mousedown");
+ sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1});
+ sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1});
+ sendMouseEvent(int_win, "target0", "mouseup");
+
+ window.addEventListener("message", function(aEvent) {
+ if (aEvent.data == "Test Touch") {
+ // Synthesize touch events to run this test.
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchmove");
+ sendTouchEvent(int_win, "target0", "touchend");
+ window.postMessage("Test Pen", "*");
+ } else if (aEvent.data == "Test Pen") {
+ // Synthesize pen events to run this test.
+ sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ sendMouseEvent(int_win, "target0", "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1});
+ sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1});
+ sendMouseEvent(int_win, "target0", "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ }
+ });
+ window.postMessage("Test Touch", "*");
}
</script>
</head>
diff --git a/dom/events/test/pointerevents/test_pointerevent_setpointercapture_relatedtarget-manual.html b/dom/events/test/pointerevents/test_pointerevent_setpointercapture_relatedtarget-manual.html
index 0883d616b..09e97ec97 100644
--- a/dom/events/test/pointerevents/test_pointerevent_setpointercapture_relatedtarget-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_setpointercapture_relatedtarget-manual.html
@@ -19,8 +19,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
function executeTest(int_win) {
sendMouseEvent(int_win, "target1", "mousemove");
sendMouseEvent(int_win, "btnCapture", "mousedown");
- sendMouseEvent(int_win, "target1", "mousemove");
- sendMouseEvent(int_win, "target1", "mouseup");
+ sendMouseEvent(int_win, "btnCapture", "mousemove");
+ sendMouseEvent(int_win, "btnCapture", "mouseup");
}
</script>
</head>
diff --git a/dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html b/dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html
new file mode 100644
index 000000000..53d390996
--- /dev/null
+++ b/dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for triggering Fullscreen by pointer events</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+function startTest() {
+ let win = window.open("data:text/html,<body><div id='target' style='width: 50px; height: 50px; background: green'></div></body>", "_blank");
+ win.addEventListener("load", () => {
+ let target = win.document.getElementById("target");
+ target.addEventListener("pointerdown", () => {
+ target.requestFullscreen();
+ target.addEventListener("pointerdown", () => {
+ win.document.exitFullscreen();
+ }, {once: true});
+ }, {once: true});
+
+ win.document.addEventListener("fullscreenchange", () => {
+ if (win.document.fullscreenElement) {
+ ok(win.document.fullscreenElement, target, "fullscreenElement should be the div element");
+ // synthesize mouse events to generate pointer events and leave full screen.
+ synthesizeMouseAtCenter(target, { type: "mousedown" }, win);
+ synthesizeMouseAtCenter(target, { type: "mouseup" }, win);
+ } else {
+ win.close();
+ SimpleTest.finish();
+ }
+ });
+ // Make sure our window is focused before starting the test
+ SimpleTest.waitForFocus(() => {
+ // synthesize mouse events to generate pointer events and enter full screen.
+ synthesizeMouseAtCenter(target, { type: "mousedown" }, win);
+ synthesizeMouseAtCenter(target, { type: "mouseup" }, win);
+ }, win);
+ });
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["full-screen-api.unprefix.enabled", true],
+ ["full-screen-api.allow-trusted-requests-only", false],
+ ["dom.w3c_pointer_events.enabled", true]
+ ]
+ }, startTest);
+});
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_trigger_popup_by_pointer_events.html b/dom/events/test/pointerevents/test_trigger_popup_by_pointer_events.html
new file mode 100644
index 000000000..cda279e26
--- /dev/null
+++ b/dom/events/test/pointerevents/test_trigger_popup_by_pointer_events.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for triggering popup by pointer events</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div id="target" style="width: 50px; height: 50px; background: green"></div>
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+function sendMouseEvent(element, eventName, listenEventName, handler) {
+ element.addEventListener(listenEventName, handler, {once: true});
+ synthesizeMouseAtCenter(element, {type: eventName});
+}
+
+function checkAllowOpenPopup(e) {
+ let w = window.open("about:blank");
+ ok(w, "Should allow popup in the " + e.type + " listener");
+ if (w) {
+ w.close();
+ }
+}
+
+function checkBlockOpenPopup(e) {
+ let w = window.open("about:blank");
+ ok(!w, "Should block popup in the " + e.type + " listener");
+ if (w) {
+ w.close();
+ }
+}
+
+function startTest() {
+ let target = document.getElementById("target");
+ // By default, only allow opening popup in the pointerup listener.
+ sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mousedown", "pointerdown", checkBlockOpenPopup);
+ sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", "pointerup", checkAllowOpenPopup);
+ SpecialPowers.pushPrefEnv({"set": [["dom.popup_allowed_events",
+ "pointerdown pointerup"]]}, () => {
+ // Adding pointerdown to preference should work
+ sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mousedown", "pointerdown", checkAllowOpenPopup);
+ sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", "pointerup", checkAllowOpenPopup);
+ SpecialPowers.pushPrefEnv({"set": [["dom.popup_allowed_events",
+ "pointerdown pointerup pointermove"]]}, () => {
+ // Adding pointermove to preference should be no effect.
+ sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mousedown", "pointerdown", checkAllowOpenPopup);
+ sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", "pointerup", checkAllowOpenPopup);
+ SimpleTest.finish();
+ });
+ });
+}
+
+const DENY_ACTION = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION;
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPermissions([{'type': 'popup', 'allow': DENY_ACTION,
+ 'context': document}], () => {
+ SpecialPowers.pushPrefEnv({
+ "set": [["dom.w3c_pointer_events.enabled", true]]
+ }, startTest);
+ });
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_eventTimeStamp.html b/dom/events/test/test_eventTimeStamp.html
index a3d096432..056203e92 100644
--- a/dom/events/test/test_eventTimeStamp.html
+++ b/dom/events/test/test_eventTimeStamp.html
@@ -17,7 +17,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=77992
<script type="text/js-worker" id="worker-src">
// Simply returns the event timestamp
onmessage = function(evt) {
- postMessage(evt.timeStamp);
+ postMessage(evt.timeStamp + performance.timeOrigin);
}
</script>
<script type="text/js-worker" id="shared-worker-src">
@@ -25,7 +25,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=77992
onconnect = function(evt) {
var port = evt.ports[0];
port.onmessage = function(messageEvt) {
- port.postMessage(messageEvt.timeStamp);
+ port.postMessage(messageEvt.timeStamp + performance.timeOrigin);
};
};
</script>
@@ -57,11 +57,11 @@ function testRegularEvents() {
finishTests();
return;
}
- var timeBeforeEvent = window.performance.now();
- window.addEventListener("load", function(evt) {
- var timeAfterEvent = window.performance.now();
- ok(evt.timeStamp > timeBeforeEvent &&
- evt.timeStamp < timeAfterEvent,
+ var timeBeforeEvent = performance.now();
+ addEventListener("load", function(evt) {
+ var timeAfterEvent = performance.now();
+ ok(evt.timeStamp >= timeBeforeEvent &&
+ evt.timeStamp <= timeAfterEvent,
"Event timestamp (" + evt.timeStamp + ") is in expected range: (" +
timeBeforeEvent + ", " + timeAfterEvent + ")");
testWorkerEvents();
@@ -71,18 +71,18 @@ function testRegularEvents() {
function testWorkerEvents() {
var blob = new Blob([ document.getElementById("worker-src").textContent ],
{ type: "text/javascript" });
- var worker = new Worker(window.URL.createObjectURL(blob));
+ var worker = new Worker(URL.createObjectURL(blob));
worker.onmessage = function(evt) {
- var timeAfterEvent = window.performance.now();
- ok(evt.data > timeBeforeEvent &&
- evt.data < timeAfterEvent,
- "Event timestamp in dedicated worker (" + evt.data +
- ") is in expected range: (" +
- timeBeforeEvent + ", " + timeAfterEvent + ")");
+ var timeAfterEvent = performance.now() + performance.timeOrigin;
+ ok(evt.data >= timeBeforeEvent &&
+ evt.data <= timeAfterEvent,
+ // "Event timestamp in dedicated worker (" + evt.data +
+ // ") is in expected range: (" +
+ // timeBeforeEvent + ", " + timeAfterEvent + ")");
worker.terminate();
testSharedWorkerEvents();
};
- var timeBeforeEvent = window.performance.now();
+ var timeBeforeEvent = performance.now() + performance.timeOrigin;
worker.postMessage("");
}
@@ -92,16 +92,16 @@ function testSharedWorkerEvents() {
{ type: "text/javascript" });
// Delay creation of worker slightly so it is easier to distinguish
// shared worker creation time from this document's navigation start
- window.setTimeout(function() {
- var timeBeforeWorkerCreation = window.performance.now();
- var worker = new SharedWorker(window.URL.createObjectURL(blob));
+ setTimeout(function() {
+ var timeBeforeEvent = performance.now() + performance.timeOrigin;
+ var worker = new SharedWorker(URL.createObjectURL(blob));
worker.port.onmessage = function(evt) {
- var timeAfterEvent = window.performance.now();
- ok(evt.data > 0 &&
- evt.data < timeAfterEvent - timeBeforeWorkerCreation,
- "Event timestamp in shared worker (" + evt.data +
- ") is in expected range: (0, " +
- (timeAfterEvent - timeBeforeWorkerCreation) + ")");
+ var timeAfterEvent = performance.now() + performance.timeOrigin;
+ ok(evt.data >= timeBeforeEvent &&
+ evt.data <= timeAfterEvent,
+ // "Event timestamp in shared worker (" + evt.data +
+ // ") is in expected range: (0, " +
+ // timeBeforeEvent + ", " + timeAfterEvent + ")");
worker.port.close();
finishTests();
};
diff --git a/dom/fetch/InternalHeaders.cpp b/dom/fetch/InternalHeaders.cpp
index e81863173..11585615e 100644
--- a/dom/fetch/InternalHeaders.cpp
+++ b/dom/fetch/InternalHeaders.cpp
@@ -21,12 +21,14 @@ InternalHeaders::InternalHeaders(const nsTArray<Entry>&& aHeaders,
HeadersGuardEnum aGuard)
: mGuard(aGuard)
, mList(aHeaders)
+ , mListDirty(true)
{
}
InternalHeaders::InternalHeaders(const nsTArray<HeadersEntry>& aHeadersEntryList,
HeadersGuardEnum aGuard)
: mGuard(aGuard)
+ , mListDirty(true)
{
for (const HeadersEntry& headersEntry : aHeadersEntryList) {
mList.AppendElement(Entry(headersEntry.name(), headersEntry.value()));
@@ -56,6 +58,8 @@ InternalHeaders::Append(const nsACString& aName, const nsACString& aValue,
return;
}
+ SetListDirty();
+
mList.AppendElement(Entry(lowerName, aValue));
}
@@ -69,6 +73,8 @@ InternalHeaders::Delete(const nsACString& aName, ErrorResult& aRv)
return;
}
+ SetListDirty();
+
// remove in reverse order to minimize copying
for (int32_t i = mList.Length() - 1; i >= 0; --i) {
if (lowerName == mList[i].mName) {
@@ -155,6 +161,8 @@ InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorRes
return;
}
+ SetListDirty();
+
int32_t firstIndex = INT32_MAX;
// remove in reverse order to minimize copying
@@ -177,6 +185,7 @@ InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorRes
void
InternalHeaders::Clear()
{
+ SetListDirty();
mList.Clear();
}
@@ -419,5 +428,54 @@ InternalHeaders::GetUnsafeHeaders(nsTArray<nsCString>& aNames) const
}
}
+void
+InternalHeaders::MaybeSortList()
+{
+ class Comparator {
+ public:
+ bool Equals(const Entry& aA, const Entry& aB) const
+ {
+ return aA.mName == aB.mName;
+ }
+
+ bool LessThan(const Entry& aA, const Entry& aB) const
+ {
+ return aA.mName < aB.mName;
+ }
+ };
+
+ if (!mListDirty) {
+ return;
+ }
+
+ mListDirty = false;
+
+ Comparator comparator;
+
+ mSortedList.Clear();
+ for (const Entry& entry : mList) {
+ bool found = false;
+ for (Entry& sortedEntry : mSortedList) {
+ if (sortedEntry.mName == entry.mName) {
+ sortedEntry.mValue += ", ";
+ sortedEntry.mValue += entry.mValue;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ mSortedList.InsertElementSorted(entry, comparator);
+ }
+ }
+}
+
+void
+InternalHeaders::SetListDirty()
+{
+ mSortedList.Clear();
+ mListDirty = true;
+}
+
} // namespace dom
} // namespace mozilla
diff --git a/dom/fetch/InternalHeaders.h b/dom/fetch/InternalHeaders.h
index e47066669..9a6d6dae7 100644
--- a/dom/fetch/InternalHeaders.h
+++ b/dom/fetch/InternalHeaders.h
@@ -45,14 +45,23 @@ private:
HeadersGuardEnum mGuard;
nsTArray<Entry> mList;
+ nsTArray<Entry> mSortedList;
+
+ // This boolean is set to true at any writing operation to mList. It's set to
+ // false when mSortedList is regenerated. This happens when the header is
+ // iterated.
+ bool mListDirty;
+
public:
explicit InternalHeaders(HeadersGuardEnum aGuard = HeadersGuardEnum::None)
: mGuard(aGuard)
+ , mListDirty(false)
{
}
explicit InternalHeaders(const InternalHeaders& aOther)
: mGuard(HeadersGuardEnum::None)
+ , mListDirty(true)
{
ErrorResult result;
Fill(aOther, result);
@@ -79,19 +88,22 @@ public:
bool Has(const nsACString& aName, ErrorResult& aRv) const;
void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv);
- uint32_t GetIterableLength() const
+ uint32_t GetIterableLength()
{
- return mList.Length();
+ MaybeSortList();
+ return mSortedList.Length();
}
- const NS_ConvertASCIItoUTF16 GetKeyAtIndex(unsigned aIndex) const
+ const NS_ConvertASCIItoUTF16 GetKeyAtIndex(unsigned aIndex)
{
- MOZ_ASSERT(aIndex < mList.Length());
- return NS_ConvertASCIItoUTF16(mList[aIndex].mName);
+ MaybeSortList();
+ MOZ_ASSERT(aIndex < mSortedList.Length());
+ return NS_ConvertASCIItoUTF16(mSortedList[aIndex].mName);
}
- const NS_ConvertASCIItoUTF16 GetValueAtIndex(unsigned aIndex) const
+ const NS_ConvertASCIItoUTF16 GetValueAtIndex(unsigned aIndex)
{
- MOZ_ASSERT(aIndex < mList.Length());
- return NS_ConvertASCIItoUTF16(mList[aIndex].mValue);
+ MaybeSortList();
+ MOZ_ASSERT(aIndex < mSortedList.Length());
+ return NS_ConvertASCIItoUTF16(mSortedList[aIndex].mValue);
}
void Clear();
@@ -152,6 +164,9 @@ private:
const nsACString& aValue);
static bool IsRevalidationHeader(const nsACString& aName);
+
+ void MaybeSortList();
+ void SetListDirty();
};
} // namespace dom
diff --git a/dom/fetch/Response.cpp b/dom/fetch/Response.cpp
index a76071bf8..3b3ada6d3 100644
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -104,7 +104,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
return nullptr;
}
- Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams> body;
+ Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>> body;
ResponseInit init;
init.mStatus = aStatus;
RefPtr<Response> r = Response::Constructor(aGlobal, body, init, aRv);
@@ -125,7 +125,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
/*static*/ already_AddRefed<Response>
Response::Constructor(const GlobalObject& aGlobal,
- const Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& aBody,
+ const Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>>& aBody,
const ResponseInit& aInit, ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
@@ -191,7 +191,7 @@ Response::Constructor(const GlobalObject& aGlobal,
}
}
- if (aBody.WasPassed()) {
+ if (aBody.WasPassed() && !aBody.Value().IsNull()) {
if (aInit.mStatus == 204 || aInit.mStatus == 205 || aInit.mStatus == 304) {
aRv.ThrowTypeError<MSG_RESPONSE_NULL_STATUS_WITH_BODY>();
return nullptr;
@@ -200,7 +200,7 @@ Response::Constructor(const GlobalObject& aGlobal,
nsCOMPtr<nsIInputStream> bodyStream;
nsCString contentType;
uint64_t bodySize = 0;
- aRv = ExtractByteStreamFromBody(aBody.Value(),
+ aRv = ExtractByteStreamFromBody(aBody.Value().Value(),
getter_AddRefs(bodyStream),
contentType,
bodySize);
diff --git a/dom/fetch/Response.h b/dom/fetch/Response.h
index 64b3c5f45..de367bef6 100644
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -114,7 +114,7 @@ public:
static already_AddRefed<Response>
Constructor(const GlobalObject& aGlobal,
- const Optional<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& aBody,
+ const Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>>& aBody,
const ResponseInit& aInit, ErrorResult& rv);
nsIGlobalObject* GetParentObject() const
diff --git a/dom/html/HTMLAllCollection.cpp b/dom/html/HTMLAllCollection.cpp
index afa160e0c..6305cce31 100644
--- a/dom/html/HTMLAllCollection.cpp
+++ b/dom/html/HTMLAllCollection.cpp
@@ -8,6 +8,7 @@
#include "mozilla/dom/HTMLAllCollectionBinding.h"
#include "mozilla/dom/Nullable.h"
+#include "mozilla/dom/Element.h"
#include "nsHTMLDocument.h"
namespace mozilla {
@@ -86,14 +87,14 @@ IsAllNamedElement(nsIContent* aContent)
}
static bool
-DocAllResultMatch(nsIContent* aContent, int32_t aNamespaceID, nsIAtom* aAtom,
+DocAllResultMatch(Element* aElement, int32_t aNamespaceID, nsIAtom* aAtom,
void* aData)
{
- if (aContent->GetID() == aAtom) {
+ if (aElement->GetID() == aAtom) {
return true;
}
- nsGenericHTMLElement* elm = nsGenericHTMLElement::FromContent(aContent);
+ nsGenericHTMLElement* elm = nsGenericHTMLElement::FromContent(aElement);
if (!elm) {
return false;
}
diff --git a/dom/html/HTMLDataListElement.cpp b/dom/html/HTMLDataListElement.cpp
index d9ad4da09..5aa772645 100644
--- a/dom/html/HTMLDataListElement.cpp
+++ b/dom/html/HTMLDataListElement.cpp
@@ -35,11 +35,11 @@ NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
NS_IMPL_ELEMENT_CLONE(HTMLDataListElement)
bool
-HTMLDataListElement::MatchOptions(nsIContent* aContent, int32_t aNamespaceID,
+HTMLDataListElement::MatchOptions(Element* aElement, int32_t aNamespaceID,
nsIAtom* aAtom, void* aData)
{
- return aContent->NodeInfo()->Equals(nsGkAtoms::option, kNameSpaceID_XHTML) &&
- !aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+ return aElement->NodeInfo()->Equals(nsGkAtoms::option, kNameSpaceID_XHTML) &&
+ !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
}
} // namespace dom
diff --git a/dom/html/HTMLDataListElement.h b/dom/html/HTMLDataListElement.h
index e0aff818b..ba2a2e0b4 100644
--- a/dom/html/HTMLDataListElement.h
+++ b/dom/html/HTMLDataListElement.h
@@ -37,8 +37,8 @@ public:
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
// This function is used to generate the nsContentList (option elements).
- static bool MatchOptions(nsIContent* aContent, int32_t aNamespaceID,
- nsIAtom* aAtom, void* aData);
+ static bool MatchOptions(Element* aElement, int32_t aNamespaceID,
+ nsIAtom* aAtom, void* aData);
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLDataListElement,
nsGenericHTMLElement)
diff --git a/dom/html/HTMLFieldSetElement.cpp b/dom/html/HTMLFieldSetElement.cpp
index 865d3c9cf..d72fd1061 100644
--- a/dom/html/HTMLFieldSetElement.cpp
+++ b/dom/html/HTMLFieldSetElement.cpp
@@ -120,10 +120,10 @@ HTMLFieldSetElement::GetType(nsAString& aType)
/* static */
bool
-HTMLFieldSetElement::MatchListedElements(nsIContent* aContent, int32_t aNamespaceID,
+HTMLFieldSetElement::MatchListedElements(Element* aElement, int32_t aNamespaceID,
nsIAtom* aAtom, void* aData)
{
- nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aContent);
+ nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aElement);
return formControl;
}
diff --git a/dom/html/HTMLFieldSetElement.h b/dom/html/HTMLFieldSetElement.h
index d169434ae..96fff4582 100644
--- a/dom/html/HTMLFieldSetElement.h
+++ b/dom/html/HTMLFieldSetElement.h
@@ -124,8 +124,8 @@ private:
void NotifyElementsForFirstLegendChange(bool aNotify);
// This function is used to generate the nsContentList (listed form elements).
- static bool MatchListedElements(nsIContent* aContent, int32_t aNamespaceID,
- nsIAtom* aAtom, void* aData);
+ static bool MatchListedElements(Element* aElement, int32_t aNamespaceID,
+ nsIAtom* aAtom, void* aData);
// listed form controls elements.
RefPtr<nsContentList> mElements;
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
index 78f74ae0c..52062c4b9 100644
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -114,15 +114,12 @@
#include <limits>
#include "nsIColorPicker.h"
-#include "nsIDatePicker.h"
#include "nsIStringEnumerator.h"
#include "HTMLSplitOnSpacesTokenizer.h"
#include "nsIController.h"
#include "nsIMIMEInfo.h"
#include "nsFrameSelection.h"
-#include "nsIConsoleService.h"
-
// input type=date
#include "js/Date.h"
@@ -543,9 +540,8 @@ GetDOMFileOrDirectoryPath(const OwningFileOrDirectory& aData,
bool
HTMLInputElement::ValueAsDateEnabled(JSContext* cx, JSObject* obj)
{
- return Preferences::GetBool("dom.experimental_forms", false) ||
- Preferences::GetBool("dom.forms.datepicker", false) ||
- Preferences::GetBool("dom.forms.datetime", false);
+ return IsExperimentalFormsEnabled() || IsInputDateTimeEnabled() ||
+ IsInputDateTimeOthersEnabled();
}
NS_IMETHODIMP
@@ -628,7 +624,7 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
RefPtr<DispatchChangeEventCallback> dispatchChangeEventCallback =
new DispatchChangeEventCallback(mInput);
- if (Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) &&
+ if (IsWebkitDirPickerEnabled() &&
mInput->HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory)) {
ErrorResult error;
GetFilesHelper* helper = mInput->GetOrCreateGetFilesHelper(true, error);
@@ -747,59 +743,6 @@ nsColorPickerShownCallback::Done(const nsAString& aColor)
NS_IMPL_ISUPPORTS(nsColorPickerShownCallback, nsIColorPickerShownCallback)
-class DatePickerShownCallback final : public nsIDatePickerShownCallback
-{
- ~DatePickerShownCallback() {}
-public:
- DatePickerShownCallback(HTMLInputElement* aInput,
- nsIDatePicker* aDatePicker)
- : mInput(aInput)
- , mDatePicker(aDatePicker)
- {}
-
- NS_DECL_ISUPPORTS
-
- NS_IMETHOD Done(const nsAString& aDate) override;
- NS_IMETHOD Cancel() override;
-
-private:
- RefPtr<HTMLInputElement> mInput;
- nsCOMPtr<nsIDatePicker> mDatePicker;
-};
-
-NS_IMETHODIMP
-DatePickerShownCallback::Cancel()
-{
- mInput->PickerClosed();
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DatePickerShownCallback::Done(const nsAString& aDate)
-{
- nsAutoString oldValue;
-
- mInput->PickerClosed();
- mInput->GetValue(oldValue);
-
- if(!oldValue.Equals(aDate)){
- mInput->SetValue(aDate);
- nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
- static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
- NS_LITERAL_STRING("input"), true,
- false);
- return nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
- static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
- NS_LITERAL_STRING("change"), true,
- false);
- }
-
- return NS_OK;
-}
-
-NS_IMPL_ISUPPORTS(DatePickerShownCallback, nsIDatePickerShownCallback)
-
-
bool
HTMLInputElement::IsPopupBlocked() const
{
@@ -825,56 +768,6 @@ HTMLInputElement::IsPopupBlocked() const
}
nsresult
-HTMLInputElement::InitDatePicker()
-{
- if (!Preferences::GetBool("dom.forms.datepicker", false)) {
- return NS_OK;
- }
-
- if (mPickerRunning) {
- NS_WARNING("Just one nsIDatePicker is allowed");
- return NS_ERROR_FAILURE;
- }
-
- nsCOMPtr<nsIDocument> doc = OwnerDoc();
-
- nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow();
- if (!win) {
- return NS_ERROR_FAILURE;
- }
-
- if (IsPopupBlocked()) {
- win->FirePopupBlockedEvent(doc, nullptr, EmptyString(), EmptyString());
- return NS_OK;
- }
-
- // Get Loc title
- nsXPIDLString title;
- nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
- "DatePicker", title);
-
- nsresult rv;
- nsCOMPtr<nsIDatePicker> datePicker = do_CreateInstance("@mozilla.org/datepicker;1", &rv);
- if (!datePicker) {
- return rv;
- }
-
- nsAutoString initialValue;
- GetValueInternal(initialValue);
- rv = datePicker->Init(win, title, initialValue);
-
- nsCOMPtr<nsIDatePickerShownCallback> callback =
- new DatePickerShownCallback(this, datePicker);
-
- rv = datePicker->Open(callback);
- if (NS_SUCCEEDED(rv)) {
- mPickerRunning = true;
- }
-
- return rv;
-}
-
-nsresult
HTMLInputElement::InitColorPicker()
{
if (mPickerRunning) {
@@ -1919,6 +1812,22 @@ HTMLInputElement::ConvertStringToNumber(nsAString& aValue,
aResultValue = Decimal::fromDouble(days * kMsPerDay);
return true;
}
+ case NS_FORM_INPUT_DATETIME_LOCAL:
+ {
+ uint32_t year, month, day, timeInMs;
+ if (!ParseDateTimeLocal(aValue, &year, &month, &day, &timeInMs)) {
+ return false;
+ }
+
+ JS::ClippedTime time = JS::TimeClip(JS::MakeDate(year, month - 1, day,
+ timeInMs));
+ if (!time.isValid()) {
+ return false;
+ }
+
+ aResultValue = Decimal::fromDouble(time.toDouble());
+ return true;
+ }
default:
MOZ_ASSERT(false, "Unrecognized input type");
return false;
@@ -2108,21 +2017,17 @@ HTMLInputElement::ConvertNumberToString(Decimal aValue,
}
case NS_FORM_INPUT_TIME:
{
+ aValue = aValue.floor();
// Per spec, we need to truncate |aValue| and we should only represent
// times inside a day [00:00, 24:00[, which means that we should do a
// modulo on |aValue| using the number of milliseconds in a day (86400000).
- uint32_t value = NS_floorModulo(aValue.floor(), Decimal(86400000)).toDouble();
+ uint32_t value =
+ NS_floorModulo(aValue, Decimal::fromDouble(kMsPerDay)).toDouble();
- uint16_t milliseconds = value % 1000;
- value /= 1000;
-
- uint8_t seconds = value % 60;
- value /= 60;
-
- uint8_t minutes = value % 60;
- value /= 60;
-
- uint8_t hours = value;
+ uint16_t milliseconds, seconds, minutes, hours;
+ if (!GetTimeFromMs(value, &hours, &minutes, &seconds, &milliseconds)) {
+ return false;
+ }
if (milliseconds != 0) {
aResultString.AppendPrintf("%02d:%02d:%02d.%03d",
@@ -2192,6 +2097,42 @@ HTMLInputElement::ConvertNumberToString(Decimal aValue,
aResultString.AppendPrintf("%04.0f-W%02d", year, week);
return true;
}
+ case NS_FORM_INPUT_DATETIME_LOCAL:
+ {
+ aValue = aValue.floor();
+
+ uint32_t timeValue =
+ NS_floorModulo(aValue, Decimal::fromDouble(kMsPerDay)).toDouble();
+
+ uint16_t milliseconds, seconds, minutes, hours;
+ if (!GetTimeFromMs(timeValue,
+ &hours, &minutes, &seconds, &milliseconds)) {
+ return false;
+ }
+
+ double year = JS::YearFromTime(aValue.toDouble());
+ double month = JS::MonthFromTime(aValue.toDouble());
+ double day = JS::DayFromTime(aValue.toDouble());
+
+ if (IsNaN(year) || IsNaN(month) || IsNaN(day)) {
+ return false;
+ }
+
+ if (milliseconds != 0) {
+ aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d:%02d.%03d",
+ year, month + 1, day, hours, minutes,
+ seconds, milliseconds);
+ } else if (seconds != 0) {
+ aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d:%02d",
+ year, month + 1, day, hours, minutes,
+ seconds);
+ } else {
+ aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d",
+ year, month + 1, day, hours, minutes);
+ }
+
+ return true;
+ }
default:
MOZ_ASSERT(false, "Unrecognized input type");
return false;
@@ -2202,8 +2143,7 @@ HTMLInputElement::ConvertNumberToString(Decimal aValue,
Nullable<Date>
HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
{
- // TODO: this is temporary until bug 888331 is fixed.
- if (!IsDateTimeInputType(mType) || mType == NS_FORM_INPUT_DATETIME_LOCAL) {
+ if (!IsDateTimeInputType(mType)) {
return Nullable<Date>();
}
@@ -2261,6 +2201,19 @@ HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
return Nullable<Date>(Date(time));
}
+ case NS_FORM_INPUT_DATETIME_LOCAL:
+ {
+ uint32_t year, month, day, timeInMs;
+ nsAutoString value;
+ GetValueInternal(value);
+ if (!ParseDateTimeLocal(value, &year, &month, &day, &timeInMs)) {
+ return Nullable<Date>();
+ }
+
+ JS::ClippedTime time = JS::TimeClip(JS::MakeDate(year, month - 1, day,
+ timeInMs));
+ return Nullable<Date>(Date(time));
+ }
}
MOZ_ASSERT(false, "Unrecognized input type");
@@ -2271,8 +2224,7 @@ HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
void
HTMLInputElement::SetValueAsDate(Nullable<Date> aDate, ErrorResult& aRv)
{
- // TODO: this is temporary until bug 888331 is fixed.
- if (!IsDateTimeInputType(mType) || mType == NS_FORM_INPUT_DATETIME_LOCAL) {
+ if (!IsDateTimeInputType(mType)) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
@@ -2380,11 +2332,8 @@ HTMLInputElement::GetMaximum() const
Decimal
HTMLInputElement::GetStepBase() const
{
- MOZ_ASSERT(mType == NS_FORM_INPUT_NUMBER ||
- mType == NS_FORM_INPUT_DATE ||
- mType == NS_FORM_INPUT_TIME ||
- mType == NS_FORM_INPUT_MONTH ||
- mType == NS_FORM_INPUT_WEEK ||
+ MOZ_ASSERT(IsDateTimeInputType(mType) ||
+ mType == NS_FORM_INPUT_NUMBER ||
mType == NS_FORM_INPUT_RANGE,
"Check that kDefaultStepBase is correct for this new type");
@@ -2515,11 +2464,8 @@ HTMLInputElement::ApplyStep(int32_t aStep)
bool
HTMLInputElement::IsExperimentalMobileType(uint8_t aType)
{
- return (aType == NS_FORM_INPUT_DATE &&
- !Preferences::GetBool("dom.forms.datetime", false) &&
- !Preferences::GetBool("dom.forms.datepicker", false)) ||
- (aType == NS_FORM_INPUT_TIME &&
- !Preferences::GetBool("dom.forms.datetime", false));
+ return (aType == NS_FORM_INPUT_DATE || aType == NS_FORM_INPUT_TIME) &&
+ !IsInputDateTimeEnabled();
}
bool
@@ -2832,7 +2778,8 @@ HTMLInputElement::GetOwnerDateTimeControl()
HTMLInputElement::FromContentOrNull(
GetParent()->GetParent()->GetParent()->GetParent());
if (ownerDateTimeControl &&
- ownerDateTimeControl->mType == NS_FORM_INPUT_TIME) {
+ (ownerDateTimeControl->mType == NS_FORM_INPUT_TIME ||
+ ownerDateTimeControl->mType == NS_FORM_INPUT_DATE)) {
return ownerDateTimeControl;
}
}
@@ -3024,8 +2971,8 @@ HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
nsXPIDLString value;
if (mFilesOrDirectories.IsEmpty()) {
- if ((Preferences::GetBool("dom.input.dirpicker", false) && Allowdirs()) ||
- (Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) &&
+ if ((IsDirPickerEnabled() && Allowdirs()) ||
+ (IsWebkitDirPickerEnabled() &&
HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory))) {
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
"NoDirSelected", value);
@@ -3054,7 +3001,7 @@ HTMLInputElement::SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& a
{
ClearGetFilesHelpers();
- if (Preferences::GetBool("dom.webkitBlink.filesystem.enabled", false)) {
+ if (IsWebkitFileSystemEnabled()) {
HTMLInputElementBinding::ClearCachedWebkitEntriesValue(this);
mEntries.Clear();
}
@@ -3073,7 +3020,7 @@ HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
mFilesOrDirectories.Clear();
ClearGetFilesHelpers();
- if (Preferences::GetBool("dom.webkitBlink.filesystem.enabled", false)) {
+ if (IsWebkitFileSystemEnabled()) {
HTMLInputElementBinding::ClearCachedWebkitEntriesValue(this);
mEntries.Clear();
}
@@ -3096,14 +3043,14 @@ HTMLInputElement::MozSetDndFilesAndDirectories(const nsTArray<OwningFileOrDirect
{
SetFilesOrDirectories(aFilesOrDirectories, true);
- if (Preferences::GetBool("dom.webkitBlink.filesystem.enabled", false)) {
+ if (IsWebkitFileSystemEnabled()) {
UpdateEntries(aFilesOrDirectories);
}
RefPtr<DispatchChangeEventCallback> dispatchChangeEventCallback =
new DispatchChangeEventCallback(this);
- if (Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) &&
+ if (IsWebkitDirPickerEnabled() &&
HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory)) {
ErrorResult rv;
GetFilesHelper* helper = GetOrCreateGetFilesHelper(true /* recursionFlag */,
@@ -3181,8 +3128,8 @@ HTMLInputElement::GetFiles()
return nullptr;
}
- if (Preferences::GetBool("dom.input.dirpicker", false) && Allowdirs() &&
- (!Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) ||
+ if (IsDirPickerEnabled() && Allowdirs() &&
+ (!IsWebkitDirPickerEnabled() ||
!HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory))) {
return nullptr;
}
@@ -3282,7 +3229,8 @@ HTMLInputElement::SetValueInternal(const nsAString& aValue, uint32_t aFlags)
if (frame) {
frame->UpdateForValueChange();
}
- } else if (mType == NS_FORM_INPUT_TIME &&
+ } else if ((mType == NS_FORM_INPUT_TIME ||
+ mType == NS_FORM_INPUT_DATE) &&
!IsExperimentalMobileType(mType)) {
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
@@ -3591,7 +3539,8 @@ HTMLInputElement::Blur(ErrorResult& aError)
}
}
- if (mType == NS_FORM_INPUT_TIME && !IsExperimentalMobileType(mType)) {
+ if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
+ !IsExperimentalMobileType(mType)) {
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
frame->HandleBlurEvent();
@@ -3618,7 +3567,8 @@ HTMLInputElement::Focus(ErrorResult& aError)
}
}
- if (mType == NS_FORM_INPUT_TIME && !IsExperimentalMobileType(mType)) {
+ if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
+ !IsExperimentalMobileType(mType)) {
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
frame->HandleFocusEvent();
@@ -3956,7 +3906,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
}
- if (mType == NS_FORM_INPUT_TIME &&
+ if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
!IsExperimentalMobileType(mType) &&
aVisitor.mEvent->mMessage == eFocus &&
aVisitor.mEvent->mOriginalTarget == this) {
@@ -4083,7 +4033,8 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
// Stop the event if the related target's first non-native ancestor is the
// same as the original target's first non-native ancestor (we are moving
// inside of the same element).
- if (mType == NS_FORM_INPUT_TIME && !IsExperimentalMobileType(mType) &&
+ if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
+ !IsExperimentalMobileType(mType) &&
(aVisitor.mEvent->mMessage == eFocus ||
aVisitor.mEvent->mMessage == eFocusIn ||
aVisitor.mEvent->mMessage == eFocusOut ||
@@ -4361,8 +4312,8 @@ HTMLInputElement::MaybeInitPickers(EventChainPostVisitor& aVisitor)
do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
if (target &&
target->FindFirstNonChromeOnlyAccessContent() == this &&
- ((Preferences::GetBool("dom.input.dirpicker", false) && Allowdirs()) ||
- (Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) &&
+ ((IsDirPickerEnabled() && Allowdirs()) ||
+ (IsWebkitDirPickerEnabled() &&
HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory)))) {
type = FILE_PICKER_DIRECTORY;
}
@@ -4371,9 +4322,6 @@ HTMLInputElement::MaybeInitPickers(EventChainPostVisitor& aVisitor)
if (mType == NS_FORM_INPUT_COLOR) {
return InitColorPicker();
}
- if (mType == NS_FORM_INPUT_DATE) {
- return InitDatePicker();
- }
return NS_OK;
}
@@ -5383,6 +5331,29 @@ HTMLInputElement::MaximumWeekInYear(uint32_t aYear) const
}
bool
+HTMLInputElement::GetTimeFromMs(double aValue, uint16_t* aHours,
+ uint16_t* aMinutes, uint16_t* aSeconds,
+ uint16_t* aMilliseconds) const {
+ MOZ_ASSERT(aValue >= 0 && aValue < kMsPerDay,
+ "aValue must be milliseconds within a day!");
+
+ uint32_t value = floor(aValue);
+
+ *aMilliseconds = value % 1000;
+ value /= 1000;
+
+ *aSeconds = value % 60;
+ value /= 60;
+
+ *aMinutes = value % 60;
+ value /= 60;
+
+ *aHours = value;
+
+ return true;
+}
+
+bool
HTMLInputElement::IsValidWeek(const nsAString& aValue) const
{
uint32_t year, week;
@@ -5730,20 +5701,131 @@ HTMLInputElement::ParseTime(const nsAString& aValue, uint32_t* aResult)
return true;
}
-static bool
-IsDateTimeEnabled(int32_t aNewType)
+/* static */ bool
+HTMLInputElement::IsDateTimeTypeSupported(uint8_t aDateTimeInputType)
+{
+ return ((aDateTimeInputType == NS_FORM_INPUT_DATE ||
+ aDateTimeInputType == NS_FORM_INPUT_TIME) &&
+ (IsInputDateTimeEnabled() || IsExperimentalFormsEnabled())) ||
+ ((aDateTimeInputType == NS_FORM_INPUT_MONTH ||
+ aDateTimeInputType == NS_FORM_INPUT_WEEK ||
+ aDateTimeInputType == NS_FORM_INPUT_DATETIME_LOCAL) &&
+ IsInputDateTimeOthersEnabled());
+}
+
+/* static */ bool
+HTMLInputElement::IsWebkitDirPickerEnabled()
{
- return (aNewType == NS_FORM_INPUT_DATE &&
- (Preferences::GetBool("dom.forms.datetime", false) ||
- Preferences::GetBool("dom.experimental_forms", false) ||
- Preferences::GetBool("dom.forms.datepicker", false))) ||
- (aNewType == NS_FORM_INPUT_TIME &&
- (Preferences::GetBool("dom.forms.datetime", false) ||
- Preferences::GetBool("dom.experimental_forms", false))) ||
- ((aNewType == NS_FORM_INPUT_MONTH ||
- aNewType == NS_FORM_INPUT_WEEK ||
- aNewType == NS_FORM_INPUT_DATETIME_LOCAL) &&
- Preferences::GetBool("dom.forms.datetime", false));
+ static bool sWebkitDirPickerEnabled = false;
+ static bool sWebkitDirPickerPrefCached = false;
+ if (!sWebkitDirPickerPrefCached) {
+ sWebkitDirPickerPrefCached = true;
+ Preferences::AddBoolVarCache(&sWebkitDirPickerEnabled,
+ "dom.webkitBlink.dirPicker.enabled",
+ false);
+ }
+
+ return sWebkitDirPickerEnabled;
+}
+
+/* static */ bool
+HTMLInputElement::IsWebkitFileSystemEnabled()
+{
+ static bool sWebkitFileSystemEnabled = false;
+ static bool sWebkitFileSystemPrefCached = false;
+ if (!sWebkitFileSystemPrefCached) {
+ sWebkitFileSystemPrefCached = true;
+ Preferences::AddBoolVarCache(&sWebkitFileSystemEnabled,
+ "dom.webkitBlink.filesystem.enabled",
+ false);
+ }
+
+ return sWebkitFileSystemEnabled;
+}
+
+/* static */ bool
+HTMLInputElement::IsDirPickerEnabled()
+{
+ static bool sDirPickerEnabled = false;
+ static bool sDirPickerPrefCached = false;
+ if (!sDirPickerPrefCached) {
+ sDirPickerPrefCached = true;
+ Preferences::AddBoolVarCache(&sDirPickerEnabled, "dom.input.dirpicker",
+ false);
+ }
+
+ return sDirPickerEnabled;
+}
+
+/* static */ bool
+HTMLInputElement::IsExperimentalFormsEnabled()
+{
+ static bool sExperimentalFormsEnabled = false;
+ static bool sExperimentalFormsPrefCached = false;
+ if (!sExperimentalFormsPrefCached) {
+ sExperimentalFormsPrefCached = true;
+ Preferences::AddBoolVarCache(&sExperimentalFormsEnabled,
+ "dom.experimental_forms",
+ false);
+ }
+
+ return sExperimentalFormsEnabled;
+}
+
+/* static */ bool
+HTMLInputElement::IsInputDateTimeEnabled()
+{
+ static bool sDateTimeEnabled = false;
+ static bool sDateTimePrefCached = false;
+ if (!sDateTimePrefCached) {
+ sDateTimePrefCached = true;
+ Preferences::AddBoolVarCache(&sDateTimeEnabled, "dom.forms.datetime",
+ false);
+ }
+
+ return sDateTimeEnabled;
+}
+
+/* static */ bool
+HTMLInputElement::IsInputDateTimeOthersEnabled()
+{
+ static bool sDateTimeOthersEnabled = false;
+ static bool sDateTimeOthersPrefCached = false;
+ if (!sDateTimeOthersPrefCached) {
+ sDateTimeOthersPrefCached = true;
+ Preferences::AddBoolVarCache(&sDateTimeOthersEnabled,
+ "dom.forms.datetime.others", false);
+ }
+
+ return sDateTimeOthersEnabled;
+}
+
+/* static */ bool
+HTMLInputElement::IsInputNumberEnabled()
+{
+ static bool sInputNumberEnabled = false;
+ static bool sInputNumberPrefCached = false;
+ if (!sInputNumberPrefCached) {
+ sInputNumberPrefCached = true;
+ Preferences::AddBoolVarCache(&sInputNumberEnabled, "dom.forms.number",
+ false);
+ }
+
+ return sInputNumberEnabled;
+}
+
+/* static */ bool
+HTMLInputElement::IsInputColorEnabled()
+{
+ static bool sInputColorEnabled = false;
+ static bool sInputColorPrefCached = false;
+ if (!sInputColorPrefCached) {
+ sInputColorPrefCached = true;
+ Preferences::AddBoolVarCache(&sInputColorEnabled, "dom.forms.color",
+ false);
+ }
+
+ return sInputColorEnabled;
}
bool
@@ -5760,13 +5842,9 @@ HTMLInputElement::ParseAttribute(int32_t aNamespaceID,
bool success = aResult.ParseEnumValue(aValue, kInputTypeTable, false);
if (success) {
newType = aResult.GetEnumValue();
- if ((IsExperimentalMobileType(newType) &&
- !Preferences::GetBool("dom.experimental_forms", false)) ||
- (newType == NS_FORM_INPUT_NUMBER &&
- !Preferences::GetBool("dom.forms.number", false)) ||
- (newType == NS_FORM_INPUT_COLOR &&
- !Preferences::GetBool("dom.forms.color", false)) ||
- (IsDateTimeInputType(newType) && !IsDateTimeEnabled(newType))) {
+ if ((newType == NS_FORM_INPUT_NUMBER && !IsInputNumberEnabled()) ||
+ (newType == NS_FORM_INPUT_COLOR && !IsInputColorEnabled()) ||
+ (IsDateTimeInputType(newType) && !IsDateTimeTypeSupported(newType))) {
newType = kInputDefaultType->value;
aResult.SetTo(newType, &aValue);
}
@@ -7161,13 +7239,15 @@ HTMLInputElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, int32_t*
if (mType == NS_FORM_INPUT_FILE ||
mType == NS_FORM_INPUT_NUMBER ||
- mType == NS_FORM_INPUT_TIME) {
+ mType == NS_FORM_INPUT_TIME ||
+ mType == NS_FORM_INPUT_DATE) {
if (aTabIndex) {
// We only want our native anonymous child to be tabable to, not ourself.
*aTabIndex = -1;
}
if (mType == NS_FORM_INPUT_NUMBER ||
- mType == NS_FORM_INPUT_TIME) {
+ mType == NS_FORM_INPUT_TIME ||
+ mType == NS_FORM_INPUT_DATE) {
*aIsFocusable = true;
} else {
*aIsFocusable = defaultFocusable;
@@ -7650,8 +7730,7 @@ HTMLInputElement::HasPatternMismatch() const
bool
HTMLInputElement::IsRangeOverflow() const
{
- // TODO: this is temporary until bug 888331 is fixed.
- if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_DATETIME_LOCAL) {
+ if (!DoesMinMaxApply()) {
return false;
}
@@ -7671,8 +7750,7 @@ HTMLInputElement::IsRangeOverflow() const
bool
HTMLInputElement::IsRangeUnderflow() const
{
- // TODO: this is temporary until bug 888331 is fixed.
- if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_DATETIME_LOCAL) {
+ if (!DoesMinMaxApply()) {
return false;
}
@@ -8622,6 +8700,7 @@ HTMLInputElement::GetStepScaleFactor() const
case NS_FORM_INPUT_RANGE:
return kStepScaleFactorNumberRange;
case NS_FORM_INPUT_TIME:
+ case NS_FORM_INPUT_DATETIME_LOCAL:
return kStepScaleFactorTime;
case NS_FORM_INPUT_MONTH:
return kStepScaleFactorMonth;
@@ -8646,6 +8725,7 @@ HTMLInputElement::GetDefaultStep() const
case NS_FORM_INPUT_RANGE:
return kDefaultStep;
case NS_FORM_INPUT_TIME:
+ case NS_FORM_INPUT_DATETIME_LOCAL:
return kDefaultStepTime;
default:
MOZ_ASSERT(false, "Unrecognized input type");
@@ -8680,8 +8760,7 @@ HTMLInputElement::UpdateHasRange()
mHasRange = false;
- // TODO: this is temporary until bug 888331 is fixed.
- if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_DATETIME_LOCAL) {
+ if (!DoesMinMaxApply()) {
return;
}
@@ -8800,6 +8879,16 @@ HTMLInputElement::GetWebkitEntries(nsTArray<RefPtr<FileSystemEntry>>& aSequence)
aSequence.AppendElements(mEntries);
}
+already_AddRefed<nsINodeList>
+HTMLInputElement::GetLabels()
+{
+ if (!IsLabelable()) {
+ return nullptr;
+ }
+
+ return nsGenericHTMLElement::Labels();
+}
+
} // namespace dom
} // namespace mozilla
diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h
index e5d670e08..98a590443 100644
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -704,6 +704,8 @@ public:
// XPCOM GetCustomVisibility() is OK
+ already_AddRefed<nsINodeList> GetLabels();
+
// XPCOM Select() is OK
Nullable<int32_t> GetSelectionStart(ErrorResult& aRv);
@@ -794,6 +796,15 @@ public:
void UpdateDateTimePicker(const DateTimeValue& aValue);
void CloseDateTimePicker();
+ /*
+ * The following are called from datetime input box binding to get the
+ * corresponding computed values.
+ */
+ double GetStepAsDouble() { return GetStep().toDouble(); }
+ double GetStepBaseAsDouble() { return GetStepBase().toDouble(); }
+ double GetMinimumAsDouble() { return GetMinimum().toDouble(); }
+ double GetMaximumAsDouble() { return GetMaximum().toDouble(); }
+
HTMLInputElement* GetOwnerNumberControl();
HTMLInputElement* GetOwnerDateTimeControl();
@@ -1059,11 +1070,7 @@ protected:
/**
* Returns if the step attribute apply for the current type.
*/
- bool DoesStepApply() const
- {
- // TODO: this is temporary until bug 888331 is fixed.
- return DoesMinMaxApply() && mType != NS_FORM_INPUT_DATETIME_LOCAL;
- }
+ bool DoesStepApply() const { return DoesMinMaxApply(); }
/**
* Returns if stepDown and stepUp methods apply for the current type.
@@ -1073,11 +1080,7 @@ protected:
/**
* Returns if valueAsNumber attribute applies for the current type.
*/
- bool DoesValueAsNumberApply() const
- {
- // TODO: this is temporary until bug 888331 is fixed.
- return DoesMinMaxApply() && mType != NS_FORM_INPUT_DATETIME_LOCAL;
- }
+ bool DoesValueAsNumberApply() const { return DoesMinMaxApply(); }
/**
* Returns if autocomplete attribute applies for the current type.
@@ -1285,6 +1288,7 @@ protected:
* https://html.spec.whatwg.org/multipage/infrastructure.html#valid-normalised-local-date-and-time-string
*/
void NormalizeDateTimeLocal(nsAString& aValue) const;
+
/**
* This methods returns the number of days since epoch for a given year and
* week.
@@ -1316,6 +1320,13 @@ protected:
uint32_t MaximumWeekInYear(uint32_t aYear) const;
/**
+ * This method converts aValue (milliseconds within a day) to hours, minutes,
+ * seconds and milliseconds.
+ */
+ bool GetTimeFromMs(double aValue, uint16_t* aHours, uint16_t* aMinutes,
+ uint16_t* aSeconds, uint16_t* aMilliseconds) const;
+
+ /**
* This methods returns true if it's a leap year.
*/
bool IsLeapYear(uint32_t aYear) const;
@@ -1440,7 +1451,6 @@ protected:
};
nsresult InitFilePicker(FilePickerType aType);
nsresult InitColorPicker();
- nsresult InitDatePicker();
/**
* Use this function before trying to open a picker.
@@ -1630,9 +1640,73 @@ private:
return IsSingleLineTextControl(false, aType) ||
aType == NS_FORM_INPUT_RANGE ||
aType == NS_FORM_INPUT_NUMBER ||
- aType == NS_FORM_INPUT_TIME;
+ aType == NS_FORM_INPUT_TIME ||
+ aType == NS_FORM_INPUT_DATE;
}
+ /**
+ * Checks if aDateTimeInputType should be supported based on "dom.forms.datetime",
+ * and "dom.experimental_forms".
+ */
+ static bool
+ IsDateTimeTypeSupported(uint8_t aDateTimeInputType);
+
+ /**
+ * Checks preference "dom.webkitBlink.dirPicker.enabled" to determine if
+ * webkitdirectory should be supported.
+ */
+ static bool
+ IsWebkitDirPickerEnabled();
+
+ /**
+ * Checks preference "dom.webkitBlink.filesystem.enabled" to determine if
+ * webkitEntries should be supported.
+ */
+ static bool
+ IsWebkitFileSystemEnabled();
+
+ /**
+ * Checks preference "dom.input.dirpicker" to determine if file and directory
+ * entries API should be supported.
+ */
+ static bool
+ IsDirPickerEnabled();
+
+ /**
+ * Checks preference "dom.experimental_forms" to determine if experimental
+ * implementation of input element should be enabled.
+ */
+ static bool
+ IsExperimentalFormsEnabled();
+
+ /**
+ * Checks preference "dom.forms.datetime" to determine if input date and time
+ * should be supported.
+ */
+ static bool
+ IsInputDateTimeEnabled();
+
+ /**
+ * Checks preference "dom.forms.datetime.others" to determine if input week,
+ * month and datetime-local should be supported.
+ */
+ static bool
+ IsInputDateTimeOthersEnabled();
+
+ /**
+ * Checks preference "dom.forms.number" to determine if input type=number
+ * should be supported.
+ */
+ static bool
+ IsInputNumberEnabled();
+
+ /**
+ * Checks preference "dom.forms.color" to determine if date/time related
+ * types should be supported.
+ */
+ static bool
+ IsInputColorEnabled();
+
struct nsFilePickerFilter {
nsFilePickerFilter()
: mFilterMask(0) {}
diff --git a/dom/html/HTMLLabelElement.cpp b/dom/html/HTMLLabelElement.cpp
index c1d22b0a6..d1c037336 100644
--- a/dom/html/HTMLLabelElement.cpp
+++ b/dom/html/HTMLLabelElement.cpp
@@ -14,6 +14,7 @@
#include "nsFocusManager.h"
#include "nsIDOMMouseEvent.h"
#include "nsQueryObject.h"
+#include "mozilla/dom/ShadowRoot.h"
// construction, destruction
@@ -268,17 +269,23 @@ HTMLLabelElement::GetLabeledElement() const
return GetFirstLabelableDescendant();
}
- // We have a @for. The id has to be linked to an element in the same document
+ // We have a @for. The id has to be linked to an element in the same tree
// and this element should be a labelable form control.
- //XXXsmaug It is unclear how this should work in case the element is in
- // Shadow DOM.
- // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=26365.
- nsIDocument* doc = GetUncomposedDoc();
- if (!doc) {
- return nullptr;
+ nsINode* root = SubtreeRoot();
+ ShadowRoot* shadow = ShadowRoot::FromNode(root);
+ Element* element = nullptr;
+
+ if (shadow) {
+ element = shadow->GetElementById(elementId);
+ } else {
+ nsIDocument* doc = GetUncomposedDoc();
+ if (doc) {
+ element = doc->GetElementById(elementId);
+ } else {
+ element = nsContentUtils::MatchElementId(root->AsContent(), elementId);
+ }
}
- Element* element = doc->GetElementById(elementId);
if (element && element->IsLabelable()) {
return static_cast<nsGenericHTMLElement*>(element);
}
diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp
index b64761270..1f1a545fa 100644
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -11,7 +11,9 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/AsyncEventDispatcher.h"
+#ifdef MOZ_EME
#include "mozilla/dom/MediaEncryptedEvent.h"
+#endif
#include "base/basictypes.h"
#include "nsIDOMHTMLMediaElement.h"
@@ -820,7 +822,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextTrackManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioTrackList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVideoTrackList)
+#ifdef MOZ_EME
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeys)
+#endif
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedVideoStreamTrack)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -845,7 +849,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLE
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextTrackManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioTrackList)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mVideoTrackList)
+#ifdef MOZ_EME
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaKeys)
+#endif
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectedVideoStreamTrack)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -1020,12 +1026,14 @@ void HTMLMediaElement::ShutdownDecoder()
void HTMLMediaElement::AbortExistingLoads()
{
+#ifdef MOZ_EME
// If there is no existing decoder then we don't have anything to
// report. This prevents reporting the initial load from an
// empty video element as a failed EME load.
if (mDecoder) {
ReportEMETelemetry();
}
+#endif
// Abort any already-running instance of the resource selection algorithm.
mLoadWaitStatus = NOT_WAITING;
@@ -1084,7 +1092,9 @@ void HTMLMediaElement::AbortExistingLoads()
mDownloadSuspendedByCache = false;
mMediaInfo = MediaInfo();
mIsEncrypted = false;
+#ifdef MOZ_EME
mPendingEncryptedInitData.mInitDatas.Clear();
+#endif
mWaitingForKey = NOT_WAITING_FOR_KEY;
mSourcePointer = nullptr;
@@ -2681,9 +2691,11 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
if (!window) {
return nullptr;
}
+#ifdef MOZ_EME
if (ContainsRestrictedContent()) {
return nullptr;
}
+#endif
if (!mOutputStreams.IsEmpty() &&
aGraph != mOutputStreams[0].mStream->GetInputStream()->Graph()) {
@@ -3638,6 +3650,7 @@ void HTMLMediaElement::HiddenVideoStop()
mVideoDecodeSuspendTimer = nullptr;
}
+#ifdef MOZ_EME
void
HTMLMediaElement::ReportEMETelemetry()
{
@@ -3649,6 +3662,7 @@ HTMLMediaElement::ReportEMETelemetry()
this, mLoadedDataFired ? "true" : "false"));
}
}
+#endif
void
HTMLMediaElement::ReportTelemetry()
@@ -3997,6 +4011,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
ms.mFinishWhenEnded);
}
+#ifdef MOZ_EME
if (mMediaKeys) {
if (mMediaKeys->GetCDMProxy()) {
mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
@@ -4006,6 +4021,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
return NS_ERROR_FAILURE;
}
}
+#endif
MediaEventSource<void>* waitingForKeyProducer = mDecoder->WaitingForKeyEvent();
// Not every decoder will produce waitingForKey events, only add ones that can
@@ -4468,7 +4484,11 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
SetMediaInfo(*aInfo);
- mIsEncrypted = aInfo->IsEncrypted() || mPendingEncryptedInitData.IsEncrypted();
+ mIsEncrypted = aInfo->IsEncrypted()
+#ifdef MOZ_EME
+ || mPendingEncryptedInitData.IsEncrypted()
+#endif
+ ;
mTags = aTags.forget();
mLoadedDataFired = false;
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
@@ -4494,11 +4514,13 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
return;
}
+#ifdef MOZ_EME
// Dispatch a distinct 'encrypted' event for each initData we have.
for (const auto& initData : mPendingEncryptedInitData.mInitDatas) {
DispatchEncrypted(initData.mInitData, initData.mType);
}
mPendingEncryptedInitData.mInitDatas.Clear();
+#endif
}
mWatchManager.ManualNotify(&HTMLMediaElement::UpdateReadyStateInternal);
@@ -4550,6 +4572,11 @@ void HTMLMediaElement::FirstFrameLoaded()
ChangeDelayLoadStatus(false);
+ // FIXME: This is a workaround for DoneCreatingElement() not being called
+ // at the appropriate time when cloning elements, to preserve the "muted"
+ // status. See bug 1424871.
+ if (HasAttr(kNameSpaceID_None, nsGkAtoms::muted)) SetMuted(true);
+
if (mDecoder && mAllowSuspendAfterFirstFrame && mPaused &&
!HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
@@ -5426,9 +5453,12 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
UpdateAudioChannelPlayingState();
if (aPauseElement) {
ReportTelemetry();
+#ifdef MOZ_EME
ReportEMETelemetry();
+#endif
- // For EME content, force destruction of the CDM client (and CDM
+#ifdef MOZ_EME
+ // For EME content, we may force destruction of the CDM client (and CDM
// instance if this is the last client for that CDM instance) and
// the CDM's decoder. This ensures the CDM gets reliable and prompt
// shutdown notifications, as it may have book-keeping it needs
@@ -5440,6 +5470,7 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
ShutdownDecoder();
}
}
+#endif
if (mDecoder) {
mDecoder->Pause();
mDecoder->Suspend();
@@ -5490,6 +5521,17 @@ void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
bool pauseElement = ShouldElementBePaused();
SuspendOrResumeElement(pauseElement, !IsActive());
+#ifdef MOZ_EME
+ // If the owning document has become inactive we should shutdown the CDM.
+ if (!OwnerDoc()->IsCurrentActiveDocument() && mMediaKeys) {
+ mMediaKeys->Shutdown();
+ mMediaKeys = nullptr;
+ if (mDecoder) {
+ ShutdownDecoder();
+ }
+ }
+#endif
+
AddRemoveSelfReference();
}
@@ -6265,6 +6307,7 @@ HTMLMediaElement::OnVisibilityChange(Visibility aNewVisibility)
}
+#ifdef MOZ_EME
MediaKeys*
HTMLMediaElement::GetMediaKeys() const
{
@@ -6474,6 +6517,7 @@ HTMLMediaElement::GetTopLevelPrincipal()
principal = doc->NodePrincipal();
return principal.forget();
}
+#endif //MOZ_EME
void
HTMLMediaElement::CannotDecryptWaitingForKey()
diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h
index d40e9df46..b65049206 100644
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -20,7 +20,9 @@
#include "mozilla/dom/TextTrackManager.h"
#include "mozilla/WeakPtr.h"
#include "MediaDecoder.h"
+#ifdef MOZ_EME
#include "mozilla/dom/MediaKeys.h"
+#endif
#include "mozilla/StateWatching.h"
#include "nsGkAtoms.h"
#include "PrincipalChangeObserver.h"
@@ -630,6 +632,7 @@ public:
// XPCOM MozPreservesPitch() is OK
+#ifdef MOZ_EME
MediaKeys* GetMediaKeys() const;
already_AddRefed<Promise> SetMediaKeys(MediaKeys* mediaKeys,
@@ -651,6 +654,7 @@ public:
already_AddRefed<nsIPrincipal> GetTopLevelPrincipal();
bool ContainsRestrictedContent();
+#endif // MOZ_EME
void CannotDecryptWaitingForKey();
@@ -1198,7 +1202,9 @@ protected:
*/
void HiddenVideoStop();
+#ifdef MOZ_EME
void ReportEMETelemetry();
+#endif
void ReportTelemetry();
@@ -1471,8 +1477,10 @@ protected:
// Timer used to simulate video-suspend.
nsCOMPtr<nsITimer> mVideoDecodeSuspendTimer;
+#ifdef MOZ_EME
// Encrypted Media Extension media keys.
RefPtr<MediaKeys> mMediaKeys;
+#endif
// Stores the time at the start of the current 'played' range.
double mCurrentPlayRangeStart;
@@ -1627,8 +1635,10 @@ protected:
// Listens for waitingForKey events from the owned decoder.
MediaEventListener mWaitingForKeyListener;
+#ifdef MOZ_EME
// Init Data that needs to be sent in 'encrypted' events in MetadataLoaded().
EncryptionInfo mPendingEncryptedInitData;
+#endif
// True if the media's channel's download has been suspended.
Watchable<bool> mDownloadSuspendedByCache;
diff --git a/dom/html/HTMLSelectElement.cpp b/dom/html/HTMLSelectElement.cpp
index 24ddabb65..53f42317a 100644
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -735,12 +735,12 @@ HTMLSelectElement::SetLength(uint32_t aLength, ErrorResult& aRv)
/* static */
bool
-HTMLSelectElement::MatchSelectedOptions(nsIContent* aContent,
+HTMLSelectElement::MatchSelectedOptions(Element* aElement,
int32_t /* unused */,
nsIAtom* /* unused */,
void* /* unused*/)
{
- HTMLOptionElement* option = HTMLOptionElement::FromContent(aContent);
+ HTMLOptionElement* option = HTMLOptionElement::FromContent(aElement);
return option && option->Selected();
}
diff --git a/dom/html/HTMLSelectElement.h b/dom/html/HTMLSelectElement.h
index d7e4350b4..8a25385de 100644
--- a/dom/html/HTMLSelectElement.h
+++ b/dom/html/HTMLSelectElement.h
@@ -247,7 +247,7 @@ public:
mOptions->IndexedSetter(aIndex, aOption, aRv);
}
- static bool MatchSelectedOptions(nsIContent* aContent, int32_t, nsIAtom*,
+ static bool MatchSelectedOptions(Element* aElement, int32_t, nsIAtom*,
void*);
nsIHTMLCollection* SelectedOptions();
diff --git a/dom/html/HTMLTableRowElement.cpp b/dom/html/HTMLTableRowElement.cpp
index 2dec9c883..ac2463400 100644
--- a/dom/html/HTMLTableRowElement.cpp
+++ b/dom/html/HTMLTableRowElement.cpp
@@ -120,10 +120,10 @@ HTMLTableRowElement::SectionRowIndex() const
}
static bool
-IsCell(nsIContent *aContent, int32_t aNamespaceID,
+IsCell(Element *aElement, int32_t aNamespaceID,
nsIAtom* aAtom, void *aData)
{
- return aContent->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th);
+ return aElement->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th);
}
nsIHTMLCollection*
diff --git a/dom/html/crashtests/1350972.html b/dom/html/crashtests/1350972.html
new file mode 100644
index 000000000..7af7f9e17
--- /dev/null
+++ b/dom/html/crashtests/1350972.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+ try { o1 = document.createElement('tr'); } catch(e) {};
+ try { o2 = document.createElement('div'); } catch(e) {};
+ try { o3 = document.createElement('hr'); } catch(e) {};
+ try { o4 = document.createElement('textarea'); } catch(e) {};
+ try { o5 = document.getSelection(); } catch(e) {};
+ try { o6 = document.createRange(); } catch(e) {};
+ try { document.documentElement.appendChild(o2); } catch(e) {};
+ try { document.documentElement.appendChild(o3); } catch(e) {};
+ try { o2.appendChild(o4); } catch(e) {};
+ try { o3.outerHTML = "<noscript contenteditable='true'>"; } catch(e) {};
+ try { o4.select(); } catch(e) {};
+ try { o5.addRange(o6); } catch(e) {};
+ try { document.documentElement.appendChild(o1); } catch(e) {};
+ try { o5.selectAllChildren(o1); } catch(e) {};
+ try { o6.selectNode(o1); } catch(e) {};
+</script>
+</head>
+</html> \ No newline at end of file
diff --git a/dom/html/crashtests/crashtests.list b/dom/html/crashtests/crashtests.list
index e55a0a350..a2068ea4e 100644
--- a/dom/html/crashtests/crashtests.list
+++ b/dom/html/crashtests/crashtests.list
@@ -78,4 +78,5 @@ load 1237633.html
load 1281972-1.html
load 1282894.html
load 1290904.html
+asserts(0-3) load 1350972.html
load 1386905.html
diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp
index d75001a83..2f890325a 100644
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -108,6 +108,7 @@
#include "mozilla/StyleSetHandle.h"
#include "mozilla/StyleSetHandleInlines.h"
#include "ReferrerPolicy.h"
+#include "mozilla/dom/HTMLLabelElement.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -493,6 +494,14 @@ nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
}
}
+ // We need to consider a labels element is moved to another subtree
+ // with different root, it needs to update labels list and its root
+ // as well.
+ nsDOMSlots* slots = GetExistingDOMSlots();
+ if (slots && slots->mLabelsList) {
+ slots->mLabelsList->MaybeResetRoot(SubtreeRoot());
+ }
+
return rv;
}
@@ -513,6 +522,13 @@ nsGenericHTMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
}
}
+ // We need to consider a labels element is removed from tree,
+ // it needs to update labels list and its root as well.
+ nsDOMSlots* slots = GetExistingDOMSlots();
+ if (slots && slots->mLabelsList) {
+ slots->mLabelsList->MaybeResetRoot(SubtreeRoot());
+ }
+
nsStyledElement::UnbindFromTree(aDeep, aNullParent);
}
@@ -1701,6 +1717,30 @@ nsGenericHTMLElement::IsLabelable() const
return IsAnyOfHTMLElements(nsGkAtoms::progress, nsGkAtoms::meter);
}
+/* static */ bool
+nsGenericHTMLElement::MatchLabelsElement(Element* aElement, int32_t aNamespaceID,
+ nsIAtom* aAtom, void* aData)
+{
+ HTMLLabelElement* element = HTMLLabelElement::FromContent(aElement);
+ return element && element->GetControl() == aData;
+}
+
+already_AddRefed<nsINodeList>
+nsGenericHTMLElement::Labels()
+{
+ MOZ_ASSERT(IsLabelable(),
+ "Labels() only allow labelable elements to use it.");
+ nsDOMSlots* slots = DOMSlots();
+
+ if (!slots->mLabelsList) {
+ slots->mLabelsList = new nsLabelsNodeList(SubtreeRoot(), MatchLabelsElement,
+ nullptr, this);
+ }
+
+ RefPtr<nsLabelsNodeList> labels = slots->mLabelsList;
+ return labels.forget();
+}
+
bool
nsGenericHTMLElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
{
diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h
index 3cca41c3d..0635c27e1 100644
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -834,6 +834,12 @@ public:
}
virtual bool IsLabelable() const override;
+
+ static bool MatchLabelsElement(Element* aElement, int32_t aNamespaceID,
+ nsIAtom* aAtom, void* aData);
+
+ already_AddRefed<nsINodeList> Labels();
+
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
static bool TouchEventsEnabled(JSContext* /* unused */, JSObject* /* unused */);
diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp
index 5e6302941..69e710242 100644
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -1100,31 +1100,31 @@ nsHTMLDocument::Applets()
}
bool
-nsHTMLDocument::MatchLinks(nsIContent *aContent, int32_t aNamespaceID,
+nsHTMLDocument::MatchLinks(Element* aElement, int32_t aNamespaceID,
nsIAtom* aAtom, void* aData)
{
- nsIDocument* doc = aContent->GetUncomposedDoc();
+ nsIDocument* doc = aElement->GetUncomposedDoc();
if (doc) {
- NS_ASSERTION(aContent->IsInUncomposedDoc(),
+ NS_ASSERTION(aElement->IsInUncomposedDoc(),
"This method should never be called on content nodes that "
"are not in a document!");
#ifdef DEBUG
{
nsCOMPtr<nsIHTMLDocument> htmldoc =
- do_QueryInterface(aContent->GetUncomposedDoc());
+ do_QueryInterface(aElement->GetUncomposedDoc());
NS_ASSERTION(htmldoc,
"Huh, how did this happen? This should only be used with "
"HTML documents!");
}
#endif
- mozilla::dom::NodeInfo *ni = aContent->NodeInfo();
+ mozilla::dom::NodeInfo *ni = aElement->NodeInfo();
nsIAtom *localName = ni->NameAtom();
if (ni->NamespaceID() == kNameSpaceID_XHTML &&
(localName == nsGkAtoms::a || localName == nsGkAtoms::area)) {
- return aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::href);
+ return aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::href);
}
}
@@ -1148,24 +1148,24 @@ nsHTMLDocument::Links()
}
bool
-nsHTMLDocument::MatchAnchors(nsIContent *aContent, int32_t aNamespaceID,
+nsHTMLDocument::MatchAnchors(Element* aElement, int32_t aNamespaceID,
nsIAtom* aAtom, void* aData)
{
- NS_ASSERTION(aContent->IsInUncomposedDoc(),
+ NS_ASSERTION(aElement->IsInUncomposedDoc(),
"This method should never be called on content nodes that "
"are not in a document!");
#ifdef DEBUG
{
nsCOMPtr<nsIHTMLDocument> htmldoc =
- do_QueryInterface(aContent->GetUncomposedDoc());
+ do_QueryInterface(aElement->GetUncomposedDoc());
NS_ASSERTION(htmldoc,
"Huh, how did this happen? This should only be used with "
"HTML documents!");
}
#endif
- if (aContent->NodeInfo()->Equals(nsGkAtoms::a, kNameSpaceID_XHTML)) {
- return aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::name);
+ if (aElement->IsHTMLElement(nsGkAtoms::a)) {
+ return aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::name);
}
return false;
@@ -1255,6 +1255,11 @@ nsHTMLDocument::GetCookie(nsAString& aCookie, ErrorResult& rv)
rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
+
+ // If the document is a cookie-averse document, return an empty string.
+ if (IsCookieAverse()) {
+ return;
+ }
// not having a cookie service isn't an error
nsCOMPtr<nsICookieService> service = do_GetService(NS_COOKIESERVICE_CONTRACTID);
@@ -1310,6 +1315,11 @@ nsHTMLDocument::SetCookie(const nsAString& aCookie, ErrorResult& rv)
return;
}
+ // If the document is a cookie-averse document, do nothing.
+ if (IsCookieAverse()) {
+ return;
+ }
+
// not having a cookie service isn't an error
nsCOMPtr<nsICookieService> service = do_GetService(NS_COOKIESERVICE_CONTRACTID);
if (service && mDocumentURI) {
@@ -1526,6 +1536,18 @@ nsHTMLDocument::Open(JSContext* cx,
nsCOMPtr<nsIDocument> ret = this;
return ret.forget();
}
+
+ // Now double-check that our invariants still hold.
+ if (!mScriptGlobalObject) {
+ nsCOMPtr<nsIDocument> ret = this;
+ return ret.forget();
+ }
+
+ nsPIDOMWindowOuter* outer = GetWindow();
+ if (!outer || (GetInnerWindow() != outer->GetCurrentInnerWindow())) {
+ nsCOMPtr<nsIDocument> ret = this;
+ return ret.forget();
+ }
}
nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(shell));
@@ -1942,14 +1964,14 @@ nsHTMLDocument::Writeln(JSContext* cx, const Sequence<nsString>& aText,
}
bool
-nsHTMLDocument::MatchNameAttribute(nsIContent* aContent, int32_t aNamespaceID,
+nsHTMLDocument::MatchNameAttribute(Element* aElement, int32_t aNamespaceID,
nsIAtom* aAtom, void* aData)
{
- NS_PRECONDITION(aContent, "Must have content node to work with!");
+ NS_PRECONDITION(aElement, "Must have element to work with!");
nsString* elementName = static_cast<nsString*>(aData);
return
- aContent->GetNameSpaceID() == kNameSpaceID_XHTML &&
- aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
+ aElement->GetNameSpaceID() == kNameSpaceID_XHTML &&
+ aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
*elementName, eCaseMatters);
}
@@ -2127,26 +2149,10 @@ NS_IMETHODIMP
nsHTMLDocument::GetSelection(nsISelection** aReturn)
{
ErrorResult rv;
- NS_IF_ADDREF(*aReturn = GetSelection(rv));
+ NS_IF_ADDREF(*aReturn = nsDocument::GetSelection(rv));
return rv.StealNSResult();
}
-Selection*
-nsHTMLDocument::GetSelection(ErrorResult& aRv)
-{
- nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
- if (!window) {
- return nullptr;
- }
-
- NS_ASSERTION(window->IsInnerWindow(), "Should have inner window here!");
- if (!window->IsCurrentInnerWindow()) {
- return nullptr;
- }
-
- return nsGlobalWindow::Cast(window)->GetSelection(aRv);
-}
-
NS_IMETHODIMP
nsHTMLDocument::CaptureEvents()
{
@@ -2269,10 +2275,10 @@ nsHTMLDocument::GetForms()
return mForms;
}
-static bool MatchFormControls(nsIContent* aContent, int32_t aNamespaceID,
- nsIAtom* aAtom, void* aData)
+static bool MatchFormControls(Element* aElement, int32_t aNamespaceID,
+ nsIAtom* aAtom, void* aData)
{
- return aContent->IsNodeOfType(nsIContent::eHTML_FORM_CONTROL);
+ return aElement->IsNodeOfType(nsIContent::eHTML_FORM_CONTROL);
}
nsContentList*
diff --git a/dom/html/nsHTMLDocument.h b/dom/html/nsHTMLDocument.h
index 2dbbf2b57..1fa81f6cd 100644
--- a/dom/html/nsHTMLDocument.h
+++ b/dom/html/nsHTMLDocument.h
@@ -242,7 +242,6 @@ public:
{
// Deprecated
}
- mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aRv);
// The XPCOM CaptureEvents works fine for us.
// The XPCOM ReleaseEvents works fine for us.
// We're picking up GetLocation from Document
@@ -261,12 +260,13 @@ protected:
nsIContent *MatchId(nsIContent *aContent, const nsAString& aId);
- static bool MatchLinks(nsIContent *aContent, int32_t aNamespaceID,
+ static bool MatchLinks(mozilla::dom::Element* aElement, int32_t aNamespaceID,
+ nsIAtom* aAtom, void* aData);
+ static bool MatchAnchors(mozilla::dom::Element* aElement, int32_t aNamespaceID,
nsIAtom* aAtom, void* aData);
- static bool MatchAnchors(nsIContent *aContent, int32_t aNamespaceID,
- nsIAtom* aAtom, void* aData);
- static bool MatchNameAttribute(nsIContent* aContent, int32_t aNamespaceID,
- nsIAtom* aAtom, void* aData);
+ static bool MatchNameAttribute(mozilla::dom::Element* aElement,
+ int32_t aNamespaceID,
+ nsIAtom* aAtom, void* aData);
static void* UseExistingNameString(nsINode* aRootNode, const nsString* aName);
static void DocumentWriteTerminationFunc(nsISupports *aRef);
diff --git a/dom/html/nsIFormControl.h b/dom/html/nsIFormControl.h
index aaa92146c..e07f7c829 100644
--- a/dom/html/nsIFormControl.h
+++ b/dom/html/nsIFormControl.h
@@ -270,8 +270,8 @@ nsIFormControl::IsSingleLineTextControl(bool aExcludePassword, uint32_t aType)
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
// On Android/B2G, date/time input appears as a normal text box.
aType == NS_FORM_INPUT_TIME ||
-#endif
aType == NS_FORM_INPUT_DATE ||
+#endif
aType == NS_FORM_INPUT_MONTH ||
aType == NS_FORM_INPUT_WEEK ||
aType == NS_FORM_INPUT_DATETIME_LOCAL ||
diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp
index d70199362..187afb66d 100644
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -1418,19 +1418,16 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue)
}
}
- if (shouldInitializeEditor) {
- // Initialize the plaintext editor
- nsCOMPtr<nsIPlaintextEditor> textEditor(do_QueryInterface(newEditor));
- if (textEditor) {
+ // Initialize the plaintext editor
+ nsCOMPtr<nsIPlaintextEditor> textEditor = do_QueryInterface(newEditor);
+ if (textEditor) {
+ if (shouldInitializeEditor) {
// Set up wrapping
textEditor->SetWrapColumn(GetWrapCols());
-
- // Set max text field length
- int32_t maxLength;
- if (GetMaxLength(&maxLength)) {
- textEditor->SetMaxTextLength(maxLength);
- }
}
+
+ // Set max text field length
+ textEditor->SetMaxTextLength(GetMaxLength());
}
nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
@@ -1895,22 +1892,22 @@ be called if @placeholder is the empty string when trimmed from line breaks");
return NS_OK;
}
-bool
-nsTextEditorState::GetMaxLength(int32_t* aMaxLength)
+int32_t
+nsTextEditorState::GetMaxLength()
{
nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
nsGenericHTMLElement* element =
nsGenericHTMLElement::FromContentOrNull(content);
- NS_ENSURE_TRUE(element, false);
+ if (NS_WARN_IF(!element)) {
+ return -1;
+ }
const nsAttrValue* attr = element->GetParsedAttr(nsGkAtoms::maxlength);
if (attr && attr->Type() == nsAttrValue::eInteger) {
- *aMaxLength = attr->GetIntegerValue();
-
- return true;
+ return attr->GetIntegerValue();
}
- return false;
+ return -1;
}
void
diff --git a/dom/html/nsTextEditorState.h b/dom/html/nsTextEditorState.h
index 11494f155..caf5e8eed 100644
--- a/dom/html/nsTextEditorState.h
+++ b/dom/html/nsTextEditorState.h
@@ -203,7 +203,7 @@ public:
* @param aMaxLength the value of the max length attr
* @returns false if attr not defined
*/
- bool GetMaxLength(int32_t* aMaxLength);
+ int32_t GetMaxLength();
void ClearValueCache() { mCachedValue.Truncate(); }
diff --git a/dom/html/test/forms/mochitest.ini b/dom/html/test/forms/mochitest.ini
index 35955b189..199e4baf8 100644
--- a/dom/html/test/forms/mochitest.ini
+++ b/dom/html/test/forms/mochitest.ini
@@ -30,8 +30,14 @@ skip-if = os == "android" # up/down arrow keys not supported on android
skip-if = android_version == '18' # Android, bug 1147974
[test_input_color_picker_update.html]
skip-if = android_version == '18' # Android, bug 1147974
+[test_input_date_key_events.html]
+skip-if = os == "android"
+[test_input_datetime_input_change_events.html]
+skip-if = os == "android"
[test_input_datetime_focus_blur.html]
skip-if = os == "android"
+[test_input_datetime_focus_blur_events.html]
+skip-if = os == "android"
[test_input_datetime_tabindex.html]
skip-if = os == "android"
[test_input_defaultValue.html]
@@ -61,8 +67,6 @@ skip-if = os == "android"
[test_input_textarea_set_value_no_scroll.html]
[test_input_time_key_events.html]
skip-if = os == "android"
-[test_input_time_focus_blur_events.html]
-skip-if = os == "android"
[test_input_types_pref.html]
[test_input_typing_sanitization.html]
[test_input_untrusted_key_events.html]
diff --git a/dom/html/test/forms/test_button_attributes_reflection.html b/dom/html/test/forms/test_button_attributes_reflection.html
index 26858e939..4e702b3ac 100644
--- a/dom/html/test/forms/test_button_attributes_reflection.html
+++ b/dom/html/test/forms/test_button_attributes_reflection.html
@@ -128,9 +128,12 @@ is(typeof(document.createElement("button").setCustomValidity), "function",
"button.setCustomValidity should be a function");
// .labels
-todo("labels" in document.createElement("button"),
- "button.labels isn't implemented yet");
-
+ok("labels" in document.createElement("button"),
+ "button.labels should be an IDL attribute of the button element");
+is(typeof(document.createElement("button").labels), "object",
+ "button.labels should be an object");
+ok(document.createElement("button").labels instanceof NodeList,
+ "button.labels sohuld be an instance of NodeList");
</script>
</pre>
</body>
diff --git a/dom/html/test/forms/test_input_date_key_events.html b/dom/html/test/forms/test_input_date_key_events.html
new file mode 100644
index 000000000..f502d6a4d
--- /dev/null
+++ b/dom/html/test/forms/test_input_date_key_events.html
@@ -0,0 +1,228 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1286182
+-->
+<head>
+ <title>Test key events for time control</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta charset="UTF-8">
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1286182">Mozilla Bug 1286182</a>
+<p id="display"></p>
+<div id="content">
+ <input id="input" type="date">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+// Turn off Spatial Navigation because it hijacks arrow keydown events:
+SimpleTest.waitForFocus(function() {
+ SpecialPowers.pushPrefEnv({"set":[["snav.enabled", false]]}, function() {
+ test();
+ SimpleTest.finish();
+ });
+});
+
+var testData = [
+ /**
+ * keys: keys to send to the input element.
+ * initialVal: initial value set to the input element.
+ * expectedVal: expected value of the input element after sending the keys.
+ */
+ {
+ // Type 11222016, default order is month, day, year.
+ keys: ["11222016"],
+ initialVal: "",
+ expectedVal: "2016-11-22"
+ },
+ {
+ // Type 3 in the month field will automatically advance to the day field,
+ // then type 5 in the day field will automatically advance to the year
+ // field.
+ keys: ["352016"],
+ initialVal: "",
+ expectedVal: "2016-03-05"
+ },
+ {
+ // Type 13 in the month field will set it to the maximum month, which is
+ // 12.
+ keys: ["13012016"],
+ initialVal: "",
+ expectedVal: "2016-12-01"
+ },
+ {
+ // Type 00 in the month field will set it to the minimum month, which is 1.
+ keys: ["00012016"],
+ initialVal: "",
+ expectedVal: "2016-01-01"
+ },
+ {
+ // Type 33 in the day field will set it to the maximum day, which is 31.
+ keys: ["12332016"],
+ initialVal: "",
+ expectedVal: "2016-12-31"
+ },
+ {
+ // Type 00 in the day field will set it to the minimum day, which is 1.
+ keys: ["12002016"],
+ initialVal: "",
+ expectedVal: "2016-12-01"
+ },
+ {
+ // Type 275769 in the year field will set it to the maximum year, which is
+ // 275760.
+ keys: ["0101275769"],
+ initialVal: "",
+ expectedVal: "275760-01-01"
+ },
+ {
+ // Type 000000 in the year field will set it to the minimum year, which is
+ // 0001.
+ keys: ["0101000000"],
+ initialVal: "",
+ expectedVal: "0001-01-01"
+ },
+ {
+ // Advance to year field and decrement.
+ keys: ["VK_TAB", "VK_TAB", "VK_DOWN"],
+ initialVal: "2016-11-25",
+ expectedVal: "2015-11-25"
+ },
+ {
+ // Right key should do the same thing as TAB key.
+ keys: ["VK_RIGHT", "VK_RIGHT", "VK_DOWN"],
+ initialVal: "2016-11-25",
+ expectedVal: "2015-11-25"
+ },
+ {
+ // Advance to day field then back to month field and decrement.
+ keys: ["VK_RIGHT", "VK_LEFT", "VK_DOWN"],
+ initialVal: "2000-05-01",
+ expectedVal: "2000-04-01"
+ },
+ {
+ // Focus starts on the first field, month in this case, and increment.
+ keys: ["VK_UP"],
+ initialVal: "2000-03-01",
+ expectedVal: "2000-04-01"
+ },
+ {
+ // Advance to day field and decrement.
+ keys: ["VK_TAB", "VK_DOWN"],
+ initialVal: "1234-01-01",
+ expectedVal: "1234-01-31"
+ },
+ {
+ // Advance to day field and increment.
+ keys: ["VK_TAB", "VK_UP"],
+ initialVal: "1234-01-01",
+ expectedVal: "1234-01-02"
+ },
+ {
+ // PageUp on month field increments month by 3.
+ keys: ["VK_PAGE_UP"],
+ initialVal: "1999-01-01",
+ expectedVal: "1999-04-01"
+ },
+ {
+ // PageDown on month field decrements month by 3.
+ keys: ["VK_PAGE_DOWN"],
+ initialVal: "1999-01-01",
+ expectedVal: "1999-10-01"
+ },
+ {
+ // PageUp on day field increments day by 7.
+ keys: ["VK_TAB", "VK_PAGE_UP"],
+ initialVal: "1999-01-01",
+ expectedVal: "1999-01-08"
+ },
+ {
+ // PageDown on day field decrements day by 7.
+ keys: ["VK_TAB", "VK_PAGE_DOWN"],
+ initialVal: "1999-01-01",
+ expectedVal: "1999-01-25"
+ },
+ {
+ // PageUp on year field increments year by 10.
+ keys: ["VK_TAB", "VK_TAB", "VK_PAGE_UP"],
+ initialVal: "1999-01-01",
+ expectedVal: "2009-01-01"
+ },
+ {
+ // PageDown on year field decrements year by 10.
+ keys: ["VK_TAB", "VK_TAB", "VK_PAGE_DOWN"],
+ initialVal: "1999-01-01",
+ expectedVal: "1989-01-01"
+ },
+ {
+ // Home key on month field sets it to the minimum month, which is 01.
+ keys: ["VK_HOME"],
+ initialVal: "2016-06-01",
+ expectedVal: "2016-01-01"
+ },
+ {
+ // End key on month field sets it to the maximum month, which is 12.
+ keys: ["VK_END"],
+ initialVal: "2016-06-01",
+ expectedVal: "2016-12-01"
+ },
+ {
+ // Home key on day field sets it to the minimum day, which is 01.
+ keys: ["VK_TAB", "VK_HOME"],
+ initialVal: "2016-01-10",
+ expectedVal: "2016-01-01"
+ },
+ {
+ // End key on day field sets it to the maximum day, which is 31.
+ keys: ["VK_TAB", "VK_END"],
+ initialVal: "2016-01-10",
+ expectedVal: "2016-01-31"
+ },
+ {
+ // Home key should have no effect on year field.
+ keys: ["VK_TAB", "VK_TAB", "VK_HOME"],
+ initialVal: "2016-01-01",
+ expectedVal: "2016-01-01"
+ },
+ {
+ // End key should have no effect on year field.
+ keys: ["VK_TAB", "VK_TAB", "VK_END"],
+ initialVal: "2016-01-01",
+ expectedVal: "2016-01-01"
+ },
+];
+
+function sendKeys(aKeys) {
+ for (let i = 0; i < aKeys.length; i++) {
+ let key = aKeys[i];
+ if (key.startsWith("VK")) {
+ synthesizeKey(key, {});
+ } else {
+ sendString(key);
+ }
+ }
+}
+
+function test() {
+ var elem = document.getElementById("input");
+
+ for (let { keys, initialVal, expectedVal } of testData) {
+ elem.focus();
+ elem.value = initialVal;
+ sendKeys(keys);
+ elem.blur();
+ is(elem.value, expectedVal,
+ "Test with " + keys + ", result should be " + expectedVal);
+ elem.value = "";
+ }
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/html/test/forms/test_input_datetime_focus_blur.html b/dom/html/test/forms/test_input_datetime_focus_blur.html
index 5b8d95b25..85f7b4bb4 100644
--- a/dom/html/test/forms/test_input_datetime_focus_blur.html
+++ b/dom/html/test/forms/test_input_datetime_focus_blur.html
@@ -4,7 +4,7 @@
https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
-->
<head>
- <title>Test focus/blur behaviour for &lt;input type='time'&gt;</title>
+ <title>Test focus/blur behaviour for date/time input types</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
@@ -12,7 +12,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1288591">Mozilla Bug 1288591</a>
<p id="display"></p>
<div id="content">
- <input id="input" type="time">
+ <input id="input_time" type="time">
+ <input id="input_date" type="date">
</div>
<pre id="test">
<script type="application/javascript">
@@ -30,15 +31,15 @@ SimpleTest.waitForFocus(function() {
SimpleTest.finish();
});
-function test() {
- let time = document.getElementById("input");
- time.focus();
+function testFocusBlur(type) {
+ let input = document.getElementById("input_" + type);
+ input.focus();
- // The active element returns the input type=time.
+ // The active element returns the date/time input element.
let activeElement = document.activeElement;
- is(activeElement, time, "activeElement should be the time element");
+ is(activeElement, input, "activeElement should be the date/time input element");
is(activeElement.localName, "input", "activeElement should be an input element");
- is(activeElement.type, "time", "activeElement should be of type time");
+ is(activeElement.type, type, "activeElement should be of type " + type);
// Use FocusManager to check that the actual focus is on the anonymous
// text control.
@@ -48,10 +49,17 @@ function test() {
is(focusedElement.localName, "input", "focusedElement should be an input element");
is(focusedElement.type, "text", "focusedElement should be of type text");
- time.blur();
- isnot(document.activeElement, time, "activeElement should no longer be the time element");
+ input.blur();
+ isnot(document.activeElement, input, "activeElement should no longer be the datetime input element");
}
+function test() {
+ let inputTypes = ["time", "date"];
+
+ for (let i = 0; i < inputTypes.length; i++) {
+ testFocusBlur(inputTypes[i]);
+ }
+}
</script>
</pre>
</body>
diff --git a/dom/html/test/forms/test_input_datetime_focus_blur_events.html b/dom/html/test/forms/test_input_datetime_focus_blur_events.html
new file mode 100644
index 000000000..873dda627
--- /dev/null
+++ b/dom/html/test/forms/test_input_datetime_focus_blur_events.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1301306
+-->
+<head>
+<title>Test for Bug 1301306</title>
+<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1301306">Mozilla Bug 722599</a>
+<p id="display"></p>
+<div id="content">
+<input type="time" id="input_time" onfocus="++focusEvents[0]"
+ onblur="++blurEvents[0]" onfocusin="++focusInEvents[0]"
+ onfocusout="++focusOutEvents[0]">
+<input type="date" id="input_date" onfocus="++focusEvents[1]"
+ onblur="++blurEvents[1]" onfocusin="++focusInEvents[1]"
+ onfocusout="++focusOutEvents[1]">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/**
+ * Test for Bug 1301306.
+ * This test checks that when moving inside the time input element, e.g. jumping
+ * through the inner text boxes, does not fire extra focus/blur events.
+ **/
+
+var inputTypes = ["time", "date"];
+var focusEvents = [0, 0];
+var focusInEvents = [0, 0];
+var focusOutEvents = [0, 0];
+var blurEvents = [0, 0];
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+ test();
+ SimpleTest.finish();
+});
+
+function test() {
+ for (var i = 0; i < inputTypes.length; i++) {
+ var input = document.getElementById("input_" + inputTypes[i]);
+
+ input.focus();
+ is(focusEvents[i], 1, inputTypes[i] + " input element should have dispatched focus event.");
+ is(focusInEvents[i], 1, inputTypes[i] + " input element should have dispatched focusin event.");
+ is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
+ is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event.");
+
+ // Move around inside the input element's input box.
+ synthesizeKey("VK_TAB", {});
+ is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event.");
+ is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
+ is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
+ is(blurEvents[i], 0, inputTypes[i] + " time input element should not have dispatched blur event.");
+
+ synthesizeKey("VK_RIGHT", {});
+ is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event.");
+ is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
+ is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
+ is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event.");
+
+ synthesizeKey("VK_LEFT", {});
+ is(focusEvents[i], 1,inputTypes[i] + " input element should not have dispatched focus event.");
+ is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
+ is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
+ is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event.");
+
+ synthesizeKey("VK_RIGHT", {});
+ is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event.");
+ is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
+ is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
+ is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event.");
+
+ input.blur();
+ is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event.");
+ is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
+ is(focusOutEvents[i], 1, inputTypes[i] + " input element should have dispatched focusout event.");
+ is(blurEvents[i], 1, inputTypes[i] + " input element should have dispatched blur event.");
+ }
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/html/test/forms/test_input_datetime_input_change_events.html b/dom/html/test/forms/test_input_datetime_input_change_events.html
new file mode 100644
index 000000000..e636995d3
--- /dev/null
+++ b/dom/html/test/forms/test_input_datetime_input_change_events.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1370858
+-->
+<head>
+<title>Test for Bug 1370858</title>
+<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1370858">Mozilla Bug 722599</a>
+<p id="display"></p>
+<div id="content">
+<input type="time" id="input_time" onchange="++changeEvents[0]"
+ oninput="++inputEvents[0]">
+<input type="date" id="input_date" onchange="++changeEvents[1]"
+ oninput="++inputEvents[1]">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/**
+ * Test for Bug 1370858.
+ * Test that change and input events are (not) fired for date/time inputs.
+ **/
+
+var inputTypes = ["time", "date"];
+var changeEvents = [0, 0];
+var inputEvents = [0, 0];
+var values = ["10:30", "2017-06-08"];
+var expectedValues = [["09:30", "01:30"], ["2017-05-08", "2017-01-08"]];
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+ test();
+ SimpleTest.finish();
+});
+
+function test() {
+ for (var i = 0; i < inputTypes.length; i++) {
+ var input = document.getElementById("input_" + inputTypes[i]);
+ var inputRect = input.getBoundingClientRect();
+
+ // Points over the input's reset button
+ var resetButton_X = inputRect.width - 15;
+ var resetButton_Y = inputRect.height / 2;
+
+ is(changeEvents[i], 0, "Number of change events should be 0 at start.");
+ is(inputEvents[i], 0, "Number of input events should be 0 at start.");
+
+ // Test that change and input events are not dispatched setting .value by
+ // script.
+ input.value = values[i];
+ is(input.value, values[i], "Check that value was set correctly (0).");
+ is(changeEvents[i], 0, "Change event should not have dispatched (0).");
+ is(inputEvents[i], 0, "Input event should not have dispatched (0).");
+
+ // Test that change and input events are fired when changing the value using
+ // up/down keys.
+ input.focus();
+ synthesizeKey("VK_DOWN", {});
+ is(input.value, expectedValues[i][0], "Check that value was set correctly (1).");
+ is(changeEvents[i], 1, "Change event should be dispatched (1).");
+ is(inputEvents[i], 1, "Input event should ne dispatched (1).");
+
+ // Test that change and input events are fired when changing the value with
+ // the keyboard.
+ synthesizeKey("0", {});
+ synthesizeKey("1", {});
+ is(input.value, expectedValues[i][1], "Check that value was set correctly (2).");
+ is(changeEvents[i], 2, "Change event should be dispatched (2).");
+ is(inputEvents[i], 2, "Input event should be dispatched (2).");
+
+ // Test that change and input events are fired when clearing the value using
+ // the reset button.
+ synthesizeMouse(input, resetButton_X, resetButton_Y, {});
+ is(input.value, "", "Check that value was set correctly (3).");
+ is(changeEvents[i], 3, "Change event should be dispatched (3).");
+ is(inputEvents[i], 3, "Input event should be dispatched (3).");
+ }
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/html/test/forms/test_input_datetime_tabindex.html b/dom/html/test/forms/test_input_datetime_tabindex.html
index fb7c9b2f1..8023ccf9b 100644
--- a/dom/html/test/forms/test_input_datetime_tabindex.html
+++ b/dom/html/test/forms/test_input_datetime_tabindex.html
@@ -4,7 +4,7 @@
https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
-->
<head>
- <title>Test tabindex attribute for &lt;input type='time'&gt;</title>
+ <title>Test tabindex attribute for date/time input types</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
@@ -16,13 +16,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
<input id="time1" type="time" tabindex="0">
<input id="time2" type="time" tabindex="-1">
<input id="time3" type="time" tabindex="0">
+ <input id="date1" type="date" tabindex="0">
+ <input id="date2" type="date" tabindex="-1">
+ <input id="date3" type="date" tabindex="0">
</div>
<pre id="test">
<script type="application/javascript">
/**
* Test for Bug 1288591.
- * This test checks whether date/time input types' tabindex attribute works
+ * This test checks whether date/time input types tabindex attribute works
* correctly.
**/
SimpleTest.waitForExplicitFinish();
@@ -31,41 +34,49 @@ SimpleTest.waitForFocus(function() {
SimpleTest.finish();
});
-function test() {
- let time1 = document.getElementById("time1");
- let time2 = document.getElementById("time2");
- let time3 = document.getElementById("time3");
+function testTabindex(type) {
+ let input1 = document.getElementById(type + "1");
+ let input2 = document.getElementById(type + "2");
+ let input3 = document.getElementById(type + "3");
- time1.focus();
- is(document.activeElement, time1,
+ input1.focus();
+ is(document.activeElement, input1,
"input element with tabindex=0 is focusable");
- // Advance to time1 minute field
+ // Advance to next inner field
synthesizeKey("VK_TAB", {});
- is(document.activeElement, time1,
+ is(document.activeElement, input1,
"input element with tabindex=0 is tabbable");
- // Advance to time1 AM/PM field
+ // Advance to next inner field
synthesizeKey("VK_TAB", {});
- is(document.activeElement, time1,
+ is(document.activeElement, input1,
"input element with tabindex=0 is tabbable");
// Advance to next element
synthesizeKey("VK_TAB", {});
- is(document.activeElement, time3,
+ is(document.activeElement, input3,
"input element with tabindex=-1 is not tabbable");
- time2.focus();
- is(document.activeElement, time2,
+ input2.focus();
+ is(document.activeElement, input2,
"input element with tabindex=-1 is still focusable");
// Changing the tabindex attribute dynamically.
- time3.setAttribute("tabindex", "-1");
- synthesizeKey("VK_TAB", {}); // need only one TAB since time2 is not tabbable
- isnot(document.activeElement, time3,
+ input3.setAttribute("tabindex", "-1");
+ synthesizeKey("VK_TAB", {}); // need only one TAB since input2 is not tabbable
+ isnot(document.activeElement, input3,
"element with tabindex changed to -1 should not be tabbable");
}
+function test() {
+ let inputTypes = ["time", "date"];
+
+ for (let i = 0; i < inputTypes.length; i++) {
+ testTabindex(inputTypes[i]);
+ }
+}
+
</script>
</pre>
</body>
diff --git a/dom/html/test/forms/test_input_time_focus_blur_events.html b/dom/html/test/forms/test_input_time_focus_blur_events.html
deleted file mode 100644
index 483741477..000000000
--- a/dom/html/test/forms/test_input_time_focus_blur_events.html
+++ /dev/null
@@ -1,82 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1301306
--->
-<head>
-<title>Test for Bug 1301306</title>
-<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1301306">Mozilla Bug 722599</a>
-<p id="display"></p>
-<div id="content">
-<input type="time" id="input_time" onfocus="++focusEvent" onblur="++blurEvent"
- onfocusin="++focusInEvent" onfocusout="++focusOutEvent">
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
-/**
- * Test for Bug 1301306.
- * This test checks that when moving inside the time input element, e.g. jumping
- * through the inner text boxes, does not fire extra focus/blur events.
- **/
-
-var focusEvent = 0;
-var focusInEvent = 0;
-var focusOutEvent = 0;
-var blurEvent = 0;
-
-SimpleTest.waitForExplicitFinish();
-SimpleTest.waitForFocus(function() {
- test();
- SimpleTest.finish();
-});
-
-function test() {
- var time = document.getElementById("input_time");
- time.focus();
- is(focusEvent, 1, "time input element should have dispatched focus event.");
- is(focusInEvent, 1, "time input element should have dispatched focusin event.");
- is(focusOutEvent, 0, "time input element should not have dispatched focusout event.");
- is(blurEvent, 0, "time input element should not have dispatched blur event.");
-
- // Move around inside the input element's input box.
- synthesizeKey("VK_TAB", {});
- is(focusEvent, 1, "time input element should not have dispatched focus event.");
- is(focusInEvent, 1, "time input element should have dispatched focusin event.");
- is(focusOutEvent, 0, "time input element should not have dispatched focusout event.");
- is(blurEvent, 0, "time input element should not have dispatched blur event.");
-
- synthesizeKey("VK_RIGHT", {});
- is(focusEvent, 1, "time input element should not have dispatched focus event.");
- is(focusInEvent, 1, "time input element should have dispatched focusin event.");
- is(focusOutEvent, 0, "time input element should not have dispatched focusout event.");
- is(blurEvent, 0, "time input element should not have dispatched blur event.");
-
- synthesizeKey("VK_LEFT", {});
- is(focusEvent, 1, "time input element should not have dispatched focus event.");
- is(focusInEvent, 1, "time input element should have dispatched focusin event.");
- is(focusOutEvent, 0, "time input element should not have dispatched focusout event.");
- is(blurEvent, 0, "time input element should not have dispatched blur event.");
-
- synthesizeKey("VK_RIGHT", {});
- is(focusEvent, 1, "time input element should not have dispatched focus event.");
- is(focusInEvent, 1, "time input element should have dispatched focusin event.");
- is(focusOutEvent, 0, "time input element should not have dispatched focusout event.");
- is(blurEvent, 0, "time input element should not have dispatched blur event.");
-
- time.blur();
- is(focusEvent, 1, "time input element should not have dispatched focus event.");
- is(focusInEvent, 1, "time input element should have dispatched focusin event.");
- is(focusOutEvent, 1, "time input element should not have dispatched focusout event.");
- is(blurEvent, 1, "time input element should have dispatched blur event.");
-}
-
-</script>
-</pre>
-</body>
-</html>
diff --git a/dom/html/test/forms/test_input_types_pref.html b/dom/html/test/forms/test_input_types_pref.html
index 243836f34..5279d6a2a 100644
--- a/dom/html/test/forms/test_input_types_pref.html
+++ b/dom/html/test/forms/test_input_types_pref.html
@@ -37,47 +37,63 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=764481
inputType: "color",
expectedType: "color"
}, {
- prefs: [["dom.experimental_forms", false], ["dom.forms.datepicker", false],
- ["dom.forms.datetime", false]],
+ prefs: [["dom.experimental_forms", false], ["dom.forms.datetime", false]],
inputType: "date",
expectedType: "text"
}, {
- prefs: [["dom.experimental_forms", true], ["dom.forms.datepicker", false],
- ["dom.forms.datetime", false]],
+ prefs: [["dom.experimental_forms", true], ["dom.forms.datetime", false]],
inputType: "date",
expectedType: "date"
}, {
- prefs: [["dom.experimental_forms", false], ["dom.forms.datepicker", true],
- ["dom.forms.datetime", false]],
+ prefs: [["dom.experimental_forms", false], ["dom.forms.datetime", true]],
inputType: "date",
expectedType: "date"
}, {
- prefs: [["dom.experimental_forms", false], ["dom.forms.datepicker", false],
- ["dom.forms.datetime", true]],
- inputType: "date",
- expectedType: "date"
+ prefs: [["dom.experimental_forms", false], ["dom.forms.datetime", false]],
+ inputType: "time",
+ expectedType: "text"
+ }, {
+ prefs: [["dom.experimental_forms", true], ["dom.forms.datetime", false]],
+ inputType: "time",
+ expectedType: "time"
+ }, {
+ prefs: [["dom.experimental_forms", false], ["dom.forms.datetime", true]],
+ inputType: "time",
+ expectedType: "time"
+ }, {
+ prefs: [["dom.forms.datetime", false], ["dom.forms.datetime.others", false]],
+ inputType: "month",
+ expectedType: "text"
}, {
- prefs: [["dom.forms.datetime", false]],
+ prefs: [["dom.forms.datetime", true], ["dom.forms.datetime.others", false]],
inputType: "month",
expectedType: "text"
}, {
- prefs: [["dom.forms.datetime", true]],
+ prefs: [["dom.forms.datetime", false], ["dom.forms.datetime.others", true]],
inputType: "month",
expectedType: "month"
}, {
- prefs: [["dom.forms.datetime", false]],
+ prefs: [["dom.forms.datetime", false], ["dom.forms.datetime.others", false]],
+ inputType: "week",
+ expectedType: "text"
+ }, {
+ prefs: [["dom.forms.datetime", true], ["dom.forms.datetime.others", false]],
inputType: "week",
expectedType: "text"
}, {
- prefs: [["dom.forms.datetime", true]],
+ prefs: [["dom.forms.datetime", false], ["dom.forms.datetime.others", true]],
inputType: "week",
expectedType: "week"
}, {
- prefs: [["dom.forms.datetime", false]],
+ prefs: [["dom.forms.datetime", false], ["dom.forms.datetime.others", false]],
+ inputType: "datetime-local",
+ expectedType: "text"
+ }, {
+ prefs: [["dom.forms.datetime", true], ["dom.forms.datetime.others", false]],
inputType: "datetime-local",
expectedType: "text"
}, {
- prefs: [["dom.forms.datetime", true]],
+ prefs: [["dom.forms.datetime", false], ["dom.forms.datetime.others", true]],
inputType: "datetime-local",
expectedType: "datetime-local"
}
diff --git a/dom/html/test/forms/test_input_typing_sanitization.html b/dom/html/test/forms/test_input_typing_sanitization.html
index 0896f19df..eee300b33 100644
--- a/dom/html/test/forms/test_input_typing_sanitization.html
+++ b/dom/html/test/forms/test_input_typing_sanitization.html
@@ -26,6 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=765772
* This test checks that when a user types in some input types, it will not be
* in a state where the value will be un-sanitized and usable (by a script).
*/
+const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
var input = document.getElementById('i');
var form = document.getElementById('f');
@@ -143,6 +144,7 @@ function runTest()
]
},
{
+ mobileOnly: true,
type: 'date',
validData: [
'0001-01-01',
@@ -161,6 +163,28 @@ function runTest()
]
},
{
+ mobileOnly: true,
+ type: 'time',
+ validData: [
+ '00:00',
+ '09:09:00',
+ '08:23:23.1',
+ '21:43:56.12',
+ '23:12:45.100',
+ ],
+ invalidData: [
+ '00:',
+ '00:00:',
+ '25:00',
+ '-00:00',
+ '00:00:00.',
+ '00:60',
+ '10:58:99',
+ ':19:10',
+ '23:08:09.1012',
+ ]
+ },
+ {
type: 'month',
validData: [
'0001-01',
@@ -218,6 +242,10 @@ function runTest()
for (test of data) {
gCurrentTest = test;
+ if (gCurrentTest.mobileOnly && isDesktop) {
+ continue;
+ }
+
input.type = test.type;
gValidData = test.validData;
gInvalidData = test.invalidData;
diff --git a/dom/html/test/forms/test_max_attribute.html b/dom/html/test/forms/test_max_attribute.html
index 4007cfad6..091ad321b 100644
--- a/dom/html/test/forms/test_max_attribute.html
+++ b/dom/html/test/forms/test_max_attribute.html
@@ -31,8 +31,7 @@ var data = [
{ type: 'month', apply: true },
{ type: 'week', apply: true },
{ type: 'time', apply: true },
- // TODO: temporary set to false until bug 888331 is fixed.
- { type: 'datetime-local', apply: false },
+ { type: 'datetime-local', apply: true },
{ type: 'number', apply: true },
{ type: 'range', apply: true },
{ type: 'color', apply: false },
@@ -71,7 +70,8 @@ function checkValidity(aElement, aValidity, aApply, aRangeApply)
"element overflow status should be " + !aValidity);
var overflowMsg =
(aElement.type == "date" || aElement.type == "time" ||
- aElement.type == "month" || aElement.type == "week") ?
+ aElement.type == "month" || aElement.type == "week" ||
+ aElement.type == "datetime-local") ?
("Please select a value that is no later than " + aElement.max + ".") :
("Please select a value that is no more than " + aElement.max + ".");
is(aElement.validationMessage,
@@ -148,7 +148,7 @@ for (var test of data) {
input.max = '2016-W39';
break;
case 'datetime-local':
- // TODO: this is temporary until bug 888331 is fixed.
+ input.max = '2016-12-31T23:59:59';
break;
default:
ok(false, 'please, add a case for this new type (' + input.type + ')');
@@ -421,7 +421,44 @@ for (var test of data) {
break;
case 'datetime-local':
- // TODO: this is temporary until bug 888331 is fixed.
+ input.value = '2016-01-01T12:00';
+ checkValidity(input, true, apply, apply);
+
+ input.value = '2016-12-31T23:59:59';
+ checkValidity(input, true, apply, apply);
+
+ input.value = 'foo';
+ checkValidity(input, true, apply, apply);
+
+ input.value = '2016-12-31T23:59:59.123';
+ checkValidity(input, false, apply, apply);
+
+ input.value = '2017-01-01T10:00';
+ checkValidity(input, false, apply, apply);
+
+ input.max = '2017-01-01T10:00';
+ checkValidity(input, true, apply, apply);
+
+ input.value = '2017-01-01T10:00:30';
+ checkValidity(input, false, apply, apply);
+
+ input.value = '1000-01-01T12:00';
+ checkValidity(input, true, apply, apply);
+
+ input.value = '2100-01-01T12:00';
+ checkValidity(input, false, apply, apply);
+
+ input.max = '0050-12-31T23:59:59.999';
+ checkValidity(input, false, apply, apply);
+
+ input.value = '0050-12-31T23:59:59';
+ checkValidity(input, true, apply, apply);
+
+ input.max = '';
+ checkValidity(input, true, apply, false);
+
+ input.max = 'foo';
+ checkValidity(input, true, apply, false);
break;
}
diff --git a/dom/html/test/forms/test_min_attribute.html b/dom/html/test/forms/test_min_attribute.html
index 1258babec..22f21de39 100644
--- a/dom/html/test/forms/test_min_attribute.html
+++ b/dom/html/test/forms/test_min_attribute.html
@@ -31,8 +31,7 @@ var data = [
{ type: 'month', apply: true },
{ type: 'week', apply: true },
{ type: 'time', apply: true },
- // TODO: temporary set to false until bug 888331 is fixed.
- { type: 'datetime-local', apply: false },
+ { type: 'datetime-local', apply: true },
{ type: 'number', apply: true },
{ type: 'range', apply: true },
{ type: 'color', apply: false },
@@ -71,7 +70,8 @@ function checkValidity(aElement, aValidity, aApply, aRangeApply)
"element underflow status should be " + !aValidity);
var underflowMsg =
(aElement.type == "date" || aElement.type == "time" ||
- aElement.type == "month" || aElement.type == "week") ?
+ aElement.type == "month" || aElement.type == "week" ||
+ aElement.type == "datetime-local") ?
("Please select a value that is no earlier than " + aElement.min + ".") :
("Please select a value that is no less than " + aElement.min + ".");
is(aElement.validationMessage,
@@ -146,10 +146,10 @@ for (var test of data) {
input.min = '2016-06';
break;
case 'week':
- input.min = "2016-W39";
+ input.min = '2016-W39';
break;
case 'datetime-local':
- // TODO: this is temporary until bug 888331 is fixed.
+ input.min = '2017-01-01T00:00';
break;
default:
ok(false, 'please, add a case for this new type (' + input.type + ')');
@@ -420,7 +420,44 @@ for (var test of data) {
checkValidity(input, true, apply, false);
break;
case 'datetime-local':
- // TODO: this is temporary until bug 888331 is fixed.
+ input.value = '2017-12-31T23:59';
+ checkValidity(input, true, apply, apply);
+
+ input.value = '2017-01-01T00:00';
+ checkValidity(input, true, apply, apply);
+
+ input.value = '2017-01-01T00:00:00.123';
+ checkValidity(input, true, apply, apply);
+
+ input.value = 'foo';
+ checkValidity(input, true, apply, apply);
+
+ input.value = '2016-12-31T23:59';
+ checkValidity(input, false, apply, apply);
+
+ input.min = '2016-01-01T00:00';
+ checkValidity(input, true, apply, apply);
+
+ input.value = '2015-12-31T23:59';
+ checkValidity(input, false, apply, apply);
+
+ input.value = '1000-01-01T00:00';
+ checkValidity(input, false, apply, apply);
+
+ input.value = '10000-01-01T00:00';
+ checkValidity(input, true, apply, apply);
+
+ input.min = '0010-01-01T12:00';
+ checkValidity(input, true, apply, apply);
+
+ input.value = '0010-01-01T10:00';
+ checkValidity(input, false, apply, apply);
+
+ input.min = '';
+ checkValidity(input, true, apply, false);
+
+ input.min = 'foo';
+ checkValidity(input, true, apply, false);
break;
default:
ok(false, 'write tests for ' + input.type);
diff --git a/dom/html/test/forms/test_step_attribute.html b/dom/html/test/forms/test_step_attribute.html
index 31277860c..a14afa461 100644
--- a/dom/html/test/forms/test_step_attribute.html
+++ b/dom/html/test/forms/test_step_attribute.html
@@ -31,8 +31,7 @@ var data = [
{ type: 'month', apply: true },
{ type: 'week', apply: true },
{ type: 'time', apply: true },
- // TODO: temporary set to false until bug 888331 is fixed.
- { type: 'datetime-local', apply: false },
+ { type: 'datetime-local', apply: true },
{ type: 'number', apply: true },
{ type: 'range', apply: true },
{ type: 'color', apply: false },
@@ -950,7 +949,104 @@ for (var test of data) {
break;
case 'datetime-local':
- // TODO: this is temporary until bug 888331 is fixed.
+ // When step is invalid, every datetime is valid
+ input.step = 0;
+ input.value = '2017-02-06T12:00';
+ checkValidity(input, true, apply);
+
+ input.step = 'foo';
+ input.value = '1970-01-01T00:00';
+ checkValidity(input, true, apply);
+
+ input.step = '-1';
+ input.value = '1969-12-12 00:10';
+ checkValidity(input, true, apply);
+
+ input.removeAttribute('step');
+ input.value = '1500-01-01T12:00';
+ checkValidity(input, true, apply);
+
+ input.step = 'any';
+ input.value = '1966-12-12T12:00';
+ checkValidity(input, true, apply);
+
+ input.step = 'ANY';
+ input.value = '2017-01-01 12:00';
+ checkValidity(input, true, apply);
+
+ // When min is set to a valid datetime, there is a step base.
+ input.min = '2017-01-01T00:00:00';
+ input.step = '2';
+ input.value = '2017-01-01T00:00:02';
+ checkValidity(input, true, apply);
+
+ input.value = '2017-01-01T00:00:03';
+ checkValidity(input, false, apply,
+ { low: "2017-01-01T00:00:02", high: "2017-01-01T00:00:04" });
+
+ input.min = '2017-01-01T00:00:05';
+ input.value = '2017-01-01T00:00:08';
+ checkValidity(input, false, apply,
+ { low: "2017-01-01T00:00:07", high: "2017-01-01T00:00:09" });
+
+ input.min = '2000-01-01T00:00';
+ input.step = '120';
+ input.value = '2000-01-01T00:02';
+ checkValidity(input, true, apply);
+
+ // Without any step attribute the datetime is valid
+ input.removeAttribute('step');
+ checkValidity(input, true, apply);
+
+ input.min = '1950-01-01T00:00';
+ input.step = '129600'; // 1.5 day
+ input.value = '1950-01-02T00:00';
+ checkValidity(input, false, apply,
+ { low: "1950-01-01T00:00", high: "1950-01-02T12:00" });
+
+ input.step = '259200'; // 3 days
+ input.value = '1950-01-04T12:00';
+ checkValidity(input, false, apply,
+ { low: "1950-01-04T00:00", high: "1950-01-07T00:00" });
+
+ input.value = '1950-01-10T00:00';
+ checkValidity(input, true, apply);
+
+ input.step = '0.5'; // half a second
+ input.value = '1950-01-01T00:00:00.123';
+ checkValidity(input, false, apply,
+ { low: "1950-01-01T00:00", high: "1950-01-01T00:00:00.500" });
+
+ input.value = '2000-01-01T12:30:30.600';
+ checkValidity(input, false, apply,
+ { low: "2000-01-01T12:30:30.500", high: "2000-01-01T12:30:31" });
+
+ input.value = '1950-01-05T00:00:00.500';
+ checkValidity(input, true, apply);
+
+ input.step = '2.1';
+ input.min = '1991-01-01T12:00';
+ input.value = '1991-01-01T12:00';
+ checkValidity(input, true, apply);
+
+ input.value = '1991-01-01T12:00:03';
+ checkValidity(input, false, apply,
+ { low: "1991-01-01T12:00:02.100", high: "1991-01-01T12:00:04.200" });
+
+ input.value = '1991-01-01T12:00:06.3';
+ checkValidity(input, true, apply);
+
+ input.step = '2.1';
+ input.min = '1969-12-20T10:00:05';
+ input.value = '1969-12-20T10:00:05';
+ checkValidity(input, true, apply);
+
+ input.value = '1969-12-20T10:00:08';
+ checkValidity(input, false, apply,
+ { low: "1969-12-20T10:00:07.100", high: "1969-12-20T10:00:09.200" });
+
+ input.value = '1969-12-20T10:00:09.200';
+ checkValidity(input, true, apply);
break;
default:
diff --git a/dom/html/test/forms/test_stepup_stepdown.html b/dom/html/test/forms/test_stepup_stepdown.html
index d96895180..21cde58aa 100644
--- a/dom/html/test/forms/test_stepup_stepdown.html
+++ b/dom/html/test/forms/test_stepup_stepdown.html
@@ -52,13 +52,8 @@ function checkAvailability()
["time", true],
["month", true],
["week", true],
- ["color", false],
- ];
-
- var todoList =
- [
- ["datetime", true],
["datetime-local", true],
+ ["color", false],
];
var element = document.createElement("input");
@@ -82,27 +77,6 @@ function checkAvailability()
}
is(exceptionCaught, !data[1], "stepUp() availability is not correct");
}
-
- for (data of todoList) {
- var exceptionCaught = false;
- element.type = data[0];
- try {
- element.stepDown();
- } catch (e) {
- exceptionCaught = true;
- }
- todo_is(exceptionCaught, !data[1],
- "stepDown() availability is not correct");
-
- exceptionCaught = false;
- try {
- element.stepUp();
- } catch (e) {
- exceptionCaught = true;
- }
- todo_is(exceptionCaught, !data[1],
- "stepUp() availability is not correct");
- }
}
function checkStepDown()
@@ -509,6 +483,80 @@ function checkStepDown()
[ '2016-W01', 'AnY', null, null, 1, null, true ],
[ '2016-W01', 'aNy', null, null, 1, null, true ],
]},
+ { type: 'datetime-local', data: [
+ // Regular case.
+ [ '2017-02-07T09:30', null, null, null, null, '2017-02-07T09:29', false ],
+ // Argument testing.
+ [ '2017-02-07T09:30', null, null, null, 1, '2017-02-07T09:29', false ],
+ [ '2017-02-07T09:30', null, null, null, 5, '2017-02-07T09:25', false ],
+ [ '2017-02-07T09:30', null, null, null, -1, '2017-02-07T09:31', false ],
+ [ '2017-02-07T09:30', null, null, null, 0, '2017-02-07T09:30', false ],
+ // hour/minutes/seconds wrapping.
+ [ '2000-01-01T05:00', null, null, null, null, '2000-01-01T04:59', false ],
+ [ '2000-01-01T05:00:00', 1, null, null, null, '2000-01-01T04:59:59', false ],
+ [ '2000-01-01T05:00:00', 0.1, null, null, null, '2000-01-01T04:59:59.900', false ],
+ [ '2000-01-01T05:00:00', 0.01, null, null, null, '2000-01-01T04:59:59.990', false ],
+ [ '2000-01-01T05:00:00', 0.001, null, null, null, '2000-01-01T04:59:59.999', false ],
+ // month/year wrapping.
+ [ '2012-08-01T12:00', null, null, null, 1440, '2012-07-31T12:00', false ],
+ [ '1969-01-02T12:00', null, null, null, 5760, '1968-12-29T12:00', false ],
+ [ '1969-12-31T00:00', null, null, null, -1440, '1970-01-01T00:00', false ],
+ [ '2012-02-29T00:00', null, null, null, -1440, '2012-03-01T00:00', false ],
+ // stepDown() on '00:00' gives '23:59'.
+ [ '2017-02-07T00:00', null, null, null, 1, '2017-02-06T23:59', false ],
+ [ '2017-02-07T00:00', null, null, null, 3, '2017-02-06T23:57', false ],
+ // Some random step values..
+ [ '2017-02-07T16:07', '0.5', null, null, null, '2017-02-07T16:06:59.500', false ],
+ [ '2017-02-07T16:07', '2', null, null, null, '2017-02-07T16:06:58', false ],
+ [ '2017-02-07T16:07', '0.25', null, null, 4, '2017-02-07T16:06:59', false ],
+ [ '2017-02-07T16:07', '1.1', '2017-02-07T16:00', null, 1, '2017-02-07T16:06:59.100', false ],
+ [ '2017-02-07T16:07', '1.1', '2017-02-07T16:00', null, 2, '2017-02-07T16:06:58', false ],
+ [ '2017-02-07T16:07', '1.1', '2017-02-07T16:00', null, 10, '2017-02-07T16:06:49.200', false ],
+ [ '2017-02-07T16:07', '129600', '2017-02-01T00:00', null, 2, '2017-02-05T12:00', false ],
+ // step = 0 isn't allowed (-> step = 1).
+ [ '2017-02-07T10:15', '0', null, null, null, '2017-02-07T10:14', false ],
+ // step < 0 isn't allowed (-> step = 1).
+ [ '2017-02-07T10:15', '-1', null, null, null, '2017-02-07T10:14', false ],
+ // step = NaN isn't allowed (-> step = 1).
+ [ '2017-02-07T10:15', 'foo', null, null, null, '2017-02-07T10:14', false ],
+ // Min values testing.
+ [ '2012-02-02T17:02', '60', 'foo', null, 2, '2012-02-02T17:00', false ],
+ [ '2012-02-02T17:10', '60', '2012-02-02T17:09', null, null, '2012-02-02T17:09', false ],
+ [ '2012-02-02T17:10', '60', '2012-02-02T17:10', null, null, '2012-02-02T17:10', false ],
+ [ '2012-02-02T17:10', '60', '2012-02-02T17:30', null, 1, '2012-02-02T17:10', false ],
+ [ '2012-02-02T17:10', '180', '2012-02-02T17:05', null, null, '2012-02-02T17:08', false ],
+ [ '2012-02-03T20:05', '86400', '2012-02-02T17:05', null, null, '2012-02-03T17:05', false ],
+ [ '2012-02-03T18:00', '129600', '2012-02-01T00:00', null, null, '2012-02-02T12:00', false ],
+ // Max values testing.
+ [ '2012-02-02T17:15', '60', null, 'foo', null, '2012-02-02T17:14', false ],
+ [ '2012-02-02T17:15', null, null, '2012-02-02T17:20', null, '2012-02-02T17:14', false ],
+ [ '2012-02-02T17:15', null, null, '2012-02-02T17:15', null, '2012-02-02T17:14', false ],
+ [ '2012-02-02T17:15', null, null, '2012-02-02T17:13', 4, '2012-02-02T17:11', false ],
+ [ '2012-02-02T17:15', '120', null, '2012-02-02T17:13', 3, '2012-02-02T17:09', false ],
+ [ '2012-02-03T20:05', '86400', null, '2012-02-03T20:05', null, '2012-02-02T20:05', false ],
+ [ '2012-02-03T18:00', '129600', null, '2012-02-03T20:00', null, '2012-02-02T06:00', false ],
+ // Step mismatch.
+ [ '2017-02-07T17:19', '120', '2017-02-07T17:10', null, null, '2017-02-07T17:18', false ],
+ [ '2017-02-07T17:19', '120', '2017-02-07T17:10', null, 2, '2017-02-07T17:16', false ],
+ [ '2017-02-07T17:19', '120', '2017-02-07T17:18', '2017-02-07T17:25', null, '2017-02-07T17:18', false ],
+ [ '2017-02-07T17:19', '120', null, null, null, '2017-02-07T17:17', false ],
+ [ '2017-02-07T17:19', '180', null, null, null, '2017-02-07T17:16', false ],
+ [ '2017-02-07T17:19', '172800', '2017-02-02T17:19', '2017-02-10T17:19', null, '2017-02-06T17:19', false ],
+ // Clamping.
+ [ '2017-02-07T17:22', null, null, '2017-02-07T17:11', null, '2017-02-07T17:11', false ],
+ [ '2017-02-07T17:22', '120', '2017-02-07T17:20', '2017-02-07T17:22', null, '2017-02-07T17:20', false ],
+ [ '2017-02-07T17:22', '300', '2017-02-07T17:12', '2017-02-07T17:20', 10, '2017-02-07T17:12', false ],
+ [ '2017-02-07T17:22', '300', '2017-02-07T17:18', '2017-02-07T17:20', 2, '2017-02-07T17:18', false ],
+ [ '2017-02-07T17:22', '600', '2017-02-02T17:00', '2017-02-07T17:00', 15, '2017-02-07T15:00', false ],
+ [ '2017-02-07T17:22', '600', '2017-02-02T17:00', '2017-02-07T17:00', 2, '2017-02-07T17:00', false ],
+ // value = "" (NaN).
+ [ '', null, null, null, null, '1969-12-31T23:59', false ],
+ // With step = 'any'.
+ [ '2017-02-07T15:20', 'any', null, null, 1, null, true ],
+ [ '2017-02-07T15:20', 'ANY', null, null, 1, null, true ],
+ [ '2017-02-07T15:20', 'AnY', null, null, 1, null, true ],
+ [ '2017-02-07T15:20', 'aNy', null, null, 1, null, true ],
+ ]},
];
for (var test of testData) {
@@ -958,6 +1006,78 @@ function checkStepUp()
[ '2016-W01', 'AnY', null, null, 1, null, true ],
[ '2016-W01', 'aNy', null, null, 1, null, true ],
]},
+ { type: 'datetime-local', data: [
+ // Regular case.
+ [ '2017-02-07T17:09', null, null, null, null, '2017-02-07T17:10', false ],
+ // Argument testing.
+ [ '2017-02-07T17:10', null, null, null, 1, '2017-02-07T17:11', false ],
+ [ '2017-02-07T17:10', null, null, null, 5, '2017-02-07T17:15', false ],
+ [ '2017-02-07T17:10', null, null, null, -1, '2017-02-07T17:09', false ],
+ [ '2017-02-07T17:10', null, null, null, 0, '2017-02-07T17:10', false ],
+ // hour/minutes/seconds wrapping.
+ [ '2000-01-01T04:59', null, null, null, null, '2000-01-01T05:00', false ],
+ [ '2000-01-01T04:59:59', 1, null, null, null, '2000-01-01T05:00', false ],
+ [ '2000-01-01T04:59:59.900', 0.1, null, null, null, '2000-01-01T05:00', false ],
+ [ '2000-01-01T04:59:59.990', 0.01, null, null, null, '2000-01-01T05:00', false ],
+ [ '2000-01-01T04:59:59.999', 0.001, null, null, null, '2000-01-01T05:00', false ],
+ // month/year wrapping.
+ [ '2012-07-31T12:00', null, null, null, 1440, '2012-08-01T12:00', false ],
+ [ '1968-12-29T12:00', null, null, null, 5760, '1969-01-02T12:00', false ],
+ [ '1970-01-01T00:00', null, null, null, -1440, '1969-12-31T00:00', false ],
+ [ '2012-03-01T00:00', null, null, null, -1440, '2012-02-29T00:00', false ],
+ // stepUp() on '23:59' gives '00:00'.
+ [ '2017-02-07T23:59', null, null, null, 1, '2017-02-08T00:00', false ],
+ [ '2017-02-07T23:59', null, null, null, 3, '2017-02-08T00:02', false ],
+ // Some random step values..
+ [ '2017-02-07T17:40', '0.5', null, null, null, '2017-02-07T17:40:00.500', false ],
+ [ '2017-02-07T17:40', '2', null, null, null, '2017-02-07T17:40:02', false ],
+ [ '2017-02-07T17:40', '0.25', null, null, 4, '2017-02-07T17:40:01', false ],
+ [ '2017-02-07T17:40', '1.1', '2017-02-07T17:00', null, 1, '2017-02-07T17:40:00.200', false ],
+ [ '2017-02-07T17:40', '1.1', '2017-02-07T17:00', null, 2, '2017-02-07T17:40:01.300', false ],
+ [ '2017-02-07T17:40', '1.1', '2017-02-07T17:00', null, 10, '2017-02-07T17:40:10.100', false ],
+ [ '2017-02-07T17:40', '129600', '2017-02-01T00:00', null, 2, '2017-02-10T00:00', false ],
+ // step = 0 isn't allowed (-> step = 1).
+ [ '2017-02-07T17:39', '0', null, null, null, '2017-02-07T17:40', false ],
+ // step < 0 isn't allowed (-> step = 1).
+ [ '2017-02-07T17:39', '-1', null, null, null, '2017-02-07T17:40', false ],
+ // step = NaN isn't allowed (-> step = 1).
+ [ '2017-02-07T17:39', 'foo', null, null, null, '2017-02-07T17:40', false ],
+ // Min values testing.
+ [ '2012-02-02T17:00', '60', 'foo', null, 2, '2012-02-02T17:02', false ],
+ [ '2012-02-02T17:10', '60', '2012-02-02T17:10', null, null, '2012-02-02T17:11', false ],
+ [ '2012-02-02T17:10', '60', '2012-02-02T17:30', null, 1, '2012-02-02T17:30', false ],
+ [ '2012-02-02T17:10', '180', '2012-02-02T17:05', null, null, '2012-02-02T17:11', false ],
+ [ '2012-02-02T17:10', '86400', '2012-02-02T17:05', null, null, '2012-02-03T17:05', false ],
+ [ '2012-02-02T17:10', '129600', '2012-02-01T00:00', null, null, '2012-02-04T00:00', false ],
+ // Max values testing.
+ [ '2012-02-02T17:15', '60', null, 'foo', null, '2012-02-02T17:16', false ],
+ [ '2012-02-02T17:15', null, null, '2012-02-02T17:20', null, '2012-02-02T17:16', false ],
+ [ '2012-02-02T17:15', null, null, '2012-02-02T17:15', null, '2012-02-02T17:15', false ],
+ [ '2012-02-02T17:15', null, null, '2012-02-02T17:13', 4, '2012-02-02T17:15', false ],
+ [ '2012-02-02T20:05', '86400', null, '2012-02-03T20:05', null, '2012-02-03T20:05', false ],
+ [ '2012-02-02T18:00', '129600', null, '2012-02-04T20:00', null, '2012-02-04T06:00', false ],
+ // Step mismatch.
+ [ '2017-02-07T17:19', '120', '2017-02-07T17:10', null, null, '2017-02-07T17:20', false ],
+ [ '2017-02-07T17:19', '120', '2017-02-07T17:10', null, 2, '2017-02-07T17:22', false ],
+ [ '2017-02-07T17:19', '120', '2017-02-07T17:18', '2017-02-07T17:25', null, '2017-02-07T17:20', false ],
+ [ '2017-02-07T17:19', '120', null, null, null, '2017-02-07T17:21', false ],
+ [ '2017-02-07T17:19', '180', null, null, null, '2017-02-07T17:22', false ],
+ [ '2017-02-03T17:19', '172800', '2017-02-02T17:19', '2017-02-10T17:19', null, '2017-02-04T17:19', false ],
+ // Clamping.
+ [ '2017-02-07T17:22', null, null, '2017-02-07T17:11', null, '2017-02-07T17:22', false ],
+ [ '2017-02-07T17:22', '120', '2017-02-07T17:20', '2017-02-07T17:22', null, '2017-02-07T17:22', false ],
+ [ '2017-02-07T17:22', '300', '2017-02-07T17:12', '2017-02-07T17:20', 10, '2017-02-07T17:22', false ],
+ [ '2017-02-07T17:22', '300', '2017-02-07T17:18', '2017-02-07T17:20', 2, '2017-02-07T17:22', false ],
+ [ '2017-02-06T17:22', '600', '2017-02-02T17:00', '2017-02-07T17:20', 15, '2017-02-06T19:50', false ],
+ [ '2017-02-06T17:22', '600', '2017-02-02T17:10', '2017-02-07T17:20', 2, '2017-02-06T17:40', false ],
+ // value = "" (NaN).
+ [ '', null, null, null, null, '1970-01-01T00:01', false ],
+ // With step = 'any'.
+ [ '2017-02-07T17:30', 'any', null, null, 1, null, true ],
+ [ '2017-02-07T17:30', 'ANY', null, null, 1, null, true ],
+ [ '2017-02-07T17:30', 'AnY', null, null, 1, null, true ],
+ [ '2017-02-07T17:30', 'aNy', null, null, 1, null, true ],
+ ]},
];
for (var test of testData) {
diff --git a/dom/html/test/forms/test_valueAsDate_pref.html b/dom/html/test/forms/test_valueAsDate_pref.html
index 8518c291b..0369980e4 100644
--- a/dom/html/test/forms/test_valueAsDate_pref.html
+++ b/dom/html/test/forms/test_valueAsDate_pref.html
@@ -12,8 +12,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=874640
/** Test for Bug 874640 **/
var states = [
- // dom.experimental_forms, dom.forms.datepicker, dom.forms.datetime, expectedValueAsDate
- [ 'true', 'true', 'true', 'true' ],
+ // dom.experimental_forms, dom.forms.datetime, dom.forms.datetime.others, expectedValueAsDate
+ [ 'true', 'true', ,'true', 'true' ],
[ 'true', 'false', 'false', 'true' ],
[ 'false', 'true', 'false', 'true' ],
[ 'false', 'false', 'true', 'true' ],
@@ -33,8 +33,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=874640
SpecialPowers.pushPrefEnv({"set":[
["dom.experimental_forms", state[0] === 'true'],
- ["dom.forms.datepicker", state[1] === 'true'],
- ["dom.forms.datetime", state[2] === 'true']]},
+ ["dom.forms.datetime", state[1] === 'true'],
+ ["dom.forms.datetime.others", state[2] === 'true']]},
function() {
iframe.src = 'data:text/html,<script>' +
'parent.is("valueAsDate" in document.createElement("input"), ' +
diff --git a/dom/html/test/forms/test_valueasdate_attribute.html b/dom/html/test/forms/test_valueasdate_attribute.html
index 8c19fefd9..65cab3b8e 100644
--- a/dom/html/test/forms/test_valueasdate_attribute.html
+++ b/dom/html/test/forms/test_valueasdate_attribute.html
@@ -47,8 +47,7 @@ var validTypes =
["color", false],
["month", true],
["week", true],
- // TODO: temporary set to false until bug 888331 is fixed.
- ["datetime-local", false],
+ ["datetime-local", true],
];
function checkAvailability()
@@ -622,6 +621,107 @@ function checkWeekSet()
}
}
+function checkDatetimeLocalGet()
+{
+ var validData =
+ [
+ // Simple cases.
+ [ "2016-12-27T10:30", Date.UTC(2016, 11, 27, 10, 30, 0) ],
+ [ "2016-12-27T10:30:40", Date.UTC(2016, 11, 27, 10, 30, 40) ],
+ [ "2016-12-27T10:30:40.567", Date.UTC(2016, 11, 27, 10, 30, 40, 567) ],
+ [ "1969-12-31T12:00:00", Date.UTC(1969, 11, 31, 12, 0, 0) ],
+ [ "1970-01-01T00:00", 0 ],
+ // Leap years.
+ [ "1804-02-29 12:34", Date.UTC(1804, 1, 29, 12, 34, 0) ],
+ [ "2016-02-29T12:34", Date.UTC(2016, 1, 29, 12, 34, 0) ],
+ [ "2016-12-31T12:34:56", Date.UTC(2016, 11, 31, 12, 34, 56) ],
+ [ "2016-01-01T12:34:56.789", Date.UTC(2016, 0, 1, 12, 34, 56, 789) ],
+ [ "2017-01-01 12:34:56.789", Date.UTC(2017, 0, 1, 12, 34, 56, 789) ],
+ // Maximum valid datetime-local (limited by the ecma date object range).
+ [ "275760-09-13T00:00", 8640000000000000 ],
+ // Minimum valid datetime-local (limited by the input element minimum valid value).
+ [ "0001-01-01T00:00", -62135596800000 ],
+ ];
+
+ var invalidData =
+ [
+ [ "invaliddateime-local" ],
+ [ "0000-01-01T00:00" ],
+ [ "2016-12-25T00:00Z" ],
+ [ "2015-02-29T12:34" ],
+ [ "1-1-1T12:00" ],
+ [ "" ],
+ // This datetime-local is valid for the input element, but is out of the
+ // date object range. In this case, on getting valueAsDate, a Date object
+ // will be created, but it will have a NaN internal value, and will return
+ // the string "Invalid Date".
+ [ "275760-09-13T12:00", true ],
+ ];
+
+ element.type = "datetime-local";
+ for (let data of validData) {
+ element.value = data[0];
+ is(element.valueAsDate.valueOf(), data[1],
+ "valueAsDate should return the " +
+ "valid date object representing this datetime-local");
+ }
+
+ for (let data of invalidData) {
+ element.value = data[0];
+ if (data[1]) {
+ is(String(element.valueAsDate), "Invalid Date",
+ "valueAsDate should return an invalid Date object " +
+ "when the element value is not a valid datetime-local");
+ } else {
+ is(element.valueAsDate, null,
+ "valueAsDate should return null " +
+ "when the element value is not a valid datetime-local");
+ }
+ }
+}
+
+function checkDatetimeLocalSet()
+{
+ var testData =
+ [
+ // Simple cases.
+ [ Date.UTC(2016, 11, 27, 10, 30, 0), "2016-12-27T10:30" ],
+ [ Date.UTC(2016, 11, 27, 10, 30, 30), "2016-12-27T10:30:30" ],
+ [ Date.UTC(1999, 11, 31, 23, 59, 59), "1999-12-31T23:59:59" ],
+ [ Date.UTC(1999, 11, 31, 23, 59, 59, 999), "1999-12-31T23:59:59.999" ],
+ [ Date.UTC(123456, 7, 8, 9, 10), "123456-08-08T09:10" ],
+ [ 0, "1970-01-01T00:00" ],
+ // Maximum valid datetime-local (limited by the ecma date object range).
+ [ 8640000000000000, "275760-09-13T00:00" ],
+ // Minimum valid datetime-local (limited by the input element minimum valid value).
+ [ -62135596800000, "0001-01-01T00:00" ],
+ // Leap years.
+ [ Date.UTC(1804, 1, 29, 12, 34, 0), "1804-02-29T12:34" ],
+ [ Date.UTC(2016, 1, 29, 12, 34, 0), "2016-02-29T12:34" ],
+ [ Date.UTC(2016, 11, 31, 12, 34, 56), "2016-12-31T12:34:56" ],
+ [ Date.UTC(2016, 0, 1, 12, 34, 56, 789), "2016-01-01T12:34:56.789" ],
+ [ Date.UTC(2017, 0, 1, 12, 34, 56, 789), "2017-01-01T12:34:56.789" ],
+ // "Values must be truncated to valid datetime-local"
+ [ 123.123456789123, "1970-01-01T00:00:00.123" ],
+ [ 1e-1, "1970-01-01T00:00" ],
+ [ -1.1, "1969-12-31T23:59:59.999" ],
+ [ -345600000, "1969-12-28T00:00" ],
+ // Negative years, this is out of range for the input element,
+ // the corresponding datetime-local string is the empty string
+ [ -62135596800001, "" ],
+ ];
+
+ element.type = "datetime-local";
+ for (let data of testData) {
+ element.valueAsDate = new Date(data[0]);
+ is(element.value, data[1], "valueAsDate should set the value to " +
+ data[1]);
+ element.valueAsDate = new testFrame.Date(data[0]);
+ is(element.value, data[1], "valueAsDate with other-global date should " +
+ "set the value to " + data[1]);
+ }
+}
+
checkAvailability();
checkGarbageValues();
checkWithBustedPrototype();
@@ -642,6 +742,10 @@ checkMonthSet();
checkWeekGet();
checkWeekSet();
+// Test <input type='datetime-local'>.
+checkDatetimeLocalGet();
+checkDatetimeLocalSet();
+
</script>
</pre>
</body>
diff --git a/dom/html/test/forms/test_valueasnumber_attribute.html b/dom/html/test/forms/test_valueasnumber_attribute.html
index d7471502b..2660fc7ed 100644
--- a/dom/html/test/forms/test_valueasnumber_attribute.html
+++ b/dom/html/test/forms/test_valueasnumber_attribute.html
@@ -46,8 +46,7 @@ function checkAvailability()
["color", false],
["month", true],
["week", true],
- // TODO: temporary set to false until bug 888331 is fixed.
- ["datetime-local", false],
+ ["datetime-local", true],
];
var element = document.createElement('input');
@@ -612,7 +611,6 @@ function checkWeekGet()
var element = document.createElement('input');
element.type = "week";
for (let data of validData) {
- dump("Test: " + data[0]);
element.value = data[0];
is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
"integer value representing this week");
@@ -698,7 +696,120 @@ function checkWeekSet()
try {
element.valueAsNumber = data[0];
- is(element.value, data[1], "valueAsNumber should set the value to " + data[1]);
+ is(element.value, data[1], "valueAsNumber should set the value to " +
+ data[1]);
+ } catch(e) {
+ caught = true;
+ }
+
+ if (data[2]) {
+ ok(caught, "valueAsNumber should have thrown");
+ is(element.value, data[1], "the value should not have changed");
+ } else {
+ ok(!caught, "valueAsNumber should not have thrown");
+ }
+ }
+}
+
+function checkDatetimeLocalGet() {
+ var validData =
+ [
+ // Simple cases.
+ [ "2016-12-20T09:58", Date.UTC(2016, 11, 20, 9, 58) ],
+ [ "2016-12-20T09:58:30", Date.UTC(2016, 11, 20, 9, 58, 30) ],
+ [ "2016-12-20T09:58:30.123", Date.UTC(2016, 11, 20, 9, 58, 30, 123) ],
+ [ "2017-01-01T10:00", Date.UTC(2017, 0, 1, 10, 0, 0) ],
+ [ "1969-12-31T12:00:00", Date.UTC(1969, 11, 31, 12, 0, 0) ],
+ [ "1970-01-01T00:00", 0 ],
+ // Leap years.
+ [ "1804-02-29 12:34", Date.UTC(1804, 1, 29, 12, 34, 0) ],
+ [ "2016-02-29T12:34", Date.UTC(2016, 1, 29, 12, 34, 0) ],
+ [ "2016-12-31T12:34:56", Date.UTC(2016, 11, 31, 12, 34, 56) ],
+ [ "2016-01-01T12:34:56.789", Date.UTC(2016, 0, 1, 12, 34, 56, 789) ],
+ [ "2017-01-01 12:34:56.789", Date.UTC(2017, 0, 1, 12, 34, 56, 789) ],
+ // Maximum valid datetime-local (limited by the ecma date object range).
+ [ "275760-09-13T00:00", 8640000000000000 ],
+ // Minimum valid datetime-local (limited by the input element minimum valid value).
+ [ "0001-01-01T00:00", -62135596800000 ],
+ ];
+
+ var invalidData =
+ [
+ "invaliddatetime-local",
+ "0000-01-01T00:00",
+ "2016-12-25T00:00Z",
+ "2015-02-29T12:34",
+ "1-1-1T12:00",
+ // Out of range.
+ "275760-09-13T12:00",
+ ];
+
+ var element = document.createElement('input');
+ element.type = "datetime-local";
+ for (let data of validData) {
+ element.value = data[0];
+ is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
+ "integer value representing this datetime-local");
+ }
+
+ for (let data of invalidData) {
+ element.value = data;
+ ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " +
+ "when the element value is not a valid datetime-local");
+ }
+}
+
+function checkDatetimeLocalSet()
+{
+ var testData =
+ [
+ // Simple cases.
+ [ Date.UTC(2016, 11, 20, 9, 58, 0), "2016-12-20T09:58", ],
+ [ Date.UTC(2016, 11, 20, 9, 58, 30), "2016-12-20T09:58:30" ],
+ [ Date.UTC(2016, 11, 20, 9, 58, 30, 123), "2016-12-20T09:58:30.123" ],
+ [ Date.UTC(2017, 0, 1, 10, 0, 0), "2017-01-01T10:00" ],
+ [ Date.UTC(1969, 11, 31, 12, 0, 0), "1969-12-31T12:00" ],
+ [ 0, "1970-01-01T00:00" ],
+ // Maximum valid week (limited by the ecma date object range).
+ [ 8640000000000000, "275760-09-13T00:00" ],
+ // Minimum valid datetime-local (limited by the input element minimum valid value).
+ [ -62135596800000, "0001-01-01T00:00" ],
+ // Leap years.
+ [ Date.UTC(1804, 1, 29, 12, 34, 0), "1804-02-29T12:34" ],
+ [ Date.UTC(2016, 1, 29, 12, 34, 0), "2016-02-29T12:34" ],
+ [ Date.UTC(2016, 11, 31, 12, 34, 56), "2016-12-31T12:34:56" ],
+ [ Date.UTC(2016, 0, 1, 12, 34, 56, 789), "2016-01-01T12:34:56.789" ],
+ [ Date.UTC(2017, 0, 1, 12, 34, 56, 789), "2017-01-01T12:34:56.789" ],
+ // "Values must be truncated to valid datetime-local"
+ [ 0.3, "1970-01-01T00:00" ],
+ [ 1e-1, "1970-01-01T00:00" ],
+ [ -1 , "1969-12-31T23:59:59.999" ],
+ [ -345600000, "1969-12-28T00:00" ],
+ // Invalid numbers.
+ // Those are implicitly converted to numbers
+ [ "", "1970-01-01T00:00" ],
+ [ true, "1970-01-01T00:00:00.001" ],
+ [ false, "1970-01-01T00:00" ],
+ [ null, "1970-01-01T00:00" ],
+ // Those are converted to NaN, the corresponding week string is the empty string
+ [ "invaliddatetime-local", "" ],
+ [ NaN, "" ],
+ [ undefined, "" ],
+ // Infinity will keep the current value and throw (so we need to set a current value).
+ [ Date.UTC(2016, 11, 27, 15, 10, 0), "2016-12-27T15:10" ],
+ [ Infinity, "2016-12-27T15:10", true ],
+ [ -Infinity, "2016-12-27T15:10", true ],
+ ];
+
+ var element = document.createElement('input');
+ element.type = "datetime-local";
+ for (let data of testData) {
+ var caught = false;
+
+ try {
+ element.valueAsNumber = data[0];
+ is(element.value, data[1], "valueAsNumber should set the value to " +
+ data[1]);
} catch(e) {
caught = true;
}
@@ -738,6 +849,10 @@ checkMonthSet();
checkWeekGet();
checkWeekSet();
+// <input type='datetime-local'> test
+checkDatetimeLocalGet();
+checkDatetimeLocalSet();
+
</script>
</pre>
</body>
diff --git a/dom/html/test/test_bug558788-1.html b/dom/html/test/test_bug558788-1.html
index 94b7a5f00..4db61ed73 100644
--- a/dom/html/test/test_bug558788-1.html
+++ b/dom/html/test/test_bug558788-1.html
@@ -154,13 +154,14 @@ function checkInputURL()
sendString("ttp://mozilla.org");
checkValidApplies(element);
- for (var i=0; i<13; ++i) {
+ for (var i=0; i<10; ++i) {
synthesizeKey("VK_BACK_SPACE", {});
checkValidApplies(element);
}
synthesizeKey("VK_BACK_SPACE", {});
- for (var i=0; i<4; ++i) {
+ // "http://" is now invalid
+ for (var i=0; i<7; ++i) {
checkInvalidApplies(element);
synthesizeKey("VK_BACK_SPACE", {});
}
diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp
index 702d5c985..9d4e72f2f 100644
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -7,6 +7,7 @@
#include "ActorsParent.h"
#include <algorithm>
+#include <stdint.h> // UINTPTR_MAX, uintptr_t
#include "FileInfo.h"
#include "FileManager.h"
#include "IDBObjectStore.h"
@@ -859,6 +860,11 @@ ReadCompressedIndexDataValuesFromBlob(const uint8_t* aBlobData,
"ReadCompressedIndexDataValuesFromBlob",
js::ProfileEntry::Category::STORAGE);
+ if (uintptr_t(aBlobData) > UINTPTR_MAX - aBlobDataLength) {
+ IDB_REPORT_INTERNAL_ERR();
+ return NS_ERROR_FILE_CORRUPTED;
+ }
+
const uint8_t* blobDataIter = aBlobData;
const uint8_t* blobDataEnd = aBlobData + aBlobDataLength;
@@ -878,7 +884,8 @@ ReadCompressedIndexDataValuesFromBlob(const uint8_t* aBlobData,
if (NS_WARN_IF(blobDataIter == blobDataEnd) ||
NS_WARN_IF(keyBufferLength > uint64_t(UINT32_MAX)) ||
- NS_WARN_IF(blobDataIter + keyBufferLength > blobDataEnd)) {
+ NS_WARN_IF(keyBufferLength > uintptr_t(blobDataEnd)) ||
+ NS_WARN_IF(blobDataIter > blobDataEnd - keyBufferLength)) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_FILE_CORRUPTED;
}
@@ -896,7 +903,8 @@ ReadCompressedIndexDataValuesFromBlob(const uint8_t* aBlobData,
if (sortKeyBufferLength > 0) {
if (NS_WARN_IF(blobDataIter == blobDataEnd) ||
NS_WARN_IF(sortKeyBufferLength > uint64_t(UINT32_MAX)) ||
- NS_WARN_IF(blobDataIter + sortKeyBufferLength > blobDataEnd)) {
+ NS_WARN_IF(sortKeyBufferLength > uintptr_t(blobDataEnd)) ||
+ NS_WARN_IF(blobDataIter > blobDataEnd - sortKeyBufferLength)) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_FILE_CORRUPTED;
}
@@ -18177,11 +18185,25 @@ QuotaClient::ShutdownWorkThreads()
mShutdownRequested = true;
+ // Shutdown maintenance thread pool (this spins the event loop until all
+ // threads are gone). This should release any maintenance related quota
+ // objects.
if (mMaintenanceThreadPool) {
mMaintenanceThreadPool->Shutdown();
mMaintenanceThreadPool = nullptr;
}
+ // Let any runnables dispatched from dying maintenance threads to be
+ // processed. This should release any maintenance related directory locks.
+ if (mCurrentMaintenance) {
+ nsIThread* currentThread = NS_GetCurrentThread();
+ MOZ_ASSERT(currentThread);
+
+ do {
+ MOZ_ALWAYS_TRUE(NS_ProcessNextEvent(currentThread));
+ } while (!mCurrentMaintenance);
+ }
+
RefPtr<ConnectionPool> connectionPool = gConnectionPool.get();
if (connectionPool) {
connectionPool->Shutdown();
@@ -18401,7 +18423,8 @@ Maintenance::Start()
AssertIsOnBackgroundThread();
MOZ_ASSERT(mState == State::Initial);
- if (IsAborted()) {
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
+ IsAborted()) {
return NS_ERROR_ABORT;
}
@@ -18425,7 +18448,8 @@ Maintenance::CreateIndexedDatabaseManager()
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mState == State::CreateIndexedDatabaseManager);
- if (IsAborted()) {
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
+ IsAborted()) {
return NS_ERROR_ABORT;
}
@@ -18450,7 +18474,8 @@ Maintenance::OpenDirectory()
MOZ_ASSERT(!mDirectoryLock);
MOZ_ASSERT(QuotaManager::Get());
- if (IsAborted()) {
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
+ IsAborted()) {
return NS_ERROR_ABORT;
}
@@ -18474,7 +18499,8 @@ Maintenance::DirectoryOpen()
MOZ_ASSERT(mState == State::DirectoryOpenPending);
MOZ_ASSERT(mDirectoryLock);
- if (IsAborted()) {
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
+ IsAborted()) {
return NS_ERROR_ABORT;
}
@@ -18504,7 +18530,8 @@ Maintenance::DirectoryWork()
// We have to find all database files that match any persistence type and any
// origin. We ignore anything out of the ordinary for now.
- if (IsAborted()) {
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
+ IsAborted()) {
return NS_ERROR_ABORT;
}
@@ -18691,8 +18718,10 @@ Maintenance::DirectoryWork()
continue;
}
+ nsCString suffix;
nsCString group;
nsCString origin;
+ bool isApp;
nsTArray<nsString> databasePaths;
while (true) {
@@ -18748,19 +18777,18 @@ Maintenance::DirectoryWork()
// Found a database.
if (databasePaths.IsEmpty()) {
+ MOZ_ASSERT(suffix.IsEmpty());
MOZ_ASSERT(group.IsEmpty());
MOZ_ASSERT(origin.IsEmpty());
int64_t dummyTimeStamp;
- nsCString dummySuffix;
- bool dummyIsApp;
if (NS_WARN_IF(NS_FAILED(
quotaManager->GetDirectoryMetadata2(originDir,
&dummyTimeStamp,
- dummySuffix,
+ suffix,
group,
origin,
- &dummyIsApp)))) {
+ &isApp)))) {
// Not much we can do here...
continue;
}
@@ -18776,6 +18804,22 @@ Maintenance::DirectoryWork()
group,
origin,
Move(databasePaths)));
+
+ nsCOMPtr<nsIFile> directory;
+
+ // Idle maintenance may occur before origin is initailized.
+ // Ensure origin is initialized first. It will initialize all origins
+ // for temporary storage including IDB origins.
+ rv = quotaManager->EnsureOriginIsInitialized(persistenceType,
+ suffix,
+ group,
+ origin,
+ isApp,
+ getter_AddRefs(directory));
+
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
}
}
@@ -18827,6 +18871,11 @@ Maintenance::BeginDatabaseMaintenance()
}
};
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
+ IsAborted()) {
+ return NS_ERROR_ABORT;
+ }
+
RefPtr<nsThreadPool> threadPool;
for (DirectoryInfo& directoryInfo : mDirectoryInfos) {
@@ -19013,6 +19062,11 @@ DatabaseMaintenance::PerformMaintenanceOnDatabase()
}
};
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
+ mMaintenance->IsAborted()) {
+ return;
+ }
+
nsCOMPtr<nsIFile> databaseFile = GetFileForPath(mDatabasePath);
MOZ_ASSERT(databaseFile);
@@ -19029,10 +19083,6 @@ DatabaseMaintenance::PerformMaintenanceOnDatabase()
AutoClose autoClose(connection);
- if (mMaintenance->IsAborted()) {
- return;
- }
-
AutoProgressHandler progressHandler(mMaintenance);
if (NS_WARN_IF(NS_FAILED(progressHandler.Register(connection)))) {
return;
@@ -19051,20 +19101,12 @@ DatabaseMaintenance::PerformMaintenanceOnDatabase()
return;
}
- if (mMaintenance->IsAborted()) {
- return;
- }
-
MaintenanceAction maintenanceAction;
rv = DetermineMaintenanceAction(connection, databaseFile, &maintenanceAction);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
- if (mMaintenance->IsAborted()) {
- return;
- }
-
switch (maintenanceAction) {
case MaintenanceAction::Nothing:
break;
@@ -19091,6 +19133,11 @@ DatabaseMaintenance::CheckIntegrity(mozIStorageConnection* aConnection,
MOZ_ASSERT(aConnection);
MOZ_ASSERT(aOk);
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
+ mMaintenance->IsAborted()) {
+ return NS_ERROR_ABORT;
+ }
+
nsresult rv;
// First do a full integrity_check. Scope statements tightly here because
@@ -19208,6 +19255,11 @@ DatabaseMaintenance::DetermineMaintenanceAction(
MOZ_ASSERT(aDatabaseFile);
MOZ_ASSERT(aMaintenanceAction);
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
+ mMaintenance->IsAborted()) {
+ return NS_ERROR_ABORT;
+ }
+
int32_t schemaVersion;
nsresult rv = aConnection->GetSchemaVersion(&schemaVersion);
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -19417,6 +19469,11 @@ DatabaseMaintenance::IncrementalVacuum(mozIStorageConnection* aConnection)
MOZ_ASSERT(!IsOnBackgroundThread());
MOZ_ASSERT(aConnection);
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
+ mMaintenance->IsAborted()) {
+ return;
+ }
+
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"PRAGMA incremental_vacuum;"
));
@@ -19434,6 +19491,11 @@ DatabaseMaintenance::FullVacuum(mozIStorageConnection* aConnection,
MOZ_ASSERT(aConnection);
MOZ_ASSERT(aDatabaseFile);
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
+ mMaintenance->IsAborted()) {
+ return;
+ }
+
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"VACUUM;"
));
diff --git a/dom/indexedDB/test/browser_forgetThisSite.js b/dom/indexedDB/test/browser_forgetThisSite.js
index c1177908f..02674922f 100644
--- a/dom/indexedDB/test/browser_forgetThisSite.js
+++ b/dom/indexedDB/test/browser_forgetThisSite.js
@@ -67,9 +67,10 @@ function test2()
function test3()
{
// Remove database from domain 2
- ForgetAboutSite.removeDataFromDomain(domains[1]);
- setPermission(testPageURL4, "indexedDB");
- executeSoon(test4);
+ ForgetAboutSite.removeDataFromDomain(domains[1]).then(() => {
+ setPermission(testPageURL4, "indexedDB");
+ executeSoon(test4);
+ });
}
function test4()
diff --git a/dom/interfaces/security/nsIContentSecurityPolicy.idl b/dom/interfaces/security/nsIContentSecurityPolicy.idl
index ade5b1243..da4297f33 100644
--- a/dom/interfaces/security/nsIContentSecurityPolicy.idl
+++ b/dom/interfaces/security/nsIContentSecurityPolicy.idl
@@ -61,6 +61,7 @@ interface nsIContentSecurityPolicy : nsISerializable
const unsigned short BLOCK_ALL_MIXED_CONTENT = 19;
const unsigned short REQUIRE_SRI_FOR = 20;
const unsigned short SANDBOX_DIRECTIVE = 21;
+ const unsigned short WORKER_SRC_DIRECTIVE = 22;
/**
* Accessor method for a read-only string version of the policy at a given
@@ -98,6 +99,11 @@ interface nsIContentSecurityPolicy : nsISerializable
readonly attribute bool blockAllMixedContent;
/**
+ * Returns whether this policy enforces the frame-ancestors directive.
+ */
+ readonly attribute bool enforcesFrameAncestors;
+
+ /**
* Obtains the referrer policy (as integer) for this browsing context as
* specified in CSP. If there are multiple policies and...
* - only one sets a referrer policy: that policy is returned
diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp
index ca4acf114..75678ca96 100644
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -585,11 +585,6 @@ ContentChild::Init(MessageLoop* aIOLoop,
SendBackUpXResources(FileDescriptor(xSocketFd));
#endif
-#ifdef MOZ_CRASHREPORTER
- SendPCrashReporterConstructor(CrashReporter::CurrentThreadId(),
- XRE_GetProcessType());
-#endif
-
SendGetProcessAttributes(&mID, &mIsForApp, &mIsForBrowser);
InitProcessAttributes();
@@ -1439,18 +1434,6 @@ ContentChild::RecvSetProcessSandbox(const MaybeFileDesc& aBroker)
sandboxEnabled = StartMacOSContentSandbox();
#endif
-#if defined(MOZ_CRASHREPORTER)
- CrashReporter::AnnotateCrashReport(
- NS_LITERAL_CSTRING("ContentSandboxEnabled"),
- sandboxEnabled? NS_LITERAL_CSTRING("1") : NS_LITERAL_CSTRING("0"));
-#if defined(XP_LINUX) && !defined(OS_ANDROID)
- nsAutoCString flagsString;
- flagsString.AppendInt(SandboxInfo::Get().AsInteger());
-
- CrashReporter::AnnotateCrashReport(
- NS_LITERAL_CSTRING("ContentSandboxCapabilities"), flagsString);
-#endif /* XP_LINUX && !OS_ANDROID */
-#endif /* MOZ_CRASHREPORTER */
#endif /* MOZ_CONTENT_SANDBOX */
return true;
@@ -1740,11 +1723,7 @@ PCrashReporterChild*
ContentChild::AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id,
const uint32_t& processType)
{
-#ifdef MOZ_CRASHREPORTER
- return new CrashReporterChild();
-#else
return nullptr;
-#endif
}
bool
@@ -2159,16 +2138,6 @@ ContentChild::ProcessingError(Result aCode, const char* aReason)
NS_RUNTIMEABORT("not reached");
}
-#if defined(MOZ_CRASHREPORTER) && !defined(MOZ_B2G)
- if (PCrashReporterChild* c = LoneManagedOrNullAsserts(ManagedPCrashReporterChild())) {
- CrashReporterChild* crashReporter =
- static_cast<CrashReporterChild*>(c);
- nsDependentCString reason(aReason);
- crashReporter->SendAnnotateCrashReport(
- NS_LITERAL_CSTRING("ipc_channel_error"),
- reason);
- }
-#endif
NS_RUNTIMEABORT("Content child abort due to IPC error");
}
@@ -2872,10 +2841,6 @@ ContentChild::RecvShutdown()
// to wait for that event loop to finish. Otherwise we could prematurely
// terminate an "unload" or "pagehide" event handler (which might be doing a
// sync XHR, for example).
-#if defined(MOZ_CRASHREPORTER)
- CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCShutdownState"),
- NS_LITERAL_CSTRING("RecvShutdown"));
-#endif
nsCOMPtr<nsIThread> thread;
nsresult rv = NS_GetMainThread(getter_AddRefs(thread));
if (NS_SUCCEEDED(rv) && thread) {
@@ -2923,10 +2888,6 @@ ContentChild::RecvShutdown()
// parent closes.
StartForceKillTimer();
-#if defined(MOZ_CRASHREPORTER)
- CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCShutdownState"),
- NS_LITERAL_CSTRING("SendFinishShutdown"));
-#endif
// Ignore errors here. If this fails, the parent will kill us after a
// timeout.
Unused << SendFinishShutdown();
diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp
index ff40db8d7..286f1d851 100644
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -249,10 +249,6 @@ using namespace mozilla::system;
#include "mozilla/widget/AudioSession.h"
#endif
-#ifdef MOZ_CRASHREPORTER
-#include "nsThread.h"
-#endif
-
#ifdef ACCESSIBILITY
#include "nsAccessibilityService.h"
#endif
@@ -273,9 +269,6 @@ using base::KillProcess;
using mozilla::ProfileGatherer;
#endif
-#ifdef MOZ_CRASHREPORTER
-using namespace CrashReporter;
-#endif
using namespace mozilla::dom::power;
using namespace mozilla::media;
using namespace mozilla::embedding;
@@ -1847,36 +1840,6 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
NS_LITERAL_CSTRING("content"), 1);
props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true);
-
-#ifdef MOZ_CRASHREPORTER
- // There's a window in which child processes can crash
- // after IPC is established, but before a crash reporter
- // is created.
- if (PCrashReporterParent* p = LoneManagedOrNullAsserts(ManagedPCrashReporterParent())) {
- CrashReporterParent* crashReporter =
- static_cast<CrashReporterParent*>(p);
-
- // If we're an app process, always stomp the latest URI
- // loaded in the child process with our manifest URL. We
- // would rather associate the crashes with apps than
- // random child windows loaded in them.
- //
- // XXX would be nice if we could get both ...
- if (!mAppManifestURL.IsEmpty()) {
- crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("URL"),
- NS_ConvertUTF16toUTF8(mAppManifestURL));
- }
-
- // if mCreatedPairedMinidumps is true, we've already generated
- // parent/child dumps for dekstop crashes.
- if (!mCreatedPairedMinidumps) {
- crashReporter->GenerateCrashReport(this, nullptr);
- }
-
- nsAutoString dumpID(crashReporter->ChildDumpID());
- props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID);
- }
-#endif
}
nsAutoString cpId;
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
@@ -3090,33 +3053,6 @@ ContentParent::KillHard(const char* aReason)
mCalledKillHard = true;
mForceKillTimer = nullptr;
-#if defined(MOZ_CRASHREPORTER) && !defined(MOZ_B2G)
- // We're about to kill the child process associated with this content.
- // Something has gone wrong to get us here, so we generate a minidump
- // of the parent and child for submission to the crash server.
- if (PCrashReporterParent* p = LoneManagedOrNullAsserts(ManagedPCrashReporterParent())) {
- CrashReporterParent* crashReporter =
- static_cast<CrashReporterParent*>(p);
- // GeneratePairedMinidump creates two minidumps for us - the main
- // one is for the content process we're about to kill, and the other
- // one is for the main browser process. That second one is the extra
- // minidump tagging along, so we have to tell the crash reporter that
- // it exists and is being appended.
- nsAutoCString additionalDumps("browser");
- crashReporter->AnnotateCrashReport(
- NS_LITERAL_CSTRING("additional_minidumps"),
- additionalDumps);
- nsDependentCString reason(aReason);
- crashReporter->AnnotateCrashReport(
- NS_LITERAL_CSTRING("ipc_channel_error"),
- reason);
-
- // Generate the report and insert into the queue for submittal.
- mCreatedPairedMinidumps = crashReporter->GenerateCompleteMinidump(this);
-
- Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1);
- }
-#endif
ProcessHandle otherProcessHandle;
if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) {
NS_ERROR("Failed to open child process when attempting kill.");
@@ -3168,11 +3104,7 @@ PCrashReporterParent*
ContentParent::AllocPCrashReporterParent(const NativeThreadId& tid,
const uint32_t& processType)
{
-#ifdef MOZ_CRASHREPORTER
- return new CrashReporterParent();
-#else
return nullptr;
-#endif
}
bool
@@ -3292,11 +3224,15 @@ PPrintingParent*
ContentParent::AllocPPrintingParent()
{
#ifdef NS_PRINTING
- MOZ_ASSERT(!mPrintingParent,
- "Only one PrintingParent should be created per process.");
+ MOZ_RELEASE_ASSERT(!mPrintingParent,
+ "Only one PrintingParent should be created per process.");
// Create the printing singleton for this process.
mPrintingParent = new PrintingParent();
+
+ // Take another reference for IPDL code.
+ mPrintingParent.get()->AddRef();
+
return mPrintingParent.get();
#else
MOZ_ASSERT_UNREACHABLE("Should never be created if no printing.");
@@ -3308,8 +3244,11 @@ bool
ContentParent::DeallocPPrintingParent(PPrintingParent* printing)
{
#ifdef NS_PRINTING
- MOZ_ASSERT(mPrintingParent == printing,
- "Only one PrintingParent should have been created per process.");
+ MOZ_RELEASE_ASSERT(mPrintingParent == printing,
+ "Only one PrintingParent should have been created per process.");
+
+ // Release reference taken for IPDL code.
+ static_cast<PrintingParent*>(printing)->Release();
mPrintingParent = nullptr;
#else
@@ -5001,9 +4940,6 @@ ContentParent::RecvNotifyPushSubscriptionModifiedObservers(const nsCString& aSco
bool
ContentParent::RecvNotifyLowMemory()
{
-#ifdef MOZ_CRASHREPORTER
- nsThread::SaveMemoryReportNearOOM(nsThread::ShouldSaveMemoryReport::kForceReport);
-#endif
return true;
}
diff --git a/dom/ipc/ContentProcess.cpp b/dom/ipc/ContentProcess.cpp
index 66125f332..2413d8808 100644
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -8,10 +8,6 @@
#include "ContentProcess.h"
-#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
-#include "mozilla/WindowsVersion.h"
-#endif
-
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
#include <stdlib.h>
#endif
@@ -33,9 +29,8 @@ static bool
IsSandboxTempDirRequired()
{
// On Windows, a sandbox-writable temp directory is only used
- // for Vista or later with sandbox pref level >= 1.
- return (IsVistaOrLater() &&
- (Preferences::GetInt("security.sandbox.content.level") >= 1));
+ // when sandbox pref level >= 1.
+ return Preferences::GetInt("security.sandbox.content.level") >= 1;
}
static void
diff --git a/dom/ipc/CrashReporterParent.cpp b/dom/ipc/CrashReporterParent.cpp
index fc627387f..677b29670 100644
--- a/dom/ipc/CrashReporterParent.cpp
+++ b/dom/ipc/CrashReporterParent.cpp
@@ -13,13 +13,6 @@
#include "mozilla/Telemetry.h"
-#ifdef MOZ_CRASHREPORTER
-#include "nsExceptionHandler.h"
-#include "nsICrashService.h"
-#include "mozilla/SyncRunnable.h"
-#include "nsThreadUtils.h"
-#endif
-
namespace mozilla {
namespace dom {
@@ -29,9 +22,6 @@ void
CrashReporterParent::AnnotateCrashReport(const nsCString& key,
const nsCString& data)
{
-#ifdef MOZ_CRASHREPORTER
- mNotes.Put(key, data);
-#endif
}
void
@@ -49,9 +39,6 @@ CrashReporterParent::RecvAppendAppNotes(const nsCString& data)
CrashReporterParent::CrashReporterParent()
:
-#ifdef MOZ_CRASHREPORTER
- mNotes(4),
-#endif
mStartTime(::time(nullptr))
, mInitialized(false)
{
@@ -72,75 +59,5 @@ CrashReporterParent::SetChildData(const NativeThreadId& tid,
mProcessType = GeckoProcessType(processType);
}
-#ifdef MOZ_CRASHREPORTER
-bool
-CrashReporterParent::GenerateCrashReportForMinidump(nsIFile* minidump,
- const AnnotationTable* processNotes)
-{
- if (!CrashReporter::GetIDFromMinidump(minidump, mChildDumpID)) {
- return false;
- }
-
- bool result = GenerateChildData(processNotes);
- FinalizeChildData();
- return result;
-}
-
-bool
-CrashReporterParent::GenerateChildData(const AnnotationTable* processNotes)
-{
- MOZ_ASSERT(mInitialized);
-
- if (mChildDumpID.IsEmpty()) {
- NS_WARNING("problem with GenerateChildData: no child dump id yet!");
- return false;
- }
-
- nsAutoCString type;
- switch (mProcessType) {
- case GeckoProcessType_Content:
- type = NS_LITERAL_CSTRING("content");
- break;
- case GeckoProcessType_Plugin:
- case GeckoProcessType_GMPlugin:
- type = NS_LITERAL_CSTRING("plugin");
- break;
- default:
- NS_ERROR("unknown process type");
- break;
- }
- mNotes.Put(NS_LITERAL_CSTRING("ProcessType"), type);
-
- char startTime[32];
- SprintfLiteral(startTime, "%lld", static_cast<long long>(mStartTime));
- mNotes.Put(NS_LITERAL_CSTRING("StartupTime"), nsDependentCString(startTime));
-
- if (!mAppNotes.IsEmpty()) {
- mNotes.Put(NS_LITERAL_CSTRING("Notes"), mAppNotes);
- }
-
- // Append these notes to the end of the extra file based on the current
- // dump id we obtained from CreatePairedMinidumps.
- bool ret = CrashReporter::AppendExtraData(mChildDumpID, mNotes);
- if (ret && processNotes) {
- ret = CrashReporter::AppendExtraData(mChildDumpID, *processNotes);
- }
-
- if (!ret) {
- NS_WARNING("problem appending child data to .extra");
- }
- return ret;
-}
-
-void
-CrashReporterParent::FinalizeChildData()
-{
- MOZ_ASSERT(mInitialized);
-
- CrashReporterHost::NotifyCrashService(mProcessType, mChildDumpID, &mNotes);
- mNotes.Clear();
-}
-#endif
-
} // namespace dom
} // namespace mozilla
diff --git a/dom/ipc/CrashReporterParent.h b/dom/ipc/CrashReporterParent.h
index 25824f279..71896c5c1 100644
--- a/dom/ipc/CrashReporterParent.h
+++ b/dom/ipc/CrashReporterParent.h
@@ -10,122 +10,16 @@
#include "mozilla/dom/PCrashReporterParent.h"
#include "mozilla/dom/TabMessageUtils.h"
#include "nsIFile.h"
-#ifdef MOZ_CRASHREPORTER
-#include "nsExceptionHandler.h"
-#include "nsDataHashtable.h"
-#endif
namespace mozilla {
namespace dom {
class CrashReporterParent : public PCrashReporterParent
{
-#ifdef MOZ_CRASHREPORTER
- typedef CrashReporter::AnnotationTable AnnotationTable;
-#endif
public:
CrashReporterParent();
virtual ~CrashReporterParent();
-#ifdef MOZ_CRASHREPORTER
-
- /*
- * Attempt to create a bare-bones crash report, along with extra process-
- * specific annotations present in the given AnnotationTable. Calls
- * GenerateChildData and FinalizeChildData.
- *
- * @returns true if successful, false otherwise.
- */
- template<class Toplevel>
- bool
- GenerateCrashReport(Toplevel* t, const AnnotationTable* processNotes);
-
- /*
- * Attempt to generate a parent/child pair of minidumps from the given
- * toplevel actor. This calls CrashReporter::CreateMinidumpsAndPair to
- * generate the minidumps. Crash reporter annotations set prior to this
- * call will be saved via PairedDumpCallbackExtra into an .extra file
- * under the proper crash id. AnnotateCrashReport annotations are not
- * set in this call and the report is not finalized.
- *
- * @returns true if successful, false otherwise.
- */
- template<class Toplevel>
- bool
- GeneratePairedMinidump(Toplevel* t);
-
- /*
- * Attempts to take a minidump of the current process and pair that with
- * a named minidump handed in by the caller.
- *
- * @param aTopLevel - top level actor this reporter is associated with.
- * @param aMinidump - the minidump to associate with.
- * @param aPairName - the name of the additional minidump.
- * @returns true if successful, false otherwise.
- */
- template<class Toplevel>
- bool
- GenerateMinidumpAndPair(Toplevel* aTopLevel, nsIFile* aMinidump,
- const nsACString& aPairName);
-
- /**
- * Apply child process annotations to an existing paired mindump generated
- * with GeneratePairedMinidump.
- *
- * Be careful about calling generate apis immediately after this call,
- * see FinalizeChildData.
- *
- * @param processNotes (optional) - Additional notes to append. Annotations
- * stored in mNotes will also be applied. processNotes can be null.
- * @returns true if successful, false otherwise.
- */
- bool
- GenerateChildData(const AnnotationTable* processNotes);
-
- /**
- * Handles main thread finalization tasks after a report has been
- * generated. Does the following:
- * - register the finished report with the crash service manager
- * - records telemetry related data about crashes
- *
- * Be careful about calling generate apis immediately after this call,
- * if this api is called on a non-main thread it will fire off a runnable
- * to complete its work async.
- */
- void
- FinalizeChildData();
-
- /*
- * Attempt to generate a full paired dump complete with any child
- * annoations, and finalizes the report. Note this call is only valid
- * on the main thread. Calling on a background thread will fail.
- *
- * @returns true if successful, false otherwise.
- */
- template<class Toplevel>
- bool
- GenerateCompleteMinidump(Toplevel* t);
-
- /**
- * Submits a raw minidump handed in, calls GenerateChildData and
- * FinalizeChildData. Used by content plugins and gmp.
- *
- * @returns true if successful, false otherwise.
- */
- bool
- GenerateCrashReportForMinidump(nsIFile* minidump,
- const AnnotationTable* processNotes);
-
- /*
- * Instantiate a new crash reporter actor from a given parent that manages
- * the protocol.
- *
- * @returns true if successful, false otherwise.
- */
- template<class Toplevel>
- static bool CreateCrashReporter(Toplevel* actor);
-#endif // MOZ_CRASHREPORTER
-
/*
* Initialize this reporter with data from the child process.
*/
@@ -160,14 +54,6 @@ public:
virtual bool RecvAppendAppNotes(const nsCString& aData) override;
-#ifdef MOZ_CRASHREPORTER
- void
- NotifyCrashService();
-#endif
-
-#ifdef MOZ_CRASHREPORTER
- AnnotationTable mNotes;
-#endif
nsCString mAppNotes;
nsString mChildDumpID;
// stores the child main thread id
@@ -178,128 +64,6 @@ public:
bool mInitialized;
};
-#ifdef MOZ_CRASHREPORTER
-template<class Toplevel>
-inline bool
-CrashReporterParent::GeneratePairedMinidump(Toplevel* t)
-{
- mozilla::ipc::ScopedProcessHandle child;
-#ifdef XP_MACOSX
- child = t->Process()->GetChildTask();
-#else
- if (!base::OpenPrivilegedProcessHandle(t->OtherPid(), &child.rwget())) {
- NS_WARNING("Failed to open child process handle.");
- return false;
- }
-#endif
- nsCOMPtr<nsIFile> childDump;
- if (CrashReporter::CreateMinidumpsAndPair(child,
- mMainThread,
- NS_LITERAL_CSTRING("browser"),
- nullptr, // pair with a dump of this process and thread
- getter_AddRefs(childDump)) &&
- CrashReporter::GetIDFromMinidump(childDump, mChildDumpID)) {
- return true;
- }
- return false;
-}
-
-template<class Toplevel>
-inline bool
-CrashReporterParent::GenerateMinidumpAndPair(Toplevel* aTopLevel,
- nsIFile* aMinidumpToPair,
- const nsACString& aPairName)
-{
- mozilla::ipc::ScopedProcessHandle childHandle;
-#ifdef XP_MACOSX
- childHandle = aTopLevel->Process()->GetChildTask();
-#else
- if (!base::OpenPrivilegedProcessHandle(aTopLevel->OtherPid(),
- &childHandle.rwget())) {
- NS_WARNING("Failed to open child process handle.");
- return false;
- }
-#endif
- nsCOMPtr<nsIFile> targetDump;
- if (CrashReporter::CreateMinidumpsAndPair(childHandle,
- mMainThread, // child thread id
- aPairName,
- aMinidumpToPair,
- getter_AddRefs(targetDump)) &&
- CrashReporter::GetIDFromMinidump(targetDump, mChildDumpID)) {
- return true;
- }
- return false;
-}
-
-template<class Toplevel>
-inline bool
-CrashReporterParent::GenerateCrashReport(Toplevel* t,
- const AnnotationTable* processNotes)
-{
- nsCOMPtr<nsIFile> crashDump;
- if (t->TakeMinidump(getter_AddRefs(crashDump), nullptr) &&
- CrashReporter::GetIDFromMinidump(crashDump, mChildDumpID)) {
- bool result = GenerateChildData(processNotes);
- FinalizeChildData();
- return result;
- }
- return false;
-}
-
-template<class Toplevel>
-inline bool
-CrashReporterParent::GenerateCompleteMinidump(Toplevel* t)
-{
- mozilla::ipc::ScopedProcessHandle child;
- if (!NS_IsMainThread()) {
- NS_WARNING("GenerateCompleteMinidump can't be called on non-main thread.");
- return false;
- }
-
-#ifdef XP_MACOSX
- child = t->Process()->GetChildTask();
-#else
- if (!base::OpenPrivilegedProcessHandle(t->OtherPid(), &child.rwget())) {
- NS_WARNING("Failed to open child process handle.");
- return false;
- }
-#endif
- nsCOMPtr<nsIFile> childDump;
- if (CrashReporter::CreateMinidumpsAndPair(child,
- mMainThread,
- NS_LITERAL_CSTRING("browser"),
- nullptr, // pair with a dump of this process and thread
- getter_AddRefs(childDump)) &&
- CrashReporter::GetIDFromMinidump(childDump, mChildDumpID)) {
- bool result = GenerateChildData(nullptr);
- FinalizeChildData();
- return result;
- }
- return false;
-}
-
-template<class Toplevel>
-/* static */ bool
-CrashReporterParent::CreateCrashReporter(Toplevel* actor)
-{
-#ifdef MOZ_CRASHREPORTER
- NativeThreadId id;
- uint32_t processType;
- PCrashReporterParent* p =
- actor->CallPCrashReporterConstructor(&id, &processType);
- if (p) {
- static_cast<CrashReporterParent*>(p)->SetChildData(id, processType);
- } else {
- NS_ERROR("Error creating crash reporter actor");
- }
- return !!p;
-#endif
- return false;
-}
-
-#endif
-
} // namespace dom
} // namespace mozilla
diff --git a/dom/ipc/DatePickerParent.cpp b/dom/ipc/DatePickerParent.cpp
deleted file mode 100644
index 509944ddd..000000000
--- a/dom/ipc/DatePickerParent.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "DatePickerParent.h"
-#include "nsComponentManagerUtils.h"
-#include "nsIDocument.h"
-#include "nsIDOMWindow.h"
-#include "mozilla/Unused.h"
-#include "mozilla/dom/Element.h"
-#include "mozilla/dom/TabParent.h"
-
-using mozilla::Unused;
-using namespace mozilla::dom;
-
-NS_IMPL_ISUPPORTS(DatePickerParent::DatePickerShownCallback,
- nsIDatePickerShownCallback);
-
-NS_IMETHODIMP
-DatePickerParent::DatePickerShownCallback::Cancel()
-{
- if (mDatePickerParent) {
- Unused << mDatePickerParent->SendCancel();
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DatePickerParent::DatePickerShownCallback::Done(const nsAString& aDate)
-{
- if (mDatePickerParent) {
- Unused << mDatePickerParent->Send__delete__(mDatePickerParent,
- nsString(aDate));
- }
- return NS_OK;
-}
-
-void
-DatePickerParent::DatePickerShownCallback::Destroy()
-{
- mDatePickerParent = nullptr;
-}
-
-bool
-DatePickerParent::CreateDatePicker()
-{
- mPicker = do_CreateInstance("@mozilla.org/datepicker;1");
- if (!mPicker) {
- return false;
- }
-
- Element* ownerElement = TabParent::GetFrom(Manager())->GetOwnerElement();
- if (!ownerElement) {
- return false;
- }
-
- nsCOMPtr<mozIDOMWindowProxy> window = do_QueryInterface(ownerElement->OwnerDoc()->GetWindow());
- if (!window) {
- return false;
- }
-
- return NS_SUCCEEDED(mPicker->Init(window, mTitle, mInitialDate));
-}
-
-bool
-DatePickerParent::RecvOpen()
-{
- if (!CreateDatePicker()) {
- Unused << Send__delete__(this, mInitialDate);
- return true;
- }
-
- mCallback = new DatePickerShownCallback(this);
-
- mPicker->Open(mCallback);
- return true;
-};
-
-void
-DatePickerParent::ActorDestroy(ActorDestroyReason aWhy)
-{
- if (mCallback) {
- mCallback->Destroy();
- }
-}
diff --git a/dom/ipc/DatePickerParent.h b/dom/ipc/DatePickerParent.h
deleted file mode 100644
index 73b66f96c..000000000
--- a/dom/ipc/DatePickerParent.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_DatePickerParent_h
-#define mozilla_dom_DatePickerParent_h
-
-#include "mozilla/dom/PDatePickerParent.h"
-#include "nsIDatePicker.h"
-
-namespace mozilla {
-namespace dom {
-
-class DatePickerParent : public PDatePickerParent
-{
- public:
- DatePickerParent(const nsString& aTitle,
- const nsString& aInitialDate)
- : mTitle(aTitle)
- , mInitialDate(aInitialDate)
- {}
-
- virtual bool RecvOpen() override;
- virtual void ActorDestroy(ActorDestroyReason aWhy) override;
-
- class DatePickerShownCallback final
- : public nsIDatePickerShownCallback
- {
- public:
- explicit DatePickerShownCallback(DatePickerParent* aDatePickerParnet)
- : mDatePickerParent(aDatePickerParnet)
- {}
-
- NS_DECL_ISUPPORTS
- NS_DECL_NSIDATEPICKERSHOWNCALLBACK
-
- void Destroy();
-
- private:
- ~DatePickerShownCallback() {}
- DatePickerParent* mDatePickerParent;
- };
-
- private:
- virtual ~DatePickerParent() {}
-
- bool CreateDatePicker();
-
- RefPtr<DatePickerShownCallback> mCallback;
- nsCOMPtr<nsIDatePicker> mPicker;
-
- nsString mTitle;
- nsString mInitialDate;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_DatePickerParent_h
diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl
index 249657c26..f09e484ee 100644
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -9,9 +9,7 @@ include protocol PBlob;
include protocol PColorPicker;
include protocol PContent;
include protocol PContentBridge;
-include protocol PDatePicker;
include protocol PDocAccessible;
-include protocol PDocumentRenderer;
include protocol PFilePicker;
include protocol PIndexedDBPermissionRequest;
include protocol PRenderFrame;
@@ -117,9 +115,7 @@ nested(upto inside_cpow) sync protocol PBrowser
manager PContent or PContentBridge;
manages PColorPicker;
- manages PDatePicker;
manages PDocAccessible;
- manages PDocumentRenderer;
manages PFilePicker;
manages PIndexedDBPermissionRequest;
manages PRenderFrame;
@@ -443,12 +439,6 @@ parent:
*/
async PColorPicker(nsString title, nsString initialColor);
- /**
- * Create an asynchronous date picker on the parent side,
- * but don't open it yet.
- */
- async PDatePicker(nsString title, nsString initialDate);
-
async PFilePicker(nsString aTitle, int16_t aMode);
/**
@@ -739,24 +729,6 @@ child:
async LoadRemoteScript(nsString aURL, bool aRunInGlobalScope);
/**
- * Create a asynchronous request to render whatever document is
- * loaded in the child when this message arrives. When the
- * request finishes, PDocumentRenderer:__delete__ is sent back to
- * this side to notify completion.
- *
- * |documentRect| is the area of the remote document to draw,
- * transformed by |transform|. The rendered area will have the
- * default background color |bgcolor|. |renderFlags| are the
- * nsIPresShell::RenderDocument() flags to use on the remote side,
- * and if true, |flushLayout| will do just that before rendering
- * the document. The rendered image will be of size |renderSize|.
- */
- async PDocumentRenderer(nsRect documentRect, Matrix transform,
- nsString bgcolor,
- uint32_t renderFlags, bool flushLayout,
- IntSize renderSize);
-
- /**
* Sent by the chrome process when it no longer wants this remote
* <browser>. The child side cleans up in response, then
* finalizing its death by sending back __delete__() to the
diff --git a/dom/ipc/PDatePicker.ipdl b/dom/ipc/PDatePicker.ipdl
deleted file mode 100644
index 90a2654bb..000000000
--- a/dom/ipc/PDatePicker.ipdl
+++ /dev/null
@@ -1,27 +0,0 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
-/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
-
-/* 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 protocol PBrowser;
-
-namespace mozilla {
-namespace dom {
-
-protocol PDatePicker
-{
- manager PBrowser;
-
-parent:
- async Open();
-
-child:
- async Cancel();
-
- async __delete__(nsString color);
-};
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/ipc/PDocumentRenderer.ipdl b/dom/ipc/PDocumentRenderer.ipdl
deleted file mode 100644
index bdaed45d7..000000000
--- a/dom/ipc/PDocumentRenderer.ipdl
+++ /dev/null
@@ -1,25 +0,0 @@
-/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
-/* 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 protocol PBrowser;
-
-include "mozilla/GfxMessageUtils.h";
-
-using nsIntSize from "nsSize.h";
-
-namespace mozilla {
-namespace ipc {
-
-protocol PDocumentRenderer
-{
- manager PBrowser;
-
-parent:
- // Returns the width and height, in pixels, of the returned ARGB32 data.
- async __delete__(nsIntSize renderedSize, nsCString data);
-};
-
-} // namespace ipc
-} // namespace mozilla
diff --git a/dom/ipc/ProcessHangMonitor.cpp b/dom/ipc/ProcessHangMonitor.cpp
index b574be61f..d46a1f5d5 100644
--- a/dom/ipc/ProcessHangMonitor.cpp
+++ b/dom/ipc/ProcessHangMonitor.cpp
@@ -27,9 +27,6 @@
#include "nsITabParent.h"
#include "nsPluginHost.h"
#include "nsThreadUtils.h"
-#ifdef MOZ_CRASHREPORTER
-#include "nsExceptionHandler.h"
-#endif
#include "base/task.h"
#include "base/thread.h"
@@ -556,16 +553,6 @@ HangMonitorParent::HangMonitorParent(ProcessHangMonitor* aMonitor)
HangMonitorParent::~HangMonitorParent()
{
-#ifdef MOZ_CRASHREPORTER
- MutexAutoLock lock(mBrowserCrashDumpHashLock);
-
- for (auto iter = mBrowserCrashDumpIds.Iter(); !iter.Done(); iter.Next()) {
- nsString crashId = iter.UserData();
- if (!crashId.IsEmpty()) {
- CrashReporter::DeleteMinidumpFilesForID(crashId);
- }
- }
-#endif
}
void
@@ -698,24 +685,6 @@ bool
HangMonitorParent::TakeBrowserMinidump(const PluginHangData& aPhd,
nsString& aCrashId)
{
-#ifdef MOZ_CRASHREPORTER
- MutexAutoLock lock(mBrowserCrashDumpHashLock);
- if (!mBrowserCrashDumpIds.Get(aPhd.pluginId(), &aCrashId)) {
- nsCOMPtr<nsIFile> browserDump;
- if (CrashReporter::TakeMinidump(getter_AddRefs(browserDump), true)) {
- if (!CrashReporter::GetIDFromMinidump(browserDump, aCrashId)
- || aCrashId.IsEmpty()) {
- browserDump->Remove(false);
- NS_WARNING("Failed to generate timely browser stack, "
- "this is bad for plugin hang analysis!");
- } else {
- mBrowserCrashDumpIds.Put(aPhd.pluginId(), aCrashId);
- return true;
- }
- }
- }
-#endif // MOZ_CRASHREPORTER
-
return false;
}
@@ -840,11 +809,6 @@ HangMonitorParent::CleanupPluginHang(uint32_t aPluginId, bool aRemoveFiles)
return;
}
mBrowserCrashDumpIds.Remove(aPluginId);
-#ifdef MOZ_CRASHREPORTER
- if (aRemoveFiles && !crashId.IsEmpty()) {
- CrashReporter::DeleteMinidumpFilesForID(crashId);
- }
-#endif
}
void
diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp
index eaf4a32ed..705799c54 100644
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -22,7 +22,6 @@
#include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
#include "mozilla/plugins/PluginWidgetChild.h"
#include "mozilla/IMEStateManager.h"
-#include "mozilla/ipc/DocumentRendererChild.h"
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/layers/APZChild.h"
#include "mozilla/layers/APZCCallbackHelper.h"
@@ -53,9 +52,6 @@
#include "nsEmbedCID.h"
#include "nsGlobalWindow.h"
#include <algorithm>
-#ifdef MOZ_CRASHREPORTER
-#include "nsExceptionHandler.h"
-#endif
#include "nsFilePickerProxy.h"
#include "mozilla/dom/Element.h"
#include "nsGlobalWindow.h"
@@ -100,7 +96,6 @@
#include "LayersLogging.h"
#include "nsDOMClassInfoID.h"
#include "nsColorPickerProxy.h"
-#include "nsDatePickerProxy.h"
#include "nsContentPermissionHelper.h"
#include "nsPresShell.h"
#include "nsIAppsService.h"
@@ -1262,10 +1257,6 @@ TabChild::RecvLoadURL(const nsCString& aURI,
NS_WARNING("WebNavigation()->LoadURI failed. Eating exception, what else can I do?");
}
-#ifdef MOZ_CRASHREPORTER
- CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), aURI);
-#endif
-
return true;
}
@@ -2006,57 +1997,6 @@ TabChild::DeallocPDocAccessibleChild(a11y::PDocAccessibleChild* aChild)
return true;
}
-PDocumentRendererChild*
-TabChild::AllocPDocumentRendererChild(const nsRect& documentRect,
- const mozilla::gfx::Matrix& transform,
- const nsString& bgcolor,
- const uint32_t& renderFlags,
- const bool& flushLayout,
- const nsIntSize& renderSize)
-{
- return new DocumentRendererChild();
-}
-
-bool
-TabChild::DeallocPDocumentRendererChild(PDocumentRendererChild* actor)
-{
- delete actor;
- return true;
-}
-
-bool
-TabChild::RecvPDocumentRendererConstructor(PDocumentRendererChild* actor,
- const nsRect& documentRect,
- const mozilla::gfx::Matrix& transform,
- const nsString& bgcolor,
- const uint32_t& renderFlags,
- const bool& flushLayout,
- const nsIntSize& renderSize)
-{
- DocumentRendererChild *render = static_cast<DocumentRendererChild *>(actor);
-
- nsCOMPtr<nsIWebBrowser> browser = do_QueryInterface(WebNavigation());
- if (!browser)
- return true; // silently ignore
- nsCOMPtr<mozIDOMWindowProxy> window;
- if (NS_FAILED(browser->GetContentDOMWindow(getter_AddRefs(window))) ||
- !window)
- {
- return true; // silently ignore
- }
-
- nsCString data;
- bool ret = render->RenderDocument(nsPIDOMWindowOuter::From(window),
- documentRect, transform,
- bgcolor,
- renderFlags, flushLayout,
- renderSize, data);
- if (!ret)
- return true; // silently ignore
-
- return PDocumentRendererChild::Send__delete__(actor, renderSize, data);
-}
-
PColorPickerChild*
TabChild::AllocPColorPickerChild(const nsString&, const nsString&)
{
@@ -2072,21 +2012,6 @@ TabChild::DeallocPColorPickerChild(PColorPickerChild* aColorPicker)
return true;
}
-PDatePickerChild*
-TabChild::AllocPDatePickerChild(const nsString&, const nsString&)
-{
- NS_RUNTIMEABORT("unused");
- return nullptr;
-}
-
-bool
-TabChild::DeallocPDatePickerChild(PDatePickerChild* aDatePicker)
-{
- nsDatePickerProxy* picker = static_cast<nsDatePickerProxy*>(aDatePicker);
- NS_RELEASE(picker);
- return true;
-}
-
PFilePickerChild*
TabChild::AllocPFilePickerChild(const nsString&, const int16_t&)
{
diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h
index b23c7c19e..d9988a596 100644
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -445,37 +445,12 @@ public:
virtual bool DeallocPDocAccessibleChild(PDocAccessibleChild*) override;
- virtual PDocumentRendererChild*
- AllocPDocumentRendererChild(const nsRect& aDocumentRect,
- const gfx::Matrix& aTransform,
- const nsString& aBggcolor,
- const uint32_t& aRenderFlags,
- const bool& aFlushLayout,
- const nsIntSize& arenderSize) override;
-
- virtual bool
- DeallocPDocumentRendererChild(PDocumentRendererChild* aCctor) override;
-
- virtual bool
- RecvPDocumentRendererConstructor(PDocumentRendererChild* aActor,
- const nsRect& aDocumentRect,
- const gfx::Matrix& aTransform,
- const nsString& aBgcolor,
- const uint32_t& aRenderFlags,
- const bool& aFlushLayout,
- const nsIntSize& aRenderSize) override;
-
-
virtual PColorPickerChild*
AllocPColorPickerChild(const nsString& aTitle,
const nsString& aInitialColor) override;
virtual bool DeallocPColorPickerChild(PColorPickerChild* aActor) override;
- virtual PDatePickerChild*
- AllocPDatePickerChild(const nsString& title, const nsString& initialDate) override;
- virtual bool DeallocPDatePickerChild(PDatePickerChild* actor) override;
-
virtual PFilePickerChild*
AllocPFilePickerChild(const nsString& aTitle, const int16_t& aMode) override;
diff --git a/dom/ipc/TabMessageUtils.h b/dom/ipc/TabMessageUtils.h
index cdb76099d..2933173d7 100644
--- a/dom/ipc/TabMessageUtils.h
+++ b/dom/ipc/TabMessageUtils.h
@@ -13,10 +13,6 @@
#include "nsPIDOMWindow.h"
#include "nsCOMPtr.h"
-#ifdef MOZ_CRASHREPORTER
-#include "nsExceptionHandler.h"
-#endif
-
namespace mozilla {
namespace dom {
struct RemoteDOMEvent
@@ -28,12 +24,8 @@ struct RemoteDOMEvent
bool ReadRemoteEvent(const IPC::Message* aMsg, PickleIterator* aIter,
mozilla::dom::RemoteDOMEvent* aResult);
-#ifdef MOZ_CRASHREPORTER
-typedef CrashReporter::ThreadId NativeThreadId;
-#else
// unused in this case
typedef int32_t NativeThreadId;
-#endif
} // namespace dom
} // namespace mozilla
diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp
index 0df4c1253..0f190708f 100644
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -28,7 +28,6 @@
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/Hal.h"
#include "mozilla/IMEStateManager.h"
-#include "mozilla/ipc/DocumentRendererParent.h"
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
#include "mozilla/layers/AsyncDragMetrics.h"
#include "mozilla/layers/InputAPZContext.h"
@@ -81,7 +80,6 @@
#include "PermissionMessageUtils.h"
#include "StructuredCloneData.h"
#include "ColorPickerParent.h"
-#include "DatePickerParent.h"
#include "FilePickerParent.h"
#include "TabChild.h"
#include "LoadContext.h"
@@ -957,24 +955,6 @@ TabParent::GetTopLevelDocAccessible() const
return nullptr;
}
-PDocumentRendererParent*
-TabParent::AllocPDocumentRendererParent(const nsRect& documentRect,
- const gfx::Matrix& transform,
- const nsString& bgcolor,
- const uint32_t& renderFlags,
- const bool& flushLayout,
- const nsIntSize& renderSize)
-{
- return new DocumentRendererParent();
-}
-
-bool
-TabParent::DeallocPDocumentRendererParent(PDocumentRendererParent* actor)
-{
- delete actor;
- return true;
-}
-
PFilePickerParent*
TabParent::AllocPFilePickerParent(const nsString& aTitle, const int16_t& aMode)
{
@@ -2443,20 +2423,6 @@ TabParent::DeallocPColorPickerParent(PColorPickerParent* actor)
return true;
}
-PDatePickerParent*
-TabParent::AllocPDatePickerParent(const nsString& aTitle,
- const nsString& aInitialDate)
-{
- return new DatePickerParent(aTitle, aInitialDate);
-}
-
-bool
-TabParent::DeallocPDatePickerParent(PDatePickerParent* actor)
-{
- delete actor;
- return true;
-}
-
PRenderFrameParent*
TabParent::AllocPRenderFrameParent()
{
diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h
index 43afb0538..3624ce320 100644
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -347,10 +347,6 @@ public:
virtual bool
DeallocPColorPickerParent(PColorPickerParent* aColorPicker) override;
- virtual PDatePickerParent*
- AllocPDatePickerParent(const nsString& aTitle, const nsString& aInitialDate) override;
- virtual bool DeallocPDatePickerParent(PDatePickerParent* aDatePicker) override;
-
virtual PDocAccessibleParent*
AllocPDocAccessibleParent(PDocAccessibleParent*, const uint64_t&,
const uint32_t&, const IAccessibleHolder&) override;
@@ -473,17 +469,6 @@ public:
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId);
- virtual PDocumentRendererParent*
- AllocPDocumentRendererParent(const nsRect& documentRect,
- const gfx::Matrix& transform,
- const nsString& bgcolor,
- const uint32_t& renderFlags,
- const bool& flushLayout,
- const nsIntSize& renderSize) override;
-
- virtual bool
- DeallocPDocumentRendererParent(PDocumentRendererParent* actor) override;
-
virtual PFilePickerParent*
AllocPFilePickerParent(const nsString& aTitle,
const int16_t& aMode) override;
diff --git a/dom/ipc/moz.build b/dom/ipc/moz.build
index 153bd3aae..71d193d44 100644
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -55,7 +55,6 @@ UNIFIED_SOURCES += [
'ContentProcess.cpp',
'ContentProcessManager.cpp',
'CrashReporterParent.cpp',
- 'DatePickerParent.cpp',
'FilePickerParent.cpp',
'nsIContentChild.cpp',
'nsIContentParent.cpp',
@@ -95,8 +94,6 @@ IPDL_SOURCES += [
'PContentPermissionRequest.ipdl',
'PCrashReporter.ipdl',
'PCycleCollectWithLogs.ipdl',
- 'PDatePicker.ipdl',
- 'PDocumentRenderer.ipdl',
'PFilePicker.ipdl',
'PMemoryReportRequest.ipdl',
'PPluginWidget.ipdl',
diff --git a/dom/locales/en-US/chrome/layout/HtmlForm.properties b/dom/locales/en-US/chrome/layout/HtmlForm.properties
index 621a0b2b3..82274b2bc 100644
--- a/dom/locales/en-US/chrome/layout/HtmlForm.properties
+++ b/dom/locales/en-US/chrome/layout/HtmlForm.properties
@@ -34,7 +34,6 @@ NoDirSelected=No directory selected.
# %S will be a number greater or equal to 2.
XFilesSelected=%S files selected.
ColorPicker=Choose a color
-DatePicker=Choose a date
# LOCALIZATION NOTE (AndNMoreFiles): Semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# This string is shown at the end of the tooltip text for <input type='file'
diff --git a/dom/locales/en-US/chrome/plugins.properties b/dom/locales/en-US/chrome/plugins.properties
index ee8d25c88..fe03be59e 100644
--- a/dom/locales/en-US/chrome/plugins.properties
+++ b/dom/locales/en-US/chrome/plugins.properties
@@ -21,9 +21,6 @@ description_label=Description
suffixes_label=Suffixes
learn_more_label=Learn More
-deprecation_description=Missing something? Some plugins are no longer supported.
-deprecation_learn_more=Learn More.
-
# GMP Plugins
gmp_license_info=License information
gmp_privacy_info=Privacy Information
diff --git a/dom/locales/en-US/chrome/security/csp.properties b/dom/locales/en-US/chrome/security/csp.properties
index fc7fc04ba..4c4054cee 100644
--- a/dom/locales/en-US/chrome/security/csp.properties
+++ b/dom/locales/en-US/chrome/security/csp.properties
@@ -91,6 +91,10 @@ ignoringReportOnlyDirective = Ignoring sandbox directive when delivered in a rep
# LOCALIZATION NOTE (deprecatedReferrerDirective):
# %1$S is the value of the deprecated Referrer Directive.
deprecatedReferrerDirective = Referrer Directive ‘%1$S’ has been deprecated. Please use the Referrer-Policy header instead.
+# LOCALIZATION NOTE (IgnoringSrcBecauseOfDirective):
+# %1$S is the name of the src that is ignored.
+# %2$S is the name of the directive that causes the src to be ignored.
+IgnoringSrcBecauseOfDirective=Ignoring ‘%1$S’ because of ‘%2$S’ directive.
# CSP Errors:
# LOCALIZATION NOTE (couldntParseInvalidSource):
@@ -108,9 +112,10 @@ couldntParsePort = Couldn’t parse port in %1$S
# LOCALIZATION NOTE (duplicateDirective):
# %1$S is the name of the duplicate directive
duplicateDirective = Duplicate %1$S directives detected. All but the first instance will be ignored.
-# LOCALIZATION NOTE (deprecatedDirective):
-# %1$S is the name of the deprecated directive, %2$S is the name of the replacement.
-deprecatedDirective = Directive ‘%1$S’ has been deprecated. Please use directive ‘%2$S’ instead.
+# LOCALIZATION NOTE (deprecatedChildSrcDirective):
+# %1$S is the value of the deprecated directive.
+# Do not localize: worker-src, frame-src
+deprecatedChildSrcDirective = Directive ‘%1$S’ has been deprecated. Please use directive ‘worker-src’ to control workers, or directive ‘frame-src’ to control frames respectively.
# LOCALIZATION NOTE (couldntParseInvalidSandboxFlag):
# %1$S is the option that could not be understood
couldntParseInvalidSandboxFlag = Couldn’t parse invalid sandbox flag ‘%1$S’
diff --git a/dom/locales/en-US/chrome/security/security.properties b/dom/locales/en-US/chrome/security/security.properties
index 8b66cc265..c0b80996c 100644
--- a/dom/locales/en-US/chrome/security/security.properties
+++ b/dom/locales/en-US/chrome/security/security.properties
@@ -81,3 +81,6 @@ MimeTypeMismatch=The resource from “%1$S” was blocked due to MIME type misma
XCTOHeaderValueMissing=X-Content-Type-Options header warning: value was “%1$S”; did you mean to send “nosniff”?
BlockScriptWithWrongMimeType=Script from “%1$S” was blocked because of a disallowed MIME type.
+
+# LOCALIZATION NOTE: Do not translate "data: URI".
+BlockTopLevelDataURINavigation=Navigation to toplevel data: URI not allowed (Blocked loading of: “%1$S”)
diff --git a/dom/media/AudioConverter.cpp b/dom/media/AudioConverter.cpp
index 77ad46ec6..25b981f43 100644
--- a/dom/media/AudioConverter.cpp
+++ b/dom/media/AudioConverter.cpp
@@ -362,15 +362,13 @@ size_t
AudioConverter::ResampleRecipientFrames(size_t aFrames) const
{
if (!aFrames && mIn.Rate() != mOut.Rate()) {
- // The resampler will be drained, account for frames currently buffered
- // in the resampler.
if (!mResampler) {
return 0;
}
- return speex_resampler_get_output_latency(mResampler);
- } else {
- return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1;
+ // We drain by pushing in get_input_latency() samples of 0
+ aFrames = speex_resampler_get_input_latency(mResampler);
}
+ return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1;
}
size_t
diff --git a/dom/media/Benchmark.cpp b/dom/media/Benchmark.cpp
index a4761f1b1..fdbedeca5 100644
--- a/dom/media/Benchmark.cpp
+++ b/dom/media/Benchmark.cpp
@@ -22,7 +22,7 @@ namespace mozilla {
// Update this version number to force re-running the benchmark. Such as when
// an improvement to FFVP9 or LIBVPX is deemed worthwhile.
-const uint32_t VP9Benchmark::sBenchmarkVersionID = 1;
+const uint32_t VP9Benchmark::sBenchmarkVersionID = 3;
const char* VP9Benchmark::sBenchmarkFpsPref = "media.benchmark.vp9.fps";
const char* VP9Benchmark::sBenchmarkFpsVersionCheck = "media.benchmark.vp9.versioncheck";
diff --git a/dom/media/DOMMediaStream.cpp b/dom/media/DOMMediaStream.cpp
index 6794ee32f..c1d451035 100644..100755
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -9,6 +9,7 @@
#include "nsIScriptError.h"
#include "nsIUUIDGenerator.h"
#include "nsPIDOMWindow.h"
+#include "mozilla/TimerClamping.h"
#include "mozilla/dom/MediaStreamBinding.h"
#include "mozilla/dom/MediaStreamTrackEvent.h"
#include "mozilla/dom/LocalMediaStreamBinding.h"
@@ -544,8 +545,8 @@ DOMMediaStream::CurrentTime()
if (!mPlaybackStream) {
return 0.0;
}
- return mPlaybackStream->
- StreamTimeToSeconds(mPlaybackStream->GetCurrentTime() - mLogicalStreamStartTime);
+ return TimerClamping::ReduceSTimeValue(mPlaybackStream->
+ StreamTimeToSeconds(mPlaybackStream->GetCurrentTime() - mLogicalStreamStartTime));
}
void
diff --git a/dom/media/DecoderDoctorDiagnostics.cpp b/dom/media/DecoderDoctorDiagnostics.cpp
index 91c2d8dfb..778e8c4c5 100644
--- a/dom/media/DecoderDoctorDiagnostics.cpp
+++ b/dom/media/DecoderDoctorDiagnostics.cpp
@@ -576,16 +576,9 @@ DecoderDoctorDocumentWatcher::SynthesizeAnalysis()
// going through expected decoders from most to least desirable.
#if defined(XP_WIN)
if (!formatsRequiringWMF.IsEmpty()) {
- if (IsVistaOrLater()) {
- DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> Cannot play media because WMF was not found",
- this, mDocument, NS_ConvertUTF16toUTF8(formatsRequiringWMF).get());
- ReportAnalysis(mDocument, sMediaWMFNeeded, false, formatsRequiringWMF);
- } else {
- DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> Cannot play media before Windows Vista",
- this, mDocument, NS_ConvertUTF16toUTF8(formatsRequiringWMF).get());
- ReportAnalysis(mDocument, sMediaUnsupportedBeforeWindowsVista,
- false, formatsRequiringWMF);
- }
+ DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> Cannot play media because WMF was not found",
+ this, mDocument, NS_ConvertUTF16toUTF8(formatsRequiringWMF).get());
+ ReportAnalysis(mDocument, sMediaWMFNeeded, false, formatsRequiringWMF);
return;
}
#endif
diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp
index 9b74bd58c..40e3b72cf 100644
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -1055,6 +1055,7 @@ AudioCallbackDriver::StateCallback(cubeb_state aState)
{
STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver State: %d", aState));
if (aState == CUBEB_STATE_ERROR && mShouldFallbackIfError) {
+ mShouldFallbackIfError = false;
MonitorAutoLock lock(GraphImpl()->GetMonitor());
// Fall back to a driver using a normal thread. If needed,
// the graph will try to re-open an audio stream later.
diff --git a/dom/media/MediaData.cpp b/dom/media/MediaData.cpp
index 0439a7473..4a52c22ae 100644
--- a/dom/media/MediaData.cpp
+++ b/dom/media/MediaData.cpp
@@ -90,7 +90,7 @@ ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane)
return aPlane.mWidth <= PlanarYCbCrImage::MAX_DIMENSION &&
aPlane.mHeight <= PlanarYCbCrImage::MAX_DIMENSION &&
aPlane.mWidth * aPlane.mHeight < MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
- aPlane.mStride > 0;
+ aPlane.mStride > 0 && aPlane.mWidth <= aPlane.mStride;
}
#ifdef MOZ_WIDGET_GONK
diff --git a/dom/media/MediaDecoderOwner.h b/dom/media/MediaDecoderOwner.h
index f884686fb..f993b4324 100644
--- a/dom/media/MediaDecoderOwner.h
+++ b/dom/media/MediaDecoderOwner.h
@@ -143,11 +143,13 @@ public:
// reference to the decoder to prevent further calls into the decoder.
virtual void NotifyXPCOMShutdown() = 0;
+#ifdef MOZ_EME
// Dispatches a "encrypted" event to the HTMLMediaElement, with the
// provided init data. Actual dispatch may be delayed until HAVE_METADATA.
// Main thread only.
virtual void DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
const nsAString& aInitDataType) = 0;
+#endif
};
} // namespace mozilla
diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp
index 2093803ad..06e8b963b 100644
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -346,8 +346,12 @@ MediaFormatReader::DecoderFactory::DoCreateDecoder(TrackType aTrack)
if (!mOwner->mPlatform) {
mOwner->mPlatform = new PDMFactory();
if (mOwner->IsEncrypted()) {
+#ifdef MOZ_EME
MOZ_ASSERT(mOwner->mCDMProxy);
mOwner->mPlatform->SetCDMProxy(mOwner->mCDMProxy);
+#else
+ return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, "EME not supported");
+#endif
}
}
@@ -577,6 +581,7 @@ MediaFormatReader::InitInternal()
return NS_OK;
}
+#ifdef MOZ_EME
class DispatchKeyNeededEvent : public Runnable {
public:
DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder,
@@ -602,6 +607,7 @@ private:
nsTArray<uint8_t> mInitData;
nsString mInitDataType;
};
+#endif
void
MediaFormatReader::SetCDMProxy(CDMProxy* aProxy)
@@ -618,7 +624,11 @@ MediaFormatReader::SetCDMProxy(CDMProxy* aProxy)
bool
MediaFormatReader::IsWaitingOnCDMResource() {
MOZ_ASSERT(OnTaskQueue());
+#ifdef MOZ_EME
return IsEncrypted() && !mCDMProxy;
+#else
+ return false;
+#endif
}
RefPtr<MediaDecoderReader::MetadataPromise>
@@ -725,11 +735,13 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
UniquePtr<EncryptionInfo> crypto = mDemuxer->GetCrypto();
if (mDecoder && crypto && crypto->IsEncrypted()) {
+#ifdef MOZ_EME
// Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
NS_DispatchToMainThread(
new DispatchKeyNeededEvent(mDecoder, crypto->mInitDatas[i].mInitData, crypto->mInitDatas[i].mType));
}
+#endif
mInfo.mCrypto = *crypto;
}
diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp
index 96e2c23e0..97a6855d9 100644
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1853,20 +1853,18 @@ MediaManager::GetNonE10sParent()
MediaManager::StartupInit()
{
#ifdef WIN32
- if (IsVistaOrLater() && !IsWin8OrLater()) {
- // Bug 1107702 - Older Windows fail in GetAdaptersInfo (and others) if the
- // first(?) call occurs after the process size is over 2GB (kb/2588507).
- // Attempt to 'prime' the pump by making a call at startup.
- unsigned long out_buf_len = sizeof(IP_ADAPTER_INFO);
- PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *) moz_xmalloc(out_buf_len);
- if (GetAdaptersInfo(pAdapterInfo, &out_buf_len) == ERROR_BUFFER_OVERFLOW) {
- free(pAdapterInfo);
- pAdapterInfo = (IP_ADAPTER_INFO *) moz_xmalloc(out_buf_len);
- GetAdaptersInfo(pAdapterInfo, &out_buf_len);
- }
- if (pAdapterInfo) {
- free(pAdapterInfo);
- }
+ // Bug 1107702 - Some Windows versions fail in GetAdaptersInfo (and others)
+ // if the first(?) call occurs after the process size is over 2GB (kb/2588507).
+ // Attempt to 'prime' the pump by making a call at startup.
+ unsigned long out_buf_len = sizeof(IP_ADAPTER_INFO);
+ PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *) moz_xmalloc(out_buf_len);
+ if (GetAdaptersInfo(pAdapterInfo, &out_buf_len) == ERROR_BUFFER_OVERFLOW) {
+ free(pAdapterInfo);
+ pAdapterInfo = (IP_ADAPTER_INFO *) moz_xmalloc(out_buf_len);
+ GetAdaptersInfo(pAdapterInfo, &out_buf_len);
+ }
+ if (pAdapterInfo) {
+ free(pAdapterInfo);
}
#endif
}
@@ -2130,19 +2128,11 @@ if (privileged) {
case MediaSourceEnum::Application:
case MediaSourceEnum::Window:
// Deny screensharing request if support is disabled, or
- // the requesting document is not from a host on the whitelist, or
- // we're on WinXP until proved that it works
+ // the requesting document is not from a host on the whitelist
if (!Preferences::GetBool(((videoType == MediaSourceEnum::Browser)?
"media.getusermedia.browser.enabled" :
"media.getusermedia.screensharing.enabled"),
false) ||
-#if defined(XP_WIN)
- (
- // Allow tab sharing for all platforms including XP
- (videoType != MediaSourceEnum::Browser) &&
- !Preferences::GetBool("media.getusermedia.screensharing.allow_on_old_platforms",
- false) && !IsVistaOrLater()) ||
-#endif
(!privileged && !HostIsHttps(*docURI))) {
RefPtr<MediaStreamError> error =
new MediaStreamError(aWindow,
diff --git a/dom/media/MediaPrefs.h b/dom/media/MediaPrefs.h
index 62b8fc47b..b237ecd3d 100644
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -156,10 +156,6 @@ private:
DECL_MEDIA_PREF("media.ogg.flac.enabled", FlacInOgg, bool, false);
DECL_MEDIA_PREF("media.flac.enabled", FlacEnabled, bool, true);
-#if defined(MOZ_RUST_MP4PARSE) && !defined(RELEASE_OR_BETA)
- DECL_MEDIA_PREF("media.rust.test_mode", RustTestMode, bool, false);
-#endif
-
public:
// Manage the singleton:
static MediaPrefs& GetSingleton();
diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp
index 94cafa029..e2934cbb2 100644
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -1715,6 +1715,10 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG)
RefPtr<GraphDriver> driver = CurrentDriver();
MonitorAutoUnlock unlock(mMonitor);
driver->Start();
+ // It's not safe to Shutdown() a thread from StableState, and
+ // releasing this may shutdown a SystemClockDriver thread.
+ // Proxy the release to outside of StableState.
+ NS_ReleaseOnMainThread(driver.forget(), true); // always proxy
}
}
diff --git a/dom/media/MediaStreamTrack.cpp b/dom/media/MediaStreamTrack.cpp
index 8ccdeb90c..75cdeb1d1 100644
--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -165,11 +165,15 @@ MediaStreamTrack::Destroy()
mPrincipalHandleListener->Forget();
mPrincipalHandleListener = nullptr;
}
- for (auto l : mTrackListeners) {
- RemoveListener(l);
+ // Remove all listeners -- avoid iterating over the list we're removing from
+ const nsTArray<RefPtr<MediaStreamTrackListener>> trackListeners(mTrackListeners);
+ for (auto listener : trackListeners) {
+ RemoveListener(listener);
}
- for (auto l : mDirectTrackListeners) {
- RemoveDirectListener(l);
+ // Do the same as above for direct listeners
+ const nsTArray<RefPtr<DirectMediaStreamTrackListener>> directTrackListeners(mDirectTrackListeners);
+ for (auto listener : directTrackListeners) {
+ RemoveDirectListener(listener);
}
}
diff --git a/dom/media/eme/MediaKeySystemAccess.cpp b/dom/media/eme/MediaKeySystemAccess.cpp
index 7007d3a03..4cff464e7 100644
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -140,26 +140,12 @@ MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem,
aOutMessage = NS_LITERAL_CSTRING("Adobe EME disabled");
return MediaKeySystemStatus::Cdm_disabled;
}
-#ifdef XP_WIN
- // Win Vista and later only.
- if (!IsVistaOrLater()) {
- aOutMessage = NS_LITERAL_CSTRING("Minimum Windows version (Vista) not met for Adobe EME");
- return MediaKeySystemStatus::Cdm_not_supported;
- }
-#endif
return EnsureCDMInstalled(aKeySystem, aOutMessage);
}
}
if (IsWidevineKeySystem(aKeySystem)) {
if (Preferences::GetBool("media.gmp-widevinecdm.visible", false)) {
-#ifdef XP_WIN
- // Win Vista and later only.
- if (!IsVistaOrLater()) {
- aOutMessage = NS_LITERAL_CSTRING("Minimum Windows version (Vista) not met for Widevine EME");
- return MediaKeySystemStatus::Cdm_not_supported;
- }
-#endif
if (!Preferences::GetBool("media.gmp-widevinecdm.enabled", false)) {
aOutMessage = NS_LITERAL_CSTRING("Widevine EME disabled");
return MediaKeySystemStatus::Cdm_disabled;
diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp
index 4cf07ddbd..fdd6f2c7e 100644
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -52,14 +52,6 @@ IsWhitelistedH264Codec(const nsAString& aCodec)
return false;
}
-#ifdef XP_WIN
- // Disable 4k video on windows vista since it performs poorly.
- if (!IsWin7OrLater() &&
- level >= H264_LEVEL_5) {
- return false;
- }
-#endif
-
// Just assume what we can play on all platforms the codecs/formats that
// WMF can play, since we don't have documentation about what other
// platforms can play... According to the WMF documentation:
diff --git a/dom/media/gmp/GMPChild.cpp b/dom/media/gmp/GMPChild.cpp
index 953dae3c6..f8e75e299 100644
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -257,10 +257,6 @@ GMPChild::Init(const nsAString& aPluginPath,
return false;
}
-#ifdef MOZ_CRASHREPORTER
- SendPCrashReporterConstructor(CrashReporter::CurrentThreadId());
-#endif
-
mPluginPath = aPluginPath;
mSandboxVoucherPath = aVoucherPath;
diff --git a/dom/media/gmp/GMPParent.cpp b/dom/media/gmp/GMPParent.cpp
index 75468ea9a..00bc97777 100644
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -29,12 +29,6 @@
using mozilla::dom::CrashReporterParent;
using mozilla::ipc::GeckoChildProcessHost;
-#ifdef MOZ_CRASHREPORTER
-#include "nsPrintfCString.h"
-using CrashReporter::AnnotationTable;
-using CrashReporter::GetIDFromMinidump;
-#endif
-
#include "mozilla/Telemetry.h"
#ifdef XP_WIN
@@ -224,10 +218,6 @@ GMPParent::AbortWaitingForGMPAsyncShutdown(nsITimer* aTimer, void* aClosure)
NS_WARNING("Timed out waiting for GMP async shutdown!");
GMPParent* parent = reinterpret_cast<GMPParent*>(aClosure);
MOZ_ASSERT(parent->mService);
-#if defined(MOZ_CRASHREPORTER)
- parent->mService->SetAsyncShutdownPluginState(parent, 'G',
- NS_LITERAL_CSTRING("Timed out waiting for async shutdown"));
-#endif
parent->mService->AsyncShutdownComplete(parent);
}
@@ -270,22 +260,8 @@ GMPParent::RecvPGMPContentChildDestroyed()
{
--mGMPContentChildCount;
if (!IsUsed()) {
-#if defined(MOZ_CRASHREPORTER)
- if (mService) {
- mService->SetAsyncShutdownPluginState(this, 'E',
- NS_LITERAL_CSTRING("Last content child destroyed"));
- }
-#endif
CloseIfUnused();
}
-#if defined(MOZ_CRASHREPORTER)
- else {
- if (mService) {
- mService->SetAsyncShutdownPluginState(this, 'F',
- nsPrintfCString("Content child destroyed, remaining: %u", mGMPContentChildCount));
- }
- }
-#endif
return true;
}
@@ -307,38 +283,14 @@ GMPParent::CloseIfUnused()
if (mAsyncShutdownRequired) {
if (!mAsyncShutdownInProgress) {
LOGD("%s: sending async shutdown notification", __FUNCTION__);
-#if defined(MOZ_CRASHREPORTER)
- if (mService) {
- mService->SetAsyncShutdownPluginState(this, 'H',
- NS_LITERAL_CSTRING("Sent BeginAsyncShutdown"));
- }
-#endif
mAsyncShutdownInProgress = true;
if (!SendBeginAsyncShutdown()) {
-#if defined(MOZ_CRASHREPORTER)
- if (mService) {
- mService->SetAsyncShutdownPluginState(this, 'I',
- NS_LITERAL_CSTRING("Could not send BeginAsyncShutdown - Aborting async shutdown"));
- }
-#endif
AbortAsyncShutdown();
} else if (NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
-#if defined(MOZ_CRASHREPORTER)
- if (mService) {
- mService->SetAsyncShutdownPluginState(this, 'J',
- NS_LITERAL_CSTRING("Could not start timer after sending BeginAsyncShutdown - Aborting async shutdown"));
- }
-#endif
AbortAsyncShutdown();
}
}
} else {
-#if defined(MOZ_CRASHREPORTER)
- if (mService) {
- mService->SetAsyncShutdownPluginState(this, 'K',
- NS_LITERAL_CSTRING("No (more) async-shutdown required"));
- }
-#endif
// No async-shutdown, kill async-shutdown timer started in CloseActive().
AbortAsyncShutdown();
// Any async shutdown must be complete. Shutdown GMPStorage.
@@ -385,29 +337,11 @@ GMPParent::CloseActive(bool aDieWhenUnloaded)
mState = GMPStateUnloading;
}
if (mState != GMPStateNotLoaded && IsUsed()) {
-#if defined(MOZ_CRASHREPORTER)
- if (mService) {
- mService->SetAsyncShutdownPluginState(this, 'A',
- nsPrintfCString("Sent CloseActive, content children to close: %u", mGMPContentChildCount));
- }
-#endif
if (!SendCloseActive()) {
-#if defined(MOZ_CRASHREPORTER)
- if (mService) {
- mService->SetAsyncShutdownPluginState(this, 'B',
- NS_LITERAL_CSTRING("Could not send CloseActive - Aborting async shutdown"));
- }
-#endif
AbortAsyncShutdown();
} else if (IsUsed()) {
// We're expecting RecvPGMPContentChildDestroyed's -> Start async-shutdown timer now if needed.
if (mAsyncShutdownRequired && NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
-#if defined(MOZ_CRASHREPORTER)
- if (mService) {
- mService->SetAsyncShutdownPluginState(this, 'C',
- NS_LITERAL_CSTRING("Could not start timer after sending CloseActive - Aborting async shutdown"));
- }
-#endif
AbortAsyncShutdown();
}
} else {
@@ -418,12 +352,6 @@ GMPParent::CloseActive(bool aDieWhenUnloaded)
// that time, it might not have proceeded with shutdown; And calling it
// again after shutdown is fine because after the first one we'll be in
// GMPStateNotLoaded.
-#if defined(MOZ_CRASHREPORTER)
- if (mService) {
- mService->SetAsyncShutdownPluginState(this, 'D',
- NS_LITERAL_CSTRING("Content children already destroyed"));
- }
-#endif
CloseIfUnused();
}
}
@@ -630,78 +558,10 @@ GMPParent::EnsureProcessLoaded()
return NS_SUCCEEDED(rv);
}
-#ifdef MOZ_CRASHREPORTER
-void
-GMPParent::WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes)
-{
- notes.Put(NS_LITERAL_CSTRING("GMPPlugin"), NS_LITERAL_CSTRING("1"));
- notes.Put(NS_LITERAL_CSTRING("PluginFilename"),
- NS_ConvertUTF16toUTF8(mName));
- notes.Put(NS_LITERAL_CSTRING("PluginName"), mDisplayName);
- notes.Put(NS_LITERAL_CSTRING("PluginVersion"), mVersion);
-}
-
-void
-GMPParent::GetCrashID(nsString& aResult)
-{
- CrashReporterParent* cr =
- static_cast<CrashReporterParent*>(LoneManagedOrNullAsserts(ManagedPCrashReporterParent()));
- if (NS_WARN_IF(!cr)) {
- return;
- }
-
- AnnotationTable notes(4);
- WriteExtraDataForMinidump(notes);
- nsCOMPtr<nsIFile> dumpFile;
- TakeMinidump(getter_AddRefs(dumpFile), nullptr);
- if (!dumpFile) {
- NS_WARNING("GMP crash without crash report");
- aResult = mName;
- aResult += '-';
- AppendUTF8toUTF16(mVersion, aResult);
- return;
- }
- GetIDFromMinidump(dumpFile, aResult);
- cr->GenerateCrashReportForMinidump(dumpFile, &notes);
-}
-
-static void
-GMPNotifyObservers(const uint32_t aPluginID, const nsACString& aPluginName, const nsAString& aPluginDumpID)
-{
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- nsCOMPtr<nsIWritablePropertyBag2> propbag =
- do_CreateInstance("@mozilla.org/hash-property-bag;1");
- if (obs && propbag) {
- propbag->SetPropertyAsUint32(NS_LITERAL_STRING("pluginID"), aPluginID);
- propbag->SetPropertyAsACString(NS_LITERAL_STRING("pluginName"), aPluginName);
- propbag->SetPropertyAsAString(NS_LITERAL_STRING("pluginDumpID"), aPluginDumpID);
- obs->NotifyObservers(propbag, "gmp-plugin-crash", nullptr);
- }
-
- RefPtr<gmp::GeckoMediaPluginService> service =
- gmp::GeckoMediaPluginService::GetGeckoMediaPluginService();
- if (service) {
- service->RunPluginCrashCallbacks(aPluginID, aPluginName);
- }
-}
-#endif
void
GMPParent::ActorDestroy(ActorDestroyReason aWhy)
{
LOGD("%s: (%d)", __FUNCTION__, (int)aWhy);
-#ifdef MOZ_CRASHREPORTER
- if (AbnormalShutdown == aWhy) {
- Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
- NS_LITERAL_CSTRING("gmplugin"), 1);
- nsString dumpID;
- GetCrashID(dumpID);
-
- // NotifyObservers is mainthread-only
- NS_DispatchToMainThread(WrapRunnableNM(&GMPNotifyObservers,
- mPluginId, mDisplayName, dumpID),
- NS_DISPATCH_NORMAL);
- }
-#endif
// warn us off trying to close again
mState = GMPStateClosing;
mAbnormalShutdownInProgress = true;
@@ -711,12 +571,6 @@ GMPParent::ActorDestroy(ActorDestroyReason aWhy)
if (AbnormalShutdown == aWhy) {
RefPtr<GMPParent> self(this);
if (mAsyncShutdownRequired) {
-#if defined(MOZ_CRASHREPORTER)
- if (mService) {
- mService->SetAsyncShutdownPluginState(this, 'M',
- NS_LITERAL_CSTRING("Actor destroyed"));
- }
-#endif
mService->AsyncShutdownComplete(this);
mAsyncShutdownRequired = false;
}
@@ -732,9 +586,7 @@ GMPParent::ActorDestroy(ActorDestroyReason aWhy)
mozilla::dom::PCrashReporterParent*
GMPParent::AllocPCrashReporterParent(const NativeThreadId& aThread)
{
-#ifndef MOZ_CRASHREPORTER
MOZ_ASSERT(false, "Should only be sent if crash reporting is enabled.");
-#endif
CrashReporterParent* cr = new CrashReporterParent();
cr->SetChildData(aThread, GeckoProcessType_GMPlugin);
return cr;
@@ -1043,12 +895,6 @@ GMPParent::RecvAsyncShutdownComplete()
LOGD("%s", __FUNCTION__);
MOZ_ASSERT(mAsyncShutdownRequired);
-#if defined(MOZ_CRASHREPORTER)
- if (mService) {
- mService->SetAsyncShutdownPluginState(this, 'L',
- NS_LITERAL_CSTRING("Received AsyncShutdownComplete"));
- }
-#endif
AbortAsyncShutdown();
return true;
}
diff --git a/dom/media/gmp/GMPParent.h b/dom/media/gmp/GMPParent.h
index 91a6fb429..4f91ec5ba 100644
--- a/dom/media/gmp/GMPParent.h
+++ b/dom/media/gmp/GMPParent.h
@@ -25,17 +25,6 @@
class nsIThread;
-#ifdef MOZ_CRASHREPORTER
-#include "nsExceptionHandler.h"
-
-namespace mozilla {
-namespace dom {
-class PCrashReporterParent;
-class CrashReporterParent;
-}
-}
-#endif
-
namespace mozilla {
namespace gmp {
@@ -177,10 +166,6 @@ private:
RefPtr<GenericPromise> ReadGMPInfoFile(nsIFile* aFile);
RefPtr<GenericPromise> ParseChromiumManifest(nsString aJSON); // Main thread.
RefPtr<GenericPromise> ReadChromiumManifestFile(nsIFile* aFile); // GMP thread.
-#ifdef MOZ_CRASHREPORTER
- void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes);
- void GetCrashID(nsString& aResult);
-#endif
void ActorDestroy(ActorDestroyReason aWhy) override;
PCrashReporterParent* AllocPCrashReporterParent(const NativeThreadId& aThread) override;
diff --git a/dom/media/gmp/GMPServiceParent.cpp b/dom/media/gmp/GMPServiceParent.cpp
index 8741989e3..f25c36811 100644
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -36,10 +36,6 @@
#include "nsHashKeys.h"
#include "nsIFile.h"
#include "nsISimpleEnumerator.h"
-#if defined(MOZ_CRASHREPORTER)
-#include "nsExceptionHandler.h"
-#include "nsPrintfCString.h"
-#endif
#include "nsIXULRuntime.h"
#include "GMPDecoderModule.h"
#include <limits>
@@ -88,9 +84,6 @@ NS_IMPL_ISUPPORTS_INHERITED(GeckoMediaPluginServiceParent,
GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent()
: mShuttingDown(false)
-#ifdef MOZ_CRASHREPORTER
- , mAsyncShutdownPluginStatesMutex("GeckoMediaPluginService::mAsyncShutdownPluginStatesMutex")
-#endif
, mScannedPluginOnDisk(false)
, mWaitingForPluginsSyncShutdown(false)
, mInitPromiseMonitor("GeckoMediaPluginServiceParent::mInitPromiseMonitor")
@@ -421,28 +414,16 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject,
if (gmpThread) {
LOGD(("%s::%s Starting to unload plugins, waiting for first sync shutdown..."
, __CLASS__, __FUNCTION__));
-#ifdef MOZ_CRASHREPORTER
- SetAsyncShutdownPluginState(nullptr, '0',
- NS_LITERAL_CSTRING("Dispatching UnloadPlugins"));
-#endif
gmpThread->Dispatch(
NewRunnableMethod(this,
&GeckoMediaPluginServiceParent::UnloadPlugins),
NS_DISPATCH_NORMAL);
-#ifdef MOZ_CRASHREPORTER
- SetAsyncShutdownPluginState(nullptr, '1',
- NS_LITERAL_CSTRING("Waiting for sync shutdown"));
-#endif
// Wait for UnloadPlugins() to do initial sync shutdown...
while (mWaitingForPluginsSyncShutdown) {
NS_ProcessNextEvent(NS_GetCurrentThread(), true);
}
-#ifdef MOZ_CRASHREPORTER
- SetAsyncShutdownPluginState(nullptr, '4',
- NS_LITERAL_CSTRING("Waiting for async shutdown"));
-#endif
// Wait for other plugins (if any) to do async shutdown...
auto syncShutdownPluginsRemaining =
std::numeric_limits<decltype(mAsyncShutdownPlugins.Length())>::max();
@@ -452,10 +433,6 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject,
if (mAsyncShutdownPlugins.IsEmpty()) {
LOGD(("%s::%s Finished unloading all plugins"
, __CLASS__, __FUNCTION__));
-#if defined(MOZ_CRASHREPORTER)
- CrashReporter::RemoveCrashReportAnnotation(
- NS_LITERAL_CSTRING("AsyncPluginShutdown"));
-#endif
break;
} else if (mAsyncShutdownPlugins.Length() < syncShutdownPluginsRemaining) {
// First time here, or number of pending plugins has decreased.
@@ -463,24 +440,10 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject,
syncShutdownPluginsRemaining = mAsyncShutdownPlugins.Length();
LOGD(("%s::%s Still waiting for %d plugins to shutdown..."
, __CLASS__, __FUNCTION__, (int)syncShutdownPluginsRemaining));
-#if defined(MOZ_CRASHREPORTER)
- nsAutoCString names;
- for (const auto& plugin : mAsyncShutdownPlugins) {
- if (!names.IsEmpty()) { names.Append(NS_LITERAL_CSTRING(", ")); }
- names.Append(plugin->GetDisplayName());
- }
- CrashReporter::AnnotateCrashReport(
- NS_LITERAL_CSTRING("AsyncPluginShutdown"),
- names);
-#endif
}
}
NS_ProcessNextEvent(NS_GetCurrentThread(), true);
}
-#ifdef MOZ_CRASHREPORTER
- SetAsyncShutdownPluginState(nullptr, '5',
- NS_LITERAL_CSTRING("Async shutdown complete"));
-#endif
} else {
// GMP thread has already shutdown.
MOZ_ASSERT(mPlugins.IsEmpty());
@@ -627,66 +590,6 @@ GeckoMediaPluginServiceParent::AsyncShutdownComplete(GMPParent* aParent)
}
}
-#ifdef MOZ_CRASHREPORTER
-void
-GeckoMediaPluginServiceParent::SetAsyncShutdownPluginState(GMPParent* aGMPParent,
- char aId,
- const nsCString& aState)
-{
- MutexAutoLock lock(mAsyncShutdownPluginStatesMutex);
- if (!aGMPParent) {
- mAsyncShutdownPluginStates.Update(NS_LITERAL_CSTRING("-"),
- NS_LITERAL_CSTRING("-"),
- aId,
- aState);
- return;
- }
- mAsyncShutdownPluginStates.Update(aGMPParent->GetDisplayName(),
- nsPrintfCString("%p", aGMPParent),
- aId,
- aState);
-}
-
-void
-GeckoMediaPluginServiceParent::AsyncShutdownPluginStates::Update(const nsCString& aPlugin,
- const nsCString& aInstance,
- char aId,
- const nsCString& aState)
-{
- nsCString note;
- StatesByInstance* instances = mStates.LookupOrAdd(aPlugin);
- if (!instances) { return; }
- State* state = instances->LookupOrAdd(aInstance);
- if (!state) { return; }
- state->mStateSequence += aId;
- state->mLastStateDescription = aState;
- note += '{';
- bool firstPlugin = true;
- for (auto pluginIt = mStates.ConstIter(); !pluginIt.Done(); pluginIt.Next()) {
- if (!firstPlugin) { note += ','; } else { firstPlugin = false; }
- note += pluginIt.Key();
- note += ":{";
- bool firstInstance = true;
- for (auto instanceIt = pluginIt.UserData()->ConstIter(); !instanceIt.Done(); instanceIt.Next()) {
- if (!firstInstance) { note += ','; } else { firstInstance = false; }
- note += instanceIt.Key();
- note += ":\"";
- note += instanceIt.UserData()->mStateSequence;
- note += '=';
- note += instanceIt.UserData()->mLastStateDescription;
- note += '"';
- }
- note += '}';
- }
- note += '}';
- LOGD(("%s::%s states[%s][%s]='%c'/'%s' -> %s", __CLASS__, __FUNCTION__,
- aPlugin.get(), aInstance.get(), aId, aState.get(), note.get()));
- CrashReporter::AnnotateCrashReport(
- NS_LITERAL_CSTRING("AsyncPluginShutdownStates"),
- note);
-}
-#endif // MOZ_CRASHREPORTER
-
void
GeckoMediaPluginServiceParent::NotifyAsyncShutdownComplete()
{
@@ -714,10 +617,6 @@ GeckoMediaPluginServiceParent::UnloadPlugins()
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
MOZ_ASSERT(!mShuttingDownOnGMPThread);
mShuttingDownOnGMPThread = true;
-#ifdef MOZ_CRASHREPORTER
- SetAsyncShutdownPluginState(nullptr, '2',
- NS_LITERAL_CSTRING("Starting to unload plugins"));
-#endif
nsTArray<RefPtr<GMPParent>> plugins;
{
@@ -742,17 +641,9 @@ GeckoMediaPluginServiceParent::UnloadPlugins()
// Note: CloseActive may be async; it could actually finish
// shutting down when all the plugins have unloaded.
for (const auto& plugin : plugins) {
-#ifdef MOZ_CRASHREPORTER
- SetAsyncShutdownPluginState(plugin, 'S',
- NS_LITERAL_CSTRING("CloseActive"));
-#endif
plugin->CloseActive(true);
}
-#ifdef MOZ_CRASHREPORTER
- SetAsyncShutdownPluginState(nullptr, '3',
- NS_LITERAL_CSTRING("Dispatching sync-shutdown-complete"));
-#endif
nsCOMPtr<nsIRunnable> task(NewRunnableMethod(
this, &GeckoMediaPluginServiceParent::NotifySyncShutdownComplete));
NS_DispatchToMainThread(task);
diff --git a/dom/media/gmp/GMPServiceParent.h b/dom/media/gmp/GMPServiceParent.h
index f3f43e215..49d81055b 100644
--- a/dom/media/gmp/GMPServiceParent.h
+++ b/dom/media/gmp/GMPServiceParent.h
@@ -54,9 +54,6 @@ public:
void AsyncShutdownComplete(GMPParent* aParent);
int32_t AsyncShutdownTimeoutMs();
-#ifdef MOZ_CRASHREPORTER
- void SetAsyncShutdownPluginState(GMPParent* aGMPParent, char aId, const nsCString& aState);
-#endif // MOZ_CRASHREPORTER
RefPtr<GenericPromise> EnsureInitialized();
RefPtr<GenericPromise> AsyncAddPluginDirectory(const nsAString& aDirectory);
@@ -169,21 +166,6 @@ private:
bool mShuttingDown;
nsTArray<RefPtr<GMPParent>> mAsyncShutdownPlugins;
-#ifdef MOZ_CRASHREPORTER
- Mutex mAsyncShutdownPluginStatesMutex; // Protects mAsyncShutdownPluginStates.
- class AsyncShutdownPluginStates
- {
- public:
- void Update(const nsCString& aPlugin, const nsCString& aInstance,
- char aId, const nsCString& aState);
- private:
- struct State { nsCString mStateSequence; nsCString mLastStateDescription; };
- typedef nsClassHashtable<nsCStringHashKey, State> StatesByInstance;
- typedef nsClassHashtable<nsCStringHashKey, StatesByInstance> StateInstancesByPlugin;
- StateInstancesByPlugin mStates;
- } mAsyncShutdownPluginStates;
-#endif // MOZ_CRASHREPORTER
-
// True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any
// plugins found there into mPlugins.
Atomic<bool> mScannedPluginOnDisk;
diff --git a/dom/media/gtest/TestGMPCrossOrigin.cpp b/dom/media/gtest/TestGMPCrossOrigin.cpp
index 036282153..33ac98388 100644
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp
+++ b/dom/media/gtest/TestGMPCrossOrigin.cpp
@@ -1521,11 +1521,6 @@ TEST(GeckoMediaPlugins, GMPPluginVoucher) {
#if defined(XP_WIN)
TEST(GeckoMediaPlugins, GMPOutputProtection) {
- // Output Protection is not available pre-Vista.
- if (!IsVistaOrLater()) {
- return;
- }
-
RefPtr<GMPStorageTest> runner = new GMPStorageTest();
runner->DoTest(&GMPStorageTest::TestOutputProtection);
}
diff --git a/dom/media/gtest/moz.build b/dom/media/gtest/moz.build
index fc92d5ef3..d5d02bced 100644
--- a/dom/media/gtest/moz.build
+++ b/dom/media/gtest/moz.build
@@ -35,10 +35,6 @@ if CONFIG['MOZ_WEBM_ENCODER']:
'TestWebMWriter.cpp',
]
-if CONFIG['MOZ_RUST']:
- UNIFIED_SOURCES += ['TestRust.cpp',]
-
-
TEST_HARNESS_FILES.gtest += [
'../test/gizmo-frag.mp4',
'../test/gizmo.mp4',
diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp
index 4265aed81..ac6d82411 100644
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -58,6 +58,7 @@ AppendStateToStr(SourceBufferAttributes::AppendState aState)
static Atomic<uint32_t> sStreamSourceID(0u);
+#ifdef MOZ_EME
class DispatchKeyNeededEvent : public Runnable {
public:
DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder,
@@ -83,6 +84,7 @@ private:
nsTArray<uint8_t> mInitData;
nsString mInitDataType;
};
+#endif
TrackBuffersManager::TrackBuffersManager(MediaSourceDecoder* aParentDecoder,
const nsACString& aType)
@@ -1097,12 +1099,14 @@ TrackBuffersManager::OnDemuxerInitDone(nsresult)
UniquePtr<EncryptionInfo> crypto = mInputDemuxer->GetCrypto();
if (crypto && crypto->IsEncrypted()) {
+#ifdef MOZ_EME
// Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
NS_DispatchToMainThread(
new DispatchKeyNeededEvent(mParentDecoder, crypto->mInitDatas[i].mInitData,
crypto->mInitDatas[i].mType));
}
+#endif
info.mCrypto = *crypto;
// We clear our crypto init data array, so the MediaFormatReader will
// not emit an encrypted event for the same init data again.
diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp
index a72d910f5..c1e58fdc2 100644
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -47,10 +47,6 @@
#include "MP4Decoder.h"
#include "mozilla/dom/RemoteVideoDecoder.h"
-#ifdef XP_WIN
-#include "mozilla/WindowsVersion.h"
-#endif
-
#include "mp4_demuxer/H264.h"
namespace mozilla {
@@ -367,16 +363,7 @@ PDMFactory::CreatePDMs()
}
#endif
#ifdef XP_WIN
- if (MediaPrefs::PDMWMFEnabled() && IsVistaOrLater() && !IsWin7AndPre2000Compatible()) {
- // *Only* use WMF on Vista and later, as if Firefox is run in Windows 95
- // compatibility mode on Windows 7 (it does happen!) we may crash trying
- // to startup WMF. So we need to detect the OS version here, as in
- // compatibility mode IsVistaOrLater() and friends behave as if we're on
- // the emulated version of Windows. See bug 1279171.
- // Additionally, we don't want to start the RemoteDecoderModule if we
- // expect it's not going to work (i.e. on Windows older than Vista).
- // IsWin7AndPre2000Compatible() uses GetVersionEx as the user specified OS version can
- // be reflected when compatibility mode is in effect.
+ if (MediaPrefs::PDMWMFEnabled()) {
m = new WMFDecoderModule();
RefPtr<PlatformDecoderModule> remote = new dom::RemoteDecoderModule(m);
StartupPDM(remote);
diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
index 5c1b6c97b..aec1e9136 100644
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
@@ -181,8 +181,8 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample, bool* aGotFrame)
#endif
)) {
while (inputSize) {
- uint8_t* data;
- int size;
+ uint8_t* data = inputData;
+ int size = inputSize;
int len = mLib->av_parser_parse2(mCodecParser, mCodecContext, &data, &size,
inputData, inputSize,
aSample->mTime, aSample->mTimecode,
diff --git a/dom/media/platforms/wmf/WMF.h b/dom/media/platforms/wmf/WMF.h
index 5ede0d361..6988ef083 100644
--- a/dom/media/platforms/wmf/WMF.h
+++ b/dom/media/platforms/wmf/WMF.h
@@ -7,18 +7,6 @@
#ifndef WMF_H_
#define WMF_H_
-#if WINVER < _WIN32_WINNT_WIN7
-#error \
-You must include WMF.h before including mozilla headers, \
-otherwise mozconfig.h will be included \
-and that sets WINVER to WinXP, \
-which makes Windows Media Foundation unavailable.
-#endif
-
-#pragma push_macro("WINVER")
-#undef WINVER
-#define WINVER _WIN32_WINNT_WIN7
-
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
@@ -35,7 +23,7 @@ which makes Windows Media Foundation unavailable.
#include <codecapi.h>
// The Windows headers helpfully declare min and max macros, which don't
-// compile in the prescence of std::min and std::max and unified builds.
+// compile in the presence of std::min and std::max and unified builds.
// So undef them here.
#ifdef min
#undef min
@@ -97,8 +85,4 @@ HRESULT MFCreateDXGISurfaceBuffer(REFIID riid,
} // end namespace wmf
} // end namespace mozilla
-
-
-#pragma pop_macro("WINVER")
-
#endif
diff --git a/dom/media/platforms/wmf/WMFUtils.cpp b/dom/media/platforms/wmf/WMFUtils.cpp
index 8aec8a8af..055012d0f 100644
--- a/dom/media/platforms/wmf/WMFUtils.cpp
+++ b/dom/media/platforms/wmf/WMFUtils.cpp
@@ -205,31 +205,17 @@ LoadDLLs()
HRESULT
MFStartup()
{
- if (!IsVistaOrLater() || IsWin7AndPre2000Compatible()) {
- // *Only* use WMF on Vista and later, as if Firefox is run in Windows 95
- // compatibility mode on Windows 7 (it does happen!) we may crash trying
- // to startup WMF. So we need to detect the OS version here, as in
- // compatibility mode IsVistaOrLater() and friends behave as if we're on
- // the emulated version of Windows. See bug 1279171.
- // Using GetVersionEx API which takes compatibility mode into account.
- return E_FAIL;
- }
-
HRESULT hr = LoadDLLs();
if (FAILED(hr)) {
return hr;
}
- const int MF_VISTA_VERSION = (0x0001 << 16 | MF_API_VERSION);
const int MF_WIN7_VERSION = (0x0002 << 16 | MF_API_VERSION);
// decltype is unusable for functions having default parameters
DECL_FUNCTION_PTR(MFStartup, ULONG, DWORD);
ENSURE_FUNCTION_PTR_(MFStartup, Mfplat.dll)
- if (!IsWin7OrLater())
- return MFStartupPtr(MF_VISTA_VERSION, MFSTARTUP_FULL);
- else
- return MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL);
+ return MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL);
}
HRESULT
diff --git a/dom/media/systemservices/MediaParent.cpp b/dom/media/systemservices/MediaParent.cpp
index 109a44a28..89a495f6a 100644
--- a/dom/media/systemservices/MediaParent.cpp
+++ b/dom/media/systemservices/MediaParent.cpp
@@ -37,6 +37,7 @@ mozilla::LazyLogModule gMediaParentLog("MediaParent");
namespace mozilla {
namespace media {
+StaticMutex sOriginKeyStoreMutex;
static OriginKeyStore* sOriginKeyStore = nullptr;
class OriginKeyStore : public nsISupports
@@ -332,6 +333,7 @@ class OriginKeyStore : public nsISupports
private:
virtual ~OriginKeyStore()
{
+ StaticMutexAutoLock lock(sOriginKeyStoreMutex);
sOriginKeyStore = nullptr;
LOG((__FUNCTION__));
}
@@ -340,6 +342,7 @@ public:
static OriginKeyStore* Get()
{
MOZ_ASSERT(NS_IsMainThread());
+ StaticMutexAutoLock lock(sOriginKeyStoreMutex);
if (!sOriginKeyStore) {
sOriginKeyStore = new OriginKeyStore();
}
@@ -384,8 +387,8 @@ Parent<Super>::RecvGetOriginKey(const uint32_t& aRequestId,
return false;
}
- // Then over to stream-transport thread to do the actual file io.
- // Stash a pledge to hold the answer and get an id for this request.
+ // Then over to stream-transport thread (a thread pool) to do the actual
+ // file io. Stash a pledge to hold the answer and get an id for this request.
RefPtr<Pledge<nsCString>> p = new Pledge<nsCString>();
uint32_t id = mOutstandingPledges.Append(*p);
@@ -397,12 +400,17 @@ Parent<Super>::RecvGetOriginKey(const uint32_t& aRequestId,
rv = sts->Dispatch(NewRunnableFrom([this, that, id, profileDir, aOrigin,
aPrivateBrowsing, aPersist]() -> nsresult {
MOZ_ASSERT(!NS_IsMainThread());
- mOriginKeyStore->mOriginKeys.SetProfileDir(profileDir);
+ StaticMutexAutoLock lock(sOriginKeyStoreMutex);
+ if (!sOriginKeyStore) {
+ return NS_ERROR_FAILURE;
+ }
+ sOriginKeyStore->mOriginKeys.SetProfileDir(profileDir);
+
nsCString result;
if (aPrivateBrowsing) {
- mOriginKeyStore->mPrivateBrowsingOriginKeys.GetOriginKey(aOrigin, result);
+ sOriginKeyStore->mPrivateBrowsingOriginKeys.GetOriginKey(aOrigin, result);
} else {
- mOriginKeyStore->mOriginKeys.GetOriginKey(aOrigin, result, aPersist);
+ sOriginKeyStore->mOriginKeys.GetOriginKey(aOrigin, result, aPersist);
}
// Pass result back to main thread.
@@ -450,19 +458,21 @@ Parent<Super>::RecvSanitizeOriginKeys(const uint64_t& aSinceWhen,
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
- // Over to stream-transport thread to do the file io.
+ // Over to stream-transport thread (a thread pool) to do the file io.
nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(sts);
- RefPtr<OriginKeyStore> store(mOriginKeyStore);
-
- rv = sts->Dispatch(NewRunnableFrom([profileDir, store, aSinceWhen,
+ rv = sts->Dispatch(NewRunnableFrom([profileDir, aSinceWhen,
aOnlyPrivateBrowsing]() -> nsresult {
MOZ_ASSERT(!NS_IsMainThread());
- store->mPrivateBrowsingOriginKeys.Clear(aSinceWhen);
+ StaticMutexAutoLock lock(sOriginKeyStoreMutex);
+ if (!sOriginKeyStore) {
+ return NS_ERROR_FAILURE;
+ }
+ sOriginKeyStore->mPrivateBrowsingOriginKeys.Clear(aSinceWhen);
if (!aOnlyPrivateBrowsing) {
- store->mOriginKeys.SetProfileDir(profileDir);
- store->mOriginKeys.Clear(aSinceWhen);
+ sOriginKeyStore->mOriginKeys.SetProfileDir(profileDir);
+ sOriginKeyStore->mOriginKeys.Clear(aSinceWhen);
}
return NS_OK;
}), NS_DISPATCH_NORMAL);
diff --git a/dom/media/test/test_background_video_suspend.html b/dom/media/test/test_background_video_suspend.html
index e872eacf8..a5ac5cc2c 100644..100755
--- a/dom/media/test/test_background_video_suspend.html
+++ b/dom/media/test/test_background_video_suspend.html
@@ -15,7 +15,7 @@ var MIN_DELAY = 100;
function testDelay(v, start, min) {
let end = performance.now();
let delay = end - start;
- ok(delay > min, `${v.token} suspended with a delay of ${delay} ms`);
+ ok(delay >= min, `${v.token} suspended with a delay of ${delay} ms`);
}
startTest({
@@ -25,7 +25,7 @@ startTest({
[ "media.suspend-bkgnd-video.enabled", true ],
// User a short delay to ensure video decode suspend happens before end
// of video.
- [ "media.suspend-bkgnd-video.delay-ms", MIN_DELAY ]
+ [ "media.suspend-bkgnd-video.delay-ms", MIN_DELAY ],
],
tests: gDecodeSuspendTests,
runTest: (test, token) => {
diff --git a/dom/media/test/test_streams_element_capture.html b/dom/media/test/test_streams_element_capture.html
index 5e30a3ce4..a29eeef4d 100644..100755
--- a/dom/media/test/test_streams_element_capture.html
+++ b/dom/media/test/test_streams_element_capture.html
@@ -38,7 +38,8 @@ function startTest(test) {
var stream;
var checkEnded = function() {
- is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime");
+ // We know the video time won't match up to the stream time
+ // is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime");
if (test.duration) {
isGreaterThanOrEqualEps(vout.currentTime, test.duration,
test.name + " current time at end");
diff --git a/dom/media/test/test_streams_element_capture_createObjectURL.html b/dom/media/test/test_streams_element_capture_createObjectURL.html
index d5d7efc5c..d952c7142 100644..100755
--- a/dom/media/test/test_streams_element_capture_createObjectURL.html
+++ b/dom/media/test/test_streams_element_capture_createObjectURL.html
@@ -38,7 +38,8 @@ function startTest(test, token) {
var stream;
var checkEnded = function() {
- is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime");
+ // We know the video time won't match up to the stream time
+ // is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime");
if (test.duration) {
isGreaterThanOrEqualEps(vout.currentTime, test.duration,
test.name + " current time at end");
diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp
index f61226a48..85842c811 100644..100755
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -41,6 +41,7 @@
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "nsPrintfCString.h"
+#include "mozilla/TimerClamping.h"
#include "OscillatorNode.h"
#include "PannerNode.h"
#include "PeriodicWave.h"
@@ -379,10 +380,12 @@ AudioContext::CreateMediaElementSource(HTMLMediaElement& aMediaElement,
return nullptr;
}
+#ifdef MOZ_EME
if (aMediaElement.ContainsRestrictedContent()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
+#endif
if (CheckClosed(aRv)) {
return nullptr;
@@ -744,7 +747,7 @@ double
AudioContext::CurrentTime() const
{
MediaStream* stream = Destination()->Stream();
- return stream->StreamTimeToSeconds(stream->GetCurrentTime());
+ return TimerClamping::ReduceSTimeValue(stream->StreamTimeToSeconds(stream->GetCurrentTime()));
}
void
diff --git a/dom/media/webrtc/MediaEngineWebRTC.cpp b/dom/media/webrtc/MediaEngineWebRTC.cpp
index 522f23f61..1a2dc9a04 100644
--- a/dom/media/webrtc/MediaEngineWebRTC.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTC.cpp
@@ -268,11 +268,7 @@ MediaEngineWebRTC::EnumerateVideoDevices(dom::MediaSourceEnum aMediaSource,
bool
MediaEngineWebRTC::SupportsDuplex()
{
-#ifndef XP_WIN
return mFullDuplex;
-#else
- return IsVistaOrLater() && mFullDuplex;
-#endif
}
void
diff --git a/dom/performance/Performance.cpp b/dom/performance/Performance.cpp
index 17273c55d..93a6b7313 100644..100755
--- a/dom/performance/Performance.cpp
+++ b/dom/performance/Performance.cpp
@@ -13,14 +13,17 @@
#include "PerformanceMeasure.h"
#include "PerformanceObserver.h"
#include "PerformanceResourceTiming.h"
+#include "PerformanceService.h"
#include "PerformanceWorker.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/PerformanceBinding.h"
#include "mozilla/dom/PerformanceEntryEvent.h"
#include "mozilla/dom/PerformanceNavigationBinding.h"
#include "mozilla/dom/PerformanceObserverBinding.h"
+#include "mozilla/dom/PerformanceNavigationTiming.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Preferences.h"
+#include "mozilla/TimerClamping.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
@@ -37,27 +40,6 @@ using namespace workers;
namespace {
-// Helper classes
-class MOZ_STACK_CLASS PerformanceEntryComparator final
-{
-public:
- bool Equals(const PerformanceEntry* aElem1,
- const PerformanceEntry* aElem2) const
- {
- MOZ_ASSERT(aElem1 && aElem2,
- "Trying to compare null performance entries");
- return aElem1->StartTime() == aElem2->StartTime();
- }
-
- bool LessThan(const PerformanceEntry* aElem1,
- const PerformanceEntry* aElem2) const
- {
- MOZ_ASSERT(aElem1 && aElem2,
- "Trying to compare null performance entries");
- return aElem1->StartTime() < aElem2->StartTime();
- }
-};
-
class PrefEnabledRunnable final
: public WorkerCheckAPIExposureOnMainThreadRunnable
{
@@ -102,14 +84,12 @@ NS_IMPL_RELEASE_INHERITED(Performance, DOMEventTargetHelper)
/* static */ already_AddRefed<Performance>
Performance::CreateForMainThread(nsPIDOMWindowInner* aWindow,
nsDOMNavigationTiming* aDOMTiming,
- nsITimedChannel* aChannel,
- Performance* aParentPerformance)
+ nsITimedChannel* aChannel)
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<Performance> performance =
- new PerformanceMainThread(aWindow, aDOMTiming, aChannel,
- aParentPerformance);
+ new PerformanceMainThread(aWindow, aDOMTiming, aChannel);
return performance.forget();
}
@@ -141,6 +121,24 @@ Performance::Performance(nsPIDOMWindowInner* aWindow)
Performance::~Performance()
{}
+DOMHighResTimeStamp
+Performance::Now() const
+{
+ TimeDuration duration = TimeStamp::Now() - CreationTimeStamp();
+ return RoundTime(duration.ToMilliseconds());
+}
+
+DOMHighResTimeStamp
+Performance::TimeOrigin()
+{
+ if (!mPerformanceService) {
+ mPerformanceService = PerformanceService::GetOrCreate();
+ }
+
+ MOZ_ASSERT(mPerformanceService);
+ return mPerformanceService->TimeOrigin(CreationTimeStamp());
+}
+
JSObject*
Performance::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
@@ -228,9 +226,9 @@ Performance::ClearResourceTimings()
DOMHighResTimeStamp
Performance::RoundTime(double aTime) const
{
- // Round down to the nearest 20us, because if the timer is too accurate people
+ // Round down to the nearest 2ms, because if the timer is too accurate people
// can do nasty timing attacks with it.
- const double maxResolutionMs = 0.020;
+ const double maxResolutionMs = 2;
return floor(aTime / maxResolutionMs) * maxResolutionMs;
}
@@ -265,7 +263,7 @@ Performance::ClearMarks(const Optional<nsAString>& aName)
DOMHighResTimeStamp
Performance::ResolveTimestampFromName(const nsAString& aName,
- ErrorResult& aRv)
+ ErrorResult& aRv)
{
AutoTArray<RefPtr<PerformanceEntry>, 1> arr;
DOMHighResTimeStamp ts;
diff --git a/dom/performance/Performance.h b/dom/performance/Performance.h
index bc70589a5..4debecc90 100644
--- a/dom/performance/Performance.h
+++ b/dom/performance/Performance.h
@@ -24,6 +24,7 @@ namespace dom {
class PerformanceEntry;
class PerformanceNavigation;
class PerformanceObserver;
+class PerformanceService;
class PerformanceTiming;
namespace workers {
@@ -45,8 +46,7 @@ public:
static already_AddRefed<Performance>
CreateForMainThread(nsPIDOMWindowInner* aWindow,
nsDOMNavigationTiming* aDOMTiming,
- nsITimedChannel* aChannel,
- Performance* aParentPerformance);
+ nsITimedChannel* aChannel);
static already_AddRefed<Performance>
CreateForWorker(workers::WorkerPrivate* aWorkerPrivate);
@@ -54,21 +54,23 @@ public:
JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> aGivenProto) override;
- void GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval);
+ virtual void GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval);
- void GetEntriesByType(const nsAString& aEntryType,
- nsTArray<RefPtr<PerformanceEntry>>& aRetval);
+ virtual void GetEntriesByType(const nsAString& aEntryType,
+ nsTArray<RefPtr<PerformanceEntry>>& aRetval);
- void GetEntriesByName(const nsAString& aName,
- const Optional<nsAString>& aEntryType,
- nsTArray<RefPtr<PerformanceEntry>>& aRetval);
+ virtual void GetEntriesByName(const nsAString& aName,
+ const Optional<nsAString>& aEntryType,
+ nsTArray<RefPtr<PerformanceEntry>>& aRetval);
virtual void AddEntry(nsIHttpChannel* channel,
nsITimedChannel* timedChannel) = 0;
void ClearResourceTimings();
- virtual DOMHighResTimeStamp Now() const = 0;
+ DOMHighResTimeStamp Now() const;
+
+ DOMHighResTimeStamp TimeOrigin();
void Mark(const nsAString& aName, ErrorResult& aRv);
@@ -101,8 +103,6 @@ public:
virtual nsITimedChannel* GetChannel() const = 0;
- virtual Performance* GetParentPerformance() const = 0;
-
protected:
Performance();
explicit Performance(nsPIDOMWindowInner* aWindow);
@@ -126,10 +126,16 @@ protected:
virtual DOMHighResTimeStamp CreationTime() const = 0;
- virtual bool IsPerformanceTimingAttribute(const nsAString& aName) = 0;
+ virtual bool IsPerformanceTimingAttribute(const nsAString& aName)
+ {
+ return false;
+ }
virtual DOMHighResTimeStamp
- GetPerformanceTimingFromString(const nsAString& aTimingName) = 0;
+ GetPerformanceTimingFromString(const nsAString& aTimingName)
+ {
+ return 0;
+ }
bool IsResourceEntryLimitReached() const
{
@@ -147,13 +153,15 @@ protected:
nsTObserverArray<PerformanceObserver*> mObservers;
-private:
+protected:
nsTArray<RefPtr<PerformanceEntry>> mUserEntries;
nsTArray<RefPtr<PerformanceEntry>> mResourceEntries;
uint64_t mResourceTimingBufferSize;
static const uint64_t kDefaultResourceTimingBufferSize = 150;
bool mPendingNotificationObserversTask;
+
+ RefPtr<PerformanceService> mPerformanceService;
};
} // namespace dom
diff --git a/dom/performance/PerformanceEntry.h b/dom/performance/PerformanceEntry.h
index bc4f84f1c..0af9f669e 100644
--- a/dom/performance/PerformanceEntry.h
+++ b/dom/performance/PerformanceEntry.h
@@ -90,6 +90,27 @@ protected:
nsString mEntryType;
};
+// Helper classes
+class MOZ_STACK_CLASS PerformanceEntryComparator final
+{
+public:
+ bool Equals(const PerformanceEntry* aElem1,
+ const PerformanceEntry* aElem2) const
+ {
+ MOZ_ASSERT(aElem1 && aElem2,
+ "Trying to compare null performance entries");
+ return aElem1->StartTime() == aElem2->StartTime();
+ }
+
+ bool LessThan(const PerformanceEntry* aElem1,
+ const PerformanceEntry* aElem2) const
+ {
+ MOZ_ASSERT(aElem1 && aElem2,
+ "Trying to compare null performance entries");
+ return aElem1->StartTime() < aElem2->StartTime();
+ }
+};
+
} // namespace dom
} // namespace mozilla
diff --git a/dom/performance/PerformanceMainThread.cpp b/dom/performance/PerformanceMainThread.cpp
index b60b68f62..64c06d3ea 100644
--- a/dom/performance/PerformanceMainThread.cpp
+++ b/dom/performance/PerformanceMainThread.cpp
@@ -6,6 +6,7 @@
#include "PerformanceMainThread.h"
#include "PerformanceNavigation.h"
+#include "nsICacheInfoChannel.h"
namespace mozilla {
namespace dom {
@@ -16,7 +17,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PerformanceMainThread,
Performance)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTiming,
mNavigation,
- mParentPerformance)
+ mDocEntry)
tmp->mMozMemory = nullptr;
mozilla::DropJSObjects(this);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -25,7 +26,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PerformanceMainThread,
Performance)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTiming,
mNavigation,
- mParentPerformance)
+ mDocEntry)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -45,12 +46,10 @@ NS_INTERFACE_MAP_END_INHERITING(Performance)
PerformanceMainThread::PerformanceMainThread(nsPIDOMWindowInner* aWindow,
nsDOMNavigationTiming* aDOMTiming,
- nsITimedChannel* aChannel,
- Performance* aParentPerformance)
+ nsITimedChannel* aChannel)
: Performance(aWindow)
, mDOMTiming(aDOMTiming)
, mChannel(aChannel)
- , mParentPerformance(aParentPerformance)
{
MOZ_ASSERT(aWindow, "Parent window object should be provided");
}
@@ -78,7 +77,7 @@ PerformanceTiming*
PerformanceMainThread::Timing()
{
if (!mTiming) {
- // For navigation timing, the third argument (an nsIHtttpChannel) is null
+ // For navigation timing, the third argument (an nsIHttpChannel) is null
// since the cross-domain redirect were already checked. The last argument
// (zero time) for performance.timing is the navigation start value.
mTiming = new PerformanceTiming(this, mChannel, nullptr,
@@ -108,12 +107,6 @@ PerformanceMainThread::Navigation()
return mNavigation;
}
-DOMHighResTimeStamp
-PerformanceMainThread::Now() const
-{
- return RoundTime(GetDOMTiming()->TimeStampToDOMHighRes(TimeStamp::Now()));
-}
-
/**
* An entry should be added only after the resource is loaded.
* This method is not thread safe and can only be called on the main thread.
@@ -161,27 +154,7 @@ PerformanceMainThread::AddEntry(nsIHttpChannel* channel,
// The PerformanceResourceTiming object will use the PerformanceTiming
// object to get all the required timings.
RefPtr<PerformanceResourceTiming> performanceEntry =
- new PerformanceResourceTiming(performanceTiming, this, entryName);
-
- nsAutoCString protocol;
- channel->GetProtocolVersion(protocol);
- performanceEntry->SetNextHopProtocol(NS_ConvertUTF8toUTF16(protocol));
-
- uint64_t encodedBodySize = 0;
- channel->GetEncodedBodySize(&encodedBodySize);
- performanceEntry->SetEncodedBodySize(encodedBodySize);
-
- uint64_t transferSize = 0;
- channel->GetTransferSize(&transferSize);
- performanceEntry->SetTransferSize(transferSize);
-
- uint64_t decodedBodySize = 0;
- channel->GetDecodedBodySize(&decodedBodySize);
- if (decodedBodySize == 0) {
- decodedBodySize = encodedBodySize;
- }
- performanceEntry->SetDecodedBodySize(decodedBodySize);
-
+ new PerformanceResourceTiming(performanceTiming, this, entryName, channel);
// If the initiator type had no valid value, then set it to the default
// ("other") value.
if (initiatorType.IsEmpty()) {
@@ -200,7 +173,7 @@ PerformanceMainThread::IsPerformanceTimingAttribute(const nsAString& aName)
static const char* attributes[] =
{"navigationStart", "unloadEventStart", "unloadEventEnd", "redirectStart",
"redirectEnd", "fetchStart", "domainLookupStart", "domainLookupEnd",
- "connectStart", "connectEnd", "requestStart", "responseStart",
+ "connectStart", "secureConnectionStart", "connectEnd", "requestStart", "responseStart",
"responseEnd", "domLoading", "domInteractive",
"domContentLoadedEventStart", "domContentLoadedEventEnd", "domComplete",
"loadEventStart", "loadEventEnd", nullptr};
@@ -249,6 +222,9 @@ PerformanceMainThread::GetPerformanceTimingFromString(const nsAString& aProperty
if (aProperty.EqualsLiteral("connectStart")) {
return Timing()->ConnectStart();
}
+ if (aProperty.EqualsLiteral("secureConnectionStart")) {
+ return Timing()->SecureConnectionStart();
+ }
if (aProperty.EqualsLiteral("connectEnd")) {
return Timing()->ConnectEnd();
}
@@ -332,5 +308,65 @@ PerformanceMainThread::CreationTime() const
return GetDOMTiming()->GetNavigationStart();
}
+void
+PerformanceMainThread::EnsureDocEntry()
+{
+ if (!mDocEntry && nsContentUtils::IsPerformanceNavigationTimingEnabled()) {
+ nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
+ RefPtr<PerformanceTiming> timing =
+ new PerformanceTiming(this, mChannel, nullptr, 0);
+ mDocEntry = new PerformanceNavigationTiming(timing, this,
+ httpChannel);
+ }
+}
+
+
+void
+PerformanceMainThread::GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval)
+{
+ aRetval = mResourceEntries;
+ aRetval.AppendElements(mUserEntries);
+
+ EnsureDocEntry();
+ if (mDocEntry) {
+ aRetval.AppendElement(mDocEntry);
+ }
+
+ aRetval.Sort(PerformanceEntryComparator());
+}
+
+void
+PerformanceMainThread::GetEntriesByType(const nsAString& aEntryType,
+ nsTArray<RefPtr<PerformanceEntry>>& aRetval)
+{
+ if (aEntryType.EqualsLiteral("navigation")) {
+ aRetval.Clear();
+ EnsureDocEntry();
+ if (mDocEntry) {
+ aRetval.AppendElement(mDocEntry);
+ }
+ return;
+ }
+
+ Performance::GetEntriesByType(aEntryType, aRetval);
+}
+
+void
+PerformanceMainThread::GetEntriesByName(const nsAString& aName,
+ const Optional<nsAString>& aEntryType,
+ nsTArray<RefPtr<PerformanceEntry>>& aRetval)
+{
+ if (aName.EqualsLiteral("document")) {
+ aRetval.Clear();
+ EnsureDocEntry();
+ if (mDocEntry) {
+ aRetval.AppendElement(mDocEntry);
+ }
+ return;
+ }
+
+ Performance::GetEntriesByName(aName, aEntryType, aRetval);
+}
+
} // dom namespace
} // mozilla namespace
diff --git a/dom/performance/PerformanceMainThread.h b/dom/performance/PerformanceMainThread.h
index 84773f29b..9f0e185fc 100644
--- a/dom/performance/PerformanceMainThread.h
+++ b/dom/performance/PerformanceMainThread.h
@@ -17,16 +17,12 @@ class PerformanceMainThread final : public Performance
public:
PerformanceMainThread(nsPIDOMWindowInner* aWindow,
nsDOMNavigationTiming* aDOMTiming,
- nsITimedChannel* aChannel,
- Performance* aParentPerformance);
+ nsITimedChannel* aChannel);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(PerformanceMainThread,
Performance)
- // Performance WebIDL methods
- DOMHighResTimeStamp Now() const override;
-
virtual PerformanceTiming* Timing() override;
virtual PerformanceNavigation* Navigation() override;
@@ -51,10 +47,14 @@ public:
return mChannel;
}
- virtual Performance* GetParentPerformance() const override
- {
- return mParentPerformance;
- }
+ // The GetEntries* methods need to be overriden in order to add the
+ // the document entry of type navigation.
+ virtual void GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval) override;
+ virtual void GetEntriesByType(const nsAString& aEntryType,
+ nsTArray<RefPtr<PerformanceEntry>>& aRetval) override;
+ virtual void GetEntriesByName(const nsAString& aName,
+ const Optional<nsAString>& aEntryType,
+ nsTArray<RefPtr<PerformanceEntry>>& aRetval) override;
protected:
~PerformanceMainThread();
@@ -72,12 +72,13 @@ protected:
GetPerformanceTimingFromString(const nsAString& aTimingName) override;
void DispatchBufferFullEvent() override;
+ void EnsureDocEntry();
+ RefPtr<PerformanceEntry> mDocEntry;
RefPtr<nsDOMNavigationTiming> mDOMTiming;
nsCOMPtr<nsITimedChannel> mChannel;
RefPtr<PerformanceTiming> mTiming;
RefPtr<PerformanceNavigation> mNavigation;
- RefPtr<Performance> mParentPerformance;
JS::Heap<JSObject*> mMozMemory;
};
diff --git a/dom/performance/PerformanceNavigationTiming.cpp b/dom/performance/PerformanceNavigationTiming.cpp
new file mode 100644
index 000000000..4e00b2bb2
--- /dev/null
+++ b/dom/performance/PerformanceNavigationTiming.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/PerformanceNavigationTiming.h"
+#include "mozilla/dom/PerformanceNavigationTimingBinding.h"
+
+using namespace mozilla::dom;
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceNavigationTiming)
+NS_INTERFACE_MAP_END_INHERITING(PerformanceResourceTiming)
+
+NS_IMPL_ADDREF_INHERITED(PerformanceNavigationTiming, PerformanceResourceTiming)
+NS_IMPL_RELEASE_INHERITED(PerformanceNavigationTiming, PerformanceResourceTiming)
+
+JSObject*
+PerformanceNavigationTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return PerformanceNavigationTimingBinding::Wrap(aCx, this, aGivenProto);
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::UnloadEventStart() const
+{
+ return mTiming->GetDOMTiming()->GetUnloadEventStartHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::UnloadEventEnd() const
+{
+ return mTiming->GetDOMTiming()->GetUnloadEventEndHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::DomInteractive() const
+{
+ return mTiming->GetDOMTiming()->GetDomInteractiveHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::DomContentLoadedEventStart() const
+{
+ return mTiming->GetDOMTiming()->GetDomContentLoadedEventStartHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::DomContentLoadedEventEnd() const
+{
+ return mTiming->GetDOMTiming()->GetDomContentLoadedEventEndHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::DomComplete() const
+{
+ return mTiming->GetDOMTiming()->GetDomCompleteHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::LoadEventStart() const
+{
+ return mTiming->GetDOMTiming()->GetLoadEventStartHighRes();
+}
+
+DOMHighResTimeStamp
+PerformanceNavigationTiming::LoadEventEnd() const
+{
+ return mTiming->GetDOMTiming()->GetLoadEventEndHighRes();
+}
+
+NavigationType
+PerformanceNavigationTiming::Type() const
+{
+ switch(mTiming->GetDOMTiming()->GetType()) {
+ case nsDOMNavigationTiming::TYPE_NAVIGATE:
+ return NavigationType::Navigate;
+ break;
+ case nsDOMNavigationTiming::TYPE_RELOAD:
+ return NavigationType::Reload;
+ break;
+ case nsDOMNavigationTiming::TYPE_BACK_FORWARD:
+ return NavigationType::Back_forward;
+ break;
+ default:
+ // The type is TYPE_RESERVED or some other value that was later added.
+ // We fallback to the default of Navigate.
+ return NavigationType::Navigate;
+ }
+}
+
+uint16_t
+PerformanceNavigationTiming::RedirectCount() const
+{
+ return mTiming->GetRedirectCount();
+}
diff --git a/dom/performance/PerformanceNavigationTiming.h b/dom/performance/PerformanceNavigationTiming.h
new file mode 100644
index 000000000..8555f1987
--- /dev/null
+++ b/dom/performance/PerformanceNavigationTiming.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PerformanceNavigationTiming_h___
+#define mozilla_dom_PerformanceNavigationTiming_h___
+
+#include "nsCOMPtr.h"
+#include "nsIChannel.h"
+#include "nsITimedChannel.h"
+#include "mozilla/dom/PerformanceResourceTiming.h"
+#include "mozilla/dom/PerformanceNavigationTimingBinding.h"
+#include "nsIHttpChannel.h"
+
+namespace mozilla {
+namespace dom {
+
+// https://www.w3.org/TR/navigation-timing-2/#sec-PerformanceNavigationTiming
+class PerformanceNavigationTiming final
+ : public PerformanceResourceTiming
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+
+ // Note that aPerformanceTiming must be initalized with zeroTime = 0
+ // so that timestamps are relative to startTime, as opposed to the
+ // performance.timing object for which timestamps are absolute and has a
+ // zeroTime initialized to navigationStart
+ explicit PerformanceNavigationTiming(PerformanceTiming* aPerformanceTiming,
+ Performance* aPerformance,
+ nsIHttpChannel* aChannel)
+ : PerformanceResourceTiming(aPerformanceTiming, aPerformance,
+ NS_LITERAL_STRING("document"), aChannel) {
+ SetEntryType(NS_LITERAL_STRING("navigation"));
+ SetInitiatorType(NS_LITERAL_STRING("navigation"));
+ }
+
+ DOMHighResTimeStamp Duration() const override
+ {
+ return LoadEventEnd() - StartTime();
+ }
+
+ DOMHighResTimeStamp StartTime() const override
+ {
+ return 0;
+ }
+
+ JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+ DOMHighResTimeStamp UnloadEventStart() const;
+ DOMHighResTimeStamp UnloadEventEnd() const;
+
+ DOMHighResTimeStamp DomInteractive() const;
+ DOMHighResTimeStamp DomContentLoadedEventStart() const;
+ DOMHighResTimeStamp DomContentLoadedEventEnd() const;
+ DOMHighResTimeStamp DomComplete() const;
+ DOMHighResTimeStamp LoadEventStart() const;
+ DOMHighResTimeStamp LoadEventEnd() const;
+ NavigationType Type() const;
+ uint16_t RedirectCount() const;
+
+private:
+ ~PerformanceNavigationTiming() {}
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PerformanceNavigationTiming_h___
diff --git a/dom/performance/PerformanceObserver.cpp b/dom/performance/PerformanceObserver.cpp
index 11dd30ac2..d02acfb09 100644
--- a/dom/performance/PerformanceObserver.cpp
+++ b/dom/performance/PerformanceObserver.cpp
@@ -114,12 +114,13 @@ PerformanceObserver::Notify()
RefPtr<PerformanceObserverEntryList> list =
new PerformanceObserverEntryList(this, mQueuedEntries);
+ mQueuedEntries.Clear();
+
ErrorResult rv;
mCallback->Call(this, *list, *this, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
}
- mQueuedEntries.Clear();
}
void
@@ -170,6 +171,17 @@ PerformanceObserver::Observe(const PerformanceObserverInit& aOptions,
mEntryTypes.SwapElements(validEntryTypes);
mPerformance->AddObserver(this);
+
+ if (aOptions.mBuffered) {
+ for (auto entryType : mEntryTypes) {
+ nsTArray<RefPtr<PerformanceEntry>> existingEntries;
+ mPerformance->GetEntriesByType(entryType, existingEntries);
+ if (!existingEntries.IsEmpty()) {
+ mQueuedEntries.AppendElements(existingEntries);
+ }
+ }
+ }
+
mConnected = true;
}
diff --git a/dom/performance/PerformanceObserverEntryList.cpp b/dom/performance/PerformanceObserverEntryList.cpp
index 349103f08..20e818f3d 100644
--- a/dom/performance/PerformanceObserverEntryList.cpp
+++ b/dom/performance/PerformanceObserverEntryList.cpp
@@ -66,6 +66,7 @@ PerformanceObserverEntryList::GetEntries(
aRetval.AppendElement(entry);
}
+ aRetval.Sort(PerformanceEntryComparator());
}
void
@@ -79,6 +80,7 @@ PerformanceObserverEntryList::GetEntriesByType(
aRetval.AppendElement(entry);
}
}
+ aRetval.Sort(PerformanceEntryComparator());
}
void
@@ -88,9 +90,18 @@ PerformanceObserverEntryList::GetEntriesByName(
nsTArray<RefPtr<PerformanceEntry>>& aRetval)
{
aRetval.Clear();
+ const bool typePassed = aEntryType.WasPassed();
for (const RefPtr<PerformanceEntry>& entry : mEntries) {
- if (entry->GetName().Equals(aName)) {
- aRetval.AppendElement(entry);
+ if (!entry->GetName().Equals(aName)) {
+ continue;
}
+
+ if (typePassed &&
+ !entry->GetEntryType().Equals(aEntryType.Value())) {
+ continue;
+ }
+
+ aRetval.AppendElement(entry);
}
+ aRetval.Sort(PerformanceEntryComparator());
}
diff --git a/dom/performance/PerformanceResourceTiming.cpp b/dom/performance/PerformanceResourceTiming.cpp
index 60a20ca28..2eaa4eb9a 100644
--- a/dom/performance/PerformanceResourceTiming.cpp
+++ b/dom/performance/PerformanceResourceTiming.cpp
@@ -25,7 +25,8 @@ NS_IMPL_RELEASE_INHERITED(PerformanceResourceTiming, PerformanceEntry)
PerformanceResourceTiming::PerformanceResourceTiming(PerformanceTiming* aPerformanceTiming,
Performance* aPerformance,
- const nsAString& aName)
+ const nsAString& aName,
+ nsIHttpChannel* aChannel)
: PerformanceEntry(aPerformance, aName, NS_LITERAL_STRING("resource")),
mTiming(aPerformanceTiming),
mEncodedBodySize(0),
@@ -33,6 +34,34 @@ PerformanceResourceTiming::PerformanceResourceTiming(PerformanceTiming* aPerform
mDecodedBodySize(0)
{
MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
+ SetPropertiesFromChannel(aChannel);
+}
+
+void
+PerformanceResourceTiming::SetPropertiesFromChannel(nsIHttpChannel* aChannel)
+{
+ if (!aChannel) {
+ return;
+ }
+
+ nsAutoCString protocol;
+ Unused << aChannel->GetProtocolVersion(protocol);
+ SetNextHopProtocol(NS_ConvertUTF8toUTF16(protocol));
+
+ uint64_t encodedBodySize = 0;
+ Unused << aChannel->GetEncodedBodySize(&encodedBodySize);
+ SetEncodedBodySize(encodedBodySize);
+
+ uint64_t transferSize = 0;
+ Unused << aChannel->GetTransferSize(&transferSize);
+ SetTransferSize(transferSize);
+
+ uint64_t decodedBodySize = 0;
+ Unused << aChannel->GetDecodedBodySize(&decodedBodySize);
+ if (decodedBodySize == 0) {
+ decodedBodySize = encodedBodySize;
+ }
+ SetDecodedBodySize(decodedBodySize);
}
PerformanceResourceTiming::~PerformanceResourceTiming()
@@ -42,8 +71,22 @@ PerformanceResourceTiming::~PerformanceResourceTiming()
DOMHighResTimeStamp
PerformanceResourceTiming::StartTime() const
{
- DOMHighResTimeStamp startTime = mTiming->RedirectStartHighRes();
- return startTime ? startTime : mTiming->FetchStartHighRes();
+ // Force the start time to be the earliest of:
+ // - RedirectStart
+ // - WorkerStart
+ // - AsyncOpen
+ // Ignore zero values. The RedirectStart and WorkerStart values
+ // can come from earlier redirected channels prior to the AsyncOpen
+ // time being recorded.
+ DOMHighResTimeStamp redirect = mTiming->RedirectStartHighRes();
+ redirect = redirect ? redirect : DBL_MAX;
+
+ DOMHighResTimeStamp worker = mTiming->WorkerStartHighRes();
+ worker = worker ? worker : DBL_MAX;
+
+ DOMHighResTimeStamp asyncOpen = mTiming->AsyncOpenHighRes();
+
+ return std::min(asyncOpen, std::min(redirect, worker));
}
JSObject*
diff --git a/dom/performance/PerformanceResourceTiming.h b/dom/performance/PerformanceResourceTiming.h
index abb653d66..98a03327e 100644
--- a/dom/performance/PerformanceResourceTiming.h
+++ b/dom/performance/PerformanceResourceTiming.h
@@ -18,7 +18,7 @@ namespace mozilla {
namespace dom {
// http://www.w3.org/TR/resource-timing/#performanceresourcetiming
-class PerformanceResourceTiming final : public PerformanceEntry
+class PerformanceResourceTiming : public PerformanceEntry
{
public:
typedef mozilla::TimeStamp TimeStamp;
@@ -30,7 +30,8 @@ public:
PerformanceResourceTiming(PerformanceTiming* aPerformanceTiming,
Performance* aPerformance,
- const nsAString& aName);
+ const nsAString& aName,
+ nsIHttpChannel* aChannel = nullptr);
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -62,6 +63,12 @@ public:
mNextHopProtocol = aNextHopProtocol;
}
+ DOMHighResTimeStamp WorkerStart() const {
+ return mTiming && mTiming->TimingAllowed()
+ ? mTiming->WorkerStartHighRes()
+ : 0;
+ }
+
DOMHighResTimeStamp FetchStart() const {
return mTiming
? mTiming->FetchStartHighRes()
@@ -128,9 +135,9 @@ public:
DOMHighResTimeStamp SecureConnectionStart() const
{
- // This measurement is not available for Navigation Timing either.
- // There is a different bug submitted for it.
- return 0;
+ return mTiming && mTiming->TimingAllowed()
+ ? mTiming->SecureConnectionStartHighRes()
+ : 0;
}
virtual const PerformanceResourceTiming* ToResourceTiming() const override
@@ -170,6 +177,7 @@ public:
protected:
virtual ~PerformanceResourceTiming();
+ void SetPropertiesFromChannel(nsIHttpChannel* aChannel);
nsString mInitiatorType;
nsString mNextHopProtocol;
diff --git a/dom/performance/PerformanceService.cpp b/dom/performance/PerformanceService.cpp
new file mode 100644
index 000000000..cf119af89
--- /dev/null
+++ b/dom/performance/PerformanceService.cpp
@@ -0,0 +1,46 @@
+/* -*- 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 "PerformanceService.h"
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/StaticPtr.h"
+
+namespace mozilla {
+namespace dom {
+
+static StaticRefPtr<PerformanceService> gPerformanceService;
+static StaticMutex gPerformanceServiceMutex;
+
+/* static */ PerformanceService*
+PerformanceService::GetOrCreate()
+{
+ StaticMutexAutoLock al(gPerformanceServiceMutex);
+
+ if (!gPerformanceService) {
+ gPerformanceService = new PerformanceService();
+ ClearOnShutdown(&gPerformanceService);
+ }
+
+ return gPerformanceService;
+}
+
+DOMHighResTimeStamp
+PerformanceService::TimeOrigin(const TimeStamp& aCreationTimeStamp) const
+{
+ return (aCreationTimeStamp - mCreationTimeStamp).ToMilliseconds() +
+ (mCreationEpochTime / PR_USEC_PER_MSEC);
+}
+
+PerformanceService::PerformanceService()
+{
+ mCreationTimeStamp = TimeStamp::Now();
+ mCreationEpochTime = PR_Now();
+}
+
+} // dom namespace
+} // mozilla namespace
diff --git a/dom/performance/PerformanceService.h b/dom/performance/PerformanceService.h
new file mode 100644
index 000000000..9abbd674d
--- /dev/null
+++ b/dom/performance/PerformanceService.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef dom_performance_PerformanceService_h
+#define dom_performance_PerformanceService_h
+
+#include "mozilla/TimeStamp.h"
+#include "nsCOMPtr.h"
+#include "nsDOMNavigationTiming.h"
+
+namespace mozilla {
+namespace dom {
+
+// This class is thread-safe.
+
+// We use this singleton for having the correct value of performance.timeOrigin.
+// This value must be calculated on top of the pair:
+// - mCreationTimeStamp (monotonic clock)
+// - mCreationEpochTime (unix epoch time)
+// These 2 values must be taken "at the same time" in order to be used
+// correctly.
+
+class PerformanceService
+{
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PerformanceService)
+
+ static PerformanceService*
+ GetOrCreate();
+
+ DOMHighResTimeStamp
+ TimeOrigin(const TimeStamp& aCreationTimeStamp) const;
+
+private:
+ PerformanceService();
+ ~PerformanceService() = default;
+
+ TimeStamp mCreationTimeStamp;
+ PRTime mCreationEpochTime;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // dom_performance_PerformanceService_h
diff --git a/dom/performance/PerformanceTiming.cpp b/dom/performance/PerformanceTiming.cpp
index 527cf9441..887a23938 100644..100755
--- a/dom/performance/PerformanceTiming.cpp
+++ b/dom/performance/PerformanceTiming.cpp
@@ -21,7 +21,7 @@ PerformanceTiming::PerformanceTiming(Performance* aPerformance,
DOMHighResTimeStamp aZeroTime)
: mPerformance(aPerformance),
mFetchStart(0.0),
- mZeroTime(aZeroTime),
+ mZeroTime(TimerClamping::ReduceMsTimeValue(aZeroTime)),
mRedirectCount(0),
mTimingAllowed(true),
mAllRedirectsSameOrigin(true),
@@ -46,6 +46,23 @@ PerformanceTiming::PerformanceTiming(Performance* aPerformance,
mReportCrossOriginRedirect = mTimingAllowed && redirectsPassCheck;
}
+ mSecureConnection = false;
+ nsCOMPtr<nsIURI> uri;
+ if (aHttpChannel) {
+ aHttpChannel->GetURI(getter_AddRefs(uri));
+ } else {
+ nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
+ if (httpChannel) {
+ httpChannel->GetURI(getter_AddRefs(uri));
+ }
+ }
+
+ if (uri) {
+ nsresult rv = uri->SchemeIs("https", &mSecureConnection);
+ if (NS_FAILED(rv)) {
+ mSecureConnection = false;
+ }
+ }
InitializeTimingInfo(aChannel);
}
@@ -56,6 +73,7 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
{
if (aChannel) {
aChannel->GetAsyncOpen(&mAsyncOpen);
+ aChannel->GetDispatchFetchEventStart(&mWorkerStart);
aChannel->GetAllRedirectsSameOrigin(&mAllRedirectsSameOrigin);
aChannel->GetRedirectCount(&mRedirectCount);
aChannel->GetRedirectStart(&mRedirectStart);
@@ -63,12 +81,49 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
aChannel->GetDomainLookupStart(&mDomainLookupStart);
aChannel->GetDomainLookupEnd(&mDomainLookupEnd);
aChannel->GetConnectStart(&mConnectStart);
+ aChannel->GetSecureConnectionStart(&mSecureConnectionStart);
aChannel->GetConnectEnd(&mConnectEnd);
aChannel->GetRequestStart(&mRequestStart);
aChannel->GetResponseStart(&mResponseStart);
aChannel->GetCacheReadStart(&mCacheReadStart);
aChannel->GetResponseEnd(&mResponseEnd);
aChannel->GetCacheReadEnd(&mCacheReadEnd);
+
+ // The performance timing api essentially requires that the event timestamps
+ // have a strict relation with each other. The truth, however, is the browser
+ // engages in a number of speculative activities that sometimes mean connections
+ // and lookups begin at different times. Workaround that here by clamping
+ // these values to what we expect FetchStart to be. This means the later of
+ // AsyncOpen or WorkerStart times.
+ if (!mAsyncOpen.IsNull()) {
+ // We want to clamp to the expected FetchStart value. This is later of
+ // the AsyncOpen and WorkerStart values.
+ const TimeStamp* clampTime = &mAsyncOpen;
+ if (!mWorkerStart.IsNull() && mWorkerStart > mAsyncOpen) {
+ clampTime = &mWorkerStart;
+ }
+
+ if (!mDomainLookupStart.IsNull() && mDomainLookupStart < *clampTime) {
+ mDomainLookupStart = *clampTime;
+ }
+
+ if (!mDomainLookupEnd.IsNull() && mDomainLookupEnd < *clampTime) {
+ mDomainLookupEnd = *clampTime;
+ }
+
+ if (!mConnectStart.IsNull() && mConnectStart < *clampTime) {
+ mConnectStart = *clampTime;
+ }
+
+ if (mSecureConnection && !mSecureConnectionStart.IsNull() &&
+ mSecureConnectionStart < *clampTime) {
+ mSecureConnectionStart = *clampTime;
+ }
+
+ if (!mConnectEnd.IsNull() && mConnectEnd < *clampTime) {
+ mConnectEnd = *clampTime;
+ }
+ }
}
}
@@ -85,11 +140,15 @@ PerformanceTiming::FetchStartHighRes()
}
MOZ_ASSERT(!mAsyncOpen.IsNull(), "The fetch start time stamp should always be "
"valid if the performance timing is enabled");
- mFetchStart = (!mAsyncOpen.IsNull())
- ? TimeStampToDOMHighRes(mAsyncOpen)
- : 0.0;
+ if (!mAsyncOpen.IsNull()) {
+ if (!mWorkerStart.IsNull() && mWorkerStart > mAsyncOpen) {
+ mFetchStart = TimeStampToDOMHighRes(mWorkerStart);
+ } else {
+ mFetchStart = TimeStampToDOMHighRes(mAsyncOpen);
+ }
+ }
}
- return mFetchStart;
+ return TimerClamping::ReduceMsTimeValue(mFetchStart);
}
DOMTimeMilliSec
@@ -134,7 +193,7 @@ PerformanceTiming::TimingAllowed() const
return mTimingAllowed;
}
-uint16_t
+uint8_t
PerformanceTiming::GetRedirectCount() const
{
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
@@ -159,6 +218,26 @@ PerformanceTiming::ShouldReportCrossOriginRedirect() const
return (mRedirectCount != 0) && mReportCrossOriginRedirect;
}
+DOMHighResTimeStamp
+PerformanceTiming::AsyncOpenHighRes()
+{
+ if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
+ mAsyncOpen.IsNull()) {
+ return mZeroTime;
+ }
+ return TimeStampToReducedDOMHighResOrFetchStart(mAsyncOpen);
+}
+
+DOMHighResTimeStamp
+PerformanceTiming::WorkerStartHighRes()
+{
+ if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
+ mWorkerStart.IsNull()) {
+ return mZeroTime;
+ }
+ return TimeStampToReducedDOMHighResOrFetchStart(mWorkerStart);
+}
+
/**
* RedirectStartHighRes() is used by both the navigation timing and the
* resource timing. Since, navigation timing and resource timing check and
@@ -175,7 +254,7 @@ PerformanceTiming::RedirectStartHighRes()
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
return mZeroTime;
}
- return TimeStampToDOMHighResOrFetchStart(mRedirectStart);
+ return TimeStampToReducedDOMHighResOrFetchStart(mRedirectStart);
}
DOMTimeMilliSec
@@ -208,7 +287,7 @@ PerformanceTiming::RedirectEndHighRes()
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
return mZeroTime;
}
- return TimeStampToDOMHighResOrFetchStart(mRedirectEnd);
+ return TimeStampToReducedDOMHighResOrFetchStart(mRedirectEnd);
}
DOMTimeMilliSec
@@ -231,7 +310,7 @@ PerformanceTiming::DomainLookupStartHighRes()
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
return mZeroTime;
}
- return TimeStampToDOMHighResOrFetchStart(mDomainLookupStart);
+ return TimeStampToReducedDOMHighResOrFetchStart(mDomainLookupStart);
}
DOMTimeMilliSec
@@ -248,7 +327,7 @@ PerformanceTiming::DomainLookupEndHighRes()
}
// Bug 1155008 - nsHttpTransaction is racy. Return DomainLookupStart when null
return mDomainLookupEnd.IsNull() ? DomainLookupStartHighRes()
- : TimeStampToDOMHighRes(mDomainLookupEnd);
+ : TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(mDomainLookupEnd));
}
DOMTimeMilliSec
@@ -264,7 +343,7 @@ PerformanceTiming::ConnectStartHighRes()
return mZeroTime;
}
return mConnectStart.IsNull() ? DomainLookupEndHighRes()
- : TimeStampToDOMHighRes(mConnectStart);
+ : TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(mConnectStart));
}
DOMTimeMilliSec
@@ -274,6 +353,25 @@ PerformanceTiming::ConnectStart()
}
DOMHighResTimeStamp
+PerformanceTiming::SecureConnectionStartHighRes()
+{
+ if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
+ return mZeroTime;
+ }
+ return !mSecureConnection
+ ? 0 // We use 0 here, because mZeroTime is sometimes set to the navigation
+ // start time.
+ : (mSecureConnectionStart.IsNull() ? mZeroTime
+ : TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(mSecureConnectionStart)));
+}
+
+DOMTimeMilliSec
+PerformanceTiming::SecureConnectionStart()
+{
+ return static_cast<int64_t>(SecureConnectionStartHighRes());
+}
+
+DOMHighResTimeStamp
PerformanceTiming::ConnectEndHighRes()
{
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
@@ -281,7 +379,7 @@ PerformanceTiming::ConnectEndHighRes()
}
// Bug 1155008 - nsHttpTransaction is racy. Return ConnectStart when null
return mConnectEnd.IsNull() ? ConnectStartHighRes()
- : TimeStampToDOMHighRes(mConnectEnd);
+ : TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(mConnectEnd));
}
DOMTimeMilliSec
@@ -296,7 +394,7 @@ PerformanceTiming::RequestStartHighRes()
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
return mZeroTime;
}
- return TimeStampToDOMHighResOrFetchStart(mRequestStart);
+ return TimeStampToReducedDOMHighResOrFetchStart(mRequestStart);
}
DOMTimeMilliSec
@@ -315,7 +413,7 @@ PerformanceTiming::ResponseStartHighRes()
(!mCacheReadStart.IsNull() && mCacheReadStart < mResponseStart)) {
mResponseStart = mCacheReadStart;
}
- return TimeStampToDOMHighResOrFetchStart(mResponseStart);
+ return TimeStampToReducedDOMHighResOrFetchStart(mResponseStart);
}
DOMTimeMilliSec
@@ -336,7 +434,7 @@ PerformanceTiming::ResponseEndHighRes()
}
// Bug 1155008 - nsHttpTransaction is racy. Return ResponseStart when null
return mResponseEnd.IsNull() ? ResponseStartHighRes()
- : TimeStampToDOMHighRes(mResponseEnd);
+ : TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(mResponseEnd));
}
DOMTimeMilliSec
diff --git a/dom/performance/PerformanceTiming.h b/dom/performance/PerformanceTiming.h
index aef54a258..435e1bca1 100644..100755
--- a/dom/performance/PerformanceTiming.h
+++ b/dom/performance/PerformanceTiming.h
@@ -10,6 +10,7 @@
#include "mozilla/Attributes.h"
#include "nsContentUtils.h"
#include "nsDOMNavigationTiming.h"
+#include "mozilla/TimerClamping.h"
#include "nsWrapperCache.h"
#include "Performance.h"
@@ -68,10 +69,10 @@ public:
* page), if the given TimeStamp is valid. Otherwise, it will return
* the FetchStart timing value.
*/
- inline DOMHighResTimeStamp TimeStampToDOMHighResOrFetchStart(TimeStamp aStamp)
+ inline DOMHighResTimeStamp TimeStampToReducedDOMHighResOrFetchStart(TimeStamp aStamp)
{
return (!aStamp.IsNull())
- ? TimeStampToDOMHighRes(aStamp)
+ ? TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(aStamp))
: FetchStartHighRes();
}
@@ -119,7 +120,7 @@ public:
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
return 0;
}
- return GetDOMTiming()->GetNavigationStart();
+ return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetNavigationStart());
}
DOMTimeMilliSec UnloadEventStart()
@@ -127,7 +128,7 @@ public:
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
return 0;
}
- return GetDOMTiming()->GetUnloadEventStart();
+ return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetUnloadEventStart());
}
DOMTimeMilliSec UnloadEventEnd()
@@ -135,10 +136,10 @@ public:
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
return 0;
}
- return GetDOMTiming()->GetUnloadEventEnd();
+ return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetUnloadEventEnd());
}
- uint16_t GetRedirectCount() const;
+ uint8_t GetRedirectCount() const;
// Checks if the resource is either same origin as the page that started
// the load, or if the response contains the Timing-Allow-Origin header
@@ -154,13 +155,19 @@ public:
// the timing-allow-origin check in HttpBaseChannel::TimingAllowCheck
bool ShouldReportCrossOriginRedirect() const;
+ // The last channel's AsyncOpen time. This may occur before the FetchStart
+ // in some cases.
+ DOMHighResTimeStamp AsyncOpenHighRes();
+
// High resolution (used by resource timing)
+ DOMHighResTimeStamp WorkerStartHighRes();
DOMHighResTimeStamp FetchStartHighRes();
DOMHighResTimeStamp RedirectStartHighRes();
DOMHighResTimeStamp RedirectEndHighRes();
DOMHighResTimeStamp DomainLookupStartHighRes();
DOMHighResTimeStamp DomainLookupEndHighRes();
DOMHighResTimeStamp ConnectStartHighRes();
+ DOMHighResTimeStamp SecureConnectionStartHighRes();
DOMHighResTimeStamp ConnectEndHighRes();
DOMHighResTimeStamp RequestStartHighRes();
DOMHighResTimeStamp ResponseStartHighRes();
@@ -173,6 +180,7 @@ public:
DOMTimeMilliSec DomainLookupStart();
DOMTimeMilliSec DomainLookupEnd();
DOMTimeMilliSec ConnectStart();
+ DOMTimeMilliSec SecureConnectionStart();
DOMTimeMilliSec ConnectEnd();
DOMTimeMilliSec RequestStart();
DOMTimeMilliSec ResponseStart();
@@ -183,7 +191,7 @@ public:
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
return 0;
}
- return GetDOMTiming()->GetDomLoading();
+ return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetDomLoading());
}
DOMTimeMilliSec DomInteractive() const
@@ -191,7 +199,7 @@ public:
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
return 0;
}
- return GetDOMTiming()->GetDomInteractive();
+ return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetDomInteractive());
}
DOMTimeMilliSec DomContentLoadedEventStart() const
@@ -199,7 +207,7 @@ public:
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
return 0;
}
- return GetDOMTiming()->GetDomContentLoadedEventStart();
+ return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetDomContentLoadedEventStart());
}
DOMTimeMilliSec DomContentLoadedEventEnd() const
@@ -207,7 +215,7 @@ public:
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
return 0;
}
- return GetDOMTiming()->GetDomContentLoadedEventEnd();
+ return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetDomContentLoadedEventEnd());
}
DOMTimeMilliSec DomComplete() const
@@ -215,7 +223,7 @@ public:
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
return 0;
}
- return GetDOMTiming()->GetDomComplete();
+ return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetDomComplete());
}
DOMTimeMilliSec LoadEventStart() const
@@ -223,7 +231,7 @@ public:
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
return 0;
}
- return GetDOMTiming()->GetLoadEventStart();
+ return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetLoadEventStart());
}
DOMTimeMilliSec LoadEventEnd() const
@@ -231,7 +239,15 @@ public:
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
return 0;
}
- return GetDOMTiming()->GetLoadEventEnd();
+ return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetLoadEventEnd());
+ }
+
+ DOMTimeMilliSec TimeToNonBlankPaint() const
+ {
+ if (!nsContentUtils::IsPerformanceTimingEnabled()) {
+ return 0;
+ }
+ return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetTimeToNonBlankPaint());
}
private:
@@ -250,18 +266,20 @@ private:
DOMHighResTimeStamp mZeroTime;
TimeStamp mAsyncOpen;
+ TimeStamp mWorkerStart;
TimeStamp mRedirectStart;
TimeStamp mRedirectEnd;
TimeStamp mDomainLookupStart;
TimeStamp mDomainLookupEnd;
TimeStamp mConnectStart;
+ TimeStamp mSecureConnectionStart;
TimeStamp mConnectEnd;
TimeStamp mRequestStart;
TimeStamp mResponseStart;
TimeStamp mCacheReadStart;
TimeStamp mResponseEnd;
TimeStamp mCacheReadEnd;
- uint16_t mRedirectCount;
+ uint8_t mRedirectCount;
bool mTimingAllowed;
bool mAllRedirectsSameOrigin;
bool mInitialized;
@@ -270,6 +288,8 @@ private:
// redirectEnd attributes. It is false if there were no redirects, or if
// any of the responses didn't pass the timing-allow-check
bool mReportCrossOriginRedirect;
+
+ bool mSecureConnection;
};
} // namespace dom
diff --git a/dom/performance/PerformanceWorker.cpp b/dom/performance/PerformanceWorker.cpp
index 85ca2ccd8..f10c58446 100644
--- a/dom/performance/PerformanceWorker.cpp
+++ b/dom/performance/PerformanceWorker.cpp
@@ -23,37 +23,6 @@ PerformanceWorker::~PerformanceWorker()
mWorkerPrivate->AssertIsOnWorkerThread();
}
-DOMHighResTimeStamp
-PerformanceWorker::Now() const
-{
- TimeDuration duration =
- TimeStamp::Now() - mWorkerPrivate->NowBaseTimeStamp();
- return RoundTime(duration.ToMilliseconds());
-}
-
-// To be removed once bug 1124165 lands
-bool
-PerformanceWorker::IsPerformanceTimingAttribute(const nsAString& aName)
-{
- // In workers we just support navigationStart.
- return aName.EqualsASCII("navigationStart");
-}
-
-DOMHighResTimeStamp
-PerformanceWorker::GetPerformanceTimingFromString(const nsAString& aProperty)
-{
- if (!IsPerformanceTimingAttribute(aProperty)) {
- return 0;
- }
-
- if (aProperty.EqualsLiteral("navigationStart")) {
- return mWorkerPrivate->NowBaseTime();
- }
-
- MOZ_CRASH("IsPerformanceTimingAttribute and GetPerformanceTimingFromString are out of sync");
- return 0;
-}
-
void
PerformanceWorker::InsertUserEntry(PerformanceEntry* aEntry)
{
@@ -72,13 +41,13 @@ PerformanceWorker::InsertUserEntry(PerformanceEntry* aEntry)
TimeStamp
PerformanceWorker::CreationTimeStamp() const
{
- return mWorkerPrivate->NowBaseTimeStamp();
+ return mWorkerPrivate->CreationTimeStamp();
}
DOMHighResTimeStamp
PerformanceWorker::CreationTime() const
{
- return mWorkerPrivate->NowBaseTime();
+ return mWorkerPrivate->CreationTime();
}
} // dom namespace
diff --git a/dom/performance/PerformanceWorker.h b/dom/performance/PerformanceWorker.h
index 7eef0d974..346bdd026 100644
--- a/dom/performance/PerformanceWorker.h
+++ b/dom/performance/PerformanceWorker.h
@@ -21,9 +21,6 @@ class PerformanceWorker final : public Performance
public:
explicit PerformanceWorker(workers::WorkerPrivate* aWorkerPrivate);
- // Performance WebIDL methods
- DOMHighResTimeStamp Now() const override;
-
virtual PerformanceTiming* Timing() override
{
MOZ_CRASH("This should not be called on workers.");
@@ -64,12 +61,6 @@ public:
return nullptr;
}
- virtual Performance* GetParentPerformance() const override
- {
- MOZ_CRASH("This should not be called on workers.");
- return nullptr;
- }
-
protected:
~PerformanceWorker();
@@ -80,11 +71,6 @@ protected:
void InsertUserEntry(PerformanceEntry* aEntry) override;
- bool IsPerformanceTimingAttribute(const nsAString& aName) override;
-
- DOMHighResTimeStamp
- GetPerformanceTimingFromString(const nsAString& aTimingName) override;
-
void DispatchBufferFullEvent() override
{
MOZ_CRASH("This should not be called on workers.");
diff --git a/dom/performance/moz.build b/dom/performance/moz.build
index 3286a0a4c..e1f96fec8 100644
--- a/dom/performance/moz.build
+++ b/dom/performance/moz.build
@@ -10,9 +10,11 @@ EXPORTS.mozilla.dom += [
'PerformanceMark.h',
'PerformanceMeasure.h',
'PerformanceNavigation.h',
+ 'PerformanceNavigationTiming.h',
'PerformanceObserver.h',
'PerformanceObserverEntryList.h',
'PerformanceResourceTiming.h',
+ 'PerformanceService.h',
'PerformanceTiming.h',
]
@@ -23,9 +25,11 @@ UNIFIED_SOURCES += [
'PerformanceMark.cpp',
'PerformanceMeasure.cpp',
'PerformanceNavigation.cpp',
+ 'PerformanceNavigationTiming.cpp',
'PerformanceObserver.cpp',
'PerformanceObserverEntryList.cpp',
'PerformanceResourceTiming.cpp',
+ 'PerformanceService.cpp',
'PerformanceTiming.cpp',
'PerformanceWorker.cpp',
]
diff --git a/dom/performance/tests/mochitest.ini b/dom/performance/tests/mochitest.ini
index 18f7f0e45..bee0b2e70 100644
--- a/dom/performance/tests/mochitest.ini
+++ b/dom/performance/tests/mochitest.ini
@@ -1,13 +1,11 @@
[DEFAULT]
support-files =
- performance_observer.html
test_performance_observer.js
test_performance_user_timing.js
test_worker_performance_now.js
worker_performance_user_timing.js
worker_performance_observer.js
sharedworker_performance_user_timing.js
- worker_performance_observer.html
[test_performance_observer.html]
[test_performance_user_timing.html]
@@ -15,3 +13,4 @@ support-files =
[test_worker_observer.html]
[test_sharedWorker_performance_user_timing.html]
[test_worker_performance_now.html]
+[test_timeOrigin.html]
diff --git a/dom/performance/tests/performance_observer.html b/dom/performance/tests/performance_observer.html
deleted file mode 100644
index b8ced9296..000000000
--- a/dom/performance/tests/performance_observer.html
+++ /dev/null
@@ -1,74 +0,0 @@
-<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
--->
-<!DOCTYPE html>
-<meta charset=utf-8>
-<html>
-<head>
-<title>Test for performance observer</title>
-<script>
-'use strict';
-[
- "promise_test", "test", "setup",
- "assert_true", "assert_equals", "assert_array_equals",
- "assert_throws", "assert_unreached"
-].forEach(func => {
- window[func] = opener[func].bind(opener);
-});
-function done() {
- opener.add_completion_callback(() => {
- self.close();
- });
- opener.done();
-}
-
-</script>
-<script src="test_performance_observer.js"></script>
-</head>
-<body>
-<div id="log"></div>
-<script>
-function makeXHR(aUrl) {
- var xmlhttp = new XMLHttpRequest();
- xmlhttp.open("get", aUrl, true);
- xmlhttp.send();
-}
-
-promise_test(t => {
- var promise = new Promise(resolve => {
- performance.clearResourceTimings();
-
- var observer = new PerformanceObserver(list => resolve(list));
- observer.observe({entryTypes: ['resource']});
- t.add_cleanup(() => observer.disconnect());
- });
-
- makeXHR("test-data.json");
-
- return promise.then(list => {
- assert_equals(list.getEntries().length, 1);
- assert_array_equals(list.getEntries(),
- performance.getEntriesByType("resource"),
- "Observed 'resource' entries should equal to entries obtained by getEntriesByType.");
-
- // getEntries filtering tests
- assert_array_equals(list.getEntries({name: "http://mochi.test:8888/tests/dom/base/test/test-data.json"}),
- performance.getEntriesByName("http://mochi.test:8888/tests/dom/base/test/test-data.json"),
- "getEntries with name filter should return correct results.");
- assert_array_equals(list.getEntries({entryType: "resource"}),
- performance.getEntriesByType("resource"),
- "getEntries with entryType filter should return correct results.");
- assert_array_equals(list.getEntries({initiatorType: "xmlhttprequest"}),
- performance.getEntriesByType("resource"),
- "getEntries with initiatorType filter should return correct results.");
- assert_array_equals(list.getEntries({initiatorType: "link"}),
- [],
- "getEntries with non-existent initiatorType filter should return an empty array.");
- });
-}, "resource-timing test");
-
-done();
-
-</script>
-</body>
diff --git a/dom/performance/tests/test_performance_observer.html b/dom/performance/tests/test_performance_observer.html
index d36878315..7df881bd4 100644
--- a/dom/performance/tests/test_performance_observer.html
+++ b/dom/performance/tests/test_performance_observer.html
@@ -3,15 +3,55 @@
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
+<html>
+<head>
<meta charset=utf-8>
<title>Test for performance observer</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<div id=log></div>
+</head>
+<body>
+<div id="log"></div>
+<script src="test_performance_observer.js"></script>
<script>
-'use strict';
-SpecialPowers.pushPrefEnv({"set": [["dom.enable_performance_observer", true]]},
- function() {
- window.open("performance_observer.html");
- });
+function makeXHR(aUrl) {
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.open("get", aUrl, true);
+ xmlhttp.send();
+}
+
+promise_test(t => {
+ var promise = new Promise(resolve => {
+ performance.clearResourceTimings();
+
+ var observer = new PerformanceObserver(list => resolve(list));
+ observer.observe({entryTypes: ['resource']});
+ t.add_cleanup(() => observer.disconnect());
+ });
+
+ makeXHR("test-data.json");
+
+ return promise.then(list => {
+ assert_equals(list.getEntries().length, 1);
+ assert_array_equals(list.getEntries(),
+ performance.getEntriesByType("resource"),
+ "Observed 'resource' entries should equal to entries obtained by getEntriesByType.");
+
+ // getEntries filtering tests
+ assert_array_equals(list.getEntries({name: "http://mochi.test:8888/tests/dom/base/test/test-data.json"}),
+ performance.getEntriesByName("http://mochi.test:8888/tests/dom/base/test/test-data.json"),
+ "getEntries with name filter should return correct results.");
+ assert_array_equals(list.getEntries({entryType: "resource"}),
+ performance.getEntriesByType("resource"),
+ "getEntries with entryType filter should return correct results.");
+ assert_array_equals(list.getEntries({initiatorType: "xmlhttprequest"}),
+ performance.getEntriesByType("resource"),
+ "getEntries with initiatorType filter should return correct results.");
+ assert_array_equals(list.getEntries({initiatorType: "link"}),
+ [],
+ "getEntries with non-existent initiatorType filter should return an empty array.");
+ });
+}, "resource-timing test");
+
</script>
+</body>
diff --git a/dom/performance/tests/test_performance_user_timing.js b/dom/performance/tests/test_performance_user_timing.js
index 3d05ebb77..a15dbebb6 100644
--- a/dom/performance/tests/test_performance_user_timing.js
+++ b/dom/performance/tests/test_performance_user_timing.js
@@ -126,15 +126,18 @@ var steps = [
},
// Test measure
function () {
- ok(true, "Running measure addition with no start/end time test");
- performance.measure("test");
- var measures = performance.getEntriesByType("measure");
- is(measures.length, 1, "number of measures should be 1");
- var measure = measures[0];
- is(measure.name, "test", "measure name should be 'test'");
- is(measure.entryType, "measure", "measure type should be 'measure'");
- is(measure.startTime, 0, "measure start time should be zero");
- ok(measure.duration >= 0, "measure duration should not be negative");
+ // We don't have navigationStart in workers.
+ if ("window" in self) {
+ ok(true, "Running measure addition with no start/end time test");
+ performance.measure("test", "navigationStart");
+ var measures = performance.getEntriesByType("measure");
+ is(measures.length, 1, "number of measures should be 1");
+ var measure = measures[0];
+ is(measure.name, "test", "measure name should be 'test'");
+ is(measure.entryType, "measure", "measure type should be 'measure'");
+ is(measure.startTime, 0, "measure start time should be zero");
+ ok(measure.duration >= 0, "measure duration should not be negative");
+ }
},
function () {
ok(true, "Running measure addition with only start time test");
@@ -263,7 +266,7 @@ var steps = [
performance.measure("test", n);
ok(true, "Measure created from reserved name as starting time: " + n);
} catch (e) {
- ok(["redirectStart", "redirectEnd", "unloadEventStart", "unloadEventEnd", "loadEventEnd"].indexOf(n) >= 0,
+ ok(["redirectStart", "redirectEnd", "unloadEventStart", "unloadEventEnd", "loadEventEnd", "secureConnectionStart"].indexOf(n) >= 0,
"Measure created from reserved name as starting time: " + n + " and threw expected error");
}
};
diff --git a/dom/performance/tests/test_timeOrigin.html b/dom/performance/tests/test_timeOrigin.html
new file mode 100644
index 000000000..5a8a461f3
--- /dev/null
+++ b/dom/performance/tests/test_timeOrigin.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Test for performance.timeOrigin</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="test_performance_user_timing.js"></script>
+ </head>
+ <body>
+ <script type="text/js-worker" id="worker-src">
+ postMessage({ now: performance.now(), timeOrigin: performance.timeOrigin });
+ </script>
+
+ <script type="text/js-worker" id="shared-worker-src">
+ onconnect = function(evt) {
+ evt.ports[0].postMessage({ now: performance.now(), timeOrigin: performance.timeOrigin });
+ };
+ </script>
+
+ <script class="testbody" type="text/javascript">
+
+function testBasic() {
+ ok("timeOrigin" in performance, "Performance.timeOrigin exists.");
+ ok(performance.timeOrigin > 0, "TimeOrigin must be greater than 0.");
+ next();
+}
+
+function testWorker() {
+ var now = performance.now();
+
+ var blob = new Blob([ document.getElementById("worker-src").textContent ],
+ { type: "text/javascript" });
+ var w = new Worker(URL.createObjectURL(blob));
+ w.onmessage = function(e) {
+ ok (e.now + e.timeOrigin > now + performance.now, "Comparing worker.now and window.now");
+ next();
+ }
+}
+
+function testSharedWorker() {
+ var now = performance.now();
+
+ var blob = new Blob([ document.getElementById("shared-worker-src").textContent ],
+ { type: "text/javascript" });
+ var w = new SharedWorker(URL.createObjectURL(blob));
+ w.port.onmessage = function(e) {
+ ok (e.now + e.timeOrigin > now + performance.now, "Comparing worker.now and window.now");
+ next();
+ }
+}
+
+var tests = [ testBasic, testWorker, testSharedWorker ];
+function next() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(next);
+ </script>
+ </pre>
+ </body>
+</html>
diff --git a/dom/performance/tests/test_worker_observer.html b/dom/performance/tests/test_worker_observer.html
index b9ed0c964..9a55ef1d5 100644
--- a/dom/performance/tests/test_worker_observer.html
+++ b/dom/performance/tests/test_worker_observer.html
@@ -3,15 +3,16 @@
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
+<html>
+<head>
<meta charset=utf-8>
<title>Test for performance observer in worker</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<div id=log></div>
+</head>
+<body>
+<div id="log"></div>
<script>
-'use strict';
-SpecialPowers.pushPrefEnv({"set": [["dom.enable_performance_observer", true]]},
- function() {
- window.open("worker_performance_observer.html");
- });
+fetch_tests_from_worker(new Worker("worker_performance_observer.js"));
</script>
+</body>
diff --git a/dom/performance/tests/test_worker_performance_now.js b/dom/performance/tests/test_worker_performance_now.js
index c2a905031..dee4efce6 100644
--- a/dom/performance/tests/test_worker_performance_now.js
+++ b/dom/performance/tests/test_worker_performance_now.js
@@ -26,51 +26,5 @@ var n = self.performance.now(), d = Date.now();
ok(n >= 0, "The value of now() should be equal to or greater than 0.");
ok(self.performance.now() >= n, "The value of now() should monotonically increase.");
-// The spec says performance.now() should have micro-second resolution, but allows 1ms if the platform doesn't support it.
-// Our implementation does provide micro-second resolution, except for windows XP combined with some HW properties
-// where we can't use QueryPerformanceCounters (see comments at mozilla-central/xpcom/ds/TimeStamp_windows.cpp).
-// This XP-low-res case results in about 15ms resolutions, and can be identified when perf.now() returns only integers.
-//
-// Since setTimeout might return too early/late, our goal is that perf.now() changed within 2ms
-// (or 25ms for XP-low-res), rather than specific number of setTimeout(N) invocations.
-// See bug 749894 (intermittent failures of this test)
-var platformPossiblyLowRes;
-workerTestGetOSCPU(function(oscpu) {
- platformPossiblyLowRes = oscpu.indexOf("Windows NT 5.1") == 0; // XP only
- setTimeout(checkAfterTimeout, 1);
-});
-var allInts = (n % 1) == 0; // Indicator of limited HW resolution.
-var checks = 0;
+workerTestDone();
-function checkAfterTimeout() {
- checks++;
- var d2 = Date.now();
- var n2 = self.performance.now();
-
- allInts = allInts && (n2 % 1) == 0;
- var lowResCounter = platformPossiblyLowRes && allInts;
-
- if ( n2 == n && checks < 50 && // 50 is just a failsafe. Our real goals are 2ms or 25ms.
- ( (d2 - d) < 2 // The spec allows 1ms resolution. We allow up to measured 2ms to ellapse.
- ||
- lowResCounter &&
- (d2 - d) < 25
- )
- ) {
- setTimeout(checkAfterTimeout, 1);
- return;
- }
-
- // Loose spec: 1ms resolution, or 15ms resolution for the XP-low-res case.
- // We shouldn't test that dt is actually within 2/25ms since the iterations break if it isn't, and timeout could be late.
- ok(n2 > n, "Loose - the value of now() should increase within 2ms (or 25ms if low-res counter) (delta now(): " + (n2 - n) + " ms).");
-
- // Strict spec: if it's not the XP-low-res case, while the spec allows 1ms resolution, it prefers microseconds, which we provide.
- // Since the fastest setTimeout return which I observed was ~500 microseconds, a microseconds counter should change in 1 iteretion.
- ok(n2 > n && (lowResCounter || checks == 1),
- "Strict - [if high-res counter] the value of now() should increase after one setTimeout (hi-res: " + (!lowResCounter) +
- ", iters: " + checks +
- ", dt: " + (d2 - d) +
- ", now(): " + n2 + ").");
- workerTestDone();
-};
diff --git a/dom/performance/tests/worker_performance_observer.html b/dom/performance/tests/worker_performance_observer.html
deleted file mode 100644
index 613762f52..000000000
--- a/dom/performance/tests/worker_performance_observer.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
--->
-<!DOCTYPE html>
-<meta charset=utf-8>
-<html>
-<head>
-<title>Test for performance observer in worker</title>
-</head>
-<body>
-<div id="log"></div>
-<script>
-[
- "async_test", "test", "setup",
- "assert_true", "assert_equals", "assert_array_equals",
- "assert_throws", "fetch_tests_from_worker"
-].forEach(func => {
- window[func] = opener[func].bind(opener);
-});
-
-function done() {
- opener.add_completion_callback(() => {
- self.close();
- });
- opener.done();
-}
-
-fetch_tests_from_worker(new Worker("worker_performance_observer.js"));
-done();
-</script>
-</body>
diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp
index 6ee23f38b..916bdea0f 100644
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -109,10 +109,6 @@
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
#endif
-#if MOZ_CRASHREPORTER
-#include "nsExceptionHandler.h"
-#endif
-
#include "npapi.h"
using namespace mozilla;
@@ -962,12 +958,6 @@ nsPluginHost::TrySetUpPluginInstance(const nsACString &aMimeType,
plugin->GetLibrary()->SetHasLocalInstance();
-#if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_CRASHREPORTER)
- if (pluginTag->mIsFlashPlugin) {
- CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FlashVersion"), pluginTag->Version());
- }
-#endif
-
RefPtr<nsNPAPIPluginInstance> instance = new nsNPAPIPluginInstance();
// This will create the owning reference. The connection must be made between the
@@ -2024,45 +2014,9 @@ struct CompareFilesByTime
} // namespace
-bool
-nsPluginHost::ShouldAddPlugin(nsPluginTag* aPluginTag)
-{
-#if defined(XP_WIN) && (defined(__x86_64__) || defined(_M_X64))
- // On 64-bit windows, the only plugins we should load are flash and
- // silverlight. Use library filename and MIME type to check.
- if (StringBeginsWith(aPluginTag->FileName(), NS_LITERAL_CSTRING("NPSWF"), nsCaseInsensitiveCStringComparator()) &&
- (aPluginTag->HasMimeType(NS_LITERAL_CSTRING("application/x-shockwave-flash")) ||
- aPluginTag->HasMimeType(NS_LITERAL_CSTRING("application/x-shockwave-flash-test")))) {
- return true;
- }
- if (StringBeginsWith(aPluginTag->FileName(), NS_LITERAL_CSTRING("npctrl"), nsCaseInsensitiveCStringComparator()) &&
- (aPluginTag->HasMimeType(NS_LITERAL_CSTRING("application/x-silverlight-test")) ||
- aPluginTag->HasMimeType(NS_LITERAL_CSTRING("application/x-silverlight-2")) ||
- aPluginTag->HasMimeType(NS_LITERAL_CSTRING("application/x-silverlight")))) {
- return true;
- }
- // Accept the test plugin MIME types, so mochitests still work.
- if (aPluginTag->HasMimeType(NS_LITERAL_CSTRING("application/x-test")) ||
- aPluginTag->HasMimeType(NS_LITERAL_CSTRING("application/x-Second-Test")) ||
- aPluginTag->HasMimeType(NS_LITERAL_CSTRING("application/x-java-test"))) {
- return true;
- }
-#ifdef PLUGIN_LOGGING
- PLUGIN_LOG(PLUGIN_LOG_NORMAL,
- ("ShouldAddPlugin : Ignoring non-flash plugin library %s\n", aPluginTag->FileName().get()));
-#endif // PLUGIN_LOGGING
- return false;
-#else
- return true;
-#endif // defined(XP_WIN) && (defined(__x86_64__) || defined(_M_X64))
-}
-
void
nsPluginHost::AddPluginTag(nsPluginTag* aPluginTag)
{
- if (!ShouldAddPlugin(aPluginTag)) {
- return;
- }
aPluginTag->mNext = mPlugins;
mPlugins = aPluginTag;
@@ -2078,22 +2032,6 @@ nsPluginHost::AddPluginTag(nsPluginTag* aPluginTag)
}
}
-static bool
-PluginInfoIsFlash(const nsPluginInfo& info)
-{
- if (!info.fName || strcmp(info.fName, "Shockwave Flash") != 0) {
- return false;
- }
- for (uint32_t i = 0; i < info.fVariantCount; ++i) {
- if (info.fMimeTypeArray[i] &&
- (!strcmp(info.fMimeTypeArray[i], "application/x-shockwave-flash") ||
- !strcmp(info.fMimeTypeArray[i], "application/x-shockwave-flash-test"))) {
- return true;
- }
- }
- return false;
-}
-
typedef NS_NPAPIPLUGIN_CALLBACK(char *, NP_GETMIMEDESCRIPTION)(void);
nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
@@ -2114,8 +2052,6 @@ nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
("nsPluginHost::ScanPluginsDirectory dir=%s\n", dirPath.get()));
#endif
- bool flashOnly = Preferences::GetBool("plugin.load_flash_only", true);
-
nsCOMPtr<nsISimpleEnumerator> iter;
rv = pluginsDir->GetDirectoryEntries(getter_AddRefs(iter));
if (NS_FAILED(rv))
@@ -2218,8 +2154,7 @@ nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
res = pluginFile.GetPluginInfo(info, &library);
}
// if we don't have mime type don't proceed, this is not a plugin
- if (NS_FAILED(res) || !info.fMimeTypeArray ||
- (flashOnly && !PluginInfoIsFlash(info))) {
+ if (NS_FAILED(res) || !info.fMimeTypeArray) {
RefPtr<nsInvalidPluginTag> invalidTag = new nsInvalidPluginTag(filePath.get(),
fileModTime);
pluginFile.FreePluginInfo(info);
@@ -2867,14 +2802,12 @@ nsPluginHost::WritePluginInfo()
return rv;
}
- bool flashOnly = Preferences::GetBool("plugin.load_flash_only", true);
-
PR_fprintf(fd, "Generated File. Do not edit.\n");
PR_fprintf(fd, "\n[HEADER]\nVersion%c%s%c%c%c\nArch%c%s%c%c\n",
PLUGIN_REGISTRY_FIELD_DELIMITER,
kPluginRegistryVersion,
- flashOnly ? 't' : 'f',
+ 'f', //flashOnly
PLUGIN_REGISTRY_FIELD_DELIMITER,
PLUGIN_REGISTRY_END_OF_LINE_MARKER,
PLUGIN_REGISTRY_FIELD_DELIMITER,
@@ -3071,9 +3004,8 @@ nsPluginHost::ReadPluginInfo()
// If we're reading an old registry, ignore it
// If we flipped the flash-only pref, ignore it
- bool flashOnly = Preferences::GetBool("plugin.load_flash_only", true);
nsAutoCString expectedVersion(kPluginRegistryVersion);
- expectedVersion.Append(flashOnly ? 't' : 'f');
+ expectedVersion.Append('f'); //flashOnly
if (!expectedVersion.Equals(values[1])) {
return rv;
@@ -3214,10 +3146,6 @@ nsPluginHost::ReadPluginInfo()
MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
("LoadCachedPluginsInfo : Loading Cached plugininfo for %s\n", tag->FileName().get()));
- if (!ShouldAddPlugin(tag)) {
- continue;
- }
-
tag->mNext = mCachedPlugins;
mCachedPlugins = tag;
}
diff --git a/dom/plugins/base/nsPluginsDirDarwin.cpp b/dom/plugins/base/nsPluginsDirDarwin.cpp
index 6edc4fd6a..0085eec0d 100644
--- a/dom/plugins/base/nsPluginsDirDarwin.cpp
+++ b/dom/plugins/base/nsPluginsDirDarwin.cpp
@@ -26,9 +26,6 @@
#include "mozilla/UniquePtr.h"
#include "nsCocoaFeatures.h"
-#if defined(MOZ_CRASHREPORTER)
-#include "nsExceptionHandler.h"
-#endif
#include <string.h>
#include <stdio.h>
@@ -487,14 +484,6 @@ nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary)
NS_WARNING(msg.get());
return NS_ERROR_FAILURE;
}
-#if defined(MOZ_CRASHREPORTER)
- // The block above assumes that "fbplugin" is the filename of the plugin
- // to be blocked, or that the filename starts with "fbplugin_". But we
- // don't yet know for sure if this is always true. So for the time being
- // record extra information in our crash logs.
- CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Bug_1086977"),
- fileName);
-#endif
}
// It's possible that our plugin has 2 entry points that'll give us mime type
@@ -504,14 +493,6 @@ nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary)
// Sadly we have to load the library for this to work.
rv = LoadPlugin(outLibrary);
-#if defined(MOZ_CRASHREPORTER)
- if (nsCocoaFeatures::OnYosemiteOrLater()) {
- // If we didn't crash in LoadPlugin(), change the previous annotation so we
- // don't sow confusion.
- CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Bug_1086977"),
- NS_LITERAL_CSTRING("Didn't crash, please ignore"));
- }
-#endif
if (NS_FAILED(rv))
return rv;
diff --git a/dom/plugins/ipc/PluginMessageUtils.h b/dom/plugins/ipc/PluginMessageUtils.h
index 55be59d62..4532fac93 100644
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -23,9 +23,6 @@
#include "nsTArray.h"
#include "mozilla/Logging.h"
#include "nsHashKeys.h"
-#ifdef MOZ_CRASHREPORTER
-# include "nsExceptionHandler.h"
-#endif
#ifdef XP_MACOSX
#include "PluginInterposeOSX.h"
#else
diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp
index 84dc7c71f..7350a7fa7 100644
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -753,10 +753,6 @@ PluginModuleChild::AnswerPCrashReporterConstructor(
mozilla::dom::NativeThreadId* id,
uint32_t* processType)
{
-#ifdef MOZ_CRASHREPORTER
- *id = CrashReporter::CurrentThreadId();
- *processType = XRE_GetProcessType();
-#endif
return true;
}
diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp
index b85a3e94b..73f9c1025 100755
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -74,12 +74,6 @@ using namespace mozilla;
using namespace mozilla::plugins;
using namespace mozilla::plugins::parent;
-#ifdef MOZ_CRASHREPORTER
-#include "mozilla/dom/CrashReporterParent.h"
-
-using namespace CrashReporter;
-#endif
-
static const char kContentTimeoutPref[] = "dom.ipc.plugins.contentTimeoutSecs";
static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs";
@@ -134,66 +128,6 @@ mozilla::plugins::SetupBridge(uint32_t aPluginId,
return true;
}
-#ifdef MOZ_CRASHREPORTER_INJECTOR
-
-/**
- * Use for executing CreateToolhelp32Snapshot off main thread
- */
-class mozilla::plugins::FinishInjectorInitTask : public mozilla::CancelableRunnable
-{
-public:
- FinishInjectorInitTask()
- : mMutex("FlashInjectorInitTask::mMutex")
- , mParent(nullptr)
- , mMainThreadMsgLoop(MessageLoop::current())
- {
- MOZ_ASSERT(NS_IsMainThread());
- }
-
- void Init(PluginModuleChromeParent* aParent)
- {
- MOZ_ASSERT(aParent);
- mParent = aParent;
- }
-
- void PostToMainThread()
- {
- RefPtr<Runnable> self = this;
- mSnapshot.own(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
- { // Scope for lock
- mozilla::MutexAutoLock lock(mMutex);
- if (mMainThreadMsgLoop) {
- mMainThreadMsgLoop->PostTask(self.forget());
- }
- }
- }
-
- NS_IMETHOD Run() override
- {
- mParent->DoInjection(mSnapshot);
- // We don't need to hold this lock during DoInjection, but we do need
- // to obtain it before returning from Run() to ensure that
- // PostToMainThread has completed before we return.
- mozilla::MutexAutoLock lock(mMutex);
- return NS_OK;
- }
-
- nsresult Cancel() override
- {
- mozilla::MutexAutoLock lock(mMutex);
- mMainThreadMsgLoop = nullptr;
- return NS_OK;
- }
-
-private:
- mozilla::Mutex mMutex;
- nsAutoHandle mSnapshot;
- PluginModuleChromeParent* mParent;
- MessageLoop* mMainThreadMsgLoop;
-};
-
-#endif // MOZ_CRASHREPORTER_INJECTOR
-
namespace {
/**
@@ -578,29 +512,6 @@ PluginModuleChromeParent::OnProcessLaunched(const bool aSucceeded)
RegisterSettingsCallbacks();
-#ifdef MOZ_CRASHREPORTER
- // If this fails, we're having IPC troubles, and we're doomed anyways.
- if (!CrashReporterParent::CreateCrashReporter(this)) {
- mShutdown = true;
- Close();
- OnInitFailure();
- return;
- }
- CrashReporterParent* crashReporter = CrashReporter();
- if (crashReporter) {
- crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"),
- mIsStartingAsync ?
- NS_LITERAL_CSTRING("1") :
- NS_LITERAL_CSTRING("0"));
- }
-#ifdef XP_WIN
- { // Scope for lock
- mozilla::MutexAutoLock lock(mCrashReporterMutex);
- mCrashReporter = CrashReporter();
- }
-#endif
-#endif
-
#if defined(XP_WIN) && defined(_X86_)
// Protected mode only applies to Windows and only to x86.
if (!mIsBlocklisted && mIsFlashPlugin &&
@@ -686,12 +597,6 @@ PluginModuleParent::PluginModuleParent(bool aIsChrome, bool aAllowAsyncInit)
, mIsNPShutdownPending(false)
, mAsyncNewRv(NS_ERROR_NOT_INITIALIZED)
{
-#if defined(MOZ_CRASHREPORTER)
- CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"),
- mIsStartingAsync ?
- NS_LITERAL_CSTRING("1") :
- NS_LITERAL_CSTRING("0"));
-#endif
}
PluginModuleParent::~PluginModuleParent()
@@ -734,15 +639,6 @@ PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath,
, mHangUIParent(nullptr)
, mHangUIEnabled(true)
, mIsTimerReset(true)
-#ifdef MOZ_CRASHREPORTER
- , mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex")
- , mCrashReporter(nullptr)
-#endif
-#endif
-#ifdef MOZ_CRASHREPORTER_INJECTOR
- , mFlashProcess1(0)
- , mFlashProcess2(0)
- , mFinishInitTask(nullptr)
#endif
, mInitOnAsyncConnect(false)
, mAsyncInitRv(NS_ERROR_NOT_INITIALIZED)
@@ -790,17 +686,6 @@ PluginModuleChromeParent::~PluginModuleChromeParent()
mSubprocess = nullptr;
}
-#ifdef MOZ_CRASHREPORTER_INJECTOR
- if (mFlashProcess1)
- UnregisterInjectorCallback(mFlashProcess1);
- if (mFlashProcess2)
- UnregisterInjectorCallback(mFlashProcess2);
- if (mFinishInitTask) {
- // mFinishInitTask will be deleted by the main thread message_loop
- mFinishInitTask->Cancel();
- }
-#endif
-
UnregisterSettingsCallbacks();
Preferences::UnregisterCallback(TimeoutChanged, kChildTimeoutPref, this);
@@ -818,52 +703,6 @@ PluginModuleChromeParent::~PluginModuleChromeParent()
mozilla::HangMonitor::UnregisterAnnotator(*this);
}
-#ifdef MOZ_CRASHREPORTER
-void
-PluginModuleChromeParent::WriteExtraDataForMinidump(AnnotationTable& notes)
-{
-#ifdef XP_WIN
- // mCrashReporterMutex is already held by the caller
- mCrashReporterMutex.AssertCurrentThreadOwns();
-#endif
- typedef nsDependentCString CS;
-
- // Get the plugin filename, try to get just the file leafname
- const std::string& pluginFile = mSubprocess->GetPluginFilePath();
- size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
- if (filePos == std::string::npos)
- filePos = 0;
- else
- filePos++;
- notes.Put(NS_LITERAL_CSTRING("PluginFilename"), CS(pluginFile.substr(filePos).c_str()));
-
- notes.Put(NS_LITERAL_CSTRING("PluginName"), mPluginName);
- notes.Put(NS_LITERAL_CSTRING("PluginVersion"), mPluginVersion);
-
- CrashReporterParent* crashReporter = CrashReporter();
- if (crashReporter) {
-#ifdef XP_WIN
- if (mPluginCpuUsageOnHang.Length() > 0) {
- notes.Put(NS_LITERAL_CSTRING("NumberOfProcessors"),
- nsPrintfCString("%d", PR_GetNumberOfProcessors()));
-
- nsCString cpuUsageStr;
- cpuUsageStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[0] * 100) / 100);
- notes.Put(NS_LITERAL_CSTRING("PluginCpuUsage"), cpuUsageStr);
-
-#ifdef MOZ_CRASHREPORTER_INJECTOR
- for (uint32_t i=1; i<mPluginCpuUsageOnHang.Length(); ++i) {
- nsCString tempStr;
- tempStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[i] * 100) / 100);
- notes.Put(nsPrintfCString("CpuUsageFlashProcess%d", i), tempStr);
- }
-#endif
- }
-#endif
- }
-}
-#endif // MOZ_CRASHREPORTER
-
void
PluginModuleParent::SetChildTimeout(const int32_t aChildTimeout)
{
@@ -1123,20 +962,6 @@ PluginModuleChromeParent::AnnotateHang(mozilla::HangMonitor::HangAnnotations& aA
}
}
-#ifdef MOZ_CRASHREPORTER
-static bool
-CreatePluginMinidump(base::ProcessId processId, ThreadId childThread,
- nsIFile* parentMinidump, const nsACString& name)
-{
- mozilla::ipc::ScopedProcessHandle handle;
- if (processId == 0 ||
- !base::OpenPrivilegedProcessHandle(processId, &handle.rwget())) {
- return false;
- }
- return CreateAdditionalChildMinidump(handle, 0, parentMinidump, name);
-}
-#endif
-
bool
PluginModuleChromeParent::ShouldContinueFromReplyTimeout()
{
@@ -1184,87 +1009,7 @@ PluginModuleChromeParent::TakeFullMinidump(base::ProcessId aContentPid,
const nsAString& aBrowserDumpId,
nsString& aDumpId)
{
-#ifdef MOZ_CRASHREPORTER
-#ifdef XP_WIN
- mozilla::MutexAutoLock lock(mCrashReporterMutex);
-#endif // XP_WIN
-
- CrashReporterParent* crashReporter = CrashReporter();
- if (!crashReporter) {
- return;
- }
-
- bool reportsReady = false;
-
- // Check to see if we already have a browser dump id - with e10s plugin
- // hangs we take this earlier (see ProcessHangMonitor) from a background
- // thread. We do this before we message the main thread about the hang
- // since the posted message will trash our browser stack state.
- bool exists;
- nsCOMPtr<nsIFile> browserDumpFile;
- if (!aBrowserDumpId.IsEmpty() &&
- CrashReporter::GetMinidumpForID(aBrowserDumpId, getter_AddRefs(browserDumpFile)) &&
- browserDumpFile &&
- NS_SUCCEEDED(browserDumpFile->Exists(&exists)) && exists)
- {
- // We have a single browser report, generate a new plugin process parent
- // report and pair it up with the browser report handed in.
- reportsReady = crashReporter->GenerateMinidumpAndPair(this, browserDumpFile,
- NS_LITERAL_CSTRING("browser"));
- if (!reportsReady) {
- browserDumpFile = nullptr;
- CrashReporter::DeleteMinidumpFilesForID(aBrowserDumpId);
- }
- }
-
- // Generate crash report including plugin and browser process minidumps.
- // The plugin process is the parent report with additional dumps including
- // the browser process, content process when running under e10s, and
- // various flash subprocesses if we're the flash module.
- if (!reportsReady) {
- reportsReady = crashReporter->GeneratePairedMinidump(this);
- }
-
- if (reportsReady) {
- // Important to set this here, it tells the ActorDestroy handler
- // that we have an existing crash report that needs to be finalized.
- mPluginDumpID = crashReporter->ChildDumpID();
- aDumpId = mPluginDumpID;
- PLUGIN_LOG_DEBUG(
- ("generated paired browser/plugin minidumps: %s)",
- NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
- nsAutoCString additionalDumps("browser");
- nsCOMPtr<nsIFile> pluginDumpFile;
- if (GetMinidumpForID(mPluginDumpID, getter_AddRefs(pluginDumpFile)) &&
- pluginDumpFile) {
-#ifdef MOZ_CRASHREPORTER_INJECTOR
- // If we have handles to the flash sandbox processes on Windows,
- // include those minidumps as well.
- if (CreatePluginMinidump(mFlashProcess1, 0, pluginDumpFile,
- NS_LITERAL_CSTRING("flash1"))) {
- additionalDumps.AppendLiteral(",flash1");
- }
- if (CreatePluginMinidump(mFlashProcess2, 0, pluginDumpFile,
- NS_LITERAL_CSTRING("flash2"))) {
- additionalDumps.AppendLiteral(",flash2");
- }
-#endif // MOZ_CRASHREPORTER_INJECTOR
- if (aContentPid != mozilla::ipc::kInvalidProcessId) {
- // Include the content process minidump
- if (CreatePluginMinidump(aContentPid, 0,
- pluginDumpFile,
- NS_LITERAL_CSTRING("content"))) {
- additionalDumps.AppendLiteral(",content");
- }
- }
- }
- crashReporter->AnnotateCrashReport(
- NS_LITERAL_CSTRING("additional_minidumps"),
- additionalDumps);
- } else {
- NS_WARNING("failed to capture paired minidumps from hang");
- }
-#endif // MOZ_CRASHREPORTER
+ /*** STUB ***/
}
void
@@ -1273,43 +1018,6 @@ PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop,
const nsCString& aMonitorDescription,
const nsAString& aDumpId)
{
-#ifdef MOZ_CRASHREPORTER
- // Start by taking a full minidump if necessary, this is done early
- // because it also needs to lock the mCrashReporterMutex and Mutex doesn't
- // support recrusive locking.
- nsAutoString dumpId;
- if (aDumpId.IsEmpty()) {
- TakeFullMinidump(aContentPid, EmptyString(), dumpId);
- }
-
-#ifdef XP_WIN
- mozilla::MutexAutoLock lock(mCrashReporterMutex);
- CrashReporterParent* crashReporter = mCrashReporter;
- if (!crashReporter) {
- // If mCrashReporter is null then the hang has ended, the plugin module
- // is shutting down. There's nothing to do here.
- return;
- }
-#else
- CrashReporterParent* crashReporter = CrashReporter();
-#endif // XP_WIN
- crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("PluginHang"),
- NS_LITERAL_CSTRING("1"));
- crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("HangMonitorDescription"),
- aMonitorDescription);
-#ifdef XP_WIN
- if (mHangUIParent) {
- unsigned int hangUIDuration = mHangUIParent->LastShowDurationMs();
- if (hangUIDuration) {
- nsPrintfCString strHangUIDuration("%u", hangUIDuration);
- crashReporter->AnnotateCrashReport(
- NS_LITERAL_CSTRING("PluginHangUIDuration"),
- strHangUIDuration);
- }
- }
-#endif // XP_WIN
-#endif // MOZ_CRASHREPORTER
-
mozilla::ipc::ScopedProcessHandle geckoChildProcess;
bool childOpened = base::OpenProcessHandle(OtherPid(),
&geckoChildProcess.rwget());
@@ -1323,19 +1031,6 @@ PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop,
processHandles.AppendElement(geckoChildProcess);
}
-#ifdef MOZ_CRASHREPORTER_INJECTOR
- mozilla::ipc::ScopedProcessHandle flashBrokerProcess;
- if (mFlashProcess1 &&
- base::OpenProcessHandle(mFlashProcess1, &flashBrokerProcess.rwget())) {
- processHandles.AppendElement(flashBrokerProcess);
- }
- mozilla::ipc::ScopedProcessHandle flashSandboxProcess;
- if (mFlashProcess2 &&
- base::OpenProcessHandle(mFlashProcess2, &flashSandboxProcess.rwget())) {
- processHandles.AppendElement(flashSandboxProcess);
- }
-#endif
-
if (!GetProcessCpuUsage(processHandles, mPluginCpuUsageOnHang)) {
mPluginCpuUsageOnHang.Clear();
}
@@ -1482,108 +1177,6 @@ PluginModuleChromeParent::OnHangUIContinue()
}
#endif // XP_WIN
-#ifdef MOZ_CRASHREPORTER
-CrashReporterParent*
-PluginModuleChromeParent::CrashReporter()
-{
- return static_cast<CrashReporterParent*>(LoneManagedOrNullAsserts(ManagedPCrashReporterParent()));
-}
-
-#ifdef MOZ_CRASHREPORTER_INJECTOR
-static void
-RemoveMinidump(nsIFile* minidump)
-{
- if (!minidump)
- return;
-
- minidump->Remove(false);
- nsCOMPtr<nsIFile> extraFile;
- if (GetExtraFileForMinidump(minidump,
- getter_AddRefs(extraFile))) {
- extraFile->Remove(true);
- }
-}
-#endif // MOZ_CRASHREPORTER_INJECTOR
-
-void
-PluginModuleChromeParent::ProcessFirstMinidump()
-{
-#ifdef XP_WIN
- mozilla::MutexAutoLock lock(mCrashReporterMutex);
-#endif
- CrashReporterParent* crashReporter = CrashReporter();
- if (!crashReporter)
- return;
-
- AnnotationTable notes(4);
- WriteExtraDataForMinidump(notes);
-
- if (!mPluginDumpID.IsEmpty()) {
- // mPluginDumpID may be set in TerminateChildProcess, which means the
- // process hang monitor has already collected a 3-way browser, plugin,
- // content crash report. If so, update the existing report with our
- // annotations and finalize it. If not, fall through for standard
- // plugin crash report handling.
- crashReporter->GenerateChildData(&notes);
- crashReporter->FinalizeChildData();
- return;
- }
-
- uint32_t sequence = UINT32_MAX;
- nsCOMPtr<nsIFile> dumpFile;
- nsAutoCString flashProcessType;
- TakeMinidump(getter_AddRefs(dumpFile), &sequence);
-
-#ifdef MOZ_CRASHREPORTER_INJECTOR
- nsCOMPtr<nsIFile> childDumpFile;
- uint32_t childSequence;
-
- if (mFlashProcess1 &&
- TakeMinidumpForChild(mFlashProcess1,
- getter_AddRefs(childDumpFile),
- &childSequence)) {
- if (childSequence < sequence) {
- RemoveMinidump(dumpFile);
- dumpFile = childDumpFile;
- sequence = childSequence;
- flashProcessType.AssignLiteral("Broker");
- }
- else {
- RemoveMinidump(childDumpFile);
- }
- }
- if (mFlashProcess2 &&
- TakeMinidumpForChild(mFlashProcess2,
- getter_AddRefs(childDumpFile),
- &childSequence)) {
- if (childSequence < sequence) {
- RemoveMinidump(dumpFile);
- dumpFile = childDumpFile;
- sequence = childSequence;
- flashProcessType.AssignLiteral("Sandbox");
- }
- else {
- RemoveMinidump(childDumpFile);
- }
- }
-#endif
-
- if (!dumpFile) {
- NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
- return;
- }
-
- PLUGIN_LOG_DEBUG(("got child minidump: %s",
- NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
-
- GetIDFromMinidump(dumpFile, mPluginDumpID);
- if (!flashProcessType.IsEmpty()) {
- notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"), flashProcessType);
- }
- crashReporter->GenerateCrashReportForMinidump(dumpFile, &notes);
-}
-#endif
-
void
PluginModuleParent::ActorDestroy(ActorDestroyReason why)
{
@@ -1621,9 +1214,6 @@ void
PluginModuleChromeParent::ActorDestroy(ActorDestroyReason why)
{
if (why == AbnormalShutdown) {
-#ifdef MOZ_CRASHREPORTER
- ProcessFirstMinidump();
-#endif
Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
NS_LITERAL_CSTRING("plugin"), 1);
}
@@ -2405,9 +1995,6 @@ PluginModuleChromeParent::RecvNP_InitializeResult(const NPError& aError)
}
#endif
-#ifdef MOZ_CRASHREPORTER_INJECTOR
- InitializeInjector();
-#endif
}
return PluginModuleParent::RecvNP_InitializeResult(aError) && ok;
@@ -2955,24 +2542,12 @@ PCrashReporterParent*
PluginModuleChromeParent::AllocPCrashReporterParent(mozilla::dom::NativeThreadId* id,
uint32_t* processType)
{
-#ifdef MOZ_CRASHREPORTER
- return new CrashReporterParent();
-#else
return nullptr;
-#endif
}
bool
PluginModuleChromeParent::DeallocPCrashReporterParent(PCrashReporterParent* actor)
{
-#ifdef MOZ_CRASHREPORTER
-#ifdef XP_WIN
- mozilla::MutexAutoLock lock(mCrashReporterMutex);
- if (actor == static_cast<PCrashReporterParent*>(mCrashReporter)) {
- mCrashReporter = nullptr;
- }
-#endif
-#endif
delete actor;
return true;
}
@@ -3134,107 +2709,6 @@ PluginModuleParent::AnswerNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
return true;
}
-#ifdef MOZ_CRASHREPORTER_INJECTOR
-
-// We only add the crash reporter to subprocess which have the filename
-// FlashPlayerPlugin*
-#define FLASH_PROCESS_PREFIX "FLASHPLAYERPLUGIN"
-
-static DWORD
-GetFlashChildOfPID(DWORD pid, HANDLE snapshot)
-{
- PROCESSENTRY32 entry = {
- sizeof(entry)
- };
- for (BOOL ok = Process32First(snapshot, &entry);
- ok;
- ok = Process32Next(snapshot, &entry)) {
- if (entry.th32ParentProcessID == pid) {
- nsString name(entry.szExeFile);
- ToUpperCase(name);
- if (StringBeginsWith(name, NS_LITERAL_STRING(FLASH_PROCESS_PREFIX))) {
- return entry.th32ProcessID;
- }
- }
- }
- return 0;
-}
-
-// We only look for child processes of the Flash plugin, NPSWF*
-#define FLASH_PLUGIN_PREFIX "NPSWF"
-
-void
-PluginModuleChromeParent::InitializeInjector()
-{
- if (!Preferences::GetBool("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", false))
- return;
-
- nsCString path(Process()->GetPluginFilePath().c_str());
- ToUpperCase(path);
- int32_t lastSlash = path.RFindCharInSet("\\/");
- if (kNotFound == lastSlash)
- return;
-
- if (!StringBeginsWith(Substring(path, lastSlash + 1),
- NS_LITERAL_CSTRING(FLASH_PLUGIN_PREFIX)))
- return;
-
- TimeStamp th32Start = TimeStamp::Now();
- mFinishInitTask = mChromeTaskFactory.NewTask<FinishInjectorInitTask>();
- mFinishInitTask->Init(this);
- if (!::QueueUserWorkItem(&PluginModuleChromeParent::GetToolhelpSnapshot,
- mFinishInitTask, WT_EXECUTEDEFAULT)) {
- mFinishInitTask = nullptr;
- return;
- }
- TimeStamp th32End = TimeStamp::Now();
- mTimeBlocked += (th32End - th32Start);
-}
-
-void
-PluginModuleChromeParent::DoInjection(const nsAutoHandle& aSnapshot)
-{
- DWORD pluginProcessPID = GetProcessId(Process()->GetChildProcessHandle());
- mFlashProcess1 = GetFlashChildOfPID(pluginProcessPID, aSnapshot);
- if (mFlashProcess1) {
- InjectCrashReporterIntoProcess(mFlashProcess1, this);
-
- mFlashProcess2 = GetFlashChildOfPID(mFlashProcess1, aSnapshot);
- if (mFlashProcess2) {
- InjectCrashReporterIntoProcess(mFlashProcess2, this);
- }
- }
- mFinishInitTask = nullptr;
-}
-
-DWORD WINAPI
-PluginModuleChromeParent::GetToolhelpSnapshot(LPVOID aContext)
-{
- FinishInjectorInitTask* task = static_cast<FinishInjectorInitTask*>(aContext);
- MOZ_ASSERT(task);
- task->PostToMainThread();
- return 0;
-}
-
-void
-PluginModuleChromeParent::OnCrash(DWORD processID)
-{
- if (!mShutdown) {
- GetIPCChannel()->CloseWithError();
- mozilla::ipc::ScopedProcessHandle geckoPluginChild;
- if (base::OpenProcessHandle(OtherPid(), &geckoPluginChild.rwget())) {
- if (!base::KillProcess(geckoPluginChild,
- base::PROCESS_END_KILLED_BY_USER, false)) {
- NS_ERROR("May have failed to kill child process.");
- }
- } else {
- NS_ERROR("Failed to open child process when attempting kill.");
- }
- }
-}
-
-#endif // MOZ_CRASHREPORTER_INJECTOR
-
#ifdef MOZ_ENABLE_PROFILER_SPS
class PluginProfilerObserver final : public nsIObserver,
public nsSupportsWeakReference
diff --git a/dom/plugins/ipc/PluginModuleParent.h b/dom/plugins/ipc/PluginModuleParent.h
index cc24d6ed2..946d4c236 100644
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -26,10 +26,6 @@
#include "nsWindowsHelpers.h"
#endif
-#ifdef MOZ_CRASHREPORTER
-#include "nsExceptionHandler.h"
-#endif
-
class nsIProfileSaveEvent;
class nsPluginTag;
@@ -56,9 +52,6 @@ class PluginInstanceParent;
#ifdef XP_WIN
class PluginHangUIParent;
#endif
-#ifdef MOZ_CRASHREPORTER_INJECTOR
-class FinishInjectorInitTask;
-#endif
/**
* PluginModuleParent
@@ -80,9 +73,6 @@ class FinishInjectorInitTask;
class PluginModuleParent
: public PPluginModuleParent
, public PluginLibrary
-#ifdef MOZ_CRASHREPORTER_INJECTOR
- , public CrashReporter::InjectorCrashCallback
-#endif
{
protected:
typedef mozilla::PluginLibrary PluginLibrary;
@@ -395,10 +385,6 @@ class PluginModuleContentParent : public PluginModuleParent
virtual bool ShouldContinueFromReplyTimeout() override;
virtual void OnExitedSyncSend() override;
-#ifdef MOZ_CRASHREPORTER_INJECTOR
- void OnCrash(DWORD processID) override {}
-#endif
-
static PluginModuleContentParent* sSavedModuleParent;
uint32_t mPluginId;
@@ -522,11 +508,6 @@ private:
virtual bool ShouldContinueFromReplyTimeout() override;
-#ifdef MOZ_CRASHREPORTER
- void ProcessFirstMinidump();
- void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes);
-#endif
-
virtual PCrashReporterParent*
AllocPCrashReporterParent(mozilla::dom::NativeThreadId* id,
uint32_t* processType) override;
@@ -594,17 +575,6 @@ private:
PluginHangUIParent *mHangUIParent;
bool mHangUIEnabled;
bool mIsTimerReset;
-#ifdef MOZ_CRASHREPORTER
- /**
- * This mutex protects the crash reporter when the Plugin Hang UI event
- * handler is executing off main thread. It is intended to protect both
- * the mCrashReporter variable in addition to the CrashReporterParent object
- * that mCrashReporter refers to.
- */
- mozilla::Mutex mCrashReporterMutex;
- CrashReporterParent* mCrashReporter;
-#endif // MOZ_CRASHREPORTER
-
/**
* Launches the Plugin Hang UI.
@@ -626,20 +596,6 @@ private:
friend class mozilla::dom::CrashReporterParent;
friend class mozilla::plugins::PluginAsyncSurrogate;
-#ifdef MOZ_CRASHREPORTER_INJECTOR
- friend class mozilla::plugins::FinishInjectorInitTask;
-
- void InitializeInjector();
- void DoInjection(const nsAutoHandle& aSnapshot);
- static DWORD WINAPI GetToolhelpSnapshot(LPVOID aContext);
-
- void OnCrash(DWORD processID) override;
-
- DWORD mFlashProcess1;
- DWORD mFlashProcess2;
- RefPtr<mozilla::plugins::FinishInjectorInitTask> mFinishInitTask;
-#endif
-
void OnProcessLaunched(const bool aSucceeded);
class LaunchedTask : public LaunchCompleteTask
diff --git a/dom/plugins/ipc/hangui/plugin-hang-ui.exe.manifest b/dom/plugins/ipc/hangui/plugin-hang-ui.exe.manifest
index 8d6149c58..f5b7345f9 100644
--- a/dom/plugins/ipc/hangui/plugin-hang-ui.exe.manifest
+++ b/dom/plugins/ipc/hangui/plugin-hang-ui.exe.manifest
@@ -32,7 +32,6 @@
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
- <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
</assembly>
diff --git a/dom/plugins/test/mochitest/test_crash_notify_no_report.xul b/dom/plugins/test/mochitest/test_crash_notify_no_report.xul
index a1344bf0f..ac2b878fb 100644
--- a/dom/plugins/test/mochitest/test_crash_notify_no_report.xul
+++ b/dom/plugins/test/mochitest/test_crash_notify_no_report.xul
@@ -83,21 +83,10 @@ function onPluginCrashed(aEvent) {
getService(Components.interfaces.nsIObserverService);
os.removeObserver(testObserver, "plugin-crashed");
- // re-set MOZ_CRASHREPORTER_NO_REPORT
- let env = Components.classes["@mozilla.org/process/environment;1"]
- .getService(Components.interfaces.nsIEnvironment);
- env.set("MOZ_CRASHREPORTER_NO_REPORT", "1");
SimpleTest.finish();
}
function runTests() {
- // the test harness will have set MOZ_CRASHREPORTER_NO_REPORT,
- // ensure that we can change the setting and have our minidumps
- // wind up in Crash Reports/pending
- let env = Components.classes["@mozilla.org/process/environment;1"]
- .getService(Components.interfaces.nsIEnvironment);
- env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
-
var os = Components.classes["@mozilla.org/observer-service;1"].
getService(Components.interfaces.nsIObserverService);
os.addObserver(testObserver, "plugin-crashed", true);
diff --git a/dom/plugins/test/mochitest/test_crash_submit.xul b/dom/plugins/test/mochitest/test_crash_submit.xul
index 22f39384b..53b42b25c 100644
--- a/dom/plugins/test/mochitest/test_crash_submit.xul
+++ b/dom/plugins/test/mochitest/test_crash_submit.xul
@@ -70,11 +70,6 @@ var testObserver = {
getService(Components.interfaces.nsIObserverService);
os.removeObserver(testObserver, "crash-report-status");
- // Then re-set MOZ_CRASHREPORTER_NO_REPORT
- let env = Components.classes["@mozilla.org/process/environment;1"]
- .getService(Components.interfaces.nsIEnvironment);
- env.set("MOZ_CRASHREPORTER_NO_REPORT", "1");
-
// Finally re-set crashreporter URL
crashReporter.serverURL = oldServerURL;
@@ -123,13 +118,6 @@ function onPluginCrashed(aEvent) {
}
function runTests() {
- // the test harness will have set MOZ_CRASHREPORTER_NO_REPORT,
- // ensure that we can change the setting and have our minidumps
- // wind up in Crash Reports/pending
- let env = Components.classes["@mozilla.org/process/environment;1"]
- .getService(Components.interfaces.nsIEnvironment);
- env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
-
// Override the crash reporter URL to send to our fake server
crashReporter.serverURL = NetUtil.newURI(SERVER_URL);
diff --git a/dom/plugins/test/mochitest/test_hang_submit.xul b/dom/plugins/test/mochitest/test_hang_submit.xul
index 6c037ecd4..52ed78c6b 100644
--- a/dom/plugins/test/mochitest/test_hang_submit.xul
+++ b/dom/plugins/test/mochitest/test_hang_submit.xul
@@ -78,10 +78,6 @@ var testObserver = {
// Next unregister our observer
Services.obs.removeObserver(testObserver, "crash-report-status");
- // Then re-set MOZ_CRASHREPORTER_NO_REPORT
- let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
- env.set("MOZ_CRASHREPORTER_NO_REPORT", "1");
-
// Finally re-set prefs
crashReporter.serverURL = oldServerURL;
Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", oldTimeoutPref);
@@ -133,13 +129,6 @@ function runTests() {
// Default plugin hang timeout is too high for mochitests
Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", 1);
- // the test harness will have set MOZ_CRASHREPORTER_NO_REPORT,
- // ensure that we can change the setting and have our minidumps
- // wind up in Crash Reports/pending
- let env = Cc["@mozilla.org/process/environment;1"]
- .getService(Ci.nsIEnvironment);
- env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
-
// Override the crash reporter URL to send to our fake server
crashReporter.serverURL = NetUtil.newURI(SERVER_URL);
diff --git a/dom/plugins/test/unit/xpcshell.ini b/dom/plugins/test/unit/xpcshell.ini
index 8dae66b20..69b6731b2 100644
--- a/dom/plugins/test/unit/xpcshell.ini
+++ b/dom/plugins/test/unit/xpcshell.ini
@@ -5,7 +5,7 @@ tail =
tags = addons
firefox-appdir = browser
support-files =
- !/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+ !/toolkit/mozapps/webextensions/test/xpcshell/head_addons.js
[test_allowed_types.js]
skip-if = appname == "thunderbird"
diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp
index bf1fa5f50..557f3a1f9 100644
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -38,9 +38,6 @@
#include "WorkerRunnable.h"
#include "WrapperFactory.h"
#include "xpcpublic.h"
-#ifdef MOZ_CRASHREPORTER
-#include "nsExceptionHandler.h"
-#endif
namespace mozilla {
namespace dom {
@@ -564,37 +561,40 @@ Promise::Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
// static
already_AddRefed<Promise>
-Promise::All(const GlobalObject& aGlobal,
+Promise::All(JSContext* aCx,
const nsTArray<RefPtr<Promise>>& aPromiseList, ErrorResult& aRv)
{
- nsCOMPtr<nsIGlobalObject> global;
- global = do_QueryInterface(aGlobal.GetAsSupports());
- if (!global) {
+ JS::Rooted<JSObject*> globalObj(aCx, JS::CurrentGlobalOrNull(aCx));
+ if (!globalObj) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
- JSContext* cx = aGlobal.Context();
+ nsCOMPtr<nsIGlobalObject> global = xpc::NativeGlobal(globalObj);
+ if (!global) {
+ aRv.Throw(NS_ERROR_UNEXPECTED);
+ return nullptr;
+ }
- JS::AutoObjectVector promises(cx);
+ JS::AutoObjectVector promises(aCx);
if (!promises.reserve(aPromiseList.Length())) {
- aRv.NoteJSContextException(cx);
+ aRv.NoteJSContextException(aCx);
return nullptr;
}
for (auto& promise : aPromiseList) {
- JS::Rooted<JSObject*> promiseObj(cx, promise->PromiseObj());
+ JS::Rooted<JSObject*> promiseObj(aCx, promise->PromiseObj());
// Just in case, make sure these are all in the context compartment.
- if (!JS_WrapObject(cx, &promiseObj)) {
- aRv.NoteJSContextException(cx);
+ if (!JS_WrapObject(aCx, &promiseObj)) {
+ aRv.NoteJSContextException(aCx);
return nullptr;
}
promises.infallibleAppend(promiseObj);
}
- JS::Rooted<JSObject*> result(cx, JS::GetWaitForAllPromise(cx, promises));
+ JS::Rooted<JSObject*> result(aCx, JS::GetWaitForAllPromise(aCx, promises));
if (!result) {
- aRv.NoteJSContextException(cx);
+ aRv.NoteJSContextException(aCx);
return nullptr;
}
diff --git a/dom/promise/Promise.h b/dom/promise/Promise.h
index f2ad3bd6c..642603a11 100644
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -188,23 +188,26 @@ public:
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
JS::MutableHandle<JSObject*> aWrapper);
- // Do the equivalent of Promise.resolve in the current compartment of aCx.
- // Errorrs are reported on the ErrorResult; if aRv comes back !Failed(), this
- // function MUST return a non-null value.
+ // Do the equivalent of Promise.resolve in the compartment of aGlobal. The
+ // compartment of aCx is ignored. Errors are reported on the ErrorResult; if
+ // aRv comes back !Failed(), this function MUST return a non-null value.
static already_AddRefed<Promise>
Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
- // Do the equivalent of Promise.reject in the current compartment of aCx.
- // Errorrs are reported on the ErrorResult; if aRv comes back !Failed(), this
- // function MUST return a non-null value.
+ // Do the equivalent of Promise.reject in the compartment of aGlobal. The
+ // compartment of aCx is ignored. Errors are reported on the ErrorResult; if
+ // aRv comes back !Failed(), this function MUST return a non-null value.
static already_AddRefed<Promise>
Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
+ // Do the equivalent of Promise.all in the current compartment of aCx. Errors
+ // are reported on the ErrorResult; if aRv comes back !Failed(), this function
+ // MUST return a non-null value.
static already_AddRefed<Promise>
- All(const GlobalObject& aGlobal,
- const nsTArray<RefPtr<Promise>>& aPromiseList, ErrorResult& aRv);
+ All(JSContext* aCx, const nsTArray<RefPtr<Promise>>& aPromiseList,
+ ErrorResult& aRv);
void
Then(JSContext* aCx,
diff --git a/dom/push/moz.build b/dom/push/moz.build
index b96099161..35683120f 100644
--- a/dom/push/moz.build
+++ b/dom/push/moz.build
@@ -16,7 +16,7 @@ EXTRA_JS_MODULES += [
'PushService.jsm',
]
-if CONFIG['MOZ_BUILD_APP'] != 'mobile/android':
+if not CONFIG['MOZ_FENNEC']:
# Everything but Fennec.
EXTRA_JS_MODULES += [
'PushServiceHttp2.jsm',
diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp
index 815c7734d..979bd915f 100644
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -156,10 +156,13 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
nsAutoString nonce;
bool parserCreated = false;
if (!isPreload) {
- nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(aRequestContext);
- if (htmlElement) {
- rv = htmlElement->GetAttribute(NS_LITERAL_STRING("nonce"), nonce);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (aContentType == nsIContentPolicy::TYPE_SCRIPT ||
+ aContentType == nsIContentPolicy::TYPE_STYLESHEET) {
+ nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(aRequestContext);
+ if (htmlElement) {
+ rv = htmlElement->GetAttribute(NS_LITERAL_STRING("nonce"), nonce);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
}
nsCOMPtr<nsIScriptElement> script = do_QueryInterface(aRequestContext);
@@ -168,9 +171,10 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
}
}
- // aExtra is only non-null if the channel got redirected.
- bool wasRedirected = (aExtra != nullptr);
+ // aExtra holds the original URI of the channel if the
+ // channel got redirected (until we fix Bug 1332422).
nsCOMPtr<nsIURI> originalURI = do_QueryInterface(aExtra);
+ bool wasRedirected = originalURI;
bool permitted = permitsInternal(dir,
aContentLocation,
@@ -216,14 +220,6 @@ nsCSPContext::permitsInternal(CSPDirective aDir,
nsAutoString violatedDirective;
for (uint32_t p = 0; p < mPolicies.Length(); p++) {
-
- // According to the W3C CSP spec, frame-ancestors checks are ignored for
- // report-only policies (when "monitoring").
- if (aDir == nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE &&
- mPolicies[p]->getReportOnlyFlag()) {
- continue;
- }
-
if (!mPolicies[p]->permits(aDir,
aContentLocation,
aNonce,
@@ -343,6 +339,20 @@ nsCSPContext::GetBlockAllMixedContent(bool *outBlockAllMixedContent)
}
NS_IMETHODIMP
+nsCSPContext::GetEnforcesFrameAncestors(bool *outEnforcesFrameAncestors)
+{
+ *outEnforcesFrameAncestors = false;
+ for (uint32_t i = 0; i < mPolicies.Length(); i++) {
+ if (!mPolicies[i]->getReportOnlyFlag() &&
+ mPolicies[i]->hasDirective(nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE)) {
+ *outEnforcesFrameAncestors = true;
+ return NS_OK;
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsCSPContext::GetReferrerPolicy(uint32_t* outPolicy, bool* outIsSet)
{
*outIsSet = false;
diff --git a/dom/security/nsCSPParser.cpp b/dom/security/nsCSPParser.cpp
index a662c9cd1..a0eba6918 100644
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -136,6 +136,9 @@ nsCSPParser::nsCSPParser(cspTokens& aTokens,
, mUnsafeInlineKeywordSrc(nullptr)
, mChildSrc(nullptr)
, mFrameSrc(nullptr)
+ , mWorkerSrc(nullptr)
+ , mScriptSrc(nullptr)
+ , mParsingFrameAncestorsDir(false)
, mTokens(aTokens)
, mSelfURI(aSelfURI)
, mPolicy(nullptr)
@@ -531,7 +534,7 @@ nsCSPParser::keywordSource()
// Special case handling for 'self' which is not stored internally as a keyword,
// but rather creates a nsCSPHostSrc using the selfURI
if (CSP_IsKeyword(mCurToken, CSP_SELF)) {
- return CSP_CreateHostSrcFromURI(mSelfURI);
+ return CSP_CreateHostSrcFromSelfURI(mSelfURI);
}
if (CSP_IsKeyword(mCurToken, CSP_STRICT_DYNAMIC)) {
@@ -807,6 +810,7 @@ nsCSPParser::sourceExpression()
if (nsCSPHostSrc *cspHost = hostSource()) {
// Do not forget to set the parsed scheme.
cspHost->setScheme(parsedScheme);
+ cspHost->setWithinFrameAncestorsDir(mParsingFrameAncestorsDir);
return cspHost;
}
// Error was reported in hostSource()
@@ -1097,21 +1101,37 @@ nsCSPParser::directiveName()
return new nsUpgradeInsecureDirective(CSP_StringToCSPDirective(mCurToken));
}
- // child-src has it's own class to handle frame-src if necessary
+ // child-src by itself is deprecatd but will be enforced
+ // * for workers (if worker-src is not explicitly specified)
+ // * for frames (if frame-src is not explicitly specified)
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::CHILD_SRC_DIRECTIVE)) {
+ const char16_t* params[] = { mCurToken.get() };
+ logWarningErrorToConsole(nsIScriptError::warningFlag,
+ "deprecatedChildSrcDirective",
+ params, ArrayLength(params));
mChildSrc = new nsCSPChildSrcDirective(CSP_StringToCSPDirective(mCurToken));
return mChildSrc;
}
- // if we have a frame-src, cache it so we can decide whether to use child-src
+ // if we have a frame-src, cache it so we can discard child-src for frames
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE)) {
- const char16_t* params[] = { mCurToken.get(), NS_LITERAL_STRING("child-src").get() };
- logWarningErrorToConsole(nsIScriptError::warningFlag, "deprecatedDirective",
- params, ArrayLength(params));
mFrameSrc = new nsCSPDirective(CSP_StringToCSPDirective(mCurToken));
return mFrameSrc;
}
+ // if we have a worker-src, cache it so we can discard child-src for workers
+ if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE)) {
+ mWorkerSrc = new nsCSPDirective(CSP_StringToCSPDirective(mCurToken));
+ return mWorkerSrc;
+ }
+
+ // if we have a script-src, cache it as a fallback for worker-src
+ // in case child-src is not present
+ if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE)) {
+ mScriptSrc = new nsCSPScriptSrcDirective(CSP_StringToCSPDirective(mCurToken));
+ return mScriptSrc;
+ }
+
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::REQUIRE_SRI_FOR)) {
return new nsRequireSRIForDirective(CSP_StringToCSPDirective(mCurToken));
}
@@ -1209,6 +1229,9 @@ nsCSPParser::directive()
mStrictDynamic = false;
mUnsafeInlineKeywordSrc = nullptr;
+ mParsingFrameAncestorsDir =
+ CSP_IsDirective(mCurDir[0], nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE);
+
// Try to parse all the srcs by handing the array off to directiveValue
nsTArray<nsCSPBaseSrc*> srcs;
directiveValue(srcs);
@@ -1285,9 +1308,22 @@ nsCSPParser::policy()
directive();
}
- if (mChildSrc && !mFrameSrc) {
- // if we have a child-src, it handles frame-src too, unless frame-src is set
- mChildSrc->setHandleFrameSrc();
+ if (mChildSrc) {
+ if (!mFrameSrc) {
+ // if frame-src is specified explicitly for that policy than child-src should
+ // not restrict frames; if not, than child-src needs to restrict frames.
+ mChildSrc->setRestrictFrames();
+ }
+ if (!mWorkerSrc) {
+ // if worker-src is specified explicitly for that policy than child-src should
+ // not restrict workers; if not, than child-src needs to restrict workers.
+ mChildSrc->setRestrictWorkers();
+ }
+ }
+ // if script-src is specified, but not worker-src and also no child-src, then
+ // script-src has to govern workers.
+ if (mScriptSrc && !mWorkerSrc && !mChildSrc) {
+ mScriptSrc->setRestrictWorkers();
}
return mPolicy;
diff --git a/dom/security/nsCSPParser.h b/dom/security/nsCSPParser.h
index 30954b10f..d500a1c18 100644
--- a/dom/security/nsCSPParser.h
+++ b/dom/security/nsCSPParser.h
@@ -243,14 +243,21 @@ class nsCSPParser {
bool mStrictDynamic; // false, if 'strict-dynamic' is not defined
nsCSPKeywordSrc* mUnsafeInlineKeywordSrc; // null, otherwise invlidate()
- // cache variables for child-src and frame-src directive handling.
- // frame-src is deprecated in favor of child-src, however if we
- // see a frame-src directive, it takes precedence for frames and iframes.
- // At the end of parsing, if we have a child-src directive, we need to
- // decide whether it will handle frames, or if there is a frame-src we
- // should honor instead.
- nsCSPChildSrcDirective* mChildSrc;
- nsCSPDirective* mFrameSrc;
+ // cache variables for child-src, frame-src and worker-src handling;
+ // in CSP 3 child-src is deprecated. For backwards compatibility
+ // child-src needs to restrict:
+ // (*) frames, in case frame-src is not expicitly specified
+ // (*) workers, in case worker-src is not expicitly specified
+ // If neither worker-src, nor child-src is present, then script-src
+ // needs to govern workers.
+ nsCSPChildSrcDirective* mChildSrc;
+ nsCSPDirective* mFrameSrc;
+ nsCSPDirective* mWorkerSrc;
+ nsCSPScriptSrcDirective* mScriptSrc;
+
+ // cache variable to let nsCSPHostSrc know that it's within
+ // the frame-ancestors directive.
+ bool mParsingFrameAncestorsDir;
cspTokens mTokens;
nsIURI* mSelfURI;
diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp
index 63b4aae2c..49832f8f4 100644
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -230,7 +230,7 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType)
case nsIContentPolicy::TYPE_INTERNAL_WORKER:
case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER:
- return nsIContentSecurityPolicy::CHILD_SRC_DIRECTIVE;
+ return nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE;
case nsIContentPolicy::TYPE_SUBDOCUMENT:
return nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE;
@@ -266,20 +266,21 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType)
}
nsCSPHostSrc*
-CSP_CreateHostSrcFromURI(nsIURI* aURI)
+CSP_CreateHostSrcFromSelfURI(nsIURI* aSelfURI)
{
// Create the host first
nsCString host;
- aURI->GetHost(host);
+ aSelfURI->GetAsciiHost(host);
nsCSPHostSrc *hostsrc = new nsCSPHostSrc(NS_ConvertUTF8toUTF16(host));
+ hostsrc->setGeneratedFromSelfKeyword();
// Add the scheme.
nsCString scheme;
- aURI->GetScheme(scheme);
+ aSelfURI->GetScheme(scheme);
hostsrc->setScheme(NS_ConvertUTF8toUTF16(scheme));
int32_t port;
- aURI->GetPort(&port);
+ aSelfURI->GetPort(&port);
// Only add port if it's not default port.
if (port > 0) {
nsAutoString portStr;
@@ -348,13 +349,17 @@ CSP_IsQuotelessKeyword(const nsAString& aKey)
* @param aUpgradeInsecure
* Whether the policy makes use of the directive
* 'upgrade-insecure-requests'.
+ * @param aFromSelfURI
+ * Whether a scheme was generated from the keyword 'self'
+ * which then allows schemeless sources to match ws and wss.
*/
bool
permitsScheme(const nsAString& aEnforcementScheme,
nsIURI* aUri,
bool aReportOnly,
- bool aUpgradeInsecure)
+ bool aUpgradeInsecure,
+ bool aFromSelfURI)
{
nsAutoCString scheme;
nsresult rv = aUri->GetScheme(scheme);
@@ -373,8 +378,20 @@ permitsScheme(const nsAString& aEnforcementScheme,
// allow scheme-less sources where the protected resource is http
// and the load is https, see:
// http://www.w3.org/TR/CSP2/#match-source-expression
- if (aEnforcementScheme.EqualsASCII("http") &&
- scheme.EqualsASCII("https")) {
+ if (aEnforcementScheme.EqualsASCII("http")) {
+ if (scheme.EqualsASCII("https")) {
+ return true;
+ }
+ if ((scheme.EqualsASCII("ws") || scheme.EqualsASCII("wss")) && aFromSelfURI) {
+ return true;
+ }
+ }
+ if (aEnforcementScheme.EqualsASCII("https")) {
+ if (scheme.EqualsLiteral("wss") && aFromSelfURI) {
+ return true;
+ }
+ }
+ if (aEnforcementScheme.EqualsASCII("ws") && scheme.EqualsASCII("wss")) {
return true;
}
@@ -483,7 +500,7 @@ nsCSPSchemeSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirect
if (mInvalidated) {
return false;
}
- return permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure);
+ return permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure, false);
}
bool
@@ -503,6 +520,8 @@ nsCSPSchemeSrc::toString(nsAString& outStr) const
nsCSPHostSrc::nsCSPHostSrc(const nsAString& aHost)
: mHost(aHost)
+ , mGeneratedFromSelfKeyword(false)
+ , mWithinFrameAncstorsDir(false)
{
ToLowerCase(mHost);
}
@@ -611,7 +630,7 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
// http://www.w3.org/TR/CSP11/#match-source-expression
// 4.3) scheme matching: Check if the scheme matches.
- if (!permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure)) {
+ if (!permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure, mGeneratedFromSelfKeyword)) {
return false;
}
@@ -642,7 +661,7 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
// Before we can check if the host matches, we have to
// extract the host part from aUri.
nsAutoCString uriHost;
- nsresult rv = aUri->GetHost(uriHost);
+ nsresult rv = aUri->GetAsciiHost(uriHost);
NS_ENSURE_SUCCESS(rv, false);
nsString decodedUriHost;
@@ -686,6 +705,11 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
rv = url->GetFilePath(uriPath);
NS_ENSURE_SUCCESS(rv, false);
+ if (mWithinFrameAncstorsDir) {
+ // no path matching for frame-ancestors to not leak any path information.
+ return true;
+ }
+
nsString decodedUriPath;
CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriPath), decodedUriPath);
@@ -1160,6 +1184,11 @@ nsCSPDirective::toDomCSPStruct(mozilla::dom::CSP& outCSP) const
outCSP.mSandbox.Value() = mozilla::Move(srcs);
return;
+ case nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE:
+ outCSP.mWorker_src.Construct();
+ outCSP.mWorker_src.Value() = mozilla::Move(srcs);
+ return;
+
// REFERRER_DIRECTIVE and REQUIRE_SRI_FOR are handled in nsCSPPolicy::toDomCSPStruct()
default:
@@ -1212,7 +1241,8 @@ bool nsCSPDirective::equals(CSPDirective aDirective) const
nsCSPChildSrcDirective::nsCSPChildSrcDirective(CSPDirective aDirective)
: nsCSPDirective(aDirective)
- , mHandleFrameSrc(false)
+ , mRestrictFrames(false)
+ , mRestrictWorkers(false)
{
}
@@ -1220,30 +1250,58 @@ nsCSPChildSrcDirective::~nsCSPChildSrcDirective()
{
}
-void nsCSPChildSrcDirective::setHandleFrameSrc()
-{
- mHandleFrameSrc = true;
-}
-
bool nsCSPChildSrcDirective::restrictsContentType(nsContentPolicyType aContentType) const
{
if (aContentType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
- return mHandleFrameSrc;
+ return mRestrictFrames;
}
-
- return (aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER
- || aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER
- || aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER
- );
+ if (aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
+ aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
+ aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER) {
+ return mRestrictWorkers;
+ }
+ return false;
}
bool nsCSPChildSrcDirective::equals(CSPDirective aDirective) const
{
if (aDirective == nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE) {
- return mHandleFrameSrc;
+ return mRestrictFrames;
}
+ if (aDirective == nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE) {
+ return mRestrictWorkers;
+ }
+ return (mDirective == aDirective);
+}
+
+/* =============== nsCSPScriptSrcDirective ============= */
+
+nsCSPScriptSrcDirective::nsCSPScriptSrcDirective(CSPDirective aDirective)
+ : nsCSPDirective(aDirective)
+ , mRestrictWorkers(false)
+{
+}
- return (aDirective == nsIContentSecurityPolicy::CHILD_SRC_DIRECTIVE);
+nsCSPScriptSrcDirective::~nsCSPScriptSrcDirective()
+{
+}
+
+bool nsCSPScriptSrcDirective::restrictsContentType(nsContentPolicyType aContentType) const
+{
+ if (aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
+ aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
+ aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER) {
+ return mRestrictWorkers;
+ }
+ return mDirective == CSP_ContentTypeToDirective(aContentType);
+}
+
+bool nsCSPScriptSrcDirective::equals(CSPDirective aDirective) const
+{
+ if (aDirective == nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE) {
+ return mRestrictWorkers;
+ }
+ return (mDirective == aDirective);
}
/* =============== nsBlockAllMixedContentDirective ============= */
diff --git a/dom/security/nsCSPUtils.h b/dom/security/nsCSPUtils.h
index b33c8932a..91096712a 100644
--- a/dom/security/nsCSPUtils.h
+++ b/dom/security/nsCSPUtils.h
@@ -93,7 +93,8 @@ static const char* CSPStrDirectives[] = {
"child-src", // CHILD_SRC_DIRECTIVE
"block-all-mixed-content", // BLOCK_ALL_MIXED_CONTENT
"require-sri-for", // REQUIRE_SRI_FOR
- "sandbox" // SANDBOX_DIRECTIVE
+ "sandbox", // SANDBOX_DIRECTIVE
+ "worker-src" // WORKER_SRC_DIRECTIVE
};
inline const char* CSP_CSPDirectiveToString(CSPDirective aDir)
@@ -186,7 +187,7 @@ nsresult CSP_AppendCSPFromHeader(nsIContentSecurityPolicy* aCsp,
class nsCSPHostSrc;
-nsCSPHostSrc* CSP_CreateHostSrcFromURI(nsIURI* aURI);
+nsCSPHostSrc* CSP_CreateHostSrcFromSelfURI(nsIURI* aSelfURI);
bool CSP_IsValidDirective(const nsAString& aDir);
bool CSP_IsDirective(const nsAString& aValue, CSPDirective aDir);
bool CSP_IsKeyword(const nsAString& aValue, enum CSPKeyword aKey);
@@ -256,6 +257,12 @@ class nsCSPHostSrc : public nsCSPBaseSrc {
void setPort(const nsAString& aPort);
void appendPath(const nsAString &aPath);
+ inline void setGeneratedFromSelfKeyword() const
+ { mGeneratedFromSelfKeyword = true;}
+
+ inline void setWithinFrameAncestorsDir(bool aValue) const
+ { mWithinFrameAncstorsDir = aValue; }
+
inline void getScheme(nsAString& outStr) const
{ outStr.Assign(mScheme); };
@@ -273,6 +280,8 @@ class nsCSPHostSrc : public nsCSPBaseSrc {
nsString mHost;
nsString mPort;
nsString mPath;
+ mutable bool mGeneratedFromSelfKeyword;
+ mutable bool mWithinFrameAncstorsDir;
};
/* =============== nsCSPKeywordSrc ============ */
@@ -437,7 +446,7 @@ class nsCSPDirective {
bool visitSrcs(nsCSPSrcVisitor* aVisitor) const;
- private:
+ protected:
CSPDirective mDirective;
nsTArray<nsCSPBaseSrc*> mSrcs;
};
@@ -445,26 +454,52 @@ class nsCSPDirective {
/* =============== nsCSPChildSrcDirective ============= */
/*
- * In CSP 2, the child-src directive covers both workers and
- * subdocuments (i.e., frames and iframes). Workers were removed
- * from script-src, but frames can be controlled by either child-src
- * or frame-src directives, so child-src needs to know whether it should
- * also restrict frames. When both are present the frame-src directive
- * takes precedent.
+ * In CSP 3 child-src is deprecated. For backwards compatibility
+ * child-src needs to restrict:
+ * (*) frames, in case frame-src is not expicitly specified
+ * (*) workers, in case worker-src is not expicitly specified
*/
class nsCSPChildSrcDirective : public nsCSPDirective {
public:
explicit nsCSPChildSrcDirective(CSPDirective aDirective);
virtual ~nsCSPChildSrcDirective();
- void setHandleFrameSrc();
+ void setRestrictFrames()
+ { mRestrictFrames = true; }
+
+ void setRestrictWorkers()
+ { mRestrictWorkers = true; }
+
+ virtual bool restrictsContentType(nsContentPolicyType aContentType) const;
+
+ virtual bool equals(CSPDirective aDirective) const;
+
+ private:
+ bool mRestrictFrames;
+ bool mRestrictWorkers;
+};
+
+/* =============== nsCSPScriptSrcDirective ============= */
+
+/*
+ * In CSP 3 worker-src restricts workers, for backwards compatibily
+ * script-src has to restrict workers as the ultimate fallback if
+ * neither worker-src nor child-src is present in a CSP.
+ */
+class nsCSPScriptSrcDirective : public nsCSPDirective {
+ public:
+ explicit nsCSPScriptSrcDirective(CSPDirective aDirective);
+ virtual ~nsCSPScriptSrcDirective();
+
+ void setRestrictWorkers()
+ { mRestrictWorkers = true; }
virtual bool restrictsContentType(nsContentPolicyType aContentType) const;
virtual bool equals(CSPDirective aDirective) const;
private:
- bool mHandleFrameSrc;
+ bool mRestrictWorkers;
};
/* =============== nsBlockAllMixedContentDirective === */
diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp
index c4e1ed8e1..0cc4933fe 100644
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -1,8 +1,10 @@
#include "nsContentSecurityManager.h"
+#include "nsEscape.h"
#include "nsIChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIStreamListener.h"
#include "nsILoadInfo.h"
+#include "nsIOService.h"
#include "nsContentUtils.h"
#include "nsCORSListenerProxy.h"
#include "nsIStreamListener.h"
@@ -10,11 +12,86 @@
#include "nsMixedContentBlocker.h"
#include "mozilla/dom/Element.h"
+#include "mozilla/dom/TabChild.h"
NS_IMPL_ISUPPORTS(nsContentSecurityManager,
nsIContentSecurityManager,
nsIChannelEventSink)
+/* static */ bool
+nsContentSecurityManager::AllowTopLevelNavigationToDataURI(nsIChannel* aChannel)
+{
+ // Let's block all toplevel document navigations to a data: URI.
+ // In all cases where the toplevel document is navigated to a
+ // data: URI the triggeringPrincipal is a codeBasePrincipal, or
+ // a NullPrincipal. In other cases, e.g. typing a data: URL into
+ // the URL-Bar, the triggeringPrincipal is a SystemPrincipal;
+ // we don't want to block those loads. Only exception, loads coming
+ // from an external applicaton (e.g. Thunderbird) don't load
+ // using a codeBasePrincipal, but we want to block those loads.
+ if (!mozilla::net::nsIOService::BlockToplevelDataUriNavigations()) {
+ return true;
+ }
+ nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+ if (!loadInfo) {
+ return true;
+ }
+ if (loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) {
+ return true;
+ }
+ if (loadInfo->GetForceAllowDataURI()) {
+ // if the loadinfo explicitly allows the data URI navigation, let's allow it now
+ return true;
+ }
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
+ NS_ENSURE_SUCCESS(rv, true);
+ bool isDataURI =
+ (NS_SUCCEEDED(uri->SchemeIs("data", &isDataURI)) && isDataURI);
+ if (!isDataURI) {
+ return true;
+ }
+ // Whitelist data: images as long as they are not SVGs
+ nsAutoCString filePath;
+ uri->GetFilePath(filePath);
+ if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/")) &&
+ !StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/svg+xml"))) {
+ return true;
+ }
+ // Whitelist data: PDFs and JSON
+ if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("application/pdf")) ||
+ StringBeginsWith(filePath, NS_LITERAL_CSTRING("application/json"))) {
+ return true;
+ }
+ // Redirecting to a toplevel data: URI is not allowed, hence we make
+ // sure the RedirectChain is empty.
+ if (!loadInfo->GetLoadTriggeredFromExternal() &&
+ nsContentUtils::IsSystemPrincipal(loadInfo->TriggeringPrincipal()) &&
+ loadInfo->RedirectChain().IsEmpty()) {
+ return true;
+ }
+ nsAutoCString dataSpec;
+ uri->GetSpec(dataSpec);
+ if (dataSpec.Length() > 50) {
+ dataSpec.Truncate(50);
+ dataSpec.AppendLiteral("...");
+ }
+ nsCOMPtr<nsITabChild> tabChild = do_QueryInterface(loadInfo->ContextForTopLevelLoad());
+ nsCOMPtr<nsIDocument> doc;
+ if (tabChild) {
+ doc = static_cast<mozilla::dom::TabChild*>(tabChild.get())->GetDocument();
+ }
+ NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(dataSpec));
+ const char16_t* params[] = { specUTF16.get() };
+ nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+ NS_LITERAL_CSTRING("DATA_URI_BLOCKED"),
+ doc,
+ nsContentUtils::eSECURITY_PROPERTIES,
+ "BlockTopLevelDataURINavigation",
+ params, ArrayLength(params));
+ return false;
+}
+
static nsresult
ValidateSecurityFlags(nsILoadInfo* aLoadInfo)
{
@@ -176,7 +253,7 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
nsContentPolicyType internalContentPolicyType =
aLoadInfo->InternalContentPolicyType();
nsCString mimeTypeGuess;
- nsCOMPtr<nsINode> requestingContext = nullptr;
+ nsCOMPtr<nsISupports> requestingContext = nullptr;
#ifdef DEBUG
// Don't enforce TYPE_DOCUMENT assertions for loads
@@ -250,10 +327,13 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
case nsIContentPolicy::TYPE_XMLHTTPREQUEST: {
// alias nsIContentPolicy::TYPE_DATAREQUEST:
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
- "type_xml requires requestingContext of type Document");
-
+#ifdef DEBUG
+ {
+ nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
+ MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE,
+ "type_xml requires requestingContext of type Document");
+ }
+#endif
// We're checking for the external TYPE_XMLHTTPREQUEST here in case
// an addon creates a request with that type.
if (internalContentPolicyType ==
@@ -274,18 +354,26 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST: {
mimeTypeGuess = EmptyCString();
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::ELEMENT_NODE,
- "type_subrequest requires requestingContext of type Element");
+#ifdef DEBUG
+ {
+ nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
+ MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::ELEMENT_NODE,
+ "type_subrequest requires requestingContext of type Element");
+ }
+#endif
break;
}
case nsIContentPolicy::TYPE_DTD: {
mimeTypeGuess = EmptyCString();
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
- "type_dtd requires requestingContext of type Document");
+#ifdef DEBUG
+ {
+ nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
+ MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE,
+ "type_dtd requires requestingContext of type Document");
+ }
+#endif
break;
}
@@ -303,9 +391,13 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
mimeTypeGuess = EmptyCString();
}
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::ELEMENT_NODE,
- "type_media requires requestingContext of type Element");
+#ifdef DEBUG
+ {
+ nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
+ MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::ELEMENT_NODE,
+ "type_media requires requestingContext of type Element");
+ }
+#endif
break;
}
@@ -332,18 +424,26 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
case nsIContentPolicy::TYPE_XSLT: {
mimeTypeGuess = NS_LITERAL_CSTRING("application/xml");
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
- "type_xslt requires requestingContext of type Document");
+#ifdef DEBUG
+ {
+ nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
+ MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE,
+ "type_xslt requires requestingContext of type Document");
+ }
+#endif
break;
}
case nsIContentPolicy::TYPE_BEACON: {
mimeTypeGuess = EmptyCString();
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
- "type_beacon requires requestingContext of type Document");
+#ifdef DEBUG
+ {
+ nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
+ MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE,
+ "type_beacon requires requestingContext of type Document");
+ }
+#endif
break;
}
diff --git a/dom/security/nsContentSecurityManager.h b/dom/security/nsContentSecurityManager.h
index 912c0e89f..bab847743 100644
--- a/dom/security/nsContentSecurityManager.h
+++ b/dom/security/nsContentSecurityManager.h
@@ -32,6 +32,8 @@ public:
static nsresult doContentSecurityCheck(nsIChannel* aChannel,
nsCOMPtr<nsIStreamListener>& aInAndOutListener);
+ static bool AllowTopLevelNavigationToDataURI(nsIChannel* aChannel);
+
private:
static nsresult CheckChannel(nsIChannel* aChannel);
diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp
index a9aca5333..4e80dce3f 100644
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -337,7 +337,11 @@ nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
nullptr, // aExtra
requestingPrincipal,
&decision);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_FAILED(rv)) {
+ autoCallback.DontCallback();
+ aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
+ return NS_BINDING_FAILED;
+ }
if (nsMixedContentBlocker::sSendHSTSPriming) {
// The LoadInfo passed in is for the original channel, HSTS priming needs to
@@ -358,6 +362,7 @@ nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
// If the channel is about to load mixed content, abort the channel
if (!NS_CP_ACCEPTED(decision)) {
autoCallback.DontCallback();
+ aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
return NS_BINDING_FAILED;
}
diff --git a/dom/security/test/csp/file_child-src_worker-redirect.html b/dom/security/test/csp/file_child-src_worker-redirect.html
index 188f173b8..b0029935c 100644
--- a/dom/security/test/csp/file_child-src_worker-redirect.html
+++ b/dom/security/test/csp/file_child-src_worker-redirect.html
@@ -23,11 +23,8 @@
);
worker.onerror = function(error) {
- var msg = error.message;
- if (msg.match(/^NetworkError/) || msg.match(/Failed to load worker script/)) {
- // this means CSP blocked it
- msg = "blocked";
- }
+ // this means CSP blocked it
+ var msg = !("message" in error) ? "blocked" : e.message;
window.parent.postMessage({id:page_id, message:msg}, 'http://mochi.test:8888');
error.preventDefault();
};
diff --git a/dom/security/test/csp/file_frame_ancestors_ro.html b/dom/security/test/csp/file_frame_ancestors_ro.html
new file mode 100644
index 000000000..ff5ae9cf9
--- /dev/null
+++ b/dom/security/test/csp/file_frame_ancestors_ro.html
@@ -0,0 +1 @@
+<html><body>Child Document</body></html>
diff --git a/dom/security/test/csp/file_frame_ancestors_ro.html^headers^ b/dom/security/test/csp/file_frame_ancestors_ro.html^headers^
new file mode 100644
index 000000000..d018af3a9
--- /dev/null
+++ b/dom/security/test/csp/file_frame_ancestors_ro.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy-Report-Only: frame-ancestors 'none'; report-uri http://mochi.test:8888/foo.sjs
diff --git a/dom/security/test/csp/file_frame_src.js b/dom/security/test/csp/file_frame_src.js
new file mode 100644
index 000000000..8e81f0743
--- /dev/null
+++ b/dom/security/test/csp/file_frame_src.js
@@ -0,0 +1,14 @@
+let testframe = document.getElementById("testframe");
+testframe.onload = function() {
+ parent.postMessage({
+ result: "frame-allowed",
+ href: document.location.href,
+ }, "*");
+}
+testframe.onerror = function() {
+ parent.postMessage({
+ result: "frame-blocked",
+ href: document.location.href,
+ }, "*");
+}
+testframe.src = "file_frame_src_inner.html"
diff --git a/dom/security/test/csp/file_frame_src_child_governs.html b/dom/security/test/csp/file_frame_src_child_governs.html
new file mode 100644
index 000000000..a51cb75be
--- /dev/null
+++ b/dom/security/test/csp/file_frame_src_child_governs.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="child-src https://example.com">";
+</head>
+<body>
+<iframe id="testframe"></iframe>
+<script type="text/javascript" src="file_frame_src.js"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_frame_src_frame_governs.html b/dom/security/test/csp/file_frame_src_frame_governs.html
new file mode 100644
index 000000000..2c5d5857f
--- /dev/null
+++ b/dom/security/test/csp/file_frame_src_frame_governs.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="frame-src https://example.com; child-src 'none'">";
+</head>
+<body>
+<iframe id="testframe"></iframe>
+<script type="text/javascript" src="file_frame_src.js"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_frame_src_inner.html b/dom/security/test/csp/file_frame_src_inner.html
new file mode 100644
index 000000000..4a2fc6095
--- /dev/null
+++ b/dom/security/test/csp/file_frame_src_inner.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+dummy iframe
+</body>
+</html>
diff --git a/dom/security/test/csp/file_ignore_xfo.html b/dom/security/test/csp/file_ignore_xfo.html
new file mode 100644
index 000000000..6746a3adb
--- /dev/null
+++ b/dom/security/test/csp/file_ignore_xfo.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1024557: Ignore x-frame-options if CSP with frame-ancestors exists</title>
+</head>
+<body>
+<div id="cspmessage">Ignoring XFO because of CSP</div>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_ignore_xfo.html^headers^ b/dom/security/test/csp/file_ignore_xfo.html^headers^
new file mode 100644
index 000000000..e93f9e3ec
--- /dev/null
+++ b/dom/security/test/csp/file_ignore_xfo.html^headers^
@@ -0,0 +1,3 @@
+Content-Security-Policy: frame-ancestors http://mochi.test:8888
+X-Frame-Options: deny
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_image_nonce.html b/dom/security/test/csp/file_image_nonce.html
new file mode 100644
index 000000000..5d57bb837
--- /dev/null
+++ b/dom/security/test/csp/file_image_nonce.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <title>Bug 1355801: Nonce should not apply to images</title>
+ </head>
+<body>
+
+<img id='matchingNonce' src='http://mochi.test:8888/tests/image/test/mochitest/blue.png?a' nonce='abc'></img>
+<img id='nonMatchingNonce' src='http://mochi.test:8888/tests/image/test/mochitest/blue.png?b' nonce='bca'></img>
+<img id='noNonce' src='http://mochi.test:8888/tests/image/test/mochitest/blue.png?c'></img>
+
+<script type='application/javascript'>
+ var matchingNonce = document.getElementById('matchingNonce');
+ matchingNonce.onload = function(e) {
+ window.parent.postMessage({result: 'img-with-matching-nonce-loaded'}, '*');
+ };
+ matchingNonce.onerror = function(e) {
+ window.parent.postMessage({result: 'img-with-matching-nonce-blocked'}, '*');
+ }
+
+ var nonMatchingNonce = document.getElementById('nonMatchingNonce');
+ nonMatchingNonce.onload = function(e) {
+ window.parent.postMessage({result: 'img-with_non-matching-nonce-loaded'}, '*');
+ };
+ nonMatchingNonce.onerror = function(e) {
+ window.parent.postMessage({result: 'img-with_non-matching-nonce-blocked'}, '*');
+ }
+
+ var noNonce = document.getElementById('noNonce');
+ noNonce.onload = function(e) {
+ window.parent.postMessage({result: 'img-without-nonce-loaded'}, '*');
+ };
+ noNonce.onerror = function(e) {
+ window.parent.postMessage({result: 'img-without-nonce-blocked'}, '*');
+ }
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_image_nonce.html^headers^ b/dom/security/test/csp/file_image_nonce.html^headers^
new file mode 100644
index 000000000..0d63558c4
--- /dev/null
+++ b/dom/security/test/csp/file_image_nonce.html^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: img-src 'nonce-abc';
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_punycode_host_src.js b/dom/security/test/csp/file_punycode_host_src.js
new file mode 100644
index 000000000..3505faf70
--- /dev/null
+++ b/dom/security/test/csp/file_punycode_host_src.js
@@ -0,0 +1,2 @@
+const LOADED = true;
+parent.postMessage({result: 'script-allowed'}, "*"); \ No newline at end of file
diff --git a/dom/security/test/csp/file_punycode_host_src.sjs b/dom/security/test/csp/file_punycode_host_src.sjs
new file mode 100644
index 000000000..3189cc063
--- /dev/null
+++ b/dom/security/test/csp/file_punycode_host_src.sjs
@@ -0,0 +1,45 @@
+// custom *.sjs for Bug 1224225
+// Punycode in CSP host sources
+
+const HTML_PART1 =
+ "<!DOCTYPE HTML>" +
+ "<html><head><meta charset=\"utf-8\">" +
+ "<title>Bug 1224225 - CSP source matching should work for punycoded domain names</title>" +
+ "</head>" +
+ "<body>" +
+ "<script id='script' src='";
+
+const TESTCASE1 = "http://sub2.ält.example.org/";
+const TESTCASE2 = "http://sub2.xn--lt-uia.example.org/"
+
+const HTML_PART2 = "tests/dom/security/test/csp/file_punycode_host_src.js'></script>" +
+ "</body>" +
+ "</html>";
+
+function handleRequest(request, response)
+{
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+
+ Components.utils.importGlobalProperties(["URLSearchParams"]);
+ const query = new URLSearchParams(request.queryString);
+
+
+ if (query.get("csp")) {
+ response.setHeader("Content-Security-Policy", query.get("csp"), false);
+ }
+ if (query.get("action") == "script-unicode-csp-punycode") {
+ response.write(HTML_PART1 + TESTCASE1 + HTML_PART2);
+ return
+ }
+ if (query.get("action") == "script-punycode-csp-punycode") {
+ response.write(HTML_PART1 + TESTCASE2 + HTML_PART2);
+ return
+ }
+
+
+ // we should never get here, but just in case
+ // return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_ro_ignore_xfo.html b/dom/security/test/csp/file_ro_ignore_xfo.html
new file mode 100644
index 000000000..85e7f0092
--- /dev/null
+++ b/dom/security/test/csp/file_ro_ignore_xfo.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1024557: Ignore x-frame-options if CSP with frame-ancestors exists</title>
+</head>
+<body>
+<div id="cspmessage">Ignoring XFO because of CSP_RO</div>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/security/test/csp/file_ro_ignore_xfo.html^headers^ b/dom/security/test/csp/file_ro_ignore_xfo.html^headers^
new file mode 100644
index 000000000..ab8366f06
--- /dev/null
+++ b/dom/security/test/csp/file_ro_ignore_xfo.html^headers^
@@ -0,0 +1,3 @@
+Content-Security-Policy-Report-Only: frame-ancestors http://mochi.test:8888
+X-Frame-Options: deny
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_spawn_service_worker.js b/dom/security/test/csp/file_spawn_service_worker.js
new file mode 100644
index 000000000..b262fa10a
--- /dev/null
+++ b/dom/security/test/csp/file_spawn_service_worker.js
@@ -0,0 +1 @@
+// dummy file
diff --git a/dom/security/test/csp/file_spawn_shared_worker.js b/dom/security/test/csp/file_spawn_shared_worker.js
new file mode 100644
index 000000000..00063bc5c
--- /dev/null
+++ b/dom/security/test/csp/file_spawn_shared_worker.js
@@ -0,0 +1,7 @@
+onconnect = function(e) {
+ var port = e.ports[0];
+ port.addEventListener("message", function(e) {
+ port.postMessage("shared worker is executing");
+ });
+ port.start();
+}
diff --git a/dom/security/test/csp/file_spawn_worker.js b/dom/security/test/csp/file_spawn_worker.js
new file mode 100644
index 000000000..acde7408c
--- /dev/null
+++ b/dom/security/test/csp/file_spawn_worker.js
@@ -0,0 +1 @@
+postMessage("worker is executing");
diff --git a/dom/security/test/csp/file_upgrade_insecure_navigation.sjs b/dom/security/test/csp/file_upgrade_insecure_navigation.sjs
new file mode 100644
index 000000000..51afa39bf
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_navigation.sjs
@@ -0,0 +1,79 @@
+// Custom *.sjs file specifically for the needs of
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1271173
+
+"use strict";
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+
+const TEST_NAVIGATIONAL_UPGRADE = `
+ <!DOCTYPE html>
+ <html>
+ <head><meta charset="utf-8"></head>
+ <body>
+ <a href="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation.sjs?action=framenav" id="testlink">clickme</a>
+ <script type="text/javascript">
+ // before navigating the current frame we open the window and check that uir applies
+ var myWin = window.open("http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation.sjs?action=docnav");
+
+ window.addEventListener("message", receiveMessage, false);
+ function receiveMessage(event) {
+ myWin.close();
+ var link = document.getElementById('testlink');
+ link.click();
+ }
+ </script>
+ </body>
+ </html>`;
+
+const FRAME_NAV = `
+ <!DOCTYPE html>
+ <html>
+ <head><meta charset="utf-8"></head>
+ <body>
+ <script type="text/javascript">
+ parent.postMessage({result: document.documentURI}, "*");
+ </script>
+ </body>
+ </html>`;
+
+const DOC_NAV = `
+ <!DOCTYPE html>
+ <html>
+ <head><meta charset="utf-8"></head>
+ <body>
+ <script type="text/javascript">
+ // call back to the main testpage signaling whether the upgraded succeeded
+ window.opener.parent.postMessage({result: document.documentURI}, "*");
+ // let the opener (iframe) now that we can now close the window and move on with the test.
+ window.opener.postMessage({result: "readyToMoveOn"}, "*");
+ </script>
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ const query = new URLSearchParams(request.queryString);
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+ if (query.get("csp")) {
+ response.setHeader("Content-Security-Policy", query.get("csp"), false);
+ }
+
+ if (query.get("action") === "perform_navigation") {
+ response.write(TEST_NAVIGATIONAL_UPGRADE);
+ return;
+ }
+
+ if (query.get("action") === "framenav") {
+ response.write(FRAME_NAV);
+ return;
+ }
+
+ if (query.get("action") === "docnav") {
+ response.write(DOC_NAV);
+ return;
+ }
+
+ // we should never get here, but just in case
+ // return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_websocket_explicit.html b/dom/security/test/csp/file_websocket_explicit.html
new file mode 100644
index 000000000..51462ab74
--- /dev/null
+++ b/dom/security/test/csp/file_websocket_explicit.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1345615: Allow websocket schemes when using 'self' in CSP</title>
+ <meta http-equiv="Content-Security-Policy" content="connect-src ws:">
+</head>
+<body>
+ <script type="application/javascript">
+ /* load socket using ws */
+ var wsSocket = new WebSocket("ws://example.com/tests/dom/security/test/csp/file_websocket_self");
+ wsSocket.onopen = function(e) {
+ window.parent.postMessage({result: "explicit-ws-loaded"}, "*");
+ wsSocket.close();
+ };
+ wsSocket.onerror = function(e) {
+ window.parent.postMessage({result: "explicit-ws-blocked"}, "*");
+ };
+
+ /* load socket using wss */
+ var wssSocket = new WebSocket("wss://example.com/tests/dom/security/test/csp/file_websocket_self");
+ wssSocket.onopen = function(e) {
+ window.parent.postMessage({result: "explicit-wss-loaded"}, "*");
+ wssSocket.close();
+ };
+ wssSocket.onerror = function(e) {
+ window.parent.postMessage({result: "explicit-wss-blocked"}, "*");
+ };
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_websocket_self.html b/dom/security/test/csp/file_websocket_self.html
new file mode 100644
index 000000000..3ff5f0558
--- /dev/null
+++ b/dom/security/test/csp/file_websocket_self.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1345615: Allow websocket schemes when using 'self' in CSP</title>
+ <meta http-equiv="Content-Security-Policy" content="connect-src 'self'">
+</head>
+<body>
+ <script type="application/javascript">
+ /* load socket using ws */
+ var wsSocket = new WebSocket("ws://example.com/tests/dom/security/test/csp/file_websocket_self");
+ wsSocket.onopen = function(e) {
+ window.parent.postMessage({result: "self-ws-loaded"}, "*");
+ wsSocket.close();
+ };
+ wsSocket.onerror = function(e) {
+ window.parent.postMessage({result: "self-ws-blocked"}, "*");
+ };
+
+ /* load socket using wss */
+ var wssSocket = new WebSocket("wss://example.com/tests/dom/security/test/csp/file_websocket_self");
+ wssSocket.onopen = function(e) {
+ window.parent.postMessage({result: "self-wss-loaded"}, "*");
+ wssSocket.close();
+ };
+ wssSocket.onerror = function(e) {
+ window.parent.postMessage({result: "self-wss-blocked"}, "*");
+ };
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_websocket_self_wsh.py b/dom/security/test/csp/file_websocket_self_wsh.py
new file mode 100644
index 000000000..5fe508a91
--- /dev/null
+++ b/dom/security/test/csp/file_websocket_self_wsh.py
@@ -0,0 +1,7 @@
+from mod_pywebsocket import msgutil
+
+def web_socket_do_extra_handshake(request):
+ pass
+
+def web_socket_transfer_data(request):
+ pass
diff --git a/dom/security/test/csp/file_worker_src.js b/dom/security/test/csp/file_worker_src.js
new file mode 100644
index 000000000..ad3ade6a6
--- /dev/null
+++ b/dom/security/test/csp/file_worker_src.js
@@ -0,0 +1,52 @@
+
+let myWorker = new Worker("file_spawn_worker.js");
+myWorker.onmessage = function(event) {
+ parent.postMessage({
+ result: "worker-allowed",
+ href: document.location.href,
+ }, "*");
+}
+myWorker.onerror = function(event) {
+ parent.postMessage({
+ result: "worker-blocked",
+ href: document.location.href,
+ }, "*");
+}
+
+// --------------------------------------------
+
+var mySharedWorker = new SharedWorker('file_spawn_shared_worker.js');
+mySharedWorker.port.onmessage = function(ev) {
+ parent.postMessage({
+ result: "shared-worker-allowed",
+ href: document.location.href,
+ }, "*");
+}
+mySharedWorker.onerror = function(evt) {
+ evt.preventDefault();
+ parent.postMessage({
+ result: "shared-worker-blocked",
+ href: document.location.href,
+ }, "*");
+}
+mySharedWorker.port.start();
+mySharedWorker.port.postMessage('foo');
+
+// --------------------------------------------
+
+navigator.serviceWorker.register('file_spawn_service_worker.js')
+.then(function(reg) {
+ // registration worked
+ reg.unregister().then(function() {
+ parent.postMessage({
+ result: "service-worker-allowed",
+ href: document.location.href,
+ }, "*");
+ });
+}).catch(function(error) {
+ // registration failed
+ parent.postMessage({
+ result: "service-worker-blocked",
+ href: document.location.href,
+ }, "*");
+});
diff --git a/dom/security/test/csp/file_worker_src_child_governs.html b/dom/security/test/csp/file_worker_src_child_governs.html
new file mode 100644
index 000000000..ca8a683aa
--- /dev/null
+++ b/dom/security/test/csp/file_worker_src_child_governs.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="child-src https://example.com; script-src 'nonce-foo'">";
+</head>
+<body>
+<script type="text/javascript" src="file_worker_src.js" nonce="foo"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_worker_src_script_governs.html b/dom/security/test/csp/file_worker_src_script_governs.html
new file mode 100644
index 000000000..0385fee57
--- /dev/null
+++ b/dom/security/test/csp/file_worker_src_script_governs.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-foo' https://example.com">";
+</head>
+<body>
+<script type="text/javascript" src="file_worker_src.js" nonce="foo"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_worker_src_worker_governs.html b/dom/security/test/csp/file_worker_src_worker_governs.html
new file mode 100644
index 000000000..93c8f6122
--- /dev/null
+++ b/dom/security/test/csp/file_worker_src_worker_governs.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="worker-src https://example.com; child-src 'none'; script-src 'nonce-foo'">";
+</head>
+<body>
+<script type="text/javascript" src="file_worker_src.js" nonce="foo"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini
index 8add999c3..33b112020 100644
--- a/dom/security/test/csp/mochitest.ini
+++ b/dom/security/test/csp/mochitest.ini
@@ -91,6 +91,8 @@ support-files =
file_bug941404.html
file_bug941404_xhr.html
file_bug941404_xhr.html^headers^
+ file_frame_ancestors_ro.html
+ file_frame_ancestors_ro.html^headers^
file_hash_source.html
file_dual_header_testserver.sjs
file_hash_source.html^headers^
@@ -206,6 +208,18 @@ support-files =
file_iframe_srcdoc.sjs
file_iframe_sandbox_srcdoc.html
file_iframe_sandbox_srcdoc.html^headers^
+ file_ignore_xfo.html
+ file_ignore_xfo.html^headers^
+ file_ro_ignore_xfo.html
+ file_ro_ignore_xfo.html^headers^
+ file_upgrade_insecure_navigation.sjs
+ file_image_nonce.html
+ file_image_nonce.html^headers^
+ file_punycode_host_src.sjs
+ file_punycode_host_src.js
+ file_websocket_self.html
+ file_websocket_explicit.html
+ file_websocket_self_wsh.py
[test_base-uri.html]
[test_blob_data_schemes.html]
@@ -228,6 +242,7 @@ skip-if = toolkit == 'android' # Times out, not sure why (bug 1008445)
[test_bug910139.html]
[test_bug909029.html]
[test_bug1229639.html]
+[test_frame_ancestors_ro.html]
[test_policyuri_regression_from_multipolicy.html]
[test_nonce_source.html]
[test_bug941404.html]
@@ -292,9 +307,30 @@ tags = mcb
[test_strict_dynamic.html]
[test_strict_dynamic_parser_inserted.html]
[test_strict_dynamic_default_src.html]
+[test_upgrade_insecure_navigation.html]
[test_iframe_sandbox_srcdoc.html]
[test_iframe_srcdoc.html]
[test_sandbox_allow_scripts.html]
support-files =
file_sandbox_allow_scripts.html
file_sandbox_allow_scripts.html^headers^
+[test_ignore_xfo.html]
+[test_image_nonce.html]
+[test_punycode_host_src.html]
+[test_websocket_self.html]
+skip-if = toolkit == 'android'
+[test_worker_src.html]
+support-files =
+ file_worker_src_worker_governs.html
+ file_worker_src_child_governs.html
+ file_worker_src_script_governs.html
+ file_worker_src.js
+ file_spawn_worker.js
+ file_spawn_shared_worker.js
+ file_spawn_service_worker.js
+[test_frame_src.html]
+support-files =
+ file_frame_src_frame_governs.html
+ file_frame_src_child_governs.html
+ file_frame_src.js
+ file_frame_src_inner.html
diff --git a/dom/security/test/csp/test_child-src_worker.html b/dom/security/test/csp/test_child-src_worker.html
index 7dcbd03f6..ea9e7b28e 100644
--- a/dom/security/test/csp/test_child-src_worker.html
+++ b/dom/security/test/csp/test_child-src_worker.html
@@ -83,19 +83,19 @@
id: "script-src-worker",
file: WORKER_TEST_FILE,
result : "blocked",
- policy : "default-src 'none'; script-src 'self' 'unsafe-inline'"
+ policy : "default-src 'none'; script-src https://www.example.org 'unsafe-inline'"
},
'script-src-service_worker': {
id: "script-src-service_worker",
file: SERVICE_WORKER_TEST_FILE,
result : "blocked",
- policy : "default-src 'none'; script-src 'self' 'unsafe-inline'"
+ policy : "default-src 'none'; script-src https://www.example.org 'unsafe-inline'"
},
'script-src-self-shared_worker': {
id: "script-src-self-shared_worker",
file: SHARED_WORKER_TEST_FILE,
result : "blocked",
- policy : "default-src 'none'; script-src 'self' 'unsafe-inline'"
+ policy : "default-src 'none'; script-src https://www.example.org 'unsafe-inline'"
},
};
diff --git a/dom/security/test/csp/test_frame_ancestors_ro.html b/dom/security/test/csp/test_frame_ancestors_ro.html
new file mode 100644
index 000000000..90f68e25e
--- /dev/null
+++ b/dom/security/test/csp/test_frame_ancestors_ro.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for frame-ancestors support in Content-Security-Policy-Report-Only</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width: 100%" id="cspframe"></iframe>
+<script type="text/javascript">
+const docUri = "http://mochi.test:8888/tests/dom/security/test/csp/file_frame_ancestors_ro.html";
+const frame = document.getElementById("cspframe");
+
+let testResults = {
+ reportFired: false,
+ frameLoaded: false
+};
+
+function checkResults(reportObj) {
+ let cspReport = reportObj["csp-report"];
+ is(cspReport["document-uri"], docUri, "Incorrect document-uri");
+
+ // we can not test for the whole referrer since it includes platform specific information
+ is(cspReport["referrer"], document.location.toString(), "Incorrect referrer");
+ is(cspReport["blocked-uri"], document.location.toString(), "Incorrect blocked-uri");
+ is(cspReport["violated-directive"], "frame-ancestors 'none'", "Incorrect violated-directive");
+ is(cspReport["original-policy"], "frame-ancestors 'none'; report-uri http://mochi.test:8888/foo.sjs", "Incorrect original-policy");
+ testResults.reportFired = true;
+}
+
+let chromeScriptUrl = SimpleTest.getTestFileURL("file_report_chromescript.js");
+let script = SpecialPowers.loadChromeScript(chromeScriptUrl);
+
+script.addMessageListener('opening-request-completed', function ml(msg) {
+ if (msg.error) {
+ ok(false, "Could not query report (exception: " + msg.error + ")");
+ } else {
+ try {
+ let reportObj = JSON.parse(msg.report);
+ // test for the proper values in the report object
+ checkResults(reportObj);
+ } catch (e) {
+ ok(false, "Error verifying report object (exception: " + e + ")");
+ }
+ }
+
+ script.removeMessageListener('opening-request-completed', ml);
+ script.sendAsyncMessage("finish");
+ checkTestResults();
+});
+
+frame.addEventListener( 'load', () => {
+ // Make sure the frame is still loaded
+ testResults.frameLoaded = true;
+ checkTestResults()
+} );
+
+function checkTestResults() {
+ if( testResults.reportFired && testResults.frameLoaded ) {
+ SimpleTest.finish();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+frame.src = docUri;
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_frame_src.html b/dom/security/test/csp/test_frame_src.html
new file mode 100644
index 000000000..07de90cfa
--- /dev/null
+++ b/dom/security/test/csp/test_frame_src.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1302667 - Test frame-src</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load a page inlcuding a frame a CSP of:
+ * >> frame-src https://example.com; child-src 'none'
+ * and make sure that frame-src governs frames correctly. In addition,
+ * we make sure that child-src is discarded in case frame-src is specified.
+ */
+
+const ORIGIN_1 = "https://example.com/tests/dom/security/test/csp/";
+const ORIGIN_2 = "https://test1.example.com/tests/dom/security/test/csp/";
+
+let TESTS = [
+ // frame-src tests
+ ORIGIN_1 + "file_frame_src_frame_governs.html",
+ ORIGIN_2 + "file_frame_src_frame_governs.html",
+ // child-src tests
+ ORIGIN_1 + "file_frame_src_child_governs.html",
+ ORIGIN_2 + "file_frame_src_child_governs.html",
+];
+
+let testIndex = 0;
+
+function checkFinish() {
+ if (testIndex >= TESTS.length) {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+ return;
+ }
+ runNextTest();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ let href = event.data.href;
+ let result = event.data.result;
+
+ if (href.startsWith("https://example.com")) {
+ if (result == "frame-allowed") {
+ ok(true, "allowing frame from https://example.com (" + result + ")");
+ }
+ else {
+ ok(false, "blocking frame from https://example.com (" + result + ")");
+ }
+ }
+ else if (href.startsWith("https://test1.example.com")) {
+ if (result == "frame-blocked") {
+ ok(true, "blocking frame from https://test1.example.com (" + result + ")");
+ }
+ else {
+ ok(false, "allowing frame from https://test1.example.com (" + result + ")");
+ }
+ }
+ else {
+ // sanity check, we should never enter that branch, bust just in case...
+ ok(false, "unexpected result: " + result);
+ }
+ checkFinish();
+}
+
+function runNextTest() {
+ document.getElementById("testframe").src = TESTS[testIndex];
+ testIndex++;
+}
+
+// fire up the tests
+runNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_ignore_xfo.html b/dom/security/test/csp/test_ignore_xfo.html
new file mode 100644
index 000000000..fb3aadc6c
--- /dev/null
+++ b/dom/security/test/csp/test_ignore_xfo.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1024557: Ignore x-frame-options if CSP with frame-ancestors exists</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="csp_testframe"></iframe>
+<iframe style="width:100%;" id="csp_ro_testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * We load two frames using:
+ * x-frame-options: deny
+ * where the first frame uses a csp and the second a csp_ro including frame-ancestors.
+ * We make sure that xfo is ignored for regular csp but not for csp_ro.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var testcounter = 0;
+function checkFinished() {
+ testcounter++;
+ if (testcounter < 2) {
+ return;
+ }
+ SimpleTest.finish();
+}
+
+// 1) test XFO with CSP
+var csp_testframe = document.getElementById("csp_testframe");
+csp_testframe.onload = function() {
+ var msg = csp_testframe.contentWindow.document.getElementById("cspmessage");
+ is(msg.innerHTML, "Ignoring XFO because of CSP", "Loading frame with with XFO and CSP");
+ checkFinished();
+}
+csp_testframe.onerror = function() {
+ ok(false, "sanity: should not fire onerror for csp_testframe");
+}
+csp_testframe.src = "file_ignore_xfo.html";
+
+// 2) test XFO with CSP_RO
+var csp_ro_testframe = document.getElementById("csp_ro_testframe");
+csp_ro_testframe.onload = function() {
+ var msg = csp_ro_testframe.contentWindow.document.getElementById("cspmessage");
+ is(msg, null, "Blocking frame with with XFO and CSP_RO");
+ checkFinished();
+}
+csp_ro_testframe.onerror = function() {
+ ok(false, "sanity: should not fire onerror for csp_ro_testframe");
+}
+csp_ro_testframe.src = "file_ro_ignore_xfo.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_image_nonce.html b/dom/security/test/csp/test_image_nonce.html
new file mode 100644
index 000000000..ff6d636b6
--- /dev/null
+++ b/dom/security/test/csp/test_image_nonce.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load three images: (a) with a matching nonce,
+ (b) with a non matching nonce,
+ * (c) with no nonce
+ * and make sure that all three images get blocked because
+ * "img-src nonce-bla" should not allow an image load, not
+ * even if the nonce matches*.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var counter = 0;
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+function checkResults(aResult) {
+ counter++;
+ if (aResult === "img-with-matching-nonce-blocked" ||
+ aResult === "img-with_non-matching-nonce-blocked" ||
+ aResult === "img-without-nonce-blocked") {
+ ok (true, "correct result for: " + aResult);
+ }
+ else {
+ ok(false, "unexpected result: " + aResult + "\n\n");
+ }
+ if (counter < 3) {
+ return;
+ }
+ finishTest();
+}
+
+// a postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to bubble up results back to this main page.
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+document.getElementById("testframe").src = "file_image_nonce.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_punycode_host_src.html b/dom/security/test/csp/test_punycode_host_src.html
new file mode 100644
index 000000000..8d891725c
--- /dev/null
+++ b/dom/security/test/csp/test_punycode_host_src.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1224225 - CSP source matching should work for punycoded domain names</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load scripts within an iframe and make sure that the
+ * CSP matching is same for punycode domain names as well as IDNA.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+
+var curTest;
+var counter = -1;
+
+const tests = [
+ { // test 1
+ description: "loads script as sub2.ält.example.org, but whitelist in CSP as sub2.xn--lt-uia.example.org",
+ action: "script-unicode-csp-punycode",
+ csp: "script-src http://sub2.xn--lt-uia.example.org;",
+ expected: "script-allowed",
+
+ },
+ { // test 2
+ description: "loads script as sub2.xn--lt-uia.example.org, and whitelist in CSP as sub2.xn--lt-uia.example.org",
+ action: "script-punycode-csp-punycode",
+ csp: "script-src http://sub2.xn--lt-uia.example.org;",
+ expected: "script-allowed",
+
+ },
+ { // test 3
+ description: "loads script as sub2.xn--lt-uia.example.org, and whitelist in CSP as sub2.xn--lt-uia.example.org",
+ action: "script-punycode-csp-punycode",
+ csp: "script-src *.xn--lt-uia.example.org;",
+ expected: "script-allowed",
+
+ },
+
+];
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+function checkResults(result) {
+ is(result, curTest.expected, curTest.description);
+ loadNextTest();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+function loadNextTest() {
+ counter++;
+ if (counter == tests.length) {
+ finishTest();
+ return;
+ }
+ curTest = tests[counter];
+ var testframe = document.getElementById("testframe");
+ testframe.src = `file_punycode_host_src.sjs?action=${curTest.action}&csp=${curTest.csp}`;
+}
+
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_upgrade_insecure_navigation.html b/dom/security/test/csp/test_upgrade_insecure_navigation.html
new file mode 100644
index 000000000..db6a6a1be
--- /dev/null
+++ b/dom/security/test/csp/test_upgrade_insecure_navigation.html
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1271173 - Missing spec on Upgrade Insecure Requests(Navigational Upgrades) </title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+<iframe style="width:100%;" id="sandboxedtestframe"
+ sandbox="allow-scripts allow-top-navigation allow-same-origin allow-pointer-lock allow-popups"></iframe>
+
+<script class="testbody" type="text/javascript">
+/*
+ * Description of the test:
+ * We load a page into an iframe that performs a navigational request.
+ * We make sure that upgrade-insecure-requests applies and the page
+ * gets upgraded to https if same origin.
+ * Please note that uir only applies to sandboxed iframes if
+ * the value 'allow-same-origin' is specified.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var tests = [
+ {
+ csp: "upgrade-insecure-requests;",
+ result: "https",
+ origin: "http://example.com",
+ desc: "upgrade-insecure-requests same origin should upgrade"
+ },
+ {
+ csp: "",
+ result: "http",
+ origin: "http://example.com",
+ desc: "No upgrade-insecure-requests same origin should not upgrade"
+ },
+ {
+ csp: "upgrade-insecure-requests;",
+ result: "http",
+ origin: "http://mochi.test:8888",
+ desc: "upgrade-insecure-requests cross origin should not upgrade"
+ },
+ {
+ csp: "",
+ result: "http",
+ origin: "http://mochi.test:8888",
+ desc: "No upgrade-insecure-requests cross origin should not upgrade"
+ },
+];
+
+// initializing to -1 so we start at index 0 when we start the test
+var counter = -1;
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage, false);
+ SimpleTest.finish();
+}
+
+var subtests = 0;
+
+window.addEventListener("message", receiveMessage, false);
+function receiveMessage(event) {
+ var result = event.data.result;
+ // query the scheme from the URL before comparing the result
+ var scheme = result.substring(0, result.indexOf(":"));
+ is(scheme, tests[counter].result, tests[counter].desc);
+
+ // @hardcoded 4:
+ // each test run contains of two subtests (frame and top-level)
+ // and we load each test into a regular iframe and into a
+ // sandboxed iframe. only move on to the next test once all
+ // four results from the subtests have bubbled up.
+ subtests++;
+ if (subtests != 4) {
+ return;
+ }
+ subtests = 0;
+ loadNextTest();
+}
+
+function loadNextTest() {
+ counter++;
+ if (counter == tests.length) {
+ finishTest();
+ return;
+ }
+
+ var src = tests[counter].origin;
+ src += "/tests/dom/security/test/csp/file_upgrade_insecure_navigation.sjs";
+ src += "?csp=" + escape(tests[counter].csp);
+ src += "&action=perform_navigation";
+ document.getElementById("testframe").src = src;
+ document.getElementById("sandboxedtestframe").src = src;
+}
+
+// start running the tests
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_websocket_self.html b/dom/security/test/csp/test_websocket_self.html
new file mode 100644
index 000000000..a03c32704
--- /dev/null
+++ b/dom/security/test/csp/test_websocket_self.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1345615: Allow websocket schemes when using 'self' in CSP</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="test_ws_self_frame"></iframe>
+<iframe style="width:100%;" id="test_ws_explicit_frame"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load an iframe using connect-src 'self' and one
+ * iframe using connect-src ws: and make
+ * sure that in both cases ws: as well as wss: is allowed to load.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+const TOTAL_TESTS = 4;
+var counter = 0;
+
+function checkResults(result) {
+ counter++;
+ if (result === "self-ws-loaded" || result === "self-wss-loaded" ||
+ result === "explicit-ws-loaded" || result === "explicit-wss-loaded") {
+ ok(true, "Evaluating: " + result);
+ }
+ else {
+ ok(false, "Evaluating: " + result);
+ }
+ if (counter < TOTAL_TESTS) {
+ return;
+ }
+ finishTest();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+const HOST = "http://example.com/tests/dom/security/test/csp/";
+var test_ws_self_frame = document.getElementById("test_ws_self_frame");
+test_ws_self_frame.src = HOST + "file_websocket_self.html";
+
+var test_ws_explicit_frame = document.getElementById("test_ws_explicit_frame");
+test_ws_explicit_frame.src = HOST + "file_websocket_explicit.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_worker_src.html b/dom/security/test/csp/test_worker_src.html
new file mode 100644
index 000000000..3f2b44c9f
--- /dev/null
+++ b/dom/security/test/csp/test_worker_src.html
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1302667 - Test worker-src</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="worker-testframe"></iframe>
+<iframe style="width:100%;" id="child-testframe"></iframe>
+<iframe style="width:100%;" id="script-testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load a page inlcuding a worker, a shared worker as well as a
+ * service worker with a CSP of:
+ * >> worker-src https://example.com; child-src 'none'; script-src 'nonce-foo'
+ * and make sure that worker-src governs these three kinds of workers correctly.
+ * In addition, we make sure that child-src as well as script-src is discarded
+ * in case worker-src is specified. Ideally we would use "script-src 'none'" but
+ * we have to whitelist the actual script that spawns the workers, hence the nonce.
+ */
+
+let testRuns = 0;
+let messageCounter = 0;
+let numberSubTests = 9; // 3 workers * 3 frames = 9
+
+function checkFinish() {
+ messageCounter = 0;
+ if (testRuns == 0) {
+ testRuns++;
+ runTests("https://test1.example.com/tests/dom/security/test/csp/")
+ return;
+ }
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ let href = event.data.href;
+ let result = event.data.result;
+
+ if (href.startsWith("https://example.com")) {
+ if (result == "worker-allowed" ||
+ result == "shared-worker-allowed" ||
+ result == "service-worker-allowed") {
+ ok(true, "allowing worker from https://example.com (" + result + ")");
+ }
+ else {
+ ok(false, "blocking worker from https://example.com (" + result + ")");
+ }
+ }
+ else if (href.startsWith("https://test1.example.com")) {
+ if (result == "worker-blocked" ||
+ result == "shared-worker-blocked" ||
+ result == "service-worker-blocked") {
+ ok(true, "blocking worker from https://test1.example.com (" + result + ")");
+ }
+ else {
+ ok(false, "allowing worker from https://test1.example.com (" + result + ")");
+ }
+ }
+ else {
+ // sanity check, we should never enter that branch, bust just in case...
+ ok(false, "unexpected result: " + result);
+ }
+ messageCounter++;
+ if (messageCounter < numberSubTests) {
+ return;
+ }
+ checkFinish();
+}
+
+function runTests(aPath) {
+ document.getElementById("worker-testframe").src = aPath + "file_worker_src_worker_governs.html";
+ document.getElementById("child-testframe").src = aPath + "file_worker_src_child_governs.html";
+ document.getElementById("script-testframe").src = aPath + "file_worker_src_script_governs.html";
+}
+
+SpecialPowers.pushPrefEnv({"set": [
+ ["dom.serviceWorkers.enabled", true],
+ ["dom.serviceWorkers.testing.enabled", true],
+]}, function() {
+ runTests("https://example.com/tests/dom/security/test/csp/");
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/browser.ini b/dom/security/test/general/browser.ini
new file mode 100644
index 000000000..b00baa95d
--- /dev/null
+++ b/dom/security/test/general/browser.ini
@@ -0,0 +1,14 @@
+[DEFAULT]
+[browser_test_toplevel_data_navigations.js]
+support-files =
+ file_toplevel_data_navigations.sjs
+ file_toplevel_data_meta_redirect.html
+[browser_test_data_download.js]
+support-files =
+ file_data_download.html
+[browser_test_data_text_csv.js]
+support-files =
+ file_data_text_csv.html
+[browser_test_view_image_data_navigation.js]
+support-files =
+ file_view_image_data_navigation.html
diff --git a/dom/security/test/general/browser_test_data_download.js b/dom/security/test/general/browser_test_data_download.js
new file mode 100644
index 000000000..1ee8d5844
--- /dev/null
+++ b/dom/security/test/general/browser_test_data_download.js
@@ -0,0 +1,37 @@
+"use strict";
+
+const kTestPath = getRootDirectory(gTestPath)
+ .replace("chrome://mochitests/content", "http://example.com")
+const kTestURI = kTestPath + "file_data_download.html";
+
+function addWindowListener(aURL, aCallback) {
+ Services.wm.addListener({
+ onOpenWindow(aXULWindow) {
+ info("window opened, waiting for focus");
+ Services.wm.removeListener(this);
+ var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ waitForFocus(function() {
+ is(domwindow.document.location.href, aURL, "should have seen the right window open");
+ aCallback(domwindow);
+ }, domwindow);
+ },
+ onCloseWindow(aXULWindow) { },
+ onWindowTitleChange(aXULWindow, aNewTitle) { }
+ });
+}
+
+function test() {
+ waitForExplicitFinish();
+ Services.prefs.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
+ registerCleanupFunction(function() {
+ Services.prefs.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
+ });
+ addWindowListener("chrome://mozapps/content/downloads/unknownContentType.xul", function(win) {
+ is(win.document.getElementById("location").value, "data-foo.html",
+ "file name of download should match");
+ win.close();
+ finish();
+ });
+ gBrowser.loadURI(kTestURI);
+}
diff --git a/dom/security/test/general/browser_test_data_text_csv.js b/dom/security/test/general/browser_test_data_text_csv.js
new file mode 100644
index 000000000..c45e40cc2
--- /dev/null
+++ b/dom/security/test/general/browser_test_data_text_csv.js
@@ -0,0 +1,37 @@
+"use strict";
+
+const kTestPath = getRootDirectory(gTestPath)
+ .replace("chrome://mochitests/content", "http://example.com")
+const kTestURI = kTestPath + "file_data_text_csv.html";
+
+function addWindowListener(aURL, aCallback) {
+ Services.wm.addListener({
+ onOpenWindow(aXULWindow) {
+ info("window opened, waiting for focus");
+ Services.wm.removeListener(this);
+ var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ waitForFocus(function() {
+ is(domwindow.document.location.href, aURL, "should have seen the right window open");
+ aCallback(domwindow);
+ }, domwindow);
+ },
+ onCloseWindow(aXULWindow) { },
+ onWindowTitleChange(aXULWindow, aNewTitle) { }
+ });
+}
+
+function test() {
+ waitForExplicitFinish();
+ Services.prefs.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
+ registerCleanupFunction(function() {
+ Services.prefs.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
+ });
+ addWindowListener("chrome://mozapps/content/downloads/unknownContentType.xul", function(win) {
+ is(win.document.getElementById("location").value, "text/csv;foo,bar,foobar",
+ "file name of download should match");
+ win.close();
+ finish();
+ });
+ gBrowser.loadURI(kTestURI);
+}
diff --git a/dom/security/test/general/browser_test_toplevel_data_navigations.js b/dom/security/test/general/browser_test_toplevel_data_navigations.js
new file mode 100644
index 000000000..a13a6350e
--- /dev/null
+++ b/dom/security/test/general/browser_test_toplevel_data_navigations.js
@@ -0,0 +1,54 @@
+/* eslint-disable mozilla/no-arbitrary-setTimeout */
+
+"use strict";
+
+const kDataBody = "toplevel navigation to data: URI allowed";
+const kDataURI = "data:text/html,<body>" + kDataBody + "</body>";
+const kTestPath = getRootDirectory(gTestPath)
+ .replace("chrome://mochitests/content", "http://example.com")
+const kRedirectURI = kTestPath + "file_toplevel_data_navigations.sjs";
+const kMetaRedirectURI = kTestPath + "file_toplevel_data_meta_redirect.html";
+
+add_task(async function test_nav_data_uri() {
+ await SpecialPowers.pushPrefEnv({
+ "set": [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+ await BrowserTestUtils.withNewTab(kDataURI, async function(browser) {
+ await ContentTask.spawn(gBrowser.selectedBrowser, {kDataBody}, async function({kDataBody}) { // eslint-disable-line
+ is(content.document.body.innerHTML, kDataBody,
+ "data: URI navigation from system should be allowed");
+ });
+ });
+});
+
+add_task(async function test_nav_data_uri_redirect() {
+ await SpecialPowers.pushPrefEnv({
+ "set": [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+ let tab = BrowserTestUtils.addTab(gBrowser, kRedirectURI);
+ registerCleanupFunction(async function() {
+ await BrowserTestUtils.removeTab(tab);
+ });
+ // wait to make sure data: URI did not load before checking that it got blocked
+ await new Promise(resolve => setTimeout(resolve, 500));
+ await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() {
+ is(content.document.body.innerHTML, "",
+ "data: URI navigation after server redirect should be blocked");
+ });
+});
+
+add_task(async function test_nav_data_uri_meta_redirect() {
+ await SpecialPowers.pushPrefEnv({
+ "set": [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+ let tab = BrowserTestUtils.addTab(gBrowser, kMetaRedirectURI);
+ registerCleanupFunction(async function() {
+ await BrowserTestUtils.removeTab(tab);
+ });
+ // wait to make sure data: URI did not load before checking that it got blocked
+ await new Promise(resolve => setTimeout(resolve, 500));
+ await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() {
+ is(content.document.body.innerHTML, "",
+ "data: URI navigation after meta redirect should be blocked");
+ });
+});
diff --git a/dom/security/test/general/browser_test_view_image_data_navigation.js b/dom/security/test/general/browser_test_view_image_data_navigation.js
new file mode 100644
index 000000000..22de35894
--- /dev/null
+++ b/dom/security/test/general/browser_test_view_image_data_navigation.js
@@ -0,0 +1,30 @@
+"use strict";
+
+const TEST_PAGE = getRootDirectory(gTestPath) + "file_view_image_data_navigation.html";
+
+add_task(async function test_principal_right_click_open_link_in_new_tab() {
+ await SpecialPowers.pushPrefEnv({
+ "set": [["security.data_uri.block_toplevel_data_uri_navigations", true]],
+ });
+
+ await BrowserTestUtils.withNewTab(TEST_PAGE, async function(browser) {
+ let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, true);
+
+ // simulate right-click->view-image
+ BrowserTestUtils.waitForEvent(document, "popupshown", false, event => {
+ // These are operations that must be executed synchronously with the event.
+ document.getElementById("context-viewimage").doCommand();
+ event.target.hidePopup();
+ return true;
+ });
+ BrowserTestUtils.synthesizeMouseAtCenter("#testimage",
+ { type: "contextmenu", button: 2 },
+ gBrowser.selectedBrowser);
+ await loadPromise;
+
+ await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() {
+ ok(content.document.location.toString().startsWith("data:image/svg+xml;"),
+ "data:image/svg navigation allowed through right-click view-image")
+ });
+ });
+});
diff --git a/dom/security/test/general/file_block_toplevel_data_navigation.html b/dom/security/test/general/file_block_toplevel_data_navigation.html
new file mode 100644
index 000000000..5fbfdfdef
--- /dev/null
+++ b/dom/security/test/general/file_block_toplevel_data_navigation.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Toplevel data navigation</title>
+</head>
+<body>
+test1: clicking data: URI tries to navigate window<br/>
+<a id="testlink" href="data:text/html,<body>toplevel data: URI navigations should be blocked</body>">click me</a>
+<script>
+ document.getElementById('testlink').click();
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_block_toplevel_data_navigation2.html b/dom/security/test/general/file_block_toplevel_data_navigation2.html
new file mode 100644
index 000000000..e0308e1ae
--- /dev/null
+++ b/dom/security/test/general/file_block_toplevel_data_navigation2.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Toplevel data navigation</title>
+</head>
+<body>
+test2: data: URI in iframe tries to window.open(data:, _blank);<br/>
+<iframe id="testFrame" src=""></iframe>
+<script>
+ let DATA_URI = `data:text/html,<body><script>
+ var win = window.open("data:text/html,<body>toplevel data: URI navigations should be blocked</body>", "_blank");
+ setTimeout(function () {
+ var result = win.document.body.innerHTML === "" ? "blocked" : "navigated";
+ parent.postMessage(result, "*");
+ win.close();
+ }, 1000);
+ <\/script></body>`;
+
+ window.addEventListener("message", receiveMessage);
+ function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ // propagate the information back to the caller
+ window.opener.postMessage(event.data, "*");
+ }
+ document.getElementById('testFrame').src = DATA_URI;
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_block_toplevel_data_navigation3.html b/dom/security/test/general/file_block_toplevel_data_navigation3.html
new file mode 100644
index 000000000..34aeddab3
--- /dev/null
+++ b/dom/security/test/general/file_block_toplevel_data_navigation3.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Toplevel data navigation</title>
+</head>
+<body>
+test3: performing data: URI navigation through win.loc.href<br/>
+<script>
+ window.location.href = "data:text/html,<body>toplevel data: URI navigations should be blocked</body>";
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/file_block_toplevel_data_redirect.sjs b/dom/security/test/general/file_block_toplevel_data_redirect.sjs
new file mode 100644
index 000000000..64e294cab
--- /dev/null
+++ b/dom/security/test/general/file_block_toplevel_data_redirect.sjs
@@ -0,0 +1,14 @@
+// Custom *.sjs file specifically for the needs of Bug:
+// Bug 1394554 - Block toplevel data: URI navigations after redirect
+
+var DATA_URI =
+ "<body>toplevel data: URI navigations after redirect should be blocked</body>";
+
+function handleRequest(request, response)
+{
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", "data:text/html," + escape(DATA_URI), false);
+}
diff --git a/dom/security/test/general/file_data_download.html b/dom/security/test/general/file_data_download.html
new file mode 100644
index 000000000..4cc92fe8f
--- /dev/null
+++ b/dom/security/test/general/file_data_download.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test download attribute for data: URI</title>
+</head>
+<body>
+ <a href="data:text/html,<body>data download</body>" download="data-foo.html" id="testlink">download data</a>
+ <script>
+ // click the link to have the downoad panel appear
+ let testlink = document.getElementById("testlink");
+ testlink.click();
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/general/file_data_text_csv.html b/dom/security/test/general/file_data_text_csv.html
new file mode 100644
index 000000000..a9ac369d1
--- /dev/null
+++ b/dom/security/test/general/file_data_text_csv.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test open data:text/csv</title>
+</head>
+<body>
+ <a href="data:text/csv;foo,bar,foobar" id="testlink">test text/csv</a>
+ <script>
+ // click the link to have the downoad panel appear
+ let testlink = document.getElementById("testlink");
+ testlink.click();
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/general/file_toplevel_data_meta_redirect.html b/dom/security/test/general/file_toplevel_data_meta_redirect.html
new file mode 100644
index 000000000..f4f5deb52
--- /dev/null
+++ b/dom/security/test/general/file_toplevel_data_meta_redirect.html
@@ -0,0 +1,10 @@
+<html>
+<body>
+<head>
+ <meta http-equiv="refresh"
+ content="0; url='data:text/html,<body>toplevel meta redirect to data: URI should be blocked</body>'">
+</head>
+<body>
+Meta Redirect to data: URI
+</body>
+</html>
diff --git a/dom/security/test/general/file_toplevel_data_navigations.sjs b/dom/security/test/general/file_toplevel_data_navigations.sjs
new file mode 100644
index 000000000..501b833e5
--- /dev/null
+++ b/dom/security/test/general/file_toplevel_data_navigations.sjs
@@ -0,0 +1,14 @@
+// Custom *.sjs file specifically for the needs of Bug:
+// Bug 1394554 - Block toplevel data: URI navigations after redirect
+
+var DATA_URI =
+ "data:text/html,<body>toplevel data: URI navigations after redirect should be blocked</body>";
+
+function handleRequest(request, response)
+{
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", DATA_URI, false);
+}
diff --git a/dom/security/test/general/file_view_image_data_navigation.html b/dom/security/test/general/file_view_image_data_navigation.html
new file mode 100644
index 000000000..a3f9acfb4
--- /dev/null
+++ b/dom/security/test/general/file_view_image_data_navigation.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1407891: Test navigation for right-click view-image on data:image/svg</title>
+</head>
+<body>
+
+<img id="testimage" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg=="></img>
+
+</body>
+</html>
diff --git a/dom/security/test/general/mochitest.ini b/dom/security/test/general/mochitest.ini
index 70c0c9fb6..f3bcca072 100644
--- a/dom/security/test/general/mochitest.ini
+++ b/dom/security/test/general/mochitest.ini
@@ -3,7 +3,19 @@ support-files =
file_contentpolicytype_targeted_link_iframe.sjs
file_nosniff_testserver.sjs
file_block_script_wrong_mime_server.sjs
+ file_block_toplevel_data_navigation.html
+ file_block_toplevel_data_navigation2.html
+ file_block_toplevel_data_navigation3.html
+ file_block_toplevel_data_redirect.sjs
[test_contentpolicytype_targeted_link_iframe.html]
[test_nosniff.html]
[test_block_script_wrong_mime.html]
+[test_block_toplevel_data_navigation.html]
+skip-if = toolkit == 'android' # intermittent failure
+[test_block_toplevel_data_img_navigation.html]
+skip-if = toolkit == 'android' # intermittent failure
+[test_allow_opening_data_pdf.html]
+skip-if = toolkit == 'android'
+[test_allow_opening_data_json.html]
+skip-if = toolkit == 'android'
diff --git a/dom/security/test/general/test_allow_opening_data_json.html b/dom/security/test/general/test_allow_opening_data_json.html
new file mode 100644
index 000000000..1530a24e8
--- /dev/null
+++ b/dom/security/test/general/test_allow_opening_data_json.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1403814: Allow toplevel data URI navigation data:application/json</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function test_toplevel_data_json() {
+ const DATA_JSON = "data:application/json,{'my_json_key':'my_json_value'}";
+
+ let win = window.open(DATA_JSON);
+ let wrappedWin = SpecialPowers.wrap(win);
+
+ // Unfortunately we can't detect whether the JSON has loaded or not using some
+ // event, hence we are constantly polling location.href till we see that
+ // the data: URI appears. Test times out on failure.
+ var jsonLoaded = setInterval(function() {
+ if (wrappedWin.document.location.href.startsWith("data:application/json")) {
+ clearInterval(jsonLoaded);
+ ok(true, "navigating to data:application/json allowed");
+ wrappedWin.close();
+ SimpleTest.finish();
+ }
+ }, 200);
+}
+
+SpecialPowers.pushPrefEnv({
+ set: [["security.data_uri.block_toplevel_data_uri_navigations", true]]
+}, test_toplevel_data_json);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_allow_opening_data_pdf.html b/dom/security/test/general/test_allow_opening_data_pdf.html
new file mode 100644
index 000000000..6b51fe57b
--- /dev/null
+++ b/dom/security/test/general/test_allow_opening_data_pdf.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1398692: Allow toplevel navigation to a data:application/pdf</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function test_toplevel_data_pdf() {
+ // The PDF contains one page and it is a 3/72" square, the minimum allowed by the spec
+ const DATA_PDF =
+ "data:application/pdf;base64,JVBERi0xLjANCjEgMCBvYmo8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFI+PmVuZG9iaiAyIDAgb2JqPDwvVHlwZS9QYWdlcy9LaWRzWzMgMCBSXS9Db3VudCAxPj5lbmRvYmogMyAwIG9iajw8L1R5cGUvUGFnZS9NZWRpYUJveFswIDAgMyAzXT4+ZW5kb2JqDQp4cmVmDQowIDQNCjAwMDAwMDAwMDAgNjU1MzUgZg0KMDAwMDAwMDAxMCAwMDAwMCBuDQowMDAwMDAwMDUzIDAwMDAwIG4NCjAwMDAwMDAxMDIgMDAwMDAgbg0KdHJhaWxlcjw8L1NpemUgNC9Sb290IDEgMCBSPj4NCnN0YXJ0eHJlZg0KMTQ5DQolRU9G";
+
+ let win = window.open(DATA_PDF);
+ let wrappedWin = SpecialPowers.wrap(win);
+
+ // Unfortunately we can't detect whether the PDF has loaded or not using some
+ // event, hence we are constantly polling location.href till we see that
+ // the data: URI appears. Test times out on failure.
+ var pdfLoaded = setInterval(function() {
+ if (wrappedWin.document.location.href.startsWith("data:application/pdf")) {
+ clearInterval(pdfLoaded);
+ ok(true, "navigating to data:application/pdf allowed");
+ wrappedWin.close();
+ SimpleTest.finish();
+ }
+ }, 200);
+}
+
+SpecialPowers.pushPrefEnv({
+ set: [["security.data_uri.block_toplevel_data_uri_navigations", true]]
+}, test_toplevel_data_pdf);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_block_script_wrong_mime.html b/dom/security/test/general/test_block_script_wrong_mime.html
index f4da9c577..34d4b621b 100644
--- a/dom/security/test/general/test_block_script_wrong_mime.html
+++ b/dom/security/test/general/test_block_script_wrong_mime.html
@@ -53,9 +53,6 @@ function testWorker([mime, shouldLoad]) {
};
worker.onerror = (error) => {
ok(!shouldLoad, `worker with wrong mime '${mime}' should be blocked`);
- let msg = error.message;
- ok(msg.match(/^NetworkError/) || msg.match(/Failed to load worker script/),
- "should gets correct error message");
error.preventDefault();
resolve();
}
@@ -74,9 +71,6 @@ function testWorkerImportScripts([mime, shouldLoad]) {
};
worker.onerror = (error) => {
ok(!shouldLoad, `worker/importScripts with wrong mime '${mime}' should be blocked`);
- let msg = error.message;
- ok(msg.match(/^NetworkError/) || msg.match(/Failed to load worker script/),
- "should gets correct error message");
error.preventDefault();
resolve();
}
diff --git a/dom/security/test/general/test_block_toplevel_data_img_navigation.html b/dom/security/test/general/test_block_toplevel_data_img_navigation.html
new file mode 100644
index 000000000..7f8dfc748
--- /dev/null
+++ b/dom/security/test/general/test_block_toplevel_data_img_navigation.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1396798: Do not block toplevel data: navigation to image (except svgs)</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+SpecialPowers.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
+SimpleTest.registerCleanupFunction(() => {
+ SpecialPowers.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
+});
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("have to test that top level data:image loading is blocked/allowed");
+
+function test_toplevel_data_image() {
+ const DATA_PNG =
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
+ let win1 = window.open(DATA_PNG);
+ let wrappedWin1 = SpecialPowers.wrap(win1);
+ setTimeout(function () {
+ let images = wrappedWin1.document.getElementsByTagName('img');
+ is(images.length, 1, "Loading data:image/png should be allowed");
+ is(images[0].src, DATA_PNG, "Sanity: img src matches");
+ wrappedWin1.close();
+ test_toplevel_data_image_svg();
+ }, 1000);
+}
+
+function test_toplevel_data_image_svg() {
+ const DATA_SVG =
+ "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg==";
+ let win2 = window.open(DATA_SVG);
+ // Unfortunately we can't detect whether the window was closed using some event,
+ // hence we are constantly polling till we see that win == null.
+ // Test times out on failure.
+ var win2Closed = setInterval(function() {
+ if (win2 == null || win2.closed) {
+ clearInterval(win2Closed);
+ ok(true, "Loading data:image/svg+xml should be blocked");
+ SimpleTest.finish();
+ }
+ }, 200);
+}
+// fire up the tests
+test_toplevel_data_image();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_block_toplevel_data_navigation.html b/dom/security/test/general/test_block_toplevel_data_navigation.html
new file mode 100644
index 000000000..cef232b65
--- /dev/null
+++ b/dom/security/test/general/test_block_toplevel_data_navigation.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1331351 - Block top level window data: URI navigations</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+SpecialPowers.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
+SimpleTest.registerCleanupFunction(() => {
+ SpecialPowers.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
+});
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("have to test that top level data: URI navgiation is blocked");
+
+function test1() {
+ // simple data: URI click navigation should be prevented
+ let TEST_FILE = "file_block_toplevel_data_navigation.html";
+ let win1 = window.open(TEST_FILE);
+ setTimeout(function () {
+ ok(SpecialPowers.wrap(win1).document.body.innerHTML.indexOf("test1:") !== -1,
+ "toplevel data: URI navigation through click() should be blocked");
+ win1.close();
+ test2();
+ }, 1000);
+}
+
+function test2() {
+ // data: URI in iframe which opens data: URI in _blank should be blocked
+ let win2 = window.open("file_block_toplevel_data_navigation2.html");
+ window.addEventListener("message", receiveMessage);
+ function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ is(event.data, "blocked",
+ "data: URI navigation using _blank from data: URI should be blocked");
+ win2.close();
+ test3();
+ }
+}
+
+function test3() {
+ // navigating to a data: URI using window.location.href should be blocked
+ let win3 = window.open("file_block_toplevel_data_navigation3.html");
+ setTimeout(function () {
+ ok(win3.document.body.innerHTML.indexOf("test3:") !== -1,
+ "data: URI navigation through win.loc.href should be blocked");
+ win3.close();
+ test4();
+ }, 1000);
+}
+
+function test4() {
+ // navigating to a data: URI using window.open() should be blocked
+ let win4 = window.open("data:text/html,<body>toplevel data: URI navigations should be blocked</body>");
+ setTimeout(function () {
+ // Please note that the data: URI will be displayed in the URL-Bar but not
+ // loaded, hence we rather rely on document.body than document.location
+ is(win4.document.body.innerHTML, "",
+ "navigating to a data: URI using window.open() should be blocked");
+ test5();
+ }, 1000);
+}
+
+function test5() {
+ // navigating to a URI which redirects to a data: URI using window.open() should be blocked
+ let win5 = window.open("file_block_toplevel_data_redirect.sjs");
+ setTimeout(function () {
+ // Please note that the data: URI will be displayed in the URL-Bar but not
+ // loaded, hence we rather rely on document.body than document.location
+ is(SpecialPowers.wrap(win5).document.body.innerHTML, "",
+ "navigating to URI which redirects to a data: URI using window.open() should be blocked");
+ win5.close();
+ SimpleTest.finish();
+ }, 1000);
+}
+
+// fire up the tests
+test1();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html b/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html
index 7b1ab72dc..3ef243824 100644
--- a/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html
+++ b/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html
@@ -61,6 +61,7 @@ var policy = {
"content policy type should TYPESUBDOCUMENT");
categoryManager.deleteCategoryEntry("content-policy", POLICYNAME, false);
SimpleTest.finish();
+ return Ci.nsIContentPolicy.REJECT_REQUEST;
}
return Ci.nsIContentPolicy.ACCEPT;
},
diff --git a/dom/security/test/gtest/TestCSPParser.cpp b/dom/security/test/gtest/TestCSPParser.cpp
index fafa7b5d9..893e02db5 100644
--- a/dom/security/test/gtest/TestCSPParser.cpp
+++ b/dom/security/test/gtest/TestCSPParser.cpp
@@ -204,6 +204,8 @@ TEST(CSPParser, Directives)
{
static const PolicyTest policies[] =
{
+ { "connect-src xn--mnchen-3ya.de",
+ "connect-src http://xn--mnchen-3ya.de"},
{ "default-src http://www.example.com",
"default-src http://www.example.com" },
{ "script-src http://www.example.com",
@@ -238,6 +240,10 @@ TEST(CSPParser, Directives)
"script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' https:" },
{ "default-src 'sha256-siVR8' 'strict-dynamic' 'unsafe-inline' https: ",
"default-src 'sha256-siVR8' 'unsafe-inline' https:" },
+ { "worker-src https://example.com",
+ "worker-src https://example.com" },
+ { "worker-src http://worker.com; frame-src http://frame.com; child-src http://child.com",
+ "worker-src http://worker.com; frame-src http://frame.com; child-src http://child.com" },
};
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
diff --git a/dom/security/test/moz.build b/dom/security/test/moz.build
index ddb4e9b89..946959dee 100644
--- a/dom/security/test/moz.build
+++ b/dom/security/test/moz.build
@@ -27,5 +27,6 @@ MOCHITEST_CHROME_MANIFESTS += [
BROWSER_CHROME_MANIFESTS += [
'contentverifier/browser.ini',
'csp/browser.ini',
+ 'general/browser.ini',
'hsts/browser.ini',
]
diff --git a/dom/svg/DOMSVGPathSegList.cpp b/dom/svg/DOMSVGPathSegList.cpp
index edacdfc93..0b811cdb1 100644
--- a/dom/svg/DOMSVGPathSegList.cpp
+++ b/dom/svg/DOMSVGPathSegList.cpp
@@ -460,6 +460,18 @@ DOMSVGPathSegList::ReplaceItem(DOMSVGPathSeg& aNewItem,
float segAsRaw[1 + NS_SVG_PATH_SEG_MAX_ARGS];
domItem->ToSVGPathSegEncodedData(segAsRaw);
+ if (AnimListMirrorsBaseList()) {
+ // The anim val list is in sync with the base val list - remove mirroring
+ // animVal item if necessary. We do this *before* touching InternalList()
+ // so the removed item can correctly store its internal value.
+ DOMSVGPathSegList* animVal =
+ GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
+ if (animVal->ItemAt(aIndex)) {
+ animVal->ItemAt(aIndex)->RemovingFromList();
+ animVal->ItemAt(aIndex) = nullptr;
+ }
+ }
+
if (!InternalList().mData.ReplaceElementsAt(internalIndex, 1 + oldArgCount,
segAsRaw, 1 + newArgCount,
fallible)) {
@@ -474,8 +486,13 @@ DOMSVGPathSegList::ReplaceItem(DOMSVGPathSeg& aNewItem,
int32_t delta = newArgCount - oldArgCount;
if (delta != 0) {
- for (uint32_t i = aIndex + 1; i < LengthNoFlush(); ++i) {
- mItems[i].mInternalDataIndex += delta;
+ // Sync up the internal indexes of all ItemProxys that come after aIndex:
+ UpdateListIndicesFromIndex(aIndex + 1, delta);
+ if (AnimListMirrorsBaseList()) {
+ // The anim val list is in sync with the base val list
+ DOMSVGPathSegList* animVal =
+ GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
+ animVal->UpdateListIndicesFromIndex(aIndex + 1, delta);
}
}
diff --git a/dom/svg/SVGClipPathElement.cpp b/dom/svg/SVGClipPathElement.cpp
index 60d72fdf0..682d1271e 100644
--- a/dom/svg/SVGClipPathElement.cpp
+++ b/dom/svg/SVGClipPathElement.cpp
@@ -50,6 +50,13 @@ SVGClipPathElement::GetEnumInfo()
ArrayLength(sEnumInfo));
}
+bool
+SVGClipPathElement::IsUnitsObjectBoundingBox() const
+{
+ return mEnumAttributes[CLIPPATHUNITS].GetAnimValue() == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
+}
+
+
//----------------------------------------------------------------------
// nsIDOMNode methods
diff --git a/dom/svg/SVGClipPathElement.h b/dom/svg/SVGClipPathElement.h
index d84f5b30f..2d9f4c15e 100644
--- a/dom/svg/SVGClipPathElement.h
+++ b/dom/svg/SVGClipPathElement.h
@@ -36,6 +36,10 @@ public:
// WebIDL
already_AddRefed<SVGAnimatedEnumeration> ClipPathUnits();
+ // This is an internal method that does not flush style, and thus
+ // the answer may be out of date if there's a pending style flush.
+ bool IsUnitsObjectBoundingBox() const;
+
protected:
enum { CLIPPATHUNITS };
diff --git a/dom/svg/SVGGradientElement.cpp b/dom/svg/SVGGradientElement.cpp
index 1bcac67e6..93767c934 100644
--- a/dom/svg/SVGGradientElement.cpp
+++ b/dom/svg/SVGGradientElement.cpp
@@ -198,13 +198,14 @@ SVGRadialGradientElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenP
return SVGRadialGradientElementBinding::Wrap(aCx, this, aGivenProto);
}
-nsSVGElement::LengthInfo SVGRadialGradientElement::sLengthInfo[5] =
+nsSVGElement::LengthInfo SVGRadialGradientElement::sLengthInfo[6] =
{
{ &nsGkAtoms::cx, 50, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::X },
{ &nsGkAtoms::cy, 50, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::Y },
{ &nsGkAtoms::r, 50, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::XY },
{ &nsGkAtoms::fx, 50, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::X },
{ &nsGkAtoms::fy, 50, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::Y },
+ { &nsGkAtoms::fr, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::XY },
};
//----------------------------------------------------------------------
@@ -252,6 +253,12 @@ SVGRadialGradientElement::Fy()
return mLengthAttributes[ATTR_FY].ToDOMAnimatedLength(this);
}
+already_AddRefed<SVGAnimatedLength>
+SVGRadialGradientElement::Fr()
+{
+ return mLengthAttributes[ATTR_FR].ToDOMAnimatedLength(this);
+}
+
//----------------------------------------------------------------------
// nsSVGElement methods
diff --git a/dom/svg/SVGGradientElement.h b/dom/svg/SVGGradientElement.h
index 7b2c6b220..ce9f3b4b1 100644
--- a/dom/svg/SVGGradientElement.h
+++ b/dom/svg/SVGGradientElement.h
@@ -139,13 +139,14 @@ public:
already_AddRefed<SVGAnimatedLength> R();
already_AddRefed<SVGAnimatedLength> Fx();
already_AddRefed<SVGAnimatedLength> Fy();
+ already_AddRefed<SVGAnimatedLength> Fr();
protected:
virtual LengthAttributesInfo GetLengthInfo() override;
- enum { ATTR_CX, ATTR_CY, ATTR_R, ATTR_FX, ATTR_FY };
- nsSVGLength2 mLengthAttributes[5];
- static LengthInfo sLengthInfo[5];
+ enum { ATTR_CX, ATTR_CY, ATTR_R, ATTR_FX, ATTR_FY, ATTR_FR };
+ nsSVGLength2 mLengthAttributes[6];
+ static LengthInfo sLengthInfo[6];
};
} // namespace dom
diff --git a/dom/svg/SVGTextContentElement.h b/dom/svg/SVGTextContentElement.h
index 905468228..5f126c811 100644
--- a/dom/svg/SVGTextContentElement.h
+++ b/dom/svg/SVGTextContentElement.h
@@ -29,6 +29,7 @@ typedef SVGGraphicsElement SVGTextContentElementBase;
class SVGTextContentElement : public SVGTextContentElementBase
{
+ friend class ::SVGTextFrame;
public:
using FragmentOrElement::TextLength;
diff --git a/dom/tests/browser/browser.ini b/dom/tests/browser/browser.ini
index 35ebd56c6..4d3a60a2c 100644..100755
--- a/dom/tests/browser/browser.ini
+++ b/dom/tests/browser/browser.ini
@@ -8,6 +8,7 @@ support-files =
worker_bug1004814.js
geo_leak_test.html
dummy.html
+ file_workerPerformance.js
test_largeAllocation.html
test_largeAllocation.html^headers^
!/dom/tests/mochitest/geolocation/network_geolocation.sjs
@@ -44,3 +45,4 @@ support-files =
support-files =
test_new_window_from_content_child.html
[browser_xhr_sandbox.js]
+[browser_performanceAPI.js]
diff --git a/dom/tests/browser/browser_performanceAPI.js b/dom/tests/browser/browser_performanceAPI.js
new file mode 100755
index 000000000..2c28fe3d1
--- /dev/null
+++ b/dom/tests/browser/browser_performanceAPI.js
@@ -0,0 +1,139 @@
+/**
+ * Bug 1369303 - A test for making sure that performance APIs have been correctly
+ * spoofed or disabled.
+ */
+
+const TEST_PATH = "http://example.net/browser/" +
+ "dom/tests/browser/";
+
+const PERFORMANCE_TIMINGS = [
+ "navigationStart",
+ "unloadEventStart",
+ "unloadEventEnd",
+ "redirectStart",
+ "redirectEnd",
+ "fetchStart",
+ "domainLookupStart",
+ "domainLookupEnd",
+ "connectStart",
+ "connectEnd",
+ "requestStart",
+ "responseStart",
+ "responseEnd",
+ "domLoading",
+ "domInteractive",
+ "domContentLoadedEventStart",
+ "domContentLoadedEventEnd",
+ "domComplete",
+ "loadEventStart",
+ "loadEventEnd",
+];
+
+let isRounded = (x, expectedPrecision) => {
+ let rounded = (Math.floor(x / expectedPrecision) * expectedPrecision);
+ // First we do the perfectly normal check that should work just fine
+ if (rounded === x || x === 0)
+ return true;
+
+ // When we're diving by non-whole numbers, we may not get perfect
+ // multiplication/division because of floating points
+ if (Math.abs(rounded - x + expectedPrecision) < .0000001) {
+ return true;
+ } else if (Math.abs(rounded - x) < .0000001) {
+ return true;
+ }
+
+ // Then we handle the case where you're sub-millisecond and the timer is not
+ // We check that the timer is not sub-millisecond by assuming it is not if it
+ // returns an even number of milliseconds
+ if (expectedPrecision < 1 && Math.round(x) == x) {
+ if (Math.round(rounded) == x) {
+ return true;
+ }
+ }
+
+ ok(false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x +
+ " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) +
+ " Fuzzy 2: " + Math.abs(rounded - x));
+
+ return false;
+};
+
+// ================================================================================================
+// ================================================================================================
+add_task(function* () {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(
+ gBrowser, TEST_PATH + "dummy.html");
+
+ yield ContentTask.spawn(tab.linkedBrowser, {
+ list: PERFORMANCE_TIMINGS,
+ precision: 2,
+ isRoundedFunc: isRounded.toString()
+ }, (data) => {
+ let timerlist = data.list;
+ let expectedPrecision = data.precision;
+ // eslint beleives that isrounded is available in this scope, but if you
+ // remove the assignment, you will see it is not
+ // eslint-disable-next-line
+ let isRounded = eval(data.isRoundedFunc);
+
+ // Check that whether the performance timing API is correctly spoofed.
+ for (let time of timerlist) {
+ ok(isRounded(content.performance.timing[time], expectedPrecision), `For reduceTimerPrecision(` + expectedPrecision + `), the timing(${time}) is not correctly rounded: ` + content.performance.timing[time]);
+ }
+
+ // Try to add some entries.
+ content.performance.mark("Test");
+ content.performance.mark("Test-End");
+ content.performance.measure("Test-Measure", "Test", "Test-End");
+
+ // Check the entries for performance.getEntries/getEntriesByType/getEntriesByName.
+ is(content.performance.getEntries().length, 3, "For reduceTimerPrecision, there should be 3 entries for performance.getEntries()");
+ for (var i = 0; i < 3; i++) {
+ let startTime = content.performance.getEntries()[i].startTime;
+ let duration = content.performance.getEntries()[i].duration;
+ ok(isRounded(startTime, expectedPrecision), "For reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i + ").startTime is not rounded: " + startTime);
+ ok(isRounded(duration, expectedPrecision), "For reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i + ").duration is not rounded: " + duration);
+ }
+ is(content.performance.getEntriesByType("mark").length, 2, "For reduceTimerPrecision, there should be 2 entries for performance.getEntriesByType()");
+ is(content.performance.getEntriesByName("Test", "mark").length, 1, "For reduceTimerPrecision, there should be 1 entry for performance.getEntriesByName()");
+ content.performance.clearMarks();
+ content.performance.clearMeasures();
+ content.performance.clearResourceTimings();
+ });
+ gBrowser.removeTab(tab);
+});
+
+// ================================================================================================
+// ================================================================================================
+add_task(function*() {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(
+ gBrowser, TEST_PATH + "dummy.html");
+
+ yield ContentTask.spawn(tab.linkedBrowser, {
+ list: PERFORMANCE_TIMINGS,
+ precision: 2,
+ isRoundedFunc: isRounded.toString()
+ }, (data) => {
+ let expectedPrecision = data.precision;
+ let workerCall = data.workerCall;
+ return new Promise(resolve => {
+ let worker = new content.Worker("file_workerPerformance.js");
+ worker.onmessage = function(e) {
+ if (e.data.type == "status") {
+ ok(e.data.status, e.data.msg);
+ } else if (e.data.type == "finish") {
+ worker.terminate();
+ resolve();
+ } else {
+ ok(false, "Unknown message type");
+ worker.terminate();
+ resolve();
+ }
+ };
+ worker.postMessage({precision: expectedPrecision});
+ });
+ });
+
+ gBrowser.removeTab(tab);
+});
diff --git a/dom/tests/browser/file_workerPerformance.js b/dom/tests/browser/file_workerPerformance.js
new file mode 100755
index 000000000..c77ba4377
--- /dev/null
+++ b/dom/tests/browser/file_workerPerformance.js
@@ -0,0 +1,65 @@
+function ok(a, msg) {
+ postMessage({type: "status", status: !!a, msg});
+}
+
+function is(a, b, msg) {
+ ok(a === b, msg);
+}
+
+function finish() {
+ postMessage({type: "finish"});
+}
+
+let isRounded = (x, expectedPrecision) => {
+ let rounded = (Math.floor(x / expectedPrecision) * expectedPrecision);
+ // First we do the perfectly normal check that should work just fine
+ if (rounded === x || x === 0)
+ return true;
+
+ // When we're diving by non-whole numbers, we may not get perfect
+ // multiplication/division because of floating points
+ if (Math.abs(rounded - x + expectedPrecision) < .0000001) {
+ return true;
+ } else if (Math.abs(rounded - x) < .0000001) {
+ return true;
+ }
+
+ // Then we handle the case where you're sub-millisecond and the timer is not
+ // We check that the timer is not sub-millisecond by assuming it is not if it
+ // returns an even number of milliseconds
+ if (expectedPrecision < 1 && Math.round(x) == x) {
+ if (Math.round(rounded) == x) {
+ return true;
+ }
+ }
+
+ ok(false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x +
+ " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) +
+ " Fuzzy 2: " + Math.abs(rounded - x));
+
+ return false;
+};
+
+function runRTPTests(expectedPrecision) {
+ // Try to add some entries.
+ performance.mark("Test");
+ performance.mark("Test-End");
+ performance.measure("Test-Measure", "Test", "Test-End");
+
+ // Check the entries in performance.getEntries/getEntriesByType/getEntriesByName.
+ is(performance.getEntries().length, 3, "In a worker, for reduceTimerPrecision: Incorrect number of entries for performance.getEntries() for workers: " + performance.getEntries().length);
+ for (var i = 0; i < 3; i++) {
+ let startTime = performance.getEntries()[i].startTime;
+ let duration = performance.getEntries()[i].duration;
+ ok(isRounded(startTime, expectedPrecision), "In a worker, for reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i.toString() + ").startTime is not rounded: " + startTime.toString());
+ ok(isRounded(duration, expectedPrecision), "In a worker, for reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i.toString() + ").duration is not rounded: " + duration.toString());
+ }
+ is(performance.getEntriesByType("mark").length, 2, "In a worker, for reduceTimerPrecision: Incorrect number of entries for performance.getEntriesByType() for workers: " + performance.getEntriesByType("resource").length);
+ is(performance.getEntriesByName("Test", "mark").length, 1, "In a worker, for reduceTimerPrecision: Incorrect number of entries for performance.getEntriesByName() for workers: " + performance.getEntriesByName("Test", "mark").length);
+
+ finish();
+}
+
+self.onmessage = function(e) {
+ runRTPTests(e.data.precision);
+};
diff --git a/dom/tests/mochitest/fetch/test_headers_common.js b/dom/tests/mochitest/fetch/test_headers_common.js
index fe792b25b..8b17b6b12 100644
--- a/dom/tests/mochitest/fetch/test_headers_common.js
+++ b/dom/tests/mochitest/fetch/test_headers_common.js
@@ -213,12 +213,12 @@ function TestHeadersIterator() {
var value_iter = headers.values();
var entries_iter = headers.entries();
- arrayEquals(iterate(key_iter), ["foo", "foo", "foo2"], "Correct key iterator");
- arrayEquals(iterate(value_iter), ["bar", ehsanInflated, "baz2"], "Correct value iterator");
- arrayEquals(iterate(entries_iter), [["foo", "bar"], ["foo", ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator");
+ arrayEquals(iterate(key_iter), ["foo", "foo2"], "Correct key iterator");
+ arrayEquals(iterate(value_iter), ["bar, " + ehsanInflated, "baz2"], "Correct value iterator");
+ arrayEquals(iterate(entries_iter), [["foo", "bar, " + ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator");
- arrayEquals(iterateForOf(headers), [["foo", "bar"], ["foo", ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator");
- arrayEquals(iterateForOf(new Headers(headers)), [["foo", "bar"], ["foo", ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator");
+ arrayEquals(iterateForOf(headers), [["foo", "bar, " + ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator");
+ arrayEquals(iterateForOf(new Headers(headers)), [["foo", "bar, " + ehsanInflated], ["foo2", "baz2"]], "Correct entries iterator");
}
function runTest() {
diff --git a/dom/tests/mochitest/general/mochitest.ini b/dom/tests/mochitest/general/mochitest.ini
index d59527801..d00ea1d4b 100644..100755
--- a/dom/tests/mochitest/general/mochitest.ini
+++ b/dom/tests/mochitest/general/mochitest.ini
@@ -43,6 +43,8 @@ support-files =
frameStoragePrevented.html
frameStorageChrome.html
frameStorageNullprincipal.sjs
+ worker_child.js
+ worker_grandchild.js
workerStorageAllowed.js
workerStoragePrevented.js
storagePermissionsUtils.js
@@ -108,6 +110,7 @@ support-files = test_offsets.js
[test_picture_mutations.html]
[test_pointerPreserves3D.html]
[test_pointerPreserves3DClip.html]
+[test_reduce_time_precision.html]
[test_resource_timing.html]
[test_resource_timing_cross_origin.html]
[test_resource_timing_frameset.html]
diff --git a/dom/tests/mochitest/general/test_domWindowUtils_scrollXY.html b/dom/tests/mochitest/general/test_domWindowUtils_scrollXY.html
index c6ee89ee3..cf27e5d87 100644
--- a/dom/tests/mochitest/general/test_domWindowUtils_scrollXY.html
+++ b/dom/tests/mochitest/general/test_domWindowUtils_scrollXY.html
@@ -31,13 +31,13 @@
function checkGetScrollXYState(flush, vals, testName) {
let scrollX = {}, scrollY = {};
domWindowUtils.getScrollXY(flush, scrollX, scrollY);
- is(scrollX.value, vals[0], "getScrollXY x for test: " + testName);
- is(scrollY.value, vals[1], "getScrollXY y for test: " + testName);
+ is(Math.round(scrollX.value), vals[0], "getScrollXY x for test: " + testName);
+ is(Math.round(scrollY.value), vals[1], "getScrollXY y for test: " + testName);
}
function checkWindowScrollState(vals, testName) {
- is(cwindow.scrollX, vals[0], "scrollX for test: " + testName);
- is(cwindow.scrollY, vals[1], "scrollY for test: " + testName);
+ is(Math.round(cwindow.scrollX), vals[0], "scrollX for test: " + testName);
+ is(Math.round(cwindow.scrollY), vals[1], "scrollY for test: " + testName);
}
// Check initial state (0, 0)
@@ -67,8 +67,8 @@
let scrollX = {}, scrollY = {};
domWindowUtils.getScrollXY(false, scrollX, scrollY);
- is(scrollX.value, 0, "scrollX is zero for display:none iframe");
- is(scrollY.value, 0, "scrollY is zero for display:none iframe");
+ is(Math.round(scrollX.value), 0, "scrollX is zero for display:none iframe");
+ is(Math.round(scrollY.value), 0, "scrollY is zero for display:none iframe");
}
SimpleTest.waitForExplicitFinish();
diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html
index acbc12e07..4b47d2b4f 100644
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -751,9 +751,11 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"PerformanceNavigation",
// IMPORTANT: Do not change this list without review from a DOM peer!
- {name: "PerformanceObserver", nightly: true},
+ "PerformanceNavigationTiming",
// IMPORTANT: Do not change this list without review from a DOM peer!
- {name: "PerformanceObserverEntryList", nightly: true},
+ "PerformanceObserver"
+// IMPORTANT: Do not change this list without review from a DOM peer!
+ "PerformanceObserverEntryList"
// IMPORTANT: Do not change this list without review from a DOM peer!
"PerformanceResourceTiming",
// IMPORTANT: Do not change this list without review from a DOM peer!
diff --git a/dom/tests/mochitest/general/test_reduce_time_precision.html b/dom/tests/mochitest/general/test_reduce_time_precision.html
new file mode 100755
index 000000000..6f149f28d
--- /dev/null
+++ b/dom/tests/mochitest/general/test_reduce_time_precision.html
@@ -0,0 +1,143 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Tor bug
+https://trac.torproject.org/projects/tor/ticket/1517
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Tor Bug 1517 and Mozilla Bug 1424341</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://trac.torproject.org/projects/tor/ticket/1517">Tor Bug 1517</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1424341">Mozilla Bug 1424341</a>
+
+<!-- Canvas for testing 'currentTime' -->
+<canvas id="test-canvas" width="100" height="100"></canvas>
+
+<!-- The main testing script -->
+<script type="application/javascript">
+ SimpleTest.requestFlakyTimeout("testing JS time-based fingerprinting");
+
+ // Prepare for test of AudioContext.currentTime
+ let audioContext = new AudioContext();
+ // Prepare for test of CanvasStream.currentTime
+ let canvas = document.getElementById("test-canvas");
+ let context = canvas.getContext("2d");
+ context.fillText("test", 20, 20);
+ let canvasStream = canvas.captureStream(25);
+
+ // Known ways to generate time stamps, in milliseconds
+ const timeStampCodes = [
+ "performance.now()",
+ "new Date().getTime()",
+ "new Event(\"\").timeStamp",
+ "new File([], \"\").lastModified",
+ "new File([], \"\").lastModifiedDate.getTime()",
+ ];
+ // These are measured in seconds, so we need to scale them up
+ var timeStampCodesDOM = timeStampCodes.concat([
+ "audioContext.currentTime * 1000",
+ "canvasStream.currentTime * 1000",
+ ]);
+
+ let isRounded = (x) => {
+ expectedPrecision = 2;
+ let rounded = (Math.floor(x / expectedPrecision) * expectedPrecision);
+ // First we do the perfectly normal check that should work just fine
+ if (rounded === x || x === 0)
+ return true;
+
+ // When we're diving by non-whole numbers, we may not get perfect
+ // multiplication/division because of floating points.
+ // When dealing with ms since epoch, a double's precision is on the order
+ // of 1/5 of a microsecond, so we use a value a little higher than that as
+ // our epsilon.
+ // To be clear, this error is introduced in our re-calculation of 'rounded'
+ // above in JavaScript.
+ if (Math.abs(rounded - x + expectedPrecision) < .0005) {
+ return true;
+ } else if (Math.abs(rounded - x) < .0005) {
+ return true;
+ }
+
+ // Then we handle the case where you're sub-millisecond and the timer is not
+ // We check that the timer is not sub-millisecond by assuming it is not if it
+ // returns an even number of milliseconds
+ if (expectedPrecision < 1 && Math.round(x) == x) {
+ if (Math.round(rounded) == x) {
+ return true;
+ }
+ }
+
+ ok(false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x +
+ " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) +
+ " Fuzzy 2: " + Math.abs(rounded - x));
+
+ return false;
+ };
+
+ // ================================================================================================
+ // ================================================================================================
+
+ function* checkWorker(worker) {
+ // The child worker will send the results back.
+ let checkWorkerTimeStamps = () => new Promise(function(resolve) {
+ let onMessage = function(event) {
+ worker.removeEventListener("message", onMessage);
+
+ let timeStamps = event.data;
+ for (let i = 0; i < timeStampCodes.length; i++) {
+ let timeStamp = timeStamps[i];
+ ok(isRounded(timeStamp),
+ "'" + timeStampCodes[i] +
+ "' should be rounded to nearest 2 ms in workers; saw " +
+ timeStamp);
+ }
+ resolve();
+ };
+ worker.addEventListener("message", onMessage);
+ });
+
+ // Send the codes to its child worker.
+ worker.postMessage(timeStampCodes);
+
+ // First, check the child's results.
+ yield checkWorkerTimeStamps();
+ // Then, check the grandchild's results.
+ yield checkWorkerTimeStamps();
+
+ worker.terminate();
+ }
+
+ add_task(function*() {
+ let worker = new Worker("worker_child.js");
+ // Allow ~550 ms to elapse, so we can get non-zero
+ // time values for all elements.
+ yield new Promise(resolve => window.setTimeout(resolve, 550));
+ yield checkWorker(worker);
+ });
+
+ // ================================================================================================
+ // ================================================================================================
+
+
+ add_task(function*() {
+ // Loop through each timeStampCode, evaluate it,
+ // and check if it is rounded
+ for (let timeStampCode of timeStampCodesDOM) {
+ let timeStamp = eval(timeStampCode);
+ ok(isRounded(timeStamp),
+ "'" + timeStampCode + "' should be rounded to nearest 2ms" +
+ " saw " + timeStamp);
+ }
+ });
+
+</script>
+
+
+</body>
+</html>
diff --git a/dom/tests/mochitest/general/worker_child.js b/dom/tests/mochitest/general/worker_child.js
new file mode 100755
index 000000000..fa340fc65
--- /dev/null
+++ b/dom/tests/mochitest/general/worker_child.js
@@ -0,0 +1,28 @@
+let timeStampCodes;
+let worker = new Worker("worker_grandchild.js");
+
+function listenToParent(event) {
+ self.removeEventListener("message", listenToParent);
+ timeStampCodes = event.data;
+
+ let timeStamps = [];
+ for (let timeStampCode of timeStampCodes) {
+ timeStamps.push(eval(timeStampCode));
+ }
+ // Send the timeStamps to the parent.
+ postMessage(timeStamps);
+
+ // Tell the grandchild to start.
+ worker.postMessage(timeStampCodes);
+}
+
+// The worker grandchild will send results back.
+function listenToChild(event) {
+ worker.removeEventListener("message", listenToChild);
+ // Pass the results to the parent.
+ postMessage(event.data);
+ worker.terminate();
+}
+
+worker.addEventListener("message", listenToChild);
+self.addEventListener("message", listenToParent);
diff --git a/dom/tests/mochitest/general/worker_grandchild.js b/dom/tests/mochitest/general/worker_grandchild.js
new file mode 100755
index 000000000..cd21508b2
--- /dev/null
+++ b/dom/tests/mochitest/general/worker_grandchild.js
@@ -0,0 +1,10 @@
+self.addEventListener("message", function(event) {
+ let timeStampCodes = event.data;
+
+ let timeStamps = [];
+ for (let timeStampCode of timeStampCodes) {
+ timeStamps.push(eval(timeStampCode));
+ }
+ // Send the timeStamps to the parent.
+ postMessage(timeStamps);
+});
diff --git a/dom/url/URL.cpp b/dom/url/URL.cpp
index 1f15e1151..c8724c359 100644
--- a/dom/url/URL.cpp
+++ b/dom/url/URL.cpp
@@ -17,7 +17,6 @@
#include "nsEscape.h"
#include "nsHostObjectProtocolHandler.h"
#include "nsIIOService.h"
-#include "nsIURIWithQuery.h"
#include "nsIURL.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
@@ -525,21 +524,10 @@ URLMainThread::GetPathname(nsAString& aPathname, ErrorResult& aRv) const
// Do not throw! Not having a valid URI or URL should result in an empty
// string.
- nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI));
- if (url) {
- nsAutoCString file;
- nsresult rv = url->GetFilePath(file);
- if (NS_SUCCEEDED(rv)) {
- CopyUTF8toUTF16(file, aPathname);
- }
-
- return;
- }
-
- nsAutoCString path;
- nsresult rv = mURI->GetPath(path);
+ nsAutoCString file;
+ nsresult rv = mURI->GetFilePath(file);
if (NS_SUCCEEDED(rv)) {
- CopyUTF8toUTF16(path, aPathname);
+ CopyUTF8toUTF16(file, aPathname);
}
}
@@ -548,11 +536,7 @@ URLMainThread::SetPathname(const nsAString& aPathname, ErrorResult& aRv)
{
// Do not throw!
- nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI));
- if (url) {
- url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
- return;
- }
+ mURI->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
}
void
@@ -566,13 +550,9 @@ URLMainThread::GetSearch(nsAString& aSearch, ErrorResult& aRv) const
nsAutoCString search;
nsresult rv;
- nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI));
- if (url) {
- rv = url->GetQuery(search);
- if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
- CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
- }
- return;
+ rv = mURI->GetQuery(search);
+ if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
+ CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
}
}
@@ -603,11 +583,7 @@ URLMainThread::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv)
{
// Ignore failures to be compatible with NS4.
- nsCOMPtr<nsIURIWithQuery> uriWithQuery(do_QueryInterface(mURI));
- if (uriWithQuery) {
- uriWithQuery->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
- return;
- }
+ mURI->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
}
} // anonymous namespace
diff --git a/dom/url/URL.h b/dom/url/URL.h
index 16b4678ba..45e4dd289 100644
--- a/dom/url/URL.h
+++ b/dom/url/URL.h
@@ -155,6 +155,12 @@ public:
GetHref(aRetval, aRv);
}
+ void
+ ToJSON(nsAString& aResult, ErrorResult& aRv) const
+ {
+ GetHref(aResult, aRv);
+ }
+
// URLSearchParamsObserver
void
URLSearchParamsUpdated(URLSearchParams* aSearchParams) override;
diff --git a/dom/url/tests/test_url.html b/dom/url/tests/test_url.html
index 3f3f727d6..73e75667d 100644
--- a/dom/url/tests/test_url.html
+++ b/dom/url/tests/test_url.html
@@ -399,6 +399,18 @@
</script>
<script>
+ /** Test for Bug 1275746 **/
+ SimpleTest.doesThrow(() => { var url = new URL("http:"); }, "http: is not a valid URL");
+ SimpleTest.doesThrow(() => { var url = new URL("http:///"); }, "http: is not a valid URL");
+
+ var url = new URL("file:");
+ is(url.href, "file:///", "Parsing file: should work.");
+
+ url = new URL("file:///");
+ is(url.href, "file:///", "Parsing file:/// should work.");
+ </script>
+
+ <script>
var url = new URL("scheme:path/to/file?query#hash");
is(url.href, "scheme:path/to/file?query#hash");
is(url.pathname, "path/to/file");
@@ -438,5 +450,11 @@
url = new URL("data:text/html,<a href=\"http://example.org/?q\">Link</a>");
is(url.href, "data:text/html,<a%20href=\"http://example.org/?q\">Link</a>");
</script>
+
+ <script>
+ var u = new URL('http://www.example.org');
+ ok(u.toJSON(), 'http://www.example.org', "URL.toJSON()");
+ is(JSON.stringify(u), "\"http://www.example.org/\"", "JSON.stringify(u) works");
+ </script>
</body>
</html>
diff --git a/dom/webidl/CSPDictionaries.webidl b/dom/webidl/CSPDictionaries.webidl
index 54008f13a..f8de1c9ad 100644
--- a/dom/webidl/CSPDictionaries.webidl
+++ b/dom/webidl/CSPDictionaries.webidl
@@ -30,6 +30,7 @@ dictionary CSP {
sequence<DOMString> block-all-mixed-content;
sequence<DOMString> require-sri-for;
sequence<DOMString> sandbox;
+ sequence<DOMString> worker-src;
};
dictionary CSPPolicies {
diff --git a/dom/webidl/CanvasRenderingContext2D.webidl b/dom/webidl/CanvasRenderingContext2D.webidl
index 38a30f9e3..1c5564215 100644
--- a/dom/webidl/CanvasRenderingContext2D.webidl
+++ b/dom/webidl/CanvasRenderingContext2D.webidl
@@ -27,6 +27,9 @@ dictionary HitRegionOptions {
};
typedef (HTMLImageElement or
+ SVGImageElement) HTMLOrSVGImageElement;
+
+typedef (HTMLOrSVGImageElement or
HTMLCanvasElement or
HTMLVideoElement or
ImageBitmap) CanvasImageSource;
diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl
index c895fad39..0b8c278fe 100644
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -275,10 +275,11 @@ partial interface Document {
object registerElement(DOMString name, optional ElementRegistrationOptions options);
};
-// http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#sec-document-interface
+// https://w3c.github.io/page-visibility/#extensions-to-the-document-interface
partial interface Document {
readonly attribute boolean hidden;
readonly attribute VisibilityState visibilityState;
+ attribute EventHandler onvisibilitychange;
};
// http://dev.w3.org/csswg/cssom/#extensions-to-the-document-interface
@@ -429,6 +430,12 @@ partial interface Document {
void removeAnonymousContent(AnonymousContent aContent);
};
+// http://w3c.github.io/selection-api/#extensions-to-document-interface
+partial interface Document {
+ [Throws]
+ Selection? getSelection();
+};
+
// Extension to give chrome JS the ability to determine whether
// the user has interacted with the document or not.
partial interface Document {
diff --git a/dom/webidl/HTMLButtonElement.webidl b/dom/webidl/HTMLButtonElement.webidl
index c50e09ae0..579efa39c 100644
--- a/dom/webidl/HTMLButtonElement.webidl
+++ b/dom/webidl/HTMLButtonElement.webidl
@@ -44,6 +44,5 @@ interface HTMLButtonElement : HTMLElement {
boolean reportValidity();
void setCustomValidity(DOMString error);
-// Not yet implemented:
-// readonly attribute NodeList labels;
+ readonly attribute NodeList labels;
};
diff --git a/dom/webidl/HTMLDocument.webidl b/dom/webidl/HTMLDocument.webidl
index 61b466ff0..42f6d98f7 100644
--- a/dom/webidl/HTMLDocument.webidl
+++ b/dom/webidl/HTMLDocument.webidl
@@ -73,10 +73,6 @@ interface HTMLDocument : Document {
readonly attribute HTMLAllCollection all;
- // https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#selections
- [Throws]
- Selection? getSelection();
-
// @deprecated These are old Netscape 4 methods. Do not use,
// the implementation is no-op.
// XXXbz do we actually need these anymore?
diff --git a/dom/webidl/HTMLInputElement.webidl b/dom/webidl/HTMLInputElement.webidl
index d3d537f84..cf3e9a4c7 100644
--- a/dom/webidl/HTMLInputElement.webidl
+++ b/dom/webidl/HTMLInputElement.webidl
@@ -111,7 +111,7 @@ interface HTMLInputElement : HTMLElement {
boolean reportValidity();
void setCustomValidity(DOMString error);
- // Bug 850365 readonly attribute NodeList labels;
+ readonly attribute NodeList? labels;
void select();
@@ -238,6 +238,9 @@ partial interface HTMLInputElement {
dictionary DateTimeValue {
long hour;
long minute;
+ long year;
+ long month;
+ long day;
};
partial interface HTMLInputElement {
@@ -250,6 +253,14 @@ partial interface HTMLInputElement {
[Pref="dom.forms.datetime", ChromeOnly]
void setDateTimePickerState(boolean open);
+ [Pref="dom.forms.datetime", ChromeOnly,
+ BinaryName="getMinimumAsDouble"]
+ double getMinimum();
+
+ [Pref="dom.forms.datetime", ChromeOnly,
+ BinaryName="getMaximumAsDouble"]
+ double getMaximum();
+
[Pref="dom.forms.datetime", Func="IsChromeOrXBL"]
void openDateTimePicker(optional DateTimeValue initialValue);
@@ -258,4 +269,12 @@ partial interface HTMLInputElement {
[Pref="dom.forms.datetime", Func="IsChromeOrXBL"]
void closeDateTimePicker();
+
+ [Pref="dom.forms.datetime", Func="IsChromeOrXBL",
+ BinaryName="getStepAsDouble"]
+ double getStep();
+
+ [Pref="dom.forms.datetime", Func="IsChromeOrXBL",
+ BinaryName="getStepBaseAsDouble"]
+ double getStepBase();
};
diff --git a/dom/webidl/HTMLMediaElement.webidl b/dom/webidl/HTMLMediaElement.webidl
index 456579ec1..313686dac 100644
--- a/dom/webidl/HTMLMediaElement.webidl
+++ b/dom/webidl/HTMLMediaElement.webidl
@@ -153,6 +153,7 @@ partial interface HTMLMediaElement {
attribute EventHandler onmozinterruptend;
};
+#ifdef MOZ_EME
// Encrypted Media Extensions
partial interface HTMLMediaElement {
[Pref="media.eme.apiVisible"]
@@ -168,6 +169,7 @@ partial interface HTMLMediaElement {
[Pref="media.eme.apiVisible"]
attribute EventHandler onwaitingforkey;
};
+#endif
// This is just for testing
partial interface HTMLMediaElement {
diff --git a/dom/webidl/HTMLMeterElement.webidl b/dom/webidl/HTMLMeterElement.webidl
index 1f80764e9..104e00353 100644
--- a/dom/webidl/HTMLMeterElement.webidl
+++ b/dom/webidl/HTMLMeterElement.webidl
@@ -26,8 +26,5 @@ interface HTMLMeterElement : HTMLElement {
[SetterThrows]
attribute double optimum;
- /**
- * The labels attribute will be done with bug 556743.
- */
- //readonly attribute NodeList labels;
+ readonly attribute NodeList labels;
};
diff --git a/dom/webidl/HTMLOutputElement.webidl b/dom/webidl/HTMLOutputElement.webidl
index 05dcf1800..d0e4ecbe6 100644
--- a/dom/webidl/HTMLOutputElement.webidl
+++ b/dom/webidl/HTMLOutputElement.webidl
@@ -33,6 +33,5 @@ interface HTMLOutputElement : HTMLElement {
boolean reportValidity();
void setCustomValidity(DOMString error);
-// Not yet implemented (bug 556743).
-// readonly attribute NodeList labels;
+ readonly attribute NodeList labels;
};
diff --git a/dom/webidl/HTMLProgressElement.webidl b/dom/webidl/HTMLProgressElement.webidl
index 3d1000d22..028728e22 100644
--- a/dom/webidl/HTMLProgressElement.webidl
+++ b/dom/webidl/HTMLProgressElement.webidl
@@ -17,9 +17,5 @@ interface HTMLProgressElement : HTMLElement {
[SetterThrows]
attribute double max;
readonly attribute double position;
-
- /**
- * The labels attribute will be done with bug 567740.
- */
- //readonly attribute NodeList labels;
+ readonly attribute NodeList labels;
};
diff --git a/dom/webidl/HTMLSelectElement.webidl b/dom/webidl/HTMLSelectElement.webidl
index 74fc7b2cf..b18ca3634 100644
--- a/dom/webidl/HTMLSelectElement.webidl
+++ b/dom/webidl/HTMLSelectElement.webidl
@@ -53,7 +53,7 @@ interface HTMLSelectElement : HTMLElement {
boolean reportValidity();
void setCustomValidity(DOMString error);
-// NYI: readonly attribute NodeList labels;
+ readonly attribute NodeList labels;
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=20720
void remove();
diff --git a/dom/webidl/HTMLTextAreaElement.webidl b/dom/webidl/HTMLTextAreaElement.webidl
index b1005ed42..4df687a0b 100644
--- a/dom/webidl/HTMLTextAreaElement.webidl
+++ b/dom/webidl/HTMLTextAreaElement.webidl
@@ -57,7 +57,7 @@ interface HTMLTextAreaElement : HTMLElement {
boolean reportValidity();
void setCustomValidity(DOMString error);
- // readonly attribute NodeList labels;
+ readonly attribute NodeList labels;
void select();
[Throws]
diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl
index 56461e429..5452f3247 100644
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -348,12 +348,14 @@ partial interface Navigator {
readonly attribute LegacyMozTCPSocket mozTCPSocket;
};
+#ifdef MOZ_EME
partial interface Navigator {
[Pref="media.eme.apiVisible", NewObject]
Promise<MediaKeySystemAccess>
requestMediaKeySystemAccess(DOMString keySystem,
sequence<MediaKeySystemConfiguration> supportedConfigurations);
};
+#endif
#ifdef NIGHTLY_BUILD
partial interface Navigator {
diff --git a/dom/webidl/Performance.webidl b/dom/webidl/Performance.webidl
index eaede253c..0bd2677df 100644
--- a/dom/webidl/Performance.webidl
+++ b/dom/webidl/Performance.webidl
@@ -17,6 +17,9 @@ typedef sequence <PerformanceEntry> PerformanceEntryList;
interface Performance {
[DependsOn=DeviceState, Affects=Nothing]
DOMHighResTimeStamp now();
+
+ [Constant]
+ readonly attribute DOMHighResTimeStamp timeOrigin;
};
[Exposed=Window]
diff --git a/dom/webidl/PerformanceNavigationTiming.webidl b/dom/webidl/PerformanceNavigationTiming.webidl
new file mode 100644
index 000000000..fa3ecaec4
--- /dev/null
+++ b/dom/webidl/PerformanceNavigationTiming.webidl
@@ -0,0 +1,33 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://www.w3.org/TR/navigation-timing-2/#sec-PerformanceNavigationTiming
+ *
+ * Copyright © 2016 W3C® (MIT, ERCIM, Keio, Beihang).
+ * W3C liability, trademark and document use rules apply.
+ */
+
+enum NavigationType {
+ "navigate",
+ "reload",
+ "back_forward",
+ "prerender"
+};
+
+interface PerformanceNavigationTiming : PerformanceResourceTiming {
+ readonly attribute DOMHighResTimeStamp unloadEventStart;
+ readonly attribute DOMHighResTimeStamp unloadEventEnd;
+ readonly attribute DOMHighResTimeStamp domInteractive;
+ readonly attribute DOMHighResTimeStamp domContentLoadedEventStart;
+ readonly attribute DOMHighResTimeStamp domContentLoadedEventEnd;
+ readonly attribute DOMHighResTimeStamp domComplete;
+ readonly attribute DOMHighResTimeStamp loadEventStart;
+ readonly attribute DOMHighResTimeStamp loadEventEnd;
+ readonly attribute NavigationType type;
+ readonly attribute unsigned short redirectCount;
+
+ jsonifier;
+};
diff --git a/dom/webidl/PerformanceObserver.webidl b/dom/webidl/PerformanceObserver.webidl
index a3a14cb1e..4cebecbeb 100644
--- a/dom/webidl/PerformanceObserver.webidl
+++ b/dom/webidl/PerformanceObserver.webidl
@@ -9,6 +9,7 @@
dictionary PerformanceObserverInit {
required sequence<DOMString> entryTypes;
+ boolean buffered = false;
};
callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries, PerformanceObserver observer);
diff --git a/dom/webidl/PerformanceResourceTiming.webidl b/dom/webidl/PerformanceResourceTiming.webidl
index 021b84ae2..112228325 100644
--- a/dom/webidl/PerformanceResourceTiming.webidl
+++ b/dom/webidl/PerformanceResourceTiming.webidl
@@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
- * http://w3c-test.org/webperf/specs/ResourceTiming/#performanceresourcetiming
+ * https://w3c.github.io/resource-timing/#performanceresourcetiming
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
@@ -12,14 +12,10 @@
interface PerformanceResourceTiming : PerformanceEntry
{
- // A string with the name of that element that initiated the load.
- // If the initiator is a CSS resource, the initiatorType attribute must return
- // the string "css".
- // If the initiator is an XMLHttpRequest object, the initiatorType attribute
- // must return the string "xmlhttprequest".
readonly attribute DOMString initiatorType;
readonly attribute DOMString nextHopProtocol;
+ readonly attribute DOMHighResTimeStamp workerStart;
readonly attribute DOMHighResTimeStamp redirectStart;
readonly attribute DOMHighResTimeStamp redirectEnd;
readonly attribute DOMHighResTimeStamp fetchStart;
diff --git a/dom/webidl/PerformanceTiming.webidl b/dom/webidl/PerformanceTiming.webidl
index f75a46b7c..4aa403a50 100644
--- a/dom/webidl/PerformanceTiming.webidl
+++ b/dom/webidl/PerformanceTiming.webidl
@@ -21,8 +21,7 @@ interface PerformanceTiming {
readonly attribute unsigned long long domainLookupEnd;
readonly attribute unsigned long long connectStart;
readonly attribute unsigned long long connectEnd;
- // secureConnectionStart will be implemneted in bug 772589
- // readonly attribute unsigned long long secureConnectionStart;
+ readonly attribute unsigned long long secureConnectionStart;
readonly attribute unsigned long long requestStart;
readonly attribute unsigned long long responseStart;
readonly attribute unsigned long long responseEnd;
@@ -34,5 +33,11 @@ interface PerformanceTiming {
readonly attribute unsigned long long loadEventStart;
readonly attribute unsigned long long loadEventEnd;
+ // This is a Chrome proprietary extension and not part of the
+ // performance/navigation timing specification.
+ // Returns 0 if a non-blank paint has not happened.
+ [Pref="dom.performance.time_to_non_blank_paint.enabled"]
+ readonly attribute unsigned long long timeToNonBlankPaint;
+
jsonifier;
};
diff --git a/dom/webidl/PointerEvent.webidl b/dom/webidl/PointerEvent.webidl
index 2e83922c8..4e8a0eb90 100644
--- a/dom/webidl/PointerEvent.webidl
+++ b/dom/webidl/PointerEvent.webidl
@@ -17,8 +17,10 @@ interface PointerEvent : MouseEvent
readonly attribute long width;
readonly attribute long height;
readonly attribute float pressure;
+ readonly attribute float tangentialPressure;
readonly attribute long tiltX;
readonly attribute long tiltY;
+ readonly attribute long twist;
readonly attribute DOMString pointerType;
readonly attribute boolean isPrimary;
};
@@ -29,8 +31,10 @@ dictionary PointerEventInit : MouseEventInit
long width = 1;
long height = 1;
float pressure = 0;
+ float tangentialPressure = 0;
long tiltX = 0;
long tiltY = 0;
+ long twist = 0;
DOMString pointerType = "";
boolean isPrimary = false;
};
diff --git a/dom/webidl/Response.webidl b/dom/webidl/Response.webidl
index 8713146aa..08f31fe29 100644
--- a/dom/webidl/Response.webidl
+++ b/dom/webidl/Response.webidl
@@ -7,7 +7,7 @@
* https://fetch.spec.whatwg.org/#response-class
*/
-[Constructor(optional BodyInit body, optional ResponseInit init),
+[Constructor(optional BodyInit? body, optional ResponseInit init),
Exposed=(Window,Worker)]
interface Response {
[NewObject] static Response error();
diff --git a/dom/webidl/SVGRadialGradientElement.webidl b/dom/webidl/SVGRadialGradientElement.webidl
index d4a3724f6..8d7ce9016 100644
--- a/dom/webidl/SVGRadialGradientElement.webidl
+++ b/dom/webidl/SVGRadialGradientElement.webidl
@@ -21,5 +21,7 @@ interface SVGRadialGradientElement : SVGGradientElement {
readonly attribute SVGAnimatedLength fx;
[Constant]
readonly attribute SVGAnimatedLength fy;
- // readonly attribute SVGAnimatedLength fr;
+ // XXX: Bug 1242048
+ // [SameObject]
+ readonly attribute SVGAnimatedLength fr;
};
diff --git a/dom/webidl/Selection.webidl b/dom/webidl/Selection.webidl
index c90844dfa..c3eac016c 100644
--- a/dom/webidl/Selection.webidl
+++ b/dom/webidl/Selection.webidl
@@ -33,6 +33,7 @@ interface Selection {
void deleteFromDocument();
readonly attribute unsigned long rangeCount;
+ readonly attribute DOMString type;
[Throws]
Range getRangeAt(unsigned long index);
[Throws]
@@ -77,7 +78,7 @@ partial interface Selection {
void removeSelectionListener(nsISelectionListener listenerToRemove);
[ChromeOnly,BinaryName="rawType"]
- readonly attribute short type;
+ readonly attribute short selectionType;
[ChromeOnly,Throws,Pref="dom.testing.selection.GetRangesForInterval"]
sequence<Range> GetRangesForInterval(Node beginNode, long beginOffset, Node endNode, long endOffset,
diff --git a/dom/webidl/URL.webidl b/dom/webidl/URL.webidl
index 0baa9913c..4d491e1b3 100644
--- a/dom/webidl/URL.webidl
+++ b/dom/webidl/URL.webidl
@@ -44,9 +44,12 @@ interface URL {
attribute USVString pathname;
[Throws]
attribute USVString search;
- readonly attribute URLSearchParams searchParams;
+ [SameObject] readonly attribute URLSearchParams searchParams;
[Throws]
attribute USVString hash;
+
+ [Throws]
+ USVString toJSON();
};
partial interface URL {
diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl
index 055a274cc..36b1f0313 100644
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -182,14 +182,10 @@ partial interface Window {
[ChromeOnly] void mozScrollSnap();
// The four properties below are double per spec at the moment, but whether
// that will continue is unclear.
- //[Replaceable, Throws] readonly attribute double scrollX;
- //[Replaceable, Throws] readonly attribute double pageXOffset;
- //[Replaceable, Throws] readonly attribute double scrollY;
- //[Replaceable, Throws] readonly attribute double pageYOffset;
- [Replaceable, Throws] readonly attribute long scrollX;
- [Replaceable, Throws] readonly attribute long pageXOffset;
- [Replaceable, Throws] readonly attribute long scrollY;
- [Replaceable, Throws] readonly attribute long pageYOffset;
+ [Replaceable, Throws] readonly attribute double scrollX;
+ [Throws] readonly attribute double pageXOffset;
+ [Replaceable, Throws] readonly attribute double scrollY;
+ [Throws] readonly attribute double pageYOffset;
// client
// These are writable because we allow chrome to write them. And they need
diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build
index efa90230d..8469c9001 100644
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -9,6 +9,7 @@ GENERATED_WEBIDL_FILES = [
]
PREPROCESSED_WEBIDL_FILES = [
+ 'HTMLMediaElement.webidl',
'Navigator.webidl',
'Node.webidl',
'Promise.webidl',
@@ -18,7 +19,6 @@ PREPROCESSED_WEBIDL_FILES = [
WEBIDL_FILES = [
'AbstractWorker.webidl',
- 'AddonManager.webidl',
'AnalyserNode.webidl',
'Animatable.webidl',
'Animation.webidl',
@@ -211,7 +211,6 @@ WEBIDL_FILES = [
'HTMLLIElement.webidl',
'HTMLLinkElement.webidl',
'HTMLMapElement.webidl',
- 'HTMLMediaElement.webidl',
'HTMLMenuElement.webidl',
'HTMLMenuItemElement.webidl',
'HTMLMetaElement.webidl',
@@ -348,6 +347,7 @@ WEBIDL_FILES = [
'PerformanceMark.webidl',
'PerformanceMeasure.webidl',
'PerformanceNavigation.webidl',
+ 'PerformanceNavigationTiming.webidl',
'PerformanceObserver.webidl',
'PerformanceObserverEntryList.webidl',
'PerformanceResourceTiming.webidl',
@@ -592,6 +592,9 @@ WEBIDL_FILES = [
'XULElement.webidl',
]
+if CONFIG['MOZ_WEBEXTENSIONS']:
+ WEBIDL_FILES += ['AddonManager.webidl']
+
if CONFIG['MOZ_AUDIO_CHANNEL_MANAGER']:
WEBIDL_FILES += [
'AudioChannelManager.webidl',
@@ -692,7 +695,6 @@ else:
]
GENERATED_EVENTS_WEBIDL_FILES = [
- 'AddonEvent.webidl',
'AnimationPlaybackEvent.webidl',
'AutocompleteErrorEvent.webidl',
'BlobEvent.webidl',
@@ -734,6 +736,9 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'WebGLContextEvent.webidl',
]
+if CONFIG['MOZ_WEBEXTENSIONS']:
+ GENERATED_EVENTS_WEBIDL_FILES += ['AddonEvent.webidl']
+
if CONFIG['MOZ_WEBRTC']:
GENERATED_EVENTS_WEBIDL_FILES += [
'RTCDataChannelEvent.webidl',
@@ -764,12 +769,12 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
'MozWifiStatusChangeEvent.webidl',
]
-if CONFIG['MOZ_BUILD_APP'] in ['browser', 'xulrunner'] or CONFIG['MOZ_SUITE']:
+if CONFIG['MOZ_BUILD_APP'] in ['xulrunner'] or CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_SUITE']:
WEBIDL_FILES += [
'BrowserFeedWriter.webidl',
]
-if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']:
+if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_FENNEC'] or CONFIG['MOZ_XULRUNNER']:
WEBIDL_FILES += [
'External.webidl',
]
diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp
index 1f5616873..1739f3d31 100644
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -301,7 +301,9 @@ LoadContextOptions(const char* aPrefName, void* /* aClosure */)
.setNativeRegExp(GetWorkerPref<bool>(NS_LITERAL_CSTRING("native_regexp")))
.setAsyncStack(GetWorkerPref<bool>(NS_LITERAL_CSTRING("asyncstack")))
.setWerror(GetWorkerPref<bool>(NS_LITERAL_CSTRING("werror")))
- .setExtraWarnings(GetWorkerPref<bool>(NS_LITERAL_CSTRING("strict")));
+ .setExtraWarnings(GetWorkerPref<bool>(NS_LITERAL_CSTRING("strict")))
+ .setArrayProtoValues(GetWorkerPref<bool>(
+ NS_LITERAL_CSTRING("array_prototype_values")));
RuntimeService::SetDefaultContextOptions(contextOptions);
diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp
index 09b09a24b..1f79e2c92 100644
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -12,6 +12,7 @@
#include "nsINetworkInterceptController.h"
#include "nsIOutputStream.h"
#include "nsIScriptError.h"
+#include "nsITimedChannel.h"
#include "nsIUnicodeDecoder.h"
#include "nsIUnicodeEncoder.h"
#include "nsContentPolicyUtils.h"
@@ -108,6 +109,12 @@ NS_IMETHODIMP
CancelChannelRunnable::Run()
{
MOZ_ASSERT(NS_IsMainThread());
+
+ // TODO: When bug 1204254 is implemented, this time marker should be moved to
+ // the point where the body of the network request is complete.
+ mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
+ mChannel->SaveTimeStampsToUnderlyingChannel();
+
mChannel->Cancel(mStatus);
mRegistration->MaybeScheduleUpdate();
return NS_OK;
@@ -230,6 +237,9 @@ public:
return NS_OK;
}
+ mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
+ mChannel->SaveTimeStampsToUnderlyingChannel();
+
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
if (obsService) {
obsService->NotifyObservers(underlyingChannel, "service-worker-synthesized-response", nullptr);
@@ -948,10 +958,8 @@ ExtendableEvent::GetPromise()
}
JSContext* cx = jsapi.cx();
- GlobalObject global(cx, globalObj->GetGlobalJSObject());
-
ErrorResult result;
- RefPtr<Promise> p = Promise::All(global, Move(mPromises), result);
+ RefPtr<Promise> p = Promise::All(cx, Move(mPromises), result);
if (NS_WARN_IF(result.MaybeSetPendingException(cx))) {
return nullptr;
}
diff --git a/dom/workers/ServiceWorkerPrivate.cpp b/dom/workers/ServiceWorkerPrivate.cpp
index eaa548f95..24b2e11e6 100644
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -13,6 +13,7 @@
#include "nsINetworkInterceptController.h"
#include "nsIPushErrorReporter.h"
#include "nsISupportsImpl.h"
+#include "nsITimedChannel.h"
#include "nsIUploadChannel2.h"
#include "nsNetUtil.h"
#include "nsProxyRelease.h"
@@ -1255,6 +1256,7 @@ class FetchEventRunnable : public ExtendableFunctionalEventWorkerRunnable
nsCString mMethod;
nsString mClientId;
bool mIsReload;
+ bool mMarkLaunchServiceWorkerEnd;
RequestCache mCacheMode;
RequestMode mRequestMode;
RequestRedirect mRequestRedirect;
@@ -1273,13 +1275,15 @@ public:
const nsACString& aScriptSpec,
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
const nsAString& aDocumentId,
- bool aIsReload)
+ bool aIsReload,
+ bool aMarkLaunchServiceWorkerEnd)
: ExtendableFunctionalEventWorkerRunnable(
aWorkerPrivate, aKeepAliveToken, aRegistration)
, mInterceptedChannel(aChannel)
, mScriptSpec(aScriptSpec)
, mClientId(aDocumentId)
, mIsReload(aIsReload)
+ , mMarkLaunchServiceWorkerEnd(aMarkLaunchServiceWorkerEnd)
, mCacheMode(RequestCache::Default)
, mRequestMode(RequestMode::No_cors)
, mRequestRedirect(RequestRedirect::Follow)
@@ -1417,6 +1421,12 @@ public:
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
MOZ_ASSERT(aWorkerPrivate);
+
+ if (mMarkLaunchServiceWorkerEnd) {
+ mInterceptedChannel->SetLaunchServiceWorkerEnd(TimeStamp::Now());
+ }
+
+ mInterceptedChannel->SetDispatchFetchEventEnd(TimeStamp::Now());
return DispatchFetchEvent(aCx, aWorkerPrivate);
}
@@ -1445,6 +1455,10 @@ private:
NS_IMETHOD Run() override
{
AssertIsOnMainThread();
+
+ mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
+ mChannel->SaveTimeStampsToUnderlyingChannel();
+
nsresult rv = mChannel->ResetInterception();
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to resume intercepted network request");
@@ -1520,6 +1534,8 @@ private:
event->PostInit(mInterceptedChannel, mRegistration, mScriptSpec);
event->SetTrusted(true);
+ mInterceptedChannel->SetHandleFetchEventStart(TimeStamp::Now());
+
RefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
nsresult rv2 = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv2)) || !event->WaitToRespond()) {
@@ -1614,9 +1630,21 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
nsCOMPtr<nsIRunnable> failRunnable =
NewRunnableMethod(aChannel, &nsIInterceptedChannel::ResetInterception);
- nsresult rv = SpawnWorkerIfNeeded(FetchEvent, failRunnable, aLoadGroup);
+ aChannel->SetLaunchServiceWorkerStart(TimeStamp::Now());
+ aChannel->SetDispatchFetchEventStart(TimeStamp::Now());
+
+ bool newWorkerCreated = false;
+ nsresult rv = SpawnWorkerIfNeeded(FetchEvent,
+ failRunnable,
+ &newWorkerCreated,
+ aLoadGroup);
+
NS_ENSURE_SUCCESS(rv, rv);
+ if (!newWorkerCreated) {
+ aChannel->SetLaunchServiceWorkerEnd(TimeStamp::Now());
+ }
+
nsMainThreadPtrHandle<nsIInterceptedChannel> handle(
new nsMainThreadPtrHolder<nsIInterceptedChannel>(aChannel, false));
@@ -1646,7 +1674,7 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
RefPtr<FetchEventRunnable> r =
new FetchEventRunnable(mWorkerPrivate, token, handle,
mInfo->ScriptSpec(), regInfo,
- aDocumentId, aIsReload);
+ aDocumentId, aIsReload, newWorkerCreated);
rv = r->Init();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@@ -1669,6 +1697,7 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
nsresult
ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
nsIRunnable* aLoadFailedRunnable,
+ bool* aNewWorkerCreated,
nsILoadGroup* aLoadGroup)
{
AssertIsOnMainThread();
@@ -1679,6 +1708,12 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
// the overriden load group when intercepting a fetch.
MOZ_ASSERT_IF(aWhy == FetchEvent, aLoadGroup);
+ // Defaults to no new worker created, but if there is one, we'll set the value
+ // to true at the end of this function.
+ if (aNewWorkerCreated) {
+ *aNewWorkerCreated = false;
+ }
+
if (mWorkerPrivate) {
mWorkerPrivate->UpdateOverridenLoadGroup(aLoadGroup);
RenewKeepAliveToken(aWhy);
@@ -1762,6 +1797,10 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
RenewKeepAliveToken(aWhy);
+ if (aNewWorkerCreated) {
+ *aNewWorkerCreated = true;
+ }
+
return NS_OK;
}
diff --git a/dom/workers/ServiceWorkerPrivate.h b/dom/workers/ServiceWorkerPrivate.h
index 8d59ea1d0..911b07a11 100644
--- a/dom/workers/ServiceWorkerPrivate.h
+++ b/dom/workers/ServiceWorkerPrivate.h
@@ -189,6 +189,7 @@ private:
nsresult
SpawnWorkerIfNeeded(WakeUpReason aWhy,
nsIRunnable* aLoadFailedRunnable,
+ bool* aNewWorkerCreated = nullptr,
nsILoadGroup* aLoadGroup = nullptr);
~ServiceWorkerPrivate();
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index c2ab4aca3..8848e881a 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -495,6 +495,82 @@ private:
}
};
+class ReportCompileErrorRunnable final : public WorkerRunnable
+{
+public:
+ static void
+ CreateAndDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+ {
+ MOZ_ASSERT(aWorkerPrivate);
+ aWorkerPrivate->AssertIsOnWorkerThread();
+
+ RefPtr<ReportCompileErrorRunnable> runnable =
+ new ReportCompileErrorRunnable(aCx, aWorkerPrivate);
+ runnable->Dispatch();
+ }
+
+private:
+ ReportCompileErrorRunnable(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+ : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount)
+ {
+ aWorkerPrivate->AssertIsOnWorkerThread();
+ }
+
+ void
+ PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
+ {
+ aWorkerPrivate->AssertIsOnWorkerThread();
+
+ // Dispatch may fail if the worker was canceled, no need to report that as
+ // an error, so don't call base class PostDispatch.
+ }
+
+ bool
+ WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+ {
+ if (aWorkerPrivate->IsFrozen() ||
+ aWorkerPrivate->IsParentWindowPaused()) {
+ MOZ_ASSERT(!IsDebuggerRunnable());
+ aWorkerPrivate->QueueRunnable(this);
+ return true;
+ }
+
+ if (aWorkerPrivate->IsSharedWorker()) {
+ aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, EmptyString(),
+ EmptyString(),
+ EmptyString(), 0, 0,
+ JSREPORT_ERROR,
+ /* isErrorEvent */ false);
+ return true;
+ }
+
+ if (aWorkerPrivate->IsServiceWorker()) {
+ RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+ if (swm) {
+ swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
+ aWorkerPrivate->WorkerName(),
+ aWorkerPrivate->ScriptURL(),
+ EmptyString(), EmptyString(), EmptyString(),
+ 0, 0, JSREPORT_ERROR, JSEXN_ERR);
+ }
+ return true;
+ }
+
+ if (!aWorkerPrivate->IsAcceptingEvents()) {
+ return true;
+ }
+
+ RefPtr<Event> event =
+ Event::Constructor(aWorkerPrivate, NS_LITERAL_STRING("error"),
+ EventInit());
+ event->SetTrusted(true);
+
+ nsEventStatus status = nsEventStatus_eIgnore;
+ aWorkerPrivate->DispatchDOMEvent(nullptr, event, nullptr, &status);
+ return true;
+ }
+};
+
class CompileScriptRunnable final : public WorkerRunnable
{
nsString mScriptURL;
@@ -538,9 +614,15 @@ private:
}
// Make sure to propagate exceptions from rv onto aCx, so that they will get
- // reported after we return. We do this for all failures on rv, because now
- // we're using rv to track all the state we care about.
- //
+ // reported after we return. We want to propagate just JS exceptions,
+ // because all the other errors are handled when the script is loaded.
+ // See: https://dom.spec.whatwg.org/#concept-event-fire
+ if (rv.Failed() && !rv.IsJSException()) {
+ ReportCompileErrorRunnable::CreateAndDispatch(aCx, aWorkerPrivate);
+ rv.SuppressException();
+ return false;
+ }
+
// This is a little dumb, but aCx is in the null compartment here because we
// set it up that way in our Run(), since we had not created the global at
// that point yet. So we need to enter the compartment of our global,
@@ -1171,7 +1253,8 @@ private:
if (aWorkerPrivate->IsSharedWorker()) {
aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, mMessage, mFilename,
mLine, mLineNumber,
- mColumnNumber, mFlags);
+ mColumnNumber, mFlags,
+ /* isErrorEvent */ true);
return true;
}
@@ -2336,8 +2419,6 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
MOZ_ASSERT_IF(mIsChromeWorker, mIsSecureContext);
MOZ_ASSERT(IsDedicatedWorker());
- mNowBaseTimeStamp = aParent->NowBaseTimeStamp();
- mNowBaseTimeHighRes = aParent->NowBaseTime();
if (aParent->mParentFrozen) {
Freeze(nullptr);
@@ -2368,18 +2449,6 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
.creationOptions().setSecureContext(true);
}
- if (IsDedicatedWorker() && mLoadInfo.mWindow &&
- mLoadInfo.mWindow->GetPerformance()) {
- mNowBaseTimeStamp = mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()->
- GetNavigationStartTimeStamp();
- mNowBaseTimeHighRes =
- mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()->
- GetNavigationStartHighRes();
- } else {
- mNowBaseTimeStamp = CreationTimeStamp();
- mNowBaseTimeHighRes = CreationTime();
- }
-
// Our parent can get suspended after it initiates the async creation
// of a new worker thread. In this case suspend the new worker as well.
if (mLoadInfo.mWindow && mLoadInfo.mWindow->IsSuspended()) {
@@ -3250,7 +3319,8 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
const nsAString& aLine,
uint32_t aLineNumber,
uint32_t aColumnNumber,
- uint32_t aFlags)
+ uint32_t aFlags,
+ bool aIsErrorEvent)
{
AssertIsOnMainThread();
@@ -3281,31 +3351,42 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
// May be null.
nsPIDOMWindowInner* window = sharedWorker->GetOwner();
- RootedDictionary<ErrorEventInit> errorInit(aCx);
- errorInit.mBubbles = false;
- errorInit.mCancelable = true;
- errorInit.mMessage = aMessage;
- errorInit.mFilename = aFilename;
- errorInit.mLineno = aLineNumber;
- errorInit.mColno = aColumnNumber;
-
- RefPtr<ErrorEvent> errorEvent =
- ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
- errorInit);
- if (!errorEvent) {
+ RefPtr<Event> event;
+
+ if (aIsErrorEvent) {
+ RootedDictionary<ErrorEventInit> errorInit(aCx);
+ errorInit.mBubbles = false;
+ errorInit.mCancelable = true;
+ errorInit.mMessage = aMessage;
+ errorInit.mFilename = aFilename;
+ errorInit.mLineno = aLineNumber;
+ errorInit.mColno = aColumnNumber;
+
+ event = ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
+ errorInit);
+ } else {
+ event = Event::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
+ EventInit());
+ }
+
+ if (!event) {
ThrowAndReport(window, NS_ERROR_UNEXPECTED);
continue;
}
- errorEvent->SetTrusted(true);
+ event->SetTrusted(true);
bool defaultActionEnabled;
- nsresult rv = sharedWorker->DispatchEvent(errorEvent, &defaultActionEnabled);
+ nsresult rv = sharedWorker->DispatchEvent(event, &defaultActionEnabled);
if (NS_FAILED(rv)) {
ThrowAndReport(window, rv);
continue;
}
+ if (!aIsErrorEvent) {
+ continue;
+ }
+
if (defaultActionEnabled) {
// Add the owning window to our list so that we will fire an error event
// at it later.
diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h
index 8008f30e5..28283bed7 100644
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -216,8 +216,6 @@ private:
WorkerType mWorkerType;
TimeStamp mCreationTimeStamp;
DOMHighResTimeStamp mCreationTimeHighRes;
- TimeStamp mNowBaseTimeStamp;
- DOMHighResTimeStamp mNowBaseTimeHighRes;
protected:
// The worker is owned by its thread, which is represented here. This is set
@@ -408,7 +406,8 @@ public:
const nsAString& aLine,
uint32_t aLineNumber,
uint32_t aColumnNumber,
- uint32_t aFlags);
+ uint32_t aFlags,
+ bool aIsErrorEvent);
void
WorkerScriptLoaded();
@@ -578,14 +577,11 @@ public:
return mCreationTimeHighRes;
}
- TimeStamp NowBaseTimeStamp() const
+ DOMHighResTimeStamp TimeStampToDOMHighRes(const TimeStamp& aTimeStamp) const
{
- return mNowBaseTimeStamp;
- }
-
- DOMHighResTimeStamp NowBaseTime() const
- {
- return mNowBaseTimeHighRes;
+ MOZ_ASSERT(!aTimeStamp.IsNull());
+ TimeDuration duration = aTimeStamp - mCreationTimeStamp;
+ return duration.ToMilliseconds();
}
nsIPrincipal*
diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp
index d9a987b62..54252e53b 100644
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -968,11 +968,4 @@ IsDebuggerSandbox(JSObject* object)
SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox;
}
-bool
-GetterOnlyJSNative(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
-{
- JS_ReportErrorNumberASCII(aCx, js::GetErrorMessage, nullptr, JSMSG_GETTER_ONLY);
- return false;
-}
-
END_WORKERS_NAMESPACE
diff --git a/dom/workers/Workers.h b/dom/workers/Workers.h
index ad083d3b8..cd15a4d7c 100644
--- a/dom/workers/Workers.h
+++ b/dom/workers/Workers.h
@@ -362,14 +362,6 @@ IsDebuggerGlobal(JSObject* global);
bool
IsDebuggerSandbox(JSObject* object);
-// Throws the JSMSG_GETTER_ONLY exception. This shouldn't be used going
-// forward -- getter-only properties should just use JS_PSG for the setter
-// (implying no setter at all), which will not throw when set in non-strict
-// code but will in strict code. Old code should use this only for temporary
-// compatibility reasons.
-extern bool
-GetterOnlyJSNative(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
-
END_WORKERS_NAMESPACE
#endif // mozilla_dom_workers_workers_h__
diff --git a/dom/workers/test/serviceworkers/chrome.ini b/dom/workers/test/serviceworkers/chrome.ini
index e064e7fd0..6d7dbebd0 100644
--- a/dom/workers/test/serviceworkers/chrome.ini
+++ b/dom/workers/test/serviceworkers/chrome.ini
@@ -3,6 +3,8 @@ skip-if = os == 'android'
support-files =
chrome_helpers.js
empty.js
+ fetch.js
+ hello.html
serviceworker.html
serviceworkerinfo_iframe.html
serviceworkermanager_iframe.html
@@ -10,6 +12,7 @@ support-files =
worker.js
worker2.js
+[test_devtools_serviceworker_interception.html]
[test_privateBrowsing.html]
[test_serviceworkerinfo.xul]
[test_serviceworkermanager.xul]
diff --git a/dom/workers/test/serviceworkers/test_devtools_serviceworker_interception.html b/dom/workers/test/serviceworkers/test_devtools_serviceworker_interception.html
new file mode 100644
index 000000000..d49ebb2c9
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_devtools_serviceworker_interception.html
@@ -0,0 +1,168 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1168875 - test devtools serviceworker interception.</title>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet"
+ type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+// Constants
+const Ci = Components.interfaces;
+const workerScope = "http://mochi.test:8888/chrome/dom/workers/test/serviceworkers/";
+const workerURL = workerScope + "fetch.js";
+const contentPage = workerScope + "hello.html";
+
+function createTestWindow(aURL) {
+ var mainwindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ var win = mainwindow.OpenBrowserWindow(contentPage);
+
+ return new Promise(aResolve => {
+ win.addEventListener("DOMContentLoaded", function callback() {
+ if (win.content.location.href != aURL) {
+ win.gBrowser.loadURI(aURL);
+ return;
+ }
+
+ win.removeEventListener("DOMContentLoaded", callback);
+ aResolve(win.content);
+ });
+ });
+}
+
+function executeTest(aWindow) {
+ var registration;
+
+ return Promise.resolve()
+ // Should not be intercepted.
+ .then(_ => fetchAndCheckTimedChannel(aWindow, false, true, "hello.html"))
+
+ // Regist a service worker.
+ .then(_ => register(aWindow, workerURL, workerScope))
+ .then(r => registration = r)
+
+ // Should be intercpeted and synthesized.
+ .then(_ => fetchAndCheckTimedChannel(aWindow, true, false, "fake.html"))
+
+ // Should be intercepted but still fetch from network.
+ .then(_ => fetchAndCheckTimedChannel(aWindow, true, true,
+ "hello.html?ForBypassingHttpCache"))
+
+ // Tear down
+ .then(_ => registration.unregister());
+}
+
+function register(aWindow, aURL, aScope) {
+ return aWindow.navigator.serviceWorker.register(aURL, {scope: aScope})
+ .then(r => {
+ var worker = r.installing;
+ return new Promise(function(aResolve) {
+ worker.onstatechange = function() {
+ if (worker.state == "activated") {
+ aResolve(r);
+ }
+ }
+ });
+ });
+}
+
+function fetchAndCheckTimedChannel(aWindow, aIntercepted, aFetch, aURL) {
+ var resolveFunction;
+ var promise = new Promise(aResolve => resolveFunction = aResolve);
+
+ var topic = aFetch ? "http-on-examine-response"
+ : "service-worker-synthesized-response";
+
+ function observer(aSubject) {
+ var channel = aSubject.QueryInterface(Ci.nsIChannel);
+ ok(channel.URI.spec.endsWith(aURL));
+
+ var tc = aSubject.QueryInterface(Ci.nsITimedChannel);
+
+ // Check service worker related timings.
+ var serviceWorkerTimings = [{start: tc.launchServiceWorkerStartTime,
+ end: tc.launchServiceWorkerEndTime},
+ {start: tc.dispatchFetchEventStartTime,
+ end: tc.dispatchFetchEventEndTime},
+ {start: tc.handleFetchEventStartTime,
+ end: tc.handleFetchEventEndTime}];
+ if (aIntercepted) {
+ serviceWorkerTimings.reduce((aPreviousTimings, aCurrentTimings) => {
+ ok(aPreviousTimings.start <= aCurrentTimings.start,
+ "Start time order check.");
+ ok(aPreviousTimings.end <= aCurrentTimings.end,
+ "End time order check.");
+ ok(aCurrentTimings.start <= aCurrentTimings.end,
+ "Start time should be smaller than end time.");
+ return aCurrentTimings;
+ });
+ } else {
+ serviceWorkerTimings.forEach(aTimings => {
+ is(aTimings.start, 0);
+ is(aTimings.end, 0);
+ });
+ }
+
+ // Check network related timings.
+ var networkTimings = [tc.domainLookupStartTime,
+ tc.domainLookupEndTime,
+ tc.connectStartTime,
+ tc.connectEndTime,
+ tc.requestStartTime,
+ tc.responseStartTime,
+ tc.responseEndTime];
+ if (aFetch) {
+ networkTimings.reduce((aPreviousTiming, aCurrentTiming) => {
+ ok(aPreviousTiming <= aCurrentTiming);
+ return aCurrentTiming;
+ });
+ } else {
+ networkTimings.forEach(aTiming => is(aTiming, 0));
+ }
+
+ SpecialPowers.removeObserver(observer, topic);
+ resolveFunction();
+ }
+
+ SpecialPowers.addObserver(observer, topic, false);
+
+ // return promise;
+ return Promise.all([aWindow.fetch(aURL), promise]);
+}
+
+function runTest() {
+ return Promise.resolve()
+ .then(_ => createTestWindow(contentPage))
+ .then(w => executeTest(w))
+ .catch(e => ok(false, "Some test failed with error " + e))
+ .then(_ => SimpleTest.finish());
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [
+ ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+ ["dom.serviceWorkers.enabled", true],
+ ["dom.serviceWorkers.testing.enabled", true],
+]}, runTest);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
index 9dbfcc099..a4d498fb8 100644
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -172,9 +172,9 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"PerformanceMeasure",
// IMPORTANT: Do not change this list without review from a DOM peer!
- { name: "PerformanceObserver", nightly: true },
+ "PerformanceObserver",
// IMPORTANT: Do not change this list without review from a DOM peer!
- { name: "PerformanceObserverEntryList", nightly: true },
+ "PerformanceObserverEntryList",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Request",
// IMPORTANT: Do not change this list without review from a DOM peer!
diff --git a/dom/workers/test/test_404.html b/dom/workers/test/test_404.html
index e2e83a35e..15e5ded68 100644
--- a/dom/workers/test/test_404.html
+++ b/dom/workers/test/test_404.html
@@ -25,7 +25,6 @@ Tests of DOM Worker Threads
worker.onerror = function(event) {
is(event.target, worker);
- is(event.message, 'NetworkError: Failed to load worker script at "nonexistent_worker.js"');
event.preventDefault();
SimpleTest.finish();
};
diff --git a/dom/workers/test/test_bug1036484.html b/dom/workers/test/test_bug1036484.html
index 17b9d490f..49c31bbc9 100644
--- a/dom/workers/test/test_bug1036484.html
+++ b/dom/workers/test/test_bug1036484.html
@@ -25,7 +25,6 @@ function test(script) {
worker.onerror = function(event) {
is(event.target, worker);
- ok(event.message.startsWith("NetworkError: Failed to load worker script"))
event.preventDefault();
runTests();
};
diff --git a/dom/workers/test/test_loadError.html b/dom/workers/test/test_loadError.html
index dc109b796..b9a215d11 100644
--- a/dom/workers/test/test_loadError.html
+++ b/dom/workers/test/test_loadError.html
@@ -13,15 +13,13 @@
<script class="testbody" type="text/javascript">
"use strict";
-var loadErrorMessage = 'SecurityError: Failed to load worker script at "about:blank"';
-
function nextTest() {
(function(){
function workerfunc() {
var subworker = new Worker("about:blank");
subworker.onerror = function(e) {
e.preventDefault();
- postMessage(e.message);
+ postMessage("ERROR");
}
}
var b = new Blob([workerfunc+'workerfunc();']);
@@ -37,7 +35,7 @@ function nextTest() {
return;
}
w.onmessage = function(e) {
- is(e.data, loadErrorMessage,
+ is(e.data, "ERROR",
"Should catch the error when loading inner script");
if (++i < 2) callworker(i);
else SimpleTest.finish();
@@ -54,8 +52,6 @@ try {
var worker = new Worker("about:blank");
worker.onerror = function(e) {
e.preventDefault();
- is(e.message, loadErrorMessage,
- "Should get the right error from the toplevel script");
nextTest();
}
diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js
index e0647682c..6fe5fcaff 100644
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -163,9 +163,9 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"PerformanceMeasure",
// IMPORTANT: Do not change this list without review from a DOM peer!
- { name: "PerformanceObserver", nightly: true },
+ "PerformanceObserver",
// IMPORTANT: Do not change this list without review from a DOM peer!
- { name: "PerformanceObserverEntryList", nightly: true },
+ "PerformanceObserverEntryList",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Request",
// IMPORTANT: Do not change this list without review from a DOM peer!
diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp
index a47a01aa0..4fd34a993 100644
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -1081,10 +1081,75 @@ XMLHttpRequestMainThread::CloseRequestWithError(const ProgressEventType aType)
}
void
-XMLHttpRequestMainThread::Abort(ErrorResult& arv)
+XMLHttpRequestMainThread::RequestErrorSteps(const ProgressEventType aEventType,
+ const nsresult aOptionalException,
+ ErrorResult& aRv)
+{
+ // Step 1
+ mState = State::done;
+
+ StopProgressEventTimer();
+
+ // Step 2
+ mFlagSend = false;
+
+ // Step 3
+ ResetResponse();
+
+ // If we're in the destructor, don't risk dispatching an event.
+ if (mFlagDeleted) {
+ mFlagSyncLooping = false;
+ return;
+ }
+
+ // Step 4
+ if (mFlagSynchronous && NS_FAILED(aOptionalException)) {
+ aRv.Throw(aOptionalException);
+ return;
+ }
+
+ // Step 5
+ FireReadystatechangeEvent();
+
+ // Step 6
+ if (mUpload && !mUploadComplete) {
+
+ // Step 6-1
+ mUploadComplete = true;
+
+ // Step 6-2
+ if (mFlagHadUploadListenersOnSend) {
+
+ // Steps 6-3, 6-4 (loadend is fired for us)
+ DispatchProgressEvent(mUpload, aEventType, 0, -1);
+ }
+ }
+
+ // Steps 7 and 8 (loadend is fired for us)
+ DispatchProgressEvent(this, aEventType, 0, -1);
+}
+
+void
+XMLHttpRequestMainThread::Abort(ErrorResult& aRv)
{
mFlagAborted = true;
- CloseRequestWithError(ProgressEventType::abort);
+
+ // Step 1
+ CloseRequest();
+
+ // Step 2
+ if ((mState == State::opened && mFlagSend) ||
+ mState == State::headers_received ||
+ mState == State::loading) {
+ RequestErrorSteps(ProgressEventType::abort, NS_OK, aRv);
+ }
+
+ // Step 3
+ if (mState == State::done) {
+ ChangeState(State::unsent, false); // no ReadystateChange event
+ }
+
+ mFlagSyncLooping = false;
}
NS_IMETHODIMP
diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h
index c9bcddf99..68499874a 100644
--- a/dom/xhr/XMLHttpRequestMainThread.h
+++ b/dom/xhr/XMLHttpRequestMainThread.h
@@ -397,6 +397,11 @@ public:
}
void
+ RequestErrorSteps(const ProgressEventType aEventType,
+ const nsresult aOptionalException,
+ ErrorResult& aRv);
+
+ void
Abort() {
ErrorResult rv;
Abort(rv);
diff --git a/dom/xhr/XMLHttpRequestWorker.cpp b/dom/xhr/XMLHttpRequestWorker.cpp
index f61383baf..e7193a279 100644
--- a/dom/xhr/XMLHttpRequestWorker.cpp
+++ b/dom/xhr/XMLHttpRequestWorker.cpp
@@ -1148,8 +1148,8 @@ EventRunnable::PreDispatch(WorkerPrivate* /* unused */)
} else {
bool doClone = true;
JS::Rooted<JS::Value> transferable(cx);
- JS::Rooted<JSObject*> obj(cx, response.isObjectOrNull() ?
- response.toObjectOrNull() : nullptr);
+ JS::Rooted<JSObject*> obj(cx, response.isObject() ?
+ &response.toObject() : nullptr);
if (obj && JS_IsArrayBufferObject(obj)) {
// Use cached response if the arraybuffer has been transfered.
if (mProxy->mArrayBufferResponseWasTransferred) {
@@ -1669,7 +1669,9 @@ XMLHttpRequestWorker::MaybeDispatchPrematureAbortEvents(ErrorResult& aRv)
// Only send readystatechange event when state changed.
bool isStateChanged = false;
- if (mStateData.mReadyState != 4) {
+ if ((mStateData.mReadyState == 1 && mStateData.mFlagSend) ||
+ mStateData.mReadyState == 2 ||
+ mStateData.mReadyState == 3) {
isStateChanged = true;
mStateData.mReadyState = 4;
}
@@ -1811,6 +1813,8 @@ XMLHttpRequestWorker::SendInternal(SendRunnable* aRunnable,
aRunnable->SetSyncLoopTarget(syncLoopTarget);
aRunnable->SetHaveUploadListeners(hasUploadListeners);
+ mStateData.mFlagSend = true;
+
aRunnable->Dispatch(aRv);
if (aRv.Failed()) {
// Dispatch() may have spun the event loop and we may have already unrooted.
@@ -1837,6 +1841,7 @@ XMLHttpRequestWorker::SendInternal(SendRunnable* aRunnable,
if (!autoSyncLoop->Run() && !aRv.Failed()) {
aRv.Throw(NS_ERROR_FAILURE);
}
+ mStateData.mFlagSend = false;
}
bool
diff --git a/dom/xhr/XMLHttpRequestWorker.h b/dom/xhr/XMLHttpRequestWorker.h
index 90232fe85..c6647f8f3 100644
--- a/dom/xhr/XMLHttpRequestWorker.h
+++ b/dom/xhr/XMLHttpRequestWorker.h
@@ -34,15 +34,16 @@ public:
uint32_t mStatus;
nsCString mStatusText;
uint16_t mReadyState;
+ bool mFlagSend;
JS::Heap<JS::Value> mResponse;
nsresult mResponseTextResult;
nsresult mStatusResult;
nsresult mResponseResult;
StateData()
- : mStatus(0), mReadyState(0), mResponse(JS::UndefinedValue()),
- mResponseTextResult(NS_OK), mStatusResult(NS_OK),
- mResponseResult(NS_OK)
+ : mStatus(0), mReadyState(0), mFlagSend(false),
+ mResponse(JS::UndefinedValue()), mResponseTextResult(NS_OK),
+ mStatusResult(NS_OK), mResponseResult(NS_OK)
{ }
void trace(JSTracer* trc);
diff --git a/dom/xslt/xpath/txXPCOMExtensionFunction.cpp b/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
index 4913702aa..032161722 100644
--- a/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
+++ b/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
@@ -322,7 +322,7 @@ public:
void trace(JSTracer* trc) {
for (uint8_t i = 0; i < mCount; ++i) {
if (mArray[i].type == nsXPTType::T_JSVAL) {
- JS::UnsafeTraceRoot(trc, &mArray[i].val.j, "txParam value");
+ JS::UnsafeTraceRoot(trc, &mArray[i].val.j.asValueRef(), "txParam value");
}
}
}
diff --git a/dom/xul/XULDocument.cpp b/dom/xul/XULDocument.cpp
index ae3cdb7eb..1dcb55aee 100644
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -1919,26 +1919,26 @@ XULDocument::StartLayout(void)
/* static */
bool
-XULDocument::MatchAttribute(nsIContent* aContent,
+XULDocument::MatchAttribute(Element* aElement,
int32_t aNamespaceID,
nsIAtom* aAttrName,
void* aData)
{
- NS_PRECONDITION(aContent, "Must have content node to work with!");
+ NS_PRECONDITION(aElement, "Must have content node to work with!");
nsString* attrValue = static_cast<nsString*>(aData);
if (aNamespaceID != kNameSpaceID_Unknown &&
aNamespaceID != kNameSpaceID_Wildcard) {
return attrValue->EqualsLiteral("*") ?
- aContent->HasAttr(aNamespaceID, aAttrName) :
- aContent->AttrValueIs(aNamespaceID, aAttrName, *attrValue,
+ aElement->HasAttr(aNamespaceID, aAttrName) :
+ aElement->AttrValueIs(aNamespaceID, aAttrName, *attrValue,
eCaseMatters);
}
// Qualified name match. This takes more work.
- uint32_t count = aContent->GetAttrCount();
+ uint32_t count = aElement->GetAttrCount();
for (uint32_t i = 0; i < count; ++i) {
- const nsAttrName* name = aContent->GetAttrNameAt(i);
+ const nsAttrName* name = aElement->GetAttrNameAt(i);
bool nameMatch;
if (name->IsAtom()) {
nameMatch = name->Atom() == aAttrName;
@@ -1950,7 +1950,7 @@ XULDocument::MatchAttribute(nsIContent* aContent,
if (nameMatch) {
return attrValue->EqualsLiteral("*") ||
- aContent->AttrValueIs(name->NamespaceID(), name->LocalName(),
+ aElement->AttrValueIs(name->NamespaceID(), name->LocalName(),
*attrValue, eCaseMatters);
}
}
diff --git a/dom/xul/XULDocument.h b/dom/xul/XULDocument.h
index a2f82bb89..06abb797f 100644
--- a/dom/xul/XULDocument.h
+++ b/dom/xul/XULDocument.h
@@ -180,7 +180,7 @@ public:
NS_IMETHOD OnScriptCompileComplete(JSScript* aScript, nsresult aStatus) override;
static bool
- MatchAttribute(nsIContent* aContent,
+ MatchAttribute(Element* aContent,
int32_t aNameSpaceID,
nsIAtom* aAttrName,
void* aData);