summaryrefslogtreecommitdiffstats
path: root/dom
diff options
context:
space:
mode:
Diffstat (limited to 'dom')
-rw-r--r--dom/base/BlobSet.h3
-rw-r--r--dom/base/CORSMode.h2
-rw-r--r--dom/base/ChromeUtils.cpp1
-rw-r--r--dom/base/ChromeUtils.h1
-rw-r--r--dom/base/CustomElementRegistry.cpp3
-rw-r--r--dom/base/DocGroup.cpp1
-rw-r--r--dom/base/DocGroup.h1
-rw-r--r--dom/base/GroupedSHistory.h2
-rw-r--r--dom/base/ImageTracker.cpp2
-rw-r--r--dom/base/ImageTracker.h1
-rw-r--r--dom/base/MutableBlobStorage.h3
-rw-r--r--dom/base/MutableBlobStreamListener.cpp1
-rw-r--r--dom/base/Navigator.cpp59
-rw-r--r--dom/base/Navigator.h9
-rw-r--r--dom/base/NodeInfo.cpp1
-rw-r--r--dom/base/Pose.h1
-rw-r--r--dom/base/TabGroup.h2
-rw-r--r--dom/base/ThirdPartyUtil.cpp1
-rw-r--r--dom/base/TimeoutHandler.cpp1
-rw-r--r--dom/base/TimeoutHandler.h2
-rwxr-xr-xdom/base/TimerClamping.h2
-rwxr-xr-xdom/base/moz.build4
-rw-r--r--dom/base/nsAttrValue.cpp34
-rw-r--r--dom/base/nsAttrValue.h13
-rw-r--r--dom/base/nsContentUtils.cpp1
-rw-r--r--dom/base/nsContentUtils.h4
-rw-r--r--dom/base/nsDOMMutationObserver.cpp4
-rw-r--r--dom/base/nsDocument.cpp8
-rw-r--r--dom/base/nsFocusManager.cpp9
-rw-r--r--dom/base/nsJSEnvironment.cpp1
-rw-r--r--dom/base/nsJSUtils.cpp1
-rw-r--r--dom/base/nsScriptLoader.cpp2
-rw-r--r--dom/bindings/Bindings.conf13
-rw-r--r--dom/bindings/Codegen.py6
-rw-r--r--dom/bindings/GenerateCSS2PropertiesWebIDL.py1
-rw-r--r--dom/bindings/WebIDLGlobalNameHash.cpp4
-rw-r--r--dom/bindings/WebIDLGlobalNameHash.h1
-rw-r--r--dom/bindings/moz.build2
-rw-r--r--dom/bindings/mozwebidlcodegen/__init__.py1
-rw-r--r--dom/bindings/nsScriptError.h5
-rw-r--r--dom/bindings/nsScriptErrorWithStack.cpp4
-rw-r--r--dom/events/test/test_all_synthetic_events.html4
-rw-r--r--dom/flyweb/FlyWebDiscoveryManager.cpp125
-rw-r--r--dom/flyweb/FlyWebDiscoveryManager.h61
-rw-r--r--dom/flyweb/FlyWebPublishOptionsIPCSerializer.h33
-rw-r--r--dom/flyweb/FlyWebPublishedServer.cpp675
-rw-r--r--dom/flyweb/FlyWebPublishedServer.h109
-rw-r--r--dom/flyweb/FlyWebPublishedServerIPC.h172
-rw-r--r--dom/flyweb/FlyWebServerEvents.cpp141
-rw-r--r--dom/flyweb/FlyWebServerEvents.h88
-rw-r--r--dom/flyweb/FlyWebService.cpp1310
-rw-r--r--dom/flyweb/FlyWebService.h113
-rw-r--r--dom/flyweb/HttpServer.cpp1319
-rw-r--r--dom/flyweb/HttpServer.h193
-rw-r--r--dom/flyweb/PFlyWebPublishedServer.ipdl38
-rw-r--r--dom/flyweb/moz.build42
-rw-r--r--dom/heapsnapshot/.gitattributes1
-rw-r--r--dom/heapsnapshot/AutoMemMap.cpp64
-rw-r--r--dom/heapsnapshot/AutoMemMap.h75
-rw-r--r--dom/heapsnapshot/CoreDump.pb.cc2542
-rw-r--r--dom/heapsnapshot/CoreDump.pb.h1893
-rw-r--r--dom/heapsnapshot/CoreDump.proto143
-rw-r--r--dom/heapsnapshot/DeserializedNode.cpp150
-rw-r--r--dom/heapsnapshot/DeserializedNode.h317
-rw-r--r--dom/heapsnapshot/DominatorTree.cpp140
-rw-r--r--dom/heapsnapshot/DominatorTree.h67
-rw-r--r--dom/heapsnapshot/FileDescriptorOutputStream.cpp86
-rw-r--r--dom/heapsnapshot/FileDescriptorOutputStream.h41
-rw-r--r--dom/heapsnapshot/HeapSnapshot.cpp1619
-rw-r--r--dom/heapsnapshot/HeapSnapshot.h224
-rw-r--r--dom/heapsnapshot/HeapSnapshotTempFileHelperChild.h32
-rw-r--r--dom/heapsnapshot/HeapSnapshotTempFileHelperParent.cpp53
-rw-r--r--dom/heapsnapshot/HeapSnapshotTempFileHelperParent.h35
-rw-r--r--dom/heapsnapshot/PHeapSnapshotTempFileHelper.ipdl35
-rw-r--r--dom/heapsnapshot/ZeroCopyNSIOutputStream.cpp100
-rw-r--r--dom/heapsnapshot/ZeroCopyNSIOutputStream.h70
-rw-r--r--dom/heapsnapshot/generate-core-dump-sources.sh26
-rw-r--r--dom/heapsnapshot/moz.build52
-rw-r--r--dom/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp100
-rw-r--r--dom/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp91
-rw-r--r--dom/heapsnapshot/tests/gtest/DevTools.h276
-rw-r--r--dom/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp73
-rw-r--r--dom/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp64
-rw-r--r--dom/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp53
-rw-r--r--dom/heapsnapshot/tests/gtest/SerializesEverythingInHeapGraphOnce.cpp37
-rw-r--r--dom/heapsnapshot/tests/gtest/SerializesTypeNames.cpp30
-rw-r--r--dom/heapsnapshot/tests/gtest/moz.build31
-rw-r--r--dom/heapsnapshot/tests/mochitest/chrome.ini8
-rw-r--r--dom/heapsnapshot/tests/mochitest/mochitest.ini6
-rw-r--r--dom/heapsnapshot/tests/mochitest/test_DominatorTree_01.html37
-rw-r--r--dom/heapsnapshot/tests/mochitest/test_SaveHeapSnapshot.html25
-rw-r--r--dom/heapsnapshot/tests/mochitest/test_saveHeapSnapshot_e10s_01.html82
-rw-r--r--dom/heapsnapshot/tests/unit/.eslintrc.js6
-rw-r--r--dom/heapsnapshot/tests/unit/Census.jsm165
-rw-r--r--dom/heapsnapshot/tests/unit/Match.jsm190
-rw-r--r--dom/heapsnapshot/tests/unit/dominator-tree-worker.js47
-rw-r--r--dom/heapsnapshot/tests/unit/head_heapsnapshot.js448
-rw-r--r--dom/heapsnapshot/tests/unit/heap-snapshot-worker.js46
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_01.js46
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_02.js45
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_03.js47
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_04.js53
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTreeNode_attachShortestPaths_01.js132
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTreeNode_getNodeByIdAlongPath_01.js44
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_01.js112
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_02.js30
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_03.js117
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTreeNode_partialTraversal_01.js164
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTree_01.js23
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTree_02.js40
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTree_03.js13
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTree_04.js22
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTree_05.js75
-rw-r--r--dom/heapsnapshot/tests/unit/test_DominatorTree_06.js56
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_01.js22
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_02.js23
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_01.js59
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_02.js22
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_03.js62
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_getCensusIndividuals_01.js89
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_getCreationTime_01.js58
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_01.js69
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_02.js31
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_getImmediatelyDominated_01.js81
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_readHeapSnapshot_01.js18
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_01.js54
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_02.js59
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_01.js27
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_02.js29
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_03.js48
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_04.js118
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_05.js44
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_06.js109
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_07.js52
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_01.js69
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_02.js47
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_creationTime_01.js30
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_deepStack_01.js70
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_describeNode_01.js42
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_01.js31
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_02.js57
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_03.js34
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_04.js36
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_05.js24
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_06.js125
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_07.js82
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_08.js82
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_09.js92
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_10.js68
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_11.js116
-rw-r--r--dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_12.js50
-rw-r--r--dom/heapsnapshot/tests/unit/test_ReadHeapSnapshot.js20
-rw-r--r--dom/heapsnapshot/tests/unit/test_ReadHeapSnapshot_with_allocations.js36
-rw-r--r--dom/heapsnapshot/tests/unit/test_ReadHeapSnapshot_worker.js40
-rw-r--r--dom/heapsnapshot/tests/unit/test_SaveHeapSnapshot.js82
-rw-r--r--dom/heapsnapshot/tests/unit/test_census-tree-node-01.js76
-rw-r--r--dom/heapsnapshot/tests/unit/test_census-tree-node-02.js136
-rw-r--r--dom/heapsnapshot/tests/unit/test_census-tree-node-03.js96
-rw-r--r--dom/heapsnapshot/tests/unit/test_census-tree-node-04.js159
-rw-r--r--dom/heapsnapshot/tests/unit/test_census-tree-node-05.js145
-rw-r--r--dom/heapsnapshot/tests/unit/test_census-tree-node-06.js200
-rw-r--r--dom/heapsnapshot/tests/unit/test_census-tree-node-07.js200
-rw-r--r--dom/heapsnapshot/tests/unit/test_census-tree-node-08.js142
-rw-r--r--dom/heapsnapshot/tests/unit/test_census-tree-node-09.js44
-rw-r--r--dom/heapsnapshot/tests/unit/test_census-tree-node-10.js43
-rw-r--r--dom/heapsnapshot/tests/unit/test_census_diff_01.js74
-rw-r--r--dom/heapsnapshot/tests/unit/test_census_diff_02.js25
-rw-r--r--dom/heapsnapshot/tests/unit/test_census_diff_03.js73
-rw-r--r--dom/heapsnapshot/tests/unit/test_census_diff_04.js63
-rw-r--r--dom/heapsnapshot/tests/unit/test_census_diff_05.js34
-rw-r--r--dom/heapsnapshot/tests/unit/test_census_diff_06.js137
-rw-r--r--dom/heapsnapshot/tests/unit/test_census_filtering_01.js105
-rw-r--r--dom/heapsnapshot/tests/unit/test_census_filtering_02.js124
-rw-r--r--dom/heapsnapshot/tests/unit/test_census_filtering_03.js59
-rw-r--r--dom/heapsnapshot/tests/unit/test_census_filtering_04.js102
-rw-r--r--dom/heapsnapshot/tests/unit/test_census_filtering_05.js71
-rw-r--r--dom/heapsnapshot/tests/unit/test_countToBucketBreakdown_01.js37
-rw-r--r--dom/heapsnapshot/tests/unit/test_deduplicatePaths_01.js113
-rw-r--r--dom/heapsnapshot/tests/unit/test_getCensusIndividuals_01.js60
-rw-r--r--dom/heapsnapshot/tests/unit/test_getReportLeaves_01.js114
-rw-r--r--dom/heapsnapshot/tests/unit/test_saveHeapSnapshot_e10s_01.js8
-rw-r--r--dom/heapsnapshot/tests/unit/xpcshell.ini98
-rw-r--r--dom/html/HTMLLabelElement.h2
-rw-r--r--dom/html/HTMLMediaElement.cpp18
-rw-r--r--dom/html/HTMLObjectElement.h2
-rw-r--r--dom/html/HTMLOptGroupElement.cpp11
-rw-r--r--dom/html/HTMLOptGroupElement.h4
-rw-r--r--dom/html/HTMLOptionElement.h4
-rw-r--r--dom/html/HTMLOutputElement.h2
-rw-r--r--dom/html/HTMLTableCellElement.cpp22
-rw-r--r--dom/html/HTMLTableCellElement.h4
-rw-r--r--dom/html/nsGenericHTMLElement.cpp21
-rw-r--r--dom/html/nsGenericHTMLElement.h6
-rw-r--r--dom/indexedDB/ActorsChild.cpp6
-rw-r--r--dom/inputmethod/moz.build5
-rw-r--r--dom/interfaces/base/nsIDOMWindowUtils.idl2
-rw-r--r--dom/ipc/ContentChild.cpp62
-rw-r--r--dom/ipc/ContentChild.h17
-rw-r--r--dom/ipc/ContentParent.cpp41
-rw-r--r--dom/ipc/ContentParent.h12
-rw-r--r--dom/ipc/PContent.ipdl21
-rw-r--r--dom/mathml/nsMathMLElement.cpp20
-rw-r--r--dom/media/AbstractMediaDecoder.h2
-rw-r--r--dom/media/MediaDecoder.cpp6
-rw-r--r--dom/media/MediaDecoder.h8
-rw-r--r--dom/media/MediaDecoderReader.h4
-rw-r--r--dom/media/MediaDecoderReaderWrapper.h2
-rw-r--r--dom/media/MediaDecoderStateMachine.cpp15
-rw-r--r--dom/media/MediaDecoderStateMachine.h2
-rw-r--r--dom/media/MediaFormatReader.cpp5
-rw-r--r--dom/media/MediaFormatReader.h6
-rw-r--r--dom/media/PeerConnection.js2
-rw-r--r--dom/media/fmp4/MP4Decoder.cpp2
-rw-r--r--dom/media/gmp/GMPChild.cpp6
-rw-r--r--dom/media/gmp/GMPDecryptorParent.cpp29
-rw-r--r--dom/media/gmp/GMPDecryptorProxy.h7
-rw-r--r--dom/media/gmp/GMPParent.cpp11
-rw-r--r--dom/media/gmp/moz.build24
-rw-r--r--dom/media/gtest/MockMediaDecoderOwner.h2
-rw-r--r--dom/media/gtest/moz.build5
-rw-r--r--dom/media/mediasource/TrackBuffersManager.cpp2
-rw-r--r--dom/media/moz.build4
-rw-r--r--dom/media/platforms/PDMFactory.cpp7
-rw-r--r--dom/media/platforms/PDMFactory.h4
-rw-r--r--dom/media/platforms/moz.build4
-rw-r--r--dom/moz.build4
-rw-r--r--dom/performance/Performance.h2
-rw-r--r--dom/performance/PerformanceMainThread.cpp9
-rw-r--r--dom/performance/PerformanceMainThread.h4
-rw-r--r--dom/performance/PerformanceWorker.h2
-rw-r--r--dom/plugins/base/PluginPRLibrary.cpp35
-rw-r--r--dom/plugins/base/android/ANPAudio.cpp390
-rw-r--r--dom/plugins/base/android/ANPBase.h36
-rw-r--r--dom/plugins/base/android/ANPEvent.cpp31
-rw-r--r--dom/plugins/base/android/ANPKeyCodes.h152
-rw-r--r--dom/plugins/base/android/ANPLog.cpp26
-rw-r--r--dom/plugins/base/android/ANPNativeWindow.cpp39
-rw-r--r--dom/plugins/base/android/ANPSurface.cpp266
-rw-r--r--dom/plugins/base/android/ANPSystem.cpp88
-rw-r--r--dom/plugins/base/android/ANPVideo.cpp55
-rw-r--r--dom/plugins/base/android/ANPWindow.cpp152
-rw-r--r--dom/plugins/base/android/android_npapi.h1027
-rw-r--r--dom/plugins/base/android/moz.build35
-rw-r--r--dom/plugins/base/moz.build11
-rw-r--r--dom/plugins/base/npfunctions.h9
-rw-r--r--dom/plugins/base/nsNPAPIPlugin.cpp184
-rw-r--r--dom/plugins/base/nsNPAPIPluginInstance.cpp357
-rw-r--r--dom/plugins/base/nsNPAPIPluginInstance.h127
-rw-r--r--dom/plugins/base/nsPluginHost.cpp70
-rw-r--r--dom/plugins/base/nsPluginInstanceOwner.cpp453
-rw-r--r--dom/plugins/base/nsPluginInstanceOwner.h30
-rw-r--r--dom/plugins/base/nsPluginTags.cpp5
-rw-r--r--dom/plugins/base/nsPluginsDirUnix.cpp10
-rw-r--r--dom/plugins/ipc/NPEventAndroid.h55
-rw-r--r--dom/plugins/ipc/PluginInstanceChild.cpp2
-rw-r--r--dom/plugins/ipc/PluginInstanceParent.cpp3
-rw-r--r--dom/plugins/ipc/PluginMessageUtils.h4
-rw-r--r--dom/plugins/ipc/moz.build1
-rw-r--r--dom/presentation/AvailabilityCollection.cpp99
-rw-r--r--dom/presentation/AvailabilityCollection.h45
-rw-r--r--dom/presentation/ControllerConnectionCollection.cpp116
-rw-r--r--dom/presentation/ControllerConnectionCollection.h49
-rw-r--r--dom/presentation/DCPresentationChannelDescription.cpp46
-rw-r--r--dom/presentation/DCPresentationChannelDescription.h37
-rw-r--r--dom/presentation/Presentation.cpp182
-rw-r--r--dom/presentation/Presentation.h70
-rw-r--r--dom/presentation/PresentationAvailability.cpp206
-rw-r--r--dom/presentation/PresentationAvailability.h74
-rw-r--r--dom/presentation/PresentationCallbacks.cpp282
-rw-r--r--dom/presentation/PresentationCallbacks.h85
-rw-r--r--dom/presentation/PresentationConnection.cpp763
-rw-r--r--dom/presentation/PresentationConnection.h128
-rw-r--r--dom/presentation/PresentationConnectionList.cpp125
-rw-r--r--dom/presentation/PresentationConnectionList.h57
-rw-r--r--dom/presentation/PresentationDataChannelSessionTransport.js378
-rw-r--r--dom/presentation/PresentationDataChannelSessionTransport.manifest6
-rw-r--r--dom/presentation/PresentationDeviceInfoManager.js119
-rw-r--r--dom/presentation/PresentationDeviceInfoManager.jsm104
-rw-r--r--dom/presentation/PresentationDeviceInfoManager.manifest3
-rw-r--r--dom/presentation/PresentationDeviceManager.cpp336
-rw-r--r--dom/presentation/PresentationDeviceManager.h54
-rw-r--r--dom/presentation/PresentationLog.h26
-rw-r--r--dom/presentation/PresentationNetworkHelper.js28
-rw-r--r--dom/presentation/PresentationNetworkHelper.manifest3
-rw-r--r--dom/presentation/PresentationReceiver.cpp179
-rw-r--r--dom/presentation/PresentationReceiver.h71
-rw-r--r--dom/presentation/PresentationRequest.cpp563
-rw-r--r--dom/presentation/PresentationRequest.h84
-rw-r--r--dom/presentation/PresentationService.cpp1188
-rw-r--r--dom/presentation/PresentationService.h68
-rw-r--r--dom/presentation/PresentationServiceBase.h401
-rw-r--r--dom/presentation/PresentationSessionInfo.cpp1617
-rw-r--r--dom/presentation/PresentationSessionInfo.h304
-rw-r--r--dom/presentation/PresentationSessionRequest.cpp72
-rw-r--r--dom/presentation/PresentationSessionRequest.h41
-rw-r--r--dom/presentation/PresentationTCPSessionTransport.cpp589
-rw-r--r--dom/presentation/PresentationTCPSessionTransport.h110
-rw-r--r--dom/presentation/PresentationTerminateRequest.cpp73
-rw-r--r--dom/presentation/PresentationTerminateRequest.h41
-rw-r--r--dom/presentation/PresentationTransportBuilderConstructor.cpp85
-rw-r--r--dom/presentation/PresentationTransportBuilderConstructor.h48
-rw-r--r--dom/presentation/interfaces/moz.build30
-rw-r--r--dom/presentation/interfaces/nsIPresentationControlChannel.idl139
-rw-r--r--dom/presentation/interfaces/nsIPresentationControlService.idl156
-rw-r--r--dom/presentation/interfaces/nsIPresentationDevice.idl43
-rw-r--r--dom/presentation/interfaces/nsIPresentationDeviceManager.idl51
-rw-r--r--dom/presentation/interfaces/nsIPresentationDevicePrompt.idl58
-rw-r--r--dom/presentation/interfaces/nsIPresentationDeviceProvider.idl75
-rw-r--r--dom/presentation/interfaces/nsIPresentationListener.idl50
-rw-r--r--dom/presentation/interfaces/nsIPresentationLocalDevice.idl17
-rw-r--r--dom/presentation/interfaces/nsIPresentationNetworkHelper.idl36
-rw-r--r--dom/presentation/interfaces/nsIPresentationRequestUIGlue.idl29
-rw-r--r--dom/presentation/interfaces/nsIPresentationService.idl275
-rw-r--r--dom/presentation/interfaces/nsIPresentationSessionRequest.idl35
-rw-r--r--dom/presentation/interfaces/nsIPresentationSessionTransport.idl69
-rw-r--r--dom/presentation/interfaces/nsIPresentationSessionTransportBuilder.idl80
-rw-r--r--dom/presentation/interfaces/nsIPresentationTerminateRequest.idl33
-rw-r--r--dom/presentation/ipc/PPresentation.ipdl112
-rw-r--r--dom/presentation/ipc/PPresentationBuilder.ipdl34
-rw-r--r--dom/presentation/ipc/PPresentationRequest.ipdl22
-rw-r--r--dom/presentation/ipc/PresentationBuilderChild.cpp184
-rw-r--r--dom/presentation/ipc/PresentationBuilderChild.h48
-rw-r--r--dom/presentation/ipc/PresentationBuilderParent.cpp267
-rw-r--r--dom/presentation/ipc/PresentationBuilderParent.h52
-rw-r--r--dom/presentation/ipc/PresentationChild.cpp198
-rw-r--r--dom/presentation/ipc/PresentationChild.h101
-rw-r--r--dom/presentation/ipc/PresentationContentSessionInfo.cpp109
-rw-r--r--dom/presentation/ipc/PresentationContentSessionInfo.h62
-rw-r--r--dom/presentation/ipc/PresentationIPCService.cpp538
-rw-r--r--dom/presentation/ipc/PresentationIPCService.h75
-rw-r--r--dom/presentation/ipc/PresentationParent.cpp553
-rw-r--r--dom/presentation/ipc/PresentationParent.h137
-rw-r--r--dom/presentation/moz.build89
-rw-r--r--dom/presentation/provider/AndroidCastDeviceProvider.js461
-rw-r--r--dom/presentation/provider/AndroidCastDeviceProvider.manifest4
-rw-r--r--dom/presentation/provider/BuiltinProviders.manifest2
-rw-r--r--dom/presentation/provider/ControllerStateMachine.jsm240
-rw-r--r--dom/presentation/provider/DeviceProviderHelpers.cpp57
-rw-r--r--dom/presentation/provider/DeviceProviderHelpers.h30
-rw-r--r--dom/presentation/provider/DisplayDeviceProvider.cpp580
-rw-r--r--dom/presentation/provider/DisplayDeviceProvider.h136
-rw-r--r--dom/presentation/provider/LegacyMDNSDeviceProvider.cpp774
-rw-r--r--dom/presentation/provider/LegacyMDNSDeviceProvider.h191
-rw-r--r--dom/presentation/provider/LegacyPresentationControlService.js488
-rw-r--r--dom/presentation/provider/LegacyProviders.manifest2
-rw-r--r--dom/presentation/provider/MulticastDNSDeviceProvider.cpp1249
-rw-r--r--dom/presentation/provider/MulticastDNSDeviceProvider.h225
-rw-r--r--dom/presentation/provider/PresentationControlService.js960
-rw-r--r--dom/presentation/provider/PresentationDeviceProviderModule.cpp87
-rw-r--r--dom/presentation/provider/ReceiverStateMachine.jsm238
-rw-r--r--dom/presentation/provider/StateMachineHelper.jsm39
-rw-r--r--dom/presentation/provider/moz.build40
-rw-r--r--dom/presentation/provider/nsTCPDeviceInfo.h77
-rw-r--r--dom/presentation/tests/mochitest/PresentationDeviceInfoChromeScript.js150
-rw-r--r--dom/presentation/tests/mochitest/PresentationSessionChromeScript.js470
-rw-r--r--dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js366
-rw-r--r--dom/presentation/tests/mochitest/PresentationSessionFrameScript.js258
-rw-r--r--dom/presentation/tests/mochitest/chrome.ini14
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_1ua_receiver.html220
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_1ua_wentaway.html95
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_mixed_security_contexts.html159
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_non_receiver.html41
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_non_receiver_inner_iframe.html26
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_receiver.html140
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_receiver_auxiliary_navigation.html60
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_receiver_establish_connection_error.html79
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_receiver_inner_iframe.html26
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_reconnect.html102
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_sandboxed_presentation.html114
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_terminate.html104
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_terminate_establish_connection_error.html114
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_unknown_content_type.test1
-rw-r--r--dom/presentation/tests/mochitest/file_presentation_unknown_content_type.test^headers^1
-rw-r--r--dom/presentation/tests/mochitest/mochitest.ini77
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway.js175
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway_inproc.html18
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway_oop.html18
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js370
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_inproc.html18
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_oop.html18
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_availability.html236
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_datachannel_sessiontransport.html245
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_dc_receiver.html141
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_dc_receiver_oop.html213
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_dc_sender.html291
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_device_info.html144
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_device_info_permission.html35
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_mixed_security_contexts.html81
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation.js77
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation_inproc.html18
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation_oop.html18
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_reconnect.html379
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_sandboxed_presentation.html75
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_sender_on_terminate_request.html187
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_sender_startWithDevice.html173
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_tcp_receiver.html137
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_error.html110
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_timeout.html81
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type.js88
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type_inproc.html16
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type_oop.html16
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_tcp_receiver_oop.html178
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_tcp_sender.html260
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_tcp_sender_default_request.html151
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_tcp_sender_disconnect.html160
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html514
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_terminate.js243
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error.js197
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error_inproc.html18
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error_oop.html18
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_terminate_inproc.html18
-rw-r--r--dom/presentation/tests/mochitest/test_presentation_terminate_oop.html18
-rw-r--r--dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js1318
-rw-r--r--dom/presentation/tests/xpcshell/test_presentation_device_manager.js244
-rw-r--r--dom/presentation/tests/xpcshell/test_presentation_session_transport.js198
-rw-r--r--dom/presentation/tests/xpcshell/test_presentation_state_machine.js236
-rw-r--r--dom/presentation/tests/xpcshell/test_tcp_control_channel.js398
-rw-r--r--dom/presentation/tests/xpcshell/xpcshell.ini9
-rw-r--r--dom/push/PushRecord.jsm16
-rw-r--r--dom/push/PushService.jsm11
-rw-r--r--dom/push/PushServiceWebSocket.jsm1
-rw-r--r--dom/push/moz.build7
-rw-r--r--dom/security/nsCSPUtils.cpp16
-rw-r--r--dom/system/OSFileConstants.cpp15
-rw-r--r--dom/webidl/FlyWebDiscoveryManager.webidl39
-rw-r--r--dom/webidl/FlyWebFetchEvent.webidl13
-rw-r--r--dom/webidl/FlyWebPublish.webidl23
-rw-r--r--dom/webidl/FlyWebWebSocketEvent.webidl16
-rw-r--r--dom/webidl/Navigator.webidl11
-rw-r--r--dom/webidl/Performance.webidl2
-rw-r--r--dom/webidl/Presentation.webidl30
-rw-r--r--dom/webidl/PresentationAvailability.webidl22
-rw-r--r--dom/webidl/PresentationConnection.webidl96
-rw-r--r--dom/webidl/PresentationConnectionAvailableEvent.webidl22
-rw-r--r--dom/webidl/PresentationConnectionCloseEvent.webidl41
-rw-r--r--dom/webidl/PresentationConnectionList.webidl25
-rw-r--r--dom/webidl/PresentationDeviceInfoManager.webidl26
-rw-r--r--dom/webidl/PresentationReceiver.webidl18
-rw-r--r--dom/webidl/PresentationRequest.webidl86
-rw-r--r--dom/webidl/moz.build37
440 files changed, 15850 insertions, 37687 deletions
diff --git a/dom/base/BlobSet.h b/dom/base/BlobSet.h
index 3e22955dd..bf98cb023 100644
--- a/dom/base/BlobSet.h
+++ b/dom/base/BlobSet.h
@@ -8,6 +8,9 @@
#define mozilla_dom_BlobSet_h
#include "mozilla/RefPtr.h"
+#include "jsfriendapi.h"
+#include "nsString.h"
+#include "nsTArray.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/CORSMode.h b/dom/base/CORSMode.h
index 82f2f570d..577e78725 100644
--- a/dom/base/CORSMode.h
+++ b/dom/base/CORSMode.h
@@ -7,6 +7,8 @@
#ifndef CORSMode_h_
#define CORSMode_h_
+#include <stdint.h>
+
namespace mozilla {
enum CORSMode : uint8_t {
diff --git a/dom/base/ChromeUtils.cpp b/dom/base/ChromeUtils.cpp
index 3cde261f0..b25f0b76b 100644
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -7,6 +7,7 @@
#include "mozilla/Base64.h"
#include "mozilla/BasePrincipal.h"
+#include "jsfriendapi.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/ChromeUtils.h b/dom/base/ChromeUtils.h
index 051217c84..58a67b4f2 100644
--- a/dom/base/ChromeUtils.h
+++ b/dom/base/ChromeUtils.h
@@ -10,6 +10,7 @@
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ChromeUtilsBinding.h"
#include "mozilla/dom/ThreadSafeChromeUtilsBinding.h"
+#include "mozilla/dom/UnionTypes.h"
#include "mozilla/ErrorResult.h"
namespace mozilla {
diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp
index 3f202d33b..f582d635f 100644
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -7,8 +7,11 @@
#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/dom/CustomElementRegistryBinding.h"
+#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLElementBinding.h"
#include "mozilla/dom/WebComponentsBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "nsContentUtils.h"
#include "nsIParserService.h"
#include "jsapi.h"
diff --git a/dom/base/DocGroup.cpp b/dom/base/DocGroup.cpp
index 226879985..ba9189168 100644
--- a/dom/base/DocGroup.cpp
+++ b/dom/base/DocGroup.cpp
@@ -6,6 +6,7 @@
#include "mozilla/StaticPtr.h"
#include "mozilla/ClearOnShutdown.h"
#include "nsIDocShell.h"
+#include "nsNetCID.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/DocGroup.h b/dom/base/DocGroup.h
index f4f7ac8ad..6ecd284c1 100644
--- a/dom/base/DocGroup.h
+++ b/dom/base/DocGroup.h
@@ -7,6 +7,7 @@
#ifndef DocGroup_h
#define DocGroup_h
+#include "nsIDocument.h"
#include "nsISupports.h"
#include "nsISupportsImpl.h"
#include "nsIPrincipal.h"
diff --git a/dom/base/GroupedSHistory.h b/dom/base/GroupedSHistory.h
index 8c88a0aaf..c5e75d639 100644
--- a/dom/base/GroupedSHistory.h
+++ b/dom/base/GroupedSHistory.h
@@ -7,6 +7,8 @@
#ifndef GroupedSHistory_h
#define GroupedSHistory_h
+#include "nsCOMArray.h"
+#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
#include "nsIFrameLoader.h"
#include "nsIGroupedSHistory.h"
#include "nsIPartialSHistory.h"
diff --git a/dom/base/ImageTracker.cpp b/dom/base/ImageTracker.cpp
index 9fef059bc..d0c231981 100644
--- a/dom/base/ImageTracker.cpp
+++ b/dom/base/ImageTracker.cpp
@@ -8,6 +8,8 @@
* animating */
#include "ImageTracker.h"
+#include "mozilla/Preferences.h"
+#include "nsAppRunner.h" // for XRE_IsContentProcess
namespace mozilla {
namespace dom {
diff --git a/dom/base/ImageTracker.h b/dom/base/ImageTracker.h
index d33dc55f8..f16461192 100644
--- a/dom/base/ImageTracker.h
+++ b/dom/base/ImageTracker.h
@@ -10,6 +10,7 @@
#ifndef mozilla_dom_ImageTracker
#define mozilla_dom_ImageTracker
+#include "imgIRequest.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
diff --git a/dom/base/MutableBlobStorage.h b/dom/base/MutableBlobStorage.h
index fad391b16..ed368e5e6 100644
--- a/dom/base/MutableBlobStorage.h
+++ b/dom/base/MutableBlobStorage.h
@@ -7,6 +7,9 @@
#ifndef mozilla_dom_MutableBlobStorage_h
#define mozilla_dom_MutableBlobStorage_h
+#include "nsCycleCollectionParticipant.h"
+#include "nsThreadUtils.h"
+#include "nsProxyRelease.h"
#include "mozilla/RefPtr.h"
#include "prio.h"
diff --git a/dom/base/MutableBlobStreamListener.cpp b/dom/base/MutableBlobStreamListener.cpp
index 6769ad3e6..afcc04d9f 100644
--- a/dom/base/MutableBlobStreamListener.cpp
+++ b/dom/base/MutableBlobStreamListener.cpp
@@ -5,6 +5,7 @@
#include "MutableBlobStreamListener.h"
#include "MutableBlobStorage.h"
+#include "nsIInputStream.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp
index fdf151b6c..a544f23c1 100644
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -37,10 +37,7 @@
#include "mozilla/dom/PowerManager.h"
#include "mozilla/dom/WakeLock.h"
#include "mozilla/dom/power/PowerManagerService.h"
-#include "mozilla/dom/FlyWebPublishedServer.h"
-#include "mozilla/dom/FlyWebService.h"
#include "mozilla/dom/Permissions.h"
-#include "mozilla/dom/Presentation.h"
#include "mozilla/dom/ServiceWorkerContainer.h"
#include "mozilla/dom/StorageManager.h"
#include "mozilla/dom/TCPSocket.h"
@@ -67,8 +64,6 @@
#include "nsIAppsService.h"
#include "mozIApplication.h"
#include "WidgetUtils.h"
-#include "nsIPresentationService.h"
-
#include "mozilla/dom/MediaDevices.h"
#include "MediaManager.h"
@@ -218,7 +213,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
#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)
#endif
@@ -284,10 +278,6 @@ Navigator::Invalidate()
mTimeManager = nullptr;
}
- if (mPresentation) {
- mPresentation = nullptr;
- }
-
mServiceWorkerContainer = nullptr;
#ifdef MOZ_EME
@@ -1364,41 +1354,6 @@ Navigator::GetBattery(ErrorResult& aRv)
return mBatteryPromise;
}
-already_AddRefed<Promise>
-Navigator::PublishServer(const nsAString& aName,
- const FlyWebPublishOptions& aOptions,
- ErrorResult& aRv)
-{
- RefPtr<FlyWebService> service = FlyWebService::GetOrCreate();
- if (!service) {
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
-
- RefPtr<FlyWebPublishPromise> mozPromise =
- service->PublishServer(aName, aOptions, mWindow);
- MOZ_ASSERT(mozPromise);
-
- nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
- ErrorResult result;
- RefPtr<Promise> domPromise = Promise::Create(global, result);
- if (result.Failed()) {
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
-
- mozPromise->Then(AbstractThread::MainThread(),
- __func__,
- [domPromise] (FlyWebPublishedServer* aServer) {
- domPromise->MaybeResolve(aServer);
- },
- [domPromise] (nsresult aStatus) {
- domPromise->MaybeReject(aStatus);
- });
-
- return domPromise.forget();
-}
-
PowerManager*
Navigator::GetMozPower(ErrorResult& aRv)
{
@@ -1931,19 +1886,5 @@ Navigator::RequestMediaKeySystemAccess(const nsAString& aKeySystem,
}
#endif
-Presentation*
-Navigator::GetPresentation(ErrorResult& aRv)
-{
- if (!mPresentation) {
- if (!mWindow) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return nullptr;
- }
- mPresentation = Presentation::Create(mWindow);
- }
-
- return mPresentation;
-}
-
} // namespace dom
} // namespace mozilla
diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h
index 91b7fc15c..4ddaaabab 100644
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -39,8 +39,6 @@ class WakeLock;
class ArrayBufferViewOrBlobOrStringOrFormData;
class ServiceWorkerContainer;
class DOMRequest;
-struct FlyWebPublishOptions;
-struct FlyWebFilter;
} // namespace dom
} // namespace mozilla
@@ -74,7 +72,6 @@ class Connection;
} // namespace network
class PowerManager;
-class Presentation;
class LegacyMozTCPSocket;
class StorageManager;
@@ -141,9 +138,6 @@ public:
Geolocation* GetGeolocation(ErrorResult& aRv);
Promise* GetBattery(ErrorResult& aRv);
- already_AddRefed<Promise> PublishServer(const nsAString& aName,
- const FlyWebPublishOptions& aOptions,
- ErrorResult& aRv);
static void AppName(nsAString& aAppName, bool aUsePrefOverriddenValue);
static nsresult GetPlatform(nsAString& aPlatform,
@@ -210,8 +204,6 @@ public:
system::AudioChannelManager* GetMozAudioChannelManager(ErrorResult& aRv);
#endif // MOZ_AUDIO_CHANNEL_MANAGER
- Presentation* GetPresentation(ErrorResult& aRv);
-
bool SendBeacon(const nsAString& aUrl,
const Nullable<ArrayBufferViewOrBlobOrStringOrFormData>& aData,
ErrorResult& aRv);
@@ -288,7 +280,6 @@ private:
RefPtr<time::TimeManager> mTimeManager;
RefPtr<ServiceWorkerContainer> mServiceWorkerContainer;
nsCOMPtr<nsPIDOMWindowInner> mWindow;
- RefPtr<Presentation> mPresentation;
#ifdef MOZ_GAMEPAD
RefPtr<GamepadServiceTest> mGamepadServiceTest;
#endif
diff --git a/dom/base/NodeInfo.cpp b/dom/base/NodeInfo.cpp
index d32a00fd3..f055dfc75 100644
--- a/dom/base/NodeInfo.cpp
+++ b/dom/base/NodeInfo.cpp
@@ -15,6 +15,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Likely.h"
+#include "mozilla/Unused.h"
#include "nsNodeInfoManager.h"
#include "nsCOMPtr.h"
diff --git a/dom/base/Pose.h b/dom/base/Pose.h
index c7ef1b381..0817c8c96 100644
--- a/dom/base/Pose.h
+++ b/dom/base/Pose.h
@@ -8,6 +8,7 @@
#define mozilla_dom_Pose_h
#include "nsWrapperCache.h"
+#include "mozilla/ErrorResult.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/TabGroup.h b/dom/base/TabGroup.h
index f9fa9eec5..c436ce98d 100644
--- a/dom/base/TabGroup.h
+++ b/dom/base/TabGroup.h
@@ -7,10 +7,12 @@
#ifndef TabGroup_h
#define TabGroup_h
+#include "nsIDocument.h"
#include "nsISupports.h"
#include "nsISupportsImpl.h"
#include "nsIPrincipal.h"
#include "nsTHashtable.h"
+#include "nsHashKeys.h"
#include "nsString.h"
#include "mozilla/RefPtr.h"
diff --git a/dom/base/ThirdPartyUtil.cpp b/dom/base/ThirdPartyUtil.cpp
index 61d97f634..37d326dbc 100644
--- a/dom/base/ThirdPartyUtil.cpp
+++ b/dom/base/ThirdPartyUtil.cpp
@@ -10,6 +10,7 @@
#include "nsIChannel.h"
#include "nsIServiceManager.h"
#include "nsIHttpChannelInternal.h"
+#include "nsPIDOMWindow.h"
#include "nsIDOMWindow.h"
#include "nsILoadContext.h"
#include "nsIPrincipal.h"
diff --git a/dom/base/TimeoutHandler.cpp b/dom/base/TimeoutHandler.cpp
index 78c3f16dd..f34275840 100644
--- a/dom/base/TimeoutHandler.cpp
+++ b/dom/base/TimeoutHandler.cpp
@@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TimeoutHandler.h"
+#include "nsJSUtils.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/TimeoutHandler.h b/dom/base/TimeoutHandler.h
index cb0a0ce94..a80dc2995 100644
--- a/dom/base/TimeoutHandler.h
+++ b/dom/base/TimeoutHandler.h
@@ -7,9 +7,11 @@
#ifndef mozilla_dom_timeout_handler_h
#define mozilla_dom_timeout_handler_h
+#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
#include "nsCOMPtr.h"
#include "nsISupports.h"
#include "nsITimeoutHandler.h"
+#include "nsString.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/TimerClamping.h b/dom/base/TimerClamping.h
index 2ffd6add5..2bd1f019c 100755
--- a/dom/base/TimerClamping.h
+++ b/dom/base/TimerClamping.h
@@ -7,6 +7,8 @@
#ifndef TimerClamping_h___
#define TimerClamping_h___
+#include <math.h>
+
namespace mozilla {
class TimerClamping
diff --git a/dom/base/moz.build b/dom/base/moz.build
index 75ddefded..89f1785ca 100755
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -225,7 +225,7 @@ EXPORTS.mozilla.dom += [
'WindowOrientationObserver.h',
]
-UNIFIED_SOURCES += [
+SOURCES += [
'AnonymousContent.cpp',
'Attr.cpp',
'BarProps.cpp',
@@ -376,7 +376,7 @@ UNIFIED_SOURCES += [
]
if CONFIG['MOZ_WEBRTC']:
- UNIFIED_SOURCES += [
+ SOURCES += [
'nsDOMDataChannel.cpp',
]
diff --git a/dom/base/nsAttrValue.cpp b/dom/base/nsAttrValue.cpp
index ebddcb7ed..2418fb501 100644
--- a/dom/base/nsAttrValue.cpp
+++ b/dom/base/nsAttrValue.cpp
@@ -1526,6 +1526,40 @@ nsAttrValue::ParseIntWithFallback(const nsAString& aString, int32_t aDefault,
SetIntValueAndType(val, eInteger, nonStrict ? &aString : nullptr);
}
+void
+nsAttrValue::ParseClampedNonNegativeInt(const nsAString& aString,
+ int32_t aDefault, int32_t aMin,
+ int32_t aMax)
+{
+ ResetIfSet();
+
+ nsContentUtils::ParseHTMLIntegerResultFlags result;
+ int32_t val = nsContentUtils::ParseHTMLInteger(aString, &result);
+ bool nonStrict = (result & nsContentUtils::eParseHTMLInteger_IsPercent) ||
+ (result & nsContentUtils::eParseHTMLInteger_NonStandard) ||
+ (result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput);
+
+ if (result & nsContentUtils::eParseHTMLInteger_ErrorOverflow) {
+ if (result & nsContentUtils::eParseHTMLInteger_Negative) {
+ val = aDefault;
+ } else {
+ val = aMax;
+ }
+ nonStrict = true;
+ } else if ((result & nsContentUtils::eParseHTMLInteger_Error) || val < 0) {
+ val = aDefault;
+ nonStrict = true;
+ } else if (val < aMin) {
+ val = aMin;
+ nonStrict = true;
+ } else if (val > aMax) {
+ val = aMax;
+ nonStrict = true;
+ }
+
+ SetIntValueAndType(val, eInteger, nonStrict ? &aString : nullptr);
+}
+
bool
nsAttrValue::ParseNonNegativeIntValue(const nsAString& aString)
{
diff --git a/dom/base/nsAttrValue.h b/dom/base/nsAttrValue.h
index 655e4ca61..23f61a614 100644
--- a/dom/base/nsAttrValue.h
+++ b/dom/base/nsAttrValue.h
@@ -362,6 +362,19 @@ public:
*/
bool ParseNonNegativeIntValue(const nsAString& aString);
+ /**
+ * Parse a string value into a clamped non-negative integer.
+ * This method follows the rules for parsing non-negative integer from:
+ * https://html.spec.whatwg.org/multipage/infrastructure.html#clamped-to-the-range
+ *
+ * @param aString the string to parse
+ * @param aDefault value to return for negative or invalid values
+ * @param aMin minimum value
+ * @param aMax maximum value
+ */
+ void ParseClampedNonNegativeInt(const nsAString& aString, int32_t aDefault,
+ int32_t aMin, int32_t aMax);
+
/**
* Parse a string value into a positive integer.
* This method follows the rules for parsing non-negative integer from:
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 800f40fa1..6a9904bf9 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -1080,6 +1080,7 @@ nsContentUtils::ParseHTMLInteger(const nsAString& aValue,
int sign = 1;
if (*iter == char16_t('-')) {
sign = -1;
+ result |= eParseHTMLInteger_Negative;
++iter;
} else if (*iter == char16_t('+')) {
result |= eParseHTMLInteger_NonStandard;
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 606d67de9..ffbd15e78 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -444,7 +444,9 @@ public:
// Set if one or more error flags were set.
eParseHTMLInteger_Error = 1 << 3,
eParseHTMLInteger_ErrorNoValue = 1 << 4,
- eParseHTMLInteger_ErrorOverflow = 1 << 5
+ eParseHTMLInteger_ErrorOverflow = 1 << 5,
+ // Use this flag to detect the difference between overflow and underflow
+ eParseHTMLInteger_Negative = 1 << 6,
};
static int32_t ParseHTMLInteger(const nsAString& aValue,
ParseHTMLIntegerResultFlags *aResult);
diff --git a/dom/base/nsDOMMutationObserver.cpp b/dom/base/nsDOMMutationObserver.cpp
index 858a30ce5..0273b7b94 100644
--- a/dom/base/nsDOMMutationObserver.cpp
+++ b/dom/base/nsDOMMutationObserver.cpp
@@ -7,6 +7,7 @@
#include "nsDOMMutationObserver.h"
#include "mozilla/AnimationTarget.h"
+#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/Maybe.h"
#include "mozilla/OwningNonNull.h"
@@ -29,6 +30,9 @@ using mozilla::dom::TreeOrderComparator;
using mozilla::dom::Animation;
using mozilla::dom::Element;
+using namespace mozilla;
+using namespace mozilla::dom;
+
AutoTArray<RefPtr<nsDOMMutationObserver>, 4>*
nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index afe88a454..380593737 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -166,7 +166,6 @@
#include "mozilla/dom/HTMLIFrameElement.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/MediaSource.h"
-#include "mozilla/dom/FlyWebService.h"
#include "mozAutoDocUpdate.h"
#include "nsGlobalWindow.h"
@@ -8369,13 +8368,6 @@ nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
return false;
}
- // Don't save presentation if there are active FlyWeb connections or FlyWeb
- // servers.
- FlyWebService* flyWebService = FlyWebService::GetExisting();
- if (flyWebService && flyWebService->HasConnectionOrServer(win->WindowID())) {
- return false;
- }
-
if (mSubDocuments) {
for (auto iter = mSubDocuments->Iter(); !iter.Done(); iter.Next()) {
auto entry = static_cast<SubDocMapEntry*>(iter.Get());
diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp
index fb350fa12..01c1944be 100644
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1261,6 +1261,15 @@ nsFocusManager::SetFocusInner(nsIContent* aNewContent, int32_t aFlags,
isElementInActiveWindow = (mActiveWindow && newRootWindow == mActiveWindow);
}
+ // Exit fullscreen if a website focuses another window
+ if (!isElementInActiveWindow && aFlags & FLAG_RAISE) {
+ if (nsIDocument* doc = mActiveWindow ? mActiveWindow->GetDoc() : nullptr) {
+ if (doc && doc->GetFullscreenElement()) {
+ nsIDocument::AsyncExitFullscreen(doc);
+ }
+ }
+ }
+
// Exit fullscreen if we're focusing a windowed plugin on a non-MacOSX
// system. We don't control event dispatch to windowed plugins on non-MacOSX,
// so we can't display the "Press ESC to leave fullscreen mode" warning on
diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp
index dfd380fc2..efea3ee40 100644
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -57,6 +57,7 @@
#include "mozilla/dom/ErrorEvent.h"
#include "nsAXPCNativeCallContext.h"
#include "mozilla/CycleCollectedJSContext.h"
+#include "mozilla/Telemetry.h"
#include "nsJSPrincipals.h"
diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp
index 98b367b66..c9cec96db 100644
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -31,6 +31,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ScriptSettings.h"
+using namespace mozilla;
using namespace mozilla::dom;
bool
diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp
index 3ac00142d..25482fe7b 100644
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -1144,7 +1144,7 @@ nsScriptLoader::InstantiateModuleTree(nsModuleLoadRequest* aRequest)
nsModuleScript* ms = aRequest->mModuleScript;
MOZ_ASSERT(ms);
- if (!ms->ModuleRecord()) {
+ if (!ms || !ms->ModuleRecord()) {
return false;
}
diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf
index b00af2085..941e65eff 100644
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -53,11 +53,6 @@ DOMInterfaces = {
'concrete': False
},
-'AddonManagerPermissions': {
- 'wrapperCache': False,
- 'concrete': False
-},
-
'AnimationEffectReadOnly': {
'concrete': False
},
@@ -340,14 +335,6 @@ DOMInterfaces = {
'wrapperCache': False,
},
-'FlyWebFetchEvent': {
- 'headerFile': 'FlyWebServerEvents.h',
-},
-
-'FlyWebWebSocketEvent': {
- 'headerFile': 'FlyWebServerEvents.h',
-},
-
'FontFaceSet': {
'implicitJSContext': [ 'load' ],
},
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index 6b23e8225..e3cca63b6 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1109,6 +1109,12 @@ class CGHeaders(CGWrapper):
# Now find all the things we'll need as arguments because we
# need to wrap or unwrap them.
bindingHeaders = set()
+
+ # KeyframeAnimationOptions.webidl is doing something VERY screwy and
+ # Unified Building really sucks so directly include this
+ if prefix == "KeyframeAnimationOptionsBinding":
+ bindingHeaders.add("mozilla/dom/PrimitiveConversions.h")
+
declareIncludes = set(declareIncludes)
def addHeadersForType((t, dictionary)):
diff --git a/dom/bindings/GenerateCSS2PropertiesWebIDL.py b/dom/bindings/GenerateCSS2PropertiesWebIDL.py
index 58ec60c29..57634494f 100644
--- a/dom/bindings/GenerateCSS2PropertiesWebIDL.py
+++ b/dom/bindings/GenerateCSS2PropertiesWebIDL.py
@@ -16,6 +16,7 @@ def generateLine(propName, extendedAttrs):
return " [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
propName)
def generate(output, idlFilename, preprocessorHeader):
+ print(idlFilename)
cpp = list(buildconfig.substs['CPP'])
cpp += shellutil.split(buildconfig.substs['ACDEFINES'])
cpp.append(preprocessorHeader)
diff --git a/dom/bindings/WebIDLGlobalNameHash.cpp b/dom/bindings/WebIDLGlobalNameHash.cpp
index 7477b52e7..981a1a395 100644
--- a/dom/bindings/WebIDLGlobalNameHash.cpp
+++ b/dom/bindings/WebIDLGlobalNameHash.cpp
@@ -4,8 +4,12 @@
* 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 "jswrapper.h"
#include "WebIDLGlobalNameHash.h"
#include "js/GCAPI.h"
+#include "XrayWrapper.h"
+#include "XPCWrapper.h"
+#include "mozilla/dom/Selection.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/Maybe.h"
#include "mozilla/dom/DOMJSProxyHandler.h"
diff --git a/dom/bindings/WebIDLGlobalNameHash.h b/dom/bindings/WebIDLGlobalNameHash.h
index bbe015395..cd7be2c69 100644
--- a/dom/bindings/WebIDLGlobalNameHash.h
+++ b/dom/bindings/WebIDLGlobalNameHash.h
@@ -8,6 +8,7 @@
#define mozilla_dom_WebIDLGlobalNameHash_h__
#include "js/RootingAPI.h"
+#include "nsString.h"
#include "nsTArray.h"
namespace mozilla {
diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build
index ed8a4d37e..ca82b48a8 100644
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -89,7 +89,7 @@ LOCAL_INCLUDES += [
'/media/webrtc/signaling/src/peerconnection',
]
-UNIFIED_SOURCES += [
+SOURCES += [
'BindingUtils.cpp',
'CallbackInterface.cpp',
'CallbackObject.cpp',
diff --git a/dom/bindings/mozwebidlcodegen/__init__.py b/dom/bindings/mozwebidlcodegen/__init__.py
index b6e351e52..69f3f5e25 100644
--- a/dom/bindings/mozwebidlcodegen/__init__.py
+++ b/dom/bindings/mozwebidlcodegen/__init__.py
@@ -269,6 +269,7 @@ class WebIDLCodegenManager(LoggingMixin):
# Generate bindings from .webidl files.
for filename in sorted(changed_inputs):
basename = mozpath.basename(filename)
+ print basename
result.inputs.add(filename)
written, deps = self._generate_build_files_for_webidl(filename)
result.created |= written[0]
diff --git a/dom/bindings/nsScriptError.h b/dom/bindings/nsScriptError.h
index b8049d0a0..ac8099c1c 100644
--- a/dom/bindings/nsScriptError.h
+++ b/dom/bindings/nsScriptError.h
@@ -14,8 +14,13 @@
#include "jsapi.h"
#include "js/RootingAPI.h"
+#include "jswrapper.h"
+#include "nsCOMArray.h"
+#include "nsContentUtils.h"
+#include "nsCycleCollectionParticipant.h"
#include "nsIScriptError.h"
#include "nsString.h"
+#include "nsStringFwd.h"
class nsScriptErrorNote final : public nsIScriptErrorNote {
public:
diff --git a/dom/bindings/nsScriptErrorWithStack.cpp b/dom/bindings/nsScriptErrorWithStack.cpp
index 74c00999f..0a8df38b3 100644
--- a/dom/bindings/nsScriptErrorWithStack.cpp
+++ b/dom/bindings/nsScriptErrorWithStack.cpp
@@ -22,7 +22,7 @@ using namespace mozilla::dom;
namespace {
static nsCString
-FormatStackString(JSContext* cx, HandleObject aStack) {
+FormatStackString(JSContext* cx, JS::HandleObject aStack) {
JS::RootedString formattedStack(cx);
if (!JS::BuildStackString(cx, aStack, &formattedStack)) {
@@ -111,7 +111,7 @@ nsScriptErrorWithStack::ToString(nsACString& /*UTF8*/ aResult)
}
JSContext* cx = jsapi.cx();
- RootedObject stack(cx, mStack);
+ JS::RootedObject stack(cx, mStack);
nsCString stackString = FormatStackString(cx, stack);
nsCString combined = message + NS_LITERAL_CSTRING("\n") + stackString;
aResult.Assign(combined);
diff --git a/dom/events/test/test_all_synthetic_events.html b/dom/events/test/test_all_synthetic_events.html
index 90dbe95ee..58560fdce 100644
--- a/dom/events/test/test_all_synthetic_events.html
+++ b/dom/events/test/test_all_synthetic_events.html
@@ -139,10 +139,6 @@ const kEventConstructors = {
return new ErrorEvent(aName, aProps);
},
},
- FlyWebFetchEvent: { create: null, // Cannot create untrusted event from JS.
- },
- FlyWebWebSocketEvent: { create: null, // Cannot create untrusted event from JS.
- },
FocusEvent: { create: function (aName, aProps) {
return new FocusEvent(aName, aProps);
},
diff --git a/dom/flyweb/FlyWebDiscoveryManager.cpp b/dom/flyweb/FlyWebDiscoveryManager.cpp
deleted file mode 100644
index 5a97eb6d8..000000000
--- a/dom/flyweb/FlyWebDiscoveryManager.cpp
+++ /dev/null
@@ -1,125 +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 "nsString.h"
-#include "nsTHashtable.h"
-#include "nsClassHashtable.h"
-#include "nsIUUIDGenerator.h"
-#include "jsapi.h"
-#include "mozilla/StaticPtr.h"
-#include "mozilla/Logging.h"
-#include "nsComponentManagerUtils.h"
-#include "nsServiceManagerUtils.h"
-
-#include "mozilla/dom/FlyWebDiscoveryManager.h"
-#include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
-
-namespace mozilla {
-namespace dom {
-
-static LazyLogModule gFlyWebDiscoveryManagerLog("FlyWebDiscoveryManager");
-#undef LOG_I
-#define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebDiscoveryManagerLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
-#undef LOG_E
-#define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebDiscoveryManagerLog, mozilla::LogLevel::Error, (__VA_ARGS__))
-
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(FlyWebDiscoveryManager)
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(FlyWebDiscoveryManager)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(FlyWebDiscoveryManager)
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FlyWebDiscoveryManager)
- NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
- NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-FlyWebDiscoveryManager::FlyWebDiscoveryManager(nsISupports* aParent,
- FlyWebService* aService)
- : mParent(aParent)
- , mService(aService)
- , mNextId(0)
-{
-}
-
-FlyWebDiscoveryManager::~FlyWebDiscoveryManager()
-{
- mService->UnregisterDiscoveryManager(this);
-}
-
-JSObject*
-FlyWebDiscoveryManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
- return FlyWebDiscoveryManagerBinding::Wrap(aCx, this, aGivenProto);
-}
-
-nsISupports*
-FlyWebDiscoveryManager::GetParentObject() const
-{
- return mParent;
-}
-
-/* static */ already_AddRefed<FlyWebDiscoveryManager>
-FlyWebDiscoveryManager::Constructor(const GlobalObject& aGlobal, ErrorResult& rv)
-{
- RefPtr<FlyWebService> service = FlyWebService::GetOrCreate();
- if (!service) {
- return nullptr;
- }
-
- RefPtr<FlyWebDiscoveryManager> result = new FlyWebDiscoveryManager(
- aGlobal.GetAsSupports(), service);
- return result.forget();
-}
-
-void
-FlyWebDiscoveryManager::ListServices(nsTArray<FlyWebDiscoveredService>& aServices)
-{
- return mService->ListDiscoveredServices(aServices);
-}
-
-uint32_t
-FlyWebDiscoveryManager::StartDiscovery(FlyWebDiscoveryCallback& aCallback)
-{
- uint32_t id = GenerateId();
- mCallbackMap.Put(id, &aCallback);
- mService->RegisterDiscoveryManager(this);
- return id;
-}
-
-void
-FlyWebDiscoveryManager::StopDiscovery(uint32_t aId)
-{
- mCallbackMap.Remove(aId);
- if (mCallbackMap.Count() == 0) {
- mService->UnregisterDiscoveryManager(this);
- }
-}
-
-void
-FlyWebDiscoveryManager::PairWithService(const nsAString& aServiceId,
- FlyWebPairingCallback& aCallback)
-{
- mService->PairWithService(aServiceId, aCallback);
-}
-
-void
-FlyWebDiscoveryManager::NotifyDiscoveredServicesChanged()
-{
- nsTArray<FlyWebDiscoveredService> services;
- ListServices(services);
- Sequence<FlyWebDiscoveredService> servicesSeq;
- servicesSeq.SwapElements(services);
- for (auto iter = mCallbackMap.Iter(); !iter.Done(); iter.Next()) {
- FlyWebDiscoveryCallback *callback = iter.UserData();
- ErrorResult err;
- callback->OnDiscoveredServicesChanged(servicesSeq, err);
- ENSURE_SUCCESS_VOID(err);
- }
-}
-
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/flyweb/FlyWebDiscoveryManager.h b/dom/flyweb/FlyWebDiscoveryManager.h
deleted file mode 100644
index cb5f692f8..000000000
--- a/dom/flyweb/FlyWebDiscoveryManager.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_FlyWebDiscoveryManager_h
-#define mozilla_dom_FlyWebDiscoveryManager_h
-
-#include "nsISupportsImpl.h"
-#include "mozilla/ErrorResult.h"
-#include "nsRefPtrHashtable.h"
-#include "nsWrapperCache.h"
-#include "FlyWebDiscoveryManagerBinding.h"
-#include "FlyWebService.h"
-
-namespace mozilla {
-namespace dom {
-
-class FlyWebDiscoveryManager final : public nsISupports
- , public nsWrapperCache
-{
-public:
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FlyWebDiscoveryManager)
-
- virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
- nsISupports* GetParentObject() const;
-
- static already_AddRefed<FlyWebDiscoveryManager> Constructor(const GlobalObject& aGlobal,
- ErrorResult& rv);
-
- void ListServices(nsTArray<FlyWebDiscoveredService>& aServices);
- uint32_t StartDiscovery(FlyWebDiscoveryCallback& aCallback);
- void StopDiscovery(uint32_t aId);
-
- void PairWithService(const nsAString& aServiceId,
- FlyWebPairingCallback& callback);
-
- void NotifyDiscoveredServicesChanged();
-
-private:
- FlyWebDiscoveryManager(nsISupports* mParent, FlyWebService* aService);
- ~FlyWebDiscoveryManager();
-
- uint32_t GenerateId() {
- return ++mNextId;
- }
-
- nsCOMPtr<nsISupports> mParent;
- RefPtr<FlyWebService> mService;
-
- uint32_t mNextId;
-
- nsRefPtrHashtable<nsUint32HashKey, FlyWebDiscoveryCallback> mCallbackMap;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_FlyWebDiscoveryManager_h
diff --git a/dom/flyweb/FlyWebPublishOptionsIPCSerializer.h b/dom/flyweb/FlyWebPublishOptionsIPCSerializer.h
deleted file mode 100644
index fa1a44113..000000000
--- a/dom/flyweb/FlyWebPublishOptionsIPCSerializer.h
+++ /dev/null
@@ -1,33 +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_FlyWebPublishOptionsIPCSerialiser_h
-#define mozilla_dom_FlyWebPublishOptionsIPCSerialiser_h
-
-#include "mozilla/dom/FlyWebPublishBinding.h"
-
-namespace IPC {
-
-template <>
-struct ParamTraits<mozilla::dom::FlyWebPublishOptions>
-{
- typedef mozilla::dom::FlyWebPublishOptions paramType;
-
- // Function to serialize a FlyWebPublishOptions
- static void Write(Message *aMsg, const paramType& aParam)
- {
- WriteParam(aMsg, aParam.mUiUrl);
- }
- // Function to de-serialize a FlyWebPublishOptions
- static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
- {
- return ReadParam(aMsg, aIter, &(aResult->mUiUrl));
- }
-};
-
-}
-
-#endif // mozilla_dom_FlyWebPublishOptionsIPCSerialiser_h
diff --git a/dom/flyweb/FlyWebPublishedServer.cpp b/dom/flyweb/FlyWebPublishedServer.cpp
deleted file mode 100644
index 375df332f..000000000
--- a/dom/flyweb/FlyWebPublishedServer.cpp
+++ /dev/null
@@ -1,675 +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 "mozilla/dom/FlyWebPublishedServerIPC.h"
-#include "mozilla/dom/FlyWebPublishBinding.h"
-#include "mozilla/dom/FlyWebService.h"
-#include "mozilla/dom/Request.h"
-#include "mozilla/dom/FlyWebServerEvents.h"
-#include "mozilla/dom/ContentChild.h"
-#include "mozilla/dom/ContentParent.h"
-#include "mozilla/dom/InternalResponse.h"
-#include "mozilla/ipc/IPCStreamUtils.h"
-#include "mozilla/net/NeckoParent.h"
-#include "mozilla/net/IPCTransportProvider.h"
-#include "mozilla/ErrorResult.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/Unused.h"
-#include "nsCharSeparatedTokenizer.h"
-#include "nsGlobalWindow.h"
-#include "WebSocketChannel.h"
-
-namespace mozilla {
-namespace dom {
-
-static LazyLogModule gFlyWebPublishedServerLog("FlyWebPublishedServer");
-#undef LOG_I
-#define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebPublishedServerLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
-#undef LOG_E
-#define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebPublishedServerLog, mozilla::LogLevel::Error, (__VA_ARGS__))
-
-/******** FlyWebPublishedServer ********/
-
-FlyWebPublishedServer::FlyWebPublishedServer(nsPIDOMWindowInner* aOwner,
- const nsAString& aName,
- const FlyWebPublishOptions& aOptions)
- : mozilla::DOMEventTargetHelper(aOwner)
- , mOwnerWindowID(aOwner ? aOwner->WindowID() : 0)
- , mName(aName)
- , mUiUrl(aOptions.mUiUrl)
- , mIsRegistered(true) // Registered by the FlyWebService
-{
-}
-
-void
-FlyWebPublishedServer::LastRelease()
-{
- // Make sure to unregister to avoid dangling pointers. Use the LastRelease
- // hook rather than dtor since calling virtual functions during dtor
- // wouldn't do what we want. Also, LastRelease is called earlier than dtor
- // for CC objects.
- Close();
-}
-
-JSObject*
-FlyWebPublishedServer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
- return FlyWebPublishedServerBinding::Wrap(aCx, this, aGivenProto);
-}
-
-void
-FlyWebPublishedServer::Close()
-{
- LOG_I("FlyWebPublishedServer::Close(%p)", this);
-
- // Unregister from server.
- if (mIsRegistered) {
- MOZ_ASSERT(FlyWebService::GetExisting());
- FlyWebService::GetExisting()->UnregisterServer(this);
- mIsRegistered = false;
-
- DispatchTrustedEvent(NS_LITERAL_STRING("close"));
- }
-}
-
-void
-FlyWebPublishedServer::FireFetchEvent(InternalRequest* aRequest)
-{
- nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
- RefPtr<FlyWebFetchEvent> e = new FlyWebFetchEvent(this,
- new Request(global, aRequest),
- aRequest);
- e->Init(this);
- e->InitEvent(NS_LITERAL_STRING("fetch"), false, false);
-
- DispatchTrustedEvent(e);
-}
-
-void
-FlyWebPublishedServer::FireWebsocketEvent(InternalRequest* aConnectRequest)
-{
- nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
- RefPtr<FlyWebFetchEvent> e = new FlyWebWebSocketEvent(this,
- new Request(global, aConnectRequest),
- aConnectRequest);
- e->Init(this);
- e->InitEvent(NS_LITERAL_STRING("websocket"), false, false);
-
- DispatchTrustedEvent(e);
-}
-
-void
-FlyWebPublishedServer::PublishedServerStarted(nsresult aStatus)
-{
- LOG_I("FlyWebPublishedServer::PublishedServerStarted(%p)", this);
-
- RefPtr<FlyWebPublishPromise> promise = mPublishPromise.Ensure(__func__);
- if (NS_SUCCEEDED(aStatus)) {
- mPublishPromise.Resolve(this, __func__);
- } else {
- Close();
- mPublishPromise.Reject(aStatus, __func__);
- }
-}
-
-already_AddRefed<WebSocket>
-FlyWebPublishedServer::OnWebSocketAccept(InternalRequest* aConnectRequest,
- const Optional<nsAString>& aProtocol,
- ErrorResult& aRv)
-{
- MOZ_ASSERT(aConnectRequest);
-
- LOG_I("FlyWebPublishedServer::OnWebSocketAccept(%p)", this);
-
- nsCOMPtr<nsITransportProvider> provider =
- OnWebSocketAcceptInternal(aConnectRequest,
- aProtocol,
- aRv);
- if (aRv.Failed()) {
- return nullptr;
- }
- MOZ_ASSERT(provider);
-
- nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetOwner());
- AutoJSContext cx;
- GlobalObject global(cx, nsGlobalWindow::Cast(window)->FastGetGlobalJSObject());
-
- nsAutoCString extensions, negotiatedExtensions;
- aConnectRequest->Headers()->
- GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Extensions"), extensions, aRv);
- mozilla::net::ProcessServerWebSocketExtensions(extensions,
- negotiatedExtensions);
-
- nsCString url;
- aConnectRequest->GetURL(url);
- Sequence<nsString> protocols;
- if (aProtocol.WasPassed() &&
- !protocols.AppendElement(aProtocol.Value(), fallible)) {
- aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return nullptr;
- }
-
- return WebSocket::ConstructorCommon(global,
- NS_ConvertUTF8toUTF16(url),
- protocols,
- provider,
- negotiatedExtensions,
- aRv);
-}
-
-/******** FlyWebPublishedServerImpl ********/
-
-NS_IMPL_ISUPPORTS_INHERITED0(FlyWebPublishedServerImpl, mozilla::DOMEventTargetHelper)
-
-FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(nsPIDOMWindowInner* aOwner,
- const nsAString& aName,
- const FlyWebPublishOptions& aOptions)
- : FlyWebPublishedServer(aOwner, aName, aOptions)
- , mHttpServer(new HttpServer())
-{
- LOG_I("FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(%p)", this);
-}
-
-void
-FlyWebPublishedServerImpl::PermissionGranted(bool aGranted)
-{
- LOG_I("FlyWebPublishedServerImpl::PermissionGranted(%b)", aGranted);
- if (!aGranted) {
- PublishedServerStarted(NS_ERROR_FAILURE);
- return;
- }
-
- mHttpServer->Init(-1, Preferences::GetBool("flyweb.use-tls", false), this);
-}
-
-void
-FlyWebPublishedServerImpl::Close()
-{
- FlyWebPublishedServer::Close();
-
- if (mMDNSCancelRegister) {
- mMDNSCancelRegister->Cancel(NS_BINDING_ABORTED);
- mMDNSCancelRegister = nullptr;
- }
-
- if (mHttpServer) {
- RefPtr<HttpServer> server = mHttpServer.forget();
- server->Close();
- }
-}
-
-void
-FlyWebPublishedServerImpl::OnServerStarted(nsresult aStatus)
-{
- if (NS_SUCCEEDED(aStatus)) {
- FlyWebService::GetOrCreate()->StartDiscoveryOf(this);
- } else {
- PublishedServerStarted(aStatus);
- }
-}
-
-void
-FlyWebPublishedServerImpl::OnFetchResponse(InternalRequest* aRequest,
- InternalResponse* aResponse)
-{
- MOZ_ASSERT(aRequest);
- MOZ_ASSERT(aResponse);
-
- LOG_I("FlyWebPublishedServerImpl::OnFetchResponse(%p)", this);
-
- if (mHttpServer) {
- mHttpServer->SendResponse(aRequest, aResponse);
- }
-}
-
-void
-FlyWebPublishedServerImpl::OnWebSocketResponse(InternalRequest* aConnectRequest,
- InternalResponse* aResponse)
-{
- MOZ_ASSERT(aConnectRequest);
- MOZ_ASSERT(aResponse);
-
- LOG_I("FlyWebPublishedMDNSServer::OnWebSocketResponse(%p)", this);
-
- if (mHttpServer) {
- mHttpServer->SendWebSocketResponse(aConnectRequest, aResponse);
- }
-}
-
-already_AddRefed<nsITransportProvider>
-FlyWebPublishedServerImpl::OnWebSocketAcceptInternal(InternalRequest* aConnectRequest,
- const Optional<nsAString>& aProtocol,
- ErrorResult& aRv)
-{
- LOG_I("FlyWebPublishedServerImpl::OnWebSocketAcceptInternal(%p)", this);
-
- if (!mHttpServer) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return nullptr;
- }
-
- return mHttpServer->AcceptWebSocket(aConnectRequest,
- aProtocol,
- aRv);
-}
-
-/******** FlyWebPublishedServerChild ********/
-
-FlyWebPublishedServerChild::FlyWebPublishedServerChild(nsPIDOMWindowInner* aOwner,
- const nsAString& aName,
- const FlyWebPublishOptions& aOptions)
- : FlyWebPublishedServer(aOwner, aName, aOptions)
- , mActorExists(false)
-{
- LOG_I("FlyWebPublishedServerChild::FlyWebPublishedServerChild(%p)", this);
-
- // The matching release happens when the actor is destroyed, in
- // ContentChild::DeallocPFlyWebPublishedServerChild
- NS_ADDREF_THIS();
-}
-
-void
-FlyWebPublishedServerChild::PermissionGranted(bool aGranted)
-{
- if (!aGranted) {
- PublishedServerStarted(NS_ERROR_FAILURE);
- return;
- }
-
- mActorExists = true;
- FlyWebPublishOptions options;
- options.mUiUrl = mUiUrl;
-
- // Proceed with initialization.
- ContentChild::GetSingleton()->
- SendPFlyWebPublishedServerConstructor(this, mName, options);
-}
-
-bool
-FlyWebPublishedServerChild::RecvServerReady(const nsresult& aStatus)
-{
- LOG_I("FlyWebPublishedServerChild::RecvServerReady(%p)", this);
- MOZ_ASSERT(mActorExists);
-
- PublishedServerStarted(aStatus);
- return true;
-}
-
-bool
-FlyWebPublishedServerChild::RecvServerClose()
-{
- LOG_I("FlyWebPublishedServerChild::RecvServerClose(%p)", this);
- MOZ_ASSERT(mActorExists);
-
- Close();
-
- return true;
-}
-
-bool
-FlyWebPublishedServerChild::RecvFetchRequest(const IPCInternalRequest& aRequest,
- const uint64_t& aRequestId)
-{
- LOG_I("FlyWebPublishedServerChild::RecvFetchRequest(%p)", this);
- MOZ_ASSERT(mActorExists);
-
- RefPtr<InternalRequest> request = new InternalRequest(aRequest);
- mPendingRequests.Put(request, aRequestId);
- FireFetchEvent(request);
-
- return true;
-}
-
-bool
-FlyWebPublishedServerChild::RecvWebSocketRequest(const IPCInternalRequest& aRequest,
- const uint64_t& aRequestId,
- PTransportProviderChild* aProvider)
-{
- LOG_I("FlyWebPublishedServerChild::RecvWebSocketRequest(%p)", this);
- MOZ_ASSERT(mActorExists);
-
- RefPtr<InternalRequest> request = new InternalRequest(aRequest);
- mPendingRequests.Put(request, aRequestId);
-
- // Not addreffing here. The addref was already done when the
- // PTransportProvider child constructor original ran.
- mPendingTransportProviders.Put(aRequestId,
- dont_AddRef(static_cast<TransportProviderChild*>(aProvider)));
-
- FireWebsocketEvent(request);
-
- return true;
-}
-
-void
-FlyWebPublishedServerChild::ActorDestroy(ActorDestroyReason aWhy)
-{
- LOG_I("FlyWebPublishedServerChild::ActorDestroy(%p)", this);
-
- mActorExists = false;
-}
-
-void
-FlyWebPublishedServerChild::OnFetchResponse(InternalRequest* aRequest,
- InternalResponse* aResponse)
-{
- LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this);
-
- if (!mActorExists) {
- LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this);
- return;
- }
-
- uint64_t id = mPendingRequests.Get(aRequest);
- MOZ_ASSERT(id);
- mPendingRequests.Remove(aRequest);
-
- IPCInternalResponse ipcResp;
- UniquePtr<mozilla::ipc::AutoIPCStream> autoStream;
- nsIContentChild* cc = static_cast<ContentChild*>(Manager());
- aResponse->ToIPC(&ipcResp, cc, autoStream);
- Unused << SendFetchResponse(ipcResp, id);
- if (autoStream) {
- autoStream->TakeOptionalValue();
- }
-}
-
-already_AddRefed<nsITransportProvider>
-FlyWebPublishedServerChild::OnWebSocketAcceptInternal(InternalRequest* aRequest,
- const Optional<nsAString>& aProtocol,
- ErrorResult& aRv)
-{
- LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p)", this);
-
- if (!mActorExists) {
- LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p) - No actor!", this);
- return nullptr;
- }
-
- uint64_t id = mPendingRequests.Get(aRequest);
- MOZ_ASSERT(id);
- mPendingRequests.Remove(aRequest);
-
- RefPtr<TransportProviderChild> provider;
- mPendingTransportProviders.Remove(id, getter_AddRefs(provider));
-
- nsString protocol;
- if (aProtocol.WasPassed()) {
- protocol = aProtocol.Value();
-
- nsAutoCString reqProtocols;
- aRequest->Headers()->
- GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Protocol"), reqProtocols, aRv);
- if (!ContainsToken(reqProtocols, NS_ConvertUTF16toUTF8(protocol))) {
- // Should throw a better error here
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
- } else {
- protocol.SetIsVoid(true);
- }
-
- Unused << SendWebSocketAccept(protocol, id);
-
- return provider.forget();
-}
-
-void
-FlyWebPublishedServerChild::OnWebSocketResponse(InternalRequest* aRequest,
- InternalResponse* aResponse)
-{
- LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this);
-
- if (!mActorExists) {
- LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this);
- return;
- }
-
- uint64_t id = mPendingRequests.Get(aRequest);
- MOZ_ASSERT(id);
- mPendingRequests.Remove(aRequest);
-
- mPendingTransportProviders.Remove(id);
-
- IPCInternalResponse ipcResp;
- UniquePtr<mozilla::ipc::AutoIPCStream> autoStream;
- nsIContentChild* cc = static_cast<ContentChild*>(Manager());
- aResponse->ToIPC(&ipcResp, cc, autoStream);
-
- Unused << SendWebSocketResponse(ipcResp, id);
- if (autoStream) {
- autoStream->TakeOptionalValue();
- }
-}
-
-void
-FlyWebPublishedServerChild::Close()
-{
- LOG_I("FlyWebPublishedServerChild::Close(%p)", this);
-
- FlyWebPublishedServer::Close();
-
- if (mActorExists) {
- LOG_I("FlyWebPublishedServerChild::Close - sending __delete__ (%p)", this);
-
- Send__delete__(this);
- }
-}
-
-/******** FlyWebPublishedServerParent ********/
-
-NS_IMPL_ISUPPORTS(FlyWebPublishedServerParent, nsIDOMEventListener)
-
-FlyWebPublishedServerParent::FlyWebPublishedServerParent(const nsAString& aName,
- const FlyWebPublishOptions& aOptions)
- : mActorDestroyed(false)
- , mNextRequestId(1)
-{
- LOG_I("FlyWebPublishedServerParent::FlyWebPublishedServerParent(%p)", this);
-
- RefPtr<FlyWebService> service = FlyWebService::GetOrCreate();
- if (!service) {
- Unused << SendServerReady(NS_ERROR_FAILURE);
- return;
- }
-
- RefPtr<FlyWebPublishPromise> mozPromise =
- service->PublishServer(aName, aOptions, nullptr);
- if (!mozPromise) {
- Unused << SendServerReady(NS_ERROR_FAILURE);
- return;
- }
-
- RefPtr<FlyWebPublishedServerParent> self = this;
-
- mozPromise->Then(
- AbstractThread::MainThread(),
- __func__,
- [this, self] (FlyWebPublishedServer* aServer) {
- mPublishedServer = static_cast<FlyWebPublishedServerImpl*>(aServer);
- if (mActorDestroyed) {
- mPublishedServer->Close();
- return;
- }
-
- mPublishedServer->AddEventListener(NS_LITERAL_STRING("fetch"),
- this, false, false, 2);
- mPublishedServer->AddEventListener(NS_LITERAL_STRING("websocket"),
- this, false, false, 2);
- mPublishedServer->AddEventListener(NS_LITERAL_STRING("close"),
- this, false, false, 2);
- Unused << SendServerReady(NS_OK);
- },
- [this, self] (nsresult aStatus) {
- MOZ_ASSERT(NS_FAILED(aStatus));
- if (!mActorDestroyed) {
- Unused << SendServerReady(aStatus);
- }
- });
-}
-
-NS_IMETHODIMP
-FlyWebPublishedServerParent::HandleEvent(nsIDOMEvent* aEvent)
-{
- if (mActorDestroyed) {
- return NS_OK;
- }
-
- nsAutoString type;
- aEvent->GetType(type);
- if (type.EqualsLiteral("close")) {
- Unused << SendServerClose();
- return NS_OK;
- }
-
- if (type.EqualsLiteral("fetch")) {
- RefPtr<InternalRequest> request =
- static_cast<FlyWebFetchEvent*>(aEvent)->Request()->GetInternalRequest();
- uint64_t id = mNextRequestId++;
- mPendingRequests.Put(id, request);
-
- IPCInternalRequest ipcReq;
- request->ToIPC(&ipcReq);
- Unused << SendFetchRequest(ipcReq, id);
- return NS_OK;
- }
-
- if (type.EqualsLiteral("websocket")) {
- RefPtr<InternalRequest> request =
- static_cast<FlyWebWebSocketEvent*>(aEvent)->Request()->GetInternalRequest();
- uint64_t id = mNextRequestId++;
- mPendingRequests.Put(id, request);
-
- nsTArray<PNeckoParent*> neckoParents;
- Manager()->ManagedPNeckoParent(neckoParents);
- if (neckoParents.Length() != 1) {
- MOZ_CRASH("Expected exactly 1 PNeckoParent instance per PNeckoChild");
- }
-
- RefPtr<TransportProviderParent> provider =
- static_cast<TransportProviderParent*>(
- neckoParents[0]->SendPTransportProviderConstructor());
-
- IPCInternalRequest ipcReq;
- request->ToIPC(&ipcReq);
- Unused << SendWebSocketRequest(ipcReq, id, provider);
-
- mPendingTransportProviders.Put(id, provider.forget());
- return NS_OK;
- }
-
- MOZ_CRASH("Unknown event type");
-
- return NS_OK;
-}
-
-bool
-FlyWebPublishedServerParent::RecvFetchResponse(const IPCInternalResponse& aResponse,
- const uint64_t& aRequestId)
-{
- MOZ_ASSERT(!mActorDestroyed);
-
- RefPtr<InternalRequest> request;
- mPendingRequests.Remove(aRequestId, getter_AddRefs(request));
- if (!request) {
- static_cast<ContentParent*>(Manager())->KillHard("unknown request id");
- return false;
- }
-
- RefPtr<InternalResponse> response = InternalResponse::FromIPC(aResponse);
-
- mPublishedServer->OnFetchResponse(request, response);
-
- return true;
-}
-
-bool
-FlyWebPublishedServerParent::RecvWebSocketResponse(const IPCInternalResponse& aResponse,
- const uint64_t& aRequestId)
-{
- MOZ_ASSERT(!mActorDestroyed);
-
- mPendingTransportProviders.Remove(aRequestId);
-
- RefPtr<InternalRequest> request;
- mPendingRequests.Remove(aRequestId, getter_AddRefs(request));
- if (!request) {
- static_cast<ContentParent*>(Manager())->KillHard("unknown websocket request id");
- return false;
- }
-
- RefPtr<InternalResponse> response = InternalResponse::FromIPC(aResponse);
-
- mPublishedServer->OnWebSocketResponse(request, response);
-
- return true;
-}
-
-bool
-FlyWebPublishedServerParent::RecvWebSocketAccept(const nsString& aProtocol,
- const uint64_t& aRequestId)
-{
- MOZ_ASSERT(!mActorDestroyed);
-
- RefPtr<TransportProviderParent> providerIPC;
- mPendingTransportProviders.Remove(aRequestId, getter_AddRefs(providerIPC));
-
- RefPtr<InternalRequest> request;
- mPendingRequests.Remove(aRequestId, getter_AddRefs(request));
-
- if (!request || !providerIPC) {
- static_cast<ContentParent*>(Manager())->KillHard("unknown websocket request id");
- return false;
- }
-
- Optional<nsAString> protocol;
- if (!aProtocol.IsVoid()) {
- protocol = &aProtocol;
- }
-
- ErrorResult result;
- nsCOMPtr<nsITransportProvider> providerServer =
- mPublishedServer->OnWebSocketAcceptInternal(request, protocol, result);
- if (result.Failed()) {
- return false;
- }
-
- providerServer->SetListener(providerIPC);
-
- return true;
-}
-
-void
-FlyWebPublishedServerParent::ActorDestroy(ActorDestroyReason aWhy)
-{
- LOG_I("FlyWebPublishedServerParent::ActorDestroy(%p)", this);
-
- mActorDestroyed = true;
-}
-
-bool
-FlyWebPublishedServerParent::Recv__delete__()
-{
- LOG_I("FlyWebPublishedServerParent::Recv__delete__(%p)", this);
- MOZ_ASSERT(!mActorDestroyed);
-
- if (mPublishedServer) {
- mPublishedServer->RemoveEventListener(NS_LITERAL_STRING("fetch"),
- this, false);
- mPublishedServer->RemoveEventListener(NS_LITERAL_STRING("websocket"),
- this, false);
- mPublishedServer->RemoveEventListener(NS_LITERAL_STRING("close"),
- this, false);
- mPublishedServer->Close();
- mPublishedServer = nullptr;
- }
- return true;
-}
-
-} // namespace dom
-} // namespace mozilla
-
-
diff --git a/dom/flyweb/FlyWebPublishedServer.h b/dom/flyweb/FlyWebPublishedServer.h
deleted file mode 100644
index ec3a685ec..000000000
--- a/dom/flyweb/FlyWebPublishedServer.h
+++ /dev/null
@@ -1,109 +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_FlyWebPublishedServer_h
-#define mozilla_dom_FlyWebPublishedServer_h
-
-#include "mozilla/DOMEventTargetHelper.h"
-#include "mozilla/MozPromise.h"
-
-class nsPIDOMWindowInner;
-class nsITransportProvider;
-
-namespace mozilla {
-
-class ErrorResult;
-
-namespace dom {
-
-class InternalResponse;
-class InternalRequest;
-class WebSocket;
-struct FlyWebPublishOptions;
-class FlyWebPublishedServer;
-
-typedef MozPromise<RefPtr<FlyWebPublishedServer>, nsresult, false>
- FlyWebPublishPromise;
-
-class FlyWebPublishedServer : public mozilla::DOMEventTargetHelper
-{
-public:
- FlyWebPublishedServer(nsPIDOMWindowInner* aOwner,
- const nsAString& aName,
- const FlyWebPublishOptions& aOptions);
-
- virtual void LastRelease() override;
-
- virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
-
- uint64_t OwnerWindowID() const {
- return mOwnerWindowID;
- }
-
- void GetName(nsAString& aName)
- {
- aName = mName;
- }
- nsAString& Name()
- {
- return mName;
- }
-
- void GetUiUrl(nsAString& aUiUrl)
- {
- aUiUrl = mUiUrl;
- }
-
- virtual void PermissionGranted(bool aGranted) = 0;
-
- virtual void OnFetchResponse(InternalRequest* aRequest,
- InternalResponse* aResponse) = 0;
- already_AddRefed<WebSocket>
- OnWebSocketAccept(InternalRequest* aConnectRequest,
- const Optional<nsAString>& aProtocol,
- ErrorResult& aRv);
- virtual void OnWebSocketResponse(InternalRequest* aConnectRequest,
- InternalResponse* aResponse) = 0;
- virtual already_AddRefed<nsITransportProvider>
- OnWebSocketAcceptInternal(InternalRequest* aConnectRequest,
- const Optional<nsAString>& aProtocol,
- ErrorResult& aRv) = 0;
-
- virtual void Close();
-
- void FireFetchEvent(InternalRequest* aRequest);
- void FireWebsocketEvent(InternalRequest* aConnectRequest);
- void PublishedServerStarted(nsresult aStatus);
-
- IMPL_EVENT_HANDLER(fetch)
- IMPL_EVENT_HANDLER(websocket)
- IMPL_EVENT_HANDLER(close)
-
- already_AddRefed<FlyWebPublishPromise>
- GetPublishPromise()
- {
- return mPublishPromise.Ensure(__func__);
- }
-
-protected:
- virtual ~FlyWebPublishedServer()
- {
- MOZ_ASSERT(!mIsRegistered, "Subclass dtor forgot to call Close()");
- }
-
- uint64_t mOwnerWindowID;
- MozPromiseHolder<FlyWebPublishPromise> mPublishPromise;
-
- nsString mName;
- nsString mUiUrl;
-
- bool mIsRegistered;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_FlyWebPublishedServer_h
diff --git a/dom/flyweb/FlyWebPublishedServerIPC.h b/dom/flyweb/FlyWebPublishedServerIPC.h
deleted file mode 100644
index 942c7847e..000000000
--- a/dom/flyweb/FlyWebPublishedServerIPC.h
+++ /dev/null
@@ -1,172 +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_FlyWebPublishedServerIPC_h
-#define mozilla_dom_FlyWebPublishedServerIPC_h
-
-#include "HttpServer.h"
-#include "mozilla/dom/FlyWebPublishedServer.h"
-#include "mozilla/dom/PFlyWebPublishedServerParent.h"
-#include "mozilla/dom/PFlyWebPublishedServerChild.h"
-#include "mozilla/MozPromise.h"
-#include "nsICancelable.h"
-#include "nsIDOMEventListener.h"
-#include "nsISupportsImpl.h"
-
-class nsPIDOMWindowInner;
-
-namespace mozilla {
-namespace net {
-class TransportProviderParent;
-class TransportProviderChild;
-}
-
-namespace dom {
-
-class FlyWebPublishedServerParent;
-
-class FlyWebPublishedServerImpl final : public FlyWebPublishedServer
- , public HttpServerListener
-{
-public:
- FlyWebPublishedServerImpl(nsPIDOMWindowInner* aOwner,
- const nsAString& aName,
- const FlyWebPublishOptions& aOptions);
-
- NS_DECL_ISUPPORTS_INHERITED
-
- int32_t Port()
- {
- return mHttpServer ? mHttpServer->GetPort() : 0;
- }
- void GetCertKey(nsACString& aKey) {
- if (mHttpServer) {
- mHttpServer->GetCertKey(aKey);
- } else {
- aKey.Truncate();
- }
- }
-
- virtual void PermissionGranted(bool aGranted) override;
- virtual void OnFetchResponse(InternalRequest* aRequest,
- InternalResponse* aResponse) override;
- virtual void OnWebSocketResponse(InternalRequest* aConnectRequest,
- InternalResponse* aResponse) override;
- virtual already_AddRefed<nsITransportProvider>
- OnWebSocketAcceptInternal(InternalRequest* aConnectRequest,
- const Optional<nsAString>& aProtocol,
- ErrorResult& aRv) override;
-
- void SetCancelRegister(nsICancelable* aCancelRegister)
- {
- mMDNSCancelRegister = aCancelRegister;
- }
-
- virtual void Close() override;
-
- // HttpServerListener
- virtual void OnServerStarted(nsresult aStatus) override;
- virtual void OnRequest(InternalRequest* aRequest) override
- {
- FireFetchEvent(aRequest);
- }
- virtual void OnWebSocket(InternalRequest* aConnectRequest) override
- {
- FireWebsocketEvent(aConnectRequest);
- }
- virtual void OnServerClose() override
- {
- mHttpServer = nullptr;
- Close();
- }
-
-private:
- ~FlyWebPublishedServerImpl() {}
-
- RefPtr<HttpServer> mHttpServer;
- nsCOMPtr<nsICancelable> mMDNSCancelRegister;
- RefPtr<FlyWebPublishedServerParent> mServerParent;
-};
-
-class FlyWebPublishedServerChild final : public FlyWebPublishedServer
- , public PFlyWebPublishedServerChild
-{
-public:
- FlyWebPublishedServerChild(nsPIDOMWindowInner* aOwner,
- const nsAString& aName,
- const FlyWebPublishOptions& aOptions);
-
- virtual void PermissionGranted(bool aGranted) override;
- virtual bool RecvServerReady(const nsresult& aStatus) override;
- virtual bool RecvServerClose() override;
- virtual bool RecvFetchRequest(const IPCInternalRequest& aRequest,
- const uint64_t& aRequestId) override;
- virtual bool RecvWebSocketRequest(const IPCInternalRequest& aRequest,
- const uint64_t& aRequestId,
- PTransportProviderChild* aProvider) override;
-
- virtual void OnFetchResponse(InternalRequest* aRequest,
- InternalResponse* aResponse) override;
- virtual void OnWebSocketResponse(InternalRequest* aConnectRequest,
- InternalResponse* aResponse) override;
- virtual already_AddRefed<nsITransportProvider>
- OnWebSocketAcceptInternal(InternalRequest* aConnectRequest,
- const Optional<nsAString>& aProtocol,
- ErrorResult& aRv) override;
-
- virtual void Close() override;
-
- virtual void ActorDestroy(ActorDestroyReason aWhy) override;
-
-private:
- ~FlyWebPublishedServerChild() {}
-
- nsDataHashtable<nsRefPtrHashKey<InternalRequest>, uint64_t> mPendingRequests;
- nsRefPtrHashtable<nsUint64HashKey, TransportProviderChild>
- mPendingTransportProviders;
- bool mActorExists;
-};
-
-class FlyWebPublishedServerParent final : public PFlyWebPublishedServerParent
- , public nsIDOMEventListener
-{
-public:
- FlyWebPublishedServerParent(const nsAString& aName,
- const FlyWebPublishOptions& aOptions);
-
- NS_DECL_ISUPPORTS
- NS_DECL_NSIDOMEVENTLISTENER
-
-private:
- virtual void
- ActorDestroy(ActorDestroyReason aWhy) override;
-
- virtual bool
- Recv__delete__() override;
- virtual bool
- RecvFetchResponse(const IPCInternalResponse& aResponse,
- const uint64_t& aRequestId) override;
- virtual bool
- RecvWebSocketResponse(const IPCInternalResponse& aResponse,
- const uint64_t& aRequestId) override;
- virtual bool
- RecvWebSocketAccept(const nsString& aProtocol,
- const uint64_t& aRequestId) override;
-
- ~FlyWebPublishedServerParent() {}
-
- bool mActorDestroyed;
- uint64_t mNextRequestId;
- nsRefPtrHashtable<nsUint64HashKey, InternalRequest> mPendingRequests;
- nsRefPtrHashtable<nsUint64HashKey, TransportProviderParent>
- mPendingTransportProviders;
- RefPtr<FlyWebPublishedServerImpl> mPublishedServer;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_FlyWebPublishedServerIPC_h
diff --git a/dom/flyweb/FlyWebServerEvents.cpp b/dom/flyweb/FlyWebServerEvents.cpp
deleted file mode 100644
index fe774ffb0..000000000
--- a/dom/flyweb/FlyWebServerEvents.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/* -*- 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/. */
-
-#include "mozilla/dom/EventBinding.h"
-#include "mozilla/dom/FlyWebFetchEventBinding.h"
-#include "mozilla/dom/FlyWebPublishedServer.h"
-#include "mozilla/dom/FlyWebServerEvents.h"
-#include "mozilla/dom/FlyWebWebSocketEventBinding.h"
-#include "mozilla/dom/Nullable.h"
-#include "mozilla/dom/Promise.h"
-#include "mozilla/dom/Response.h"
-
-#include "js/GCAPI.h"
-
-namespace mozilla {
-namespace dom {
-
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(FlyWebFetchEvent)
-
-NS_IMPL_ADDREF_INHERITED(FlyWebFetchEvent, Event)
-NS_IMPL_RELEASE_INHERITED(FlyWebFetchEvent, Event)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FlyWebFetchEvent, Event)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(FlyWebFetchEvent, Event)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FlyWebFetchEvent, Event)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequest)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FlyWebFetchEvent)
-NS_INTERFACE_MAP_END_INHERITING(Event)
-
-FlyWebFetchEvent::FlyWebFetchEvent(FlyWebPublishedServer* aServer,
- class Request* aRequest,
- InternalRequest* aInternalRequest)
- : Event(aServer, nullptr, nullptr)
- , mRequest(aRequest)
- , mInternalRequest(aInternalRequest)
- , mServer(aServer)
- , mResponded(false)
-{
- MOZ_ASSERT(aServer);
- MOZ_ASSERT(aRequest);
- MOZ_ASSERT(aInternalRequest);
-}
-
-FlyWebFetchEvent::~FlyWebFetchEvent()
-{
-}
-
-JSObject*
-FlyWebFetchEvent::WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
- return FlyWebFetchEventBinding::Wrap(aCx, this, aGivenProto);
-}
-
-void
-FlyWebFetchEvent::RespondWith(Promise& aArg, ErrorResult& aRv)
-{
- if (mResponded) {
- aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return;
- }
-
- mResponded = true;
-
- aArg.AppendNativeHandler(this);
-}
-
-void
-FlyWebFetchEvent::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
-{
- RefPtr<Response> response;
- if (aValue.isObject()) {
- UNWRAP_OBJECT(Response, &aValue.toObject(), response);
- }
-
- RefPtr<InternalResponse> intResponse;
- if (response && response->Type() != ResponseType::Opaque) {
- intResponse = response->GetInternalResponse();
- }
-
- if (!intResponse) {
- intResponse = InternalResponse::NetworkError();
- }
-
- NotifyServer(intResponse);
-}
-
-void
-FlyWebFetchEvent::NotifyServer(InternalResponse* aResponse)
-{
- mServer->OnFetchResponse(mInternalRequest, aResponse);
-}
-
-void
-FlyWebFetchEvent::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
-{
- RefPtr<InternalResponse> err = InternalResponse::NetworkError();
-
- NotifyServer(err);
-}
-
-JSObject*
-FlyWebWebSocketEvent::WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
- return FlyWebWebSocketEventBinding::Wrap(aCx, this, aGivenProto);
-}
-
-already_AddRefed<WebSocket>
-FlyWebWebSocketEvent::Accept(const Optional<nsAString>& aProtocol,
- ErrorResult& aRv)
-{
- if (mResponded) {
- aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return nullptr;
- }
-
- mResponded = true;
-
- return mServer->OnWebSocketAccept(mInternalRequest, aProtocol, aRv);
-}
-
-
-void
-FlyWebWebSocketEvent::NotifyServer(InternalResponse* aResponse)
-{
- mServer->OnWebSocketResponse(mInternalRequest, aResponse);
-}
-
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/flyweb/FlyWebServerEvents.h b/dom/flyweb/FlyWebServerEvents.h
deleted file mode 100644
index f00e86018..000000000
--- a/dom/flyweb/FlyWebServerEvents.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* -*- 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_FlyWebFetchEvent_h
-#define mozilla_dom_FlyWebFetchEvent_h
-
-#include "mozilla/Attributes.h"
-#include "mozilla/ErrorResult.h"
-#include "mozilla/dom/BindingUtils.h"
-#include "mozilla/dom/Event.h"
-#include "mozilla/dom/FlyWebFetchEventBinding.h"
-#include "mozilla/dom/PromiseNativeHandler.h"
-#include "mozilla/dom/WebSocket.h"
-
-struct JSContext;
-namespace mozilla {
-namespace dom {
-
-class Request;
-class Response;
-class FlyWebPublishedServer;
-class InternalRequest;
-class InternalResponse;
-
-class FlyWebFetchEvent : public Event
- , public PromiseNativeHandler
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(FlyWebFetchEvent, Event)
-
- virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-
- virtual void
- ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
- virtual void
- RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
-
- class Request* Request() const
- {
- return mRequest;
- }
-
- void RespondWith(Promise& aArg, ErrorResult& aRv);
-
- FlyWebFetchEvent(FlyWebPublishedServer* aServer,
- class Request* aRequest,
- InternalRequest* aInternalRequest);
-
-protected:
- virtual ~FlyWebFetchEvent();
-
- virtual void NotifyServer(InternalResponse* aResponse);
-
- RefPtr<class Request> mRequest;
- RefPtr<InternalRequest> mInternalRequest;
- RefPtr<FlyWebPublishedServer> mServer;
-
- bool mResponded;
-};
-
-class FlyWebWebSocketEvent final : public FlyWebFetchEvent
-{
-public:
- FlyWebWebSocketEvent(FlyWebPublishedServer* aServer,
- class Request* aRequest,
- InternalRequest* aInternalRequest)
- : FlyWebFetchEvent(aServer, aRequest, aInternalRequest)
- {}
-
- virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-
- already_AddRefed<WebSocket> Accept(const Optional<nsAString>& aProtocol,
- ErrorResult& aRv);
-
-private:
- ~FlyWebWebSocketEvent() {};
-
- virtual void NotifyServer(InternalResponse* aResponse) override;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_FlyWebFetchEvent_h
diff --git a/dom/flyweb/FlyWebService.cpp b/dom/flyweb/FlyWebService.cpp
deleted file mode 100644
index 5f3b0d66f..000000000
--- a/dom/flyweb/FlyWebService.cpp
+++ /dev/null
@@ -1,1310 +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 "mozilla/dom/FlyWebService.h"
-#include "mozilla/ClearOnShutdown.h"
-#include "mozilla/StaticPtr.h"
-#include "mozilla/ScopeExit.h"
-#include "mozilla/dom/Promise.h"
-#include "mozilla/dom/FlyWebPublishedServerIPC.h"
-#include "mozilla/AddonPathService.h"
-#include "nsISocketTransportService.h"
-#include "mdns/libmdns/nsDNSServiceInfo.h"
-#include "nsIUUIDGenerator.h"
-#include "nsStandardURL.h"
-#include "mozilla/Services.h"
-#include "nsISupportsPrimitives.h"
-#include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
-#include "prnetdb.h"
-#include "DNS.h"
-#include "nsContentPermissionHelper.h"
-#include "nsSocketTransportService2.h"
-#include "nsSocketTransport2.h"
-#include "nsHashPropertyBag.h"
-#include "nsNetUtil.h"
-#include "nsISimpleEnumerator.h"
-#include "nsIProperty.h"
-#include "nsICertOverrideService.h"
-
-namespace mozilla {
-namespace dom {
-
-struct FlyWebPublishOptions;
-
-static LazyLogModule gFlyWebServiceLog("FlyWebService");
-#undef LOG_I
-#define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
-
-#undef LOG_E
-#define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Error, (__VA_ARGS__))
-
-#undef LOG_TEST_I
-#define LOG_TEST_I(...) MOZ_LOG_TEST(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug)
-
-class FlyWebPublishServerPermissionCheck final
- : public nsIContentPermissionRequest
- , public nsIRunnable
-{
-public:
- NS_DECL_ISUPPORTS
-
- FlyWebPublishServerPermissionCheck(const nsCString& aServiceName, uint64_t aWindowID,
- FlyWebPublishedServer* aServer)
- : mServiceName(aServiceName)
- , mWindowID(aWindowID)
- , mServer(aServer)
- {}
-
- uint64_t WindowID() const
- {
- return mWindowID;
- }
-
- NS_IMETHOD Run() override
- {
- MOZ_ASSERT(NS_IsMainThread());
-
- nsGlobalWindow* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
- if (!globalWindow) {
- return Cancel();
- }
- mWindow = globalWindow->AsInner();
- if (NS_WARN_IF(!mWindow)) {
- return Cancel();
- }
-
- nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
- if (NS_WARN_IF(!doc)) {
- return Cancel();
- }
-
- mPrincipal = doc->NodePrincipal();
- MOZ_ASSERT(mPrincipal);
-
- mRequester = new nsContentPermissionRequester(mWindow);
- return nsContentPermissionUtils::AskPermission(this, mWindow);
- }
-
- NS_IMETHOD Cancel() override
- {
- Resolve(false);
- return NS_OK;
- }
-
- NS_IMETHOD Allow(JS::HandleValue aChoices) override
- {
- MOZ_ASSERT(aChoices.isUndefined());
- Resolve(true);
- return NS_OK;
- }
-
- NS_IMETHOD GetTypes(nsIArray** aTypes) override
- {
- nsTArray<nsString> emptyOptions;
- return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("flyweb-publish-server"),
- NS_LITERAL_CSTRING("unused"), emptyOptions, aTypes);
- }
-
- NS_IMETHOD GetRequester(nsIContentPermissionRequester** aRequester) override
- {
- NS_ENSURE_ARG_POINTER(aRequester);
- nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
- requester.forget(aRequester);
- return NS_OK;
- }
-
- NS_IMETHOD GetPrincipal(nsIPrincipal** aRequestingPrincipal) override
- {
- NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
- return NS_OK;
- }
-
- NS_IMETHOD GetWindow(mozIDOMWindow** aRequestingWindow) override
- {
- NS_IF_ADDREF(*aRequestingWindow = mWindow);
- return NS_OK;
- }
-
- NS_IMETHOD GetElement(nsIDOMElement** aRequestingElement) override
- {
- *aRequestingElement = nullptr;
- return NS_OK;
- }
-
-private:
- void Resolve(bool aResolve)
- {
- mServer->PermissionGranted(aResolve);
- }
-
- virtual ~FlyWebPublishServerPermissionCheck() = default;
-
- nsCString mServiceName;
- uint64_t mWindowID;
- RefPtr<FlyWebPublishedServer> mServer;
- nsCOMPtr<nsPIDOMWindowInner> mWindow;
- nsCOMPtr<nsIPrincipal> mPrincipal;
- nsCOMPtr<nsIContentPermissionRequester> mRequester;
-};
-
-NS_IMPL_ISUPPORTS(FlyWebPublishServerPermissionCheck,
- nsIContentPermissionRequest,
- nsIRunnable)
-
-class FlyWebMDNSService final
- : public nsIDNSServiceDiscoveryListener
- , public nsIDNSServiceResolveListener
- , public nsIDNSRegistrationListener
- , public nsITimerCallback
-{
- friend class FlyWebService;
-
-private:
- enum DiscoveryState {
- DISCOVERY_IDLE,
- DISCOVERY_STARTING,
- DISCOVERY_RUNNING,
- DISCOVERY_STOPPING
- };
-
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIDNSSERVICEDISCOVERYLISTENER
- NS_DECL_NSIDNSSERVICERESOLVELISTENER
- NS_DECL_NSIDNSREGISTRATIONLISTENER
- NS_DECL_NSITIMERCALLBACK
-
- explicit FlyWebMDNSService(FlyWebService* aService,
- const nsACString& aServiceType);
-
-private:
- virtual ~FlyWebMDNSService() = default;
-
- nsresult Init();
- nsresult StartDiscovery();
- nsresult StopDiscovery();
-
- void ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices);
- bool HasService(const nsAString& aServiceId);
- nsresult PairWithService(const nsAString& aServiceId,
- UniquePtr<FlyWebService::PairedInfo>& aInfo);
-
- nsresult StartDiscoveryOf(FlyWebPublishedServerImpl* aServer);
-
- void EnsureDiscoveryStarted();
- void EnsureDiscoveryStopped();
-
- // Cycle-breaking link to manager.
- FlyWebService* mService;
- nsCString mServiceType;
-
- // Indicates the desired state of the system. If mDiscoveryActive is true,
- // it indicates that backend discovery "should be happening", and discovery
- // events should be forwarded to listeners.
- // If false, the backend discovery "should be idle", and any discovery events
- // that show up should not be forwarded to listeners.
- bool mDiscoveryActive;
-
- uint32_t mNumConsecutiveStartDiscoveryFailures;
-
- // Represents the internal discovery state as it relates to nsDNSServiceDiscovery.
- // When mDiscoveryActive is true, this state will periodically loop from
- // (IDLE => STARTING => RUNNING => STOPPING => IDLE).
- DiscoveryState mDiscoveryState;
-
- nsCOMPtr<nsITimer> mDiscoveryStartTimer;
- nsCOMPtr<nsITimer> mDiscoveryStopTimer;
- nsCOMPtr<nsIDNSServiceDiscovery> mDNSServiceDiscovery;
- nsCOMPtr<nsICancelable> mCancelDiscovery;
- nsTHashtable<nsStringHashKey> mNewServiceSet;
-
- struct DiscoveredInfo
- {
- explicit DiscoveredInfo(nsIDNSServiceInfo* aDNSServiceInfo);
- FlyWebDiscoveredService mService;
- nsCOMPtr<nsIDNSServiceInfo> mDNSServiceInfo;
- };
- nsClassHashtable<nsStringHashKey, DiscoveredInfo> mServiceMap;
-};
-
-void
-LogDNSInfo(nsIDNSServiceInfo* aServiceInfo, const char* aFunc)
-{
- if (!LOG_TEST_I()) {
- return;
- }
-
- nsCString tmp;
- aServiceInfo->GetServiceName(tmp);
- LOG_I("%s: serviceName=%s", aFunc, tmp.get());
-
- aServiceInfo->GetHost(tmp);
- LOG_I("%s: host=%s", aFunc, tmp.get());
-
- aServiceInfo->GetAddress(tmp);
- LOG_I("%s: address=%s", aFunc, tmp.get());
-
- uint16_t port = -2;
- aServiceInfo->GetPort(&port);
- LOG_I("%s: port=%d", aFunc, (int)port);
-
- nsCOMPtr<nsIPropertyBag2> attributes;
- aServiceInfo->GetAttributes(getter_AddRefs(attributes));
- if (!attributes) {
- LOG_I("%s: no attributes", aFunc);
- } else {
- nsCOMPtr<nsISimpleEnumerator> enumerator;
- attributes->GetEnumerator(getter_AddRefs(enumerator));
- MOZ_ASSERT(enumerator);
-
- LOG_I("%s: attributes start", aFunc);
-
- bool hasMoreElements;
- while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) &&
- hasMoreElements) {
- nsCOMPtr<nsISupports> element;
- MOZ_ALWAYS_SUCCEEDS(enumerator->GetNext(getter_AddRefs(element)));
- nsCOMPtr<nsIProperty> property = do_QueryInterface(element);
- MOZ_ASSERT(property);
-
- nsAutoString name;
- nsCOMPtr<nsIVariant> value;
- MOZ_ALWAYS_SUCCEEDS(property->GetName(name));
- MOZ_ALWAYS_SUCCEEDS(property->GetValue(getter_AddRefs(value)));
-
- nsAutoCString str;
- nsresult rv = value->GetAsACString(str);
- if (NS_SUCCEEDED(rv)) {
- LOG_I("%s: attribute name=%s value=%s", aFunc,
- NS_ConvertUTF16toUTF8(name).get(), str.get());
- } else {
- uint16_t type;
- MOZ_ALWAYS_SUCCEEDS(value->GetDataType(&type));
- LOG_I("%s: attribute *unstringifiable* name=%s type=%d", aFunc,
- NS_ConvertUTF16toUTF8(name).get(), (int)type);
- }
- }
-
- LOG_I("%s: attributes end", aFunc);
- }
-}
-
-NS_IMPL_ISUPPORTS(FlyWebMDNSService,
- nsIDNSServiceDiscoveryListener,
- nsIDNSServiceResolveListener,
- nsIDNSRegistrationListener,
- nsITimerCallback)
-
-FlyWebMDNSService::FlyWebMDNSService(
- FlyWebService* aService,
- const nsACString& aServiceType)
- : mService(aService)
- , mServiceType(aServiceType)
- , mDiscoveryActive(false)
- , mNumConsecutiveStartDiscoveryFailures(0)
- , mDiscoveryState(DISCOVERY_IDLE)
-{}
-
-nsresult
-FlyWebMDNSService::OnDiscoveryStarted(const nsACString& aServiceType)
-{
- MOZ_ASSERT(mDiscoveryState == DISCOVERY_STARTING);
- mDiscoveryState = DISCOVERY_RUNNING;
- // Reset consecutive start discovery failures.
- mNumConsecutiveStartDiscoveryFailures = 0;
- LOG_I("===========================================");
- LOG_I("MDNSService::OnDiscoveryStarted(%s)", PromiseFlatCString(aServiceType).get());
- LOG_I("===========================================");
-
- // Clear the new service array.
- mNewServiceSet.Clear();
-
- // If service discovery is inactive, then stop network discovery immediately.
- if (!mDiscoveryActive) {
- // Set the stop timer to fire immediately.
- Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
- return NS_OK;
- }
-
- // Otherwise, set the stop timer to fire in 5 seconds.
- Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 5 * 1000, nsITimer::TYPE_ONE_SHOT)));
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnDiscoveryStopped(const nsACString& aServiceType)
-{
- LOG_I("///////////////////////////////////////////");
- LOG_I("MDNSService::OnDiscoveryStopped(%s)", PromiseFlatCString(aServiceType).get());
- LOG_I("///////////////////////////////////////////");
- MOZ_ASSERT(mDiscoveryState == DISCOVERY_STOPPING);
- mDiscoveryState = DISCOVERY_IDLE;
-
- // If service discovery is inactive, then discard all results and do not proceed.
- if (!mDiscoveryActive) {
- mServiceMap.Clear();
- mNewServiceSet.Clear();
- return NS_OK;
- }
-
- // Process the service map, add to the pair map.
- for (auto iter = mServiceMap.Iter(); !iter.Done(); iter.Next()) {
- DiscoveredInfo* service = iter.UserData();
-
- if (!mNewServiceSet.Contains(service->mService.mServiceId)) {
- iter.Remove();
- }
- }
-
- // Notify FlyWebService of changed service list.
- mService->NotifyDiscoveredServicesChanged();
-
- // Start discovery again immediately.
- Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnServiceFound(nsIDNSServiceInfo* aServiceInfo)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceFound");
-
- // If discovery is not active, don't do anything with the result.
- // If there is no discovery underway, ignore this.
- if (!mDiscoveryActive || mDiscoveryState != DISCOVERY_RUNNING) {
- return NS_OK;
- }
-
- // Discovery is underway - resolve the service.
- nsresult rv = mDNSServiceDiscovery->ResolveService(aServiceInfo, this);
- NS_ENSURE_SUCCESS(rv, rv);
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnServiceLost(nsIDNSServiceInfo* aServiceInfo)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceLost");
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnStartDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
-{
- LOG_E("MDNSService::OnStartDiscoveryFailed(%s): %d", PromiseFlatCString(aServiceType).get(), (int) aErrorCode);
-
- MOZ_ASSERT(mDiscoveryState == DISCOVERY_STARTING);
- mDiscoveryState = DISCOVERY_IDLE;
- mNumConsecutiveStartDiscoveryFailures++;
-
- // If discovery is active, and the number of consecutive failures is < 3, try starting again.
- if (mDiscoveryActive && mNumConsecutiveStartDiscoveryFailures < 3) {
- Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
- }
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnStopDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
-{
- LOG_E("MDNSService::OnStopDiscoveryFailed(%s)", PromiseFlatCString(aServiceType).get());
- MOZ_ASSERT(mDiscoveryState == DISCOVERY_STOPPING);
- mDiscoveryState = DISCOVERY_IDLE;
-
- // If discovery is active, start discovery again immediately.
- if (mDiscoveryActive) {
- Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
- }
-
- return NS_OK;
-}
-
-static bool
-IsAcceptableServiceAddress(const nsCString& addr)
-{
- PRNetAddr prNetAddr;
- PRStatus status = PR_StringToNetAddr(addr.get(), &prNetAddr);
- if (status == PR_FAILURE) {
- return false;
- }
- // Only allow ipv4 addreses for now.
- return prNetAddr.raw.family == PR_AF_INET;
-}
-
-nsresult
-FlyWebMDNSService::OnServiceResolved(nsIDNSServiceInfo* aServiceInfo)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceResolved");
-
- // If discovery is not active, don't do anything with the result.
- // If there is no discovery underway, ignore this resolve.
- if (!mDiscoveryActive || mDiscoveryState != DISCOVERY_RUNNING) {
- return NS_OK;
- }
-
- nsresult rv;
-
- nsCString address;
- rv = aServiceInfo->GetAddress(address);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- if (!IsAcceptableServiceAddress(address)) {
- return NS_OK;
- }
-
- // Create a new serviceInfo and stuff it in the new service array.
- UniquePtr<DiscoveredInfo> svc(new DiscoveredInfo(aServiceInfo));
- mNewServiceSet.PutEntry(svc->mService.mServiceId);
-
- DiscoveredInfo* existingSvc =
- mServiceMap.Get(svc->mService.mServiceId);
- if (existingSvc) {
- // Update the underlying DNS service info, but leave the old object in place.
- existingSvc->mDNSServiceInfo = aServiceInfo;
- } else {
- DiscoveredInfo* info = svc.release();
- mServiceMap.Put(info->mService.mServiceId, info);
- }
-
- // Notify FlyWebService of changed service list.
- mService->NotifyDiscoveredServicesChanged();
-
- return NS_OK;
-}
-
-FlyWebMDNSService::DiscoveredInfo::DiscoveredInfo(nsIDNSServiceInfo* aDNSServiceInfo)
- : mDNSServiceInfo(aDNSServiceInfo)
-{
- nsCString tmp;
- DebugOnly<nsresult> drv = aDNSServiceInfo->GetServiceName(tmp);
- MOZ_ASSERT(NS_SUCCEEDED(drv));
- CopyUTF8toUTF16(tmp, mService.mDisplayName);
-
- mService.mTransport = NS_LITERAL_STRING("mdns");
-
- drv = aDNSServiceInfo->GetServiceType(tmp);
- MOZ_ASSERT(NS_SUCCEEDED(drv));
- CopyUTF8toUTF16(tmp, mService.mServiceType);
-
- nsCOMPtr<nsIPropertyBag2> attrs;
- drv = aDNSServiceInfo->GetAttributes(getter_AddRefs(attrs));
- MOZ_ASSERT(NS_SUCCEEDED(drv));
- if (attrs) {
- attrs->GetPropertyAsAString(NS_LITERAL_STRING("cert"), mService.mCert);
- attrs->GetPropertyAsAString(NS_LITERAL_STRING("path"), mService.mPath);
- }
-
- // Construct a service id from the name, host, address, and port.
- nsCString cHost;
- drv = aDNSServiceInfo->GetHost(cHost);
- MOZ_ASSERT(NS_SUCCEEDED(drv));
-
- nsCString cAddress;
- drv = aDNSServiceInfo->GetAddress(cAddress);
- MOZ_ASSERT(NS_SUCCEEDED(drv));
-
- uint16_t port;
- drv = aDNSServiceInfo->GetPort(&port);
- MOZ_ASSERT(NS_SUCCEEDED(drv));
- nsAutoString portStr;
- portStr.AppendInt(port, 10);
-
- mService.mServiceId =
- NS_ConvertUTF8toUTF16(cAddress) +
- NS_LITERAL_STRING(":") +
- portStr +
- NS_LITERAL_STRING("|") +
- mService.mServiceType +
- NS_LITERAL_STRING("|") +
- NS_ConvertUTF8toUTF16(cHost) +
- NS_LITERAL_STRING("|") +
- mService.mDisplayName;
-}
-
-
-nsresult
-FlyWebMDNSService::OnResolveFailed(nsIDNSServiceInfo* aServiceInfo, int32_t aErrorCode)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnResolveFailed");
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnServiceRegistered(nsIDNSServiceInfo* aServiceInfo)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceRegistered");
-
- nsCString cName;
- if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
- return NS_ERROR_FAILURE;
- }
-
- nsString name = NS_ConvertUTF8toUTF16(cName);
- RefPtr<FlyWebPublishedServer> existingServer =
- FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
- if (!existingServer) {
- return NS_ERROR_FAILURE;
- }
-
- existingServer->PublishedServerStarted(NS_OK);
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnServiceUnregistered(nsIDNSServiceInfo* aServiceInfo)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceUnregistered");
-
- nsCString cName;
- if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
- return NS_ERROR_FAILURE;
- }
-
- nsString name = NS_ConvertUTF8toUTF16(cName);
- RefPtr<FlyWebPublishedServer> existingServer =
- FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
- if (!existingServer) {
- return NS_ERROR_FAILURE;
- }
-
- LOG_I("OnServiceRegistered(MDNS): De-advertised server with name %s.", cName.get());
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnRegistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t errorCode)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnRegistrationFailed");
-
- nsCString cName;
- if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
- return NS_ERROR_FAILURE;
- }
-
- nsString name = NS_ConvertUTF8toUTF16(cName);
- RefPtr<FlyWebPublishedServer> existingServer =
- FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
- if (!existingServer) {
- return NS_ERROR_FAILURE;
- }
-
- LOG_I("OnServiceRegistered(MDNS): Registration of server with name %s failed.", cName.get());
-
- // Remove the nsICancelable from the published server.
- existingServer->PublishedServerStarted(NS_ERROR_FAILURE);
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnUnregistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t errorCode)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnUnregistrationFailed");
-
- nsCString cName;
- if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
- return NS_ERROR_FAILURE;
- }
-
- nsString name = NS_ConvertUTF8toUTF16(cName);
- RefPtr<FlyWebPublishedServer> existingServer =
- FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
- if (!existingServer) {
- return NS_ERROR_FAILURE;
- }
-
- LOG_I("OnServiceRegistered(MDNS): Un-Advertisement of server with name %s failed.", cName.get());
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::Notify(nsITimer* timer)
-{
- if (timer == mDiscoveryStopTimer.get()) {
- LOG_I("MDNSService::Notify() got discovery stop timeout");
- // Internet discovery stop timer has fired.
- nsresult rv = StopDiscovery();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return NS_OK;
- }
-
- if (timer == mDiscoveryStartTimer.get()) {
- LOG_I("MDNSService::Notify() got discovery start timeout");
- // Internet discovery start timer has fired.
- nsresult rv = StartDiscovery();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return NS_OK;
- }
-
- LOG_E("MDNSService::Notify got unknown timeout.");
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::Init()
-{
- MOZ_ASSERT(mDiscoveryState == DISCOVERY_IDLE);
-
- mDiscoveryStartTimer = do_CreateInstance("@mozilla.org/timer;1");
- if (!mDiscoveryStartTimer) {
- return NS_ERROR_FAILURE;
- }
-
- mDiscoveryStopTimer = do_CreateInstance("@mozilla.org/timer;1");
- if (!mDiscoveryStopTimer) {
- return NS_ERROR_FAILURE;
- }
-
- nsresult rv;
- mDNSServiceDiscovery = do_GetService(DNSSERVICEDISCOVERY_CONTRACT_ID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::StartDiscovery()
-{
- nsresult rv;
-
- // Always cancel the timer.
- rv = mDiscoveryStartTimer->Cancel();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- LOG_E("FlyWeb failed to cancel DNS service discovery start timer.");
- }
-
- // If discovery is not idle, don't start it.
- if (mDiscoveryState != DISCOVERY_IDLE) {
- return NS_OK;
- }
-
- LOG_I("FlyWeb starting dicovery.");
- mDiscoveryState = DISCOVERY_STARTING;
-
- // start the discovery.
- rv = mDNSServiceDiscovery->StartDiscovery(mServiceType, this,
- getter_AddRefs(mCancelDiscovery));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- LOG_E("FlyWeb failed to start DNS service discovery.");
- return rv;
- }
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::StopDiscovery()
-{
- nsresult rv;
-
- // Always cancel the timer.
- rv = mDiscoveryStopTimer->Cancel();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- LOG_E("FlyWeb failed to cancel DNS service discovery stop timer.");
- }
-
- // If discovery is not running, do nothing.
- if (mDiscoveryState != DISCOVERY_RUNNING) {
- return NS_OK;
- }
-
- LOG_I("FlyWeb stopping dicovery.");
-
- // Mark service discovery as stopping.
- mDiscoveryState = DISCOVERY_STOPPING;
-
- if (mCancelDiscovery) {
- LOG_I("MDNSService::StopDiscovery() - mCancelDiscovery exists!");
- nsCOMPtr<nsICancelable> cancelDiscovery = mCancelDiscovery.forget();
- rv = cancelDiscovery->Cancel(NS_ERROR_ABORT);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- LOG_E("FlyWeb failed to cancel DNS stop service discovery.");
- }
- } else {
- LOG_I("MDNSService::StopDiscovery() - mCancelDiscovery does not exist!");
- mDiscoveryState = DISCOVERY_IDLE;
- }
-
- return NS_OK;
-}
-
-void
-FlyWebMDNSService::ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices)
-{
- for (auto iter = mServiceMap.Iter(); !iter.Done(); iter.Next()) {
- aServices.AppendElement(iter.UserData()->mService);
- }
-}
-
-bool
-FlyWebMDNSService::HasService(const nsAString& aServiceId)
-{
- return mServiceMap.Contains(aServiceId);
-}
-
-nsresult
-FlyWebMDNSService::PairWithService(const nsAString& aServiceId,
- UniquePtr<FlyWebService::PairedInfo>& aInfo)
-{
- MOZ_ASSERT(HasService(aServiceId));
-
- nsresult rv;
- nsCOMPtr<nsIUUIDGenerator> uuidgen =
- do_GetService("@mozilla.org/uuid-generator;1", &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsID id;
- rv = uuidgen->GenerateUUIDInPlace(&id);
- NS_ENSURE_SUCCESS(rv, rv);
-
- aInfo.reset(new FlyWebService::PairedInfo());
-
- char uuidChars[NSID_LENGTH];
- id.ToProvidedString(uuidChars);
- CopyUTF8toUTF16(Substring(uuidChars + 1, uuidChars + NSID_LENGTH - 2),
- aInfo->mService.mHostname);
-
- DiscoveredInfo* discInfo = mServiceMap.Get(aServiceId);
-
- nsAutoString url;
- if (discInfo->mService.mCert.IsEmpty()) {
- url.AssignLiteral("http://");
- } else {
- url.AssignLiteral("https://");
- }
- url.Append(aInfo->mService.mHostname + NS_LITERAL_STRING("/"));
- nsCOMPtr<nsIURI> uiURL;
- NS_NewURI(getter_AddRefs(uiURL), url);
- MOZ_ASSERT(uiURL);
- if (!discInfo->mService.mPath.IsEmpty()) {
- nsCOMPtr<nsIURI> tmp = uiURL.forget();
- NS_NewURI(getter_AddRefs(uiURL), discInfo->mService.mPath, nullptr, tmp);
- }
- if (uiURL) {
- nsAutoCString spec;
- uiURL->GetSpec(spec);
- CopyUTF8toUTF16(spec, aInfo->mService.mUiUrl);
- }
-
- aInfo->mService.mDiscoveredService = discInfo->mService;
- aInfo->mDNSServiceInfo = discInfo->mDNSServiceInfo;
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::StartDiscoveryOf(FlyWebPublishedServerImpl* aServer)
-{
-
- RefPtr<FlyWebPublishedServer> existingServer =
- FlyWebService::GetOrCreate()->FindPublishedServerByName(aServer->Name());
- MOZ_ASSERT(existingServer);
-
- // Advertise the service via mdns.
- RefPtr<net::nsDNSServiceInfo> serviceInfo(new net::nsDNSServiceInfo());
-
- serviceInfo->SetPort(aServer->Port());
- serviceInfo->SetServiceType(mServiceType);
-
- nsCString certKey;
- aServer->GetCertKey(certKey);
- nsString uiURL;
- aServer->GetUiUrl(uiURL);
-
- if (!uiURL.IsEmpty() || !certKey.IsEmpty()) {
- RefPtr<nsHashPropertyBag> attrs = new nsHashPropertyBag();
- if (!uiURL.IsEmpty()) {
- attrs->SetPropertyAsAString(NS_LITERAL_STRING("path"), uiURL);
- }
- if (!certKey.IsEmpty()) {
- attrs->SetPropertyAsACString(NS_LITERAL_STRING("cert"), certKey);
- }
- serviceInfo->SetAttributes(attrs);
- }
-
- nsCString cstrName = NS_ConvertUTF16toUTF8(aServer->Name());
- LOG_I("MDNSService::StartDiscoveryOf() advertising service %s", cstrName.get());
- serviceInfo->SetServiceName(cstrName);
-
- LogDNSInfo(serviceInfo, "FlyWebMDNSService::StartDiscoveryOf");
-
- // Advertise the service.
- nsCOMPtr<nsICancelable> cancelRegister;
- nsresult rv = mDNSServiceDiscovery->
- RegisterService(serviceInfo, this, getter_AddRefs(cancelRegister));
- NS_ENSURE_SUCCESS(rv, rv);
-
- // All done.
- aServer->SetCancelRegister(cancelRegister);
-
- return NS_OK;
-}
-
-void
-FlyWebMDNSService::EnsureDiscoveryStarted()
-{
- mDiscoveryActive = true;
- // If state is idle, start discovery immediately.
- if (mDiscoveryState == DISCOVERY_IDLE) {
- StartDiscovery();
- }
-}
-
-void
-FlyWebMDNSService::EnsureDiscoveryStopped()
-{
- // All we need to do is set the flag to false.
- // If current state is IDLE, it's already the correct state.
- // Otherwise, the handlers for the internal state
- // transitions will check this flag and drive the state
- // towards IDLE.
- mDiscoveryActive = false;
-}
-
-static StaticRefPtr<FlyWebService> gFlyWebService;
-
-NS_IMPL_ISUPPORTS(FlyWebService, nsIObserver)
-
-FlyWebService::FlyWebService()
- : mMonitor("FlyWebService::mMonitor")
-{
- MOZ_ASSERT(NS_IsMainThread());
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- if (obs) {
- obs->AddObserver(this, "inner-window-destroyed", false);
- }
-}
-
-FlyWebService::~FlyWebService()
-{
-}
-
-FlyWebService*
-FlyWebService::GetExisting()
-{
- return gFlyWebService;
-}
-
-FlyWebService*
-FlyWebService::GetOrCreate()
-{
- if (!gFlyWebService) {
- gFlyWebService = new FlyWebService();
- ClearOnShutdown(&gFlyWebService);
- ErrorResult rv = gFlyWebService->Init();
- if (rv.Failed()) {
- gFlyWebService = nullptr;
- return nullptr;
- }
- }
- return gFlyWebService;
-}
-
-ErrorResult
-FlyWebService::Init()
-{
- // Most functions of FlyWebService should not be started in the child.
- // Instead FlyWebService in the child is mainly responsible for tracking
- // publishedServer lifetimes. Other functions are handled by the
- // FlyWebService running in the parent.
- if (XRE_GetProcessType() == GeckoProcessType_Content) {
- return ErrorResult(NS_OK);
- }
-
- MOZ_ASSERT(NS_IsMainThread());
- if (!mMDNSHttpService) {
- mMDNSHttpService = new FlyWebMDNSService(this, NS_LITERAL_CSTRING("_http._tcp."));
- ErrorResult rv;
-
- rv = mMDNSHttpService->Init();
- if (rv.Failed()) {
- LOG_E("FlyWebService failed to initialize MDNS _http._tcp.");
- mMDNSHttpService = nullptr;
- rv.SuppressException();
- }
- }
-
- if (!mMDNSFlywebService) {
- mMDNSFlywebService = new FlyWebMDNSService(this, NS_LITERAL_CSTRING("_flyweb._tcp."));
- ErrorResult rv;
-
- rv = mMDNSFlywebService->Init();
- if (rv.Failed()) {
- LOG_E("FlyWebService failed to initialize MDNS _flyweb._tcp.");
- mMDNSFlywebService = nullptr;
- rv.SuppressException();
- }
- }
-
- return ErrorResult(NS_OK);
-}
-
-static already_AddRefed<FlyWebPublishPromise>
-MakeRejectionPromise(const char* name)
-{
- MozPromiseHolder<FlyWebPublishPromise> holder;
- RefPtr<FlyWebPublishPromise> promise = holder.Ensure(name);
- holder.Reject(NS_ERROR_FAILURE, name);
- return promise.forget();
-}
-
-static bool
-CheckForFlyWebAddon(const nsACString& uriString)
-{
- // Before proceeding, ensure that the FlyWeb system addon exists.
- nsresult rv;
- nsCOMPtr<nsIURI> uri;
- rv = NS_NewURI(getter_AddRefs(uri), uriString);
- if (NS_FAILED(rv)) {
- return false;
- }
-
- JSAddonId *addonId = MapURIToAddonID(uri);
- if (!addonId) {
- return false;
- }
-
- JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId));
- nsAutoString addonIdString;
- AssignJSFlatString(addonIdString, flat);
- if (!addonIdString.EqualsLiteral("flyweb@mozilla.org")) {
- nsCString addonIdCString = NS_ConvertUTF16toUTF8(addonIdString);
- return false;
- }
-
- return true;
-}
-
-already_AddRefed<FlyWebPublishPromise>
-FlyWebService::PublishServer(const nsAString& aName,
- const FlyWebPublishOptions& aOptions,
- nsPIDOMWindowInner* aWindow)
-{
- // Scan uiUrl for illegal characters
-
- RefPtr<FlyWebPublishedServer> existingServer =
- FlyWebService::GetOrCreate()->FindPublishedServerByName(aName);
- if (existingServer) {
- LOG_I("PublishServer: Trying to publish server with already-existing name %s.",
- NS_ConvertUTF16toUTF8(aName).get());
- return MakeRejectionPromise(__func__);
- }
-
- RefPtr<FlyWebPublishedServer> server;
- if (XRE_GetProcessType() == GeckoProcessType_Content) {
- server = new FlyWebPublishedServerChild(aWindow, aName, aOptions);
- } else {
- server = new FlyWebPublishedServerImpl(aWindow, aName, aOptions);
-
- // Before proceeding, ensure that the FlyWeb system addon exists.
- if (!CheckForFlyWebAddon(NS_LITERAL_CSTRING("chrome://flyweb/skin/icon-64.png")) &&
- !CheckForFlyWebAddon(NS_LITERAL_CSTRING("chrome://flyweb/content/icon-64.png")))
- {
- LOG_E("PublishServer: Failed to find FlyWeb system addon.");
- return MakeRejectionPromise(__func__);
- }
- }
-
- if (aWindow) {
- nsresult rv;
-
- MOZ_ASSERT(NS_IsMainThread());
- rv = NS_DispatchToCurrentThread(
- MakeAndAddRef<FlyWebPublishServerPermissionCheck>(
- NS_ConvertUTF16toUTF8(aName), aWindow->WindowID(), server));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- LOG_E("PublishServer: Failed to dispatch permission check runnable for %s",
- NS_ConvertUTF16toUTF8(aName).get());
- return MakeRejectionPromise(__func__);
- }
- } else {
- // If aWindow is null, we're definitely in the e10s parent process.
- // In this case, we know that permission has already been granted
- // by the user because of content-process prompt.
- MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
- server->PermissionGranted(true);
- }
-
- mServers.AppendElement(server);
-
- return server->GetPublishPromise();
-}
-
-already_AddRefed<FlyWebPublishedServer>
-FlyWebService::FindPublishedServerByName(
- const nsAString& aName)
-{
- MOZ_ASSERT(NS_IsMainThread());
- for (FlyWebPublishedServer* publishedServer : mServers) {
- if (publishedServer->Name().Equals(aName)) {
- RefPtr<FlyWebPublishedServer> server = publishedServer;
- return server.forget();
- }
- }
- return nullptr;
-}
-
-void
-FlyWebService::RegisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager)
-{
- MOZ_ASSERT(NS_IsMainThread());
- mDiscoveryManagerTable.PutEntry(aDiscoveryManager);
- if (mMDNSHttpService) {
- mMDNSHttpService->EnsureDiscoveryStarted();
- }
- if (mMDNSFlywebService) {
- mMDNSFlywebService->EnsureDiscoveryStarted();
- }
-}
-
-void
-FlyWebService::UnregisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager)
-{
- MOZ_ASSERT(NS_IsMainThread());
- mDiscoveryManagerTable.RemoveEntry(aDiscoveryManager);
- if (mDiscoveryManagerTable.IsEmpty()) {
- if (mMDNSHttpService) {
- mMDNSHttpService->EnsureDiscoveryStopped();
- }
- if (mMDNSFlywebService) {
- mMDNSFlywebService->EnsureDiscoveryStopped();
- }
- }
-}
-
-NS_IMETHODIMP
-FlyWebService::Observe(nsISupports* aSubject, const char* aTopic,
- const char16_t* aData)
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (strcmp(aTopic, "inner-window-destroyed")) {
- return NS_OK;
- }
-
- nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
- NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
-
- uint64_t innerID;
- nsresult rv = wrapper->GetData(&innerID);
- NS_ENSURE_SUCCESS(rv, rv);
-
- for (FlyWebPublishedServer* server : mServers) {
- if (server->OwnerWindowID() == innerID) {
- server->Close();
- }
- }
-
- return NS_OK;
-}
-
-void
-FlyWebService::UnregisterServer(FlyWebPublishedServer* aServer)
-{
- MOZ_ASSERT(NS_IsMainThread());
- DebugOnly<bool> removed = mServers.RemoveElement(aServer);
- MOZ_ASSERT(removed);
-}
-
-bool
-FlyWebService::HasConnectionOrServer(uint64_t aWindowID)
-{
- MOZ_ASSERT(NS_IsMainThread());
- for (FlyWebPublishedServer* server : mServers) {
- nsPIDOMWindowInner* win = server->GetOwner();
- if (win && win->WindowID() == aWindowID) {
- return true;
- }
- }
-
- return false;
-}
-
-void
-FlyWebService::NotifyDiscoveredServicesChanged()
-{
- // Process the service map, add to the pair map.
- for (auto iter = mDiscoveryManagerTable.Iter(); !iter.Done(); iter.Next()) {
- iter.Get()->GetKey()->NotifyDiscoveredServicesChanged();
- }
-}
-
-void
-FlyWebService::ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices)
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (mMDNSHttpService) {
- mMDNSHttpService->ListDiscoveredServices(aServices);
- }
- if (mMDNSFlywebService) {
- mMDNSFlywebService->ListDiscoveredServices(aServices);
- }
-}
-
-void
-FlyWebService::PairWithService(const nsAString& aServiceId,
- FlyWebPairingCallback& aCallback)
-{
- MOZ_ASSERT(NS_IsMainThread());
- // See if we have already paired with this service. If so, re-use the
- // FlyWebPairedService for that.
- {
- ReentrantMonitorAutoEnter pairedMapLock(mMonitor);
- for (auto iter = mPairedServiceTable.Iter(); !iter.Done(); iter.Next()) {
- PairedInfo* pairInfo = iter.UserData();
- if (pairInfo->mService.mDiscoveredService.mServiceId.Equals(aServiceId)) {
- ErrorResult er;
- ReentrantMonitorAutoExit pairedMapRelease(mMonitor);
- aCallback.PairingSucceeded(pairInfo->mService, er);
- ENSURE_SUCCESS_VOID(er);
- return;
- }
- }
- }
-
- UniquePtr<PairedInfo> pairInfo;
-
- nsresult rv = NS_OK;
- bool notFound = false;
- if (mMDNSHttpService && mMDNSHttpService->HasService(aServiceId)) {
- rv = mMDNSHttpService->PairWithService(aServiceId, pairInfo);
- } else if (mMDNSFlywebService && mMDNSFlywebService->HasService(aServiceId)) {
- rv = mMDNSFlywebService->PairWithService(aServiceId, pairInfo);
- } else {
- notFound = true;
- }
-
- if (NS_FAILED(rv)) {
- ErrorResult result;
- result.Throw(rv);
- const nsAString& reason = NS_LITERAL_STRING("Error pairing.");
- aCallback.PairingFailed(reason, result);
- ENSURE_SUCCESS_VOID(result);
- return;
- }
-
- if (!pairInfo) {
- ErrorResult res;
- const nsAString& reason = notFound ?
- NS_LITERAL_STRING("No such service.") :
- NS_LITERAL_STRING("Error pairing.");
- aCallback.PairingFailed(reason, res);
- ENSURE_SUCCESS_VOID(res);
- return;
- }
-
- // Add fingerprint to certificate override database.
- if (!pairInfo->mService.mDiscoveredService.mCert.IsEmpty()) {
- nsCOMPtr<nsICertOverrideService> override =
- do_GetService("@mozilla.org/security/certoverride;1");
- if (!override ||
- NS_FAILED(override->RememberTemporaryValidityOverrideUsingFingerprint(
- NS_ConvertUTF16toUTF8(pairInfo->mService.mHostname),
- -1,
- NS_ConvertUTF16toUTF8(pairInfo->mService.mDiscoveredService.mCert),
- nsICertOverrideService::ERROR_UNTRUSTED |
- nsICertOverrideService::ERROR_MISMATCH))) {
- ErrorResult res;
- aCallback.PairingFailed(NS_LITERAL_STRING("Error adding certificate override."), res);
- ENSURE_SUCCESS_VOID(res);
- return;
- }
- }
-
- // Grab a weak reference to the PairedInfo so that we can
- // use it even after ownership has been transferred to mPairedServiceTable
- PairedInfo* pairInfoWeak = pairInfo.release();
-
- {
- ReentrantMonitorAutoEnter pairedMapLock(mMonitor);
- mPairedServiceTable.Put(
- NS_ConvertUTF16toUTF8(pairInfoWeak->mService.mHostname), pairInfoWeak);
- }
-
- ErrorResult er;
- aCallback.PairingSucceeded(pairInfoWeak->mService, er);
- ENSURE_SUCCESS_VOID(er);
-}
-
-nsresult
-FlyWebService::CreateTransportForHost(const char **types,
- uint32_t typeCount,
- const nsACString &host,
- int32_t port,
- const nsACString &hostRoute,
- int32_t portRoute,
- nsIProxyInfo *proxyInfo,
- nsISocketTransport **result)
-{
- // This might be called on background threads
-
- *result = nullptr;
-
- nsCString ipAddrString;
- uint16_t discPort;
-
- {
- ReentrantMonitorAutoEnter pairedMapLock(mMonitor);
-
- PairedInfo* info = mPairedServiceTable.Get(host);
-
- if (!info) {
- return NS_OK;
- }
-
- // Get the ip address of the underlying service.
- info->mDNSServiceInfo->GetAddress(ipAddrString);
- info->mDNSServiceInfo->GetPort(&discPort);
- }
-
- // Parse it into an NetAddr.
- PRNetAddr prNetAddr;
- PRStatus status = PR_StringToNetAddr(ipAddrString.get(), &prNetAddr);
- NS_ENSURE_FALSE(status == PR_FAILURE, NS_ERROR_FAILURE);
-
- // Convert PRNetAddr to NetAddr.
- mozilla::net::NetAddr netAddr;
- PRNetAddrToNetAddr(&prNetAddr, &netAddr);
- netAddr.inet.port = htons(discPort);
-
- RefPtr<mozilla::net::nsSocketTransport> trans = new mozilla::net::nsSocketTransport();
- nsresult rv = trans->InitPreResolved(
- types, typeCount, host, port, hostRoute, portRoute, proxyInfo, &netAddr);
- NS_ENSURE_SUCCESS(rv, rv);
-
- trans.forget(result);
- return NS_OK;
-}
-
-void
-FlyWebService::StartDiscoveryOf(FlyWebPublishedServerImpl* aServer)
-{
- MOZ_ASSERT(NS_IsMainThread());
- nsresult rv = mMDNSFlywebService ?
- mMDNSFlywebService->StartDiscoveryOf(aServer) :
- NS_ERROR_FAILURE;
-
- if (NS_FAILED(rv)) {
- aServer->PublishedServerStarted(rv);
- }
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/flyweb/FlyWebService.h b/dom/flyweb/FlyWebService.h
deleted file mode 100644
index f7b983440..000000000
--- a/dom/flyweb/FlyWebService.h
+++ /dev/null
@@ -1,113 +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_FlyWebService_h
-#define mozilla_dom_FlyWebService_h
-
-#include "nsISupportsImpl.h"
-#include "mozilla/ErrorResult.h"
-#include "nsIProtocolHandler.h"
-#include "nsDataHashtable.h"
-#include "nsClassHashtable.h"
-#include "nsIObserver.h"
-#include "mozilla/MozPromise.h"
-#include "mozilla/ReentrantMonitor.h"
-#include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
-#include "nsITimer.h"
-#include "nsICancelable.h"
-#include "nsIDNSServiceDiscovery.h"
-
-class nsPIDOMWindowInner;
-class nsIProxyInfo;
-class nsISocketTransport;
-
-namespace mozilla {
-namespace dom {
-
-struct FlyWebPublishOptions;
-struct FlyWebFilter;
-class FlyWebPublishedServer;
-class FlyWebPublishedServerImpl;
-class FlyWebPairingCallback;
-class FlyWebDiscoveryManager;
-class FlyWebMDNSService;
-
-typedef MozPromise<RefPtr<FlyWebPublishedServer>, nsresult, false>
- FlyWebPublishPromise;
-
-class FlyWebService final : public nsIObserver
-{
- friend class FlyWebMDNSService;
-public:
- NS_DECL_THREADSAFE_ISUPPORTS
- NS_DECL_NSIOBSERVER
-
- static FlyWebService* GetExisting();
- static FlyWebService* GetOrCreate();
- static already_AddRefed<FlyWebService> GetOrCreateAddRefed()
- {
- return do_AddRef(GetOrCreate());
- }
-
- already_AddRefed<FlyWebPublishPromise>
- PublishServer(const nsAString& aName,
- const FlyWebPublishOptions& aOptions,
- nsPIDOMWindowInner* aWindow);
-
- void UnregisterServer(FlyWebPublishedServer* aServer);
-
- bool HasConnectionOrServer(uint64_t aWindowID);
-
- void ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices);
- void PairWithService(const nsAString& aServiceId, FlyWebPairingCallback& aCallback);
- nsresult CreateTransportForHost(const char **types,
- uint32_t typeCount,
- const nsACString &host,
- int32_t port,
- const nsACString &hostRoute,
- int32_t portRoute,
- nsIProxyInfo *proxyInfo,
- nsISocketTransport **result);
-
- already_AddRefed<FlyWebPublishedServer> FindPublishedServerByName(
- const nsAString& aName);
-
- void RegisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager);
- void UnregisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager);
-
- // Should only be called by FlyWebPublishedServerImpl
- void StartDiscoveryOf(FlyWebPublishedServerImpl* aServer);
-
-private:
- FlyWebService();
- ~FlyWebService();
-
- ErrorResult Init();
-
- void NotifyDiscoveredServicesChanged();
-
- // Might want to make these hashes for perf
- nsTArray<FlyWebPublishedServer*> mServers;
-
- RefPtr<FlyWebMDNSService> mMDNSHttpService;
- RefPtr<FlyWebMDNSService> mMDNSFlywebService;
-
- struct PairedInfo
- {
- FlyWebPairedService mService;
- nsCOMPtr<nsIDNSServiceInfo> mDNSServiceInfo;
- };
- nsClassHashtable<nsCStringHashKey, PairedInfo>
- mPairedServiceTable;
- ReentrantMonitor mMonitor; // Protecting mPairedServiceTable
-
- nsTHashtable<nsPtrHashKey<FlyWebDiscoveryManager>> mDiscoveryManagerTable;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_FlyWebService_h
diff --git a/dom/flyweb/HttpServer.cpp b/dom/flyweb/HttpServer.cpp
deleted file mode 100644
index 26e15d9d5..000000000
--- a/dom/flyweb/HttpServer.cpp
+++ /dev/null
@@ -1,1319 +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 "mozilla/dom/HttpServer.h"
-#include "nsISocketTransport.h"
-#include "nsWhitespaceTokenizer.h"
-#include "nsNetUtil.h"
-#include "nsIStreamTransportService.h"
-#include "nsIAsyncStreamCopier2.h"
-#include "nsIPipe.h"
-#include "nsIOService.h"
-#include "nsIHttpChannelInternal.h"
-#include "Base64.h"
-#include "WebSocketChannel.h"
-#include "nsCharSeparatedTokenizer.h"
-#include "nsIX509Cert.h"
-
-static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
-
-namespace mozilla {
-namespace dom {
-
-static LazyLogModule gHttpServerLog("HttpServer");
-#undef LOG_I
-#define LOG_I(...) MOZ_LOG(gHttpServerLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
-#undef LOG_V
-#define LOG_V(...) MOZ_LOG(gHttpServerLog, mozilla::LogLevel::Verbose, (__VA_ARGS__))
-#undef LOG_E
-#define LOG_E(...) MOZ_LOG(gHttpServerLog, mozilla::LogLevel::Error, (__VA_ARGS__))
-
-
-NS_IMPL_ISUPPORTS(HttpServer,
- nsIServerSocketListener,
- nsILocalCertGetCallback)
-
-HttpServer::HttpServer()
- : mPort()
- , mHttps()
-{
-}
-
-HttpServer::~HttpServer()
-{
-}
-
-void
-HttpServer::Init(int32_t aPort, bool aHttps, HttpServerListener* aListener)
-{
- mPort = aPort;
- mHttps = aHttps;
- mListener = aListener;
-
- if (mHttps) {
- nsCOMPtr<nsILocalCertService> lcs =
- do_CreateInstance("@mozilla.org/security/local-cert-service;1");
- nsresult rv = lcs->GetOrCreateCert(NS_LITERAL_CSTRING("flyweb"), this);
- if (NS_FAILED(rv)) {
- NotifyStarted(rv);
- }
- } else {
- // Make sure to always have an async step before notifying callbacks
- HandleCert(nullptr, NS_OK);
- }
-}
-
-NS_IMETHODIMP
-HttpServer::HandleCert(nsIX509Cert* aCert, nsresult aResult)
-{
- nsresult rv = aResult;
- if (NS_SUCCEEDED(rv)) {
- rv = StartServerSocket(aCert);
- }
-
- if (NS_FAILED(rv) && mServerSocket) {
- mServerSocket->Close();
- mServerSocket = nullptr;
- }
-
- NotifyStarted(rv);
-
- return NS_OK;
-}
-
-void
-HttpServer::NotifyStarted(nsresult aStatus)
-{
- RefPtr<HttpServerListener> listener = mListener;
- nsCOMPtr<nsIRunnable> event = NS_NewRunnableFunction([listener, aStatus] ()
- {
- listener->OnServerStarted(aStatus);
- });
- NS_DispatchToCurrentThread(event);
-}
-
-nsresult
-HttpServer::StartServerSocket(nsIX509Cert* aCert)
-{
- nsresult rv;
- mServerSocket =
- do_CreateInstance(aCert ? "@mozilla.org/network/tls-server-socket;1"
- : "@mozilla.org/network/server-socket;1", &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = mServerSocket->Init(mPort, false, -1);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (aCert) {
- nsCOMPtr<nsITLSServerSocket> tls = do_QueryInterface(mServerSocket);
- rv = tls->SetServerCert(aCert);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = tls->SetSessionTickets(false);
- NS_ENSURE_SUCCESS(rv, rv);
-
- mCert = aCert;
- }
-
- rv = mServerSocket->AsyncListen(this);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = mServerSocket->GetPort(&mPort);
- NS_ENSURE_SUCCESS(rv, rv);
-
- LOG_I("HttpServer::StartServerSocket(%p)", this);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpServer::OnSocketAccepted(nsIServerSocket* aServ,
- nsISocketTransport* aTransport)
-{
- MOZ_ASSERT(SameCOMIdentity(aServ, mServerSocket));
-
- nsresult rv;
- RefPtr<Connection> conn = new Connection(aTransport, this, rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- LOG_I("HttpServer::OnSocketAccepted(%p) - Socket %p", this, conn.get());
-
- mConnections.AppendElement(conn.forget());
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpServer::OnStopListening(nsIServerSocket* aServ,
- nsresult aStatus)
-{
- MOZ_ASSERT(aServ == mServerSocket || !mServerSocket);
-
- LOG_I("HttpServer::OnStopListening(%p) - status 0x%lx", this, aStatus);
-
- Close();
-
- return NS_OK;
-}
-
-void
-HttpServer::SendResponse(InternalRequest* aRequest, InternalResponse* aResponse)
-{
- for (Connection* conn : mConnections) {
- if (conn->TryHandleResponse(aRequest, aResponse)) {
- return;
- }
- }
-
- MOZ_ASSERT(false, "Unknown request");
-}
-
-already_AddRefed<nsITransportProvider>
-HttpServer::AcceptWebSocket(InternalRequest* aConnectRequest,
- const Optional<nsAString>& aProtocol,
- ErrorResult& aRv)
-{
- for (Connection* conn : mConnections) {
- if (!conn->HasPendingWebSocketRequest(aConnectRequest)) {
- continue;
- }
- nsCOMPtr<nsITransportProvider> provider =
- conn->HandleAcceptWebSocket(aProtocol, aRv);
- if (aRv.Failed()) {
- conn->Close();
- }
- // This connection is now owned by the websocket, or we just closed it
- mConnections.RemoveElement(conn);
- return provider.forget();
- }
-
- aRv.Throw(NS_ERROR_UNEXPECTED);
- MOZ_ASSERT(false, "Unknown request");
-
- return nullptr;
-}
-
-void
-HttpServer::SendWebSocketResponse(InternalRequest* aConnectRequest,
- InternalResponse* aResponse)
-{
- for (Connection* conn : mConnections) {
- if (conn->HasPendingWebSocketRequest(aConnectRequest)) {
- conn->HandleWebSocketResponse(aResponse);
- return;
- }
- }
-
- MOZ_ASSERT(false, "Unknown request");
-}
-
-void
-HttpServer::Close()
-{
- if (mServerSocket) {
- mServerSocket->Close();
- mServerSocket = nullptr;
- }
-
- if (mListener) {
- RefPtr<HttpServerListener> listener = mListener.forget();
- listener->OnServerClose();
- }
-
- for (Connection* conn : mConnections) {
- conn->Close();
- }
- mConnections.Clear();
-}
-
-void
-HttpServer::GetCertKey(nsACString& aKey)
-{
- nsAutoString tmp;
- if (mCert) {
- mCert->GetSha256Fingerprint(tmp);
- }
- LossyCopyUTF16toASCII(tmp, aKey);
-}
-
-NS_IMPL_ISUPPORTS(HttpServer::TransportProvider,
- nsITransportProvider)
-
-HttpServer::TransportProvider::~TransportProvider()
-{
-}
-
-NS_IMETHODIMP
-HttpServer::TransportProvider::SetListener(nsIHttpUpgradeListener* aListener)
-{
- MOZ_ASSERT(!mListener);
- MOZ_ASSERT(aListener);
-
- mListener = aListener;
-
- MaybeNotify();
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpServer::TransportProvider::GetIPCChild(PTransportProviderChild** aChild)
-{
- MOZ_CRASH("Don't call this in parent process");
- *aChild = nullptr;
- return NS_OK;
-}
-
-void
-HttpServer::TransportProvider::SetTransport(nsISocketTransport* aTransport,
- nsIAsyncInputStream* aInput,
- nsIAsyncOutputStream* aOutput)
-{
- MOZ_ASSERT(!mTransport);
- MOZ_ASSERT(aTransport && aInput && aOutput);
-
- mTransport = aTransport;
- mInput = aInput;
- mOutput = aOutput;
-
- MaybeNotify();
-}
-
-void
-HttpServer::TransportProvider::MaybeNotify()
-{
- if (mTransport && mListener) {
- RefPtr<TransportProvider> self = this;
- nsCOMPtr<nsIRunnable> event = NS_NewRunnableFunction([self, this] ()
- {
- mListener->OnTransportAvailable(mTransport, mInput, mOutput);
- });
- NS_DispatchToCurrentThread(event);
- }
-}
-
-NS_IMPL_ISUPPORTS(HttpServer::Connection,
- nsIInputStreamCallback,
- nsIOutputStreamCallback)
-
-HttpServer::Connection::Connection(nsISocketTransport* aTransport,
- HttpServer* aServer,
- nsresult& rv)
- : mServer(aServer)
- , mTransport(aTransport)
- , mState(eRequestLine)
- , mPendingReqVersion()
- , mRemainingBodySize()
- , mCloseAfterRequest(false)
-{
- nsCOMPtr<nsIInputStream> input;
- rv = mTransport->OpenInputStream(0, 0, 0, getter_AddRefs(input));
- NS_ENSURE_SUCCESS_VOID(rv);
-
- mInput = do_QueryInterface(input);
-
- nsCOMPtr<nsIOutputStream> output;
- rv = mTransport->OpenOutputStream(0, 0, 0, getter_AddRefs(output));
- NS_ENSURE_SUCCESS_VOID(rv);
-
- mOutput = do_QueryInterface(output);
-
- if (mServer->mHttps) {
- SetSecurityObserver(true);
- } else {
- mInput->AsyncWait(this, 0, 0, NS_GetCurrentThread());
- }
-}
-
-NS_IMETHODIMP
-HttpServer::Connection::OnHandshakeDone(nsITLSServerSocket* aServer,
- nsITLSClientStatus* aStatus)
-{
- LOG_I("HttpServer::Connection::OnHandshakeDone(%p)", this);
-
- // XXX Verify connection security
-
- SetSecurityObserver(false);
- mInput->AsyncWait(this, 0, 0, NS_GetCurrentThread());
-
- return NS_OK;
-}
-
-void
-HttpServer::Connection::SetSecurityObserver(bool aListen)
-{
- LOG_I("HttpServer::Connection::SetSecurityObserver(%p) - %s", this,
- aListen ? "On" : "Off");
-
- nsCOMPtr<nsISupports> secInfo;
- mTransport->GetSecurityInfo(getter_AddRefs(secInfo));
- nsCOMPtr<nsITLSServerConnectionInfo> tlsConnInfo =
- do_QueryInterface(secInfo);
- MOZ_ASSERT(tlsConnInfo);
- tlsConnInfo->SetSecurityObserver(aListen ? this : nullptr);
-}
-
-HttpServer::Connection::~Connection()
-{
-}
-
-NS_IMETHODIMP
-HttpServer::Connection::OnInputStreamReady(nsIAsyncInputStream* aStream)
-{
- MOZ_ASSERT(!mInput || aStream == mInput);
-
- LOG_I("HttpServer::Connection::OnInputStreamReady(%p)", this);
-
- if (!mInput || mState == ePause) {
- return NS_OK;
- }
-
- uint64_t avail;
- nsresult rv = mInput->Available(&avail);
- if (NS_FAILED(rv)) {
- LOG_I("HttpServer::Connection::OnInputStreamReady(%p) - Connection closed", this);
-
- mServer->mConnections.RemoveElement(this);
- // Connection closed. Handle errors here.
- return NS_OK;
- }
-
- uint32_t numRead;
- rv = mInput->ReadSegments(ReadSegmentsFunc,
- this,
- UINT32_MAX,
- &numRead);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = mInput->AsyncWait(this, 0, 0, NS_GetCurrentThread());
- NS_ENSURE_SUCCESS(rv, rv);
-
- return NS_OK;
-}
-
-nsresult
-HttpServer::Connection::ReadSegmentsFunc(nsIInputStream* aIn,
- void* aClosure,
- const char* aBuffer,
- uint32_t aToOffset,
- uint32_t aCount,
- uint32_t* aWriteCount)
-{
- const char* buffer = aBuffer;
- nsresult rv = static_cast<HttpServer::Connection*>(aClosure)->
- ConsumeInput(buffer, buffer + aCount);
-
- *aWriteCount = buffer - aBuffer;
- MOZ_ASSERT(*aWriteCount <= aCount);
-
- return rv;
-}
-
-static const char*
-findCRLF(const char* aBuffer, const char* aEnd)
-{
- if (aBuffer + 1 >= aEnd) {
- return nullptr;
- }
-
- const char* pos;
- while ((pos = static_cast<const char*>(memchr(aBuffer,
- '\r',
- aEnd - aBuffer - 1)))) {
- if (*(pos + 1) == '\n') {
- return pos;
- }
- aBuffer = pos + 1;
- }
- return nullptr;
-}
-
-nsresult
-HttpServer::Connection::ConsumeInput(const char*& aBuffer,
- const char* aEnd)
-{
- nsresult rv;
- while (mState == eRequestLine ||
- mState == eHeaders) {
- // Consume line-by-line
-
- // Check if buffer boundry ended up right between the CR and LF
- if (!mInputBuffer.IsEmpty() && mInputBuffer.Last() == '\r' &&
- *aBuffer == '\n') {
- aBuffer++;
- rv = ConsumeLine(mInputBuffer.BeginReading(), mInputBuffer.Length() - 1);
- NS_ENSURE_SUCCESS(rv, rv);
-
- mInputBuffer.Truncate();
- }
-
- // Look for a CRLF
- const char* pos = findCRLF(aBuffer, aEnd);
- if (!pos) {
- mInputBuffer.Append(aBuffer, aEnd - aBuffer);
- aBuffer = aEnd;
- return NS_OK;
- }
-
- if (!mInputBuffer.IsEmpty()) {
- mInputBuffer.Append(aBuffer, pos - aBuffer);
- aBuffer = pos + 2;
- rv = ConsumeLine(mInputBuffer.BeginReading(), mInputBuffer.Length() - 1);
- NS_ENSURE_SUCCESS(rv, rv);
-
- mInputBuffer.Truncate();
- } else {
- rv = ConsumeLine(aBuffer, pos - aBuffer);
- NS_ENSURE_SUCCESS(rv, rv);
-
- aBuffer = pos + 2;
- }
- }
-
- if (mState == eBody) {
- uint32_t size = std::min(mRemainingBodySize,
- static_cast<uint32_t>(aEnd - aBuffer));
- uint32_t written = size;
-
- if (mCurrentRequestBody) {
- rv = mCurrentRequestBody->Write(aBuffer, size, &written);
- // Since we've given the pipe unlimited size, we should never
- // end up needing to block.
- MOZ_ASSERT(rv != NS_BASE_STREAM_WOULD_BLOCK);
- if (NS_FAILED(rv)) {
- written = size;
- mCurrentRequestBody = nullptr;
- }
- }
-
- aBuffer += written;
- mRemainingBodySize -= written;
- if (!mRemainingBodySize) {
- mCurrentRequestBody->Close();
- mCurrentRequestBody = nullptr;
- mState = eRequestLine;
- }
- }
-
- return NS_OK;
-}
-
-bool
-ContainsToken(const nsCString& aList, const nsCString& aToken)
-{
- nsCCharSeparatedTokenizer tokens(aList, ',');
- bool found = false;
- while (!found && tokens.hasMoreTokens()) {
- found = tokens.nextToken().Equals(aToken);
- }
- return found;
-}
-
-static bool
-IsWebSocketRequest(InternalRequest* aRequest, uint32_t aHttpVersion)
-{
- if (aHttpVersion < 1) {
- return false;
- }
-
- nsAutoCString str;
- aRequest->GetMethod(str);
- if (!str.EqualsLiteral("GET")) {
- return false;
- }
-
- InternalHeaders* headers = aRequest->Headers();
- ErrorResult res;
-
- headers->GetFirst(NS_LITERAL_CSTRING("upgrade"), str, res);
- MOZ_ASSERT(!res.Failed());
- if (!str.EqualsLiteral("websocket")) {
- return false;
- }
-
- headers->GetFirst(NS_LITERAL_CSTRING("connection"), str, res);
- MOZ_ASSERT(!res.Failed());
- if (!ContainsToken(str, NS_LITERAL_CSTRING("Upgrade"))) {
- return false;
- }
-
- headers->GetFirst(NS_LITERAL_CSTRING("sec-websocket-key"), str, res);
- MOZ_ASSERT(!res.Failed());
- nsAutoCString binary;
- if (NS_FAILED(Base64Decode(str, binary)) || binary.Length() != 16) {
- return false;
- }
-
- nsresult rv;
- headers->GetFirst(NS_LITERAL_CSTRING("sec-websocket-version"), str, res);
- MOZ_ASSERT(!res.Failed());
- if (str.ToInteger(&rv) != 13 || NS_FAILED(rv)) {
- return false;
- }
-
- return true;
-}
-
-nsresult
-HttpServer::Connection::ConsumeLine(const char* aBuffer,
- size_t aLength)
-{
- MOZ_ASSERT(mState == eRequestLine ||
- mState == eHeaders);
-
- if (MOZ_LOG_TEST(gHttpServerLog, mozilla::LogLevel::Verbose)) {
- nsCString line(aBuffer, aLength);
- LOG_V("HttpServer::Connection::ConsumeLine(%p) - \"%s\"", this, line.get());
- }
-
- if (mState == eRequestLine) {
- LOG_V("HttpServer::Connection::ConsumeLine(%p) - Parsing request line", this);
- NS_ENSURE_FALSE(mCloseAfterRequest, NS_ERROR_UNEXPECTED);
-
- if (aLength == 0) {
- // Ignore empty lines before the request line
- return NS_OK;
- }
- MOZ_ASSERT(!mPendingReq);
-
- // Process request line
- nsCWhitespaceTokenizer tokens(Substring(aBuffer, aLength));
-
- NS_ENSURE_TRUE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED);
- nsDependentCSubstring method = tokens.nextToken();
- NS_ENSURE_TRUE(NS_IsValidHTTPToken(method), NS_ERROR_UNEXPECTED);
- NS_ENSURE_TRUE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED);
- nsDependentCSubstring url = tokens.nextToken();
- // Seems like it's also allowed to pass full urls with scheme+host+port.
- // May need to support that.
- NS_ENSURE_TRUE(url.First() == '/', NS_ERROR_UNEXPECTED);
- mPendingReq = new InternalRequest(url, /* aURLFragment */ EmptyCString());
- mPendingReq->SetMethod(method);
- NS_ENSURE_TRUE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED);
- nsDependentCSubstring version = tokens.nextToken();
- NS_ENSURE_TRUE(StringBeginsWith(version, NS_LITERAL_CSTRING("HTTP/1.")),
- NS_ERROR_UNEXPECTED);
- nsresult rv;
- // This integer parsing is likely not strict enough.
- nsCString reqVersion;
- reqVersion = Substring(version, MOZ_ARRAY_LENGTH("HTTP/1.") - 1);
- mPendingReqVersion = reqVersion.ToInteger(&rv);
- NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
-
- NS_ENSURE_FALSE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED);
-
- LOG_V("HttpServer::Connection::ConsumeLine(%p) - Parsed request line", this);
-
- mState = eHeaders;
-
- return NS_OK;
- }
-
- if (aLength == 0) {
- LOG_V("HttpServer::Connection::ConsumeLine(%p) - Found end of headers", this);
-
- MaybeAddPendingHeader();
-
- ErrorResult res;
- mPendingReq->Headers()->SetGuard(HeadersGuardEnum::Immutable, res);
-
- // Check for WebSocket
- if (IsWebSocketRequest(mPendingReq, mPendingReqVersion)) {
- LOG_V("HttpServer::Connection::ConsumeLine(%p) - Fire OnWebSocket", this);
-
- mState = ePause;
- mPendingWebSocketRequest = mPendingReq.forget();
- mPendingReqVersion = 0;
-
- RefPtr<HttpServerListener> listener = mServer->mListener;
- RefPtr<InternalRequest> request = mPendingWebSocketRequest;
- nsCOMPtr<nsIRunnable> event =
- NS_NewRunnableFunction([listener, request] ()
- {
- listener->OnWebSocket(request);
- });
- NS_DispatchToCurrentThread(event);
-
- return NS_OK;
- }
-
- nsAutoCString header;
- mPendingReq->Headers()->GetFirst(NS_LITERAL_CSTRING("connection"),
- header,
- res);
- MOZ_ASSERT(!res.Failed());
- // 1.0 defaults to closing connections.
- // 1.1 and higher defaults to keep-alive.
- if (ContainsToken(header, NS_LITERAL_CSTRING("close")) ||
- (mPendingReqVersion == 0 &&
- !ContainsToken(header, NS_LITERAL_CSTRING("keep-alive")))) {
- mCloseAfterRequest = true;
- }
-
- mPendingReq->Headers()->GetFirst(NS_LITERAL_CSTRING("content-length"),
- header,
- res);
- MOZ_ASSERT(!res.Failed());
-
- LOG_V("HttpServer::Connection::ConsumeLine(%p) - content-length is \"%s\"",
- this, header.get());
-
- if (!header.IsEmpty()) {
- nsresult rv;
- mRemainingBodySize = header.ToInteger(&rv);
- NS_ENSURE_SUCCESS(rv, rv);
- } else {
- mRemainingBodySize = 0;
- }
-
- if (mRemainingBodySize) {
- LOG_V("HttpServer::Connection::ConsumeLine(%p) - Starting consume body", this);
- mState = eBody;
-
- // We use an unlimited buffer size here to ensure
- // that we get to the next request even if the webpage hangs on
- // to the request indefinitely without consuming the body.
- nsCOMPtr<nsIInputStream> input;
- nsCOMPtr<nsIOutputStream> output;
- nsresult rv = NS_NewPipe(getter_AddRefs(input),
- getter_AddRefs(output),
- 0, // Segment size
- UINT32_MAX, // Unlimited buffer size
- false, // not nonBlockingInput
- true); // nonBlockingOutput
- NS_ENSURE_SUCCESS(rv, rv);
-
- mCurrentRequestBody = do_QueryInterface(output);
- mPendingReq->SetBody(input);
- } else {
- LOG_V("HttpServer::Connection::ConsumeLine(%p) - No body", this);
- mState = eRequestLine;
- }
-
- mPendingRequests.AppendElement(PendingRequest(mPendingReq, nullptr));
-
- LOG_V("HttpServer::Connection::ConsumeLine(%p) - Fire OnRequest", this);
-
- RefPtr<HttpServerListener> listener = mServer->mListener;
- RefPtr<InternalRequest> request = mPendingReq.forget();
- nsCOMPtr<nsIRunnable> event =
- NS_NewRunnableFunction([listener, request] ()
- {
- listener->OnRequest(request);
- });
- NS_DispatchToCurrentThread(event);
-
- mPendingReqVersion = 0;
-
- return NS_OK;
- }
-
- // Parse header line
- if (aBuffer[0] == ' ' || aBuffer[0] == '\t') {
- LOG_V("HttpServer::Connection::ConsumeLine(%p) - Add to header %s",
- this,
- mPendingHeaderName.get());
-
- NS_ENSURE_FALSE(mPendingHeaderName.IsEmpty(),
- NS_ERROR_UNEXPECTED);
-
- // We might need to do whitespace trimming/compression here.
- mPendingHeaderValue.Append(aBuffer, aLength);
- return NS_OK;
- }
-
- MaybeAddPendingHeader();
-
- const char* colon = static_cast<const char*>(memchr(aBuffer, ':', aLength));
- NS_ENSURE_TRUE(colon, NS_ERROR_UNEXPECTED);
-
- ToLowerCase(Substring(aBuffer, colon - aBuffer), mPendingHeaderName);
- mPendingHeaderValue.Assign(colon + 1, aLength - (colon - aBuffer) - 1);
-
- NS_ENSURE_TRUE(NS_IsValidHTTPToken(mPendingHeaderName),
- NS_ERROR_UNEXPECTED);
-
- LOG_V("HttpServer::Connection::ConsumeLine(%p) - Parsed header %s",
- this,
- mPendingHeaderName.get());
-
- return NS_OK;
-}
-
-void
-HttpServer::Connection::MaybeAddPendingHeader()
-{
- if (mPendingHeaderName.IsEmpty()) {
- return;
- }
-
- // We might need to do more whitespace trimming/compression here.
- mPendingHeaderValue.Trim(" \t");
-
- ErrorResult rv;
- mPendingReq->Headers()->Append(mPendingHeaderName, mPendingHeaderValue, rv);
- mPendingHeaderName.Truncate();
-}
-
-bool
-HttpServer::Connection::TryHandleResponse(InternalRequest* aRequest,
- InternalResponse* aResponse)
-{
- bool handledResponse = false;
- for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) {
- PendingRequest& pending = mPendingRequests[i];
- if (pending.first() == aRequest) {
- MOZ_ASSERT(!handledResponse);
- MOZ_ASSERT(!pending.second());
-
- pending.second() = aResponse;
- if (i != 0) {
- return true;
- }
- handledResponse = true;
- }
-
- if (handledResponse && !pending.second()) {
- // Shortcut if we've handled the response, and
- // we don't have more responses to send
- return true;
- }
-
- if (i == 0 && pending.second()) {
- RefPtr<InternalResponse> resp = pending.second().forget();
- mPendingRequests.RemoveElementAt(0);
- QueueResponse(resp);
- --i;
- }
- }
-
- return handledResponse;
-}
-
-already_AddRefed<nsITransportProvider>
-HttpServer::Connection::HandleAcceptWebSocket(const Optional<nsAString>& aProtocol,
- ErrorResult& aRv)
-{
- MOZ_ASSERT(mPendingWebSocketRequest);
-
- RefPtr<InternalResponse> response =
- new InternalResponse(101, NS_LITERAL_CSTRING("Switching Protocols"));
-
- InternalHeaders* headers = response->Headers();
- headers->Set(NS_LITERAL_CSTRING("Upgrade"),
- NS_LITERAL_CSTRING("websocket"),
- aRv);
- headers->Set(NS_LITERAL_CSTRING("Connection"),
- NS_LITERAL_CSTRING("Upgrade"),
- aRv);
- if (aProtocol.WasPassed()) {
- NS_ConvertUTF16toUTF8 protocol(aProtocol.Value());
- nsAutoCString reqProtocols;
- mPendingWebSocketRequest->Headers()->
- GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Protocol"), reqProtocols, aRv);
- if (!ContainsToken(reqProtocols, protocol)) {
- // Should throw a better error here
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
-
- headers->Set(NS_LITERAL_CSTRING("Sec-WebSocket-Protocol"),
- protocol, aRv);
- }
-
- nsAutoCString key, hash;
- mPendingWebSocketRequest->Headers()->
- GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Key"), key, aRv);
- nsresult rv = mozilla::net::CalculateWebSocketHashedSecret(key, hash);
- if (NS_FAILED(rv)) {
- aRv.Throw(rv);
- return nullptr;
- }
- headers->Set(NS_LITERAL_CSTRING("Sec-WebSocket-Accept"), hash, aRv);
-
- nsAutoCString extensions, negotiatedExtensions;
- mPendingWebSocketRequest->Headers()->
- GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Extensions"), extensions, aRv);
- mozilla::net::ProcessServerWebSocketExtensions(extensions,
- negotiatedExtensions);
- if (!negotiatedExtensions.IsEmpty()) {
- headers->Set(NS_LITERAL_CSTRING("Sec-WebSocket-Extensions"),
- negotiatedExtensions, aRv);
- }
-
- RefPtr<TransportProvider> result = new TransportProvider();
- mWebSocketTransportProvider = result;
-
- QueueResponse(response);
-
- return result.forget();
-}
-
-void
-HttpServer::Connection::HandleWebSocketResponse(InternalResponse* aResponse)
-{
- MOZ_ASSERT(mPendingWebSocketRequest);
-
- mState = eRequestLine;
- mPendingWebSocketRequest = nullptr;
- mInput->AsyncWait(this, 0, 0, NS_GetCurrentThread());
-
- QueueResponse(aResponse);
-}
-
-void
-HttpServer::Connection::QueueResponse(InternalResponse* aResponse)
-{
- bool chunked = false;
-
- RefPtr<InternalHeaders> headers = new InternalHeaders(*aResponse->Headers());
- {
- ErrorResult res;
- headers->SetGuard(HeadersGuardEnum::None, res);
- }
- nsCOMPtr<nsIInputStream> body;
- int64_t bodySize;
- aResponse->GetBody(getter_AddRefs(body), &bodySize);
-
- if (body && bodySize >= 0) {
- nsCString sizeStr;
- sizeStr.AppendInt(bodySize);
-
- LOG_V("HttpServer::Connection::QueueResponse(%p) - "
- "Setting content-length to %s",
- this, sizeStr.get());
-
- ErrorResult res;
- headers->Set(NS_LITERAL_CSTRING("content-length"), sizeStr, res);
- } else if (body) {
- // Use chunked transfer encoding
- LOG_V("HttpServer::Connection::QueueResponse(%p) - Chunked transfer-encoding",
- this);
-
- ErrorResult res;
- headers->Set(NS_LITERAL_CSTRING("transfer-encoding"),
- NS_LITERAL_CSTRING("chunked"),
- res);
- headers->Delete(NS_LITERAL_CSTRING("content-length"), res);
- chunked = true;
-
- } else {
- LOG_V("HttpServer::Connection::QueueResponse(%p) - "
- "No body - setting content-length to 0", this);
-
- ErrorResult res;
- headers->Set(NS_LITERAL_CSTRING("content-length"),
- NS_LITERAL_CSTRING("0"), res);
- }
-
- nsCString head(NS_LITERAL_CSTRING("HTTP/1.1 "));
- head.AppendInt(aResponse->GetStatus());
- // XXX is the statustext security checked?
- head.Append(NS_LITERAL_CSTRING(" ") +
- aResponse->GetStatusText() +
- NS_LITERAL_CSTRING("\r\n"));
-
- AutoTArray<InternalHeaders::Entry, 16> entries;
- headers->GetEntries(entries);
-
- for (auto header : entries) {
- head.Append(header.mName +
- NS_LITERAL_CSTRING(": ") +
- header.mValue +
- NS_LITERAL_CSTRING("\r\n"));
- }
-
- head.Append(NS_LITERAL_CSTRING("\r\n"));
-
- mOutputBuffers.AppendElement()->mString = head;
- if (body) {
- OutputBuffer* bodyBuffer = mOutputBuffers.AppendElement();
- bodyBuffer->mStream = body;
- bodyBuffer->mChunked = chunked;
- }
-
- OnOutputStreamReady(mOutput);
-}
-
-namespace {
-
-typedef MozPromise<nsresult, bool, false> StreamCopyPromise;
-
-class StreamCopier final : public nsIOutputStreamCallback
- , public nsIInputStreamCallback
- , public nsIRunnable
-{
-public:
- static RefPtr<StreamCopyPromise>
- Copy(nsIInputStream* aSource, nsIAsyncOutputStream* aSink,
- bool aChunked)
- {
- RefPtr<StreamCopier> copier = new StreamCopier(aSource, aSink, aChunked);
-
- RefPtr<StreamCopyPromise> p = copier->mPromise.Ensure(__func__);
-
- nsresult rv = copier->mTarget->Dispatch(copier, NS_DISPATCH_NORMAL);
- if (NS_FAILED(rv)) {
- copier->mPromise.Resolve(rv, __func__);
- }
-
- return p;
- }
-
- NS_DECL_THREADSAFE_ISUPPORTS
- NS_DECL_NSIINPUTSTREAMCALLBACK
- NS_DECL_NSIOUTPUTSTREAMCALLBACK
- NS_DECL_NSIRUNNABLE
-
-private:
- StreamCopier(nsIInputStream* aSource, nsIAsyncOutputStream* aSink,
- bool aChunked)
- : mSource(aSource)
- , mAsyncSource(do_QueryInterface(aSource))
- , mSink(aSink)
- , mTarget(do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID))
- , mChunkRemaining(0)
- , mChunked(aChunked)
- , mAddedFinalSeparator(false)
- , mFirstChunk(aChunked)
- {
- }
- ~StreamCopier() {}
-
- static nsresult FillOutputBufferHelper(nsIOutputStream* aOutStr,
- void* aClosure,
- char* aBuffer,
- uint32_t aOffset,
- uint32_t aCount,
- uint32_t* aCountRead);
- nsresult FillOutputBuffer(char* aBuffer,
- uint32_t aCount,
- uint32_t* aCountRead);
-
- nsCOMPtr<nsIInputStream> mSource;
- nsCOMPtr<nsIAsyncInputStream> mAsyncSource;
- nsCOMPtr<nsIAsyncOutputStream> mSink;
- MozPromiseHolder<StreamCopyPromise> mPromise;
- nsCOMPtr<nsIEventTarget> mTarget; // XXX we should cache this somewhere
- uint32_t mChunkRemaining;
- nsCString mSeparator;
- bool mChunked;
- bool mAddedFinalSeparator;
- bool mFirstChunk;
-};
-
-NS_IMPL_ISUPPORTS(StreamCopier,
- nsIOutputStreamCallback,
- nsIInputStreamCallback,
- nsIRunnable)
-
-struct WriteState
-{
- StreamCopier* copier;
- nsresult sourceRv;
-};
-
-// This function only exists to enable FillOutputBuffer to be a non-static
-// function where we can use member variables more easily.
-nsresult
-StreamCopier::FillOutputBufferHelper(nsIOutputStream* aOutStr,
- void* aClosure,
- char* aBuffer,
- uint32_t aOffset,
- uint32_t aCount,
- uint32_t* aCountRead)
-{
- WriteState* ws = static_cast<WriteState*>(aClosure);
- ws->sourceRv = ws->copier->FillOutputBuffer(aBuffer, aCount, aCountRead);
- return ws->sourceRv;
-}
-
-nsresult
-CheckForEOF(nsIInputStream* aIn,
- void* aClosure,
- const char* aBuffer,
- uint32_t aToOffset,
- uint32_t aCount,
- uint32_t* aWriteCount)
-{
- *static_cast<bool*>(aClosure) = true;
- *aWriteCount = 0;
- return NS_BINDING_ABORTED;
-}
-
-nsresult
-StreamCopier::FillOutputBuffer(char* aBuffer,
- uint32_t aCount,
- uint32_t* aCountRead)
-{
- nsresult rv = NS_OK;
- while (mChunked && mSeparator.IsEmpty() && !mChunkRemaining &&
- !mAddedFinalSeparator) {
- uint64_t avail;
- rv = mSource->Available(&avail);
- if (rv == NS_BASE_STREAM_CLOSED) {
- avail = 0;
- rv = NS_OK;
- }
- NS_ENSURE_SUCCESS(rv, rv);
-
- mChunkRemaining = avail > UINT32_MAX ? UINT32_MAX :
- static_cast<uint32_t>(avail);
-
- if (!mChunkRemaining) {
- // Either it's an non-blocking stream without any data
- // currently available, or we're at EOF. Sadly there's no way
- // to tell other than to read from the stream.
- bool hadData = false;
- uint32_t numRead;
- rv = mSource->ReadSegments(CheckForEOF, &hadData, 1, &numRead);
- if (rv == NS_BASE_STREAM_CLOSED) {
- avail = 0;
- rv = NS_OK;
- }
- NS_ENSURE_SUCCESS(rv, rv);
- MOZ_ASSERT(numRead == 0);
-
- if (hadData) {
- // The source received data between the call to Available and the
- // call to ReadSegments. Restart with a new call to Available
- continue;
- }
-
- // We're at EOF, write a separator with 0
- mAddedFinalSeparator = true;
- }
-
- if (mFirstChunk) {
- mFirstChunk = false;
- MOZ_ASSERT(mSeparator.IsEmpty());
- } else {
- // For all chunks except the first, add the newline at the end
- // of the previous chunk of data
- mSeparator.AssignLiteral("\r\n");
- }
- mSeparator.AppendInt(mChunkRemaining, 16);
- mSeparator.AppendLiteral("\r\n");
-
- if (mAddedFinalSeparator) {
- mSeparator.AppendLiteral("\r\n");
- }
-
- break;
- }
-
- // If we're doing chunked encoding, we should either have a chunk size,
- // or we should have reached the end of the input stream.
- MOZ_ASSERT_IF(mChunked, mChunkRemaining || mAddedFinalSeparator);
- // We should only have a separator if we're doing chunked encoding
- MOZ_ASSERT_IF(!mSeparator.IsEmpty(), mChunked);
-
- if (!mSeparator.IsEmpty()) {
- *aCountRead = std::min(mSeparator.Length(), aCount);
- memcpy(aBuffer, mSeparator.BeginReading(), *aCountRead);
- mSeparator.Cut(0, *aCountRead);
- rv = NS_OK;
- } else if (mChunked) {
- *aCountRead = 0;
- if (mChunkRemaining) {
- rv = mSource->Read(aBuffer,
- std::min(aCount, mChunkRemaining),
- aCountRead);
- mChunkRemaining -= *aCountRead;
- }
- } else {
- rv = mSource->Read(aBuffer, aCount, aCountRead);
- }
-
- if (NS_SUCCEEDED(rv) && *aCountRead == 0) {
- rv = NS_BASE_STREAM_CLOSED;
- }
-
- return rv;
-}
-
-NS_IMETHODIMP
-StreamCopier::Run()
-{
- nsresult rv;
- while (1) {
- WriteState state = { this, NS_OK };
- uint32_t written;
- rv = mSink->WriteSegments(FillOutputBufferHelper, &state,
- mozilla::net::nsIOService::gDefaultSegmentSize,
- &written);
- MOZ_ASSERT(NS_SUCCEEDED(rv) || NS_SUCCEEDED(state.sourceRv));
- if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
- mSink->AsyncWait(this, 0, 0, mTarget);
- return NS_OK;
- }
- if (NS_FAILED(rv)) {
- mPromise.Resolve(rv, __func__);
- return NS_OK;
- }
-
- if (state.sourceRv == NS_BASE_STREAM_WOULD_BLOCK) {
- MOZ_ASSERT(mAsyncSource);
- mAsyncSource->AsyncWait(this, 0, 0, mTarget);
- mSink->AsyncWait(this, nsIAsyncInputStream::WAIT_CLOSURE_ONLY,
- 0, mTarget);
-
- return NS_OK;
- }
- if (state.sourceRv == NS_BASE_STREAM_CLOSED) {
- // We're done!
- // No longer interested in callbacks about either stream closing
- mSink->AsyncWait(nullptr, 0, 0, nullptr);
- if (mAsyncSource) {
- mAsyncSource->AsyncWait(nullptr, 0, 0, nullptr);
- }
-
- mSource->Close();
- mSource = nullptr;
- mAsyncSource = nullptr;
- mSink = nullptr;
-
- mPromise.Resolve(NS_OK, __func__);
-
- return NS_OK;
- }
-
- if (NS_FAILED(state.sourceRv)) {
- mPromise.Resolve(state.sourceRv, __func__);
- return NS_OK;
- }
- }
-
- MOZ_ASSUME_UNREACHABLE_MARKER();
-}
-
-NS_IMETHODIMP
-StreamCopier::OnInputStreamReady(nsIAsyncInputStream* aStream)
-{
- MOZ_ASSERT(aStream == mAsyncSource ||
- (!mSource && !mAsyncSource && !mSink));
- return mSource ? Run() : NS_OK;
-}
-
-NS_IMETHODIMP
-StreamCopier::OnOutputStreamReady(nsIAsyncOutputStream* aStream)
-{
- MOZ_ASSERT(aStream == mSink ||
- (!mSource && !mAsyncSource && !mSink));
- return mSource ? Run() : NS_OK;
-}
-
-} // namespace
-
-NS_IMETHODIMP
-HttpServer::Connection::OnOutputStreamReady(nsIAsyncOutputStream* aStream)
-{
- MOZ_ASSERT(aStream == mOutput || !mOutput);
- if (!mOutput) {
- return NS_OK;
- }
-
- nsresult rv;
-
- while (!mOutputBuffers.IsEmpty()) {
- if (!mOutputBuffers[0].mStream) {
- nsCString& buffer = mOutputBuffers[0].mString;
- while (!buffer.IsEmpty()) {
- uint32_t written = 0;
- rv = mOutput->Write(buffer.BeginReading(),
- buffer.Length(),
- &written);
-
- buffer.Cut(0, written);
-
- if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
- return mOutput->AsyncWait(this, 0, 0, NS_GetCurrentThread());
- }
-
- if (NS_FAILED(rv)) {
- Close();
- return NS_OK;
- }
- }
- mOutputBuffers.RemoveElementAt(0);
- } else {
- if (mOutputCopy) {
- // we're already copying the stream
- return NS_OK;
- }
-
- mOutputCopy =
- StreamCopier::Copy(mOutputBuffers[0].mStream,
- mOutput,
- mOutputBuffers[0].mChunked);
-
- RefPtr<Connection> self = this;
-
- mOutputCopy->
- Then(AbstractThread::MainThread(),
- __func__,
- [self, this] (nsresult aStatus) {
- MOZ_ASSERT(mOutputBuffers[0].mStream);
- LOG_V("HttpServer::Connection::OnOutputStreamReady(%p) - "
- "Sent body. Status 0x%lx",
- this, aStatus);
-
- mOutputBuffers.RemoveElementAt(0);
- mOutputCopy = nullptr;
- OnOutputStreamReady(mOutput);
- },
- [] (bool) { MOZ_ASSERT_UNREACHABLE("Reject unexpected"); });
- }
- }
-
- if (mPendingRequests.IsEmpty()) {
- if (mCloseAfterRequest) {
- LOG_V("HttpServer::Connection::OnOutputStreamReady(%p) - Closing channel",
- this);
- Close();
- } else if (mWebSocketTransportProvider) {
- mInput->AsyncWait(nullptr, 0, 0, nullptr);
- mOutput->AsyncWait(nullptr, 0, 0, nullptr);
-
- mWebSocketTransportProvider->SetTransport(mTransport, mInput, mOutput);
- mTransport = nullptr;
- mInput = nullptr;
- mOutput = nullptr;
- mWebSocketTransportProvider = nullptr;
- }
- }
-
- return NS_OK;
-}
-
-void
-HttpServer::Connection::Close()
-{
- if (!mTransport) {
- MOZ_ASSERT(!mOutput && !mInput);
- return;
- }
-
- mTransport->Close(NS_BINDING_ABORTED);
- if (mInput) {
- mInput->Close();
- mInput = nullptr;
- }
- if (mOutput) {
- mOutput->Close();
- mOutput = nullptr;
- }
-
- mTransport = nullptr;
-
- mInputBuffer.Truncate();
- mOutputBuffers.Clear();
- mPendingRequests.Clear();
-}
-
-
-} // namespace net
-} // namespace mozilla
diff --git a/dom/flyweb/HttpServer.h b/dom/flyweb/HttpServer.h
deleted file mode 100644
index dab601c24..000000000
--- a/dom/flyweb/HttpServer.h
+++ /dev/null
@@ -1,193 +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_HttpServer_h
-#define mozilla_dom_HttpServer_h
-
-#include "nsISupportsImpl.h"
-#include "mozilla/DOMEventTargetHelper.h"
-#include "nsITLSServerSocket.h"
-#include "nsIAsyncInputStream.h"
-#include "nsIAsyncOutputStream.h"
-#include "mozilla/Variant.h"
-#include "nsIRequestObserver.h"
-#include "mozilla/MozPromise.h"
-#include "nsITransportProvider.h"
-#include "nsILocalCertService.h"
-
-class nsIX509Cert;
-
-namespace mozilla {
-namespace dom {
-
-extern bool
-ContainsToken(const nsCString& aList, const nsCString& aToken);
-
-class InternalRequest;
-class InternalResponse;
-
-class HttpServerListener
-{
-public:
- // switch to NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING when that lands
- NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
- NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
-
- virtual void OnServerStarted(nsresult aStatus) = 0;
- virtual void OnRequest(InternalRequest* aRequest) = 0;
- virtual void OnWebSocket(InternalRequest* aConnectRequest) = 0;
- virtual void OnServerClose() = 0;
-};
-
-class HttpServer final : public nsIServerSocketListener,
- public nsILocalCertGetCallback
-{
-public:
- HttpServer();
-
- NS_DECL_ISUPPORTS
- NS_DECL_NSISERVERSOCKETLISTENER
- NS_DECL_NSILOCALCERTGETCALLBACK
-
- void Init(int32_t aPort, bool aHttps, HttpServerListener* aListener);
-
- void SendResponse(InternalRequest* aRequest, InternalResponse* aResponse);
- already_AddRefed<nsITransportProvider>
- AcceptWebSocket(InternalRequest* aConnectRequest,
- const Optional<nsAString>& aProtocol,
- ErrorResult& aRv);
- void SendWebSocketResponse(InternalRequest* aConnectRequest,
- InternalResponse* aResponse);
-
- void Close();
-
- void GetCertKey(nsACString& aKey);
-
- int32_t GetPort()
- {
- return mPort;
- }
-
-private:
- ~HttpServer();
-
- nsresult StartServerSocket(nsIX509Cert* aCert);
- void NotifyStarted(nsresult aStatus);
-
- class TransportProvider final : public nsITransportProvider
- {
- public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSITRANSPORTPROVIDER
-
- void SetTransport(nsISocketTransport* aTransport,
- nsIAsyncInputStream* aInput,
- nsIAsyncOutputStream* aOutput);
-
- private:
- virtual ~TransportProvider();
- void MaybeNotify();
-
- nsCOMPtr<nsIHttpUpgradeListener> mListener;
- nsCOMPtr<nsISocketTransport> mTransport;
- nsCOMPtr<nsIAsyncInputStream> mInput;
- nsCOMPtr<nsIAsyncOutputStream> mOutput;
- };
-
- class Connection final : public nsIInputStreamCallback
- , public nsIOutputStreamCallback
- , public nsITLSServerSecurityObserver
- {
- public:
- Connection(nsISocketTransport* aTransport,
- HttpServer* aServer,
- nsresult& rv);
-
- NS_DECL_ISUPPORTS
- NS_DECL_NSIINPUTSTREAMCALLBACK
- NS_DECL_NSIOUTPUTSTREAMCALLBACK
- NS_DECL_NSITLSSERVERSECURITYOBSERVER
-
- bool TryHandleResponse(InternalRequest* aRequest,
- InternalResponse* aResponse);
- already_AddRefed<nsITransportProvider>
- HandleAcceptWebSocket(const Optional<nsAString>& aProtocol,
- ErrorResult& aRv);
- void HandleWebSocketResponse(InternalResponse* aResponse);
- bool HasPendingWebSocketRequest(InternalRequest* aRequest)
- {
- return aRequest == mPendingWebSocketRequest;
- }
-
- void Close();
-
- private:
- ~Connection();
-
- void SetSecurityObserver(bool aListen);
-
- static nsresult ReadSegmentsFunc(nsIInputStream* aIn,
- void* aClosure,
- const char* aBuffer,
- uint32_t aToOffset,
- uint32_t aCount,
- uint32_t* aWriteCount);
- nsresult ConsumeInput(const char*& aBuffer,
- const char* aEnd);
- nsresult ConsumeLine(const char* aBuffer,
- size_t aLength);
- void MaybeAddPendingHeader();
-
- void QueueResponse(InternalResponse* aResponse);
-
- RefPtr<HttpServer> mServer;
- nsCOMPtr<nsISocketTransport> mTransport;
- nsCOMPtr<nsIAsyncInputStream> mInput;
- nsCOMPtr<nsIAsyncOutputStream> mOutput;
-
- enum { eRequestLine, eHeaders, eBody, ePause } mState;
- RefPtr<InternalRequest> mPendingReq;
- uint32_t mPendingReqVersion;
- nsCString mInputBuffer;
- nsCString mPendingHeaderName;
- nsCString mPendingHeaderValue;
- uint32_t mRemainingBodySize;
- nsCOMPtr<nsIAsyncOutputStream> mCurrentRequestBody;
- bool mCloseAfterRequest;
-
- typedef Pair<RefPtr<InternalRequest>,
- RefPtr<InternalResponse>> PendingRequest;
- nsTArray<PendingRequest> mPendingRequests;
- RefPtr<MozPromise<nsresult, bool, false>> mOutputCopy;
-
- RefPtr<InternalRequest> mPendingWebSocketRequest;
- RefPtr<TransportProvider> mWebSocketTransportProvider;
-
- struct OutputBuffer {
- nsCString mString;
- nsCOMPtr<nsIInputStream> mStream;
- bool mChunked;
- };
-
- nsTArray<OutputBuffer> mOutputBuffers;
- };
-
- friend class Connection;
-
- RefPtr<HttpServerListener> mListener;
- nsCOMPtr<nsIServerSocket> mServerSocket;
- nsCOMPtr<nsIX509Cert> mCert;
-
- nsTArray<RefPtr<Connection>> mConnections;
-
- int32_t mPort;
- bool mHttps;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_HttpServer_h
diff --git a/dom/flyweb/PFlyWebPublishedServer.ipdl b/dom/flyweb/PFlyWebPublishedServer.ipdl
deleted file mode 100644
index 4d08a47fc..000000000
--- a/dom/flyweb/PFlyWebPublishedServer.ipdl
+++ /dev/null
@@ -1,38 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=8 et 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 PContent;
-include protocol PSendStream;
-include protocol PFileDescriptorSet;
-include protocol PTransportProvider;
-include FetchTypes;
-include ChannelInfo;
-include PBackgroundSharedTypes;
-
-namespace mozilla {
-namespace dom {
-
-async protocol PFlyWebPublishedServer
-{
- manager PContent;
-
-child:
- async ServerReady(nsresult aStatus);
- async FetchRequest(IPCInternalRequest aRequest, uint64_t aRequestId);
- async WebSocketRequest(IPCInternalRequest aRequest, uint64_t aRequestId,
- PTransportProvider aProvider);
- async ServerClose();
-
-parent:
- async __delete__();
-
- async FetchResponse(IPCInternalResponse aResponse, uint64_t aRequestId);
- async WebSocketResponse(IPCInternalResponse aResponse, uint64_t aRequestId);
- async WebSocketAccept(nsString aProtocol, uint64_t aRequestId);
-};
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/flyweb/moz.build b/dom/flyweb/moz.build
deleted file mode 100644
index aa8c034b7..000000000
--- a/dom/flyweb/moz.build
+++ /dev/null
@@ -1,42 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-EXPORTS.mozilla.dom += [
- 'FlyWebDiscoveryManager.h',
- 'FlyWebPublishedServer.h',
- 'FlyWebPublishedServerIPC.h',
- 'FlyWebPublishOptionsIPCSerializer.h',
- 'FlyWebServerEvents.h',
- 'FlyWebService.h',
- 'HttpServer.h',
-]
-
-UNIFIED_SOURCES += [
- 'FlyWebDiscoveryManager.cpp',
- 'FlyWebPublishedServer.cpp',
- 'FlyWebServerEvents.cpp',
- 'FlyWebService.cpp',
- 'HttpServer.cpp'
-]
-
-IPDL_SOURCES += [
- 'PFlyWebPublishedServer.ipdl',
-]
-
-FINAL_LIBRARY = 'xul'
-
-LOCAL_INCLUDES += [
- '/dom/base',
- '/netwerk/base',
- '/netwerk/dns',
- '/netwerk/protocol/websocket',
- '/xpcom/io'
-]
-
-include('/ipc/chromium/chromium-config.mozbuild')
-
-if CONFIG['GNU_CXX']:
- CXXFLAGS += ['-Wshadow']
diff --git a/dom/heapsnapshot/.gitattributes b/dom/heapsnapshot/.gitattributes
new file mode 100644
index 000000000..44e248a8d
--- /dev/null
+++ b/dom/heapsnapshot/.gitattributes
@@ -0,0 +1 @@
+CoreDump.pb.* binary
diff --git a/dom/heapsnapshot/AutoMemMap.cpp b/dom/heapsnapshot/AutoMemMap.cpp
new file mode 100644
index 000000000..e725a99c6
--- /dev/null
+++ b/dom/heapsnapshot/AutoMemMap.cpp
@@ -0,0 +1,64 @@
+/* -*- 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/devtools/AutoMemMap.h"
+
+#include "mozilla/Unused.h"
+#include "nsDebug.h"
+
+namespace mozilla {
+namespace devtools {
+
+AutoMemMap::~AutoMemMap()
+{
+ if (addr) {
+ Unused << NS_WARN_IF(PR_MemUnmap(addr, size()) != PR_SUCCESS);
+ addr = nullptr;
+ }
+
+ if (fileMap) {
+ Unused << NS_WARN_IF(PR_CloseFileMap(fileMap) != PR_SUCCESS);
+ fileMap = nullptr;
+ }
+
+ if (fd) {
+ Unused << NS_WARN_IF(PR_Close(fd) != PR_SUCCESS);
+ fd = nullptr;
+ }
+}
+
+nsresult
+AutoMemMap::init(const char* filePath, int flags, int mode, PRFileMapProtect prot)
+{
+ MOZ_ASSERT(!fd);
+ MOZ_ASSERT(!fileMap);
+ MOZ_ASSERT(!addr);
+
+ if (PR_GetFileInfo64(filePath, &fileInfo) != PR_SUCCESS)
+ return NS_ERROR_FILE_NOT_FOUND;
+
+ // Check if the file is too big to memmap.
+ if (fileInfo.size > int64_t(UINT32_MAX))
+ return NS_ERROR_INVALID_ARG;
+ auto length = uint32_t(fileInfo.size);
+
+ fd = PR_Open(filePath, flags, flags);
+ if (!fd)
+ return NS_ERROR_UNEXPECTED;
+
+ fileMap = PR_CreateFileMap(fd, fileInfo.size, prot);
+ if (!fileMap)
+ return NS_ERROR_UNEXPECTED;
+
+ addr = PR_MemMap(fileMap, 0, length);
+ if (!addr)
+ return NS_ERROR_UNEXPECTED;
+
+ return NS_OK;
+}
+
+} // namespace devtools
+} // namespace mozilla
diff --git a/dom/heapsnapshot/AutoMemMap.h b/dom/heapsnapshot/AutoMemMap.h
new file mode 100644
index 000000000..537d68004
--- /dev/null
+++ b/dom/heapsnapshot/AutoMemMap.h
@@ -0,0 +1,75 @@
+/* -*- 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_devtools_AutoMemMap_h
+#define mozilla_devtools_AutoMemMap_h
+
+#include <prio.h>
+#include "mozilla/GuardObjects.h"
+
+namespace mozilla {
+namespace devtools {
+
+// # AutoMemMap
+//
+// AutoMemMap is an RAII class to manage mapping a file to memory. It is a
+// wrapper aorund managing opening and closing a file and calling PR_MemMap and
+// PR_MemUnmap.
+//
+// Example usage:
+//
+// {
+// AutoMemMap mm;
+// if (NS_FAILED(mm.init("/path/to/desired/file"))) {
+// // Handle the error however you see fit.
+// return false;
+// }
+//
+// doStuffWithMappedMemory(mm.address());
+// }
+// // The memory is automatically unmapped when the AutoMemMap leaves scope.
+class MOZ_RAII AutoMemMap
+{
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
+
+ PRFileInfo64 fileInfo;
+ PRFileDesc* fd;
+ PRFileMap* fileMap;
+ void* addr;
+
+ AutoMemMap(const AutoMemMap& aOther) = delete;
+ void operator=(const AutoMemMap& aOther) = delete;
+
+public:
+ explicit AutoMemMap(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
+ : fd(nullptr)
+ , fileMap(nullptr)
+ , addr(nullptr)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ };
+ ~AutoMemMap();
+
+ // Initialize this AutoMemMap.
+ nsresult init(const char* filePath, int flags = PR_RDONLY, int mode = 0,
+ PRFileMapProtect prot = PR_PROT_READONLY);
+
+ // Get the size of the memory mapped file.
+ uint32_t size() const {
+ MOZ_ASSERT(fileInfo.size <= UINT32_MAX,
+ "Should only call size() if init() succeeded.");
+ return uint32_t(fileInfo.size);
+ }
+
+ // Get the mapped memory.
+ void* address() { MOZ_ASSERT(addr); return addr; }
+ const void* address() const { MOZ_ASSERT(addr); return addr; }
+};
+
+} // namespace devtools
+} // namespace mozilla
+
+#endif // mozilla_devtools_AutoMemMap_h
diff --git a/dom/heapsnapshot/CoreDump.pb.cc b/dom/heapsnapshot/CoreDump.pb.cc
new file mode 100644
index 000000000..6c7c0e8a4
--- /dev/null
+++ b/dom/heapsnapshot/CoreDump.pb.cc
@@ -0,0 +1,2542 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: CoreDump.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "CoreDump.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace mozilla {
+namespace devtools {
+namespace protobuf {
+
+namespace {
+
+const ::google::protobuf::Descriptor* Metadata_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ Metadata_reflection_ = NULL;
+const ::google::protobuf::Descriptor* StackFrame_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ StackFrame_reflection_ = NULL;
+struct StackFrameOneofInstance {
+ const ::mozilla::devtools::protobuf::StackFrame_Data* data_;
+ ::google::protobuf::uint64 ref_;
+}* StackFrame_default_oneof_instance_ = NULL;
+const ::google::protobuf::Descriptor* StackFrame_Data_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ StackFrame_Data_reflection_ = NULL;
+struct StackFrame_DataOneofInstance {
+ const ::std::string* source_;
+ ::google::protobuf::uint64 sourceref_;
+ const ::std::string* functiondisplayname_;
+ ::google::protobuf::uint64 functiondisplaynameref_;
+}* StackFrame_Data_default_oneof_instance_ = NULL;
+const ::google::protobuf::Descriptor* Node_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ Node_reflection_ = NULL;
+struct NodeOneofInstance {
+ const ::std::string* typename__;
+ ::google::protobuf::uint64 typenameref_;
+ const ::std::string* jsobjectclassname_;
+ ::google::protobuf::uint64 jsobjectclassnameref_;
+ const ::std::string* scriptfilename_;
+ ::google::protobuf::uint64 scriptfilenameref_;
+}* Node_default_oneof_instance_ = NULL;
+const ::google::protobuf::Descriptor* Edge_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ Edge_reflection_ = NULL;
+struct EdgeOneofInstance {
+ const ::std::string* name_;
+ ::google::protobuf::uint64 nameref_;
+}* Edge_default_oneof_instance_ = NULL;
+
+} // namespace
+
+
+void protobuf_AssignDesc_CoreDump_2eproto() {
+ protobuf_AddDesc_CoreDump_2eproto();
+ const ::google::protobuf::FileDescriptor* file =
+ ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+ "CoreDump.proto");
+ GOOGLE_CHECK(file != NULL);
+ Metadata_descriptor_ = file->message_type(0);
+ static const int Metadata_offsets_[1] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Metadata, timestamp_),
+ };
+ Metadata_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ Metadata_descriptor_,
+ Metadata::default_instance_,
+ Metadata_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Metadata, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Metadata, _unknown_fields_),
+ -1,
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(Metadata));
+ StackFrame_descriptor_ = file->message_type(1);
+ static const int StackFrame_offsets_[3] = {
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_default_oneof_instance_, data_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_default_oneof_instance_, ref_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame, StackFrameType_),
+ };
+ StackFrame_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ StackFrame_descriptor_,
+ StackFrame::default_instance_,
+ StackFrame_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame, _unknown_fields_),
+ -1,
+ StackFrame_default_oneof_instance_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame, _oneof_case_[0]),
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(StackFrame));
+ StackFrame_Data_descriptor_ = StackFrame_descriptor_->nested_type(0);
+ static const int StackFrame_Data_offsets_[12] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, id_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, parent_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, line_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, column_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_Data_default_oneof_instance_, source_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_Data_default_oneof_instance_, sourceref_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_Data_default_oneof_instance_, functiondisplayname_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_Data_default_oneof_instance_, functiondisplaynameref_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, issystem_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, isselfhosted_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, SourceOrRef_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, FunctionDisplayNameOrRef_),
+ };
+ StackFrame_Data_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ StackFrame_Data_descriptor_,
+ StackFrame_Data::default_instance_,
+ StackFrame_Data_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, _unknown_fields_),
+ -1,
+ StackFrame_Data_default_oneof_instance_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, _oneof_case_[0]),
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(StackFrame_Data));
+ Node_descriptor_ = file->message_type(2);
+ static const int Node_offsets_[14] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, id_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, typename__),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, typenameref_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, size_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, edges_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, allocationstack_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, jsobjectclassname_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, jsobjectclassnameref_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, coarsetype_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, scriptfilename_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, scriptfilenameref_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, TypeNameOrRef_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, JSObjectClassNameOrRef_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, ScriptFilenameOrRef_),
+ };
+ Node_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ Node_descriptor_,
+ Node::default_instance_,
+ Node_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, _unknown_fields_),
+ -1,
+ Node_default_oneof_instance_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, _oneof_case_[0]),
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(Node));
+ Edge_descriptor_ = file->message_type(3);
+ static const int Edge_offsets_[4] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, referent_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Edge_default_oneof_instance_, name_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Edge_default_oneof_instance_, nameref_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, EdgeNameOrRef_),
+ };
+ Edge_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ Edge_descriptor_,
+ Edge::default_instance_,
+ Edge_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, _unknown_fields_),
+ -1,
+ Edge_default_oneof_instance_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, _oneof_case_[0]),
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(Edge));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+ ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+ &protobuf_AssignDesc_CoreDump_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ Metadata_descriptor_, &Metadata::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ StackFrame_descriptor_, &StackFrame::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ StackFrame_Data_descriptor_, &StackFrame_Data::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ Node_descriptor_, &Node::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ Edge_descriptor_, &Edge::default_instance());
+}
+
+} // namespace
+
+void protobuf_ShutdownFile_CoreDump_2eproto() {
+ delete Metadata::default_instance_;
+ delete Metadata_reflection_;
+ delete StackFrame::default_instance_;
+ delete StackFrame_default_oneof_instance_;
+ delete StackFrame_reflection_;
+ delete StackFrame_Data::default_instance_;
+ delete StackFrame_Data_default_oneof_instance_;
+ delete StackFrame_Data_reflection_;
+ delete Node::default_instance_;
+ delete Node_default_oneof_instance_;
+ delete Node_reflection_;
+ delete Edge::default_instance_;
+ delete Edge_default_oneof_instance_;
+ delete Edge_reflection_;
+}
+
+void protobuf_AddDesc_CoreDump_2eproto() {
+ static bool already_here = false;
+ if (already_here) return;
+ already_here = true;
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+ "\n\016CoreDump.proto\022\031mozilla.devtools.proto"
+ "buf\"\035\n\010Metadata\022\021\n\ttimeStamp\030\001 \001(\004\"\216\003\n\nS"
+ "tackFrame\022:\n\004data\030\001 \001(\0132*.mozilla.devtoo"
+ "ls.protobuf.StackFrame.DataH\000\022\r\n\003ref\030\002 \001"
+ "(\004H\000\032\242\002\n\004Data\022\n\n\002id\030\001 \001(\004\0225\n\006parent\030\002 \001("
+ "\0132%.mozilla.devtools.protobuf.StackFrame"
+ "\022\014\n\004line\030\003 \001(\r\022\016\n\006column\030\004 \001(\r\022\020\n\006source"
+ "\030\005 \001(\014H\000\022\023\n\tsourceRef\030\006 \001(\004H\000\022\035\n\023functio"
+ "nDisplayName\030\007 \001(\014H\001\022 \n\026functionDisplayN"
+ "ameRef\030\010 \001(\004H\001\022\020\n\010isSystem\030\t \001(\010\022\024\n\014isSe"
+ "lfHosted\030\n \001(\010B\r\n\013SourceOrRefB\032\n\030Functio"
+ "nDisplayNameOrRefB\020\n\016StackFrameType\"\210\003\n\004"
+ "Node\022\n\n\002id\030\001 \001(\004\022\022\n\010typeName\030\002 \001(\014H\000\022\025\n\013"
+ "typeNameRef\030\003 \001(\004H\000\022\014\n\004size\030\004 \001(\004\022.\n\005edg"
+ "es\030\005 \003(\0132\037.mozilla.devtools.protobuf.Edg"
+ "e\022>\n\017allocationStack\030\006 \001(\0132%.mozilla.dev"
+ "tools.protobuf.StackFrame\022\033\n\021jsObjectCla"
+ "ssName\030\007 \001(\014H\001\022\036\n\024jsObjectClassNameRef\030\010"
+ " \001(\004H\001\022\025\n\ncoarseType\030\t \001(\r:\0010\022\030\n\016scriptF"
+ "ilename\030\n \001(\014H\002\022\033\n\021scriptFilenameRef\030\013 \001"
+ "(\004H\002B\017\n\rTypeNameOrRefB\030\n\026JSObjectClassNa"
+ "meOrRefB\025\n\023ScriptFilenameOrRef\"L\n\004Edge\022\020"
+ "\n\010referent\030\001 \001(\004\022\016\n\004name\030\002 \001(\014H\000\022\021\n\007name"
+ "Ref\030\003 \001(\004H\000B\017\n\rEdgeNameOrRef", 948);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+ "CoreDump.proto", &protobuf_RegisterTypes);
+ Metadata::default_instance_ = new Metadata();
+ StackFrame::default_instance_ = new StackFrame();
+ StackFrame_default_oneof_instance_ = new StackFrameOneofInstance;
+ StackFrame_Data::default_instance_ = new StackFrame_Data();
+ StackFrame_Data_default_oneof_instance_ = new StackFrame_DataOneofInstance;
+ Node::default_instance_ = new Node();
+ Node_default_oneof_instance_ = new NodeOneofInstance;
+ Edge::default_instance_ = new Edge();
+ Edge_default_oneof_instance_ = new EdgeOneofInstance;
+ Metadata::default_instance_->InitAsDefaultInstance();
+ StackFrame::default_instance_->InitAsDefaultInstance();
+ StackFrame_Data::default_instance_->InitAsDefaultInstance();
+ Node::default_instance_->InitAsDefaultInstance();
+ Edge::default_instance_->InitAsDefaultInstance();
+ ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_CoreDump_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_CoreDump_2eproto {
+ StaticDescriptorInitializer_CoreDump_2eproto() {
+ protobuf_AddDesc_CoreDump_2eproto();
+ }
+} static_descriptor_initializer_CoreDump_2eproto_;
+
+// ===================================================================
+
+#ifndef _MSC_VER
+const int Metadata::kTimeStampFieldNumber;
+#endif // !_MSC_VER
+
+Metadata::Metadata()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.Metadata)
+}
+
+void Metadata::InitAsDefaultInstance() {
+}
+
+Metadata::Metadata(const Metadata& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:mozilla.devtools.protobuf.Metadata)
+}
+
+void Metadata::SharedCtor() {
+ _cached_size_ = 0;
+ timestamp_ = GOOGLE_ULONGLONG(0);
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Metadata::~Metadata() {
+ // @@protoc_insertion_point(destructor:mozilla.devtools.protobuf.Metadata)
+ SharedDtor();
+}
+
+void Metadata::SharedDtor() {
+ if (this != default_instance_) {
+ }
+}
+
+void Metadata::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Metadata::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Metadata_descriptor_;
+}
+
+const Metadata& Metadata::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_CoreDump_2eproto();
+ return *default_instance_;
+}
+
+Metadata* Metadata::default_instance_ = NULL;
+
+Metadata* Metadata::New() const {
+ return new Metadata;
+}
+
+void Metadata::Clear() {
+ timestamp_ = GOOGLE_ULONGLONG(0);
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool Metadata::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.Metadata)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional uint64 timeStamp = 1;
+ case 1: {
+ if (tag == 8) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+ input, &timestamp_)));
+ set_has_timestamp();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.Metadata)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:mozilla.devtools.protobuf.Metadata)
+ return false;
+#undef DO_
+}
+
+void Metadata::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:mozilla.devtools.protobuf.Metadata)
+ // optional uint64 timeStamp = 1;
+ if (has_timestamp()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->timestamp(), output);
+ }
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+ // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.Metadata)
+}
+
+::google::protobuf::uint8* Metadata::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.Metadata)
+ // optional uint64 timeStamp = 1;
+ if (has_timestamp()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->timestamp(), target);
+ }
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.Metadata)
+ return target;
+}
+
+int Metadata::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional uint64 timeStamp = 1;
+ if (has_timestamp()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt64Size(
+ this->timestamp());
+ }
+
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Metadata::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const Metadata* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const Metadata*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void Metadata::MergeFrom(const Metadata& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_timestamp()) {
+ set_timestamp(from.timestamp());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void Metadata::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void Metadata::CopyFrom(const Metadata& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Metadata::IsInitialized() const {
+
+ return true;
+}
+
+void Metadata::Swap(Metadata* other) {
+ if (other != this) {
+ std::swap(timestamp_, other->timestamp_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata Metadata::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = Metadata_descriptor_;
+ metadata.reflection = Metadata_reflection_;
+ return metadata;
+}
+
+
+// ===================================================================
+
+#ifndef _MSC_VER
+const int StackFrame_Data::kIdFieldNumber;
+const int StackFrame_Data::kParentFieldNumber;
+const int StackFrame_Data::kLineFieldNumber;
+const int StackFrame_Data::kColumnFieldNumber;
+const int StackFrame_Data::kSourceFieldNumber;
+const int StackFrame_Data::kSourceRefFieldNumber;
+const int StackFrame_Data::kFunctionDisplayNameFieldNumber;
+const int StackFrame_Data::kFunctionDisplayNameRefFieldNumber;
+const int StackFrame_Data::kIsSystemFieldNumber;
+const int StackFrame_Data::kIsSelfHostedFieldNumber;
+#endif // !_MSC_VER
+
+StackFrame_Data::StackFrame_Data()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.StackFrame.Data)
+}
+
+void StackFrame_Data::InitAsDefaultInstance() {
+ parent_ = const_cast< ::mozilla::devtools::protobuf::StackFrame*>(&::mozilla::devtools::protobuf::StackFrame::default_instance());
+ StackFrame_Data_default_oneof_instance_->source_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited();
+ StackFrame_Data_default_oneof_instance_->sourceref_ = GOOGLE_ULONGLONG(0);
+ StackFrame_Data_default_oneof_instance_->functiondisplayname_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited();
+ StackFrame_Data_default_oneof_instance_->functiondisplaynameref_ = GOOGLE_ULONGLONG(0);
+}
+
+StackFrame_Data::StackFrame_Data(const StackFrame_Data& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:mozilla.devtools.protobuf.StackFrame.Data)
+}
+
+void StackFrame_Data::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
+ _cached_size_ = 0;
+ id_ = GOOGLE_ULONGLONG(0);
+ parent_ = NULL;
+ line_ = 0u;
+ column_ = 0u;
+ issystem_ = false;
+ isselfhosted_ = false;
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ clear_has_SourceOrRef();
+ clear_has_FunctionDisplayNameOrRef();
+}
+
+StackFrame_Data::~StackFrame_Data() {
+ // @@protoc_insertion_point(destructor:mozilla.devtools.protobuf.StackFrame.Data)
+ SharedDtor();
+}
+
+void StackFrame_Data::SharedDtor() {
+ if (has_SourceOrRef()) {
+ clear_SourceOrRef();
+ }
+ if (has_FunctionDisplayNameOrRef()) {
+ clear_FunctionDisplayNameOrRef();
+ }
+ if (this != default_instance_) {
+ delete parent_;
+ }
+}
+
+void StackFrame_Data::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* StackFrame_Data::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return StackFrame_Data_descriptor_;
+}
+
+const StackFrame_Data& StackFrame_Data::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_CoreDump_2eproto();
+ return *default_instance_;
+}
+
+StackFrame_Data* StackFrame_Data::default_instance_ = NULL;
+
+StackFrame_Data* StackFrame_Data::New() const {
+ return new StackFrame_Data;
+}
+
+void StackFrame_Data::clear_SourceOrRef() {
+ switch(SourceOrRef_case()) {
+ case kSource: {
+ delete SourceOrRef_.source_;
+ break;
+ }
+ case kSourceRef: {
+ // No need to clear
+ break;
+ }
+ case SOURCEORREF_NOT_SET: {
+ break;
+ }
+ }
+ _oneof_case_[0] = SOURCEORREF_NOT_SET;
+}
+
+void StackFrame_Data::clear_FunctionDisplayNameOrRef() {
+ switch(FunctionDisplayNameOrRef_case()) {
+ case kFunctionDisplayName: {
+ delete FunctionDisplayNameOrRef_.functiondisplayname_;
+ break;
+ }
+ case kFunctionDisplayNameRef: {
+ // No need to clear
+ break;
+ }
+ case FUNCTIONDISPLAYNAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ _oneof_case_[1] = FUNCTIONDISPLAYNAMEORREF_NOT_SET;
+}
+
+
+void StackFrame_Data::Clear() {
+#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>( \
+ &reinterpret_cast<StackFrame_Data*>(16)->f) - \
+ reinterpret_cast<char*>(16))
+
+#define ZR_(first, last) do { \
+ size_t f = OFFSET_OF_FIELD_(first); \
+ size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last); \
+ ::memset(&first, 0, n); \
+ } while (0)
+
+ if (_has_bits_[0 / 32] & 15) {
+ ZR_(line_, column_);
+ id_ = GOOGLE_ULONGLONG(0);
+ if (has_parent()) {
+ if (parent_ != NULL) parent_->::mozilla::devtools::protobuf::StackFrame::Clear();
+ }
+ }
+ ZR_(issystem_, isselfhosted_);
+
+#undef OFFSET_OF_FIELD_
+#undef ZR_
+
+ clear_SourceOrRef();
+ clear_FunctionDisplayNameOrRef();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool StackFrame_Data::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.StackFrame.Data)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional uint64 id = 1;
+ case 1: {
+ if (tag == 8) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+ input, &id_)));
+ set_has_id();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(18)) goto parse_parent;
+ break;
+ }
+
+ // optional .mozilla.devtools.protobuf.StackFrame parent = 2;
+ case 2: {
+ if (tag == 18) {
+ parse_parent:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_parent()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(24)) goto parse_line;
+ break;
+ }
+
+ // optional uint32 line = 3;
+ case 3: {
+ if (tag == 24) {
+ parse_line:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+ input, &line_)));
+ set_has_line();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(32)) goto parse_column;
+ break;
+ }
+
+ // optional uint32 column = 4;
+ case 4: {
+ if (tag == 32) {
+ parse_column:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+ input, &column_)));
+ set_has_column();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(42)) goto parse_source;
+ break;
+ }
+
+ // optional bytes source = 5;
+ case 5: {
+ if (tag == 42) {
+ parse_source:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+ input, this->mutable_source()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(48)) goto parse_sourceRef;
+ break;
+ }
+
+ // optional uint64 sourceRef = 6;
+ case 6: {
+ if (tag == 48) {
+ parse_sourceRef:
+ clear_SourceOrRef();
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+ input, &SourceOrRef_.sourceref_)));
+ set_has_sourceref();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(58)) goto parse_functionDisplayName;
+ break;
+ }
+
+ // optional bytes functionDisplayName = 7;
+ case 7: {
+ if (tag == 58) {
+ parse_functionDisplayName:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+ input, this->mutable_functiondisplayname()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(64)) goto parse_functionDisplayNameRef;
+ break;
+ }
+
+ // optional uint64 functionDisplayNameRef = 8;
+ case 8: {
+ if (tag == 64) {
+ parse_functionDisplayNameRef:
+ clear_FunctionDisplayNameOrRef();
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+ input, &FunctionDisplayNameOrRef_.functiondisplaynameref_)));
+ set_has_functiondisplaynameref();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(72)) goto parse_isSystem;
+ break;
+ }
+
+ // optional bool isSystem = 9;
+ case 9: {
+ if (tag == 72) {
+ parse_isSystem:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &issystem_)));
+ set_has_issystem();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(80)) goto parse_isSelfHosted;
+ break;
+ }
+
+ // optional bool isSelfHosted = 10;
+ case 10: {
+ if (tag == 80) {
+ parse_isSelfHosted:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &isselfhosted_)));
+ set_has_isselfhosted();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.StackFrame.Data)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:mozilla.devtools.protobuf.StackFrame.Data)
+ return false;
+#undef DO_
+}
+
+void StackFrame_Data::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:mozilla.devtools.protobuf.StackFrame.Data)
+ // optional uint64 id = 1;
+ if (has_id()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->id(), output);
+ }
+
+ // optional .mozilla.devtools.protobuf.StackFrame parent = 2;
+ if (has_parent()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 2, this->parent(), output);
+ }
+
+ // optional uint32 line = 3;
+ if (has_line()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->line(), output);
+ }
+
+ // optional uint32 column = 4;
+ if (has_column()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->column(), output);
+ }
+
+ // optional bytes source = 5;
+ if (has_source()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
+ 5, this->source(), output);
+ }
+
+ // optional uint64 sourceRef = 6;
+ if (has_sourceref()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt64(6, this->sourceref(), output);
+ }
+
+ // optional bytes functionDisplayName = 7;
+ if (has_functiondisplayname()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
+ 7, this->functiondisplayname(), output);
+ }
+
+ // optional uint64 functionDisplayNameRef = 8;
+ if (has_functiondisplaynameref()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt64(8, this->functiondisplaynameref(), output);
+ }
+
+ // optional bool isSystem = 9;
+ if (has_issystem()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(9, this->issystem(), output);
+ }
+
+ // optional bool isSelfHosted = 10;
+ if (has_isselfhosted()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->isselfhosted(), output);
+ }
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+ // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.StackFrame.Data)
+}
+
+::google::protobuf::uint8* StackFrame_Data::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.StackFrame.Data)
+ // optional uint64 id = 1;
+ if (has_id()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->id(), target);
+ }
+
+ // optional .mozilla.devtools.protobuf.StackFrame parent = 2;
+ if (has_parent()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 2, this->parent(), target);
+ }
+
+ // optional uint32 line = 3;
+ if (has_line()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->line(), target);
+ }
+
+ // optional uint32 column = 4;
+ if (has_column()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(4, this->column(), target);
+ }
+
+ // optional bytes source = 5;
+ if (has_source()) {
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
+ 5, this->source(), target);
+ }
+
+ // optional uint64 sourceRef = 6;
+ if (has_sourceref()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(6, this->sourceref(), target);
+ }
+
+ // optional bytes functionDisplayName = 7;
+ if (has_functiondisplayname()) {
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
+ 7, this->functiondisplayname(), target);
+ }
+
+ // optional uint64 functionDisplayNameRef = 8;
+ if (has_functiondisplaynameref()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(8, this->functiondisplaynameref(), target);
+ }
+
+ // optional bool isSystem = 9;
+ if (has_issystem()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(9, this->issystem(), target);
+ }
+
+ // optional bool isSelfHosted = 10;
+ if (has_isselfhosted()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->isselfhosted(), target);
+ }
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.StackFrame.Data)
+ return target;
+}
+
+int StackFrame_Data::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional uint64 id = 1;
+ if (has_id()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt64Size(
+ this->id());
+ }
+
+ // optional .mozilla.devtools.protobuf.StackFrame parent = 2;
+ if (has_parent()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->parent());
+ }
+
+ // optional uint32 line = 3;
+ if (has_line()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt32Size(
+ this->line());
+ }
+
+ // optional uint32 column = 4;
+ if (has_column()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt32Size(
+ this->column());
+ }
+
+ }
+ if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+ // optional bool isSystem = 9;
+ if (has_issystem()) {
+ total_size += 1 + 1;
+ }
+
+ // optional bool isSelfHosted = 10;
+ if (has_isselfhosted()) {
+ total_size += 1 + 1;
+ }
+
+ }
+ switch (SourceOrRef_case()) {
+ // optional bytes source = 5;
+ case kSource: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::BytesSize(
+ this->source());
+ break;
+ }
+ // optional uint64 sourceRef = 6;
+ case kSourceRef: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt64Size(
+ this->sourceref());
+ break;
+ }
+ case SOURCEORREF_NOT_SET: {
+ break;
+ }
+ }
+ switch (FunctionDisplayNameOrRef_case()) {
+ // optional bytes functionDisplayName = 7;
+ case kFunctionDisplayName: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::BytesSize(
+ this->functiondisplayname());
+ break;
+ }
+ // optional uint64 functionDisplayNameRef = 8;
+ case kFunctionDisplayNameRef: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt64Size(
+ this->functiondisplaynameref());
+ break;
+ }
+ case FUNCTIONDISPLAYNAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void StackFrame_Data::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const StackFrame_Data* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const StackFrame_Data*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void StackFrame_Data::MergeFrom(const StackFrame_Data& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ switch (from.SourceOrRef_case()) {
+ case kSource: {
+ set_source(from.source());
+ break;
+ }
+ case kSourceRef: {
+ set_sourceref(from.sourceref());
+ break;
+ }
+ case SOURCEORREF_NOT_SET: {
+ break;
+ }
+ }
+ switch (from.FunctionDisplayNameOrRef_case()) {
+ case kFunctionDisplayName: {
+ set_functiondisplayname(from.functiondisplayname());
+ break;
+ }
+ case kFunctionDisplayNameRef: {
+ set_functiondisplaynameref(from.functiondisplaynameref());
+ break;
+ }
+ case FUNCTIONDISPLAYNAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_id()) {
+ set_id(from.id());
+ }
+ if (from.has_parent()) {
+ mutable_parent()->::mozilla::devtools::protobuf::StackFrame::MergeFrom(from.parent());
+ }
+ if (from.has_line()) {
+ set_line(from.line());
+ }
+ if (from.has_column()) {
+ set_column(from.column());
+ }
+ }
+ if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+ if (from.has_issystem()) {
+ set_issystem(from.issystem());
+ }
+ if (from.has_isselfhosted()) {
+ set_isselfhosted(from.isselfhosted());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void StackFrame_Data::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void StackFrame_Data::CopyFrom(const StackFrame_Data& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool StackFrame_Data::IsInitialized() const {
+
+ return true;
+}
+
+void StackFrame_Data::Swap(StackFrame_Data* other) {
+ if (other != this) {
+ std::swap(id_, other->id_);
+ std::swap(parent_, other->parent_);
+ std::swap(line_, other->line_);
+ std::swap(column_, other->column_);
+ std::swap(issystem_, other->issystem_);
+ std::swap(isselfhosted_, other->isselfhosted_);
+ std::swap(SourceOrRef_, other->SourceOrRef_);
+ std::swap(_oneof_case_[0], other->_oneof_case_[0]);
+ std::swap(FunctionDisplayNameOrRef_, other->FunctionDisplayNameOrRef_);
+ std::swap(_oneof_case_[1], other->_oneof_case_[1]);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata StackFrame_Data::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = StackFrame_Data_descriptor_;
+ metadata.reflection = StackFrame_Data_reflection_;
+ return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+#ifndef _MSC_VER
+const int StackFrame::kDataFieldNumber;
+const int StackFrame::kRefFieldNumber;
+#endif // !_MSC_VER
+
+StackFrame::StackFrame()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.StackFrame)
+}
+
+void StackFrame::InitAsDefaultInstance() {
+ StackFrame_default_oneof_instance_->data_ = const_cast< ::mozilla::devtools::protobuf::StackFrame_Data*>(&::mozilla::devtools::protobuf::StackFrame_Data::default_instance());
+ StackFrame_default_oneof_instance_->ref_ = GOOGLE_ULONGLONG(0);
+}
+
+StackFrame::StackFrame(const StackFrame& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:mozilla.devtools.protobuf.StackFrame)
+}
+
+void StackFrame::SharedCtor() {
+ _cached_size_ = 0;
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ clear_has_StackFrameType();
+}
+
+StackFrame::~StackFrame() {
+ // @@protoc_insertion_point(destructor:mozilla.devtools.protobuf.StackFrame)
+ SharedDtor();
+}
+
+void StackFrame::SharedDtor() {
+ if (has_StackFrameType()) {
+ clear_StackFrameType();
+ }
+ if (this != default_instance_) {
+ }
+}
+
+void StackFrame::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* StackFrame::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return StackFrame_descriptor_;
+}
+
+const StackFrame& StackFrame::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_CoreDump_2eproto();
+ return *default_instance_;
+}
+
+StackFrame* StackFrame::default_instance_ = NULL;
+
+StackFrame* StackFrame::New() const {
+ return new StackFrame;
+}
+
+void StackFrame::clear_StackFrameType() {
+ switch(StackFrameType_case()) {
+ case kData: {
+ delete StackFrameType_.data_;
+ break;
+ }
+ case kRef: {
+ // No need to clear
+ break;
+ }
+ case STACKFRAMETYPE_NOT_SET: {
+ break;
+ }
+ }
+ _oneof_case_[0] = STACKFRAMETYPE_NOT_SET;
+}
+
+
+void StackFrame::Clear() {
+ clear_StackFrameType();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool StackFrame::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.StackFrame)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1;
+ case 1: {
+ if (tag == 10) {
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_data()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(16)) goto parse_ref;
+ break;
+ }
+
+ // optional uint64 ref = 2;
+ case 2: {
+ if (tag == 16) {
+ parse_ref:
+ clear_StackFrameType();
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+ input, &StackFrameType_.ref_)));
+ set_has_ref();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.StackFrame)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:mozilla.devtools.protobuf.StackFrame)
+ return false;
+#undef DO_
+}
+
+void StackFrame::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:mozilla.devtools.protobuf.StackFrame)
+ // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1;
+ if (has_data()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 1, this->data(), output);
+ }
+
+ // optional uint64 ref = 2;
+ if (has_ref()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt64(2, this->ref(), output);
+ }
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+ // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.StackFrame)
+}
+
+::google::protobuf::uint8* StackFrame::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.StackFrame)
+ // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1;
+ if (has_data()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 1, this->data(), target);
+ }
+
+ // optional uint64 ref = 2;
+ if (has_ref()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(2, this->ref(), target);
+ }
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.StackFrame)
+ return target;
+}
+
+int StackFrame::ByteSize() const {
+ int total_size = 0;
+
+ switch (StackFrameType_case()) {
+ // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1;
+ case kData: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->data());
+ break;
+ }
+ // optional uint64 ref = 2;
+ case kRef: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt64Size(
+ this->ref());
+ break;
+ }
+ case STACKFRAMETYPE_NOT_SET: {
+ break;
+ }
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void StackFrame::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const StackFrame* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const StackFrame*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void StackFrame::MergeFrom(const StackFrame& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ switch (from.StackFrameType_case()) {
+ case kData: {
+ mutable_data()->::mozilla::devtools::protobuf::StackFrame_Data::MergeFrom(from.data());
+ break;
+ }
+ case kRef: {
+ set_ref(from.ref());
+ break;
+ }
+ case STACKFRAMETYPE_NOT_SET: {
+ break;
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void StackFrame::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void StackFrame::CopyFrom(const StackFrame& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool StackFrame::IsInitialized() const {
+
+ return true;
+}
+
+void StackFrame::Swap(StackFrame* other) {
+ if (other != this) {
+ std::swap(StackFrameType_, other->StackFrameType_);
+ std::swap(_oneof_case_[0], other->_oneof_case_[0]);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata StackFrame::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = StackFrame_descriptor_;
+ metadata.reflection = StackFrame_reflection_;
+ return metadata;
+}
+
+
+// ===================================================================
+
+#ifndef _MSC_VER
+const int Node::kIdFieldNumber;
+const int Node::kTypeNameFieldNumber;
+const int Node::kTypeNameRefFieldNumber;
+const int Node::kSizeFieldNumber;
+const int Node::kEdgesFieldNumber;
+const int Node::kAllocationStackFieldNumber;
+const int Node::kJsObjectClassNameFieldNumber;
+const int Node::kJsObjectClassNameRefFieldNumber;
+const int Node::kCoarseTypeFieldNumber;
+const int Node::kScriptFilenameFieldNumber;
+const int Node::kScriptFilenameRefFieldNumber;
+#endif // !_MSC_VER
+
+Node::Node()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.Node)
+}
+
+void Node::InitAsDefaultInstance() {
+ Node_default_oneof_instance_->typename__ = &::google::protobuf::internal::GetEmptyStringAlreadyInited();
+ Node_default_oneof_instance_->typenameref_ = GOOGLE_ULONGLONG(0);
+ allocationstack_ = const_cast< ::mozilla::devtools::protobuf::StackFrame*>(&::mozilla::devtools::protobuf::StackFrame::default_instance());
+ Node_default_oneof_instance_->jsobjectclassname_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited();
+ Node_default_oneof_instance_->jsobjectclassnameref_ = GOOGLE_ULONGLONG(0);
+ Node_default_oneof_instance_->scriptfilename_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited();
+ Node_default_oneof_instance_->scriptfilenameref_ = GOOGLE_ULONGLONG(0);
+}
+
+Node::Node(const Node& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:mozilla.devtools.protobuf.Node)
+}
+
+void Node::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
+ _cached_size_ = 0;
+ id_ = GOOGLE_ULONGLONG(0);
+ size_ = GOOGLE_ULONGLONG(0);
+ allocationstack_ = NULL;
+ coarsetype_ = 0u;
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ clear_has_TypeNameOrRef();
+ clear_has_JSObjectClassNameOrRef();
+ clear_has_ScriptFilenameOrRef();
+}
+
+Node::~Node() {
+ // @@protoc_insertion_point(destructor:mozilla.devtools.protobuf.Node)
+ SharedDtor();
+}
+
+void Node::SharedDtor() {
+ if (has_TypeNameOrRef()) {
+ clear_TypeNameOrRef();
+ }
+ if (has_JSObjectClassNameOrRef()) {
+ clear_JSObjectClassNameOrRef();
+ }
+ if (has_ScriptFilenameOrRef()) {
+ clear_ScriptFilenameOrRef();
+ }
+ if (this != default_instance_) {
+ delete allocationstack_;
+ }
+}
+
+void Node::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Node::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Node_descriptor_;
+}
+
+const Node& Node::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_CoreDump_2eproto();
+ return *default_instance_;
+}
+
+Node* Node::default_instance_ = NULL;
+
+Node* Node::New() const {
+ return new Node;
+}
+
+void Node::clear_TypeNameOrRef() {
+ switch(TypeNameOrRef_case()) {
+ case kTypeName: {
+ delete TypeNameOrRef_.typename__;
+ break;
+ }
+ case kTypeNameRef: {
+ // No need to clear
+ break;
+ }
+ case TYPENAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ _oneof_case_[0] = TYPENAMEORREF_NOT_SET;
+}
+
+void Node::clear_JSObjectClassNameOrRef() {
+ switch(JSObjectClassNameOrRef_case()) {
+ case kJsObjectClassName: {
+ delete JSObjectClassNameOrRef_.jsobjectclassname_;
+ break;
+ }
+ case kJsObjectClassNameRef: {
+ // No need to clear
+ break;
+ }
+ case JSOBJECTCLASSNAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ _oneof_case_[1] = JSOBJECTCLASSNAMEORREF_NOT_SET;
+}
+
+void Node::clear_ScriptFilenameOrRef() {
+ switch(ScriptFilenameOrRef_case()) {
+ case kScriptFilename: {
+ delete ScriptFilenameOrRef_.scriptfilename_;
+ break;
+ }
+ case kScriptFilenameRef: {
+ // No need to clear
+ break;
+ }
+ case SCRIPTFILENAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ _oneof_case_[2] = SCRIPTFILENAMEORREF_NOT_SET;
+}
+
+
+void Node::Clear() {
+#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>( \
+ &reinterpret_cast<Node*>(16)->f) - \
+ reinterpret_cast<char*>(16))
+
+#define ZR_(first, last) do { \
+ size_t f = OFFSET_OF_FIELD_(first); \
+ size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last); \
+ ::memset(&first, 0, n); \
+ } while (0)
+
+ if (_has_bits_[0 / 32] & 41) {
+ ZR_(id_, size_);
+ if (has_allocationstack()) {
+ if (allocationstack_ != NULL) allocationstack_->::mozilla::devtools::protobuf::StackFrame::Clear();
+ }
+ }
+ coarsetype_ = 0u;
+
+#undef OFFSET_OF_FIELD_
+#undef ZR_
+
+ edges_.Clear();
+ clear_TypeNameOrRef();
+ clear_JSObjectClassNameOrRef();
+ clear_ScriptFilenameOrRef();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool Node::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.Node)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional uint64 id = 1;
+ case 1: {
+ if (tag == 8) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+ input, &id_)));
+ set_has_id();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(18)) goto parse_typeName;
+ break;
+ }
+
+ // optional bytes typeName = 2;
+ case 2: {
+ if (tag == 18) {
+ parse_typeName:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+ input, this->mutable_typename_()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(24)) goto parse_typeNameRef;
+ break;
+ }
+
+ // optional uint64 typeNameRef = 3;
+ case 3: {
+ if (tag == 24) {
+ parse_typeNameRef:
+ clear_TypeNameOrRef();
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+ input, &TypeNameOrRef_.typenameref_)));
+ set_has_typenameref();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(32)) goto parse_size;
+ break;
+ }
+
+ // optional uint64 size = 4;
+ case 4: {
+ if (tag == 32) {
+ parse_size:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+ input, &size_)));
+ set_has_size();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(42)) goto parse_edges;
+ break;
+ }
+
+ // repeated .mozilla.devtools.protobuf.Edge edges = 5;
+ case 5: {
+ if (tag == 42) {
+ parse_edges:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, add_edges()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(42)) goto parse_edges;
+ if (input->ExpectTag(50)) goto parse_allocationStack;
+ break;
+ }
+
+ // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6;
+ case 6: {
+ if (tag == 50) {
+ parse_allocationStack:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_allocationstack()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(58)) goto parse_jsObjectClassName;
+ break;
+ }
+
+ // optional bytes jsObjectClassName = 7;
+ case 7: {
+ if (tag == 58) {
+ parse_jsObjectClassName:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+ input, this->mutable_jsobjectclassname()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(64)) goto parse_jsObjectClassNameRef;
+ break;
+ }
+
+ // optional uint64 jsObjectClassNameRef = 8;
+ case 8: {
+ if (tag == 64) {
+ parse_jsObjectClassNameRef:
+ clear_JSObjectClassNameOrRef();
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+ input, &JSObjectClassNameOrRef_.jsobjectclassnameref_)));
+ set_has_jsobjectclassnameref();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(72)) goto parse_coarseType;
+ break;
+ }
+
+ // optional uint32 coarseType = 9 [default = 0];
+ case 9: {
+ if (tag == 72) {
+ parse_coarseType:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+ input, &coarsetype_)));
+ set_has_coarsetype();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(82)) goto parse_scriptFilename;
+ break;
+ }
+
+ // optional bytes scriptFilename = 10;
+ case 10: {
+ if (tag == 82) {
+ parse_scriptFilename:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+ input, this->mutable_scriptfilename()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(88)) goto parse_scriptFilenameRef;
+ break;
+ }
+
+ // optional uint64 scriptFilenameRef = 11;
+ case 11: {
+ if (tag == 88) {
+ parse_scriptFilenameRef:
+ clear_ScriptFilenameOrRef();
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+ input, &ScriptFilenameOrRef_.scriptfilenameref_)));
+ set_has_scriptfilenameref();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.Node)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:mozilla.devtools.protobuf.Node)
+ return false;
+#undef DO_
+}
+
+void Node::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:mozilla.devtools.protobuf.Node)
+ // optional uint64 id = 1;
+ if (has_id()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->id(), output);
+ }
+
+ // optional bytes typeName = 2;
+ if (has_typename_()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
+ 2, this->typename_(), output);
+ }
+
+ // optional uint64 typeNameRef = 3;
+ if (has_typenameref()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt64(3, this->typenameref(), output);
+ }
+
+ // optional uint64 size = 4;
+ if (has_size()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt64(4, this->size(), output);
+ }
+
+ // repeated .mozilla.devtools.protobuf.Edge edges = 5;
+ for (int i = 0; i < this->edges_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 5, this->edges(i), output);
+ }
+
+ // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6;
+ if (has_allocationstack()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 6, this->allocationstack(), output);
+ }
+
+ // optional bytes jsObjectClassName = 7;
+ if (has_jsobjectclassname()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
+ 7, this->jsobjectclassname(), output);
+ }
+
+ // optional uint64 jsObjectClassNameRef = 8;
+ if (has_jsobjectclassnameref()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt64(8, this->jsobjectclassnameref(), output);
+ }
+
+ // optional uint32 coarseType = 9 [default = 0];
+ if (has_coarsetype()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt32(9, this->coarsetype(), output);
+ }
+
+ // optional bytes scriptFilename = 10;
+ if (has_scriptfilename()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
+ 10, this->scriptfilename(), output);
+ }
+
+ // optional uint64 scriptFilenameRef = 11;
+ if (has_scriptfilenameref()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt64(11, this->scriptfilenameref(), output);
+ }
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+ // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.Node)
+}
+
+::google::protobuf::uint8* Node::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.Node)
+ // optional uint64 id = 1;
+ if (has_id()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->id(), target);
+ }
+
+ // optional bytes typeName = 2;
+ if (has_typename_()) {
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
+ 2, this->typename_(), target);
+ }
+
+ // optional uint64 typeNameRef = 3;
+ if (has_typenameref()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(3, this->typenameref(), target);
+ }
+
+ // optional uint64 size = 4;
+ if (has_size()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(4, this->size(), target);
+ }
+
+ // repeated .mozilla.devtools.protobuf.Edge edges = 5;
+ for (int i = 0; i < this->edges_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 5, this->edges(i), target);
+ }
+
+ // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6;
+ if (has_allocationstack()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 6, this->allocationstack(), target);
+ }
+
+ // optional bytes jsObjectClassName = 7;
+ if (has_jsobjectclassname()) {
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
+ 7, this->jsobjectclassname(), target);
+ }
+
+ // optional uint64 jsObjectClassNameRef = 8;
+ if (has_jsobjectclassnameref()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(8, this->jsobjectclassnameref(), target);
+ }
+
+ // optional uint32 coarseType = 9 [default = 0];
+ if (has_coarsetype()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(9, this->coarsetype(), target);
+ }
+
+ // optional bytes scriptFilename = 10;
+ if (has_scriptfilename()) {
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
+ 10, this->scriptfilename(), target);
+ }
+
+ // optional uint64 scriptFilenameRef = 11;
+ if (has_scriptfilenameref()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(11, this->scriptfilenameref(), target);
+ }
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.Node)
+ return target;
+}
+
+int Node::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional uint64 id = 1;
+ if (has_id()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt64Size(
+ this->id());
+ }
+
+ // optional uint64 size = 4;
+ if (has_size()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt64Size(
+ this->size());
+ }
+
+ // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6;
+ if (has_allocationstack()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->allocationstack());
+ }
+
+ }
+ if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+ // optional uint32 coarseType = 9 [default = 0];
+ if (has_coarsetype()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt32Size(
+ this->coarsetype());
+ }
+
+ }
+ // repeated .mozilla.devtools.protobuf.Edge edges = 5;
+ total_size += 1 * this->edges_size();
+ for (int i = 0; i < this->edges_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->edges(i));
+ }
+
+ switch (TypeNameOrRef_case()) {
+ // optional bytes typeName = 2;
+ case kTypeName: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::BytesSize(
+ this->typename_());
+ break;
+ }
+ // optional uint64 typeNameRef = 3;
+ case kTypeNameRef: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt64Size(
+ this->typenameref());
+ break;
+ }
+ case TYPENAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ switch (JSObjectClassNameOrRef_case()) {
+ // optional bytes jsObjectClassName = 7;
+ case kJsObjectClassName: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::BytesSize(
+ this->jsobjectclassname());
+ break;
+ }
+ // optional uint64 jsObjectClassNameRef = 8;
+ case kJsObjectClassNameRef: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt64Size(
+ this->jsobjectclassnameref());
+ break;
+ }
+ case JSOBJECTCLASSNAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ switch (ScriptFilenameOrRef_case()) {
+ // optional bytes scriptFilename = 10;
+ case kScriptFilename: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::BytesSize(
+ this->scriptfilename());
+ break;
+ }
+ // optional uint64 scriptFilenameRef = 11;
+ case kScriptFilenameRef: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt64Size(
+ this->scriptfilenameref());
+ break;
+ }
+ case SCRIPTFILENAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Node::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const Node* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const Node*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void Node::MergeFrom(const Node& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ edges_.MergeFrom(from.edges_);
+ switch (from.TypeNameOrRef_case()) {
+ case kTypeName: {
+ set_typename_(from.typename_());
+ break;
+ }
+ case kTypeNameRef: {
+ set_typenameref(from.typenameref());
+ break;
+ }
+ case TYPENAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ switch (from.JSObjectClassNameOrRef_case()) {
+ case kJsObjectClassName: {
+ set_jsobjectclassname(from.jsobjectclassname());
+ break;
+ }
+ case kJsObjectClassNameRef: {
+ set_jsobjectclassnameref(from.jsobjectclassnameref());
+ break;
+ }
+ case JSOBJECTCLASSNAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ switch (from.ScriptFilenameOrRef_case()) {
+ case kScriptFilename: {
+ set_scriptfilename(from.scriptfilename());
+ break;
+ }
+ case kScriptFilenameRef: {
+ set_scriptfilenameref(from.scriptfilenameref());
+ break;
+ }
+ case SCRIPTFILENAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_id()) {
+ set_id(from.id());
+ }
+ if (from.has_size()) {
+ set_size(from.size());
+ }
+ if (from.has_allocationstack()) {
+ mutable_allocationstack()->::mozilla::devtools::protobuf::StackFrame::MergeFrom(from.allocationstack());
+ }
+ }
+ if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+ if (from.has_coarsetype()) {
+ set_coarsetype(from.coarsetype());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void Node::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void Node::CopyFrom(const Node& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Node::IsInitialized() const {
+
+ return true;
+}
+
+void Node::Swap(Node* other) {
+ if (other != this) {
+ std::swap(id_, other->id_);
+ std::swap(size_, other->size_);
+ edges_.Swap(&other->edges_);
+ std::swap(allocationstack_, other->allocationstack_);
+ std::swap(coarsetype_, other->coarsetype_);
+ std::swap(TypeNameOrRef_, other->TypeNameOrRef_);
+ std::swap(_oneof_case_[0], other->_oneof_case_[0]);
+ std::swap(JSObjectClassNameOrRef_, other->JSObjectClassNameOrRef_);
+ std::swap(_oneof_case_[1], other->_oneof_case_[1]);
+ std::swap(ScriptFilenameOrRef_, other->ScriptFilenameOrRef_);
+ std::swap(_oneof_case_[2], other->_oneof_case_[2]);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata Node::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = Node_descriptor_;
+ metadata.reflection = Node_reflection_;
+ return metadata;
+}
+
+
+// ===================================================================
+
+#ifndef _MSC_VER
+const int Edge::kReferentFieldNumber;
+const int Edge::kNameFieldNumber;
+const int Edge::kNameRefFieldNumber;
+#endif // !_MSC_VER
+
+Edge::Edge()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:mozilla.devtools.protobuf.Edge)
+}
+
+void Edge::InitAsDefaultInstance() {
+ Edge_default_oneof_instance_->name_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited();
+ Edge_default_oneof_instance_->nameref_ = GOOGLE_ULONGLONG(0);
+}
+
+Edge::Edge(const Edge& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:mozilla.devtools.protobuf.Edge)
+}
+
+void Edge::SharedCtor() {
+ ::google::protobuf::internal::GetEmptyString();
+ _cached_size_ = 0;
+ referent_ = GOOGLE_ULONGLONG(0);
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ clear_has_EdgeNameOrRef();
+}
+
+Edge::~Edge() {
+ // @@protoc_insertion_point(destructor:mozilla.devtools.protobuf.Edge)
+ SharedDtor();
+}
+
+void Edge::SharedDtor() {
+ if (has_EdgeNameOrRef()) {
+ clear_EdgeNameOrRef();
+ }
+ if (this != default_instance_) {
+ }
+}
+
+void Edge::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Edge::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Edge_descriptor_;
+}
+
+const Edge& Edge::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_CoreDump_2eproto();
+ return *default_instance_;
+}
+
+Edge* Edge::default_instance_ = NULL;
+
+Edge* Edge::New() const {
+ return new Edge;
+}
+
+void Edge::clear_EdgeNameOrRef() {
+ switch(EdgeNameOrRef_case()) {
+ case kName: {
+ delete EdgeNameOrRef_.name_;
+ break;
+ }
+ case kNameRef: {
+ // No need to clear
+ break;
+ }
+ case EDGENAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ _oneof_case_[0] = EDGENAMEORREF_NOT_SET;
+}
+
+
+void Edge::Clear() {
+ referent_ = GOOGLE_ULONGLONG(0);
+ clear_EdgeNameOrRef();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool Edge::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:mozilla.devtools.protobuf.Edge)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional uint64 referent = 1;
+ case 1: {
+ if (tag == 8) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+ input, &referent_)));
+ set_has_referent();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(18)) goto parse_name;
+ break;
+ }
+
+ // optional bytes name = 2;
+ case 2: {
+ if (tag == 18) {
+ parse_name:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+ input, this->mutable_name()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(24)) goto parse_nameRef;
+ break;
+ }
+
+ // optional uint64 nameRef = 3;
+ case 3: {
+ if (tag == 24) {
+ parse_nameRef:
+ clear_EdgeNameOrRef();
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
+ input, &EdgeNameOrRef_.nameref_)));
+ set_has_nameref();
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:mozilla.devtools.protobuf.Edge)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:mozilla.devtools.protobuf.Edge)
+ return false;
+#undef DO_
+}
+
+void Edge::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:mozilla.devtools.protobuf.Edge)
+ // optional uint64 referent = 1;
+ if (has_referent()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->referent(), output);
+ }
+
+ // optional bytes name = 2;
+ if (has_name()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
+ 2, this->name(), output);
+ }
+
+ // optional uint64 nameRef = 3;
+ if (has_nameref()) {
+ ::google::protobuf::internal::WireFormatLite::WriteUInt64(3, this->nameref(), output);
+ }
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+ // @@protoc_insertion_point(serialize_end:mozilla.devtools.protobuf.Edge)
+}
+
+::google::protobuf::uint8* Edge::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:mozilla.devtools.protobuf.Edge)
+ // optional uint64 referent = 1;
+ if (has_referent()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->referent(), target);
+ }
+
+ // optional bytes name = 2;
+ if (has_name()) {
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
+ 2, this->name(), target);
+ }
+
+ // optional uint64 nameRef = 3;
+ if (has_nameref()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(3, this->nameref(), target);
+ }
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ // @@protoc_insertion_point(serialize_to_array_end:mozilla.devtools.protobuf.Edge)
+ return target;
+}
+
+int Edge::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional uint64 referent = 1;
+ if (has_referent()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt64Size(
+ this->referent());
+ }
+
+ }
+ switch (EdgeNameOrRef_case()) {
+ // optional bytes name = 2;
+ case kName: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::BytesSize(
+ this->name());
+ break;
+ }
+ // optional uint64 nameRef = 3;
+ case kNameRef: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::UInt64Size(
+ this->nameref());
+ break;
+ }
+ case EDGENAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Edge::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const Edge* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const Edge*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void Edge::MergeFrom(const Edge& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ switch (from.EdgeNameOrRef_case()) {
+ case kName: {
+ set_name(from.name());
+ break;
+ }
+ case kNameRef: {
+ set_nameref(from.nameref());
+ break;
+ }
+ case EDGENAMEORREF_NOT_SET: {
+ break;
+ }
+ }
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_referent()) {
+ set_referent(from.referent());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void Edge::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void Edge::CopyFrom(const Edge& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Edge::IsInitialized() const {
+
+ return true;
+}
+
+void Edge::Swap(Edge* other) {
+ if (other != this) {
+ std::swap(referent_, other->referent_);
+ std::swap(EdgeNameOrRef_, other->EdgeNameOrRef_);
+ std::swap(_oneof_case_[0], other->_oneof_case_[0]);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata Edge::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = Edge_descriptor_;
+ metadata.reflection = Edge_reflection_;
+ return metadata;
+}
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+} // namespace protobuf
+} // namespace devtools
+} // namespace mozilla
+
+// @@protoc_insertion_point(global_scope)
diff --git a/dom/heapsnapshot/CoreDump.pb.h b/dom/heapsnapshot/CoreDump.pb.h
new file mode 100644
index 000000000..584c2e379
--- /dev/null
+++ b/dom/heapsnapshot/CoreDump.pb.h
@@ -0,0 +1,1893 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: CoreDump.proto
+
+#ifndef PROTOBUF_CoreDump_2eproto__INCLUDED
+#define PROTOBUF_CoreDump_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 2006000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 2006001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace mozilla {
+namespace devtools {
+namespace protobuf {
+
+// Internal implementation detail -- do not call these.
+void protobuf_AddDesc_CoreDump_2eproto();
+void protobuf_AssignDesc_CoreDump_2eproto();
+void protobuf_ShutdownFile_CoreDump_2eproto();
+
+class Metadata;
+class StackFrame;
+class StackFrame_Data;
+class Node;
+class Edge;
+
+// ===================================================================
+
+class Metadata : public ::google::protobuf::Message {
+ public:
+ Metadata();
+ virtual ~Metadata();
+
+ Metadata(const Metadata& from);
+
+ inline Metadata& operator=(const Metadata& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const Metadata& default_instance();
+
+ void Swap(Metadata* other);
+
+ // implements Message ----------------------------------------------
+
+ Metadata* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const Metadata& from);
+ void MergeFrom(const Metadata& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional uint64 timeStamp = 1;
+ inline bool has_timestamp() const;
+ inline void clear_timestamp();
+ static const int kTimeStampFieldNumber = 1;
+ inline ::google::protobuf::uint64 timestamp() const;
+ inline void set_timestamp(::google::protobuf::uint64 value);
+
+ // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.Metadata)
+ private:
+ inline void set_has_timestamp();
+ inline void clear_has_timestamp();
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::google::protobuf::uint64 timestamp_;
+ friend void protobuf_AddDesc_CoreDump_2eproto();
+ friend void protobuf_AssignDesc_CoreDump_2eproto();
+ friend void protobuf_ShutdownFile_CoreDump_2eproto();
+
+ void InitAsDefaultInstance();
+ static Metadata* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class StackFrame_Data : public ::google::protobuf::Message {
+ public:
+ StackFrame_Data();
+ virtual ~StackFrame_Data();
+
+ StackFrame_Data(const StackFrame_Data& from);
+
+ inline StackFrame_Data& operator=(const StackFrame_Data& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const StackFrame_Data& default_instance();
+
+ enum SourceOrRefCase {
+ kSource = 5,
+ kSourceRef = 6,
+ SOURCEORREF_NOT_SET = 0,
+ };
+
+ enum FunctionDisplayNameOrRefCase {
+ kFunctionDisplayName = 7,
+ kFunctionDisplayNameRef = 8,
+ FUNCTIONDISPLAYNAMEORREF_NOT_SET = 0,
+ };
+
+ void Swap(StackFrame_Data* other);
+
+ // implements Message ----------------------------------------------
+
+ StackFrame_Data* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const StackFrame_Data& from);
+ void MergeFrom(const StackFrame_Data& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional uint64 id = 1;
+ inline bool has_id() const;
+ inline void clear_id();
+ static const int kIdFieldNumber = 1;
+ inline ::google::protobuf::uint64 id() const;
+ inline void set_id(::google::protobuf::uint64 value);
+
+ // optional .mozilla.devtools.protobuf.StackFrame parent = 2;
+ inline bool has_parent() const;
+ inline void clear_parent();
+ static const int kParentFieldNumber = 2;
+ inline const ::mozilla::devtools::protobuf::StackFrame& parent() const;
+ inline ::mozilla::devtools::protobuf::StackFrame* mutable_parent();
+ inline ::mozilla::devtools::protobuf::StackFrame* release_parent();
+ inline void set_allocated_parent(::mozilla::devtools::protobuf::StackFrame* parent);
+
+ // optional uint32 line = 3;
+ inline bool has_line() const;
+ inline void clear_line();
+ static const int kLineFieldNumber = 3;
+ inline ::google::protobuf::uint32 line() const;
+ inline void set_line(::google::protobuf::uint32 value);
+
+ // optional uint32 column = 4;
+ inline bool has_column() const;
+ inline void clear_column();
+ static const int kColumnFieldNumber = 4;
+ inline ::google::protobuf::uint32 column() const;
+ inline void set_column(::google::protobuf::uint32 value);
+
+ // optional bytes source = 5;
+ inline bool has_source() const;
+ inline void clear_source();
+ static const int kSourceFieldNumber = 5;
+ inline const ::std::string& source() const;
+ inline void set_source(const ::std::string& value);
+ inline void set_source(const char* value);
+ inline void set_source(const void* value, size_t size);
+ inline ::std::string* mutable_source();
+ inline ::std::string* release_source();
+ inline void set_allocated_source(::std::string* source);
+
+ // optional uint64 sourceRef = 6;
+ inline bool has_sourceref() const;
+ inline void clear_sourceref();
+ static const int kSourceRefFieldNumber = 6;
+ inline ::google::protobuf::uint64 sourceref() const;
+ inline void set_sourceref(::google::protobuf::uint64 value);
+
+ // optional bytes functionDisplayName = 7;
+ inline bool has_functiondisplayname() const;
+ inline void clear_functiondisplayname();
+ static const int kFunctionDisplayNameFieldNumber = 7;
+ inline const ::std::string& functiondisplayname() const;
+ inline void set_functiondisplayname(const ::std::string& value);
+ inline void set_functiondisplayname(const char* value);
+ inline void set_functiondisplayname(const void* value, size_t size);
+ inline ::std::string* mutable_functiondisplayname();
+ inline ::std::string* release_functiondisplayname();
+ inline void set_allocated_functiondisplayname(::std::string* functiondisplayname);
+
+ // optional uint64 functionDisplayNameRef = 8;
+ inline bool has_functiondisplaynameref() const;
+ inline void clear_functiondisplaynameref();
+ static const int kFunctionDisplayNameRefFieldNumber = 8;
+ inline ::google::protobuf::uint64 functiondisplaynameref() const;
+ inline void set_functiondisplaynameref(::google::protobuf::uint64 value);
+
+ // optional bool isSystem = 9;
+ inline bool has_issystem() const;
+ inline void clear_issystem();
+ static const int kIsSystemFieldNumber = 9;
+ inline bool issystem() const;
+ inline void set_issystem(bool value);
+
+ // optional bool isSelfHosted = 10;
+ inline bool has_isselfhosted() const;
+ inline void clear_isselfhosted();
+ static const int kIsSelfHostedFieldNumber = 10;
+ inline bool isselfhosted() const;
+ inline void set_isselfhosted(bool value);
+
+ inline SourceOrRefCase SourceOrRef_case() const;
+ inline FunctionDisplayNameOrRefCase FunctionDisplayNameOrRef_case() const;
+ // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.StackFrame.Data)
+ private:
+ inline void set_has_id();
+ inline void clear_has_id();
+ inline void set_has_parent();
+ inline void clear_has_parent();
+ inline void set_has_line();
+ inline void clear_has_line();
+ inline void set_has_column();
+ inline void clear_has_column();
+ inline void set_has_source();
+ inline void set_has_sourceref();
+ inline void set_has_functiondisplayname();
+ inline void set_has_functiondisplaynameref();
+ inline void set_has_issystem();
+ inline void clear_has_issystem();
+ inline void set_has_isselfhosted();
+ inline void clear_has_isselfhosted();
+
+ inline bool has_SourceOrRef();
+ void clear_SourceOrRef();
+ inline void clear_has_SourceOrRef();
+
+ inline bool has_FunctionDisplayNameOrRef();
+ void clear_FunctionDisplayNameOrRef();
+ inline void clear_has_FunctionDisplayNameOrRef();
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::google::protobuf::uint64 id_;
+ ::mozilla::devtools::protobuf::StackFrame* parent_;
+ ::google::protobuf::uint32 line_;
+ ::google::protobuf::uint32 column_;
+ bool issystem_;
+ bool isselfhosted_;
+ union SourceOrRefUnion {
+ ::std::string* source_;
+ ::google::protobuf::uint64 sourceref_;
+ } SourceOrRef_;
+ union FunctionDisplayNameOrRefUnion {
+ ::std::string* functiondisplayname_;
+ ::google::protobuf::uint64 functiondisplaynameref_;
+ } FunctionDisplayNameOrRef_;
+ ::google::protobuf::uint32 _oneof_case_[2];
+
+ friend void protobuf_AddDesc_CoreDump_2eproto();
+ friend void protobuf_AssignDesc_CoreDump_2eproto();
+ friend void protobuf_ShutdownFile_CoreDump_2eproto();
+
+ void InitAsDefaultInstance();
+ static StackFrame_Data* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class StackFrame : public ::google::protobuf::Message {
+ public:
+ StackFrame();
+ virtual ~StackFrame();
+
+ StackFrame(const StackFrame& from);
+
+ inline StackFrame& operator=(const StackFrame& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const StackFrame& default_instance();
+
+ enum StackFrameTypeCase {
+ kData = 1,
+ kRef = 2,
+ STACKFRAMETYPE_NOT_SET = 0,
+ };
+
+ void Swap(StackFrame* other);
+
+ // implements Message ----------------------------------------------
+
+ StackFrame* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const StackFrame& from);
+ void MergeFrom(const StackFrame& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ typedef StackFrame_Data Data;
+
+ // accessors -------------------------------------------------------
+
+ // optional .mozilla.devtools.protobuf.StackFrame.Data data = 1;
+ inline bool has_data() const;
+ inline void clear_data();
+ static const int kDataFieldNumber = 1;
+ inline const ::mozilla::devtools::protobuf::StackFrame_Data& data() const;
+ inline ::mozilla::devtools::protobuf::StackFrame_Data* mutable_data();
+ inline ::mozilla::devtools::protobuf::StackFrame_Data* release_data();
+ inline void set_allocated_data(::mozilla::devtools::protobuf::StackFrame_Data* data);
+
+ // optional uint64 ref = 2;
+ inline bool has_ref() const;
+ inline void clear_ref();
+ static const int kRefFieldNumber = 2;
+ inline ::google::protobuf::uint64 ref() const;
+ inline void set_ref(::google::protobuf::uint64 value);
+
+ inline StackFrameTypeCase StackFrameType_case() const;
+ // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.StackFrame)
+ private:
+ inline void set_has_data();
+ inline void set_has_ref();
+
+ inline bool has_StackFrameType();
+ void clear_StackFrameType();
+ inline void clear_has_StackFrameType();
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ union StackFrameTypeUnion {
+ ::mozilla::devtools::protobuf::StackFrame_Data* data_;
+ ::google::protobuf::uint64 ref_;
+ } StackFrameType_;
+ ::google::protobuf::uint32 _oneof_case_[1];
+
+ friend void protobuf_AddDesc_CoreDump_2eproto();
+ friend void protobuf_AssignDesc_CoreDump_2eproto();
+ friend void protobuf_ShutdownFile_CoreDump_2eproto();
+
+ void InitAsDefaultInstance();
+ static StackFrame* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class Node : public ::google::protobuf::Message {
+ public:
+ Node();
+ virtual ~Node();
+
+ Node(const Node& from);
+
+ inline Node& operator=(const Node& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const Node& default_instance();
+
+ enum TypeNameOrRefCase {
+ kTypeName = 2,
+ kTypeNameRef = 3,
+ TYPENAMEORREF_NOT_SET = 0,
+ };
+
+ enum JSObjectClassNameOrRefCase {
+ kJsObjectClassName = 7,
+ kJsObjectClassNameRef = 8,
+ JSOBJECTCLASSNAMEORREF_NOT_SET = 0,
+ };
+
+ enum ScriptFilenameOrRefCase {
+ kScriptFilename = 10,
+ kScriptFilenameRef = 11,
+ SCRIPTFILENAMEORREF_NOT_SET = 0,
+ };
+
+ void Swap(Node* other);
+
+ // implements Message ----------------------------------------------
+
+ Node* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const Node& from);
+ void MergeFrom(const Node& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional uint64 id = 1;
+ inline bool has_id() const;
+ inline void clear_id();
+ static const int kIdFieldNumber = 1;
+ inline ::google::protobuf::uint64 id() const;
+ inline void set_id(::google::protobuf::uint64 value);
+
+ // optional bytes typeName = 2;
+ inline bool has_typename_() const;
+ inline void clear_typename_();
+ static const int kTypeNameFieldNumber = 2;
+ inline const ::std::string& typename_() const;
+ inline void set_typename_(const ::std::string& value);
+ inline void set_typename_(const char* value);
+ inline void set_typename_(const void* value, size_t size);
+ inline ::std::string* mutable_typename_();
+ inline ::std::string* release_typename_();
+ inline void set_allocated_typename_(::std::string* typename_);
+
+ // optional uint64 typeNameRef = 3;
+ inline bool has_typenameref() const;
+ inline void clear_typenameref();
+ static const int kTypeNameRefFieldNumber = 3;
+ inline ::google::protobuf::uint64 typenameref() const;
+ inline void set_typenameref(::google::protobuf::uint64 value);
+
+ // optional uint64 size = 4;
+ inline bool has_size() const;
+ inline void clear_size();
+ static const int kSizeFieldNumber = 4;
+ inline ::google::protobuf::uint64 size() const;
+ inline void set_size(::google::protobuf::uint64 value);
+
+ // repeated .mozilla.devtools.protobuf.Edge edges = 5;
+ inline int edges_size() const;
+ inline void clear_edges();
+ static const int kEdgesFieldNumber = 5;
+ inline const ::mozilla::devtools::protobuf::Edge& edges(int index) const;
+ inline ::mozilla::devtools::protobuf::Edge* mutable_edges(int index);
+ inline ::mozilla::devtools::protobuf::Edge* add_edges();
+ inline const ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge >&
+ edges() const;
+ inline ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge >*
+ mutable_edges();
+
+ // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6;
+ inline bool has_allocationstack() const;
+ inline void clear_allocationstack();
+ static const int kAllocationStackFieldNumber = 6;
+ inline const ::mozilla::devtools::protobuf::StackFrame& allocationstack() const;
+ inline ::mozilla::devtools::protobuf::StackFrame* mutable_allocationstack();
+ inline ::mozilla::devtools::protobuf::StackFrame* release_allocationstack();
+ inline void set_allocated_allocationstack(::mozilla::devtools::protobuf::StackFrame* allocationstack);
+
+ // optional bytes jsObjectClassName = 7;
+ inline bool has_jsobjectclassname() const;
+ inline void clear_jsobjectclassname();
+ static const int kJsObjectClassNameFieldNumber = 7;
+ inline const ::std::string& jsobjectclassname() const;
+ inline void set_jsobjectclassname(const ::std::string& value);
+ inline void set_jsobjectclassname(const char* value);
+ inline void set_jsobjectclassname(const void* value, size_t size);
+ inline ::std::string* mutable_jsobjectclassname();
+ inline ::std::string* release_jsobjectclassname();
+ inline void set_allocated_jsobjectclassname(::std::string* jsobjectclassname);
+
+ // optional uint64 jsObjectClassNameRef = 8;
+ inline bool has_jsobjectclassnameref() const;
+ inline void clear_jsobjectclassnameref();
+ static const int kJsObjectClassNameRefFieldNumber = 8;
+ inline ::google::protobuf::uint64 jsobjectclassnameref() const;
+ inline void set_jsobjectclassnameref(::google::protobuf::uint64 value);
+
+ // optional uint32 coarseType = 9 [default = 0];
+ inline bool has_coarsetype() const;
+ inline void clear_coarsetype();
+ static const int kCoarseTypeFieldNumber = 9;
+ inline ::google::protobuf::uint32 coarsetype() const;
+ inline void set_coarsetype(::google::protobuf::uint32 value);
+
+ // optional bytes scriptFilename = 10;
+ inline bool has_scriptfilename() const;
+ inline void clear_scriptfilename();
+ static const int kScriptFilenameFieldNumber = 10;
+ inline const ::std::string& scriptfilename() const;
+ inline void set_scriptfilename(const ::std::string& value);
+ inline void set_scriptfilename(const char* value);
+ inline void set_scriptfilename(const void* value, size_t size);
+ inline ::std::string* mutable_scriptfilename();
+ inline ::std::string* release_scriptfilename();
+ inline void set_allocated_scriptfilename(::std::string* scriptfilename);
+
+ // optional uint64 scriptFilenameRef = 11;
+ inline bool has_scriptfilenameref() const;
+ inline void clear_scriptfilenameref();
+ static const int kScriptFilenameRefFieldNumber = 11;
+ inline ::google::protobuf::uint64 scriptfilenameref() const;
+ inline void set_scriptfilenameref(::google::protobuf::uint64 value);
+
+ inline TypeNameOrRefCase TypeNameOrRef_case() const;
+ inline JSObjectClassNameOrRefCase JSObjectClassNameOrRef_case() const;
+ inline ScriptFilenameOrRefCase ScriptFilenameOrRef_case() const;
+ // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.Node)
+ private:
+ inline void set_has_id();
+ inline void clear_has_id();
+ inline void set_has_typename_();
+ inline void set_has_typenameref();
+ inline void set_has_size();
+ inline void clear_has_size();
+ inline void set_has_allocationstack();
+ inline void clear_has_allocationstack();
+ inline void set_has_jsobjectclassname();
+ inline void set_has_jsobjectclassnameref();
+ inline void set_has_coarsetype();
+ inline void clear_has_coarsetype();
+ inline void set_has_scriptfilename();
+ inline void set_has_scriptfilenameref();
+
+ inline bool has_TypeNameOrRef();
+ void clear_TypeNameOrRef();
+ inline void clear_has_TypeNameOrRef();
+
+ inline bool has_JSObjectClassNameOrRef();
+ void clear_JSObjectClassNameOrRef();
+ inline void clear_has_JSObjectClassNameOrRef();
+
+ inline bool has_ScriptFilenameOrRef();
+ void clear_ScriptFilenameOrRef();
+ inline void clear_has_ScriptFilenameOrRef();
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::google::protobuf::uint64 id_;
+ ::google::protobuf::uint64 size_;
+ ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge > edges_;
+ ::mozilla::devtools::protobuf::StackFrame* allocationstack_;
+ ::google::protobuf::uint32 coarsetype_;
+ union TypeNameOrRefUnion {
+ ::std::string* typename__;
+ ::google::protobuf::uint64 typenameref_;
+ } TypeNameOrRef_;
+ union JSObjectClassNameOrRefUnion {
+ ::std::string* jsobjectclassname_;
+ ::google::protobuf::uint64 jsobjectclassnameref_;
+ } JSObjectClassNameOrRef_;
+ union ScriptFilenameOrRefUnion {
+ ::std::string* scriptfilename_;
+ ::google::protobuf::uint64 scriptfilenameref_;
+ } ScriptFilenameOrRef_;
+ ::google::protobuf::uint32 _oneof_case_[3];
+
+ friend void protobuf_AddDesc_CoreDump_2eproto();
+ friend void protobuf_AssignDesc_CoreDump_2eproto();
+ friend void protobuf_ShutdownFile_CoreDump_2eproto();
+
+ void InitAsDefaultInstance();
+ static Node* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class Edge : public ::google::protobuf::Message {
+ public:
+ Edge();
+ virtual ~Edge();
+
+ Edge(const Edge& from);
+
+ inline Edge& operator=(const Edge& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const Edge& default_instance();
+
+ enum EdgeNameOrRefCase {
+ kName = 2,
+ kNameRef = 3,
+ EDGENAMEORREF_NOT_SET = 0,
+ };
+
+ void Swap(Edge* other);
+
+ // implements Message ----------------------------------------------
+
+ Edge* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const Edge& from);
+ void MergeFrom(const Edge& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional uint64 referent = 1;
+ inline bool has_referent() const;
+ inline void clear_referent();
+ static const int kReferentFieldNumber = 1;
+ inline ::google::protobuf::uint64 referent() const;
+ inline void set_referent(::google::protobuf::uint64 value);
+
+ // optional bytes name = 2;
+ inline bool has_name() const;
+ inline void clear_name();
+ static const int kNameFieldNumber = 2;
+ inline const ::std::string& name() const;
+ inline void set_name(const ::std::string& value);
+ inline void set_name(const char* value);
+ inline void set_name(const void* value, size_t size);
+ inline ::std::string* mutable_name();
+ inline ::std::string* release_name();
+ inline void set_allocated_name(::std::string* name);
+
+ // optional uint64 nameRef = 3;
+ inline bool has_nameref() const;
+ inline void clear_nameref();
+ static const int kNameRefFieldNumber = 3;
+ inline ::google::protobuf::uint64 nameref() const;
+ inline void set_nameref(::google::protobuf::uint64 value);
+
+ inline EdgeNameOrRefCase EdgeNameOrRef_case() const;
+ // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.Edge)
+ private:
+ inline void set_has_referent();
+ inline void clear_has_referent();
+ inline void set_has_name();
+ inline void set_has_nameref();
+
+ inline bool has_EdgeNameOrRef();
+ void clear_EdgeNameOrRef();
+ inline void clear_has_EdgeNameOrRef();
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::google::protobuf::uint32 _has_bits_[1];
+ mutable int _cached_size_;
+ ::google::protobuf::uint64 referent_;
+ union EdgeNameOrRefUnion {
+ ::std::string* name_;
+ ::google::protobuf::uint64 nameref_;
+ } EdgeNameOrRef_;
+ ::google::protobuf::uint32 _oneof_case_[1];
+
+ friend void protobuf_AddDesc_CoreDump_2eproto();
+ friend void protobuf_AssignDesc_CoreDump_2eproto();
+ friend void protobuf_ShutdownFile_CoreDump_2eproto();
+
+ void InitAsDefaultInstance();
+ static Edge* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+// Metadata
+
+// optional uint64 timeStamp = 1;
+inline bool Metadata::has_timestamp() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Metadata::set_has_timestamp() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Metadata::clear_has_timestamp() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Metadata::clear_timestamp() {
+ timestamp_ = GOOGLE_ULONGLONG(0);
+ clear_has_timestamp();
+}
+inline ::google::protobuf::uint64 Metadata::timestamp() const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Metadata.timeStamp)
+ return timestamp_;
+}
+inline void Metadata::set_timestamp(::google::protobuf::uint64 value) {
+ set_has_timestamp();
+ timestamp_ = value;
+ // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Metadata.timeStamp)
+}
+
+// -------------------------------------------------------------------
+
+// StackFrame_Data
+
+// optional uint64 id = 1;
+inline bool StackFrame_Data::has_id() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void StackFrame_Data::set_has_id() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void StackFrame_Data::clear_has_id() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void StackFrame_Data::clear_id() {
+ id_ = GOOGLE_ULONGLONG(0);
+ clear_has_id();
+}
+inline ::google::protobuf::uint64 StackFrame_Data::id() const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.id)
+ return id_;
+}
+inline void StackFrame_Data::set_id(::google::protobuf::uint64 value) {
+ set_has_id();
+ id_ = value;
+ // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.id)
+}
+
+// optional .mozilla.devtools.protobuf.StackFrame parent = 2;
+inline bool StackFrame_Data::has_parent() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void StackFrame_Data::set_has_parent() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void StackFrame_Data::clear_has_parent() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void StackFrame_Data::clear_parent() {
+ if (parent_ != NULL) parent_->::mozilla::devtools::protobuf::StackFrame::Clear();
+ clear_has_parent();
+}
+inline const ::mozilla::devtools::protobuf::StackFrame& StackFrame_Data::parent() const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.parent)
+ return parent_ != NULL ? *parent_ : *default_instance_->parent_;
+}
+inline ::mozilla::devtools::protobuf::StackFrame* StackFrame_Data::mutable_parent() {
+ set_has_parent();
+ if (parent_ == NULL) parent_ = new ::mozilla::devtools::protobuf::StackFrame;
+ // @@protoc_insertion_point(field_mutable:mozilla.devtools.protobuf.StackFrame.Data.parent)
+ return parent_;
+}
+inline ::mozilla::devtools::protobuf::StackFrame* StackFrame_Data::release_parent() {
+ clear_has_parent();
+ ::mozilla::devtools::protobuf::StackFrame* temp = parent_;
+ parent_ = NULL;
+ return temp;
+}
+inline void StackFrame_Data::set_allocated_parent(::mozilla::devtools::protobuf::StackFrame* parent) {
+ delete parent_;
+ parent_ = parent;
+ if (parent) {
+ set_has_parent();
+ } else {
+ clear_has_parent();
+ }
+ // @@protoc_insertion_point(field_set_allocated:mozilla.devtools.protobuf.StackFrame.Data.parent)
+}
+
+// optional uint32 line = 3;
+inline bool StackFrame_Data::has_line() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void StackFrame_Data::set_has_line() {
+ _has_bits_[0] |= 0x00000004u;
+}
+inline void StackFrame_Data::clear_has_line() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+inline void StackFrame_Data::clear_line() {
+ line_ = 0u;
+ clear_has_line();
+}
+inline ::google::protobuf::uint32 StackFrame_Data::line() const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.line)
+ return line_;
+}
+inline void StackFrame_Data::set_line(::google::protobuf::uint32 value) {
+ set_has_line();
+ line_ = value;
+ // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.line)
+}
+
+// optional uint32 column = 4;
+inline bool StackFrame_Data::has_column() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void StackFrame_Data::set_has_column() {
+ _has_bits_[0] |= 0x00000008u;
+}
+inline void StackFrame_Data::clear_has_column() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+inline void StackFrame_Data::clear_column() {
+ column_ = 0u;
+ clear_has_column();
+}
+inline ::google::protobuf::uint32 StackFrame_Data::column() const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.column)
+ return column_;
+}
+inline void StackFrame_Data::set_column(::google::protobuf::uint32 value) {
+ set_has_column();
+ column_ = value;
+ // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.column)
+}
+
+// optional bytes source = 5;
+inline bool StackFrame_Data::has_source() const {
+ return SourceOrRef_case() == kSource;
+}
+inline void StackFrame_Data::set_has_source() {
+ _oneof_case_[0] = kSource;
+}
+inline void StackFrame_Data::clear_source() {
+ if (has_source()) {
+ delete SourceOrRef_.source_;
+ clear_has_SourceOrRef();
+ }
+}
+inline const ::std::string& StackFrame_Data::source() const {
+ if (has_source()) {
+ return *SourceOrRef_.source_;
+ }
+ return ::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+inline void StackFrame_Data::set_source(const ::std::string& value) {
+ if (!has_source()) {
+ clear_SourceOrRef();
+ set_has_source();
+ SourceOrRef_.source_ = new ::std::string;
+ }
+ SourceOrRef_.source_->assign(value);
+}
+inline void StackFrame_Data::set_source(const char* value) {
+ if (!has_source()) {
+ clear_SourceOrRef();
+ set_has_source();
+ SourceOrRef_.source_ = new ::std::string;
+ }
+ SourceOrRef_.source_->assign(value);
+}
+inline void StackFrame_Data::set_source(const void* value, size_t size) {
+ if (!has_source()) {
+ clear_SourceOrRef();
+ set_has_source();
+ SourceOrRef_.source_ = new ::std::string;
+ }
+ SourceOrRef_.source_->assign(
+ reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* StackFrame_Data::mutable_source() {
+ if (!has_source()) {
+ clear_SourceOrRef();
+ set_has_source();
+ SourceOrRef_.source_ = new ::std::string;
+ }
+ return SourceOrRef_.source_;
+}
+inline ::std::string* StackFrame_Data::release_source() {
+ if (has_source()) {
+ clear_has_SourceOrRef();
+ ::std::string* temp = SourceOrRef_.source_;
+ SourceOrRef_.source_ = NULL;
+ return temp;
+ } else {
+ return NULL;
+ }
+}
+inline void StackFrame_Data::set_allocated_source(::std::string* source) {
+ clear_SourceOrRef();
+ if (source) {
+ set_has_source();
+ SourceOrRef_.source_ = source;
+ }
+}
+
+// optional uint64 sourceRef = 6;
+inline bool StackFrame_Data::has_sourceref() const {
+ return SourceOrRef_case() == kSourceRef;
+}
+inline void StackFrame_Data::set_has_sourceref() {
+ _oneof_case_[0] = kSourceRef;
+}
+inline void StackFrame_Data::clear_sourceref() {
+ if (has_sourceref()) {
+ SourceOrRef_.sourceref_ = GOOGLE_ULONGLONG(0);
+ clear_has_SourceOrRef();
+ }
+}
+inline ::google::protobuf::uint64 StackFrame_Data::sourceref() const {
+ if (has_sourceref()) {
+ return SourceOrRef_.sourceref_;
+ }
+ return GOOGLE_ULONGLONG(0);
+}
+inline void StackFrame_Data::set_sourceref(::google::protobuf::uint64 value) {
+ if (!has_sourceref()) {
+ clear_SourceOrRef();
+ set_has_sourceref();
+ }
+ SourceOrRef_.sourceref_ = value;
+}
+
+// optional bytes functionDisplayName = 7;
+inline bool StackFrame_Data::has_functiondisplayname() const {
+ return FunctionDisplayNameOrRef_case() == kFunctionDisplayName;
+}
+inline void StackFrame_Data::set_has_functiondisplayname() {
+ _oneof_case_[1] = kFunctionDisplayName;
+}
+inline void StackFrame_Data::clear_functiondisplayname() {
+ if (has_functiondisplayname()) {
+ delete FunctionDisplayNameOrRef_.functiondisplayname_;
+ clear_has_FunctionDisplayNameOrRef();
+ }
+}
+inline const ::std::string& StackFrame_Data::functiondisplayname() const {
+ if (has_functiondisplayname()) {
+ return *FunctionDisplayNameOrRef_.functiondisplayname_;
+ }
+ return ::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+inline void StackFrame_Data::set_functiondisplayname(const ::std::string& value) {
+ if (!has_functiondisplayname()) {
+ clear_FunctionDisplayNameOrRef();
+ set_has_functiondisplayname();
+ FunctionDisplayNameOrRef_.functiondisplayname_ = new ::std::string;
+ }
+ FunctionDisplayNameOrRef_.functiondisplayname_->assign(value);
+}
+inline void StackFrame_Data::set_functiondisplayname(const char* value) {
+ if (!has_functiondisplayname()) {
+ clear_FunctionDisplayNameOrRef();
+ set_has_functiondisplayname();
+ FunctionDisplayNameOrRef_.functiondisplayname_ = new ::std::string;
+ }
+ FunctionDisplayNameOrRef_.functiondisplayname_->assign(value);
+}
+inline void StackFrame_Data::set_functiondisplayname(const void* value, size_t size) {
+ if (!has_functiondisplayname()) {
+ clear_FunctionDisplayNameOrRef();
+ set_has_functiondisplayname();
+ FunctionDisplayNameOrRef_.functiondisplayname_ = new ::std::string;
+ }
+ FunctionDisplayNameOrRef_.functiondisplayname_->assign(
+ reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* StackFrame_Data::mutable_functiondisplayname() {
+ if (!has_functiondisplayname()) {
+ clear_FunctionDisplayNameOrRef();
+ set_has_functiondisplayname();
+ FunctionDisplayNameOrRef_.functiondisplayname_ = new ::std::string;
+ }
+ return FunctionDisplayNameOrRef_.functiondisplayname_;
+}
+inline ::std::string* StackFrame_Data::release_functiondisplayname() {
+ if (has_functiondisplayname()) {
+ clear_has_FunctionDisplayNameOrRef();
+ ::std::string* temp = FunctionDisplayNameOrRef_.functiondisplayname_;
+ FunctionDisplayNameOrRef_.functiondisplayname_ = NULL;
+ return temp;
+ } else {
+ return NULL;
+ }
+}
+inline void StackFrame_Data::set_allocated_functiondisplayname(::std::string* functiondisplayname) {
+ clear_FunctionDisplayNameOrRef();
+ if (functiondisplayname) {
+ set_has_functiondisplayname();
+ FunctionDisplayNameOrRef_.functiondisplayname_ = functiondisplayname;
+ }
+}
+
+// optional uint64 functionDisplayNameRef = 8;
+inline bool StackFrame_Data::has_functiondisplaynameref() const {
+ return FunctionDisplayNameOrRef_case() == kFunctionDisplayNameRef;
+}
+inline void StackFrame_Data::set_has_functiondisplaynameref() {
+ _oneof_case_[1] = kFunctionDisplayNameRef;
+}
+inline void StackFrame_Data::clear_functiondisplaynameref() {
+ if (has_functiondisplaynameref()) {
+ FunctionDisplayNameOrRef_.functiondisplaynameref_ = GOOGLE_ULONGLONG(0);
+ clear_has_FunctionDisplayNameOrRef();
+ }
+}
+inline ::google::protobuf::uint64 StackFrame_Data::functiondisplaynameref() const {
+ if (has_functiondisplaynameref()) {
+ return FunctionDisplayNameOrRef_.functiondisplaynameref_;
+ }
+ return GOOGLE_ULONGLONG(0);
+}
+inline void StackFrame_Data::set_functiondisplaynameref(::google::protobuf::uint64 value) {
+ if (!has_functiondisplaynameref()) {
+ clear_FunctionDisplayNameOrRef();
+ set_has_functiondisplaynameref();
+ }
+ FunctionDisplayNameOrRef_.functiondisplaynameref_ = value;
+}
+
+// optional bool isSystem = 9;
+inline bool StackFrame_Data::has_issystem() const {
+ return (_has_bits_[0] & 0x00000100u) != 0;
+}
+inline void StackFrame_Data::set_has_issystem() {
+ _has_bits_[0] |= 0x00000100u;
+}
+inline void StackFrame_Data::clear_has_issystem() {
+ _has_bits_[0] &= ~0x00000100u;
+}
+inline void StackFrame_Data::clear_issystem() {
+ issystem_ = false;
+ clear_has_issystem();
+}
+inline bool StackFrame_Data::issystem() const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.isSystem)
+ return issystem_;
+}
+inline void StackFrame_Data::set_issystem(bool value) {
+ set_has_issystem();
+ issystem_ = value;
+ // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.isSystem)
+}
+
+// optional bool isSelfHosted = 10;
+inline bool StackFrame_Data::has_isselfhosted() const {
+ return (_has_bits_[0] & 0x00000200u) != 0;
+}
+inline void StackFrame_Data::set_has_isselfhosted() {
+ _has_bits_[0] |= 0x00000200u;
+}
+inline void StackFrame_Data::clear_has_isselfhosted() {
+ _has_bits_[0] &= ~0x00000200u;
+}
+inline void StackFrame_Data::clear_isselfhosted() {
+ isselfhosted_ = false;
+ clear_has_isselfhosted();
+}
+inline bool StackFrame_Data::isselfhosted() const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.isSelfHosted)
+ return isselfhosted_;
+}
+inline void StackFrame_Data::set_isselfhosted(bool value) {
+ set_has_isselfhosted();
+ isselfhosted_ = value;
+ // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.isSelfHosted)
+}
+
+inline bool StackFrame_Data::has_SourceOrRef() {
+ return SourceOrRef_case() != SOURCEORREF_NOT_SET;
+}
+inline void StackFrame_Data::clear_has_SourceOrRef() {
+ _oneof_case_[0] = SOURCEORREF_NOT_SET;
+}
+inline bool StackFrame_Data::has_FunctionDisplayNameOrRef() {
+ return FunctionDisplayNameOrRef_case() != FUNCTIONDISPLAYNAMEORREF_NOT_SET;
+}
+inline void StackFrame_Data::clear_has_FunctionDisplayNameOrRef() {
+ _oneof_case_[1] = FUNCTIONDISPLAYNAMEORREF_NOT_SET;
+}
+inline StackFrame_Data::SourceOrRefCase StackFrame_Data::SourceOrRef_case() const {
+ return StackFrame_Data::SourceOrRefCase(_oneof_case_[0]);
+}
+inline StackFrame_Data::FunctionDisplayNameOrRefCase StackFrame_Data::FunctionDisplayNameOrRef_case() const {
+ return StackFrame_Data::FunctionDisplayNameOrRefCase(_oneof_case_[1]);
+}
+// -------------------------------------------------------------------
+
+// StackFrame
+
+// optional .mozilla.devtools.protobuf.StackFrame.Data data = 1;
+inline bool StackFrame::has_data() const {
+ return StackFrameType_case() == kData;
+}
+inline void StackFrame::set_has_data() {
+ _oneof_case_[0] = kData;
+}
+inline void StackFrame::clear_data() {
+ if (has_data()) {
+ delete StackFrameType_.data_;
+ clear_has_StackFrameType();
+ }
+}
+inline const ::mozilla::devtools::protobuf::StackFrame_Data& StackFrame::data() const {
+ return has_data() ? *StackFrameType_.data_
+ : ::mozilla::devtools::protobuf::StackFrame_Data::default_instance();
+}
+inline ::mozilla::devtools::protobuf::StackFrame_Data* StackFrame::mutable_data() {
+ if (!has_data()) {
+ clear_StackFrameType();
+ set_has_data();
+ StackFrameType_.data_ = new ::mozilla::devtools::protobuf::StackFrame_Data;
+ }
+ return StackFrameType_.data_;
+}
+inline ::mozilla::devtools::protobuf::StackFrame_Data* StackFrame::release_data() {
+ if (has_data()) {
+ clear_has_StackFrameType();
+ ::mozilla::devtools::protobuf::StackFrame_Data* temp = StackFrameType_.data_;
+ StackFrameType_.data_ = NULL;
+ return temp;
+ } else {
+ return NULL;
+ }
+}
+inline void StackFrame::set_allocated_data(::mozilla::devtools::protobuf::StackFrame_Data* data) {
+ clear_StackFrameType();
+ if (data) {
+ set_has_data();
+ StackFrameType_.data_ = data;
+ }
+}
+
+// optional uint64 ref = 2;
+inline bool StackFrame::has_ref() const {
+ return StackFrameType_case() == kRef;
+}
+inline void StackFrame::set_has_ref() {
+ _oneof_case_[0] = kRef;
+}
+inline void StackFrame::clear_ref() {
+ if (has_ref()) {
+ StackFrameType_.ref_ = GOOGLE_ULONGLONG(0);
+ clear_has_StackFrameType();
+ }
+}
+inline ::google::protobuf::uint64 StackFrame::ref() const {
+ if (has_ref()) {
+ return StackFrameType_.ref_;
+ }
+ return GOOGLE_ULONGLONG(0);
+}
+inline void StackFrame::set_ref(::google::protobuf::uint64 value) {
+ if (!has_ref()) {
+ clear_StackFrameType();
+ set_has_ref();
+ }
+ StackFrameType_.ref_ = value;
+}
+
+inline bool StackFrame::has_StackFrameType() {
+ return StackFrameType_case() != STACKFRAMETYPE_NOT_SET;
+}
+inline void StackFrame::clear_has_StackFrameType() {
+ _oneof_case_[0] = STACKFRAMETYPE_NOT_SET;
+}
+inline StackFrame::StackFrameTypeCase StackFrame::StackFrameType_case() const {
+ return StackFrame::StackFrameTypeCase(_oneof_case_[0]);
+}
+// -------------------------------------------------------------------
+
+// Node
+
+// optional uint64 id = 1;
+inline bool Node::has_id() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Node::set_has_id() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Node::clear_has_id() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Node::clear_id() {
+ id_ = GOOGLE_ULONGLONG(0);
+ clear_has_id();
+}
+inline ::google::protobuf::uint64 Node::id() const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.id)
+ return id_;
+}
+inline void Node::set_id(::google::protobuf::uint64 value) {
+ set_has_id();
+ id_ = value;
+ // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Node.id)
+}
+
+// optional bytes typeName = 2;
+inline bool Node::has_typename_() const {
+ return TypeNameOrRef_case() == kTypeName;
+}
+inline void Node::set_has_typename_() {
+ _oneof_case_[0] = kTypeName;
+}
+inline void Node::clear_typename_() {
+ if (has_typename_()) {
+ delete TypeNameOrRef_.typename__;
+ clear_has_TypeNameOrRef();
+ }
+}
+inline const ::std::string& Node::typename_() const {
+ if (has_typename_()) {
+ return *TypeNameOrRef_.typename__;
+ }
+ return ::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+inline void Node::set_typename_(const ::std::string& value) {
+ if (!has_typename_()) {
+ clear_TypeNameOrRef();
+ set_has_typename_();
+ TypeNameOrRef_.typename__ = new ::std::string;
+ }
+ TypeNameOrRef_.typename__->assign(value);
+}
+inline void Node::set_typename_(const char* value) {
+ if (!has_typename_()) {
+ clear_TypeNameOrRef();
+ set_has_typename_();
+ TypeNameOrRef_.typename__ = new ::std::string;
+ }
+ TypeNameOrRef_.typename__->assign(value);
+}
+inline void Node::set_typename_(const void* value, size_t size) {
+ if (!has_typename_()) {
+ clear_TypeNameOrRef();
+ set_has_typename_();
+ TypeNameOrRef_.typename__ = new ::std::string;
+ }
+ TypeNameOrRef_.typename__->assign(
+ reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* Node::mutable_typename_() {
+ if (!has_typename_()) {
+ clear_TypeNameOrRef();
+ set_has_typename_();
+ TypeNameOrRef_.typename__ = new ::std::string;
+ }
+ return TypeNameOrRef_.typename__;
+}
+inline ::std::string* Node::release_typename_() {
+ if (has_typename_()) {
+ clear_has_TypeNameOrRef();
+ ::std::string* temp = TypeNameOrRef_.typename__;
+ TypeNameOrRef_.typename__ = NULL;
+ return temp;
+ } else {
+ return NULL;
+ }
+}
+inline void Node::set_allocated_typename_(::std::string* typename_) {
+ clear_TypeNameOrRef();
+ if (typename_) {
+ set_has_typename_();
+ TypeNameOrRef_.typename__ = typename_;
+ }
+}
+
+// optional uint64 typeNameRef = 3;
+inline bool Node::has_typenameref() const {
+ return TypeNameOrRef_case() == kTypeNameRef;
+}
+inline void Node::set_has_typenameref() {
+ _oneof_case_[0] = kTypeNameRef;
+}
+inline void Node::clear_typenameref() {
+ if (has_typenameref()) {
+ TypeNameOrRef_.typenameref_ = GOOGLE_ULONGLONG(0);
+ clear_has_TypeNameOrRef();
+ }
+}
+inline ::google::protobuf::uint64 Node::typenameref() const {
+ if (has_typenameref()) {
+ return TypeNameOrRef_.typenameref_;
+ }
+ return GOOGLE_ULONGLONG(0);
+}
+inline void Node::set_typenameref(::google::protobuf::uint64 value) {
+ if (!has_typenameref()) {
+ clear_TypeNameOrRef();
+ set_has_typenameref();
+ }
+ TypeNameOrRef_.typenameref_ = value;
+}
+
+// optional uint64 size = 4;
+inline bool Node::has_size() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void Node::set_has_size() {
+ _has_bits_[0] |= 0x00000008u;
+}
+inline void Node::clear_has_size() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+inline void Node::clear_size() {
+ size_ = GOOGLE_ULONGLONG(0);
+ clear_has_size();
+}
+inline ::google::protobuf::uint64 Node::size() const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.size)
+ return size_;
+}
+inline void Node::set_size(::google::protobuf::uint64 value) {
+ set_has_size();
+ size_ = value;
+ // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Node.size)
+}
+
+// repeated .mozilla.devtools.protobuf.Edge edges = 5;
+inline int Node::edges_size() const {
+ return edges_.size();
+}
+inline void Node::clear_edges() {
+ edges_.Clear();
+}
+inline const ::mozilla::devtools::protobuf::Edge& Node::edges(int index) const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.edges)
+ return edges_.Get(index);
+}
+inline ::mozilla::devtools::protobuf::Edge* Node::mutable_edges(int index) {
+ // @@protoc_insertion_point(field_mutable:mozilla.devtools.protobuf.Node.edges)
+ return edges_.Mutable(index);
+}
+inline ::mozilla::devtools::protobuf::Edge* Node::add_edges() {
+ // @@protoc_insertion_point(field_add:mozilla.devtools.protobuf.Node.edges)
+ return edges_.Add();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge >&
+Node::edges() const {
+ // @@protoc_insertion_point(field_list:mozilla.devtools.protobuf.Node.edges)
+ return edges_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge >*
+Node::mutable_edges() {
+ // @@protoc_insertion_point(field_mutable_list:mozilla.devtools.protobuf.Node.edges)
+ return &edges_;
+}
+
+// optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6;
+inline bool Node::has_allocationstack() const {
+ return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void Node::set_has_allocationstack() {
+ _has_bits_[0] |= 0x00000020u;
+}
+inline void Node::clear_has_allocationstack() {
+ _has_bits_[0] &= ~0x00000020u;
+}
+inline void Node::clear_allocationstack() {
+ if (allocationstack_ != NULL) allocationstack_->::mozilla::devtools::protobuf::StackFrame::Clear();
+ clear_has_allocationstack();
+}
+inline const ::mozilla::devtools::protobuf::StackFrame& Node::allocationstack() const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.allocationStack)
+ return allocationstack_ != NULL ? *allocationstack_ : *default_instance_->allocationstack_;
+}
+inline ::mozilla::devtools::protobuf::StackFrame* Node::mutable_allocationstack() {
+ set_has_allocationstack();
+ if (allocationstack_ == NULL) allocationstack_ = new ::mozilla::devtools::protobuf::StackFrame;
+ // @@protoc_insertion_point(field_mutable:mozilla.devtools.protobuf.Node.allocationStack)
+ return allocationstack_;
+}
+inline ::mozilla::devtools::protobuf::StackFrame* Node::release_allocationstack() {
+ clear_has_allocationstack();
+ ::mozilla::devtools::protobuf::StackFrame* temp = allocationstack_;
+ allocationstack_ = NULL;
+ return temp;
+}
+inline void Node::set_allocated_allocationstack(::mozilla::devtools::protobuf::StackFrame* allocationstack) {
+ delete allocationstack_;
+ allocationstack_ = allocationstack;
+ if (allocationstack) {
+ set_has_allocationstack();
+ } else {
+ clear_has_allocationstack();
+ }
+ // @@protoc_insertion_point(field_set_allocated:mozilla.devtools.protobuf.Node.allocationStack)
+}
+
+// optional bytes jsObjectClassName = 7;
+inline bool Node::has_jsobjectclassname() const {
+ return JSObjectClassNameOrRef_case() == kJsObjectClassName;
+}
+inline void Node::set_has_jsobjectclassname() {
+ _oneof_case_[1] = kJsObjectClassName;
+}
+inline void Node::clear_jsobjectclassname() {
+ if (has_jsobjectclassname()) {
+ delete JSObjectClassNameOrRef_.jsobjectclassname_;
+ clear_has_JSObjectClassNameOrRef();
+ }
+}
+inline const ::std::string& Node::jsobjectclassname() const {
+ if (has_jsobjectclassname()) {
+ return *JSObjectClassNameOrRef_.jsobjectclassname_;
+ }
+ return ::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+inline void Node::set_jsobjectclassname(const ::std::string& value) {
+ if (!has_jsobjectclassname()) {
+ clear_JSObjectClassNameOrRef();
+ set_has_jsobjectclassname();
+ JSObjectClassNameOrRef_.jsobjectclassname_ = new ::std::string;
+ }
+ JSObjectClassNameOrRef_.jsobjectclassname_->assign(value);
+}
+inline void Node::set_jsobjectclassname(const char* value) {
+ if (!has_jsobjectclassname()) {
+ clear_JSObjectClassNameOrRef();
+ set_has_jsobjectclassname();
+ JSObjectClassNameOrRef_.jsobjectclassname_ = new ::std::string;
+ }
+ JSObjectClassNameOrRef_.jsobjectclassname_->assign(value);
+}
+inline void Node::set_jsobjectclassname(const void* value, size_t size) {
+ if (!has_jsobjectclassname()) {
+ clear_JSObjectClassNameOrRef();
+ set_has_jsobjectclassname();
+ JSObjectClassNameOrRef_.jsobjectclassname_ = new ::std::string;
+ }
+ JSObjectClassNameOrRef_.jsobjectclassname_->assign(
+ reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* Node::mutable_jsobjectclassname() {
+ if (!has_jsobjectclassname()) {
+ clear_JSObjectClassNameOrRef();
+ set_has_jsobjectclassname();
+ JSObjectClassNameOrRef_.jsobjectclassname_ = new ::std::string;
+ }
+ return JSObjectClassNameOrRef_.jsobjectclassname_;
+}
+inline ::std::string* Node::release_jsobjectclassname() {
+ if (has_jsobjectclassname()) {
+ clear_has_JSObjectClassNameOrRef();
+ ::std::string* temp = JSObjectClassNameOrRef_.jsobjectclassname_;
+ JSObjectClassNameOrRef_.jsobjectclassname_ = NULL;
+ return temp;
+ } else {
+ return NULL;
+ }
+}
+inline void Node::set_allocated_jsobjectclassname(::std::string* jsobjectclassname) {
+ clear_JSObjectClassNameOrRef();
+ if (jsobjectclassname) {
+ set_has_jsobjectclassname();
+ JSObjectClassNameOrRef_.jsobjectclassname_ = jsobjectclassname;
+ }
+}
+
+// optional uint64 jsObjectClassNameRef = 8;
+inline bool Node::has_jsobjectclassnameref() const {
+ return JSObjectClassNameOrRef_case() == kJsObjectClassNameRef;
+}
+inline void Node::set_has_jsobjectclassnameref() {
+ _oneof_case_[1] = kJsObjectClassNameRef;
+}
+inline void Node::clear_jsobjectclassnameref() {
+ if (has_jsobjectclassnameref()) {
+ JSObjectClassNameOrRef_.jsobjectclassnameref_ = GOOGLE_ULONGLONG(0);
+ clear_has_JSObjectClassNameOrRef();
+ }
+}
+inline ::google::protobuf::uint64 Node::jsobjectclassnameref() const {
+ if (has_jsobjectclassnameref()) {
+ return JSObjectClassNameOrRef_.jsobjectclassnameref_;
+ }
+ return GOOGLE_ULONGLONG(0);
+}
+inline void Node::set_jsobjectclassnameref(::google::protobuf::uint64 value) {
+ if (!has_jsobjectclassnameref()) {
+ clear_JSObjectClassNameOrRef();
+ set_has_jsobjectclassnameref();
+ }
+ JSObjectClassNameOrRef_.jsobjectclassnameref_ = value;
+}
+
+// optional uint32 coarseType = 9 [default = 0];
+inline bool Node::has_coarsetype() const {
+ return (_has_bits_[0] & 0x00000100u) != 0;
+}
+inline void Node::set_has_coarsetype() {
+ _has_bits_[0] |= 0x00000100u;
+}
+inline void Node::clear_has_coarsetype() {
+ _has_bits_[0] &= ~0x00000100u;
+}
+inline void Node::clear_coarsetype() {
+ coarsetype_ = 0u;
+ clear_has_coarsetype();
+}
+inline ::google::protobuf::uint32 Node::coarsetype() const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.coarseType)
+ return coarsetype_;
+}
+inline void Node::set_coarsetype(::google::protobuf::uint32 value) {
+ set_has_coarsetype();
+ coarsetype_ = value;
+ // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Node.coarseType)
+}
+
+// optional bytes scriptFilename = 10;
+inline bool Node::has_scriptfilename() const {
+ return ScriptFilenameOrRef_case() == kScriptFilename;
+}
+inline void Node::set_has_scriptfilename() {
+ _oneof_case_[2] = kScriptFilename;
+}
+inline void Node::clear_scriptfilename() {
+ if (has_scriptfilename()) {
+ delete ScriptFilenameOrRef_.scriptfilename_;
+ clear_has_ScriptFilenameOrRef();
+ }
+}
+inline const ::std::string& Node::scriptfilename() const {
+ if (has_scriptfilename()) {
+ return *ScriptFilenameOrRef_.scriptfilename_;
+ }
+ return ::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+inline void Node::set_scriptfilename(const ::std::string& value) {
+ if (!has_scriptfilename()) {
+ clear_ScriptFilenameOrRef();
+ set_has_scriptfilename();
+ ScriptFilenameOrRef_.scriptfilename_ = new ::std::string;
+ }
+ ScriptFilenameOrRef_.scriptfilename_->assign(value);
+}
+inline void Node::set_scriptfilename(const char* value) {
+ if (!has_scriptfilename()) {
+ clear_ScriptFilenameOrRef();
+ set_has_scriptfilename();
+ ScriptFilenameOrRef_.scriptfilename_ = new ::std::string;
+ }
+ ScriptFilenameOrRef_.scriptfilename_->assign(value);
+}
+inline void Node::set_scriptfilename(const void* value, size_t size) {
+ if (!has_scriptfilename()) {
+ clear_ScriptFilenameOrRef();
+ set_has_scriptfilename();
+ ScriptFilenameOrRef_.scriptfilename_ = new ::std::string;
+ }
+ ScriptFilenameOrRef_.scriptfilename_->assign(
+ reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* Node::mutable_scriptfilename() {
+ if (!has_scriptfilename()) {
+ clear_ScriptFilenameOrRef();
+ set_has_scriptfilename();
+ ScriptFilenameOrRef_.scriptfilename_ = new ::std::string;
+ }
+ return ScriptFilenameOrRef_.scriptfilename_;
+}
+inline ::std::string* Node::release_scriptfilename() {
+ if (has_scriptfilename()) {
+ clear_has_ScriptFilenameOrRef();
+ ::std::string* temp = ScriptFilenameOrRef_.scriptfilename_;
+ ScriptFilenameOrRef_.scriptfilename_ = NULL;
+ return temp;
+ } else {
+ return NULL;
+ }
+}
+inline void Node::set_allocated_scriptfilename(::std::string* scriptfilename) {
+ clear_ScriptFilenameOrRef();
+ if (scriptfilename) {
+ set_has_scriptfilename();
+ ScriptFilenameOrRef_.scriptfilename_ = scriptfilename;
+ }
+}
+
+// optional uint64 scriptFilenameRef = 11;
+inline bool Node::has_scriptfilenameref() const {
+ return ScriptFilenameOrRef_case() == kScriptFilenameRef;
+}
+inline void Node::set_has_scriptfilenameref() {
+ _oneof_case_[2] = kScriptFilenameRef;
+}
+inline void Node::clear_scriptfilenameref() {
+ if (has_scriptfilenameref()) {
+ ScriptFilenameOrRef_.scriptfilenameref_ = GOOGLE_ULONGLONG(0);
+ clear_has_ScriptFilenameOrRef();
+ }
+}
+inline ::google::protobuf::uint64 Node::scriptfilenameref() const {
+ if (has_scriptfilenameref()) {
+ return ScriptFilenameOrRef_.scriptfilenameref_;
+ }
+ return GOOGLE_ULONGLONG(0);
+}
+inline void Node::set_scriptfilenameref(::google::protobuf::uint64 value) {
+ if (!has_scriptfilenameref()) {
+ clear_ScriptFilenameOrRef();
+ set_has_scriptfilenameref();
+ }
+ ScriptFilenameOrRef_.scriptfilenameref_ = value;
+}
+
+inline bool Node::has_TypeNameOrRef() {
+ return TypeNameOrRef_case() != TYPENAMEORREF_NOT_SET;
+}
+inline void Node::clear_has_TypeNameOrRef() {
+ _oneof_case_[0] = TYPENAMEORREF_NOT_SET;
+}
+inline bool Node::has_JSObjectClassNameOrRef() {
+ return JSObjectClassNameOrRef_case() != JSOBJECTCLASSNAMEORREF_NOT_SET;
+}
+inline void Node::clear_has_JSObjectClassNameOrRef() {
+ _oneof_case_[1] = JSOBJECTCLASSNAMEORREF_NOT_SET;
+}
+inline bool Node::has_ScriptFilenameOrRef() {
+ return ScriptFilenameOrRef_case() != SCRIPTFILENAMEORREF_NOT_SET;
+}
+inline void Node::clear_has_ScriptFilenameOrRef() {
+ _oneof_case_[2] = SCRIPTFILENAMEORREF_NOT_SET;
+}
+inline Node::TypeNameOrRefCase Node::TypeNameOrRef_case() const {
+ return Node::TypeNameOrRefCase(_oneof_case_[0]);
+}
+inline Node::JSObjectClassNameOrRefCase Node::JSObjectClassNameOrRef_case() const {
+ return Node::JSObjectClassNameOrRefCase(_oneof_case_[1]);
+}
+inline Node::ScriptFilenameOrRefCase Node::ScriptFilenameOrRef_case() const {
+ return Node::ScriptFilenameOrRefCase(_oneof_case_[2]);
+}
+// -------------------------------------------------------------------
+
+// Edge
+
+// optional uint64 referent = 1;
+inline bool Edge::has_referent() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Edge::set_has_referent() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Edge::clear_has_referent() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Edge::clear_referent() {
+ referent_ = GOOGLE_ULONGLONG(0);
+ clear_has_referent();
+}
+inline ::google::protobuf::uint64 Edge::referent() const {
+ // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Edge.referent)
+ return referent_;
+}
+inline void Edge::set_referent(::google::protobuf::uint64 value) {
+ set_has_referent();
+ referent_ = value;
+ // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Edge.referent)
+}
+
+// optional bytes name = 2;
+inline bool Edge::has_name() const {
+ return EdgeNameOrRef_case() == kName;
+}
+inline void Edge::set_has_name() {
+ _oneof_case_[0] = kName;
+}
+inline void Edge::clear_name() {
+ if (has_name()) {
+ delete EdgeNameOrRef_.name_;
+ clear_has_EdgeNameOrRef();
+ }
+}
+inline const ::std::string& Edge::name() const {
+ if (has_name()) {
+ return *EdgeNameOrRef_.name_;
+ }
+ return ::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+inline void Edge::set_name(const ::std::string& value) {
+ if (!has_name()) {
+ clear_EdgeNameOrRef();
+ set_has_name();
+ EdgeNameOrRef_.name_ = new ::std::string;
+ }
+ EdgeNameOrRef_.name_->assign(value);
+}
+inline void Edge::set_name(const char* value) {
+ if (!has_name()) {
+ clear_EdgeNameOrRef();
+ set_has_name();
+ EdgeNameOrRef_.name_ = new ::std::string;
+ }
+ EdgeNameOrRef_.name_->assign(value);
+}
+inline void Edge::set_name(const void* value, size_t size) {
+ if (!has_name()) {
+ clear_EdgeNameOrRef();
+ set_has_name();
+ EdgeNameOrRef_.name_ = new ::std::string;
+ }
+ EdgeNameOrRef_.name_->assign(
+ reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* Edge::mutable_name() {
+ if (!has_name()) {
+ clear_EdgeNameOrRef();
+ set_has_name();
+ EdgeNameOrRef_.name_ = new ::std::string;
+ }
+ return EdgeNameOrRef_.name_;
+}
+inline ::std::string* Edge::release_name() {
+ if (has_name()) {
+ clear_has_EdgeNameOrRef();
+ ::std::string* temp = EdgeNameOrRef_.name_;
+ EdgeNameOrRef_.name_ = NULL;
+ return temp;
+ } else {
+ return NULL;
+ }
+}
+inline void Edge::set_allocated_name(::std::string* name) {
+ clear_EdgeNameOrRef();
+ if (name) {
+ set_has_name();
+ EdgeNameOrRef_.name_ = name;
+ }
+}
+
+// optional uint64 nameRef = 3;
+inline bool Edge::has_nameref() const {
+ return EdgeNameOrRef_case() == kNameRef;
+}
+inline void Edge::set_has_nameref() {
+ _oneof_case_[0] = kNameRef;
+}
+inline void Edge::clear_nameref() {
+ if (has_nameref()) {
+ EdgeNameOrRef_.nameref_ = GOOGLE_ULONGLONG(0);
+ clear_has_EdgeNameOrRef();
+ }
+}
+inline ::google::protobuf::uint64 Edge::nameref() const {
+ if (has_nameref()) {
+ return EdgeNameOrRef_.nameref_;
+ }
+ return GOOGLE_ULONGLONG(0);
+}
+inline void Edge::set_nameref(::google::protobuf::uint64 value) {
+ if (!has_nameref()) {
+ clear_EdgeNameOrRef();
+ set_has_nameref();
+ }
+ EdgeNameOrRef_.nameref_ = value;
+}
+
+inline bool Edge::has_EdgeNameOrRef() {
+ return EdgeNameOrRef_case() != EDGENAMEORREF_NOT_SET;
+}
+inline void Edge::clear_has_EdgeNameOrRef() {
+ _oneof_case_[0] = EDGENAMEORREF_NOT_SET;
+}
+inline Edge::EdgeNameOrRefCase Edge::EdgeNameOrRef_case() const {
+ return Edge::EdgeNameOrRefCase(_oneof_case_[0]);
+}
+
+// @@protoc_insertion_point(namespace_scope)
+
+} // namespace protobuf
+} // namespace devtools
+} // namespace mozilla
+
+#ifndef SWIG
+namespace google {
+namespace protobuf {
+
+
+} // namespace google
+} // namespace protobuf
+#endif // SWIG
+
+// @@protoc_insertion_point(global_scope)
+
+#endif // PROTOBUF_CoreDump_2eproto__INCLUDED
diff --git a/dom/heapsnapshot/CoreDump.proto b/dom/heapsnapshot/CoreDump.proto
new file mode 100644
index 000000000..24a223e11
--- /dev/null
+++ b/dom/heapsnapshot/CoreDump.proto
@@ -0,0 +1,143 @@
+/* -*- Mode: protobuf; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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/. */
+
+// # Core Dumps
+//
+// A core dump is a serialized snapshot of the heap graph. We serialize the heap
+// as a series of protobuf messages with each message prefixed by its Varint32
+// byte size so we can delimit individual protobuf messages (protobuf parsers
+// cannot determine where a message ends on their own).
+//
+// The first protobuf message is an instance of the `Metadata` message. All
+// subsequent messages will be instances of the `Node` message. The first of
+// these `Node` messages is the root node of the serialized heap graph. Here is
+// a diagram of our core dump format:
+//
+// +-----------------------------------------------------------------------+
+// | Varint32: The size of following `Metadata` message. |
+// +-----------------------------------------------------------------------+
+// | message: The core dump `Metadata` message. |
+// +-----------------------------------------------------------------------+
+// | Varint32: The size of the following `Node` message. |
+// +-----------------------------------------------------------------------+
+// | message: The first `Node` message. This is the root node. |
+// +-----------------------------------------------------------------------+
+// | Varint32: The size of the following `Node` message. |
+// +-----------------------------------------------------------------------+
+// | message: A `Node` message. |
+// +-----------------------------------------------------------------------+
+// | Varint32: The size of the following `Node` message. |
+// +-----------------------------------------------------------------------+
+// | message: A `Node` message. |
+// +-----------------------------------------------------------------------+
+// | . |
+// | . |
+// | . |
+// +-----------------------------------------------------------------------+
+//
+// Core dumps should always be written with a
+// `google::protobuf::io::GzipOutputStream` and read from a
+// `google::protobuf::io::GzipInputStream`.
+//
+// Note that all strings are de-duplicated. The first time the N^th unique
+// string is encountered, the full string is serialized. Subsequent times that
+// same string is encountered, it is referenced by N. This de-duplication
+// happens across string properties, not on a per-property basis. For example,
+// if the same K^th unique string is first used as an Edge::EdgeNameOrRef and
+// then as a StackFrame::Data::FunctionDisplayNameOrRef, the first will be the
+// actual string as the functionDisplayName oneof property, and the second will
+// be a reference to the first as the edgeNameRef oneof property whose value is
+// K.
+//
+// We would ordinarily abstract these de-duplicated strings with messages of
+// their own, but unfortunately, the protobuf compiler does not have a way to
+// inline a messsage within another message and the child message must be
+// referenced by pointer. This leads to extra mallocs that we wish to avoid.
+
+
+package mozilla.devtools.protobuf;
+
+// A collection of metadata about this core dump.
+message Metadata {
+ // Number of microseconds since midnight (00:00:00) 1 January 1970 UTC.
+ optional uint64 timeStamp = 1;
+}
+
+// A serialized version of `JS::ubi::StackFrame`. Older parent frame tails are
+// de-duplicated to cut down on [de]serialization and size costs.
+message StackFrame {
+ oneof StackFrameType {
+ // This is the first time this stack frame has been serialized, and so
+ // here is all of its data.
+ Data data = 1;
+ // A reference to a stack frame that has already been serialized and has
+ // the given number as its id.
+ uint64 ref = 2;
+ }
+
+ message Data {
+ optional uint64 id = 1;
+ optional StackFrame parent = 2;
+ optional uint32 line = 3;
+ optional uint32 column = 4;
+
+ // De-duplicated two-byte string.
+ oneof SourceOrRef {
+ bytes source = 5;
+ uint64 sourceRef = 6;
+ }
+
+ // De-duplicated two-byte string.
+ oneof FunctionDisplayNameOrRef {
+ bytes functionDisplayName = 7;
+ uint64 functionDisplayNameRef = 8;
+ }
+
+ optional bool isSystem = 9;
+ optional bool isSelfHosted = 10;
+ }
+}
+
+// A serialized version of `JS::ubi::Node` and its outgoing edges.
+message Node {
+ optional uint64 id = 1;
+
+ // De-duplicated two-byte string.
+ oneof TypeNameOrRef {
+ bytes typeName = 2;
+ uint64 typeNameRef = 3;
+ }
+
+ optional uint64 size = 4;
+ repeated Edge edges = 5;
+ optional StackFrame allocationStack = 6;
+
+ // De-duplicated one-byte string.
+ oneof JSObjectClassNameOrRef {
+ bytes jsObjectClassName = 7;
+ uint64 jsObjectClassNameRef = 8;
+ }
+
+ // JS::ubi::CoarseType. Defaults to Other.
+ optional uint32 coarseType = 9 [default = 0];
+
+ // De-duplicated one-byte string.
+ oneof ScriptFilenameOrRef {
+ bytes scriptFilename = 10;
+ uint64 scriptFilenameRef = 11;
+ }
+}
+
+// A serialized edge from the heap graph.
+message Edge {
+ optional uint64 referent = 1;
+
+ // De-duplicated two-byte string.
+ oneof EdgeNameOrRef {
+ bytes name = 2;
+ uint64 nameRef = 3;
+ }
+}
diff --git a/dom/heapsnapshot/DeserializedNode.cpp b/dom/heapsnapshot/DeserializedNode.cpp
new file mode 100644
index 000000000..fac4cccb9
--- /dev/null
+++ b/dom/heapsnapshot/DeserializedNode.cpp
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/devtools/DeserializedNode.h"
+#include "mozilla/devtools/HeapSnapshot.h"
+#include "nsCRTGlue.h"
+
+namespace mozilla {
+namespace devtools {
+
+DeserializedEdge::DeserializedEdge(DeserializedEdge&& rhs)
+{
+ referent = rhs.referent;
+ name = rhs.name;
+}
+
+DeserializedEdge& DeserializedEdge::operator=(DeserializedEdge&& rhs)
+{
+ MOZ_ASSERT(&rhs != this);
+ this->~DeserializedEdge();
+ new(this) DeserializedEdge(Move(rhs));
+ return *this;
+}
+
+JS::ubi::Node
+DeserializedNode::getEdgeReferent(const DeserializedEdge& edge)
+{
+ auto ptr = owner->nodes.lookup(edge.referent);
+ MOZ_ASSERT(ptr);
+
+ // `HashSets` only provide const access to their values, because mutating a
+ // value might change its hash, rendering it unfindable in the set.
+ // Unfortunately, the `ubi::Node` constructor requires a non-const pointer to
+ // its referent. However, the only aspect of a `DeserializedNode` we hash on
+ // is its id, which can't be changed via `ubi::Node`, so this cast can't cause
+ // the trouble `HashSet` is concerned a non-const reference would cause.
+ return JS::ubi::Node(const_cast<DeserializedNode*>(&*ptr));
+}
+
+JS::ubi::StackFrame
+DeserializedStackFrame::getParentStackFrame() const
+{
+ MOZ_ASSERT(parent.isSome());
+ auto ptr = owner->frames.lookup(parent.ref());
+ MOZ_ASSERT(ptr);
+ // See above comment in DeserializedNode::getEdgeReferent about why this
+ // const_cast is needed and safe.
+ return JS::ubi::StackFrame(const_cast<DeserializedStackFrame*>(&*ptr));
+}
+
+} // namespace devtools
+} // namespace mozilla
+
+namespace JS {
+namespace ubi {
+
+using mozilla::devtools::DeserializedEdge;
+
+const char16_t Concrete<DeserializedNode>::concreteTypeName[] =
+ u"mozilla::devtools::DeserializedNode";
+
+const char16_t*
+Concrete<DeserializedNode>::typeName() const
+{
+ return get().typeName;
+}
+
+Node::Size
+Concrete<DeserializedNode>::size(mozilla::MallocSizeOf mallocSizeof) const
+{
+ return get().size;
+}
+
+class DeserializedEdgeRange : public EdgeRange
+{
+ DeserializedNode* node;
+ Edge currentEdge;
+ size_t i;
+
+ void settle() {
+ if (i >= node->edges.length()) {
+ front_ = nullptr;
+ return;
+ }
+
+ auto& edge = node->edges[i];
+ auto referent = node->getEdgeReferent(edge);
+ currentEdge = mozilla::Move(Edge(edge.name ? NS_strdup(edge.name) : nullptr,
+ referent));
+ front_ = &currentEdge;
+ }
+
+public:
+ explicit DeserializedEdgeRange(DeserializedNode& node)
+ : node(&node)
+ , i(0)
+ {
+ settle();
+ }
+
+ void popFront() override
+ {
+ i++;
+ settle();
+ }
+};
+
+StackFrame
+Concrete<DeserializedNode>::allocationStack() const
+{
+ MOZ_ASSERT(hasAllocationStack());
+ auto id = get().allocationStack.ref();
+ auto ptr = get().owner->frames.lookup(id);
+ MOZ_ASSERT(ptr);
+ // See above comment in DeserializedNode::getEdgeReferent about why this
+ // const_cast is needed and safe.
+ return JS::ubi::StackFrame(const_cast<DeserializedStackFrame*>(&*ptr));
+}
+
+
+js::UniquePtr<EdgeRange>
+Concrete<DeserializedNode>::edges(JSContext* cx, bool) const
+{
+ js::UniquePtr<DeserializedEdgeRange> range(js_new<DeserializedEdgeRange>(get()));
+
+ if (!range)
+ return nullptr;
+
+ return js::UniquePtr<EdgeRange>(range.release());
+}
+
+StackFrame
+ConcreteStackFrame<DeserializedStackFrame>::parent() const
+{
+ return get().parent.isNothing() ? StackFrame() : get().getParentStackFrame();
+}
+
+bool
+ConcreteStackFrame<DeserializedStackFrame>::constructSavedFrameStack(
+ JSContext* cx,
+ MutableHandleObject outSavedFrameStack) const
+{
+ StackFrame f(&get());
+ return ConstructSavedFrameStackSlow(cx, f, outSavedFrameStack);
+}
+
+} // namespace ubi
+} // namespace JS
diff --git a/dom/heapsnapshot/DeserializedNode.h b/dom/heapsnapshot/DeserializedNode.h
new file mode 100644
index 000000000..60d1fb408
--- /dev/null
+++ b/dom/heapsnapshot/DeserializedNode.h
@@ -0,0 +1,317 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_devtools_DeserializedNode__
+#define mozilla_devtools_DeserializedNode__
+
+#include "js/UbiNode.h"
+#include "js/UniquePtr.h"
+#include "mozilla/devtools/CoreDump.pb.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/Move.h"
+#include "mozilla/Vector.h"
+
+// `Deserialized{Node,Edge}` translate protobuf messages from our core dump
+// format into structures we can rely upon for implementing `JS::ubi::Node`
+// specializations on top of. All of the properties of the protobuf messages are
+// optional for future compatibility, and this is the layer where we validate
+// that the properties that do actually exist in any given message fulfill our
+// semantic requirements.
+//
+// Both `DeserializedNode` and `DeserializedEdge` are always owned by a
+// `HeapSnapshot` instance, and their lifetimes must not extend after that of
+// their owning `HeapSnapshot`.
+
+namespace mozilla {
+namespace devtools {
+
+class HeapSnapshot;
+
+using NodeId = uint64_t;
+using StackFrameId = uint64_t;
+
+// A `DeserializedEdge` represents an edge in the heap graph pointing to the
+// node with id equal to `DeserializedEdge::referent` that we deserialized from
+// a core dump.
+struct DeserializedEdge {
+ NodeId referent;
+ // A borrowed reference to a string owned by this node's owning HeapSnapshot.
+ const char16_t* name;
+
+ explicit DeserializedEdge(NodeId referent, const char16_t* edgeName = nullptr)
+ : referent(referent)
+ , name(edgeName)
+ { }
+ DeserializedEdge(DeserializedEdge&& rhs);
+ DeserializedEdge& operator=(DeserializedEdge&& rhs);
+
+private:
+ DeserializedEdge(const DeserializedEdge&) = delete;
+ DeserializedEdge& operator=(const DeserializedEdge&) = delete;
+};
+
+// A `DeserializedNode` is a node in the heap graph that we deserialized from a
+// core dump.
+struct DeserializedNode {
+ using EdgeVector = Vector<DeserializedEdge>;
+ using UniqueStringPtr = UniquePtr<char16_t[]>;
+
+ NodeId id;
+ JS::ubi::CoarseType coarseType;
+ // A borrowed reference to a string owned by this node's owning HeapSnapshot.
+ const char16_t* typeName;
+ uint64_t size;
+ EdgeVector edges;
+ Maybe<StackFrameId> allocationStack;
+ // A borrowed reference to a string owned by this node's owning HeapSnapshot.
+ const char* jsObjectClassName;
+ // A borrowed reference to a string owned by this node's owning HeapSnapshot.
+ const char* scriptFilename;
+ // A weak pointer to this node's owning `HeapSnapshot`. Safe without
+ // AddRef'ing because this node's lifetime is equal to that of its owner.
+ HeapSnapshot* owner;
+
+ DeserializedNode(NodeId id,
+ JS::ubi::CoarseType coarseType,
+ const char16_t* typeName,
+ uint64_t size,
+ EdgeVector&& edges,
+ Maybe<StackFrameId> allocationStack,
+ const char* className,
+ const char* filename,
+ HeapSnapshot& owner)
+ : id(id)
+ , coarseType(coarseType)
+ , typeName(typeName)
+ , size(size)
+ , edges(Move(edges))
+ , allocationStack(allocationStack)
+ , jsObjectClassName(className)
+ , scriptFilename(filename)
+ , owner(&owner)
+ { }
+ virtual ~DeserializedNode() { }
+
+ DeserializedNode(DeserializedNode&& rhs)
+ : id(rhs.id)
+ , coarseType(rhs.coarseType)
+ , typeName(rhs.typeName)
+ , size(rhs.size)
+ , edges(Move(rhs.edges))
+ , allocationStack(rhs.allocationStack)
+ , jsObjectClassName(rhs.jsObjectClassName)
+ , scriptFilename(rhs.scriptFilename)
+ , owner(rhs.owner)
+ { }
+
+ DeserializedNode& operator=(DeserializedNode&& rhs)
+ {
+ MOZ_ASSERT(&rhs != this);
+ this->~DeserializedNode();
+ new(this) DeserializedNode(Move(rhs));
+ return *this;
+ }
+
+ // Get a borrowed reference to the given edge's referent. This method is
+ // virtual to provide a hook for gmock and gtest.
+ virtual JS::ubi::Node getEdgeReferent(const DeserializedEdge& edge);
+
+ struct HashPolicy;
+
+protected:
+ // This is only for use with `MockDeserializedNode` in testing.
+ DeserializedNode(NodeId id, const char16_t* typeName, uint64_t size)
+ : id(id)
+ , coarseType(JS::ubi::CoarseType::Other)
+ , typeName(typeName)
+ , size(size)
+ , edges()
+ , allocationStack(Nothing())
+ , jsObjectClassName(nullptr)
+ , scriptFilename(nullptr)
+ , owner(nullptr)
+ { }
+
+private:
+ DeserializedNode(const DeserializedNode&) = delete;
+ DeserializedNode& operator=(const DeserializedNode&) = delete;
+};
+
+static inline js::HashNumber
+hashIdDerivedFromPtr(uint64_t id)
+{
+ // NodeIds and StackFrameIds are always 64 bits, but they are derived from
+ // the original referents' addresses, which could have been either 32 or 64
+ // bits long. As such, NodeId and StackFrameId have little entropy in their
+ // bottom three bits, and may or may not have entropy in their upper 32
+ // bits. This hash should manage both cases well.
+ id >>= 3;
+ return js::HashNumber((id >> 32) ^ id);
+}
+
+struct DeserializedNode::HashPolicy
+{
+ using Lookup = NodeId;
+
+ static js::HashNumber hash(const Lookup& lookup) {
+ return hashIdDerivedFromPtr(lookup);
+ }
+
+ static bool match(const DeserializedNode& existing, const Lookup& lookup) {
+ return existing.id == lookup;
+ }
+};
+
+// A `DeserializedStackFrame` is a stack frame referred to by a thing in the
+// heap graph that we deserialized from a core dump.
+struct DeserializedStackFrame {
+ StackFrameId id;
+ Maybe<StackFrameId> parent;
+ uint32_t line;
+ uint32_t column;
+ // Borrowed references to strings owned by this DeserializedStackFrame's
+ // owning HeapSnapshot.
+ const char16_t* source;
+ const char16_t* functionDisplayName;
+ bool isSystem;
+ bool isSelfHosted;
+ // A weak pointer to this frame's owning `HeapSnapshot`. Safe without
+ // AddRef'ing because this frame's lifetime is equal to that of its owner.
+ HeapSnapshot* owner;
+
+ explicit DeserializedStackFrame(StackFrameId id,
+ const Maybe<StackFrameId>& parent,
+ uint32_t line,
+ uint32_t column,
+ const char16_t* source,
+ const char16_t* functionDisplayName,
+ bool isSystem,
+ bool isSelfHosted,
+ HeapSnapshot& owner)
+ : id(id)
+ , parent(parent)
+ , line(line)
+ , column(column)
+ , source(source)
+ , functionDisplayName(functionDisplayName)
+ , isSystem(isSystem)
+ , isSelfHosted(isSelfHosted)
+ , owner(&owner)
+ {
+ MOZ_ASSERT(source);
+ }
+
+ JS::ubi::StackFrame getParentStackFrame() const;
+
+ struct HashPolicy;
+
+protected:
+ // This is exposed only for MockDeserializedStackFrame in the gtests.
+ explicit DeserializedStackFrame()
+ : id(0)
+ , parent(Nothing())
+ , line(0)
+ , column(0)
+ , source(nullptr)
+ , functionDisplayName(nullptr)
+ , isSystem(false)
+ , isSelfHosted(false)
+ , owner(nullptr)
+ { };
+};
+
+struct DeserializedStackFrame::HashPolicy {
+ using Lookup = StackFrameId;
+
+ static js::HashNumber hash(const Lookup& lookup) {
+ return hashIdDerivedFromPtr(lookup);
+ }
+
+ static bool match(const DeserializedStackFrame& existing, const Lookup& lookup) {
+ return existing.id == lookup;
+ }
+};
+
+} // namespace devtools
+} // namespace mozilla
+
+namespace JS {
+namespace ubi {
+
+using mozilla::devtools::DeserializedNode;
+using mozilla::devtools::DeserializedStackFrame;
+
+template<>
+class Concrete<DeserializedNode> : public Base
+{
+protected:
+ explicit Concrete(DeserializedNode* ptr) : Base(ptr) { }
+ DeserializedNode& get() const {
+ return *static_cast<DeserializedNode*>(ptr);
+ }
+
+public:
+ static void construct(void* storage, DeserializedNode* ptr) {
+ new (storage) Concrete(ptr);
+ }
+
+ CoarseType coarseType() const final { return get().coarseType; }
+ Id identifier() const override { return get().id; }
+ bool isLive() const override { return false; }
+ const char16_t* typeName() const override;
+ Node::Size size(mozilla::MallocSizeOf mallocSizeof) const override;
+ const char* jsObjectClassName() const override { return get().jsObjectClassName; }
+ const char* scriptFilename() const final { return get().scriptFilename; }
+
+ bool hasAllocationStack() const override { return get().allocationStack.isSome(); }
+ StackFrame allocationStack() const override;
+
+ // We ignore the `bool wantNames` parameter because we can't control whether
+ // the core dump was serialized with edge names or not.
+ js::UniquePtr<EdgeRange> edges(JSContext* cx, bool) const override;
+
+ static const char16_t concreteTypeName[];
+};
+
+template<>
+class ConcreteStackFrame<DeserializedStackFrame> : public BaseStackFrame
+{
+protected:
+ explicit ConcreteStackFrame(DeserializedStackFrame* ptr)
+ : BaseStackFrame(ptr)
+ { }
+
+ DeserializedStackFrame& get() const {
+ return *static_cast<DeserializedStackFrame*>(ptr);
+ }
+
+public:
+ static void construct(void* storage, DeserializedStackFrame* ptr) {
+ new (storage) ConcreteStackFrame(ptr);
+ }
+
+ uint64_t identifier() const override { return get().id; }
+ uint32_t line() const override { return get().line; }
+ uint32_t column() const override { return get().column; }
+ bool isSystem() const override { return get().isSystem; }
+ bool isSelfHosted(JSContext* cx) const override { return get().isSelfHosted; }
+ void trace(JSTracer* trc) override { }
+ AtomOrTwoByteChars source() const override {
+ return AtomOrTwoByteChars(get().source);
+ }
+ AtomOrTwoByteChars functionDisplayName() const override {
+ return AtomOrTwoByteChars(get().functionDisplayName);
+ }
+
+ StackFrame parent() const override;
+ bool constructSavedFrameStack(JSContext* cx,
+ MutableHandleObject outSavedFrameStack)
+ const override;
+};
+
+} // namespace ubi
+} // namespace JS
+
+#endif // mozilla_devtools_DeserializedNode__
diff --git a/dom/heapsnapshot/DominatorTree.cpp b/dom/heapsnapshot/DominatorTree.cpp
new file mode 100644
index 000000000..e53c196cf
--- /dev/null
+++ b/dom/heapsnapshot/DominatorTree.cpp
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/devtools/DominatorTree.h"
+#include "mozilla/dom/DominatorTreeBinding.h"
+
+namespace mozilla {
+namespace devtools {
+
+dom::Nullable<uint64_t>
+DominatorTree::GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv)
+{
+ JS::ubi::Node::Id id(aNodeId);
+ auto node = mHeapSnapshot->getNodeById(id);
+ if (node.isNothing())
+ return dom::Nullable<uint64_t>();
+
+ auto mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf();
+ JS::ubi::Node::Size size = 0;
+ if (!mDominatorTree.getRetainedSize(*node, mallocSizeOf, size)) {
+ aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return dom::Nullable<uint64_t>();
+ }
+
+ MOZ_ASSERT(size != 0,
+ "The node should not have been unknown since we got it from the heap snapshot.");
+ return dom::Nullable<uint64_t>(size);
+}
+
+struct NodeAndRetainedSize
+{
+ JS::ubi::Node mNode;
+ JS::ubi::Node::Size mSize;
+
+ NodeAndRetainedSize(const JS::ubi::Node& aNode, JS::ubi::Node::Size aSize)
+ : mNode(aNode)
+ , mSize(aSize)
+ { }
+
+ struct Comparator
+ {
+ static bool
+ Equals(const NodeAndRetainedSize& aLhs, const NodeAndRetainedSize& aRhs)
+ {
+ return aLhs.mSize == aRhs.mSize;
+ }
+
+ static bool
+ LessThan(const NodeAndRetainedSize& aLhs, const NodeAndRetainedSize& aRhs)
+ {
+ // Use > because we want to sort from greatest to least retained size.
+ return aLhs.mSize > aRhs.mSize;
+ }
+ };
+};
+
+void
+DominatorTree::GetImmediatelyDominated(uint64_t aNodeId,
+ dom::Nullable<nsTArray<uint64_t>>& aOutResult,
+ ErrorResult& aRv)
+{
+ MOZ_ASSERT(aOutResult.IsNull());
+
+ JS::ubi::Node::Id id(aNodeId);
+ Maybe<JS::ubi::Node> node = mHeapSnapshot->getNodeById(id);
+ if (node.isNothing())
+ return;
+
+ // Get all immediately dominated nodes and their retained sizes.
+ MallocSizeOf mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf();
+ Maybe<JS::ubi::DominatorTree::DominatedSetRange> range = mDominatorTree.getDominatedSet(*node);
+ MOZ_ASSERT(range.isSome(), "The node should be known, since we got it from the heap snapshot.");
+ size_t length = range->length();
+ nsTArray<NodeAndRetainedSize> dominatedNodes(length);
+ for (const JS::ubi::Node& dominatedNode : *range) {
+ JS::ubi::Node::Size retainedSize = 0;
+ if (NS_WARN_IF(!mDominatorTree.getRetainedSize(dominatedNode, mallocSizeOf, retainedSize))) {
+ aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+ MOZ_ASSERT(retainedSize != 0,
+ "retainedSize should not be zero since we know the node is in the dominator tree.");
+
+ dominatedNodes.AppendElement(NodeAndRetainedSize(dominatedNode, retainedSize));
+ }
+
+ // Sort them by retained size.
+ NodeAndRetainedSize::Comparator comparator;
+ dominatedNodes.Sort(comparator);
+
+ // Fill the result with the nodes' ids.
+ JS::ubi::Node root = mDominatorTree.root();
+ aOutResult.SetValue(nsTArray<uint64_t>(length));
+ for (const NodeAndRetainedSize& entry : dominatedNodes) {
+ // The root dominates itself, but we don't want to expose that to JS.
+ if (entry.mNode == root)
+ continue;
+
+ aOutResult.Value().AppendElement(entry.mNode.identifier());
+ }
+}
+
+dom::Nullable<uint64_t>
+DominatorTree::GetImmediateDominator(uint64_t aNodeId) const
+{
+ JS::ubi::Node::Id id(aNodeId);
+ Maybe<JS::ubi::Node> node = mHeapSnapshot->getNodeById(id);
+ if (node.isNothing())
+ return dom::Nullable<uint64_t>();
+
+ JS::ubi::Node dominator = mDominatorTree.getImmediateDominator(*node);
+ if (!dominator || dominator == *node)
+ return dom::Nullable<uint64_t>();
+
+ return dom::Nullable<uint64_t>(dominator.identifier());
+}
+
+
+/*** Cycle Collection Boilerplate *****************************************************************/
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DominatorTree, mParent, mHeapSnapshot)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DominatorTree)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DominatorTree)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DominatorTree)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+/* virtual */ JSObject*
+DominatorTree::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
+{
+ return dom::DominatorTreeBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace devtools
+} // namespace mozilla
diff --git a/dom/heapsnapshot/DominatorTree.h b/dom/heapsnapshot/DominatorTree.h
new file mode 100644
index 000000000..f785d4916
--- /dev/null
+++ b/dom/heapsnapshot/DominatorTree.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_devtools_DominatorTree__
+#define mozilla_devtools_DominatorTree__
+
+#include "mozilla/devtools/HeapSnapshot.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/RefCounted.h"
+#include "js/UbiNodeDominatorTree.h"
+#include "nsWrapperCache.h"
+
+namespace mozilla {
+namespace devtools {
+
+class DominatorTree final : public nsISupports
+ , public nsWrapperCache
+{
+protected:
+ nsCOMPtr<nsISupports> mParent;
+
+ virtual ~DominatorTree() { }
+
+private:
+ JS::ubi::DominatorTree mDominatorTree;
+ RefPtr<HeapSnapshot> mHeapSnapshot;
+
+public:
+ explicit DominatorTree(JS::ubi::DominatorTree&& aDominatorTree, HeapSnapshot* aHeapSnapshot,
+ nsISupports* aParent)
+ : mParent(aParent)
+ , mDominatorTree(Move(aDominatorTree))
+ , mHeapSnapshot(aHeapSnapshot)
+ {
+ MOZ_ASSERT(aParent);
+ MOZ_ASSERT(aHeapSnapshot);
+ };
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS;
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DominatorTree);
+
+ nsISupports* GetParentObject() const { return mParent; }
+
+ virtual JSObject* WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) override;
+
+ // readonly attribute NodeId root
+ uint64_t Root() const { return mDominatorTree.root().identifier(); }
+
+ // [Throws] NodeSize getRetainedSize(NodeId node)
+ dom::Nullable<uint64_t> GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv);
+
+ // [Throws] sequence<NodeId>? getImmediatelyDominated(NodeId node);
+ void GetImmediatelyDominated(uint64_t aNodeId, dom::Nullable<nsTArray<uint64_t>>& aOutDominated,
+ ErrorResult& aRv);
+
+ // NodeId? getImmediateDominator(NodeId node);
+ dom::Nullable<uint64_t> GetImmediateDominator(uint64_t aNodeId) const;
+};
+
+} // namespace devtools
+} // namespace mozilla
+
+#endif // mozilla_devtools_DominatorTree__
diff --git a/dom/heapsnapshot/FileDescriptorOutputStream.cpp b/dom/heapsnapshot/FileDescriptorOutputStream.cpp
new file mode 100644
index 000000000..72a289558
--- /dev/null
+++ b/dom/heapsnapshot/FileDescriptorOutputStream.cpp
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/devtools/FileDescriptorOutputStream.h"
+#include "private/pprio.h"
+
+namespace mozilla {
+namespace devtools {
+
+/* static */ already_AddRefed<FileDescriptorOutputStream>
+FileDescriptorOutputStream::Create(const ipc::FileDescriptor& fileDescriptor)
+{
+ if (NS_WARN_IF(!fileDescriptor.IsValid()))
+ return nullptr;
+
+ auto rawFD = fileDescriptor.ClonePlatformHandle();
+ PRFileDesc* prfd = PR_ImportFile(PROsfd(rawFD.release()));
+ if (NS_WARN_IF(!prfd))
+ return nullptr;
+
+ RefPtr<FileDescriptorOutputStream> stream = new FileDescriptorOutputStream(prfd);
+ return stream.forget();
+}
+
+NS_IMPL_ISUPPORTS(FileDescriptorOutputStream, nsIOutputStream);
+
+NS_IMETHODIMP
+FileDescriptorOutputStream::Close()
+{
+ // Repeatedly closing is idempotent.
+ if (!fd)
+ return NS_OK;
+
+ if (PR_Close(fd) != PR_SUCCESS)
+ return NS_ERROR_FAILURE;
+ fd = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+FileDescriptorOutputStream::Write(const char* buf, uint32_t count, uint32_t* retval)
+{
+ if (NS_WARN_IF(!fd))
+ return NS_ERROR_FAILURE;
+
+ auto written = PR_Write(fd, buf, count);
+ if (written < 0)
+ return NS_ERROR_FAILURE;
+ *retval = written;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+FileDescriptorOutputStream::Flush()
+{
+ if (NS_WARN_IF(!fd))
+ return NS_ERROR_FAILURE;
+
+ return PR_Sync(fd) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+FileDescriptorOutputStream::WriteFrom(nsIInputStream* fromStream, uint32_t count,
+ uint32_t* retval)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+FileDescriptorOutputStream::WriteSegments(nsReadSegmentFun reader, void* closure,
+ uint32_t count, uint32_t* retval)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+FileDescriptorOutputStream::IsNonBlocking(bool* retval)
+{
+ *retval = false;
+ return NS_OK;
+}
+
+} // namespace devtools
+} // namespace mozilla
diff --git a/dom/heapsnapshot/FileDescriptorOutputStream.h b/dom/heapsnapshot/FileDescriptorOutputStream.h
new file mode 100644
index 000000000..6990f1fc3
--- /dev/null
+++ b/dom/heapsnapshot/FileDescriptorOutputStream.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_devtools_FileDescriptorOutputStream_h
+#define mozilla_devtools_FileDescriptorOutputStream_h
+
+#include <prio.h>
+
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/ipc/FileDescriptor.h"
+#include "nsIOutputStream.h"
+
+namespace mozilla {
+namespace devtools {
+
+class FileDescriptorOutputStream final : public nsIOutputStream
+{
+private:
+ PRFileDesc* fd;
+
+public:
+ static already_AddRefed<FileDescriptorOutputStream>
+ Create(const ipc::FileDescriptor& fileDescriptor);
+
+private:
+ explicit FileDescriptorOutputStream(PRFileDesc* prfd)
+ : fd(prfd)
+ { }
+
+ virtual ~FileDescriptorOutputStream() { }
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIOUTPUTSTREAM
+};
+
+} // namespace devtools
+} // namespace mozilla
+
+#endif // mozilla_devtools_FileDescriptorOutputStream_h
diff --git a/dom/heapsnapshot/HeapSnapshot.cpp b/dom/heapsnapshot/HeapSnapshot.cpp
new file mode 100644
index 000000000..299a96a9c
--- /dev/null
+++ b/dom/heapsnapshot/HeapSnapshot.cpp
@@ -0,0 +1,1619 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "HeapSnapshot.h"
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/gzip_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+
+#include "js/Debug.h"
+#include "js/TypeDecls.h"
+#include "js/UbiNodeBreadthFirst.h"
+#include "js/UbiNodeCensus.h"
+#include "js/UbiNodeDominatorTree.h"
+#include "js/UbiNodeShortestPaths.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/CycleCollectedJSContext.h"
+#include "mozilla/devtools/AutoMemMap.h"
+#include "mozilla/devtools/CoreDump.pb.h"
+#include "mozilla/devtools/DeserializedNode.h"
+#include "mozilla/devtools/DominatorTree.h"
+#include "mozilla/devtools/FileDescriptorOutputStream.h"
+#include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
+#include "mozilla/devtools/ZeroCopyNSIOutputStream.h"
+#include "mozilla/dom/ChromeUtils.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/HeapSnapshotBinding.h"
+#include "mozilla/RangedPtr.h"
+#include "mozilla/Unused.h"
+
+#include "jsapi.h"
+#include "jsfriendapi.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsCRTGlue.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsIFile.h"
+#include "nsIOutputStream.h"
+#include "nsISupportsImpl.h"
+#include "nsNetUtil.h"
+#include "nsPrintfCString.h"
+#include "prerror.h"
+#include "prio.h"
+#include "prtypes.h"
+
+namespace mozilla {
+namespace devtools {
+
+using namespace JS;
+using namespace dom;
+
+using ::google::protobuf::io::ArrayInputStream;
+using ::google::protobuf::io::CodedInputStream;
+using ::google::protobuf::io::GzipInputStream;
+using ::google::protobuf::io::ZeroCopyInputStream;
+
+using JS::ubi::AtomOrTwoByteChars;
+using JS::ubi::ShortestPaths;
+
+MallocSizeOf
+GetCurrentThreadDebuggerMallocSizeOf()
+{
+ auto ccjscx = CycleCollectedJSContext::Get();
+ MOZ_ASSERT(ccjscx);
+ auto cx = ccjscx->Context();
+ MOZ_ASSERT(cx);
+ auto mallocSizeOf = JS::dbg::GetDebuggerMallocSizeOf(cx);
+ MOZ_ASSERT(mallocSizeOf);
+ return mallocSizeOf;
+}
+
+/*** Cycle Collection Boilerplate *****************************************************************/
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HeapSnapshot, mParent)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(HeapSnapshot)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(HeapSnapshot)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HeapSnapshot)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+/* virtual */ JSObject*
+HeapSnapshot::WrapObject(JSContext* aCx, HandleObject aGivenProto)
+{
+ return HeapSnapshotBinding::Wrap(aCx, this, aGivenProto);
+}
+
+/*** Reading Heap Snapshots ***********************************************************************/
+
+/* static */ already_AddRefed<HeapSnapshot>
+HeapSnapshot::Create(JSContext* cx,
+ GlobalObject& global,
+ const uint8_t* buffer,
+ uint32_t size,
+ ErrorResult& rv)
+{
+ RefPtr<HeapSnapshot> snapshot = new HeapSnapshot(cx, global.GetAsSupports());
+ if (!snapshot->init(cx, buffer, size)) {
+ rv.Throw(NS_ERROR_UNEXPECTED);
+ return nullptr;
+ }
+ return snapshot.forget();
+}
+
+template<typename MessageType>
+static bool
+parseMessage(ZeroCopyInputStream& stream, uint32_t sizeOfMessage, MessageType& message)
+{
+ // We need to create a new `CodedInputStream` for each message so that the
+ // 64MB limit is applied per-message rather than to the whole stream.
+ CodedInputStream codedStream(&stream);
+
+ // The protobuf message nesting that core dumps exhibit is dominated by
+ // allocation stacks' frames. In the most deeply nested case, each frame has
+ // two messages: a StackFrame message and a StackFrame::Data message. These
+ // frames are on top of a small constant of other messages. There are a
+ // MAX_STACK_DEPTH number of frames, so we multiply this by 3 to make room for
+ // the two messages per frame plus some head room for the constant number of
+ // non-dominating messages.
+ codedStream.SetRecursionLimit(HeapSnapshot::MAX_STACK_DEPTH * 3);
+
+ auto limit = codedStream.PushLimit(sizeOfMessage);
+ if (NS_WARN_IF(!message.ParseFromCodedStream(&codedStream)) ||
+ NS_WARN_IF(!codedStream.ConsumedEntireMessage()) ||
+ NS_WARN_IF(codedStream.BytesUntilLimit() != 0))
+ {
+ return false;
+ }
+
+ codedStream.PopLimit(limit);
+ return true;
+}
+
+template<typename CharT, typename InternedStringSet>
+struct GetOrInternStringMatcher
+{
+ InternedStringSet& internedStrings;
+
+ explicit GetOrInternStringMatcher(InternedStringSet& strings) : internedStrings(strings) { }
+
+ const CharT* match(const std::string* str) {
+ MOZ_ASSERT(str);
+ size_t length = str->length() / sizeof(CharT);
+ auto tempString = reinterpret_cast<const CharT*>(str->data());
+
+ UniquePtr<CharT[], NSFreePolicy> owned(NS_strndup(tempString, length));
+ if (!owned || !internedStrings.append(Move(owned)))
+ return nullptr;
+
+ return internedStrings.back().get();
+ }
+
+ const CharT* match(uint64_t ref) {
+ if (MOZ_LIKELY(ref < internedStrings.length())) {
+ auto& string = internedStrings[ref];
+ MOZ_ASSERT(string);
+ return string.get();
+ }
+
+ return nullptr;
+ }
+};
+
+template<
+ // Either char or char16_t.
+ typename CharT,
+ // A reference to either `internedOneByteStrings` or `internedTwoByteStrings`
+ // if CharT is char or char16_t respectively.
+ typename InternedStringSet>
+const CharT*
+HeapSnapshot::getOrInternString(InternedStringSet& internedStrings,
+ Maybe<StringOrRef>& maybeStrOrRef)
+{
+ // Incomplete message: has neither a string nor a reference to an already
+ // interned string.
+ if (MOZ_UNLIKELY(maybeStrOrRef.isNothing()))
+ return nullptr;
+
+ GetOrInternStringMatcher<CharT, InternedStringSet> m(internedStrings);
+ return maybeStrOrRef->match(m);
+}
+
+// Get a de-duplicated string as a Maybe<StringOrRef> from the given `msg`.
+#define GET_STRING_OR_REF_WITH_PROP_NAMES(msg, strPropertyName, refPropertyName) \
+ (msg.has_##refPropertyName() \
+ ? Some(StringOrRef(msg.refPropertyName())) \
+ : msg.has_##strPropertyName() \
+ ? Some(StringOrRef(&msg.strPropertyName())) \
+ : Nothing())
+
+#define GET_STRING_OR_REF(msg, property) \
+ (msg.has_##property##ref() \
+ ? Some(StringOrRef(msg.property##ref())) \
+ : msg.has_##property() \
+ ? Some(StringOrRef(&msg.property())) \
+ : Nothing())
+
+bool
+HeapSnapshot::saveNode(const protobuf::Node& node, NodeIdSet& edgeReferents)
+{
+ // NB: de-duplicated string properties must be read back and interned in the
+ // same order here as they are written and serialized in
+ // `CoreDumpWriter::writeNode` or else indices in references to already
+ // serialized strings will be off.
+
+ if (NS_WARN_IF(!node.has_id()))
+ return false;
+ NodeId id = node.id();
+
+ // NodeIds are derived from pointers (at most 48 bits) and we rely on them
+ // fitting into JS numbers (IEEE 754 doubles, can precisely store 53 bit
+ // integers) despite storing them on disk as 64 bit integers.
+ if (NS_WARN_IF(!JS::Value::isNumberRepresentable(id)))
+ return false;
+
+ // Should only deserialize each node once.
+ if (NS_WARN_IF(nodes.has(id)))
+ return false;
+
+ if (NS_WARN_IF(!JS::ubi::Uint32IsValidCoarseType(node.coarsetype())))
+ return false;
+ auto coarseType = JS::ubi::Uint32ToCoarseType(node.coarsetype());
+
+ Maybe<StringOrRef> typeNameOrRef = GET_STRING_OR_REF_WITH_PROP_NAMES(node, typename_, typenameref);
+ auto typeName = getOrInternString<char16_t>(internedTwoByteStrings, typeNameOrRef);
+ if (NS_WARN_IF(!typeName))
+ return false;
+
+ if (NS_WARN_IF(!node.has_size()))
+ return false;
+ uint64_t size = node.size();
+
+ auto edgesLength = node.edges_size();
+ DeserializedNode::EdgeVector edges;
+ if (NS_WARN_IF(!edges.reserve(edgesLength)))
+ return false;
+ for (decltype(edgesLength) i = 0; i < edgesLength; i++) {
+ auto& protoEdge = node.edges(i);
+
+ if (NS_WARN_IF(!protoEdge.has_referent()))
+ return false;
+ NodeId referent = protoEdge.referent();
+
+ if (NS_WARN_IF(!edgeReferents.put(referent)))
+ return false;
+
+ const char16_t* edgeName = nullptr;
+ if (protoEdge.EdgeNameOrRef_case() != protobuf::Edge::EDGENAMEORREF_NOT_SET) {
+ Maybe<StringOrRef> edgeNameOrRef = GET_STRING_OR_REF(protoEdge, name);
+ edgeName = getOrInternString<char16_t>(internedTwoByteStrings, edgeNameOrRef);
+ if (NS_WARN_IF(!edgeName))
+ return false;
+ }
+
+ edges.infallibleAppend(DeserializedEdge(referent, edgeName));
+ }
+
+ Maybe<StackFrameId> allocationStack;
+ if (node.has_allocationstack()) {
+ StackFrameId id = 0;
+ if (NS_WARN_IF(!saveStackFrame(node.allocationstack(), id)))
+ return false;
+ allocationStack.emplace(id);
+ }
+ MOZ_ASSERT(allocationStack.isSome() == node.has_allocationstack());
+
+ const char* jsObjectClassName = nullptr;
+ if (node.JSObjectClassNameOrRef_case() != protobuf::Node::JSOBJECTCLASSNAMEORREF_NOT_SET) {
+ Maybe<StringOrRef> clsNameOrRef = GET_STRING_OR_REF(node, jsobjectclassname);
+ jsObjectClassName = getOrInternString<char>(internedOneByteStrings, clsNameOrRef);
+ if (NS_WARN_IF(!jsObjectClassName))
+ return false;
+ }
+
+ const char* scriptFilename = nullptr;
+ if (node.ScriptFilenameOrRef_case() != protobuf::Node::SCRIPTFILENAMEORREF_NOT_SET) {
+ Maybe<StringOrRef> scriptFilenameOrRef = GET_STRING_OR_REF(node, scriptfilename);
+ scriptFilename = getOrInternString<char>(internedOneByteStrings, scriptFilenameOrRef);
+ if (NS_WARN_IF(!scriptFilename))
+ return false;
+ }
+
+ if (NS_WARN_IF(!nodes.putNew(id, DeserializedNode(id, coarseType, typeName,
+ size, Move(edges),
+ allocationStack,
+ jsObjectClassName,
+ scriptFilename, *this))))
+ {
+ return false;
+ };
+
+ return true;
+}
+
+bool
+HeapSnapshot::saveStackFrame(const protobuf::StackFrame& frame,
+ StackFrameId& outFrameId)
+{
+ // NB: de-duplicated string properties must be read in the same order here as
+ // they are written in `CoreDumpWriter::getProtobufStackFrame` or else indices
+ // in references to already serialized strings will be off.
+
+ if (frame.has_ref()) {
+ // We should only get a reference to the previous frame if we have already
+ // seen the previous frame.
+ if (!frames.has(frame.ref()))
+ return false;
+
+ outFrameId = frame.ref();
+ return true;
+ }
+
+ // Incomplete message.
+ if (!frame.has_data())
+ return false;
+
+ auto data = frame.data();
+
+ if (!data.has_id())
+ return false;
+ StackFrameId id = data.id();
+
+ // This should be the first and only time we see this frame.
+ if (frames.has(id))
+ return false;
+
+ if (!data.has_line())
+ return false;
+ uint32_t line = data.line();
+
+ if (!data.has_column())
+ return false;
+ uint32_t column = data.column();
+
+ if (!data.has_issystem())
+ return false;
+ bool isSystem = data.issystem();
+
+ if (!data.has_isselfhosted())
+ return false;
+ bool isSelfHosted = data.isselfhosted();
+
+ Maybe<StringOrRef> sourceOrRef = GET_STRING_OR_REF(data, source);
+ auto source = getOrInternString<char16_t>(internedTwoByteStrings, sourceOrRef);
+ if (!source)
+ return false;
+
+ const char16_t* functionDisplayName = nullptr;
+ if (data.FunctionDisplayNameOrRef_case() !=
+ protobuf::StackFrame_Data::FUNCTIONDISPLAYNAMEORREF_NOT_SET)
+ {
+ Maybe<StringOrRef> nameOrRef = GET_STRING_OR_REF(data, functiondisplayname);
+ functionDisplayName = getOrInternString<char16_t>(internedTwoByteStrings, nameOrRef);
+ if (!functionDisplayName)
+ return false;
+ }
+
+ Maybe<StackFrameId> parent;
+ if (data.has_parent()) {
+ StackFrameId parentId = 0;
+ if (!saveStackFrame(data.parent(), parentId))
+ return false;
+ parent = Some(parentId);
+ }
+
+ if (!frames.putNew(id, DeserializedStackFrame(id, parent, line, column,
+ source, functionDisplayName,
+ isSystem, isSelfHosted, *this)))
+ {
+ return false;
+ }
+
+ outFrameId = id;
+ return true;
+}
+
+#undef GET_STRING_OR_REF_WITH_PROP_NAMES
+#undef GET_STRING_OR_REF
+
+// Because protobuf messages aren't self-delimiting, we serialize each message
+// preceded by its size in bytes. When deserializing, we read this size and then
+// limit reading from the stream to the given byte size. If we didn't, then the
+// first message would consume the entire stream.
+static bool
+readSizeOfNextMessage(ZeroCopyInputStream& stream, uint32_t* sizep)
+{
+ MOZ_ASSERT(sizep);
+ CodedInputStream codedStream(&stream);
+ return codedStream.ReadVarint32(sizep) && *sizep > 0;
+}
+
+bool
+HeapSnapshot::init(JSContext* cx, const uint8_t* buffer, uint32_t size)
+{
+ if (!nodes.init() || !frames.init())
+ return false;
+
+ ArrayInputStream stream(buffer, size);
+ GzipInputStream gzipStream(&stream);
+ uint32_t sizeOfMessage = 0;
+
+ // First is the metadata.
+
+ protobuf::Metadata metadata;
+ if (NS_WARN_IF(!readSizeOfNextMessage(gzipStream, &sizeOfMessage)))
+ return false;
+ if (!parseMessage(gzipStream, sizeOfMessage, metadata))
+ return false;
+ if (metadata.has_timestamp())
+ timestamp.emplace(metadata.timestamp());
+
+ // Next is the root node.
+
+ protobuf::Node root;
+ if (NS_WARN_IF(!readSizeOfNextMessage(gzipStream, &sizeOfMessage)))
+ return false;
+ if (!parseMessage(gzipStream, sizeOfMessage, root))
+ return false;
+
+ // Although the id is optional in the protobuf format for future proofing, we
+ // can't currently do anything without it.
+ if (NS_WARN_IF(!root.has_id()))
+ return false;
+ rootId = root.id();
+
+ // The set of all node ids we've found edges pointing to.
+ NodeIdSet edgeReferents(cx);
+ if (NS_WARN_IF(!edgeReferents.init()))
+ return false;
+
+ if (NS_WARN_IF(!saveNode(root, edgeReferents)))
+ return false;
+
+ // Finally, the rest of the nodes in the core dump.
+
+ // Test for the end of the stream. The protobuf library gives no way to tell
+ // the difference between an underlying read error and the stream being
+ // done. All we can do is attempt to read the size of the next message and
+ // extrapolate guestimations from the result of that operation.
+ while (readSizeOfNextMessage(gzipStream, &sizeOfMessage)) {
+ protobuf::Node node;
+ if (!parseMessage(gzipStream, sizeOfMessage, node))
+ return false;
+ if (NS_WARN_IF(!saveNode(node, edgeReferents)))
+ return false;
+ }
+
+ // Check the set of node ids referred to by edges we found and ensure that we
+ // have the node corresponding to each id. If we don't have all of them, it is
+ // unsafe to perform analyses of this heap snapshot.
+ for (auto range = edgeReferents.all(); !range.empty(); range.popFront()) {
+ if (NS_WARN_IF(!nodes.has(range.front())))
+ return false;
+ }
+
+ return true;
+}
+
+
+/*** Heap Snapshot Analyses ***********************************************************************/
+
+void
+HeapSnapshot::TakeCensus(JSContext* cx, JS::HandleObject options,
+ JS::MutableHandleValue rval, ErrorResult& rv)
+{
+ JS::ubi::Census census(cx);
+ if (NS_WARN_IF(!census.init())) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ JS::ubi::CountTypePtr rootType;
+ if (NS_WARN_IF(!JS::ubi::ParseCensusOptions(cx, census, options, rootType))) {
+ rv.Throw(NS_ERROR_UNEXPECTED);
+ return;
+ }
+
+ JS::ubi::RootedCount rootCount(cx, rootType->makeCount());
+ if (NS_WARN_IF(!rootCount)) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ JS::ubi::CensusHandler handler(census, rootCount, GetCurrentThreadDebuggerMallocSizeOf());
+
+ {
+ JS::AutoCheckCannotGC nogc;
+
+ JS::ubi::CensusTraversal traversal(cx, handler, nogc);
+ if (NS_WARN_IF(!traversal.init())) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ if (NS_WARN_IF(!traversal.addStart(getRoot()))) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ if (NS_WARN_IF(!traversal.traverse())) {
+ rv.Throw(NS_ERROR_UNEXPECTED);
+ return;
+ }
+ }
+
+ if (NS_WARN_IF(!handler.report(cx, rval))) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+}
+
+void
+HeapSnapshot::DescribeNode(JSContext* cx, JS::HandleObject breakdown, uint64_t nodeId,
+ JS::MutableHandleValue rval, ErrorResult& rv) {
+ MOZ_ASSERT(breakdown);
+ JS::RootedValue breakdownVal(cx, JS::ObjectValue(*breakdown));
+ JS::ubi::CountTypePtr rootType = JS::ubi::ParseBreakdown(cx, breakdownVal);
+ if (NS_WARN_IF(!rootType)) {
+ rv.Throw(NS_ERROR_UNEXPECTED);
+ return;
+ }
+
+ JS::ubi::RootedCount rootCount(cx, rootType->makeCount());
+ if (NS_WARN_IF(!rootCount)) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ JS::ubi::Node::Id id(nodeId);
+ Maybe<JS::ubi::Node> node = getNodeById(id);
+ if (NS_WARN_IF(node.isNothing())) {
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return;
+ }
+
+ MallocSizeOf mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf();
+ if (NS_WARN_IF(!rootCount->count(mallocSizeOf, *node))) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ if (NS_WARN_IF(!rootCount->report(cx, rval))) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+}
+
+
+already_AddRefed<DominatorTree>
+HeapSnapshot::ComputeDominatorTree(ErrorResult& rv)
+{
+ Maybe<JS::ubi::DominatorTree> maybeTree;
+ {
+ auto ccjscx = CycleCollectedJSContext::Get();
+ MOZ_ASSERT(ccjscx);
+ auto cx = ccjscx->Context();
+ MOZ_ASSERT(cx);
+ JS::AutoCheckCannotGC nogc(cx);
+ maybeTree = JS::ubi::DominatorTree::Create(cx, nogc, getRoot());
+ }
+
+ if (NS_WARN_IF(maybeTree.isNothing())) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return nullptr;
+ }
+
+ return MakeAndAddRef<DominatorTree>(Move(*maybeTree), this, mParent);
+}
+
+void
+HeapSnapshot::ComputeShortestPaths(JSContext*cx, uint64_t start,
+ const Sequence<uint64_t>& targets,
+ uint64_t maxNumPaths,
+ JS::MutableHandleObject results,
+ ErrorResult& rv)
+{
+ // First ensure that our inputs are valid.
+
+ if (NS_WARN_IF(maxNumPaths == 0)) {
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return;
+ }
+
+ Maybe<JS::ubi::Node> startNode = getNodeById(start);
+ if (NS_WARN_IF(startNode.isNothing())) {
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return;
+ }
+
+ if (NS_WARN_IF(targets.Length() == 0)) {
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return;
+ }
+
+ // Aggregate the targets into a set and make sure that they exist in the heap
+ // snapshot.
+
+ JS::ubi::NodeSet targetsSet;
+ if (NS_WARN_IF(!targetsSet.init())) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ for (const auto& target : targets) {
+ Maybe<JS::ubi::Node> targetNode = getNodeById(target);
+ if (NS_WARN_IF(targetNode.isNothing())) {
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return;
+ }
+
+ if (NS_WARN_IF(!targetsSet.put(*targetNode))) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+ }
+
+ // Walk the heap graph and find the shortest paths.
+
+ Maybe<ShortestPaths> maybeShortestPaths;
+ {
+ JS::AutoCheckCannotGC nogc(cx);
+ maybeShortestPaths = ShortestPaths::Create(cx, nogc, maxNumPaths, *startNode,
+ Move(targetsSet));
+ }
+
+ if (NS_WARN_IF(maybeShortestPaths.isNothing())) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ auto& shortestPaths = *maybeShortestPaths;
+
+ // Convert the results into a Map object mapping target node IDs to arrays of
+ // paths found.
+
+ RootedObject resultsMap(cx, JS::NewMapObject(cx));
+ if (NS_WARN_IF(!resultsMap)) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ for (auto range = shortestPaths.eachTarget(); !range.empty(); range.popFront()) {
+ JS::RootedValue key(cx, JS::NumberValue(range.front().identifier()));
+ JS::AutoValueVector paths(cx);
+
+ bool ok = shortestPaths.forEachPath(range.front(), [&](JS::ubi::Path& path) {
+ JS::AutoValueVector pathValues(cx);
+
+ for (JS::ubi::BackEdge* edge : path) {
+ JS::RootedObject pathPart(cx, JS_NewPlainObject(cx));
+ if (!pathPart) {
+ return false;
+ }
+
+ JS::RootedValue predecessor(cx, NumberValue(edge->predecessor().identifier()));
+ if (!JS_DefineProperty(cx, pathPart, "predecessor", predecessor, JSPROP_ENUMERATE)) {
+ return false;
+ }
+
+ RootedValue edgeNameVal(cx, NullValue());
+ if (edge->name()) {
+ RootedString edgeName(cx, JS_AtomizeUCString(cx, edge->name().get()));
+ if (!edgeName) {
+ return false;
+ }
+ edgeNameVal = StringValue(edgeName);
+ }
+
+ if (!JS_DefineProperty(cx, pathPart, "edge", edgeNameVal, JSPROP_ENUMERATE)) {
+ return false;
+ }
+
+ if (!pathValues.append(ObjectValue(*pathPart))) {
+ return false;
+ }
+ }
+
+ RootedObject pathObj(cx, JS_NewArrayObject(cx, pathValues));
+ return pathObj && paths.append(ObjectValue(*pathObj));
+ });
+
+ if (NS_WARN_IF(!ok)) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ JS::RootedObject pathsArray(cx, JS_NewArrayObject(cx, paths));
+ if (NS_WARN_IF(!pathsArray)) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ JS::RootedValue pathsVal(cx, ObjectValue(*pathsArray));
+ if (NS_WARN_IF(!JS::MapSet(cx, resultsMap, key, pathsVal))) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+ }
+
+ results.set(resultsMap);
+}
+
+/*** Saving Heap Snapshots ************************************************************************/
+
+// If we are only taking a snapshot of the heap affected by the given set of
+// globals, find the set of compartments the globals are allocated
+// within. Returns false on OOM failure.
+static bool
+PopulateCompartmentsWithGlobals(CompartmentSet& compartments, AutoObjectVector& globals)
+{
+ if (!compartments.init())
+ return false;
+
+ unsigned length = globals.length();
+ for (unsigned i = 0; i < length; i++) {
+ if (!compartments.put(GetObjectCompartment(globals[i])))
+ return false;
+ }
+
+ return true;
+}
+
+// Add the given set of globals as explicit roots in the given roots
+// list. Returns false on OOM failure.
+static bool
+AddGlobalsAsRoots(AutoObjectVector& globals, ubi::RootList& roots)
+{
+ unsigned length = globals.length();
+ for (unsigned i = 0; i < length; i++) {
+ if (!roots.addRoot(ubi::Node(globals[i].get()),
+ u"heap snapshot global"))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Choose roots and limits for a traversal, given `boundaries`. Set `roots` to
+// the set of nodes within the boundaries that are referred to by nodes
+// outside. If `boundaries` does not include all JS compartments, initialize
+// `compartments` to the set of included compartments; otherwise, leave
+// `compartments` uninitialized. (You can use compartments.initialized() to
+// check.)
+//
+// If `boundaries` is incoherent, or we encounter an error while trying to
+// handle it, or we run out of memory, set `rv` appropriately and return
+// `false`.
+static bool
+EstablishBoundaries(JSContext* cx,
+ ErrorResult& rv,
+ const HeapSnapshotBoundaries& boundaries,
+ ubi::RootList& roots,
+ CompartmentSet& compartments)
+{
+ MOZ_ASSERT(!roots.initialized());
+ MOZ_ASSERT(!compartments.initialized());
+
+ bool foundBoundaryProperty = false;
+
+ if (boundaries.mRuntime.WasPassed()) {
+ foundBoundaryProperty = true;
+
+ if (!boundaries.mRuntime.Value()) {
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return false;
+ }
+
+ if (!roots.init()) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return false;
+ }
+ }
+
+ if (boundaries.mDebugger.WasPassed()) {
+ if (foundBoundaryProperty) {
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return false;
+ }
+ foundBoundaryProperty = true;
+
+ JSObject* dbgObj = boundaries.mDebugger.Value();
+ if (!dbgObj || !dbg::IsDebugger(*dbgObj)) {
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return false;
+ }
+
+ AutoObjectVector globals(cx);
+ if (!dbg::GetDebuggeeGlobals(cx, *dbgObj, globals) ||
+ !PopulateCompartmentsWithGlobals(compartments, globals) ||
+ !roots.init(compartments) ||
+ !AddGlobalsAsRoots(globals, roots))
+ {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return false;
+ }
+ }
+
+ if (boundaries.mGlobals.WasPassed()) {
+ if (foundBoundaryProperty) {
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return false;
+ }
+ foundBoundaryProperty = true;
+
+ uint32_t length = boundaries.mGlobals.Value().Length();
+ if (length == 0) {
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return false;
+ }
+
+ AutoObjectVector globals(cx);
+ for (uint32_t i = 0; i < length; i++) {
+ JSObject* global = boundaries.mGlobals.Value().ElementAt(i);
+ if (!JS_IsGlobalObject(global)) {
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return false;
+ }
+ if (!globals.append(global)) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return false;
+ }
+ }
+
+ if (!PopulateCompartmentsWithGlobals(compartments, globals) ||
+ !roots.init(compartments) ||
+ !AddGlobalsAsRoots(globals, roots))
+ {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return false;
+ }
+ }
+
+ if (!foundBoundaryProperty) {
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return false;
+ }
+
+ MOZ_ASSERT(roots.initialized());
+ MOZ_ASSERT_IF(boundaries.mDebugger.WasPassed(), compartments.initialized());
+ MOZ_ASSERT_IF(boundaries.mGlobals.WasPassed(), compartments.initialized());
+ return true;
+}
+
+
+// A variant covering all the various two-byte strings that we can get from the
+// ubi::Node API.
+class TwoByteString : public Variant<JSAtom*, const char16_t*, JS::ubi::EdgeName>
+{
+ using Base = Variant<JSAtom*, const char16_t*, JS::ubi::EdgeName>;
+
+ struct AsTwoByteStringMatcher
+ {
+ TwoByteString match(JSAtom* atom) {
+ return TwoByteString(atom);
+ }
+
+ TwoByteString match(const char16_t* chars) {
+ return TwoByteString(chars);
+ }
+ };
+
+ struct IsNonNullMatcher
+ {
+ template<typename T>
+ bool match(const T& t) { return t != nullptr; }
+ };
+
+ struct LengthMatcher
+ {
+ size_t match(JSAtom* atom) {
+ MOZ_ASSERT(atom);
+ JS::ubi::AtomOrTwoByteChars s(atom);
+ return s.length();
+ }
+
+ size_t match(const char16_t* chars) {
+ MOZ_ASSERT(chars);
+ return NS_strlen(chars);
+ }
+
+ size_t match(const JS::ubi::EdgeName& ptr) {
+ MOZ_ASSERT(ptr);
+ return NS_strlen(ptr.get());
+ }
+ };
+
+ struct CopyToBufferMatcher
+ {
+ RangedPtr<char16_t> destination;
+ size_t maxLength;
+
+ CopyToBufferMatcher(RangedPtr<char16_t> destination, size_t maxLength)
+ : destination(destination)
+ , maxLength(maxLength)
+ { }
+
+ size_t match(JS::ubi::EdgeName& ptr) {
+ return ptr ? match(ptr.get()) : 0;
+ }
+
+ size_t match(JSAtom* atom) {
+ MOZ_ASSERT(atom);
+ JS::ubi::AtomOrTwoByteChars s(atom);
+ return s.copyToBuffer(destination, maxLength);
+ }
+
+ size_t match(const char16_t* chars) {
+ MOZ_ASSERT(chars);
+ JS::ubi::AtomOrTwoByteChars s(chars);
+ return s.copyToBuffer(destination, maxLength);
+ }
+ };
+
+public:
+ template<typename T>
+ MOZ_IMPLICIT TwoByteString(T&& rhs) : Base(Forward<T>(rhs)) { }
+
+ template<typename T>
+ TwoByteString& operator=(T&& rhs) {
+ MOZ_ASSERT(this != &rhs, "self-move disallowed");
+ this->~TwoByteString();
+ new (this) TwoByteString(Forward<T>(rhs));
+ return *this;
+ }
+
+ TwoByteString(const TwoByteString&) = delete;
+ TwoByteString& operator=(const TwoByteString&) = delete;
+
+ // Rewrap the inner value of a JS::ubi::AtomOrTwoByteChars as a TwoByteString.
+ static TwoByteString from(JS::ubi::AtomOrTwoByteChars&& s) {
+ AsTwoByteStringMatcher m;
+ return s.match(m);
+ }
+
+ // Returns true if the given TwoByteString is non-null, false otherwise.
+ bool isNonNull() const {
+ IsNonNullMatcher m;
+ return match(m);
+ }
+
+ // Return the length of the string, 0 if it is null.
+ size_t length() const {
+ LengthMatcher m;
+ return match(m);
+ }
+
+ // Copy the contents of a TwoByteString into the provided buffer. The buffer
+ // is NOT null terminated. The number of characters written is returned.
+ size_t copyToBuffer(RangedPtr<char16_t> destination, size_t maxLength) {
+ CopyToBufferMatcher m(destination, maxLength);
+ return match(m);
+ }
+
+ struct HashPolicy;
+};
+
+// A hashing policy for TwoByteString.
+//
+// Atoms are pointer hashed and use pointer equality, which means that we
+// tolerate some duplication across atoms and the other two types of two-byte
+// strings. In practice, we expect the amount of this duplication to be very low
+// because each type is generally a different semantic thing in addition to
+// having a slightly different representation. For example, the set of edge
+// names and the set stack frames' source names naturally tend not to overlap
+// very much if at all.
+struct TwoByteString::HashPolicy {
+ using Lookup = TwoByteString;
+
+ struct HashingMatcher {
+ js::HashNumber match(const JSAtom* atom) {
+ return js::DefaultHasher<const JSAtom*>::hash(atom);
+ }
+
+ js::HashNumber match(const char16_t* chars) {
+ MOZ_ASSERT(chars);
+ auto length = NS_strlen(chars);
+ return HashString(chars, length);
+ }
+
+ js::HashNumber match(const JS::ubi::EdgeName& ptr) {
+ MOZ_ASSERT(ptr);
+ return match(ptr.get());
+ }
+ };
+
+ static js::HashNumber hash(const Lookup& l) {
+ HashingMatcher hasher;
+ return l.match(hasher);
+ }
+
+ struct EqualityMatcher {
+ const TwoByteString& rhs;
+ explicit EqualityMatcher(const TwoByteString& rhs) : rhs(rhs) { }
+
+ bool match(const JSAtom* atom) {
+ return rhs.is<JSAtom*>() && rhs.as<JSAtom*>() == atom;
+ }
+
+ bool match(const char16_t* chars) {
+ MOZ_ASSERT(chars);
+
+ const char16_t* rhsChars = nullptr;
+ if (rhs.is<const char16_t*>())
+ rhsChars = rhs.as<const char16_t*>();
+ else if (rhs.is<JS::ubi::EdgeName>())
+ rhsChars = rhs.as<JS::ubi::EdgeName>().get();
+ else
+ return false;
+ MOZ_ASSERT(rhsChars);
+
+ auto length = NS_strlen(chars);
+ if (NS_strlen(rhsChars) != length)
+ return false;
+
+ return memcmp(chars, rhsChars, length * sizeof(char16_t)) == 0;
+ }
+
+ bool match(const JS::ubi::EdgeName& ptr) {
+ MOZ_ASSERT(ptr);
+ return match(ptr.get());
+ }
+ };
+
+ static bool match(const TwoByteString& k, const Lookup& l) {
+ EqualityMatcher eq(l);
+ return k.match(eq);
+ }
+
+ static void rekey(TwoByteString& k, TwoByteString&& newKey) {
+ k = Move(newKey);
+ }
+};
+
+// Returns whether `edge` should be included in a heap snapshot of
+// `compartments`. The optional `policy` out-param is set to INCLUDE_EDGES
+// if we want to include the referent's edges, or EXCLUDE_EDGES if we don't
+// want to include them.
+static bool
+ShouldIncludeEdge(JS::CompartmentSet* compartments,
+ const ubi::Node& origin, const ubi::Edge& edge,
+ CoreDumpWriter::EdgePolicy* policy = nullptr)
+{
+ if (policy) {
+ *policy = CoreDumpWriter::INCLUDE_EDGES;
+ }
+
+ if (!compartments) {
+ // We aren't targeting a particular set of compartments, so serialize all the
+ // things!
+ return true;
+ }
+
+ // We are targeting a particular set of compartments. If this node is in our target
+ // set, serialize it and all of its edges. If this node is _not_ in our
+ // target set, we also serialize under the assumption that it is a shared
+ // resource being used by something in our target compartments since we reached it
+ // by traversing the heap graph. However, we do not serialize its outgoing
+ // edges and we abandon further traversal from this node.
+ //
+ // If the node does not belong to any compartment, we also serialize its outgoing
+ // edges. This case is relevant for Shapes: they don't belong to a specific
+ // compartment and contain edges to parent/kids Shapes we want to include. Note
+ // that these Shapes may contain pointers into our target compartment (the
+ // Shape's getter/setter JSObjects). However, we do not serialize nodes in other
+ // compartments that are reachable from these non-compartment nodes.
+
+ JSCompartment* compartment = edge.referent.compartment();
+
+ if (!compartment || compartments->has(compartment)) {
+ return true;
+ }
+
+ if (policy) {
+ *policy = CoreDumpWriter::EXCLUDE_EDGES;
+ }
+
+ return !!origin.compartment();
+}
+
+// A `CoreDumpWriter` that serializes nodes to protobufs and writes them to the
+// given `ZeroCopyOutputStream`.
+class MOZ_STACK_CLASS StreamWriter : public CoreDumpWriter
+{
+ using FrameSet = js::HashSet<uint64_t>;
+ using TwoByteStringMap = js::HashMap<TwoByteString, uint64_t, TwoByteString::HashPolicy>;
+ using OneByteStringMap = js::HashMap<const char*, uint64_t>;
+
+ JSContext* cx;
+ bool wantNames;
+ // The set of |JS::ubi::StackFrame::identifier()|s that have already been
+ // serialized and written to the core dump.
+ FrameSet framesAlreadySerialized;
+ // The set of two-byte strings that have already been serialized and written
+ // to the core dump.
+ TwoByteStringMap twoByteStringsAlreadySerialized;
+ // The set of one-byte strings that have already been serialized and written
+ // to the core dump.
+ OneByteStringMap oneByteStringsAlreadySerialized;
+
+ ::google::protobuf::io::ZeroCopyOutputStream& stream;
+
+ JS::CompartmentSet* compartments;
+
+ bool writeMessage(const ::google::protobuf::MessageLite& message) {
+ // We have to create a new CodedOutputStream when writing each message so
+ // that the 64MB size limit used by Coded{Output,Input}Stream to prevent
+ // integer overflow is enforced per message rather than on the whole stream.
+ ::google::protobuf::io::CodedOutputStream codedStream(&stream);
+ codedStream.WriteVarint32(message.ByteSize());
+ message.SerializeWithCachedSizes(&codedStream);
+ return !codedStream.HadError();
+ }
+
+ // Attach the full two-byte string or a reference to a two-byte string that
+ // has already been serialized to a protobuf message.
+ template <typename SetStringFunction,
+ typename SetRefFunction>
+ bool attachTwoByteString(TwoByteString& string, SetStringFunction setString,
+ SetRefFunction setRef) {
+ auto ptr = twoByteStringsAlreadySerialized.lookupForAdd(string);
+ if (ptr) {
+ setRef(ptr->value());
+ return true;
+ }
+
+ auto length = string.length();
+ auto stringData = MakeUnique<std::string>(length * sizeof(char16_t), '\0');
+ if (!stringData)
+ return false;
+
+ auto buf = const_cast<char16_t*>(reinterpret_cast<const char16_t*>(stringData->data()));
+ string.copyToBuffer(RangedPtr<char16_t>(buf, length), length);
+
+ uint64_t ref = twoByteStringsAlreadySerialized.count();
+ if (!twoByteStringsAlreadySerialized.add(ptr, Move(string), ref))
+ return false;
+
+ setString(stringData.release());
+ return true;
+ }
+
+ // Attach the full one-byte string or a reference to a one-byte string that
+ // has already been serialized to a protobuf message.
+ template <typename SetStringFunction,
+ typename SetRefFunction>
+ bool attachOneByteString(const char* string, SetStringFunction setString,
+ SetRefFunction setRef) {
+ auto ptr = oneByteStringsAlreadySerialized.lookupForAdd(string);
+ if (ptr) {
+ setRef(ptr->value());
+ return true;
+ }
+
+ auto length = strlen(string);
+ auto stringData = MakeUnique<std::string>(string, length);
+ if (!stringData)
+ return false;
+
+ uint64_t ref = oneByteStringsAlreadySerialized.count();
+ if (!oneByteStringsAlreadySerialized.add(ptr, string, ref))
+ return false;
+
+ setString(stringData.release());
+ return true;
+ }
+
+ protobuf::StackFrame* getProtobufStackFrame(JS::ubi::StackFrame& frame,
+ size_t depth = 1) {
+ // NB: de-duplicated string properties must be written in the same order
+ // here as they are read in `HeapSnapshot::saveStackFrame` or else indices
+ // in references to already serialized strings will be off.
+
+ MOZ_ASSERT(frame,
+ "null frames should be represented as the lack of a serialized "
+ "stack frame");
+
+ auto id = frame.identifier();
+ auto protobufStackFrame = MakeUnique<protobuf::StackFrame>();
+ if (!protobufStackFrame)
+ return nullptr;
+
+ if (framesAlreadySerialized.has(id)) {
+ protobufStackFrame->set_ref(id);
+ return protobufStackFrame.release();
+ }
+
+ auto data = MakeUnique<protobuf::StackFrame_Data>();
+ if (!data)
+ return nullptr;
+
+ data->set_id(id);
+ data->set_line(frame.line());
+ data->set_column(frame.column());
+ data->set_issystem(frame.isSystem());
+ data->set_isselfhosted(frame.isSelfHosted(cx));
+
+ auto dupeSource = TwoByteString::from(frame.source());
+ if (!attachTwoByteString(dupeSource,
+ [&] (std::string* source) { data->set_allocated_source(source); },
+ [&] (uint64_t ref) { data->set_sourceref(ref); }))
+ {
+ return nullptr;
+ }
+
+ auto dupeName = TwoByteString::from(frame.functionDisplayName());
+ if (dupeName.isNonNull()) {
+ if (!attachTwoByteString(dupeName,
+ [&] (std::string* name) { data->set_allocated_functiondisplayname(name); },
+ [&] (uint64_t ref) { data->set_functiondisplaynameref(ref); }))
+ {
+ return nullptr;
+ }
+ }
+
+ auto parent = frame.parent();
+ if (parent && depth < HeapSnapshot::MAX_STACK_DEPTH) {
+ auto protobufParent = getProtobufStackFrame(parent, depth + 1);
+ if (!protobufParent)
+ return nullptr;
+ data->set_allocated_parent(protobufParent);
+ }
+
+ protobufStackFrame->set_allocated_data(data.release());
+
+ if (!framesAlreadySerialized.put(id))
+ return nullptr;
+
+ return protobufStackFrame.release();
+ }
+
+public:
+ StreamWriter(JSContext* cx,
+ ::google::protobuf::io::ZeroCopyOutputStream& stream,
+ bool wantNames,
+ JS::CompartmentSet* compartments)
+ : cx(cx)
+ , wantNames(wantNames)
+ , framesAlreadySerialized(cx)
+ , twoByteStringsAlreadySerialized(cx)
+ , oneByteStringsAlreadySerialized(cx)
+ , stream(stream)
+ , compartments(compartments)
+ { }
+
+ bool init() {
+ return framesAlreadySerialized.init() &&
+ twoByteStringsAlreadySerialized.init() &&
+ oneByteStringsAlreadySerialized.init();
+ }
+
+ ~StreamWriter() override { }
+
+ virtual bool writeMetadata(uint64_t timestamp) final {
+ protobuf::Metadata metadata;
+ metadata.set_timestamp(timestamp);
+ return writeMessage(metadata);
+ }
+
+ virtual bool writeNode(const JS::ubi::Node& ubiNode,
+ EdgePolicy includeEdges) override final {
+ // NB: de-duplicated string properties must be written in the same order
+ // here as they are read in `HeapSnapshot::saveNode` or else indices in
+ // references to already serialized strings will be off.
+
+ protobuf::Node protobufNode;
+ protobufNode.set_id(ubiNode.identifier());
+
+ protobufNode.set_coarsetype(JS::ubi::CoarseTypeToUint32(ubiNode.coarseType()));
+
+ auto typeName = TwoByteString(ubiNode.typeName());
+ if (NS_WARN_IF(!attachTwoByteString(typeName,
+ [&] (std::string* name) { protobufNode.set_allocated_typename_(name); },
+ [&] (uint64_t ref) { protobufNode.set_typenameref(ref); })))
+ {
+ return false;
+ }
+
+ mozilla::MallocSizeOf mallocSizeOf = dbg::GetDebuggerMallocSizeOf(cx);
+ MOZ_ASSERT(mallocSizeOf);
+ protobufNode.set_size(ubiNode.size(mallocSizeOf));
+
+ if (includeEdges) {
+ auto edges = ubiNode.edges(cx, wantNames);
+ if (NS_WARN_IF(!edges))
+ return false;
+
+ for ( ; !edges->empty(); edges->popFront()) {
+ ubi::Edge& ubiEdge = edges->front();
+ if (!ShouldIncludeEdge(compartments, ubiNode, ubiEdge)) {
+ continue;
+ }
+
+ protobuf::Edge* protobufEdge = protobufNode.add_edges();
+ if (NS_WARN_IF(!protobufEdge)) {
+ return false;
+ }
+
+ protobufEdge->set_referent(ubiEdge.referent.identifier());
+
+ if (wantNames && ubiEdge.name) {
+ TwoByteString edgeName(Move(ubiEdge.name));
+ if (NS_WARN_IF(!attachTwoByteString(edgeName,
+ [&] (std::string* name) { protobufEdge->set_allocated_name(name); },
+ [&] (uint64_t ref) { protobufEdge->set_nameref(ref); })))
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ if (ubiNode.hasAllocationStack()) {
+ auto ubiStackFrame = ubiNode.allocationStack();
+ auto protoStackFrame = getProtobufStackFrame(ubiStackFrame);
+ if (NS_WARN_IF(!protoStackFrame))
+ return false;
+ protobufNode.set_allocated_allocationstack(protoStackFrame);
+ }
+
+ if (auto className = ubiNode.jsObjectClassName()) {
+ if (NS_WARN_IF(!attachOneByteString(className,
+ [&] (std::string* name) { protobufNode.set_allocated_jsobjectclassname(name); },
+ [&] (uint64_t ref) { protobufNode.set_jsobjectclassnameref(ref); })))
+ {
+ return false;
+ }
+ }
+
+ if (auto scriptFilename = ubiNode.scriptFilename()) {
+ if (NS_WARN_IF(!attachOneByteString(scriptFilename,
+ [&] (std::string* name) { protobufNode.set_allocated_scriptfilename(name); },
+ [&] (uint64_t ref) { protobufNode.set_scriptfilenameref(ref); })))
+ {
+ return false;
+ }
+ }
+
+ return writeMessage(protobufNode);
+ }
+};
+
+// A JS::ubi::BreadthFirst handler that serializes a snapshot of the heap into a
+// core dump.
+class MOZ_STACK_CLASS HeapSnapshotHandler
+{
+ CoreDumpWriter& writer;
+ JS::CompartmentSet* compartments;
+
+public:
+ HeapSnapshotHandler(CoreDumpWriter& writer,
+ JS::CompartmentSet* compartments)
+ : writer(writer),
+ compartments(compartments)
+ { }
+
+ // JS::ubi::BreadthFirst handler interface.
+
+ class NodeData { };
+ typedef JS::ubi::BreadthFirst<HeapSnapshotHandler> Traversal;
+ bool operator() (Traversal& traversal,
+ JS::ubi::Node origin,
+ const JS::ubi::Edge& edge,
+ NodeData*,
+ bool first)
+ {
+ // We're only interested in the first time we reach edge.referent, not in
+ // every edge arriving at that node. "But, don't we want to serialize every
+ // edge in the heap graph?" you ask. Don't worry! This edge is still
+ // serialized into the core dump. Serializing a node also serializes each of
+ // its edges, and if we are traversing a given edge, we must have already
+ // visited and serialized the origin node and its edges.
+ if (!first)
+ return true;
+
+ CoreDumpWriter::EdgePolicy policy;
+ if (!ShouldIncludeEdge(compartments, origin, edge, &policy))
+ return true;
+
+ if (policy == CoreDumpWriter::EXCLUDE_EDGES)
+ traversal.abandonReferent();
+
+ return writer.writeNode(edge.referent, policy);
+ }
+};
+
+
+bool
+WriteHeapGraph(JSContext* cx,
+ const JS::ubi::Node& node,
+ CoreDumpWriter& writer,
+ bool wantNames,
+ JS::CompartmentSet* compartments,
+ JS::AutoCheckCannotGC& noGC)
+{
+ // Serialize the starting node to the core dump.
+
+ if (NS_WARN_IF(!writer.writeNode(node, CoreDumpWriter::INCLUDE_EDGES))) {
+ return false;
+ }
+
+ // Walk the heap graph starting from the given node and serialize it into the
+ // core dump.
+
+ HeapSnapshotHandler handler(writer, compartments);
+ HeapSnapshotHandler::Traversal traversal(cx, handler, noGC);
+ if (!traversal.init())
+ return false;
+ traversal.wantNames = wantNames;
+
+ bool ok = traversal.addStartVisited(node) &&
+ traversal.traverse();
+
+ return ok;
+}
+
+static unsigned long
+msSinceProcessCreation(const TimeStamp& now)
+{
+ bool ignored;
+ auto duration = now - TimeStamp::ProcessCreation(ignored);
+ return (unsigned long) duration.ToMilliseconds();
+}
+
+/* static */ already_AddRefed<nsIFile>
+HeapSnapshot::CreateUniqueCoreDumpFile(ErrorResult& rv,
+ const TimeStamp& now,
+ nsAString& outFilePath)
+{
+ nsCOMPtr<nsIFile> file;
+ rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(file));
+ if (NS_WARN_IF(rv.Failed()))
+ return nullptr;
+
+ auto ms = msSinceProcessCreation(now);
+ rv = file->AppendNative(nsPrintfCString("%lu.fxsnapshot", ms));
+ if (NS_WARN_IF(rv.Failed()))
+ return nullptr;
+
+ rv = file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0666);
+ if (NS_WARN_IF(rv.Failed()))
+ return nullptr;
+
+ rv = file->GetPath(outFilePath);
+ if (NS_WARN_IF(rv.Failed()))
+ return nullptr;
+
+ return file.forget();
+}
+
+// Deletion policy for cleaning up PHeapSnapshotTempFileHelperChild pointers.
+class DeleteHeapSnapshotTempFileHelperChild
+{
+public:
+ constexpr DeleteHeapSnapshotTempFileHelperChild() { }
+
+ void operator()(PHeapSnapshotTempFileHelperChild* ptr) const {
+ Unused << NS_WARN_IF(!HeapSnapshotTempFileHelperChild::Send__delete__(ptr));
+ }
+};
+
+// A UniquePtr alias to automatically manage PHeapSnapshotTempFileHelperChild
+// pointers.
+using UniqueHeapSnapshotTempFileHelperChild = UniquePtr<PHeapSnapshotTempFileHelperChild,
+ DeleteHeapSnapshotTempFileHelperChild>;
+
+// Get an nsIOutputStream that we can write the heap snapshot to. In non-e10s
+// and in the e10s parent process, open a file directly and create an output
+// stream for it. In e10s child processes, we are sandboxed without access to
+// the filesystem. Use IPDL to request a file descriptor from the parent
+// process.
+static already_AddRefed<nsIOutputStream>
+getCoreDumpOutputStream(ErrorResult& rv, TimeStamp& start, nsAString& outFilePath)
+{
+ if (XRE_IsParentProcess()) {
+ // Create the file and open the output stream directly.
+
+ nsCOMPtr<nsIFile> file = HeapSnapshot::CreateUniqueCoreDumpFile(rv,
+ start,
+ outFilePath);
+ if (NS_WARN_IF(rv.Failed()))
+ return nullptr;
+
+ nsCOMPtr<nsIOutputStream> outputStream;
+ rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file,
+ PR_WRONLY, -1, 0);
+ if (NS_WARN_IF(rv.Failed()))
+ return nullptr;
+
+ return outputStream.forget();
+ } else {
+ // Request a file descriptor from the parent process over IPDL.
+
+ auto cc = ContentChild::GetSingleton();
+ if (!cc) {
+ rv.Throw(NS_ERROR_UNEXPECTED);
+ return nullptr;
+ }
+
+ UniqueHeapSnapshotTempFileHelperChild helper(
+ cc->SendPHeapSnapshotTempFileHelperConstructor());
+ if (NS_WARN_IF(!helper)) {
+ rv.Throw(NS_ERROR_UNEXPECTED);
+ return nullptr;
+ }
+
+ OpenHeapSnapshotTempFileResponse response;
+ if (!helper->SendOpenHeapSnapshotTempFile(&response)) {
+ rv.Throw(NS_ERROR_UNEXPECTED);
+ return nullptr;
+ }
+ if (response.type() == OpenHeapSnapshotTempFileResponse::Tnsresult) {
+ rv.Throw(response.get_nsresult());
+ return nullptr;
+ }
+
+ auto opened = response.get_OpenedFile();
+ outFilePath = opened.path();
+ nsCOMPtr<nsIOutputStream> outputStream =
+ FileDescriptorOutputStream::Create(opened.descriptor());
+ if (NS_WARN_IF(!outputStream)) {
+ rv.Throw(NS_ERROR_UNEXPECTED);
+ return nullptr;
+ }
+
+ return outputStream.forget();
+ }
+}
+
+} // namespace devtools
+
+namespace dom {
+
+using namespace JS;
+using namespace devtools;
+
+/* static */ void
+ThreadSafeChromeUtils::SaveHeapSnapshot(GlobalObject& global,
+ const HeapSnapshotBoundaries& boundaries,
+ nsAString& outFilePath,
+ ErrorResult& rv)
+{
+ auto start = TimeStamp::Now();
+
+ bool wantNames = true;
+ CompartmentSet compartments;
+
+ nsCOMPtr<nsIOutputStream> outputStream = getCoreDumpOutputStream(rv, start, outFilePath);
+ if (NS_WARN_IF(rv.Failed()))
+ return;
+
+ ZeroCopyNSIOutputStream zeroCopyStream(outputStream);
+ ::google::protobuf::io::GzipOutputStream gzipStream(&zeroCopyStream);
+
+ JSContext* cx = global.Context();
+
+ {
+ Maybe<AutoCheckCannotGC> maybeNoGC;
+ ubi::RootList rootList(cx, maybeNoGC, wantNames);
+ if (!EstablishBoundaries(cx, rv, boundaries, rootList, compartments))
+ return;
+
+ StreamWriter writer(cx, gzipStream, wantNames,
+ compartments.initialized() ? &compartments : nullptr);
+ if (NS_WARN_IF(!writer.init())) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ MOZ_ASSERT(maybeNoGC.isSome());
+ ubi::Node roots(&rootList);
+
+ // Serialize the initial heap snapshot metadata to the core dump.
+ if (!writer.writeMetadata(PR_Now()) ||
+ // Serialize the heap graph to the core dump, starting from our list of
+ // roots.
+ !WriteHeapGraph(cx,
+ roots,
+ writer,
+ wantNames,
+ compartments.initialized() ? &compartments : nullptr,
+ maybeNoGC.ref()))
+ {
+ rv.Throw(zeroCopyStream.failed()
+ ? zeroCopyStream.result()
+ : NS_ERROR_UNEXPECTED);
+ return;
+ }
+ }
+}
+
+/* static */ already_AddRefed<HeapSnapshot>
+ThreadSafeChromeUtils::ReadHeapSnapshot(GlobalObject& global,
+ const nsAString& filePath,
+ ErrorResult& rv)
+{
+ UniquePtr<char[]> path(ToNewCString(filePath));
+ if (!path) {
+ rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return nullptr;
+ }
+
+ AutoMemMap mm;
+ rv = mm.init(path.get());
+ if (rv.Failed())
+ return nullptr;
+
+ RefPtr<HeapSnapshot> snapshot = HeapSnapshot::Create(
+ global.Context(), global, reinterpret_cast<const uint8_t*>(mm.address()),
+ mm.size(), rv);
+
+ return snapshot.forget();
+}
+
+} // namespace dom
+} // namespace mozilla
diff --git a/dom/heapsnapshot/HeapSnapshot.h b/dom/heapsnapshot/HeapSnapshot.h
new file mode 100644
index 000000000..12dfa4c2b
--- /dev/null
+++ b/dom/heapsnapshot/HeapSnapshot.h
@@ -0,0 +1,224 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_devtools_HeapSnapshot__
+#define mozilla_devtools_HeapSnapshot__
+
+#include "js/HashTable.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/devtools/DeserializedNode.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/Nullable.h"
+#include "mozilla/HashFunctions.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/RefCounted.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/UniquePtr.h"
+
+#include "CoreDump.pb.h"
+#include "nsCOMPtr.h"
+#include "nsCRTGlue.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsISupports.h"
+#include "nsWrapperCache.h"
+#include "nsXPCOM.h"
+
+namespace mozilla {
+namespace devtools {
+
+class DominatorTree;
+
+struct NSFreePolicy {
+ void operator()(void* ptr) {
+ NS_Free(ptr);
+ }
+};
+
+using UniqueTwoByteString = UniquePtr<char16_t[], NSFreePolicy>;
+using UniqueOneByteString = UniquePtr<char[], NSFreePolicy>;
+
+class HeapSnapshot final : public nsISupports
+ , public nsWrapperCache
+{
+ friend struct DeserializedNode;
+ friend struct DeserializedEdge;
+ friend struct DeserializedStackFrame;
+ friend class JS::ubi::Concrete<JS::ubi::DeserializedNode>;
+
+ explicit HeapSnapshot(JSContext* cx, nsISupports* aParent)
+ : timestamp(Nothing())
+ , rootId(0)
+ , nodes(cx)
+ , frames(cx)
+ , mParent(aParent)
+ {
+ MOZ_ASSERT(aParent);
+ };
+
+ // Initialize this HeapSnapshot from the given buffer that contains a
+ // serialized core dump. Do NOT take ownership of the buffer, only borrow it
+ // for the duration of the call. Return false on failure.
+ bool init(JSContext* cx, const uint8_t* buffer, uint32_t size);
+
+ using NodeIdSet = js::HashSet<NodeId>;
+
+ // Save the given `protobuf::Node` message in this `HeapSnapshot` as a
+ // `DeserializedNode`.
+ bool saveNode(const protobuf::Node& node, NodeIdSet& edgeReferents);
+
+ // Save the given `protobuf::StackFrame` message in this `HeapSnapshot` as a
+ // `DeserializedStackFrame`. The saved stack frame's id is returned via the
+ // out parameter.
+ bool saveStackFrame(const protobuf::StackFrame& frame,
+ StackFrameId& outFrameId);
+
+public:
+ // The maximum number of stack frames that we will serialize into a core
+ // dump. This helps prevent over-recursion in the protobuf library when
+ // deserializing stacks.
+ static const size_t MAX_STACK_DEPTH = 60;
+
+private:
+ // If present, a timestamp in the same units that `PR_Now` gives.
+ Maybe<uint64_t> timestamp;
+
+ // The id of the root node for this deserialized heap graph.
+ NodeId rootId;
+
+ // The set of nodes in this deserialized heap graph, keyed by id.
+ using NodeSet = js::HashSet<DeserializedNode, DeserializedNode::HashPolicy>;
+ NodeSet nodes;
+
+ // The set of stack frames in this deserialized heap graph, keyed by id.
+ using FrameSet = js::HashSet<DeserializedStackFrame,
+ DeserializedStackFrame::HashPolicy>;
+ FrameSet frames;
+
+ Vector<UniqueTwoByteString> internedTwoByteStrings;
+ Vector<UniqueOneByteString> internedOneByteStrings;
+
+ using StringOrRef = Variant<const std::string*, uint64_t>;
+
+ template<typename CharT,
+ typename InternedStringSet>
+ const CharT* getOrInternString(InternedStringSet& internedStrings,
+ Maybe<StringOrRef>& maybeStrOrRef);
+
+protected:
+ nsCOMPtr<nsISupports> mParent;
+
+ virtual ~HeapSnapshot() { }
+
+public:
+ // Create a `HeapSnapshot` from the given buffer that contains a serialized
+ // core dump. Do NOT take ownership of the buffer, only borrow it for the
+ // duration of the call.
+ static already_AddRefed<HeapSnapshot> Create(JSContext* cx,
+ dom::GlobalObject& global,
+ const uint8_t* buffer,
+ uint32_t size,
+ ErrorResult& rv);
+
+ // Creates the `$TEMP_DIR/XXXXXX-XXX.fxsnapshot` core dump file that heap
+ // snapshots are serialized into.
+ static already_AddRefed<nsIFile> CreateUniqueCoreDumpFile(ErrorResult& rv,
+ const TimeStamp& now,
+ nsAString& outFilePath);
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(HeapSnapshot)
+ MOZ_DECLARE_REFCOUNTED_TYPENAME(HeapSnapshot)
+
+ nsISupports* GetParentObject() const { return mParent; }
+
+ virtual JSObject* WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) override;
+
+ const char16_t* borrowUniqueString(const char16_t* duplicateString,
+ size_t length);
+
+ // Get the root node of this heap snapshot's graph.
+ JS::ubi::Node getRoot() {
+ MOZ_ASSERT(nodes.initialized());
+ auto p = nodes.lookup(rootId);
+ MOZ_ASSERT(p);
+ const DeserializedNode& node = *p;
+ return JS::ubi::Node(const_cast<DeserializedNode*>(&node));
+ }
+
+ Maybe<JS::ubi::Node> getNodeById(JS::ubi::Node::Id nodeId) {
+ auto p = nodes.lookup(nodeId);
+ if (!p)
+ return Nothing();
+ return Some(JS::ubi::Node(const_cast<DeserializedNode*>(&*p)));
+ }
+
+ void TakeCensus(JSContext* cx, JS::HandleObject options,
+ JS::MutableHandleValue rval, ErrorResult& rv);
+
+ void DescribeNode(JSContext* cx, JS::HandleObject breakdown, uint64_t nodeId,
+ JS::MutableHandleValue rval, ErrorResult& rv);
+
+ already_AddRefed<DominatorTree> ComputeDominatorTree(ErrorResult& rv);
+
+ void ComputeShortestPaths(JSContext*cx, uint64_t start,
+ const dom::Sequence<uint64_t>& targets,
+ uint64_t maxNumPaths,
+ JS::MutableHandleObject results,
+ ErrorResult& rv);
+
+ dom::Nullable<uint64_t> GetCreationTime() {
+ static const uint64_t maxTime = uint64_t(1) << 53;
+ if (timestamp.isSome() && timestamp.ref() <= maxTime) {
+ return dom::Nullable<uint64_t>(timestamp.ref());
+ }
+
+ return dom::Nullable<uint64_t>();
+ }
+};
+
+// A `CoreDumpWriter` is given the data we wish to save in a core dump and
+// serializes it to disk, or memory, or a socket, etc.
+class CoreDumpWriter
+{
+public:
+ virtual ~CoreDumpWriter() { };
+
+ // Write the given bits of metadata we would like to associate with this core
+ // dump.
+ virtual bool writeMetadata(uint64_t timestamp) = 0;
+
+ enum EdgePolicy : bool {
+ INCLUDE_EDGES = true,
+ EXCLUDE_EDGES = false
+ };
+
+ // Write the given `JS::ubi::Node` to the core dump. The given `EdgePolicy`
+ // dictates whether its outgoing edges should also be written to the core
+ // dump, or excluded.
+ virtual bool writeNode(const JS::ubi::Node& node,
+ EdgePolicy includeEdges) = 0;
+};
+
+// Serialize the heap graph as seen from `node` with the given `CoreDumpWriter`.
+// If `wantNames` is true, capture edge names. If `zones` is non-null, only
+// capture the sub-graph within the zone set, otherwise capture the whole heap
+// graph. Returns false on failure.
+bool
+WriteHeapGraph(JSContext* cx,
+ const JS::ubi::Node& node,
+ CoreDumpWriter& writer,
+ bool wantNames,
+ JS::CompartmentSet* compartments,
+ JS::AutoCheckCannotGC& noGC);
+
+// Get the mozilla::MallocSizeOf for the current thread's JSRuntime.
+MallocSizeOf GetCurrentThreadDebuggerMallocSizeOf();
+
+} // namespace devtools
+} // namespace mozilla
+
+#endif // mozilla_devtools_HeapSnapshot__
diff --git a/dom/heapsnapshot/HeapSnapshotTempFileHelperChild.h b/dom/heapsnapshot/HeapSnapshotTempFileHelperChild.h
new file mode 100644
index 000000000..a1d433a5e
--- /dev/null
+++ b/dom/heapsnapshot/HeapSnapshotTempFileHelperChild.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et 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_devtools_HeapSnapshotTempFileHelperChild_h
+#define mozilla_devtools_HeapSnapshotTempFileHelperChild_h
+
+#include "mozilla/devtools/PHeapSnapshotTempFileHelperChild.h"
+
+namespace mozilla {
+namespace devtools {
+
+class HeapSnapshotTempFileHelperChild : public PHeapSnapshotTempFileHelperChild
+{
+ explicit HeapSnapshotTempFileHelperChild() { }
+
+public:
+ static inline PHeapSnapshotTempFileHelperChild* Create();
+};
+
+/* static */ inline PHeapSnapshotTempFileHelperChild*
+HeapSnapshotTempFileHelperChild::Create()
+{
+ return new HeapSnapshotTempFileHelperChild();
+}
+
+} // namespace devtools
+} // namespace mozilla
+
+#endif // mozilla_devtools_HeapSnapshotTempFileHelperChild_h
diff --git a/dom/heapsnapshot/HeapSnapshotTempFileHelperParent.cpp b/dom/heapsnapshot/HeapSnapshotTempFileHelperParent.cpp
new file mode 100644
index 000000000..7246a9daa
--- /dev/null
+++ b/dom/heapsnapshot/HeapSnapshotTempFileHelperParent.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et 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/devtools/HeapSnapshot.h"
+#include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
+#include "mozilla/ErrorResult.h"
+#include "private/pprio.h"
+
+#include "nsIFile.h"
+
+namespace mozilla {
+namespace devtools {
+
+using ipc::FileDescriptor;
+
+static bool
+openFileFailure(ErrorResult& rv,
+ OpenHeapSnapshotTempFileResponse* outResponse)
+{
+ *outResponse = rv.StealNSResult();
+ return true;
+}
+
+bool
+HeapSnapshotTempFileHelperParent::RecvOpenHeapSnapshotTempFile(
+ OpenHeapSnapshotTempFileResponse* outResponse)
+{
+ auto start = TimeStamp::Now();
+ ErrorResult rv;
+ nsAutoString filePath;
+ nsCOMPtr<nsIFile> file = HeapSnapshot::CreateUniqueCoreDumpFile(rv,
+ start,
+ filePath);
+ if (NS_WARN_IF(rv.Failed()))
+ return openFileFailure(rv, outResponse);
+
+ PRFileDesc* prfd;
+ rv = file->OpenNSPRFileDesc(PR_WRONLY, 0, &prfd);
+ if (NS_WARN_IF(rv.Failed()))
+ return openFileFailure(rv, outResponse);
+
+ FileDescriptor::PlatformHandleType handle =
+ FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(prfd));
+ FileDescriptor fd(handle);
+ *outResponse = OpenedFile(filePath, fd);
+ return true;
+}
+
+} // namespace devtools
+} // namespace mozilla
diff --git a/dom/heapsnapshot/HeapSnapshotTempFileHelperParent.h b/dom/heapsnapshot/HeapSnapshotTempFileHelperParent.h
new file mode 100644
index 000000000..1582279da
--- /dev/null
+++ b/dom/heapsnapshot/HeapSnapshotTempFileHelperParent.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et 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_devtools_HeapSnapshotTempFileHelperParent_h
+#define mozilla_devtools_HeapSnapshotTempFileHelperParent_h
+
+#include "mozilla/devtools/PHeapSnapshotTempFileHelperParent.h"
+
+namespace mozilla {
+namespace devtools {
+
+class HeapSnapshotTempFileHelperParent : public PHeapSnapshotTempFileHelperParent
+{
+ explicit HeapSnapshotTempFileHelperParent() { }
+ void ActorDestroy(ActorDestroyReason why) override { }
+ bool RecvOpenHeapSnapshotTempFile(OpenHeapSnapshotTempFileResponse* outResponse)
+ override;
+
+ public:
+ static inline PHeapSnapshotTempFileHelperParent* Create();
+};
+
+/* static */ inline PHeapSnapshotTempFileHelperParent*
+HeapSnapshotTempFileHelperParent::Create()
+{
+ return new HeapSnapshotTempFileHelperParent();
+}
+
+} // namespace devtools
+} // namespace mozilla
+
+#endif // mozilla_devtools_HeapSnapshotTempFileHelperParent_h
diff --git a/dom/heapsnapshot/PHeapSnapshotTempFileHelper.ipdl b/dom/heapsnapshot/PHeapSnapshotTempFileHelper.ipdl
new file mode 100644
index 000000000..2576470e2
--- /dev/null
+++ b/dom/heapsnapshot/PHeapSnapshotTempFileHelper.ipdl
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 PContent;
+
+namespace mozilla {
+namespace devtools {
+
+struct OpenedFile
+{
+ nsString path;
+ FileDescriptor descriptor;
+};
+
+union OpenHeapSnapshotTempFileResponse
+{
+ nsresult;
+ OpenedFile;
+};
+
+sync protocol PHeapSnapshotTempFileHelper
+{
+ manager PContent;
+
+parent:
+ sync OpenHeapSnapshotTempFile() returns (OpenHeapSnapshotTempFileResponse response);
+
+ async __delete__();
+};
+
+} // namespace devtools
+} // namespace mozilla
diff --git a/dom/heapsnapshot/ZeroCopyNSIOutputStream.cpp b/dom/heapsnapshot/ZeroCopyNSIOutputStream.cpp
new file mode 100644
index 000000000..0c29db7f9
--- /dev/null
+++ b/dom/heapsnapshot/ZeroCopyNSIOutputStream.cpp
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/devtools/ZeroCopyNSIOutputStream.h"
+
+#include "mozilla/DebugOnly.h"
+#include "mozilla/Unused.h"
+
+namespace mozilla {
+namespace devtools {
+
+ZeroCopyNSIOutputStream::ZeroCopyNSIOutputStream(nsCOMPtr<nsIOutputStream>& out)
+ : out(out)
+ , result_(NS_OK)
+ , amountUsed(0)
+ , writtenCount(0)
+{
+ DebugOnly<bool> nonBlocking = false;
+ MOZ_ASSERT(out->IsNonBlocking(&nonBlocking) == NS_OK);
+ MOZ_ASSERT(!nonBlocking);
+}
+
+ZeroCopyNSIOutputStream::~ZeroCopyNSIOutputStream()
+{
+ if (!failed())
+ Unused << NS_WARN_IF(NS_FAILED(writeBuffer()));
+}
+
+nsresult
+ZeroCopyNSIOutputStream::writeBuffer()
+{
+ if (failed())
+ return result_;
+
+ if (amountUsed == 0)
+ return NS_OK;
+
+ int32_t amountWritten = 0;
+ while (amountWritten < amountUsed) {
+ uint32_t justWritten = 0;
+
+ result_ = out->Write(buffer + amountWritten,
+ amountUsed - amountWritten,
+ &justWritten);
+ if (NS_WARN_IF(NS_FAILED(result_)))
+ return result_;
+
+ amountWritten += justWritten;
+ }
+
+ writtenCount += amountUsed;
+ amountUsed = 0;
+ return NS_OK;
+}
+
+// ZeroCopyOutputStream Interface
+
+bool
+ZeroCopyNSIOutputStream::Next(void** data, int* size)
+{
+ MOZ_ASSERT(data != nullptr);
+ MOZ_ASSERT(size != nullptr);
+
+ if (failed())
+ return false;
+
+ if (amountUsed == BUFFER_SIZE) {
+ if (NS_FAILED(writeBuffer()))
+ return false;
+ }
+
+ *data = buffer + amountUsed;
+ *size = BUFFER_SIZE - amountUsed;
+ amountUsed = BUFFER_SIZE;
+ return true;
+}
+
+void
+ZeroCopyNSIOutputStream::BackUp(int count)
+{
+ MOZ_ASSERT(count >= 0,
+ "Cannot back up a negative amount of bytes.");
+ MOZ_ASSERT(amountUsed == BUFFER_SIZE,
+ "Can only call BackUp directly after calling Next.");
+ MOZ_ASSERT(count <= amountUsed,
+ "Can't back up further than we've given out.");
+
+ amountUsed -= count;
+}
+
+::google::protobuf::int64
+ZeroCopyNSIOutputStream::ByteCount() const
+{
+ return writtenCount + amountUsed;
+}
+
+} // namespace devtools
+} // namespace mozilla
diff --git a/dom/heapsnapshot/ZeroCopyNSIOutputStream.h b/dom/heapsnapshot/ZeroCopyNSIOutputStream.h
new file mode 100644
index 000000000..117fc0f87
--- /dev/null
+++ b/dom/heapsnapshot/ZeroCopyNSIOutputStream.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_devtools_ZeroCopyNSIOutputStream__
+#define mozilla_devtools_ZeroCopyNSIOutputStream__
+
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/common.h>
+
+#include "nsCOMPtr.h"
+#include "nsIOutputStream.h"
+
+namespace mozilla {
+namespace devtools {
+
+// A `google::protobuf::io::ZeroCopyOutputStream` implementation that uses an
+// `nsIOutputStream` under the covers.
+//
+// This class will automatically write and flush its data to the
+// `nsIOutputStream` in its destructor, but if you care whether that call
+// succeeds or fails, then you should call the `flush` method yourself. Errors
+// will be logged, however.
+class MOZ_STACK_CLASS ZeroCopyNSIOutputStream
+ : public ::google::protobuf::io::ZeroCopyOutputStream
+{
+ static const int BUFFER_SIZE = 8192;
+
+ // The nsIOutputStream we are streaming to.
+ nsCOMPtr<nsIOutputStream>& out;
+
+ // The buffer we write data to before passing it to the output stream.
+ char buffer[BUFFER_SIZE];
+
+ // The status of writing to the underlying output stream.
+ nsresult result_;
+
+ // The number of bytes in the buffer that have been used thus far.
+ int amountUsed;
+
+ // Excluding the amount of the buffer currently used (which hasn't been
+ // written and flushed yet), this is the number of bytes written to the output
+ // stream.
+ int64_t writtenCount;
+
+ // Write the internal buffer to the output stream and flush it.
+ nsresult writeBuffer();
+
+public:
+ explicit ZeroCopyNSIOutputStream(nsCOMPtr<nsIOutputStream>& out);
+
+ nsresult flush() { return writeBuffer(); }
+
+ // Return true if writing to the underlying output stream ever failed.
+ bool failed() const { return NS_FAILED(result_); }
+
+ nsresult result() const { return result_; }
+
+ // ZeroCopyOutputStream Interface
+ virtual ~ZeroCopyNSIOutputStream() override;
+ virtual bool Next(void** data, int* size) override;
+ virtual void BackUp(int count) override;
+ virtual ::google::protobuf::int64 ByteCount() const override;
+};
+
+} // namespace devtools
+} // namespace mozilla
+
+#endif // mozilla_devtools_ZeroCopyNSIOutputStream__
diff --git a/dom/heapsnapshot/generate-core-dump-sources.sh b/dom/heapsnapshot/generate-core-dump-sources.sh
new file mode 100644
index 000000000..97e492ff0
--- /dev/null
+++ b/dom/heapsnapshot/generate-core-dump-sources.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+# A script to generate devtools/server/CoreDump.pb.{h,cc} from
+# devtools/server/CoreDump.proto. This script assumes you have
+# downloaded and installed the protocol buffer compiler, and that it is either
+# on your $PATH or located at $PROTOC_PATH.
+#
+# These files were last compiled with libprotoc 2.4.1.
+
+set -e
+
+cd $(dirname $0)
+
+if [ -n $PROTOC_PATH ]; then
+ PROTOC_PATH=`which protoc`
+fi
+
+if [ ! -e $PROTOC_PATH ]; then
+ echo You must install the protocol compiler from
+ echo https://code.google.com/p/protobuf/downloads/list
+ exit 1
+fi
+
+echo Using $PROTOC_PATH as the protocol compiler
+
+$PROTOC_PATH --cpp_out="." CoreDump.proto
diff --git a/dom/heapsnapshot/moz.build b/dom/heapsnapshot/moz.build
new file mode 100644
index 000000000..3fb6b0552
--- /dev/null
+++ b/dom/heapsnapshot/moz.build
@@ -0,0 +1,52 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+with Files('**'):
+ BUG_COMPONENT = ('Firefox', 'Developer Tools: Memory')
+
+if CONFIG['ENABLE_TESTS']:
+ DIRS += ['tests/gtest']
+
+XPCSHELL_TESTS_MANIFESTS += [ 'tests/unit/xpcshell.ini' ]
+MOCHITEST_MANIFESTS += [ 'tests/mochitest/mochitest.ini' ]
+MOCHITEST_CHROME_MANIFESTS += [ 'tests/mochitest/chrome.ini' ]
+
+EXPORTS.mozilla.devtools += [
+ 'AutoMemMap.h',
+ 'CoreDump.pb.h',
+ 'DeserializedNode.h',
+ 'DominatorTree.h',
+ 'FileDescriptorOutputStream.h',
+ 'HeapSnapshot.h',
+ 'HeapSnapshotTempFileHelperChild.h',
+ 'HeapSnapshotTempFileHelperParent.h',
+ 'ZeroCopyNSIOutputStream.h',
+]
+
+IPDL_SOURCES += [
+ 'PHeapSnapshotTempFileHelper.ipdl',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+SOURCES += [
+ 'AutoMemMap.cpp',
+ 'CoreDump.pb.cc',
+ 'DeserializedNode.cpp',
+ 'DominatorTree.cpp',
+ 'FileDescriptorOutputStream.cpp',
+ 'HeapSnapshot.cpp',
+ 'HeapSnapshotTempFileHelperParent.cpp',
+ 'ZeroCopyNSIOutputStream.cpp',
+]
+
+# Disable RTTI in google protocol buffer
+DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True
+
+FINAL_LIBRARY = 'xul'
+
+if CONFIG['GNU_CXX']:
+ CXXFLAGS += ['-Wno-error=shadow']
diff --git a/dom/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp b/dom/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp
new file mode 100644
index 000000000..e236a0acf
--- /dev/null
+++ b/dom/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Test that the `JS::ubi::Node`s we create from
+// `mozilla::devtools::DeserializedNode` instances look and behave as we would
+// like.
+
+#include "DevTools.h"
+#include "js/TypeDecls.h"
+#include "mozilla/devtools/DeserializedNode.h"
+
+using testing::Field;
+using testing::ReturnRef;
+
+// A mock DeserializedNode for testing.
+struct MockDeserializedNode : public DeserializedNode
+{
+ MockDeserializedNode(NodeId id, const char16_t* typeName, uint64_t size)
+ : DeserializedNode(id, typeName, size)
+ { }
+
+ bool addEdge(DeserializedEdge&& edge)
+ {
+ return edges.append(Move(edge));
+ }
+
+ MOCK_METHOD1(getEdgeReferent, JS::ubi::Node(const DeserializedEdge&));
+};
+
+size_t fakeMallocSizeOf(const void*) {
+ EXPECT_TRUE(false);
+ MOZ_ASSERT_UNREACHABLE("fakeMallocSizeOf should never be called because "
+ "DeserializedNodes report the deserialized size.");
+ return 0;
+}
+
+DEF_TEST(DeserializedNodeUbiNodes, {
+ const char16_t* typeName = u"TestTypeName";
+ const char* className = "MyObjectClassName";
+ const char* filename = "my-cool-filename.js";
+
+ NodeId id = uint64_t(1) << 33;
+ uint64_t size = uint64_t(1) << 60;
+ MockDeserializedNode mocked(id, typeName, size);
+ mocked.coarseType = JS::ubi::CoarseType::Script;
+ mocked.jsObjectClassName = className;
+ mocked.scriptFilename = filename;
+
+ DeserializedNode& deserialized = mocked;
+ JS::ubi::Node ubi(&deserialized);
+
+ // Test the ubi::Node accessors.
+
+ EXPECT_EQ(size, ubi.size(fakeMallocSizeOf));
+ EXPECT_EQ(typeName, ubi.typeName());
+ EXPECT_EQ(JS::ubi::CoarseType::Script, ubi.coarseType());
+ EXPECT_EQ(id, ubi.identifier());
+ EXPECT_FALSE(ubi.isLive());
+ EXPECT_EQ(ubi.jsObjectClassName(), className);
+ EXPECT_EQ(ubi.scriptFilename(), filename);
+
+ // Test the ubi::Node's edges.
+
+ UniquePtr<DeserializedNode> referent1(new MockDeserializedNode(1,
+ nullptr,
+ 10));
+ DeserializedEdge edge1(referent1->id);
+ mocked.addEdge(Move(edge1));
+ EXPECT_CALL(mocked, getEdgeReferent(EdgeTo(referent1->id)))
+ .Times(1)
+ .WillOnce(Return(JS::ubi::Node(referent1.get())));
+
+ UniquePtr<DeserializedNode> referent2(new MockDeserializedNode(2,
+ nullptr,
+ 20));
+ DeserializedEdge edge2(referent2->id);
+ mocked.addEdge(Move(edge2));
+ EXPECT_CALL(mocked, getEdgeReferent(EdgeTo(referent2->id)))
+ .Times(1)
+ .WillOnce(Return(JS::ubi::Node(referent2.get())));
+
+ UniquePtr<DeserializedNode> referent3(new MockDeserializedNode(3,
+ nullptr,
+ 30));
+ DeserializedEdge edge3(referent3->id);
+ mocked.addEdge(Move(edge3));
+ EXPECT_CALL(mocked, getEdgeReferent(EdgeTo(referent3->id)))
+ .Times(1)
+ .WillOnce(Return(JS::ubi::Node(referent3.get())));
+
+ auto range = ubi.edges(cx);
+ ASSERT_TRUE(!!range);
+
+ for ( ; !range->empty(); range->popFront()) {
+ // Nothing to do here. This loop ensures that we get each edge referent
+ // that we expect above.
+ }
+ });
diff --git a/dom/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp b/dom/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp
new file mode 100644
index 000000000..72e363934
--- /dev/null
+++ b/dom/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Test that the `JS::ubi::StackFrame`s we create from
+// `mozilla::devtools::DeserializedStackFrame` instances look and behave as we would
+// like.
+
+#include "DevTools.h"
+#include "js/TypeDecls.h"
+#include "mozilla/devtools/DeserializedNode.h"
+
+using testing::Field;
+using testing::ReturnRef;
+
+// A mock DeserializedStackFrame for testing.
+struct MockDeserializedStackFrame : public DeserializedStackFrame
+{
+ MockDeserializedStackFrame() : DeserializedStackFrame() { }
+};
+
+DEF_TEST(DeserializedStackFrameUbiStackFrames, {
+ StackFrameId id = uint64_t(1) << 42;
+ uint32_t line = 1337;
+ uint32_t column = 9; // 3 space tabs!?
+ const char16_t* source = u"my-javascript-file.js";
+ const char16_t* functionDisplayName = u"myFunctionName";
+
+ MockDeserializedStackFrame mocked;
+ mocked.id = id;
+ mocked.line = line;
+ mocked.column = column;
+ mocked.source = source;
+ mocked.functionDisplayName = functionDisplayName;
+
+ DeserializedStackFrame& deserialized = mocked;
+ JS::ubi::StackFrame ubiFrame(&deserialized);
+
+ // Test the JS::ubi::StackFrame accessors.
+
+ EXPECT_EQ(id, ubiFrame.identifier());
+ EXPECT_EQ(JS::ubi::StackFrame(), ubiFrame.parent());
+ EXPECT_EQ(line, ubiFrame.line());
+ EXPECT_EQ(column, ubiFrame.column());
+ EXPECT_EQ(JS::ubi::AtomOrTwoByteChars(source), ubiFrame.source());
+ EXPECT_EQ(JS::ubi::AtomOrTwoByteChars(functionDisplayName),
+ ubiFrame.functionDisplayName());
+ EXPECT_FALSE(ubiFrame.isSelfHosted(cx));
+ EXPECT_FALSE(ubiFrame.isSystem());
+
+ JS::RootedObject savedFrame(cx);
+ EXPECT_TRUE(ubiFrame.constructSavedFrameStack(cx, &savedFrame));
+
+ uint32_t frameLine;
+ ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameLine(cx, savedFrame, &frameLine));
+ EXPECT_EQ(line, frameLine);
+
+ uint32_t frameColumn;
+ ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameColumn(cx, savedFrame, &frameColumn));
+ EXPECT_EQ(column, frameColumn);
+
+ JS::RootedObject parent(cx);
+ ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameParent(cx, savedFrame, &parent));
+ EXPECT_EQ(nullptr, parent);
+
+ ASSERT_EQ(NS_strlen(source), 21U);
+ char16_t sourceBuf[21] = {};
+
+ // Test when the length is shorter than the string length.
+ auto written = ubiFrame.source(RangedPtr<char16_t>(sourceBuf), 3);
+ EXPECT_EQ(written, 3U);
+ for (size_t i = 0; i < 3; i++) {
+ EXPECT_EQ(sourceBuf[i], source[i]);
+ }
+
+ written = ubiFrame.source(RangedPtr<char16_t>(sourceBuf), 21);
+ EXPECT_EQ(written, 21U);
+ for (size_t i = 0; i < 21; i++) {
+ EXPECT_EQ(sourceBuf[i], source[i]);
+ }
+
+ ASSERT_EQ(NS_strlen(functionDisplayName), 14U);
+ char16_t nameBuf[14] = {};
+
+ written = ubiFrame.functionDisplayName(RangedPtr<char16_t>(nameBuf), 14);
+ EXPECT_EQ(written, 14U);
+ for (size_t i = 0; i < 14; i++) {
+ EXPECT_EQ(nameBuf[i], functionDisplayName[i]);
+ }
+});
diff --git a/dom/heapsnapshot/tests/gtest/DevTools.h b/dom/heapsnapshot/tests/gtest/DevTools.h
new file mode 100644
index 000000000..6eb5cfe21
--- /dev/null
+++ b/dom/heapsnapshot/tests/gtest/DevTools.h
@@ -0,0 +1,276 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_devtools_gtest_DevTools__
+#define mozilla_devtools_gtest_DevTools__
+
+#include "CoreDump.pb.h"
+#include "jsapi.h"
+#include "jspubtd.h"
+#include "nsCRTGlue.h"
+
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+#include "mozilla/devtools/HeapSnapshot.h"
+#include "mozilla/dom/ChromeUtils.h"
+#include "mozilla/CycleCollectedJSContext.h"
+#include "mozilla/Move.h"
+#include "js/Principals.h"
+#include "js/UbiNode.h"
+#include "js/UniquePtr.h"
+
+using namespace mozilla;
+using namespace mozilla::devtools;
+using namespace mozilla::dom;
+using namespace testing;
+
+// GTest fixture class that all of our tests derive from.
+struct DevTools : public ::testing::Test {
+ bool _initialized;
+ JSContext* cx;
+ JSCompartment* compartment;
+ JS::Zone* zone;
+ JS::PersistentRootedObject global;
+
+ DevTools()
+ : _initialized(false),
+ cx(nullptr)
+ { }
+
+ virtual void SetUp() {
+ MOZ_ASSERT(!_initialized);
+
+ cx = getContext();
+ if (!cx)
+ return;
+
+ JS_BeginRequest(cx);
+
+ global.init(cx, createGlobal());
+ if (!global)
+ return;
+ JS_EnterCompartment(cx, global);
+
+ compartment = js::GetContextCompartment(cx);
+ zone = js::GetContextZone(cx);
+
+ _initialized = true;
+ }
+
+ JSContext* getContext() {
+ return CycleCollectedJSContext::Get()->Context();
+ }
+
+ static void reportError(JSContext* cx, const char* message, JSErrorReport* report) {
+ fprintf(stderr, "%s:%u:%s\n",
+ report->filename ? report->filename : "<no filename>",
+ (unsigned int) report->lineno,
+ message);
+ }
+
+ static const JSClass* getGlobalClass() {
+ static const JSClassOps globalClassOps = {
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr,
+ JS_GlobalObjectTraceHook
+ };
+ static const JSClass globalClass = {
+ "global", JSCLASS_GLOBAL_FLAGS,
+ &globalClassOps
+ };
+ return &globalClass;
+ }
+
+ JSObject* createGlobal()
+ {
+ /* Create the global object. */
+ JS::RootedObject newGlobal(cx);
+ JS::CompartmentOptions options;
+ options.behaviors().setVersion(JSVERSION_LATEST);
+ newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
+ JS::FireOnNewGlobalHook, options);
+ if (!newGlobal)
+ return nullptr;
+
+ JSAutoCompartment ac(cx, newGlobal);
+
+ /* Populate the global object with the standard globals, like Object and
+ Array. */
+ if (!JS_InitStandardClasses(cx, newGlobal))
+ return nullptr;
+
+ return newGlobal;
+ }
+
+ virtual void TearDown() {
+ _initialized = false;
+
+ if (global) {
+ JS_LeaveCompartment(cx, nullptr);
+ global = nullptr;
+ }
+ if (cx)
+ JS_EndRequest(cx);
+ }
+};
+
+
+// Helper to define a test and ensure that the fixture is initialized properly.
+#define DEF_TEST(name, body) \
+ TEST_F(DevTools, name) { \
+ ASSERT_TRUE(_initialized); \
+ body \
+ }
+
+
+// Fake JS::ubi::Node implementation
+class MOZ_STACK_CLASS FakeNode
+{
+public:
+ JS::ubi::EdgeVector edges;
+ JSCompartment* compartment;
+ JS::Zone* zone;
+ size_t size;
+
+ explicit FakeNode()
+ : edges(),
+ compartment(nullptr),
+ zone(nullptr),
+ size(1)
+ { }
+};
+
+namespace JS {
+namespace ubi {
+
+template<>
+class Concrete<FakeNode> : public Base
+{
+ const char16_t* typeName() const override {
+ return concreteTypeName;
+ }
+
+ js::UniquePtr<EdgeRange> edges(JSContext*, bool) const override {
+ return js::UniquePtr<EdgeRange>(js_new<PreComputedEdgeRange>(get().edges));
+ }
+
+ Size size(mozilla::MallocSizeOf) const override {
+ return get().size;
+ }
+
+ JS::Zone* zone() const override {
+ return get().zone;
+ }
+
+ JSCompartment* compartment() const override {
+ return get().compartment;
+ }
+
+protected:
+ explicit Concrete(FakeNode* ptr) : Base(ptr) { }
+ FakeNode& get() const { return *static_cast<FakeNode*>(ptr); }
+
+public:
+ static const char16_t concreteTypeName[];
+ static void construct(void* storage, FakeNode* ptr) {
+ new (storage) Concrete(ptr);
+ }
+};
+
+const char16_t Concrete<FakeNode>::concreteTypeName[] = u"FakeNode";
+
+} // namespace ubi
+} // namespace JS
+
+void AddEdge(FakeNode& node, FakeNode& referent, const char16_t* edgeName = nullptr) {
+ char16_t* ownedEdgeName = nullptr;
+ if (edgeName) {
+ ownedEdgeName = NS_strdup(edgeName);
+ ASSERT_NE(ownedEdgeName, nullptr);
+ }
+
+ JS::ubi::Edge edge(ownedEdgeName, &referent);
+ ASSERT_TRUE(node.edges.append(mozilla::Move(edge)));
+}
+
+
+// Custom GMock Matchers
+
+// Use the testing namespace to avoid static analysis failures in the gmock
+// matcher classes that get generated from MATCHER_P macros.
+namespace testing {
+
+// Ensure that given node has the expected number of edges.
+MATCHER_P2(EdgesLength, cx, expectedLength, "") {
+ auto edges = arg.edges(cx);
+ if (!edges)
+ return false;
+
+ int actualLength = 0;
+ for ( ; !edges->empty(); edges->popFront())
+ actualLength++;
+
+ return Matcher<int>(Eq(expectedLength))
+ .MatchAndExplain(actualLength, result_listener);
+}
+
+// Get the nth edge and match it with the given matcher.
+MATCHER_P3(Edge, cx, n, matcher, "") {
+ auto edges = arg.edges(cx);
+ if (!edges)
+ return false;
+
+ int i = 0;
+ for ( ; !edges->empty(); edges->popFront()) {
+ if (i == n) {
+ return Matcher<const JS::ubi::Edge&>(matcher)
+ .MatchAndExplain(edges->front(), result_listener);
+ }
+
+ i++;
+ }
+
+ return false;
+}
+
+// Ensures that two char16_t* strings are equal.
+MATCHER_P(UTF16StrEq, str, "") {
+ return NS_strcmp(arg, str) == 0;
+}
+
+MATCHER_P(UniqueUTF16StrEq, str, "") {
+ return NS_strcmp(arg.get(), str) == 0;
+}
+
+MATCHER(UniqueIsNull, "") {
+ return arg.get() == nullptr;
+}
+
+// Matches an edge whose referent is the node with the given id.
+MATCHER_P(EdgeTo, id, "") {
+ return Matcher<const DeserializedEdge&>(Field(&DeserializedEdge::referent, id))
+ .MatchAndExplain(arg, result_listener);
+}
+
+} // namespace testing
+
+
+// A mock `Writer` class to be used with testing `WriteHeapGraph`.
+class MockWriter : public CoreDumpWriter
+{
+public:
+ virtual ~MockWriter() override { }
+ MOCK_METHOD2(writeNode, bool(const JS::ubi::Node&, CoreDumpWriter::EdgePolicy));
+ MOCK_METHOD1(writeMetadata, bool(uint64_t));
+};
+
+void ExpectWriteNode(MockWriter& writer, FakeNode& node) {
+ EXPECT_CALL(writer, writeNode(Eq(JS::ubi::Node(&node)), _))
+ .Times(1)
+ .WillOnce(Return(true));
+}
+
+#endif // mozilla_devtools_gtest_DevTools__
diff --git a/dom/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp b/dom/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp
new file mode 100644
index 000000000..bc517d6d9
--- /dev/null
+++ b/dom/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Test that heap snapshots cross compartment boundaries when expected.
+
+#include "DevTools.h"
+
+DEF_TEST(DoesCrossCompartmentBoundaries, {
+ // Create a new global to get a new compartment.
+ JS::CompartmentOptions options;
+ JS::RootedObject newGlobal(cx, JS_NewGlobalObject(cx,
+ getGlobalClass(),
+ nullptr,
+ JS::FireOnNewGlobalHook,
+ options));
+ ASSERT_TRUE(newGlobal);
+ JSCompartment* newCompartment = nullptr;
+ {
+ JSAutoCompartment ac(cx, newGlobal);
+ ASSERT_TRUE(JS_InitStandardClasses(cx, newGlobal));
+ newCompartment = js::GetContextCompartment(cx);
+ }
+ ASSERT_TRUE(newCompartment);
+ ASSERT_NE(newCompartment, compartment);
+
+ // Our set of target compartments is both the old and new compartments.
+ JS::CompartmentSet targetCompartments;
+ ASSERT_TRUE(targetCompartments.init());
+ ASSERT_TRUE(targetCompartments.put(compartment));
+ ASSERT_TRUE(targetCompartments.put(newCompartment));
+
+ FakeNode nodeA;
+ FakeNode nodeB;
+ FakeNode nodeC;
+ FakeNode nodeD;
+
+ nodeA.compartment = compartment;
+ nodeB.compartment = nullptr;
+ nodeC.compartment = newCompartment;
+ nodeD.compartment = nullptr;
+
+ AddEdge(nodeA, nodeB);
+ AddEdge(nodeA, nodeC);
+ AddEdge(nodeB, nodeD);
+
+ ::testing::NiceMock<MockWriter> writer;
+
+ // Should serialize nodeA, because it is in one of our target compartments.
+ ExpectWriteNode(writer, nodeA);
+
+ // Should serialize nodeB, because it doesn't belong to a compartment and is
+ // therefore assumed to be shared.
+ ExpectWriteNode(writer, nodeB);
+
+ // Should also serialize nodeC, which is in our target compartments, but a
+ // different compartment than A.
+ ExpectWriteNode(writer, nodeC);
+
+ // Should serialize nodeD because it's reachable via B and both nodes B and D
+ // don't belong to a specific compartment.
+ ExpectWriteNode(writer, nodeD);
+
+ JS::AutoCheckCannotGC noGC(cx);
+
+ ASSERT_TRUE(WriteHeapGraph(cx,
+ JS::ubi::Node(&nodeA),
+ writer,
+ /* wantNames = */ false,
+ &targetCompartments,
+ noGC));
+ });
diff --git a/dom/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp b/dom/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp
new file mode 100644
index 000000000..2fe5e6ace
--- /dev/null
+++ b/dom/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Test that heap snapshots walk the compartment boundaries correctly.
+
+#include "DevTools.h"
+
+DEF_TEST(DoesntCrossCompartmentBoundaries, {
+ // Create a new global to get a new compartment.
+ JS::CompartmentOptions options;
+ JS::RootedObject newGlobal(cx, JS_NewGlobalObject(cx,
+ getGlobalClass(),
+ nullptr,
+ JS::FireOnNewGlobalHook,
+ options));
+ ASSERT_TRUE(newGlobal);
+ JSCompartment* newCompartment = nullptr;
+ {
+ JSAutoCompartment ac(cx, newGlobal);
+ ASSERT_TRUE(JS_InitStandardClasses(cx, newGlobal));
+ newCompartment = js::GetContextCompartment(cx);
+ }
+ ASSERT_TRUE(newCompartment);
+ ASSERT_NE(newCompartment, compartment);
+
+ // Our set of target compartments is only the pre-existing compartment and
+ // does not include the new compartment.
+ JS::CompartmentSet targetCompartments;
+ ASSERT_TRUE(targetCompartments.init());
+ ASSERT_TRUE(targetCompartments.put(compartment));
+
+ FakeNode nodeA;
+ FakeNode nodeB;
+ FakeNode nodeC;
+
+ nodeA.compartment = compartment;
+ nodeB.compartment = nullptr;
+ nodeC.compartment = newCompartment;
+
+ AddEdge(nodeA, nodeB);
+ AddEdge(nodeB, nodeC);
+
+ ::testing::NiceMock<MockWriter> writer;
+
+ // Should serialize nodeA, because it is in our target compartments.
+ ExpectWriteNode(writer, nodeA);
+
+ // Should serialize nodeB, because it doesn't belong to a compartment and is
+ // therefore assumed to be shared.
+ ExpectWriteNode(writer, nodeB);
+
+ // But we shouldn't ever serialize nodeC.
+
+ JS::AutoCheckCannotGC noGC(cx);
+
+ ASSERT_TRUE(WriteHeapGraph(cx,
+ JS::ubi::Node(&nodeA),
+ writer,
+ /* wantNames = */ false,
+ &targetCompartments,
+ noGC));
+ });
diff --git a/dom/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp b/dom/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp
new file mode 100644
index 000000000..be135dbb4
--- /dev/null
+++ b/dom/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Test that edge names get serialized correctly.
+
+#include "DevTools.h"
+
+using testing::Field;
+using testing::IsNull;
+using testing::Property;
+using testing::Return;
+
+DEF_TEST(SerializesEdgeNames, {
+ FakeNode node;
+ FakeNode referent;
+
+ const char16_t edgeName[] = u"edge name";
+ const char16_t emptyStr[] = u"";
+
+ AddEdge(node, referent, edgeName);
+ AddEdge(node, referent, emptyStr);
+ AddEdge(node, referent, nullptr);
+
+ ::testing::NiceMock<MockWriter> writer;
+
+ // Should get the node with edges once.
+ EXPECT_CALL(
+ writer,
+ writeNode(AllOf(EdgesLength(cx, 3),
+ Edge(cx, 0, Field(&JS::ubi::Edge::name,
+ UniqueUTF16StrEq(edgeName))),
+ Edge(cx, 1, Field(&JS::ubi::Edge::name,
+ UniqueUTF16StrEq(emptyStr))),
+ Edge(cx, 2, Field(&JS::ubi::Edge::name,
+ UniqueIsNull()))),
+ _)
+ )
+ .Times(1)
+ .WillOnce(Return(true));
+
+ // Should get the referent node that doesn't have any edges once.
+ ExpectWriteNode(writer, referent);
+
+ JS::AutoCheckCannotGC noGC(cx);
+ ASSERT_TRUE(WriteHeapGraph(cx,
+ JS::ubi::Node(&node),
+ writer,
+ /* wantNames = */ true,
+ /* zones = */ nullptr,
+ noGC));
+ });
diff --git a/dom/heapsnapshot/tests/gtest/SerializesEverythingInHeapGraphOnce.cpp b/dom/heapsnapshot/tests/gtest/SerializesEverythingInHeapGraphOnce.cpp
new file mode 100644
index 000000000..475442df8
--- /dev/null
+++ b/dom/heapsnapshot/tests/gtest/SerializesEverythingInHeapGraphOnce.cpp
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Test that everything in the heap graph gets serialized once, and only once.
+
+#include "DevTools.h"
+
+DEF_TEST(SerializesEverythingInHeapGraphOnce, {
+ FakeNode nodeA;
+ FakeNode nodeB;
+ FakeNode nodeC;
+ FakeNode nodeD;
+
+ AddEdge(nodeA, nodeB);
+ AddEdge(nodeB, nodeC);
+ AddEdge(nodeC, nodeD);
+ AddEdge(nodeD, nodeA);
+
+ ::testing::NiceMock<MockWriter> writer;
+
+ // Should serialize each node once.
+ ExpectWriteNode(writer, nodeA);
+ ExpectWriteNode(writer, nodeB);
+ ExpectWriteNode(writer, nodeC);
+ ExpectWriteNode(writer, nodeD);
+
+ JS::AutoCheckCannotGC noGC(cx);
+
+ ASSERT_TRUE(WriteHeapGraph(cx,
+ JS::ubi::Node(&nodeA),
+ writer,
+ /* wantNames = */ false,
+ /* zones = */ nullptr,
+ noGC));
+ });
diff --git a/dom/heapsnapshot/tests/gtest/SerializesTypeNames.cpp b/dom/heapsnapshot/tests/gtest/SerializesTypeNames.cpp
new file mode 100644
index 000000000..a259c297b
--- /dev/null
+++ b/dom/heapsnapshot/tests/gtest/SerializesTypeNames.cpp
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Test that a ubi::Node's typeName gets properly serialized into a core dump.
+
+#include "DevTools.h"
+
+using testing::Property;
+using testing::Return;
+
+DEF_TEST(SerializesTypeNames, {
+ FakeNode node;
+
+ ::testing::NiceMock<MockWriter> writer;
+ EXPECT_CALL(writer, writeNode(Property(&JS::ubi::Node::typeName,
+ UTF16StrEq(u"FakeNode")),
+ _))
+ .Times(1)
+ .WillOnce(Return(true));
+
+ JS::AutoCheckCannotGC noGC(cx);
+ ASSERT_TRUE(WriteHeapGraph(cx,
+ JS::ubi::Node(&node),
+ writer,
+ /* wantNames = */ true,
+ /* zones = */ nullptr,
+ noGC));
+ });
diff --git a/dom/heapsnapshot/tests/gtest/moz.build b/dom/heapsnapshot/tests/gtest/moz.build
new file mode 100644
index 000000000..08c31e47c
--- /dev/null
+++ b/dom/heapsnapshot/tests/gtest/moz.build
@@ -0,0 +1,31 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at http://mozilla.org/MPL/2.0/.
+
+Library('devtoolstests')
+
+LOCAL_INCLUDES += [
+ '../..',
+]
+
+UNIFIED_SOURCES = [
+ 'DeserializedNodeUbiNodes.cpp',
+ 'DeserializedStackFrameUbiStackFrames.cpp',
+ 'DoesCrossCompartmentBoundaries.cpp',
+ 'DoesntCrossCompartmentBoundaries.cpp',
+ 'SerializesEdgeNames.cpp',
+ 'SerializesEverythingInHeapGraphOnce.cpp',
+ 'SerializesTypeNames.cpp',
+]
+
+if CONFIG['GNU_CXX']:
+ CXXFLAGS += ['-Wno-error=shadow']
+
+# THE MOCK_METHOD2 macro from gtest triggers this clang warning and it's hard
+# to work around, so we just ignore it.
+if CONFIG['CLANG_CXX']:
+ CXXFLAGS += ['-Wno-inconsistent-missing-override']
+
+FINAL_LIBRARY = 'xul-gtest'
diff --git a/dom/heapsnapshot/tests/mochitest/chrome.ini b/dom/heapsnapshot/tests/mochitest/chrome.ini
new file mode 100644
index 000000000..497b6fe37
--- /dev/null
+++ b/dom/heapsnapshot/tests/mochitest/chrome.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+tags = devtools devtools-memory
+skip-if = os == 'android'
+support-files =
+
+[test_DominatorTree_01.html]
+[test_SaveHeapSnapshot.html]
+
diff --git a/dom/heapsnapshot/tests/mochitest/mochitest.ini b/dom/heapsnapshot/tests/mochitest/mochitest.ini
new file mode 100644
index 000000000..5e7aa8d10
--- /dev/null
+++ b/dom/heapsnapshot/tests/mochitest/mochitest.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+tags = devtools devtools-memory
+support-files =
+
+[test_saveHeapSnapshot_e10s_01.html]
+
diff --git a/dom/heapsnapshot/tests/mochitest/test_DominatorTree_01.html b/dom/heapsnapshot/tests/mochitest/test_DominatorTree_01.html
new file mode 100644
index 000000000..1f9d8c080
--- /dev/null
+++ b/dom/heapsnapshot/tests/mochitest/test_DominatorTree_01.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Sanity test that we can compute dominator trees from a heap snapshot in a web window.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>ChromeUtils.saveHeapSnapshot test</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>
+<pre id="test">
+<script>
+SimpleTest.waitForExplicitFinish();
+window.onload = function() {
+ const path = ChromeUtils.saveHeapSnapshot({ runtime: true });
+ const snapshot = ChromeUtils.readHeapSnapshot(path);
+
+ const dominatorTree = snapshot.computeDominatorTree();
+ ok(dominatorTree);
+ ok(dominatorTree instanceof DominatorTree);
+
+ let threw = false;
+ try {
+ new DominatorTree();
+ } catch (e) {
+ threw = true;
+ }
+ ok(threw, "Constructor shouldn't be usable");
+
+ SimpleTest.finish();
+};
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/heapsnapshot/tests/mochitest/test_SaveHeapSnapshot.html b/dom/heapsnapshot/tests/mochitest/test_SaveHeapSnapshot.html
new file mode 100644
index 000000000..f150a99c7
--- /dev/null
+++ b/dom/heapsnapshot/tests/mochitest/test_SaveHeapSnapshot.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Bug 1024774 - Sanity test that we can take a heap snapshot in a web window.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>ChromeUtils.saveHeapSnapshot test</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>
+<pre id="test">
+<script>
+SimpleTest.waitForExplicitFinish();
+window.onload = function() {
+ ok(ChromeUtils, "The ChromeUtils interface should be exposed in chrome windows.");
+ ChromeUtils.saveHeapSnapshot({ runtime: true });
+ ok(true, "Should save a heap snapshot and shouldn't throw.");
+ SimpleTest.finish();
+};
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/heapsnapshot/tests/mochitest/test_saveHeapSnapshot_e10s_01.html b/dom/heapsnapshot/tests/mochitest/test_saveHeapSnapshot_e10s_01.html
new file mode 100644
index 000000000..15f88f8e0
--- /dev/null
+++ b/dom/heapsnapshot/tests/mochitest/test_saveHeapSnapshot_e10s_01.html
@@ -0,0 +1,82 @@
+<!DOCTYPE HTML>
+<!--
+Bug 1201597 - Sanity test that we can take a heap snapshot in an e10s child process.
+-->
+<html>
+<head>
+ <title>saveHeapSnapshot in e10s child processes</title>
+ <script type="application/javascript"
+ src="/tests/SimpleTest/SimpleTest.js">
+ </script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+ <script type="application/javascript">
+ window.onerror = function (msg, url, line, col, err) {
+ ok(false, "@" + url + ":" + line + ":" + col + ": " + msg + "\n" + err.stack);
+ };
+
+ SimpleTest.waitForExplicitFinish();
+
+ var childFrameURL = "data:text/html,<!DOCTYPE HTML><html><body></body></html>";
+
+ // This function is stringified and loaded in the child process as a frame
+ // script.
+ function childFrameScript() {
+ try {
+ ChromeUtils.saveHeapSnapshot({ runtime: true });
+ } catch (err) {
+ sendAsyncMessage("testSaveHeapSnapshot:error",
+ { error: err.toString() });
+ return;
+ }
+
+ sendAsyncMessage("testSaveHeapSnapshot:done", {});
+ }
+
+ // Kick everything off on load.
+ window.onload = function () {
+ info("window.onload fired");
+ SpecialPowers.addPermission("browser", true, document);
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["dom.ipc.browser_frames.oop_by_default", true],
+ ["dom.mozBrowserFramesEnabled", true],
+ ["browser.pagethumbnails.capturing_disabled", true]
+ ]
+ }, function () {
+ var iframe = document.createElement("iframe");
+ SpecialPowers.wrap(iframe).mozbrowser = true;
+ iframe.id = "iframe";
+ iframe.src = childFrameURL;
+
+
+ iframe.addEventListener("mozbrowserloadend", function onLoadEnd() {
+ iframe.removeEventListener("mozbrowserloadend", onLoadEnd);
+ info("iframe done loading");
+
+ var mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+
+ function onError(e) {
+ ok(false, e.data.error);
+ }
+ mm.addMessageListener("testSaveHeapSnapshot:error", onError);
+
+ mm.addMessageListener("testSaveHeapSnapshot:done", function onMsg() {
+ mm.removeMessageListener("testSaveHeapSnapshot:done", onMsg);
+ mm.removeMessageListener("testSaveHeapSnapshot:error", onError);
+ ok(true, "Saved heap snapshot in child process");
+ SimpleTest.finish();
+ });
+
+ info("Loading frame script to save heap snapshot");
+ mm.loadFrameScript("data:,(" + encodeURI(childFrameScript.toString()) + ")();",
+ false);
+ });
+
+ info("Loading iframe");
+ document.body.appendChild(iframe);
+ });
+ };
+ </script>
+</window>
diff --git a/dom/heapsnapshot/tests/unit/.eslintrc.js b/dom/heapsnapshot/tests/unit/.eslintrc.js
new file mode 100644
index 000000000..59adf410a
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/.eslintrc.js
@@ -0,0 +1,6 @@
+"use strict";
+
+module.exports = {
+ // Extend from the common devtools xpcshell eslintrc config.
+ "extends": "../../../../.eslintrc.xpcshell.js"
+};
diff --git a/dom/heapsnapshot/tests/unit/Census.jsm b/dom/heapsnapshot/tests/unit/Census.jsm
new file mode 100644
index 000000000..f8fb1ce44
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/Census.jsm
@@ -0,0 +1,165 @@
+// Functions for checking results returned by
+// Debugger.Memory.prototype.takeCensus and
+// HeapSnapshot.prototype.takeCensus. Adapted from js/src/jit-test/lib/census.js.
+
+this.EXPORTED_SYMBOLS = ["Census"];
+
+this.Census = (function () {
+ const Census = {};
+
+ function dumpn(msg) {
+ dump("DBG-TEST: Census.jsm: " + msg + "\n");
+ }
+
+ // Census.walkCensus(subject, name, walker)
+ //
+ // Use |walker| to check |subject|, a census object of the sort returned by
+ // Debugger.Memory.prototype.takeCensus: a tree of objects with integers at the
+ // leaves. Use |name| as the name for |subject| in diagnostic messages. Return
+ // the number of leaves of |subject| we visited.
+ //
+ // A walker is an object with three methods:
+ //
+ // - enter(prop): Return the walker we should use to check the property of the
+ // subject census named |prop|. This is for recursing into the subobjects of
+ // the subject.
+ //
+ // - done(): Called after we have called 'enter' on every property of the
+ // subject.
+ //
+ // - check(value): Check |value|, a leaf in the subject.
+ //
+ // Walker methods are expected to simply throw if a node we visit doesn't look
+ // right.
+ Census.walkCensus = (subject, name, walker) => walk(subject, name, walker, 0);
+ function walk(subject, name, walker, count) {
+ if (typeof subject === "object") {
+ dumpn(name);
+ for (let prop in subject) {
+ count = walk(subject[prop],
+ name + "[" + uneval(prop) + "]",
+ walker.enter(prop),
+ count);
+ }
+ walker.done();
+ } else {
+ dumpn(name + " = " + uneval(subject));
+ walker.check(subject);
+ count++;
+ }
+
+ return count;
+ }
+
+ // A walker that doesn't check anything.
+ Census.walkAnything = {
+ enter: () => Census.walkAnything,
+ done: () => undefined,
+ check: () => undefined
+ };
+
+ // A walker that requires all leaves to be zeros.
+ Census.assertAllZeros = {
+ enter: () => Census.assertAllZeros,
+ done: () => undefined,
+ check: elt => { if (elt !== 0) throw new Error("Census mismatch: expected zero, found " + elt); }
+ };
+
+ function expectedObject() {
+ throw new Error("Census mismatch: subject has leaf where basis has nested object");
+ }
+
+ function expectedLeaf() {
+ throw new Error("Census mismatch: subject has nested object where basis has leaf");
+ }
+
+ // Return a function that, given a 'basis' census, returns a census walker that
+ // compares the subject census against the basis. The returned walker calls the
+ // given |compare|, |missing|, and |extra| functions as follows:
+ //
+ // - compare(subjectLeaf, basisLeaf): Check a leaf of the subject against the
+ // corresponding leaf of the basis.
+ //
+ // - missing(prop, value): Called when the subject is missing a property named
+ // |prop| which is present in the basis with value |value|.
+ //
+ // - extra(prop): Called when the subject has a property named |prop|, but the
+ // basis has no such property. This should return a walker that can check
+ // the subject's value.
+ function makeBasisChecker({compare, missing, extra}) {
+ return function makeWalker(basis) {
+ if (typeof basis === "object") {
+ var unvisited = new Set(Object.getOwnPropertyNames(basis));
+ return {
+ enter: prop => {
+ unvisited.delete(prop);
+ if (prop in basis) {
+ return makeWalker(basis[prop]);
+ } else {
+ return extra(prop);
+ }
+ },
+
+ done: () => unvisited.forEach(prop => missing(prop, basis[prop])),
+ check: expectedObject
+ };
+ } else {
+ return {
+ enter: expectedLeaf,
+ done: expectedLeaf,
+ check: elt => compare(elt, basis)
+ };
+ }
+ };
+ }
+
+ function missingProp(prop) {
+ throw new Error("Census mismatch: subject lacks property present in basis: " + prop);
+ }
+
+ function extraProp(prop) {
+ throw new Error("Census mismatch: subject has property not present in basis: " + prop);
+ }
+
+ // Return a walker that checks that the subject census has counts all equal to
+ // |basis|.
+ Census.assertAllEqual = makeBasisChecker({
+ compare: (a, b) => { if (a !== b) throw new Error("Census mismatch: expected " + a + " got " + b);},
+ missing: missingProp,
+ extra: extraProp
+ });
+
+ function ok(val) {
+ if (!val) {
+ throw new Error("Census mismatch: expected truthy, got " + val);
+ }
+ }
+
+ // Return a walker that checks that the subject census has at least as many
+ // items of each category as |basis|.
+ Census.assertAllNotLessThan = makeBasisChecker({
+ compare: (subject, basis) => ok(subject >= basis),
+ missing: missingProp,
+ extra: () => Census.walkAnything
+ });
+
+ // Return a walker that checks that the subject census has at most as many
+ // items of each category as |basis|.
+ Census.assertAllNotMoreThan = makeBasisChecker({
+ compare: (subject, basis) => ok(subject <= basis),
+ missing: missingProp,
+ extra: () => Census.walkAnything
+ });
+
+ // Return a walker that checks that the subject census has within |fudge|
+ // items of each category of the count in |basis|.
+ Census.assertAllWithin = function (fudge, basis) {
+ return makeBasisChecker({
+ compare: (subject, basis) => ok(Math.abs(subject - basis) <= fudge),
+ missing: missingProp,
+ extra: () => Census.walkAnything
+ })(basis);
+ };
+
+ return Census;
+}());
diff --git a/dom/heapsnapshot/tests/unit/Match.jsm b/dom/heapsnapshot/tests/unit/Match.jsm
new file mode 100644
index 000000000..c29e6484e
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/Match.jsm
@@ -0,0 +1,190 @@
+// A little pattern-matching library.
+//
+// Ported from js/src/tests/js1_8_5/reflect-parse/Match.js for use with devtools
+// server xpcshell tests.
+
+this.EXPORTED_SYMBOLS = ["Match"];
+
+this.Match = (function() {
+
+ function Pattern(template) {
+ // act like a constructor even as a function
+ if (!(this instanceof Pattern))
+ return new Pattern(template);
+
+ this.template = template;
+ }
+
+ Pattern.prototype = {
+ match: function(act) {
+ return match(act, this.template);
+ },
+
+ matches: function(act) {
+ try {
+ return this.match(act);
+ }
+ catch (e if e instanceof MatchError) {
+ return false;
+ }
+ },
+
+ assert: function(act, message) {
+ try {
+ return this.match(act);
+ }
+ catch (e if e instanceof MatchError) {
+ throw new Error((message || "failed match") + ": " + e.message);
+ }
+ },
+
+ toString: () => "[object Pattern]"
+ };
+
+ Pattern.ANY = new Pattern;
+ Pattern.ANY.template = Pattern.ANY;
+
+ Pattern.NUMBER = new Pattern;
+ Pattern.NUMBER.match = function (act) {
+ if (typeof act !== 'number') {
+ throw new MatchError("Expected number, got: " + quote(act));
+ }
+ }
+
+ Pattern.NATURAL = new Pattern
+ Pattern.NATURAL.match = function (act) {
+ if (typeof act !== 'number' || act !== Math.floor(act) || act < 0) {
+ throw new MatchError("Expected natural number, got: " + quote(act));
+ }
+ }
+
+ var quote = uneval;
+
+ function MatchError(msg) {
+ this.message = msg;
+ }
+
+ MatchError.prototype = {
+ toString: function() {
+ return "match error: " + this.message;
+ }
+ };
+
+ function isAtom(x) {
+ return (typeof x === "number") ||
+ (typeof x === "string") ||
+ (typeof x === "boolean") ||
+ (x === null) ||
+ (typeof x === "object" && x instanceof RegExp);
+ }
+
+ function isObject(x) {
+ return (x !== null) && (typeof x === "object");
+ }
+
+ function isFunction(x) {
+ return typeof x === "function";
+ }
+
+ function isArrayLike(x) {
+ return isObject(x) && ("length" in x);
+ }
+
+ function matchAtom(act, exp) {
+ if ((typeof exp) === "number" && isNaN(exp)) {
+ if ((typeof act) !== "number" || !isNaN(act))
+ throw new MatchError("expected NaN, got: " + quote(act));
+ return true;
+ }
+
+ if (exp === null) {
+ if (act !== null)
+ throw new MatchError("expected null, got: " + quote(act));
+ return true;
+ }
+
+ if (exp instanceof RegExp) {
+ if (!(act instanceof RegExp) || exp.source !== act.source)
+ throw new MatchError("expected " + quote(exp) + ", got: " + quote(act));
+ return true;
+ }
+
+ switch (typeof exp) {
+ case "string":
+ if (act !== exp)
+ throw new MatchError("expected " + quote(exp) + ", got " + quote(act));
+ return true;
+ case "boolean":
+ case "number":
+ if (exp !== act)
+ throw new MatchError("expected " + exp + ", got " + quote(act));
+ return true;
+ }
+
+ throw new Error("bad pattern: " + exp.toSource());
+ }
+
+ function matchObject(act, exp) {
+ if (!isObject(act))
+ throw new MatchError("expected object, got " + quote(act));
+
+ for (var key in exp) {
+ if (!(key in act))
+ throw new MatchError("expected property " + quote(key) + " not found in " + quote(act));
+ match(act[key], exp[key]);
+ }
+
+ return true;
+ }
+
+ function matchFunction(act, exp) {
+ if (!isFunction(act))
+ throw new MatchError("expected function, got " + quote(act));
+
+ if (act !== exp)
+ throw new MatchError("expected function: " + exp +
+ "\nbut got different function: " + act);
+ }
+
+ function matchArray(act, exp) {
+ if (!isObject(act) || !("length" in act))
+ throw new MatchError("expected array-like object, got " + quote(act));
+
+ var length = exp.length;
+ if (act.length !== exp.length)
+ throw new MatchError("expected array-like object of length " + length + ", got " + quote(act));
+
+ for (var i = 0; i < length; i++) {
+ if (i in exp) {
+ if (!(i in act))
+ throw new MatchError("expected array property " + i + " not found in " + quote(act));
+ match(act[i], exp[i]);
+ }
+ }
+
+ return true;
+ }
+
+ function match(act, exp) {
+ if (exp === Pattern.ANY)
+ return true;
+
+ if (exp instanceof Pattern)
+ return exp.match(act);
+
+ if (isAtom(exp))
+ return matchAtom(act, exp);
+
+ if (isArrayLike(exp))
+ return matchArray(act, exp);
+
+ if (isFunction(exp))
+ return matchFunction(act, exp);
+
+ return matchObject(act, exp);
+ }
+
+ return { Pattern: Pattern,
+ MatchError: MatchError };
+
+})();
diff --git a/dom/heapsnapshot/tests/unit/dominator-tree-worker.js b/dom/heapsnapshot/tests/unit/dominator-tree-worker.js
new file mode 100644
index 000000000..1f49ca841
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/dominator-tree-worker.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+console.log("Initializing worker.");
+
+self.onmessage = e => {
+ console.log("Starting test.");
+ try {
+ const path = ThreadSafeChromeUtils.saveHeapSnapshot({ runtime: true });
+ const snapshot = ThreadSafeChromeUtils.readHeapSnapshot(path);
+
+ const dominatorTree = snapshot.computeDominatorTree();
+ ok(dominatorTree);
+ ok(dominatorTree instanceof DominatorTree);
+
+ let threw = false;
+ try {
+ new DominatorTree();
+ } catch (e) {
+ threw = true;
+ }
+ ok(threw, "Constructor shouldn't be usable");
+ } catch (e) {
+ ok(false, "Unexpected error inside worker:\n" + e.toString() + "\n" + e.stack);
+ } finally {
+ done();
+ }
+};
+
+// Proxy assertions to the main thread.
+function ok(val, msg) {
+ console.log("ok(" + !!val + ", \"" + msg + "\")");
+ self.postMessage({
+ type: "assertion",
+ passed: !!val,
+ msg,
+ stack: Error().stack
+ });
+}
+
+// Tell the main thread we are done with the tests.
+function done() {
+ console.log("done()");
+ self.postMessage({
+ type: "done"
+ });
+}
diff --git a/dom/heapsnapshot/tests/unit/head_heapsnapshot.js b/dom/heapsnapshot/tests/unit/head_heapsnapshot.js
new file mode 100644
index 000000000..3171c8a6f
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/head_heapsnapshot.js
@@ -0,0 +1,448 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+var Cr = Components.results;
+var CC = Components.Constructor;
+
+const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
+const { Match } = Cu.import("resource://test/Match.jsm", {});
+const { Census } = Cu.import("resource://test/Census.jsm", {});
+const { addDebuggerToGlobal } =
+ Cu.import("resource://gre/modules/jsdebugger.jsm", {});
+const { Task } = require("devtools/shared/task");
+
+const DevToolsUtils = require("devtools/shared/DevToolsUtils");
+const flags = require("devtools/shared/flags");
+const HeapAnalysesClient =
+ require("devtools/shared/heapsnapshot/HeapAnalysesClient");
+const Services = require("Services");
+const { censusReportToCensusTreeNode } = require("devtools/shared/heapsnapshot/census-tree-node");
+const CensusUtils = require("devtools/shared/heapsnapshot/CensusUtils");
+const DominatorTreeNode = require("devtools/shared/heapsnapshot/DominatorTreeNode");
+const { deduplicatePaths } = require("devtools/shared/heapsnapshot/shortest-paths");
+const { LabelAndShallowSizeVisitor } = DominatorTreeNode;
+
+
+// Always log packets when running tests. runxpcshelltests.py will throw
+// the output away anyway, unless you give it the --verbose flag.
+if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_DEFAULT) {
+ Services.prefs.setBoolPref("devtools.debugger.log", true);
+}
+flags.wantLogging = true;
+
+const SYSTEM_PRINCIPAL = Cc["@mozilla.org/systemprincipal;1"]
+ .createInstance(Ci.nsIPrincipal);
+
+function dumpn(msg) {
+ dump("HEAPSNAPSHOT-TEST: " + msg + "\n");
+}
+
+function addTestingFunctionsToGlobal(global) {
+ global.eval(
+ `
+ const testingFunctions = Components.utils.getJSTestingFunctions();
+ for (let k in testingFunctions) {
+ this[k] = testingFunctions[k];
+ }
+ `
+ );
+ if (!global.print) {
+ global.print = do_print;
+ }
+ if (!global.newGlobal) {
+ global.newGlobal = newGlobal;
+ }
+ if (!global.Debugger) {
+ addDebuggerToGlobal(global);
+ }
+}
+
+addTestingFunctionsToGlobal(this);
+
+/**
+ * Create a new global, with all the JS shell testing functions. Similar to the
+ * newGlobal function exposed to JS shells, and useful for porting JS shell
+ * tests to xpcshell tests.
+ */
+function newGlobal() {
+ const global = new Cu.Sandbox(SYSTEM_PRINCIPAL, { freshZone: true });
+ addTestingFunctionsToGlobal(global);
+ return global;
+}
+
+function assertThrowsValue(f, val, msg) {
+ var fullmsg;
+ try {
+ f();
+ } catch (exc) {
+ if ((exc === val) === (val === val) && (val !== 0 || 1 / exc === 1 / val))
+ return;
+ fullmsg = "Assertion failed: expected exception " + val + ", got " + exc;
+ }
+ if (fullmsg === undefined)
+ fullmsg = "Assertion failed: expected exception " + val + ", no exception thrown";
+ if (msg !== undefined)
+ fullmsg += " - " + msg;
+ throw new Error(fullmsg);
+}
+
+/**
+ * Returns the full path of the file with the specified name in a
+ * platform-independent and URL-like form.
+ */
+function getFilePath(aName, aAllowMissing = false, aUsePlatformPathSeparator = false)
+{
+ let file = do_get_file(aName, aAllowMissing);
+ let path = Services.io.newFileURI(file).spec;
+ let filePrePath = "file://";
+ if ("nsILocalFileWin" in Ci &&
+ file instanceof Ci.nsILocalFileWin) {
+ filePrePath += "/";
+ }
+
+ path = path.slice(filePrePath.length);
+
+ if (aUsePlatformPathSeparator && path.match(/^\w:/)) {
+ path = path.replace(/\//g, "\\");
+ }
+
+ return path;
+}
+
+function saveNewHeapSnapshot(opts = { runtime: true }) {
+ const filePath = ChromeUtils.saveHeapSnapshot(opts);
+ ok(filePath, "Should get a file path to save the core dump to.");
+ ok(true, "Saved a heap snapshot to " + filePath);
+ return filePath;
+}
+
+function readHeapSnapshot(filePath) {
+ const snapshot = ChromeUtils.readHeapSnapshot(filePath);
+ ok(snapshot, "Should have read a heap snapshot back from " + filePath);
+ ok(snapshot instanceof HeapSnapshot, "snapshot should be an instance of HeapSnapshot");
+ return snapshot;
+}
+
+/**
+ * Save a heap snapshot to the file with the given name in the current
+ * directory, read it back as a HeapSnapshot instance, and then take a census of
+ * the heap snapshot's serialized heap graph with the provided census options.
+ *
+ * @param {Object|undefined} censusOptions
+ * Options that should be passed through to the takeCensus method. See
+ * js/src/doc/Debugger/Debugger.Memory.md for details.
+ *
+ * @param {Debugger|null} dbg
+ * If a Debugger object is given, only serialize the subgraph covered by
+ * the Debugger's debuggees. If null, serialize the whole heap graph.
+ *
+ * @param {String} fileName
+ * The file name to save the heap snapshot's core dump file to, within
+ * the current directory.
+ *
+ * @returns Census
+ */
+function saveHeapSnapshotAndTakeCensus(dbg = null, censusOptions = undefined) {
+ const snapshotOptions = dbg ? { debugger: dbg } : { runtime: true };
+ const filePath = saveNewHeapSnapshot(snapshotOptions);
+ const snapshot = readHeapSnapshot(filePath);
+
+ equal(typeof snapshot.takeCensus, "function", "snapshot should have a takeCensus method");
+
+ return snapshot.takeCensus(censusOptions);
+}
+
+/**
+ * Save a heap snapshot to disk, read it back as a HeapSnapshot instance, and
+ * then compute its dominator tree.
+ *
+ * @param {Debugger|null} dbg
+ * If a Debugger object is given, only serialize the subgraph covered by
+ * the Debugger's debuggees. If null, serialize the whole heap graph.
+ *
+ * @returns {DominatorTree}
+ */
+function saveHeapSnapshotAndComputeDominatorTree(dbg = null) {
+ const snapshotOptions = dbg ? { debugger: dbg } : { runtime: true };
+ const filePath = saveNewHeapSnapshot(snapshotOptions);
+ const snapshot = readHeapSnapshot(filePath);
+
+ equal(typeof snapshot.computeDominatorTree, "function",
+ "snapshot should have a `computeDominatorTree` method");
+
+ const dominatorTree = snapshot.computeDominatorTree();
+
+ ok(dominatorTree, "Should be able to compute a dominator tree");
+ ok(dominatorTree instanceof DominatorTree, "Should be an instance of DominatorTree");
+
+ return dominatorTree;
+}
+
+function isSavedFrame(obj) {
+ return Object.prototype.toString.call(obj) === "[object SavedFrame]";
+}
+
+function savedFrameReplacer(key, val) {
+ if (isSavedFrame(val)) {
+ return `<SavedFrame '${val.toString().split(/\n/g).shift()}'>`;
+ } else {
+ return val;
+ }
+}
+
+/**
+ * Assert that creating a CensusTreeNode from the given `report` with the
+ * specified `breakdown` creates the given `expected` CensusTreeNode.
+ *
+ * @param {Object} breakdown
+ * The census breakdown.
+ *
+ * @param {Object} report
+ * The census report.
+ *
+ * @param {Object} expected
+ * The expected CensusTreeNode result.
+ *
+ * @param {Object} options
+ * The options to pass through to `censusReportToCensusTreeNode`.
+ */
+function compareCensusViewData(breakdown, report, expected, options) {
+ dumpn("Generating CensusTreeNode from report:");
+ dumpn("breakdown: " + JSON.stringify(breakdown, null, 4));
+ dumpn("report: " + JSON.stringify(report, null, 4));
+ dumpn("expected: " + JSON.stringify(expected, savedFrameReplacer, 4));
+
+ const actual = censusReportToCensusTreeNode(breakdown, report, options);
+ dumpn("actual: " + JSON.stringify(actual, savedFrameReplacer, 4));
+
+ assertStructurallyEquivalent(actual, expected);
+}
+
+// Deep structural equivalence that can handle Map objects in addition to plain
+// objects.
+function assertStructurallyEquivalent(actual, expected, path = "root") {
+ if (actual === expected) {
+ equal(actual, expected, "actual and expected are the same");
+ return;
+ }
+
+ equal(typeof actual, typeof expected, `${path}: typeof should be the same`);
+
+ if (actual && typeof actual === "object") {
+ const actualProtoString = Object.prototype.toString.call(actual);
+ const expectedProtoString = Object.prototype.toString.call(expected);
+ equal(actualProtoString, expectedProtoString,
+ `${path}: Object.prototype.toString.call() should be the same`);
+
+ if (actualProtoString === "[object Map]") {
+ const expectedKeys = new Set([...expected.keys()]);
+
+ for (let key of actual.keys()) {
+ ok(expectedKeys.has(key),
+ `${path}: every key in actual should exist in expected: ${String(key).slice(0, 10)}`);
+ expectedKeys.delete(key);
+
+ assertStructurallyEquivalent(actual.get(key), expected.get(key),
+ path + ".get(" + String(key).slice(0, 20) + ")");
+ }
+
+ equal(expectedKeys.size, 0,
+ `${path}: every key in expected should also exist in actual, did not see ${[...expectedKeys]}`);
+ } else if (actualProtoString === "[object Set]") {
+ const expectedItems = new Set([...expected]);
+
+ for (let item of actual) {
+ ok(expectedItems.has(item),
+ `${path}: every set item in actual should exist in expected: ${item}`);
+ expectedItems.delete(item);
+ }
+
+ equal(expectedItems.size, 0,
+ `${path}: every set item in expected should also exist in actual, did not see ${[...expectedItems]}`);
+ } else {
+ const expectedKeys = new Set(Object.keys(expected));
+
+ for (let key of Object.keys(actual)) {
+ ok(expectedKeys.has(key),
+ `${path}: every key in actual should exist in expected: ${key}`);
+ expectedKeys.delete(key);
+
+ assertStructurallyEquivalent(actual[key], expected[key], path + "." + key);
+ }
+
+ equal(expectedKeys.size, 0,
+ `${path}: every key in expected should also exist in actual, did not see ${[...expectedKeys]}`);
+ }
+ } else {
+ equal(actual, expected, `${path}: primitives should be equal`);
+ }
+}
+
+/**
+ * Assert that creating a diff of the `first` and `second` census reports
+ * creates the `expected` delta-report.
+ *
+ * @param {Object} breakdown
+ * The census breakdown.
+ *
+ * @param {Object} first
+ * The first census report.
+ *
+ * @param {Object} second
+ * The second census report.
+ *
+ * @param {Object} expected
+ * The expected delta-report.
+ */
+function assertDiff(breakdown, first, second, expected) {
+ dumpn("Diffing census reports:");
+ dumpn("Breakdown: " + JSON.stringify(breakdown, null, 4));
+ dumpn("First census report: " + JSON.stringify(first, null, 4));
+ dumpn("Second census report: " + JSON.stringify(second, null, 4));
+ dumpn("Expected delta-report: " + JSON.stringify(expected, null, 4));
+
+ const actual = CensusUtils.diff(breakdown, first, second);
+ dumpn("Actual delta-report: " + JSON.stringify(actual, null, 4));
+
+ assertStructurallyEquivalent(actual, expected);
+}
+
+/**
+ * Assert that creating a label and getting a shallow size from the given node
+ * description with the specified breakdown is as expected.
+ *
+ * @param {Object} breakdown
+ * @param {Object} givenDescription
+ * @param {Number} expectedShallowSize
+ * @param {Object} expectedLabel
+ */
+function assertLabelAndShallowSize(breakdown, givenDescription, expectedShallowSize, expectedLabel) {
+ dumpn("Computing label and shallow size from node description:");
+ dumpn("Breakdown: " + JSON.stringify(breakdown, null, 4));
+ dumpn("Given description: " + JSON.stringify(givenDescription, null, 4));
+
+ const visitor = new LabelAndShallowSizeVisitor();
+ CensusUtils.walk(breakdown, description, visitor);
+
+ dumpn("Expected shallow size: " + expectedShallowSize);
+ dumpn("Actual shallow size: " + visitor.shallowSize());
+ equal(visitor.shallowSize(), expectedShallowSize, "Shallow size should be correct");
+
+ dumpn("Expected label: " + JSON.stringify(expectedLabel, null, 4));
+ dumpn("Actual label: " + JSON.stringify(visitor.label(), null, 4));
+ assertStructurallyEquivalent(visitor.label(), expectedLabel);
+}
+
+// Counter for mock DominatorTreeNode ids.
+let TEST_NODE_ID_COUNTER = 0;
+
+/**
+ * Create a mock DominatorTreeNode for testing, with sane defaults. Override any
+ * property by providing it on `opts`. Optionally pass child nodes as well.
+ *
+ * @param {Object} opts
+ * @param {Array<DominatorTreeNode>?} children
+ *
+ * @returns {DominatorTreeNode}
+ */
+function makeTestDominatorTreeNode(opts, children) {
+ const nodeId = TEST_NODE_ID_COUNTER++;
+
+ const node = Object.assign({
+ nodeId,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: (children || []).reduce((size, c) => size + c.retainedSize, 1),
+ parentId: undefined,
+ children,
+ moreChildrenAvailable: true,
+ }, opts);
+
+ if (children && children.length) {
+ children.map(c => c.parentId = node.nodeId);
+ }
+
+ return node;
+}
+
+/**
+ * Insert `newChildren` into the given dominator `tree` as specified by the
+ * `path` from the root to the node the `newChildren` should be inserted
+ * beneath. Assert that the resulting tree matches `expected`.
+ */
+function assertDominatorTreeNodeInsertion(tree, path, newChildren, moreChildrenAvailable, expected) {
+ dumpn("Inserting new children into a dominator tree:");
+ dumpn("Dominator tree: " + JSON.stringify(tree, null, 2));
+ dumpn("Path: " + JSON.stringify(path, null, 2));
+ dumpn("New children: " + JSON.stringify(newChildren, null, 2));
+ dumpn("Expected resulting tree: " + JSON.stringify(expected, null, 2));
+
+ const actual = DominatorTreeNode.insert(tree, path, newChildren, moreChildrenAvailable);
+ dumpn("Actual resulting tree: " + JSON.stringify(actual, null, 2));
+
+ assertStructurallyEquivalent(actual, expected);
+}
+
+function assertDeduplicatedPaths({ target, paths, expectedNodes, expectedEdges }) {
+ dumpn("Deduplicating paths:");
+ dumpn("target = " + target);
+ dumpn("paths = " + JSON.stringify(paths, null, 2));
+ dumpn("expectedNodes = " + expectedNodes);
+ dumpn("expectedEdges = " + JSON.stringify(expectedEdges, null, 2));
+
+ const { nodes, edges } = deduplicatePaths(target, paths);
+
+ dumpn("Actual nodes = " + nodes);
+ dumpn("Actual edges = " + JSON.stringify(edges, null, 2));
+
+ equal(nodes.length, expectedNodes.length,
+ "actual number of nodes is equal to the expected number of nodes");
+
+ equal(edges.length, expectedEdges.length,
+ "actual number of edges is equal to the expected number of edges");
+
+ const expectedNodeSet = new Set(expectedNodes);
+ const nodeSet = new Set(nodes);
+ ok(nodeSet.size === nodes.length,
+ "each returned node should be unique");
+
+ for (let node of nodes) {
+ ok(expectedNodeSet.has(node), `the ${node} node was expected`);
+ }
+
+ for (let expectedEdge of expectedEdges) {
+ let count = 0;
+ for (let edge of edges) {
+ if (edge.from === expectedEdge.from &&
+ edge.to === expectedEdge.to &&
+ edge.name === expectedEdge.name) {
+ count++;
+ }
+ }
+ equal(count, 1,
+ "should have exactly one matching edge for the expected edge = " + JSON.stringify(edge));
+ }
+}
+
+function assertCountToBucketBreakdown(breakdown, expected) {
+ dumpn("count => bucket breakdown");
+ dumpn("Initial breakdown = ", JSON.stringify(breakdown, null, 2));
+ dumpn("Expected results = ", JSON.stringify(expected, null, 2));
+
+ const actual = CensusUtils.countToBucketBreakdown(breakdown);
+ dumpn("Actual results = ", JSON.stringify(actual, null, 2));
+
+ assertStructurallyEquivalent(actual, expected);
+}
+
+/**
+ * Create a mock path entry for the given predecessor and edge.
+ */
+function pathEntry(predecessor, edge) {
+ return { predecessor, edge };
+}
diff --git a/dom/heapsnapshot/tests/unit/heap-snapshot-worker.js b/dom/heapsnapshot/tests/unit/heap-snapshot-worker.js
new file mode 100644
index 000000000..10ee70cec
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/heap-snapshot-worker.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+console.log("Initializing worker.");
+
+self.onmessage = e => {
+ console.log("Starting test.");
+ try {
+ ok(typeof ChromeUtils === "undefined",
+ "Should not have access to ChromeUtils in a worker.");
+ ok(ThreadSafeChromeUtils,
+ "Should have access to ThreadSafeChromeUtils in a worker.");
+ ok(HeapSnapshot,
+ "Should have access to HeapSnapshot in a worker.");
+
+ const filePath = ThreadSafeChromeUtils.saveHeapSnapshot({ globals: [this] });
+ ok(true, "Should be able to save a snapshot.");
+
+ const snapshot = ThreadSafeChromeUtils.readHeapSnapshot(filePath);
+ ok(snapshot, "Should be able to read a heap snapshot");
+ ok(snapshot instanceof HeapSnapshot, "Should be an instanceof HeapSnapshot");
+ } catch (e) {
+ ok(false, "Unexpected error inside worker:\n" + e.toString() + "\n" + e.stack);
+ } finally {
+ done();
+ }
+};
+
+// Proxy assertions to the main thread.
+function ok(val, msg) {
+ console.log("ok(" + !!val + ", \"" + msg + "\")");
+ self.postMessage({
+ type: "assertion",
+ passed: !!val,
+ msg,
+ stack: Error().stack
+ });
+}
+
+// Tell the main thread we are done with the tests.
+function done() {
+ console.log("done()");
+ self.postMessage({
+ type: "done"
+ });
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_01.js b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_01.js
new file mode 100644
index 000000000..845a0d263
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_01.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can generate label structures from node description reports.
+
+const breakdown = {
+ by: "coarseType",
+ objects: {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+ },
+ strings: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ scripts: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ other: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+};
+
+const description = {
+ objects: {
+ Function: { count: 1, bytes: 32 },
+ other: { count: 0, bytes: 0 }
+ },
+ strings: {},
+ scripts: {},
+ other: {}
+};
+
+const expected = [
+ "objects",
+ "Function"
+];
+
+const shallowSize = 32;
+
+function run_test() {
+ assertLabelAndShallowSize(breakdown, description, shallowSize, expected);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_02.js b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_02.js
new file mode 100644
index 000000000..e1f32de58
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_02.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can generate label structures from node description reports.
+
+const breakdown = {
+ by: "coarseType",
+ objects: {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+ },
+ strings: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ scripts: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ other: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+};
+
+const description = {
+ objects: {
+ other: { count: 1, bytes: 10 }
+ },
+ strings: {},
+ scripts: {},
+ other: {}
+};
+
+const expected = [
+ "objects",
+ "other"
+];
+
+const shallowSize = 10;
+
+function run_test() {
+ assertLabelAndShallowSize(breakdown, description, shallowSize, expected);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_03.js b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_03.js
new file mode 100644
index 000000000..ad35dcec1
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_03.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can generate label structures from node description reports.
+
+const breakdown = {
+ by: "coarseType",
+ objects: {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+ },
+ strings: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ scripts: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ other: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+};
+
+const description = {
+ objects: {
+ other: { count: 0, bytes: 0 }
+ },
+ strings: {
+ "JSString": { count: 1, bytes: 42 },
+ },
+ scripts: {},
+ other: {}
+};
+
+const expected = [
+ "strings",
+ "JSString"
+];
+
+const shallowSize = 42;
+
+function run_test() {
+ assertLabelAndShallowSize(breakdown, description, shallowSize, expected);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_04.js b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_04.js
new file mode 100644
index 000000000..566ad0dab
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_04.js
@@ -0,0 +1,53 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can generate label structures from node description reports.
+
+const breakdown = {
+ by: "coarseType",
+ objects: {
+ by: "objectClass",
+ then: {
+ by: "allocationStack",
+ then: { by: "count", count: true, bytes: true },
+ noStack: { by: "count", count: true, bytes: true },
+ },
+ other: { by: "count", count: true, bytes: true },
+ },
+ strings: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ scripts: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ other: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+};
+
+const stack = saveStack();
+
+const description = {
+ objects: {
+ Array: new Map([[stack, { count: 1, bytes: 512 }]]),
+ other: { count: 0, bytes: 0 }
+ },
+ strings: {},
+ scripts: {},
+ other: {}
+};
+
+const expected = [
+ "objects",
+ "Array",
+ stack
+];
+
+const shallowSize = 512;
+
+function run_test() {
+ assertLabelAndShallowSize(breakdown, description, shallowSize, expected);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_attachShortestPaths_01.js b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_attachShortestPaths_01.js
new file mode 100644
index 000000000..24e8e2eb5
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_attachShortestPaths_01.js
@@ -0,0 +1,132 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test that the DominatorTreeNode.attachShortestPaths function can correctly
+// attach the deduplicated shortest retaining paths for each node it is given.
+
+const startNodeId = 9999;
+const maxNumPaths = 2;
+
+// Mock data mapping node id to shortest paths to that node id.
+const shortestPaths = new Map([
+ [1000, [
+ [pathEntry(1100, "a"), pathEntry(1200, "b")],
+ [pathEntry(1100, "c"), pathEntry(1300, "d")],
+ ]],
+ [2000, [
+ [pathEntry(2100, "e"), pathEntry(2200, "f"), pathEntry(2300, "g")]
+ ]],
+ [3000, [
+ [pathEntry(3100, "h")],
+ [pathEntry(3100, "i")],
+ [pathEntry(3100, "j")],
+ [pathEntry(3200, "k")],
+ [pathEntry(3300, "l")],
+ [pathEntry(3400, "m")],
+ ]],
+]);
+
+const actual = [
+ makeTestDominatorTreeNode({ nodeId: 1000 }),
+ makeTestDominatorTreeNode({ nodeId: 2000 }),
+ makeTestDominatorTreeNode({ nodeId: 3000 }),
+];
+
+const expected = [
+ makeTestDominatorTreeNode({
+ nodeId: 1000,
+ shortestPaths: {
+ nodes: [
+ { id: 1000, label: ["SomeType-1000"] },
+ { id: 1100, label: ["SomeType-1100"] },
+ { id: 1200, label: ["SomeType-1200"] },
+ { id: 1300, label: ["SomeType-1300"] },
+ ],
+ edges: [
+ { from: 1100, to: 1200, name: "a" },
+ { from: 1100, to: 1300, name: "c" },
+ { from: 1200, to: 1000, name: "b" },
+ { from: 1300, to: 1000, name: "d" },
+ ]
+ }
+ }),
+
+ makeTestDominatorTreeNode({
+ nodeId: 2000,
+ shortestPaths: {
+ nodes: [
+ { id: 2000, label: ["SomeType-2000"] },
+ { id: 2100, label: ["SomeType-2100"] },
+ { id: 2200, label: ["SomeType-2200"] },
+ { id: 2300, label: ["SomeType-2300"] },
+ ],
+ edges: [
+ { from: 2100, to: 2200, name: "e" },
+ { from: 2200, to: 2300, name: "f" },
+ { from: 2300, to: 2000, name: "g" },
+ ]
+ }
+ }),
+
+ makeTestDominatorTreeNode({ nodeId: 3000,
+ shortestPaths: {
+ nodes: [
+ { id: 3000, label: ["SomeType-3000"] },
+ { id: 3100, label: ["SomeType-3100"] },
+ { id: 3200, label: ["SomeType-3200"] },
+ { id: 3300, label: ["SomeType-3300"] },
+ { id: 3400, label: ["SomeType-3400"] },
+ ],
+ edges: [
+ { from: 3100, to: 3000, name: "h" },
+ { from: 3100, to: 3000, name: "i" },
+ { from: 3100, to: 3000, name: "j" },
+ { from: 3200, to: 3000, name: "k" },
+ { from: 3300, to: 3000, name: "l" },
+ { from: 3400, to: 3000, name: "m" },
+ ]
+ }
+ }),
+];
+
+const breakdown = {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true }
+};
+
+const mockSnapshot = {
+ computeShortestPaths: (start, nodeIds, max) => {
+ equal(start, startNodeId);
+ equal(max, maxNumPaths);
+
+ return new Map(nodeIds.map(nodeId => {
+ const paths = shortestPaths.get(nodeId);
+ ok(paths, "Expected computeShortestPaths call for node id = " + nodeId);
+ return [nodeId, paths];
+ }));
+ },
+
+ describeNode: (bd, nodeId) => {
+ equal(bd, breakdown);
+ return {
+ ["SomeType-" + nodeId]: {
+ count: 1,
+ bytes: 10,
+ }
+ };
+ },
+};
+
+function run_test() {
+ DominatorTreeNode.attachShortestPaths(mockSnapshot,
+ breakdown,
+ startNodeId,
+ actual,
+ maxNumPaths);
+
+ dumpn("Expected = " + JSON.stringify(expected, null, 2));
+ dumpn("Actual = " + JSON.stringify(actual, null, 2));
+
+ assertStructurallyEquivalent(expected, actual);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_getNodeByIdAlongPath_01.js b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_getNodeByIdAlongPath_01.js
new file mode 100644
index 000000000..de2907809
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_getNodeByIdAlongPath_01.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can find the node with the given id along the specified path.
+
+const node3000 = makeTestDominatorTreeNode({ nodeId: 3000 });
+
+const node2000 = makeTestDominatorTreeNode({ nodeId: 2000 }, [
+ makeTestDominatorTreeNode({}),
+ node3000,
+ makeTestDominatorTreeNode({}),
+]);
+
+const node1000 = makeTestDominatorTreeNode({ nodeId: 1000 }, [
+ makeTestDominatorTreeNode({}),
+ node2000,
+ makeTestDominatorTreeNode({}),
+]);
+
+const tree = node1000;
+
+const path = [1000, 2000, 3000];
+
+const tests = [
+ { id: 1000, expected: node1000 },
+ { id: 2000, expected: node2000 },
+ { id: 3000, expected: node3000 },
+];
+
+function run_test() {
+ for (let { id, expected } of tests) {
+ const actual = DominatorTreeNode.getNodeByIdAlongPath(id, tree, path);
+ equal(actual, expected, `We should have got the node with id = ${id}`);
+ }
+
+ equal(null,
+ DominatorTreeNode.getNodeByIdAlongPath(999999999999, tree, path),
+ "null is returned for nodes that are not even in the tree");
+
+ const lastNodeId = tree.children[tree.children.length - 1].nodeId;
+ equal(null,
+ DominatorTreeNode.getNodeByIdAlongPath(lastNodeId, tree, path),
+ "null is returned for nodes that are not along the path");
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_01.js b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_01.js
new file mode 100644
index 000000000..979232ff4
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_01.js
@@ -0,0 +1,112 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can insert new children into an existing DominatorTreeNode tree.
+
+const tree = makeTestDominatorTreeNode({ nodeId: 1000 }, [
+ makeTestDominatorTreeNode({}),
+ makeTestDominatorTreeNode({ nodeId: 2000 }, [
+ makeTestDominatorTreeNode({}),
+ makeTestDominatorTreeNode({ nodeId: 3000 }),
+ makeTestDominatorTreeNode({}),
+ ]),
+ makeTestDominatorTreeNode({}),
+]);
+
+const path = [1000, 2000, 3000];
+
+const newChildren = [
+ makeTestDominatorTreeNode({ parentId: 3000 }),
+ makeTestDominatorTreeNode({ parentId: 3000 }),
+];
+
+const moreChildrenAvailable = false;
+
+const expected = {
+ nodeId: 1000,
+ parentId: undefined,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 7,
+ children: [
+ {
+ nodeId: 0,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ parentId: 1000,
+ moreChildrenAvailable: true,
+ children: undefined,
+ },
+ {
+ nodeId: 2000,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 4,
+ parentId: 1000,
+ children: [
+ {
+ nodeId: 1,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ parentId: 2000,
+ moreChildrenAvailable: true,
+ children: undefined,
+ },
+ {
+ nodeId: 3000,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ parentId: 2000,
+ children: [
+ {
+ nodeId: 7,
+ parentId: 3000,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ moreChildrenAvailable: true,
+ children: undefined,
+ },
+ {
+ nodeId: 8,
+ parentId: 3000,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ moreChildrenAvailable: true,
+ children: undefined,
+ },
+ ],
+ moreChildrenAvailable: false
+ },
+ {
+ nodeId: 3,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ parentId: 2000,
+ moreChildrenAvailable: true,
+ children: undefined,
+ },
+ ],
+ moreChildrenAvailable: true
+ },
+ {
+ nodeId: 5,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ parentId: 1000,
+ moreChildrenAvailable: true,
+ children: undefined,
+ }
+ ],
+ moreChildrenAvailable: true
+};
+
+function run_test() {
+ assertDominatorTreeNodeInsertion(tree, path, newChildren, moreChildrenAvailable, expected);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_02.js b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_02.js
new file mode 100644
index 000000000..9a8d11d0b
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_02.js
@@ -0,0 +1,30 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test attempting to insert new children into an existing DominatorTreeNode
+// tree with a bad path.
+
+const tree = makeTestDominatorTreeNode({}, [
+ makeTestDominatorTreeNode({}),
+ makeTestDominatorTreeNode({}, [
+ makeTestDominatorTreeNode({}),
+ makeTestDominatorTreeNode({}),
+ makeTestDominatorTreeNode({}),
+ ]),
+ makeTestDominatorTreeNode({}),
+]);
+
+const path = [111111, 222222, 333333];
+
+const newChildren = [
+ makeTestDominatorTreeNode({ parentId: 333333 }),
+ makeTestDominatorTreeNode({ parentId: 333333 }),
+];
+
+const moreChildrenAvailable = false;
+
+const expected = tree;
+
+function run_test() {
+ assertDominatorTreeNodeInsertion(tree, path, newChildren, moreChildrenAvailable, expected);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_03.js b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_03.js
new file mode 100644
index 000000000..f8cb5eec3
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_insert_03.js
@@ -0,0 +1,117 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test inserting new children into an existing DominatorTreeNode at the root.
+
+const tree = makeTestDominatorTreeNode({ nodeId: 666 }, [
+ makeTestDominatorTreeNode({}),
+ makeTestDominatorTreeNode({}, [
+ makeTestDominatorTreeNode({}),
+ makeTestDominatorTreeNode({}),
+ makeTestDominatorTreeNode({}),
+ ]),
+ makeTestDominatorTreeNode({}),
+]);
+
+const path = [666];
+
+const newChildren = [
+ makeTestDominatorTreeNode({
+ nodeId: 777,
+ parentId: 666
+ }),
+ makeTestDominatorTreeNode({
+ nodeId: 888,
+ parentId: 666
+ }),
+];
+
+const moreChildrenAvailable = false;
+
+const expected = {
+ nodeId: 666,
+ label: undefined,
+ parentId: undefined,
+ shallowSize: 1,
+ retainedSize: 7,
+ children: [
+ {
+ nodeId: 0,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ parentId: 666,
+ moreChildrenAvailable: true,
+ children: undefined
+ },
+ {
+ nodeId: 4,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 4,
+ parentId: 666,
+ children: [
+ {
+ nodeId: 1,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ parentId: 4,
+ moreChildrenAvailable: true,
+ children: undefined
+ },
+ {
+ nodeId: 2,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ parentId: 4,
+ moreChildrenAvailable: true,
+ children: undefined
+ },
+ {
+ nodeId: 3,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ parentId: 4,
+ moreChildrenAvailable: true,
+ children: undefined
+ }
+ ],
+ moreChildrenAvailable: true
+ },
+ {
+ nodeId: 5,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ parentId: 666,
+ moreChildrenAvailable: true,
+ children: undefined
+ },
+ {
+ nodeId: 777,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ parentId: 666,
+ moreChildrenAvailable: true,
+ children: undefined
+ },
+ {
+ nodeId: 888,
+ label: undefined,
+ shallowSize: 1,
+ retainedSize: 1,
+ parentId: 666,
+ moreChildrenAvailable: true,
+ children: undefined
+ }
+ ],
+ moreChildrenAvailable: false
+};
+
+function run_test() {
+ assertDominatorTreeNodeInsertion(tree, path, newChildren, moreChildrenAvailable, expected);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_partialTraversal_01.js b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_partialTraversal_01.js
new file mode 100644
index 000000000..78ec47b64
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTreeNode_partialTraversal_01.js
@@ -0,0 +1,164 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we correctly set `moreChildrenAvailable` when doing a partial
+// traversal of a dominator tree to create the initial incrementally loaded
+// `DominatorTreeNode` tree.
+
+// `tree` maps parent to children:
+//
+// 100
+// |- 200
+// | |- 500
+// | |- 600
+// | `- 700
+// |- 300
+// | |- 800
+// | |- 900
+// `- 400
+// |- 1000
+// |- 1100
+// `- 1200
+const tree = new Map([
+ [100, [200, 300, 400]],
+ [200, [500, 600, 700]],
+ [300, [800, 900]],
+ [400, [1000, 1100, 1200]]
+]);
+
+const mockDominatorTree = {
+ root: 100,
+ getRetainedSize: _ => 10,
+ getImmediatelyDominated: id => (tree.get(id) || []).slice()
+};
+
+const mockSnapshot = {
+ describeNode: _ => ({
+ objects: { count: 0, bytes: 0 },
+ strings: { count: 0, bytes: 0 },
+ scripts: { count: 0, bytes: 0 },
+ other: { SomeType: { count: 1, bytes: 10 } }
+ })
+};
+
+const breakdown = {
+ by: "coarseType",
+ objects: { by: "count", count: true, bytes: true },
+ strings: { by: "count", count: true, bytes: true },
+ scripts: { by: "count", count: true, bytes: true },
+ other: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true }
+ },
+};
+
+const expected = {
+ nodeId: 100,
+ label: [
+ "other",
+ "SomeType"
+ ],
+ shallowSize: 10,
+ retainedSize: 10,
+ shortestPaths: undefined,
+ children: [
+ {
+ nodeId: 200,
+ label: [
+ "other",
+ "SomeType"
+ ],
+ shallowSize: 10,
+ retainedSize: 10,
+ parentId: 100,
+ shortestPaths: undefined,
+ children: [
+ {
+ nodeId: 500,
+ label: [
+ "other",
+ "SomeType"
+ ],
+ shallowSize: 10,
+ retainedSize: 10,
+ parentId: 200,
+ moreChildrenAvailable: false,
+ shortestPaths: undefined,
+ children: undefined
+ },
+ {
+ nodeId: 600,
+ label: [
+ "other",
+ "SomeType"
+ ],
+ shallowSize: 10,
+ retainedSize: 10,
+ parentId: 200,
+ moreChildrenAvailable: false,
+ shortestPaths: undefined,
+ children: undefined
+ }
+ ],
+ moreChildrenAvailable: true
+ },
+ {
+ nodeId: 300,
+ label: [
+ "other",
+ "SomeType"
+ ],
+ shallowSize: 10,
+ retainedSize: 10,
+ parentId: 100,
+ shortestPaths: undefined,
+ children: [
+ {
+ nodeId: 800,
+ label: [
+ "other",
+ "SomeType"
+ ],
+ shallowSize: 10,
+ retainedSize: 10,
+ parentId: 300,
+ moreChildrenAvailable: false,
+ shortestPaths: undefined,
+ children: undefined
+ },
+ {
+ nodeId: 900,
+ label: [
+ "other",
+ "SomeType"
+ ],
+ shallowSize: 10,
+ retainedSize: 10,
+ parentId: 300,
+ moreChildrenAvailable: false,
+ shortestPaths: undefined,
+ children: undefined
+ }
+ ],
+ moreChildrenAvailable: false
+ }
+ ],
+ moreChildrenAvailable: true,
+ parentId: undefined,
+};
+
+function run_test() {
+ // Traverse the whole depth of the test tree, but one short of the number of
+ // siblings. This will exercise the moreChildrenAvailable handling for
+ // siblings.
+ const actual = DominatorTreeNode.partialTraversal(mockDominatorTree,
+ mockSnapshot,
+ breakdown,
+ /* maxDepth = */ 4,
+ /* siblings = */ 2);
+
+ dumpn("Expected = " + JSON.stringify(expected, null, 2));
+ dumpn("Actual = " + JSON.stringify(actual, null, 2));
+
+ assertStructurallyEquivalent(expected, actual);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTree_01.js b/dom/heapsnapshot/tests/unit/test_DominatorTree_01.js
new file mode 100644
index 000000000..e8145f658
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTree_01.js
@@ -0,0 +1,23 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Sanity test that we can compute dominator trees.
+
+function run_test() {
+ const path = ChromeUtils.saveHeapSnapshot({ runtime: true });
+ const snapshot = ChromeUtils.readHeapSnapshot(path);
+
+ const dominatorTree = snapshot.computeDominatorTree();
+ ok(dominatorTree);
+ ok(dominatorTree instanceof DominatorTree);
+
+ let threw = false;
+ try {
+ new DominatorTree();
+ } catch (e) {
+ threw = true;
+ }
+ ok(threw, "Constructor shouldn't be usable");
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTree_02.js b/dom/heapsnapshot/tests/unit/test_DominatorTree_02.js
new file mode 100644
index 000000000..a518f8a27
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTree_02.js
@@ -0,0 +1,40 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can compute dominator trees from a snapshot in a worker.
+
+add_task(function* () {
+ const worker = new ChromeWorker("resource://test/dominator-tree-worker.js");
+ worker.postMessage({});
+
+ let assertionCount = 0;
+ worker.onmessage = e => {
+ if (e.data.type !== "assertion") {
+ return;
+ }
+
+ ok(e.data.passed, e.data.msg + "\n" + e.data.stack);
+ assertionCount++;
+ };
+
+ yield waitForDone(worker);
+
+ ok(assertionCount > 0);
+ worker.terminate();
+});
+
+function waitForDone(w) {
+ return new Promise((resolve, reject) => {
+ w.onerror = e => {
+ reject();
+ ok(false, "Error in worker: " + e);
+ };
+
+ w.addEventListener("message", function listener(e) {
+ if (e.data.type === "done") {
+ w.removeEventListener("message", listener, false);
+ resolve();
+ }
+ }, false);
+ });
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTree_03.js b/dom/heapsnapshot/tests/unit/test_DominatorTree_03.js
new file mode 100644
index 000000000..0a14ce53d
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTree_03.js
@@ -0,0 +1,13 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can get the root of dominator trees.
+
+function run_test() {
+ const dominatorTree = saveHeapSnapshotAndComputeDominatorTree();
+ equal(typeof dominatorTree.root, "number", "root should be a number");
+ equal(Math.floor(dominatorTree.root), dominatorTree.root, "root should be an integer");
+ ok(dominatorTree.root >= 0, "root should be positive");
+ ok(dominatorTree.root <= Math.pow(2, 48), "root should be less than or equal to 2^48");
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTree_04.js b/dom/heapsnapshot/tests/unit/test_DominatorTree_04.js
new file mode 100644
index 000000000..e5aef3fec
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTree_04.js
@@ -0,0 +1,22 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can get the retained sizes of dominator trees.
+
+function run_test() {
+ const dominatorTree = saveHeapSnapshotAndComputeDominatorTree();
+ equal(typeof dominatorTree.getRetainedSize, "function",
+ "getRetainedSize should be a function");
+
+ const size = dominatorTree.getRetainedSize(dominatorTree.root);
+ ok(size, "should get a size for the root");
+ equal(typeof size, "number", "retained sizes should be a number");
+ equal(Math.floor(size), size, "size should be an integer");
+ ok(size > 0, "size should be positive");
+ ok(size <= Math.pow(2, 64), "size should be less than or equal to 2^64");
+
+ const bad = dominatorTree.getRetainedSize(1);
+ equal(bad, null, "null is returned for unknown node ids");
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTree_05.js b/dom/heapsnapshot/tests/unit/test_DominatorTree_05.js
new file mode 100644
index 000000000..c07cee994
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTree_05.js
@@ -0,0 +1,75 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can get the set of immediately dominated nodes for any given
+// node and that this forms a tree.
+
+function run_test() {
+ var dominatorTree = saveHeapSnapshotAndComputeDominatorTree();
+ equal(typeof dominatorTree.getImmediatelyDominated, "function",
+ "getImmediatelyDominated should be a function");
+
+ // Do a traversal of the dominator tree.
+ //
+ // Note that we don't assert directly, only if we get an unexpected
+ // value. There are just way too many nodes in the heap graph to assert for
+ // every one. This test would constantly time out and assertion messages would
+ // overflow the log size.
+
+ var root = dominatorTree.root;
+ equal(dominatorTree.getImmediateDominator(root), null,
+ "The root should not have a parent");
+
+ var seen = new Set();
+ var stack = [root];
+ while (stack.length > 0) {
+ var top = stack.pop();
+
+ if (seen.has(top)) {
+ ok(false,
+ "This is a tree, not a graph: we shouldn't have multiple edges to the same node");
+ }
+ seen.add(top);
+ if (seen.size % 1000 === 0) {
+ dumpn("Progress update: seen size = " + seen.size);
+ }
+
+ var newNodes = dominatorTree.getImmediatelyDominated(top);
+ if (Object.prototype.toString.call(newNodes) !== "[object Array]") {
+ ok(false, "getImmediatelyDominated should return an array for known node ids");
+ }
+
+ var topSize = dominatorTree.getRetainedSize(top);
+
+ var lastSize = Infinity;
+ for (var i = 0; i < newNodes.length; i++) {
+ if (typeof newNodes[i] !== "number") {
+ ok(false, "Every dominated id should be a number");
+ }
+
+ if (dominatorTree.getImmediateDominator(newNodes[i]) !== top) {
+ ok(false, "child's parent should be the expected parent");
+ }
+
+ var thisSize = dominatorTree.getRetainedSize(newNodes[i]);
+
+ if (thisSize >= topSize) {
+ ok(false, "the size of children in the dominator tree should always be less than that of their parent");
+ }
+
+ if (thisSize > lastSize) {
+ ok(false,
+ "children should be sorted by greatest to least retained size, "
+ + "lastSize = " + lastSize + ", thisSize = " + thisSize);
+ }
+
+ lastSize = thisSize;
+ stack.push(newNodes[i]);
+ }
+ }
+
+ ok(true, "Successfully walked the tree");
+ dumpn("Walked " + seen.size + " nodes");
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_DominatorTree_06.js b/dom/heapsnapshot/tests/unit/test_DominatorTree_06.js
new file mode 100644
index 000000000..680478623
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_DominatorTree_06.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the retained size of a node is the sum of its children retained
+// sizes plus its shallow size.
+
+// Note that we don't assert directly, only if we get an unexpected
+// value. There are just way too many nodes in the heap graph to assert for
+// every one. This test would constantly time out and assertion messages would
+// overflow the log size.
+function fastAssert(cond, msg) {
+ if (!cond) {
+ ok(false, msg);
+ }
+}
+
+var COUNT = { by: "count", count: false, bytes: true };
+
+function run_test() {
+ var path = saveNewHeapSnapshot();
+ var snapshot = ChromeUtils.readHeapSnapshot(path);
+ var dominatorTree = snapshot.computeDominatorTree();
+
+ // Do a traversal of the dominator tree and assert the relationship between
+ // retained size, shallow size, and children's retained sizes.
+
+ var root = dominatorTree.root;
+ var stack = [root];
+ while (stack.length > 0) {
+ var top = stack.pop();
+
+ var children = dominatorTree.getImmediatelyDominated(top);
+
+ var topRetainedSize = dominatorTree.getRetainedSize(top);
+ var topShallowSize = snapshot.describeNode(COUNT, top).bytes;
+ fastAssert(topShallowSize <= topRetainedSize,
+ "The shallow size should be less than or equal to the " +
+ "retained size");
+
+ var sumOfChildrensRetainedSizes = 0;
+ for (var i = 0; i < children.length; i++) {
+ sumOfChildrensRetainedSizes += dominatorTree.getRetainedSize(children[i]);
+ stack.push(children[i]);
+ }
+
+ fastAssert(sumOfChildrensRetainedSizes <= topRetainedSize,
+ "The sum of the children's retained sizes should be less than " +
+ "or equal to the retained size");
+ fastAssert(sumOfChildrensRetainedSizes + topShallowSize === topRetainedSize,
+ "The sum of the children's retained sizes plus the shallow " +
+ "size should be equal to the retained size");
+ }
+
+ ok(true, "Successfully walked the tree");
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_01.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_01.js
new file mode 100644
index 000000000..0114e0b69
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_01.js
@@ -0,0 +1,22 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the HeapAnalyses{Client,Worker} "computeDominatorTree" request.
+
+function run_test() {
+ run_next_test();
+}
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ const snapshotFilePath = saveNewHeapSnapshot();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath);
+ equal(typeof dominatorTreeId, "number",
+ "should get a dominator tree id, and it should be a number");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_02.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_02.js
new file mode 100644
index 000000000..6e3f5b257
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_computeDominatorTree_02.js
@@ -0,0 +1,23 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the HeapAnalyses{Client,Worker} "computeDominatorTree" request with bad
+// file paths.
+
+function run_test() {
+ run_next_test();
+}
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ let threw = false;
+ try {
+ yield client.computeDominatorTree("/etc/passwd");
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "should throw when given a bad path");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_01.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_01.js
new file mode 100644
index 000000000..7708de93c
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_01.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} can delete heap snapshots.
+
+function run_test() {
+ run_next_test();
+}
+
+const breakdown = {
+ by: "coarseType",
+ objects: { by: "count", count: true, bytes: true },
+ scripts: { by: "count", count: true, bytes: true },
+ strings: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+};
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ const snapshotFilePath = saveNewHeapSnapshot();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ let dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath);
+ ok(true, "Should have computed the dominator tree");
+
+ yield client.deleteHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have deleted the snapshot");
+
+ let threw = false;
+ try {
+ yield client.getDominatorTree({
+ dominatorTreeId: dominatorTreeId,
+ breakdown
+ });
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "getDominatorTree on deleted tree should throw an error");
+
+ threw = false;
+ try {
+ yield client.computeDominatorTree(snapshotFilePath);
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "computeDominatorTree on deleted snapshot should throw an error");
+
+ threw = false;
+ try {
+ yield client.takeCensus(snapshotFilePath);
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "takeCensus on deleted tree should throw an error");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_02.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_02.js
new file mode 100644
index 000000000..3e25ddac4
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_02.js
@@ -0,0 +1,22 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test deleteHeapSnapshot is a noop if the provided path matches no snapshot
+
+function run_test() {
+ run_next_test();
+}
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ let threw = false;
+ try {
+ yield client.deleteHeapSnapshot("path-does-not-exist");
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "deleteHeapSnapshot on non-existant path should throw an error");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_03.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_03.js
new file mode 100644
index 000000000..e648c9407
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_deleteHeapSnapshot_03.js
@@ -0,0 +1,62 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test other dominatorTrees can still be retrieved after deleting a snapshot
+
+function run_test() {
+ run_next_test();
+}
+
+const breakdown = {
+ by: "coarseType",
+ objects: { by: "count", count: true, bytes: true },
+ scripts: { by: "count", count: true, bytes: true },
+ strings: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+};
+
+function* createSnapshotAndDominatorTree(client) {
+ let snapshotFilePath = saveNewHeapSnapshot();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ let dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath);
+ return { dominatorTreeId, snapshotFilePath };
+}
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ let savedSnapshots = [
+ yield createSnapshotAndDominatorTree(client),
+ yield createSnapshotAndDominatorTree(client),
+ yield createSnapshotAndDominatorTree(client)
+ ];
+ ok(true, "Create 3 snapshots and dominator trees");
+
+ yield client.deleteHeapSnapshot(savedSnapshots[1].snapshotFilePath);
+ ok(true, "Snapshot deleted");
+
+ let tree = yield client.getDominatorTree({
+ dominatorTreeId: savedSnapshots[0].dominatorTreeId,
+ breakdown
+ });
+ ok(tree, "Should get a valid tree for first snapshot");
+
+ let threw = false;
+ try {
+ yield client.getDominatorTree({
+ dominatorTreeId: savedSnapshots[1].dominatorTreeId,
+ breakdown
+ });
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "getDominatorTree on a deleted snapshot should throw an error");
+
+ tree = yield client.getDominatorTree({
+ dominatorTreeId: savedSnapshots[2].dominatorTreeId,
+ breakdown
+ });
+ ok(tree, "Should get a valid tree for third snapshot");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getCensusIndividuals_01.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getCensusIndividuals_01.js
new file mode 100644
index 000000000..b63ad4230
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getCensusIndividuals_01.js
@@ -0,0 +1,89 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} can get census individuals.
+
+function run_test() {
+ run_next_test();
+}
+
+const COUNT = { by: "count", count: true, bytes: true };
+
+const CENSUS_BREAKDOWN = {
+ by: "coarseType",
+ objects: COUNT,
+ strings: COUNT,
+ scripts: COUNT,
+ other: COUNT,
+};
+
+const LABEL_BREAKDOWN = {
+ by: "internalType",
+ then: COUNT,
+};
+
+const MAX_INDIVIDUALS = 10;
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ const snapshotFilePath = saveNewHeapSnapshot();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath);
+ ok(true, "Should have computed dominator tree");
+
+ const { report } = yield client.takeCensus(snapshotFilePath,
+ { breakdown: CENSUS_BREAKDOWN },
+ { asTreeNode: true });
+ ok(report, "Should get a report");
+
+ let nodesWithLeafIndicesFound = 0;
+
+ yield* (function* assertCanGetIndividuals(censusNode) {
+ if (censusNode.reportLeafIndex !== undefined) {
+ nodesWithLeafIndicesFound++;
+
+ const response = yield client.getCensusIndividuals({
+ dominatorTreeId,
+ indices: DevToolsUtils.isSet(censusNode.reportLeafIndex)
+ ? censusNode.reportLeafIndex
+ : new Set([censusNode.reportLeafIndex]),
+ censusBreakdown: CENSUS_BREAKDOWN,
+ labelBreakdown: LABEL_BREAKDOWN,
+ maxRetainingPaths: 1,
+ maxIndividuals: MAX_INDIVIDUALS,
+ });
+
+ dumpn(`response = ${JSON.stringify(response, null, 4)}`);
+
+ equal(response.nodes.length, Math.min(MAX_INDIVIDUALS, censusNode.count),
+ "response.nodes.length === Math.min(MAX_INDIVIDUALS, censusNode.count)");
+
+ let lastRetainedSize = Infinity;
+ for (let individual of response.nodes) {
+ equal(typeof individual.nodeId, "number",
+ "individual.nodeId should be a number");
+ ok(individual.retainedSize <= lastRetainedSize,
+ "individual.retainedSize <= lastRetainedSize");
+ lastRetainedSize = individual.retainedSize;
+ ok(individual.shallowSize, "individual.shallowSize should exist and be non-zero");
+ ok(individual.shortestPaths, "individual.shortestPaths should exist");
+ ok(individual.shortestPaths.nodes, "individual.shortestPaths.nodes should exist");
+ ok(individual.shortestPaths.edges, "individual.shortestPaths.edges should exist");
+ ok(individual.label, "individual.label should exist");
+ }
+ }
+
+ if (censusNode.children) {
+ for (let child of censusNode.children) {
+ yield* assertCanGetIndividuals(child);
+ }
+ }
+ }(report));
+
+ equal(nodesWithLeafIndicesFound, 4, "Should have found a leaf for each coarse type");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getCreationTime_01.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getCreationTime_01.js
new file mode 100644
index 000000000..5df79de7a
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getCreationTime_01.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} can get a HeapSnapshot's
+// creation time.
+
+function waitForThirtyMilliseconds() {
+ const start = Date.now();
+ while (Date.now() - start < 30) ;
+}
+
+function run_test() {
+ run_next_test();
+}
+
+const BREAKDOWN = {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true }
+};
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+ const start = Date.now() * 1000;
+
+ // Because Date.now() is less precise than the snapshot's time stamp, give it
+ // a little bit of head room. Additionally, WinXP's timers have a granularity
+ // of only +/-15 ms.
+ waitForThirtyMilliseconds();
+ const snapshotFilePath = saveNewHeapSnapshot();
+ waitForThirtyMilliseconds();
+ const end = Date.now() * 1000;
+
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ let threw = false;
+ try {
+ yield client.getCreationTime("/not/a/real/path", {
+ breakdown: BREAKDOWN
+ });
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "getCreationTime should throw when snapshot does not exist");
+
+ let time = yield client.getCreationTime(snapshotFilePath, {
+ breakdown: BREAKDOWN
+ });
+
+ dumpn("Start = " + start);
+ dumpn("End = " + end);
+ dumpn("Time = " + time);
+
+ ok(time >= start, "creation time occurred after start");
+ ok(time <= end, "creation time occurred before end");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_01.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_01.js
new file mode 100644
index 000000000..cedea5375
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_01.js
@@ -0,0 +1,69 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the HeapAnalyses{Client,Worker} "getDominatorTree" request.
+
+function run_test() {
+ run_next_test();
+}
+
+const breakdown = {
+ by: "coarseType",
+ objects: { by: "count", count: true, bytes: true },
+ scripts: { by: "count", count: true, bytes: true },
+ strings: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+};
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ const snapshotFilePath = saveNewHeapSnapshot();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath);
+ equal(typeof dominatorTreeId, "number",
+ "should get a dominator tree id, and it should be a number");
+
+ const partialTree = yield client.getDominatorTree({
+ dominatorTreeId,
+ breakdown
+ });
+ ok(partialTree, "Should get a partial tree");
+ equal(typeof partialTree, "object",
+ "partialTree should be an object");
+
+ function checkTree(node) {
+ equal(typeof node.nodeId, "number", "each node should have an id");
+
+ if (node === partialTree) {
+ equal(node.parentId, undefined, "the root has no parent");
+ } else {
+ equal(typeof node.parentId, "number", "each node should have a parent id");
+ }
+
+ equal(typeof node.retainedSize, "number",
+ "each node should have a retained size");
+
+ ok(node.children === undefined || Array.isArray(node.children),
+ "each node either has a list of children, or undefined meaning no children loaded");
+ equal(typeof node.moreChildrenAvailable, "boolean",
+ "each node should indicate if there are more children available or not");
+
+ equal(typeof node.shortestPaths, "object",
+ "Should have shortest paths");
+ equal(typeof node.shortestPaths.nodes, "object",
+ "Should have shortest paths' nodes");
+ equal(typeof node.shortestPaths.edges, "object",
+ "Should have shortest paths' edges");
+
+ if (node.children) {
+ node.children.forEach(checkTree);
+ }
+ }
+
+ checkTree(partialTree);
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_02.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_02.js
new file mode 100644
index 000000000..fd29beece
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_02.js
@@ -0,0 +1,31 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the HeapAnalyses{Client,Worker} "getDominatorTree" request with bad
+// dominator tree ids.
+
+function run_test() {
+ run_next_test();
+}
+
+const breakdown = {
+ by: "coarseType",
+ objects: { by: "count", count: true, bytes: true },
+ scripts: { by: "count", count: true, bytes: true },
+ strings: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+};
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ let threw = false;
+ try {
+ yield client.getDominatorTree({ dominatorTreeId: 42, breakdown });
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "should throw when given a bad id");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getImmediatelyDominated_01.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getImmediatelyDominated_01.js
new file mode 100644
index 000000000..caf1c2056
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_getImmediatelyDominated_01.js
@@ -0,0 +1,81 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the HeapAnalyses{Client,Worker} "getImmediatelyDominated" request.
+
+function run_test() {
+ run_next_test();
+}
+
+const breakdown = {
+ by: "coarseType",
+ objects: { by: "count", count: true, bytes: true },
+ scripts: { by: "count", count: true, bytes: true },
+ strings: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+};
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ const snapshotFilePath = saveNewHeapSnapshot();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath);
+
+ const partialTree = yield client.getDominatorTree({
+ dominatorTreeId,
+ breakdown
+ });
+ ok(partialTree.children.length > 0,
+ "root should immediately dominate some nodes");
+
+ // First, test getting a subset of children available.
+ const response = yield client.getImmediatelyDominated({
+ dominatorTreeId,
+ breakdown,
+ nodeId: partialTree.nodeId,
+ startIndex: 0,
+ maxCount: partialTree.children.length - 1
+ });
+
+ ok(Array.isArray(response.nodes));
+ ok(response.nodes.every(node => node.parentId === partialTree.nodeId));
+ ok(response.moreChildrenAvailable);
+ equal(response.path.length, 1);
+ equal(response.path[0], partialTree.nodeId);
+
+ for (let node of response.nodes) {
+ equal(typeof node.shortestPaths, "object",
+ "Should have shortest paths");
+ equal(typeof node.shortestPaths.nodes, "object",
+ "Should have shortest paths' nodes");
+ equal(typeof node.shortestPaths.edges, "object",
+ "Should have shortest paths' edges");
+ }
+
+ // Next, test getting a subset of children available.
+ const secondResponse = yield client.getImmediatelyDominated({
+ dominatorTreeId,
+ breakdown,
+ nodeId: partialTree.nodeId,
+ startIndex: 0,
+ maxCount: Infinity
+ });
+
+ ok(Array.isArray(secondResponse.nodes));
+ ok(secondResponse.nodes.every(node => node.parentId === partialTree.nodeId));
+ ok(!secondResponse.moreChildrenAvailable);
+ equal(secondResponse.path.length, 1);
+ equal(secondResponse.path[0], partialTree.nodeId);
+
+ for (let node of secondResponse.nodes) {
+ equal(typeof node.shortestPaths, "object",
+ "Should have shortest paths");
+ equal(typeof node.shortestPaths.nodes, "object",
+ "Should have shortest paths' nodes");
+ equal(typeof node.shortestPaths.edges, "object",
+ "Should have shortest paths' edges");
+ }
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_readHeapSnapshot_01.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_readHeapSnapshot_01.js
new file mode 100644
index 000000000..0d0d58bef
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_readHeapSnapshot_01.js
@@ -0,0 +1,18 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} can read heap snapshots.
+
+function run_test() {
+ run_next_test();
+}
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ const snapshotFilePath = saveNewHeapSnapshot();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_01.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_01.js
new file mode 100644
index 000000000..6f22cbad3
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_01.js
@@ -0,0 +1,54 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} can take diffs between censuses.
+
+function run_test() {
+ run_next_test();
+}
+
+const BREAKDOWN = {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: false },
+ other: { by: "count", count: true, bytes: false },
+};
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ const markers = [allocationMarker()];
+
+ const firstSnapshotFilePath = saveNewHeapSnapshot();
+
+ // Allocate and hold an additional AllocationMarker object so we can see it in
+ // the next heap snapshot.
+ markers.push(allocationMarker());
+
+ const secondSnapshotFilePath = saveNewHeapSnapshot();
+
+ yield client.readHeapSnapshot(firstSnapshotFilePath);
+ yield client.readHeapSnapshot(secondSnapshotFilePath);
+ ok(true, "Should have read both heap snapshot files");
+
+ const { delta } = yield client.takeCensusDiff(firstSnapshotFilePath,
+ secondSnapshotFilePath,
+ { breakdown: BREAKDOWN });
+
+ equal(delta.AllocationMarker.count, 1,
+ "There exists one new AllocationMarker in the second heap snapshot");
+
+ const { delta: deltaTreeNode } = yield client.takeCensusDiff(firstSnapshotFilePath,
+ secondSnapshotFilePath,
+ { breakdown: BREAKDOWN },
+ { asTreeNode: true });
+
+ // Have to manually set these because symbol properties aren't structured
+ // cloned.
+ delta[CensusUtils.basisTotalBytes] = deltaTreeNode.totalBytes;
+ delta[CensusUtils.basisTotalCount] = deltaTreeNode.totalCount;
+
+ compareCensusViewData(BREAKDOWN, delta, deltaTreeNode,
+ "Returning delta-census as a tree node represents same data as the report");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_02.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_02.js
new file mode 100644
index 000000000..f1ba9ce84
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensusDiff_02.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} can take diffs between censuses as
+// inverted trees.
+
+function run_test() {
+ run_next_test();
+}
+
+const BREAKDOWN = {
+ by: "coarseType",
+ objects: {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+ },
+ scripts: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ strings: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ other: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+};
+
+add_task(function* () {
+ const firstSnapshotFilePath = saveNewHeapSnapshot();
+ const secondSnapshotFilePath = saveNewHeapSnapshot();
+
+ const client = new HeapAnalysesClient();
+ yield client.readHeapSnapshot(firstSnapshotFilePath);
+ yield client.readHeapSnapshot(secondSnapshotFilePath);
+
+ ok(true, "Should have read both heap snapshot files");
+
+ const { delta } = yield client.takeCensusDiff(firstSnapshotFilePath,
+ secondSnapshotFilePath,
+ { breakdown: BREAKDOWN });
+
+ const { delta: deltaTreeNode } = yield client.takeCensusDiff(firstSnapshotFilePath,
+ secondSnapshotFilePath,
+ { breakdown: BREAKDOWN },
+ { asInvertedTreeNode: true });
+
+ // Have to manually set these because symbol properties aren't structured
+ // cloned.
+ delta[CensusUtils.basisTotalBytes] = deltaTreeNode.totalBytes;
+ delta[CensusUtils.basisTotalCount] = deltaTreeNode.totalCount;
+
+ compareCensusViewData(BREAKDOWN, delta, deltaTreeNode, { invert: true });
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_01.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_01.js
new file mode 100644
index 000000000..e26981db4
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_01.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} can take censuses.
+
+function run_test() {
+ run_next_test();
+}
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ const snapshotFilePath = saveNewHeapSnapshot();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ const { report } = yield client.takeCensus(snapshotFilePath);
+ ok(report, "Should get a report");
+ equal(typeof report, "object", "report should be an object");
+
+ ok(report.objects);
+ ok(report.scripts);
+ ok(report.strings);
+ ok(report.other);
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_02.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_02.js
new file mode 100644
index 000000000..34494af70
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_02.js
@@ -0,0 +1,29 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} can take censuses with breakdown
+// options.
+
+function run_test() {
+ run_next_test();
+}
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ const snapshotFilePath = saveNewHeapSnapshot();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ const { report } = yield client.takeCensus(snapshotFilePath, {
+ breakdown: { by: "count", count: true, bytes: true }
+ });
+
+ ok(report, "Should get a report");
+ equal(typeof report, "object", "report should be an object");
+
+ ok(report.count);
+ ok(report.bytes);
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_03.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_03.js
new file mode 100644
index 000000000..486e250b5
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_03.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} bubbles errors properly when things
+// go wrong.
+
+function run_test() {
+ run_next_test();
+}
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ // Snapshot file path to a file that doesn't exist.
+ let failed = false;
+ try {
+ yield client.readHeapSnapshot(getFilePath("foo-bar-baz" + Math.random(), true));
+ } catch (e) {
+ failed = true;
+ }
+ ok(failed, "should not read heap snapshots that do not exist");
+
+ // Snapshot file path to a file that is not a heap snapshot.
+ failed = false;
+ try {
+ yield client.readHeapSnapshot(getFilePath("test_HeapAnalyses_takeCensus_03.js"));
+ } catch (e) {
+ failed = true;
+ }
+ ok(failed, "should not be able to read a file that is not a heap snapshot as a heap snapshot");
+
+ const snapshotFilePath = saveNewHeapSnapshot();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ // Bad census breakdown options.
+ failed = false;
+ try {
+ yield client.takeCensus(snapshotFilePath, {
+ breakdown: { by: "some classification that we do not have" }
+ });
+ } catch (e) {
+ failed = true;
+ }
+ ok(failed, "should not be able to breakdown by an unknown classification");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_04.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_04.js
new file mode 100644
index 000000000..769a2d99d
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_04.js
@@ -0,0 +1,118 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} can send SavedFrame stacks from
+// by-allocation-stack reports from the worker.
+
+function run_test() {
+ run_next_test();
+}
+
+add_task(function* test() {
+ const client = new HeapAnalysesClient();
+
+ // Track some allocation stacks.
+
+ const g = newGlobal();
+ const dbg = new Debugger(g);
+ g.eval(` // 1
+ this.log = []; // 2
+ function f() { this.log.push(allocationMarker()); } // 3
+ function g() { this.log.push(allocationMarker()); } // 4
+ function h() { this.log.push(allocationMarker()); } // 5
+ `); // 6
+
+ // Create one allocationMarker with tracking turned off,
+ // so it will have no associated stack.
+ g.f();
+
+ dbg.memory.allocationSamplingProbability = 1;
+
+ for (let [func, n] of [ [g.f, 20],
+ [g.g, 10],
+ [g.h, 5] ]) {
+ for (let i = 0; i < n; i++) {
+ dbg.memory.trackingAllocationSites = true;
+ // All allocations of allocationMarker occur with this line as the oldest
+ // stack frame.
+ func();
+ dbg.memory.trackingAllocationSites = false;
+ }
+ }
+
+ // Take a heap snapshot.
+
+ const snapshotFilePath = saveNewHeapSnapshot({ debugger: dbg });
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ // Run a census broken down by class name -> allocation stack so we can grab
+ // only the AllocationMarker objects we have complete control over.
+
+ const { report } = yield client.takeCensus(snapshotFilePath, {
+ breakdown: { by: "objectClass",
+ then: { by: "allocationStack",
+ then: { by: "count",
+ bytes: true,
+ count: true
+ },
+ noStack: { by: "count",
+ bytes: true,
+ count: true
+ }
+ }
+ }
+ });
+
+ // Test the generated report.
+
+ ok(report, "Should get a report");
+
+ const map = report.AllocationMarker;
+ ok(map, "Should get AllocationMarkers in the report.");
+ // From a module with a different global, and therefore a different Map
+ // constructor, so we can't use instanceof.
+ equal(map.__proto__.constructor.name, "Map");
+
+ equal(map.size, 4, "Should have 4 allocation stacks (including the lack of a stack)");
+
+ // Gather the stacks we are expecting to appear as keys, and
+ // check that there are no unexpected keys.
+ let stacks = {};
+
+ map.forEach((v, k) => {
+ if (k === "noStack") {
+ // No need to save this key.
+ } else if (k.functionDisplayName === "f" &&
+ k.parent.functionDisplayName === "test") {
+ stacks.f = k;
+ } else if (k.functionDisplayName === "g" &&
+ k.parent.functionDisplayName === "test") {
+ stacks.g = k;
+ } else if (k.functionDisplayName === "h" &&
+ k.parent.functionDisplayName === "test") {
+ stacks.h = k;
+ } else {
+ dumpn("Unexpected allocation stack:");
+ k.toString().split(/\n/g).forEach(s => dumpn(s));
+ ok(false);
+ }
+ });
+
+ ok(map.get("noStack"));
+ equal(map.get("noStack").count, 1);
+
+ ok(stacks.f);
+ ok(map.get(stacks.f));
+ equal(map.get(stacks.f).count, 20);
+
+ ok(stacks.g);
+ ok(map.get(stacks.g));
+ equal(map.get(stacks.g).count, 10);
+
+ ok(stacks.h);
+ ok(map.get(stacks.h));
+ equal(map.get(stacks.h).count, 5);
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_05.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_05.js
new file mode 100644
index 000000000..7e16d9f00
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_05.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} can take censuses and return
+// a CensusTreeNode.
+
+function run_test() {
+ run_next_test();
+}
+
+const BREAKDOWN = {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true }
+};
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ const snapshotFilePath = saveNewHeapSnapshot();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ const { report } = yield client.takeCensus(snapshotFilePath, {
+ breakdown: BREAKDOWN
+ });
+
+ const { report: treeNode } = yield client.takeCensus(snapshotFilePath, {
+ breakdown: BREAKDOWN
+ }, {
+ asTreeNode: true
+ });
+
+ ok(treeNode.children.length > 0, "treeNode has children");
+ ok(treeNode.children.every(type => {
+ return "name" in type &&
+ "bytes" in type &&
+ "count" in type;
+ }), "all of tree node's children have name, bytes, count");
+
+ compareCensusViewData(BREAKDOWN, report, treeNode,
+ "Returning census as a tree node represents same data as the report");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_06.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_06.js
new file mode 100644
index 000000000..7795a9700
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_06.js
@@ -0,0 +1,109 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} can take censuses by
+// "allocationStack" and return a CensusTreeNode.
+
+function run_test() {
+ run_next_test();
+}
+
+const BREAKDOWN = {
+ by: "objectClass",
+ then: {
+ by: "allocationStack",
+ then: { by: "count", count: true, bytes: true },
+ noStack: { by: "count", count: true, bytes: true }
+ },
+ other: { by: "count", count: true, bytes: true }
+};
+
+add_task(function* () {
+ const g = newGlobal();
+ const dbg = new Debugger(g);
+
+ // 5 allocation markers with no stack.
+ g.eval(`
+ this.markers = [];
+ for (var i = 0; i < 5; i++) {
+ markers.push(allocationMarker());
+ }
+ `);
+
+ dbg.memory.allocationSamplingProbability = 1;
+ dbg.memory.trackingAllocationSites = true;
+
+ // 5 allocation markers at 5 stacks.
+ g.eval(`
+ (function shouldHaveCountOfOne() {
+ markers.push(allocationMarker());
+ markers.push(allocationMarker());
+ markers.push(allocationMarker());
+ markers.push(allocationMarker());
+ markers.push(allocationMarker());
+ }());
+ `);
+
+ // 5 allocation markers at 1 stack.
+ g.eval(`
+ (function shouldHaveCountOfFive() {
+ for (var i = 0; i < 5; i++) {
+ markers.push(allocationMarker());
+ }
+ }());
+ `);
+
+ const snapshotFilePath = saveNewHeapSnapshot({ debugger: dbg });
+
+ const client = new HeapAnalysesClient();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ const { report } = yield client.takeCensus(snapshotFilePath, {
+ breakdown: BREAKDOWN
+ });
+
+ const { report: treeNode } = yield client.takeCensus(snapshotFilePath, {
+ breakdown: BREAKDOWN
+ }, {
+ asTreeNode: true
+ });
+
+ const markers = treeNode.children.find(c => c.name === "AllocationMarker");
+ ok(markers);
+
+ const noStack = markers.children.find(c => c.name === "noStack");
+ equal(noStack.count, 5);
+
+ let numShouldHaveFiveFound = 0;
+ let numShouldHaveOneFound = 0;
+
+ function walk(node) {
+ if (node.children) {
+ node.children.forEach(walk);
+ }
+
+ if (!isSavedFrame(node.name)) {
+ return;
+ }
+
+ if (node.name.functionDisplayName === "shouldHaveCountOfFive") {
+ equal(node.count, 5, "shouldHaveCountOfFive should have count of five");
+ numShouldHaveFiveFound++;
+ }
+
+ if (node.name.functionDisplayName === "shouldHaveCountOfOne") {
+ equal(node.count, 1, "shouldHaveCountOfOne should have count of one");
+ numShouldHaveOneFound++;
+ }
+ }
+ markers.children.forEach(walk);
+
+ equal(numShouldHaveFiveFound, 1);
+ equal(numShouldHaveOneFound, 5);
+
+ compareCensusViewData(BREAKDOWN, report, treeNode,
+ "Returning census as a tree node represents same data as the report");
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_07.js b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_07.js
new file mode 100644
index 000000000..986b3aaa8
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapAnalyses_takeCensus_07.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the HeapAnalyses{Client,Worker} can take censuses and return
+// an inverted CensusTreeNode.
+
+function run_test() {
+ run_next_test();
+}
+
+const BREAKDOWN = {
+ by: "coarseType",
+ objects: {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+ },
+ scripts: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ strings: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ other: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+};
+
+add_task(function* () {
+ const client = new HeapAnalysesClient();
+
+ const snapshotFilePath = saveNewHeapSnapshot();
+ yield client.readHeapSnapshot(snapshotFilePath);
+ ok(true, "Should have read the heap snapshot");
+
+ const { report } = yield client.takeCensus(snapshotFilePath, {
+ breakdown: BREAKDOWN
+ });
+
+ const { report: treeNode } = yield client.takeCensus(snapshotFilePath, {
+ breakdown: BREAKDOWN
+ }, {
+ asInvertedTreeNode: true
+ });
+
+ compareCensusViewData(BREAKDOWN, report, treeNode, { invert: true });
+
+ client.destroy();
+});
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_01.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_01.js
new file mode 100644
index 000000000..2ec577bd0
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_01.js
@@ -0,0 +1,69 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Sanity test that we can compute shortest paths.
+//
+// Because the actual heap graph is too unpredictable and likely to drastically
+// change as various implementation bits change, we don't test exact paths
+// here. See js/src/jsapi-tests/testUbiNode.cpp for such tests, where we can
+// control the specific graph shape and structure and so testing exact paths is
+// reliable.
+
+function run_test() {
+ const path = ChromeUtils.saveHeapSnapshot({ runtime: true });
+ const snapshot = ChromeUtils.readHeapSnapshot(path);
+
+ const dominatorTree = snapshot.computeDominatorTree();
+ const dominatedByRoot = dominatorTree.getImmediatelyDominated(dominatorTree.root)
+ .slice(0, 10);
+ ok(dominatedByRoot);
+ ok(dominatedByRoot.length);
+
+ const targetSet = new Set(dominatedByRoot);
+
+ const shortestPaths = snapshot.computeShortestPaths(dominatorTree.root, dominatedByRoot, 2);
+ ok(shortestPaths);
+ ok(shortestPaths instanceof Map);
+ ok(shortestPaths.size === targetSet.size);
+
+ for (let [target, paths] of shortestPaths) {
+ ok(targetSet.has(target),
+ "We should only get paths for our targets");
+ targetSet.delete(target);
+
+ ok(paths.length > 0,
+ "We must have at least one path, since the target is dominated by the root");
+ ok(paths.length <= 2,
+ "Should not have recorded more paths than the max requested");
+
+ dumpn("---------------------");
+ dumpn("Shortest paths for 0x" + target.toString(16) + ":");
+ for (let path of paths) {
+ dumpn(" path =");
+ for (let part of path) {
+ dumpn(" predecessor: 0x" + part.predecessor.toString(16) +
+ "; edge: " + part.edge);
+ }
+ }
+ dumpn("---------------------");
+
+ for (let path of paths) {
+ ok(path.length > 0, "Cannot have zero length paths");
+ ok(path[0].predecessor === dominatorTree.root,
+ "The first predecessor is always our start node");
+
+ for (let part of path) {
+ ok(part.predecessor, "Each part of a path has a predecessor");
+ ok(!!snapshot.describeNode({ by: "count", count: true, bytes: true},
+ part.predecessor),
+ "The predecessor is in the heap snapshot");
+ ok("edge" in part, "Each part has an (potentially null) edge property");
+ }
+ }
+ }
+
+ ok(targetSet.size === 0,
+ "We found paths for all of our targets");
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_02.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_02.js
new file mode 100644
index 000000000..04fe58733
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_computeShortestPaths_02.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test computing shortest paths with invalid arguments.
+
+function run_test() {
+ const path = ChromeUtils.saveHeapSnapshot({ runtime: true });
+ const snapshot = ChromeUtils.readHeapSnapshot(path);
+
+ const dominatorTree = snapshot.computeDominatorTree();
+ const target = dominatorTree.getImmediatelyDominated(dominatorTree.root).pop();
+ ok(target);
+
+ let threw = false;
+ try {
+ snapshot.computeShortestPaths(0, [target], 2);
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "invalid start node should throw");
+
+ threw = false;
+ try {
+ snapshot.computeShortestPaths(dominatorTree.root, [0], 2);
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "invalid target nodes should throw");
+
+ threw = false;
+ try {
+ snapshot.computeShortestPaths(dominatorTree.root, [], 2);
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "empty target nodes should throw");
+
+ threw = false;
+ try {
+ snapshot.computeShortestPaths(dominatorTree.root, [target], 0);
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "0 max paths should throw");
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_creationTime_01.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_creationTime_01.js
new file mode 100644
index 000000000..0d08fea16
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_creationTime_01.js
@@ -0,0 +1,30 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// HeapSnapshot.prototype.creationTime returns the expected time.
+
+function waitForThirtyMilliseconds() {
+ const start = Date.now();
+ while (Date.now() - start < 30) ;
+}
+
+function run_test() {
+ const start = Date.now() * 1000;
+ do_print("start = " + start);
+
+ // Because Date.now() is less precise than the snapshot's time stamp, give it
+ // a little bit of head room. Additionally, WinXP's timer only has granularity
+ // of +/- 15ms.
+ waitForThirtyMilliseconds();
+ const path = ChromeUtils.saveHeapSnapshot({ runtime: true });
+ waitForThirtyMilliseconds();
+
+ const end = Date.now() * 1000;
+ do_print("end = " + end);
+
+ const snapshot = ChromeUtils.readHeapSnapshot(path);
+ do_print("snapshot.creationTime = " + snapshot.creationTime);
+
+ ok(snapshot.creationTime >= start);
+ ok(snapshot.creationTime <= end);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_deepStack_01.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_deepStack_01.js
new file mode 100644
index 000000000..9eb11d9af
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_deepStack_01.js
@@ -0,0 +1,70 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can save a core dump with very deep allocation stacks and read
+// it back into a HeapSnapshot.
+
+function stackDepth(stack) {
+ return stack ? 1 + stackDepth(stack.parent) : 0;
+}
+
+function run_test() {
+ // Create a Debugger observing a debuggee's allocations.
+ const debuggee = new Cu.Sandbox(null);
+ const dbg = new Debugger(debuggee);
+ dbg.memory.trackingAllocationSites = true;
+
+ // Allocate some objects in the debuggee that will have their allocation
+ // stacks recorded by the Debugger.
+
+ debuggee.eval("this.objects = []");
+ debuggee.eval(
+ (function recursiveAllocate(n) {
+ if (n <= 0)
+ return;
+
+ // Make sure to recurse before pushing the object so that when TCO is
+ // implemented sometime in the future, it doesn't invalidate this test.
+ recursiveAllocate(n - 1);
+ this.objects.push({});
+ }).toString()
+ );
+ debuggee.eval("recursiveAllocate = recursiveAllocate.bind(this);");
+ debuggee.eval("recursiveAllocate(200);");
+
+ // Now save a snapshot that will include the allocation stacks and read it
+ // back again.
+
+ const filePath = ChromeUtils.saveHeapSnapshot({ runtime: true });
+ ok(true, "Should be able to save a snapshot.");
+
+ const snapshot = ChromeUtils.readHeapSnapshot(filePath);
+ ok(snapshot, "Should be able to read a heap snapshot");
+ ok(snapshot instanceof HeapSnapshot, "Should be an instanceof HeapSnapshot");
+
+ const report = snapshot.takeCensus({
+ breakdown: { by: "allocationStack",
+ then: { by: "count", bytes: true, count: true },
+ noStack: { by: "count", bytes: true, count: true }
+ }
+ });
+
+ // Keep this synchronized with `HeapSnapshot::MAX_STACK_DEPTH`!
+ const MAX_STACK_DEPTH = 60;
+
+ let foundStacks = false;
+ report.forEach((v, k) => {
+ if (k === "noStack") {
+ return;
+ }
+
+ foundStacks = true;
+ const depth = stackDepth(k);
+ dumpn("Stack depth is " + depth);
+ ok(depth <= MAX_STACK_DEPTH,
+ "Every stack should have depth less than or equal to the maximum stack depth");
+ });
+ ok(foundStacks);
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_describeNode_01.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_describeNode_01.js
new file mode 100644
index 000000000..d79cb5a7b
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_describeNode_01.js
@@ -0,0 +1,42 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can describe nodes with a breakdown.
+
+function run_test() {
+ const path = saveNewHeapSnapshot();
+ const snapshot = ChromeUtils.readHeapSnapshot(path);
+ ok(snapshot.describeNode);
+ equal(typeof snapshot.describeNode, "function");
+
+ const dt = snapshot.computeDominatorTree();
+
+ let threw = false;
+ try {
+ snapshot.describeNode(undefined, dt.root);
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "Should require a breakdown");
+
+ const breakdown = {
+ by: "coarseType",
+ objects: { by: "objectClass" },
+ scripts: { by: "internalType" },
+ strings: { by: "internalType" },
+ other: { by: "internalType" }
+ };
+
+ threw = false;
+ try {
+ snapshot.describeNode(breakdown, 0);
+ } catch (_) {
+ threw = true;
+ }
+ ok(threw, "Should throw when given an invalid node id");
+
+ const description = snapshot.describeNode(breakdown, dt.root);
+ ok(description);
+ ok(description.other);
+ ok(description.other["JS::ubi::RootList"]);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_01.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_01.js
new file mode 100644
index 000000000..f3b3090b0
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_01.js
@@ -0,0 +1,31 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// HeapSnapshot.prototype.takeCensus returns a value of an appropriate
+// shape. Ported from js/src/jit-tests/debug/Memory-takeCensus-01.js
+
+function run_test() {
+ var dbg = new Debugger;
+
+ function checkProperties(census) {
+ equal(typeof census, "object");
+ for (prop of Object.getOwnPropertyNames(census)) {
+ var desc = Object.getOwnPropertyDescriptor(census, prop);
+ equal(desc.enumerable, true);
+ equal(desc.configurable, true);
+ equal(desc.writable, true);
+ if (typeof desc.value === "object")
+ checkProperties(desc.value);
+ else
+ equal(typeof desc.value, "number");
+ }
+ }
+
+ checkProperties(saveHeapSnapshotAndTakeCensus(dbg));
+
+ var g = newGlobal();
+ dbg.addDebuggee(g);
+ checkProperties(saveHeapSnapshotAndTakeCensus(dbg));
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_02.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_02.js
new file mode 100644
index 000000000..680ac9b58
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_02.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// HeapSnapshot.prototype.takeCensus behaves plausibly as we allocate objects.
+//
+// Exact object counts vary in ways we can't predict. For example,
+// BaselineScripts can hold onto "template objects", which exist only to hold
+// the shape and type for newly created objects. When BaselineScripts are
+// discarded, these template objects go with them.
+//
+// So instead of expecting precise counts, we expect counts that are at least as
+// many as we would expect given the object graph we've built.
+//
+// Ported from js/src/jit-tests/debug/Memory-takeCensus-02.js
+
+function run_test() {
+ // A Debugger with no debuggees had better not find anything.
+ var dbg = new Debugger;
+ var census0 = saveHeapSnapshotAndTakeCensus(dbg);
+ Census.walkCensus(census0, "census0", Census.assertAllZeros);
+
+ function newGlobalWithDefs() {
+ var g = newGlobal();
+ g.eval(`
+ function times(n, fn) {
+ var a=[];
+ for (var i = 0; i<n; i++)
+ a.push(fn());
+ return a;
+ }
+ `);
+ return g;
+ }
+
+ // Allocate a large number of various types of objects, and check that census
+ // finds them.
+ var g = newGlobalWithDefs();
+ dbg.addDebuggee(g);
+
+ g.eval("var objs = times(100, () => ({}));");
+ g.eval("var rxs = times(200, () => /foo/);");
+ g.eval("var ars = times(400, () => []);");
+ g.eval("var fns = times(800, () => () => {});");
+
+ var census1 = dbg.memory.takeCensus(dbg);
+ Census.walkCensus(census1, "census1",
+ Census.assertAllNotLessThan(
+ { "objects":
+ { "Object": { count: 100 },
+ "RegExp": { count: 200 },
+ "Array": { count: 400 },
+ "Function": { count: 800 }
+ }
+ }));
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_03.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_03.js
new file mode 100644
index 000000000..25f2c3791
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_03.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// HeapSnapshot.prototype.takeCensus behaves plausibly as we add and remove
+// debuggees.
+//
+// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-03.js
+
+function run_test() {
+ var dbg = new Debugger;
+
+ var census0 = saveHeapSnapshotAndTakeCensus(dbg);
+ Census.walkCensus(census0, "census0", Census.assertAllZeros);
+
+ var g1 = newGlobal();
+ dbg.addDebuggee(g1);
+ var census1 = saveHeapSnapshotAndTakeCensus(dbg);
+ Census.walkCensus(census1, "census1", Census.assertAllNotLessThan(census0));
+
+ var g2 = newGlobal();
+ dbg.addDebuggee(g2);
+ var census2 = saveHeapSnapshotAndTakeCensus(dbg);
+ Census.walkCensus(census2, "census2", Census.assertAllNotLessThan(census1));
+
+ dbg.removeDebuggee(g2);
+ var census3 = saveHeapSnapshotAndTakeCensus(dbg);
+ Census.walkCensus(census3, "census3", Census.assertAllEqual(census1));
+
+ dbg.removeDebuggee(g1);
+ var census4 = saveHeapSnapshotAndTakeCensus(dbg);
+ Census.walkCensus(census4, "census4", Census.assertAllEqual(census0));
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_04.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_04.js
new file mode 100644
index 000000000..799844cde
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_04.js
@@ -0,0 +1,36 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that HeapSnapshot.prototype.takeCensus finds GC roots that are on the
+// stack.
+//
+// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-04.js
+
+function run_test() {
+ var g = newGlobal();
+ var dbg = new Debugger(g);
+
+ g.eval(`
+function withAllocationMarkerOnStack(f) {
+ (function () {
+ var onStack = allocationMarker();
+ f();
+ }());
+}
+`);
+
+ equal("AllocationMarker" in saveHeapSnapshotAndTakeCensus(dbg).objects, false,
+ "There shouldn't exist any allocation markers in the census.");
+
+ var allocationMarkerCount;
+ g.withAllocationMarkerOnStack(() => {
+ const census = saveHeapSnapshotAndTakeCensus(dbg);
+ allocationMarkerCount = census.objects.AllocationMarker.count;
+ });
+
+ equal(allocationMarkerCount, 1,
+ "Should have one allocation marker in the census, because there " +
+ "was one on the stack.");
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_05.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_05.js
new file mode 100644
index 000000000..da6067624
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_05.js
@@ -0,0 +1,24 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that HeapSnapshot.prototype.takeCensus finds cross compartment
+// wrapper GC roots.
+//
+// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-05.js
+
+function run_test() {
+ var g = newGlobal();
+ var dbg = new Debugger(g);
+
+ equal("AllocationMarker" in saveHeapSnapshotAndTakeCensus(dbg).objects, false,
+ "No allocation markers should exist in the census.");
+
+ this.ccw = g.allocationMarker();
+
+ const census = saveHeapSnapshotAndTakeCensus(dbg);
+ equal(census.objects.AllocationMarker.count, 1,
+ "Should have one allocation marker in the census, because there " +
+ "is one cross-compartment wrapper referring to it.");
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_06.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_06.js
new file mode 100644
index 000000000..0412410c0
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_06.js
@@ -0,0 +1,125 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Check HeapSnapshot.prototype.takeCensus handling of 'breakdown' argument.
+//
+// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-06.js
+
+function run_test() {
+ var Pattern = Match.Pattern;
+
+ var g = newGlobal();
+ var dbg = new Debugger(g);
+
+ Pattern({ count: Pattern.NATURAL,
+ bytes: Pattern.NATURAL })
+ .assert(saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count" } }));
+
+ let census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count", count: false, bytes: false } });
+ equal("count" in census, false);
+ equal("bytes" in census, false);
+
+ census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count", count: true, bytes: false } });
+ equal("count" in census, true);
+ equal("bytes" in census, false);
+
+ census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count", count: false, bytes: true } });
+ equal("count" in census, false);
+ equal("bytes" in census, true);
+
+ census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count", count: true, bytes: true } });
+ equal("count" in census, true);
+ equal("bytes" in census, true);
+
+
+ // Pattern doesn't mind objects with extra properties, so we'll restrict this
+ // list to the object classes we're pretty sure are going to stick around for
+ // the forseeable future.
+ Pattern({
+ Function: { count: Pattern.NATURAL },
+ Object: { count: Pattern.NATURAL },
+ Debugger: { count: Pattern.NATURAL },
+ Sandbox: { count: Pattern.NATURAL },
+
+ // The below are all Debugger prototype objects.
+ Source: { count: Pattern.NATURAL },
+ Environment: { count: Pattern.NATURAL },
+ Script: { count: Pattern.NATURAL },
+ Memory: { count: Pattern.NATURAL },
+ Frame: { count: Pattern.NATURAL }
+ })
+ .assert(saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "objectClass" } }));
+
+ Pattern({
+ objects: { count: Pattern.NATURAL },
+ scripts: { count: Pattern.NATURAL },
+ strings: { count: Pattern.NATURAL },
+ other: { count: Pattern.NATURAL }
+ })
+ .assert(saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "coarseType" } }));
+
+ // As for { by: 'objectClass' }, restrict our pattern to the types
+ // we predict will stick around for a long time.
+ Pattern({
+ JSString: { count: Pattern.NATURAL },
+ "js::Shape": { count: Pattern.NATURAL },
+ JSObject: { count: Pattern.NATURAL },
+ JSScript: { count: Pattern.NATURAL }
+ })
+ .assert(saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "internalType" } }));
+
+
+ // Nested breakdowns.
+
+ let coarseTypePattern = {
+ objects: { count: Pattern.NATURAL },
+ scripts: { count: Pattern.NATURAL },
+ strings: { count: Pattern.NATURAL },
+ other: { count: Pattern.NATURAL }
+ };
+
+ Pattern({
+ JSString: coarseTypePattern,
+ "js::Shape": coarseTypePattern,
+ JSObject: coarseTypePattern,
+ JSScript: coarseTypePattern,
+ })
+ .assert(saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: { by: "internalType",
+ then: { by: "coarseType" }
+ }
+ }));
+
+ Pattern({
+ Function: { count: Pattern.NATURAL },
+ Object: { count: Pattern.NATURAL },
+ Debugger: { count: Pattern.NATURAL },
+ Sandbox: { count: Pattern.NATURAL },
+ other: coarseTypePattern
+ })
+ .assert(saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: {
+ by: "objectClass",
+ then: { by: "count" },
+ other: { by: "coarseType" }
+ }
+ }));
+
+ Pattern({
+ objects: { count: Pattern.NATURAL, label: "object" },
+ scripts: { count: Pattern.NATURAL, label: "scripts" },
+ strings: { count: Pattern.NATURAL, label: "strings" },
+ other: { count: Pattern.NATURAL, label: "other" }
+ })
+ .assert(saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: {
+ by: "coarseType",
+ objects: { by: "count", label: "object" },
+ scripts: { by: "count", label: "scripts" },
+ strings: { by: "count", label: "strings" },
+ other: { by: "count", label: "other" }
+ }
+ }));
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_07.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_07.js
new file mode 100644
index 000000000..f5c36056f
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_07.js
@@ -0,0 +1,82 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// HeapSnapshot.prototype.takeCensus breakdown: check error handling on property
+// gets.
+//
+// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-07.js
+
+function run_test() {
+ var g = newGlobal();
+ var dbg = new Debugger(g);
+
+ assertThrowsValue(() => {
+ saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: { get by() { throw "ಠ_ಠ"; } }
+ });
+ }, "ಠ_ಠ");
+
+
+
+ assertThrowsValue(() => {
+ saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: { by: "count", get count() { throw "ಠ_ಠ"; } }
+ });
+ }, "ಠ_ಠ");
+
+ assertThrowsValue(() => {
+ saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: { by: "count", get bytes() { throw "ಠ_ಠ"; } }
+ });
+ }, "ಠ_ಠ");
+
+
+
+ assertThrowsValue(() => {
+ saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: { by: "objectClass", get then() { throw "ಠ_ಠ"; } }
+ });
+ }, "ಠ_ಠ");
+
+ assertThrowsValue(() => {
+ saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: { by: "objectClass", get other() { throw "ಠ_ಠ"; } }
+ });
+ }, "ಠ_ಠ");
+
+
+
+ assertThrowsValue(() => {
+ saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: { by: "coarseType", get objects() { throw "ಠ_ಠ"; } }
+ });
+ }, "ಠ_ಠ");
+
+ assertThrowsValue(() => {
+ saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: { by: "coarseType", get scripts() { throw "ಠ_ಠ"; } }
+ });
+ }, "ಠ_ಠ");
+
+ assertThrowsValue(() => {
+ saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: { by: "coarseType", get strings() { throw "ಠ_ಠ"; } }
+ });
+ }, "ಠ_ಠ");
+
+ assertThrowsValue(() => {
+ saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: { by: "coarseType", get other() { throw "ಠ_ಠ"; } }
+ });
+ }, "ಠ_ಠ");
+
+
+
+ assertThrowsValue(() => {
+ saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: { by: "internalType", get then() { throw "ಠ_ಠ"; } }
+ });
+ }, "ಠ_ಠ");
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_08.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_08.js
new file mode 100644
index 000000000..5934aa919
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_08.js
@@ -0,0 +1,82 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// HeapSnapshot.prototype.takeCensus: test by: 'count' breakdown
+//
+// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-08.js
+
+function run_test() {
+ let g = newGlobal();
+ let dbg = new Debugger(g);
+
+ g.eval(`
+ var stuff = [];
+ function add(n, c) {
+ for (let i = 0; i < n; i++)
+ stuff.push(c());
+ }
+
+ let count = 0;
+
+ function obj() { return { count: count++ }; }
+ obj.factor = 1;
+
+ // This creates a closure (a function JSObject) that has captured
+ // a Call object. So each call creates two items.
+ function fun() { let v = count; return () => { return v; } }
+ fun.factor = 2;
+
+ function str() { return 'perambulator' + count++; }
+ str.factor = 1;
+
+ // Eval a fresh text each time, allocating:
+ // - a fresh ScriptSourceObject
+ // - a new JSScripts, not an eval cache hits
+ // - a fresh prototype object
+ // - a fresh Call object, since the eval makes 'ev' heavyweight
+ // - the new function itself
+ function ev() {
+ return eval(\`(function () { return \${ count++ } })\`);
+ }
+ ev.factor = 5;
+
+ // A new object (1) with a new shape (2) with a new atom (3)
+ function shape() { return { [ 'theobroma' + count++ ]: count }; }
+ shape.factor = 3;
+ `);
+
+ let baseline = 0;
+ function countIncreasedByAtLeast(n) {
+ let oldBaseline = baseline;
+
+ // Since a census counts only reachable objects, one might assume that calling
+ // GC here would have no effect on the census results. But GC also throws away
+ // JIT code and any objects it might be holding (template objects, say);
+ // takeCensus reaches those. Shake everything loose that we can, to make the
+ // census approximate reachability a bit more closely, and make our results a
+ // bit more predictable.
+ gc(g, "shrinking");
+
+ baseline = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "count" } }).count;
+ return baseline >= oldBaseline + n;
+ }
+
+ countIncreasedByAtLeast(0);
+
+ g.add(100, g.obj);
+ ok(countIncreasedByAtLeast(g.obj.factor * 100));
+
+ g.add(100, g.fun);
+ ok(countIncreasedByAtLeast(g.fun.factor * 100));
+
+ g.add(100, g.str);
+ ok(countIncreasedByAtLeast(g.str.factor * 100));
+
+ g.add(100, g.ev);
+ ok(countIncreasedByAtLeast(g.ev.factor * 100));
+
+ g.add(100, g.shape);
+ ok(countIncreasedByAtLeast(g.shape.factor * 100));
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_09.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_09.js
new file mode 100644
index 000000000..bbacccc8d
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_09.js
@@ -0,0 +1,92 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// HeapSnapshot.prototype.takeCensus: by: allocationStack breakdown
+//
+// Ported from js/src/jit-test/tests/debug/Memory-takeCensus-09.js
+
+function run_test() {
+ var g = newGlobal();
+ var dbg = new Debugger(g);
+
+ g.eval(` // 1
+ var log = []; // 2
+ function f() { log.push(allocationMarker()); } // 3
+ function g() { f(); } // 4
+ function h() { f(); } // 5
+ `); // 6
+
+ // Create one allocationMarker with tracking turned off,
+ // so it will have no associated stack.
+ g.f();
+
+ dbg.memory.allocationSamplingProbability = 1;
+
+ for ([func, n] of [[g.f, 20], [g.g, 10], [g.h, 5]]) {
+ for (let i = 0; i < n; i++) {
+ dbg.memory.trackingAllocationSites = true;
+ // All allocations of allocationMarker occur with this line as the oldest
+ // stack frame.
+ func();
+ dbg.memory.trackingAllocationSites = false;
+ }
+ }
+
+ let census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "objectClass",
+ then: { by: "allocationStack",
+ then: { by: "count",
+ label: "haz stack"
+ },
+ noStack: { by: "count",
+ label: "no haz stack"
+ }
+ }
+ }
+ });
+
+ let map = census.AllocationMarker;
+ ok(map instanceof Map, "Should be a Map instance");
+ equal(map.size, 4, "Should have 4 allocation stacks (including the lack of a stack)");
+
+ // Gather the stacks we are expecting to appear as keys, and
+ // check that there are no unexpected keys.
+ let stacks = { };
+
+ map.forEach((v, k) => {
+ if (k === "noStack") {
+ // No need to save this key.
+ } else if (k.functionDisplayName === "f" &&
+ k.parent.functionDisplayName === "run_test") {
+ stacks.f = k;
+ } else if (k.functionDisplayName === "f" &&
+ k.parent.functionDisplayName === "g" &&
+ k.parent.parent.functionDisplayName === "run_test") {
+ stacks.fg = k;
+ } else if (k.functionDisplayName === "f" &&
+ k.parent.functionDisplayName === "h" &&
+ k.parent.parent.functionDisplayName === "run_test") {
+ stacks.fh = k;
+ } else {
+ dumpn("Unexpected allocation stack:");
+ k.toString().split(/\n/g).forEach(s => dumpn(s));
+ ok(false);
+ }
+ });
+
+ equal(map.get("noStack").label, "no haz stack");
+ equal(map.get("noStack").count, 1);
+
+ ok(stacks.f);
+ equal(map.get(stacks.f).label, "haz stack");
+ equal(map.get(stacks.f).count, 20);
+
+ ok(stacks.fg);
+ equal(map.get(stacks.fg).label, "haz stack");
+ equal(map.get(stacks.fg).count, 10);
+
+ ok(stacks.fh);
+ equal(map.get(stacks.fh).label, "haz stack");
+ equal(map.get(stacks.fh).count, 5);
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_10.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_10.js
new file mode 100644
index 000000000..a7f987f5a
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_10.js
@@ -0,0 +1,68 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Check byte counts produced by takeCensus.
+//
+// Ported from js/src/jit-test/tests/debug/Memory-take Census-10.js
+
+function run_test() {
+ let g = newGlobal();
+ let dbg = new Debugger(g);
+
+ let sizeOfAM = byteSize(allocationMarker());
+
+ // Allocate a single allocation marker, and check that we can find it.
+ g.eval("var hold = allocationMarker();");
+ let census = saveHeapSnapshotAndTakeCensus(dbg, { breakdown: { by: "objectClass" } });
+ equal(census.AllocationMarker.count, 1);
+ equal(census.AllocationMarker.bytes, sizeOfAM);
+ g.hold = null;
+
+ g.eval(` // 1
+ var objs = []; // 2
+ function fnerd() { // 3
+ objs.push(allocationMarker()); // 4
+ for (let i = 0; i < 10; i++) // 5
+ objs.push(allocationMarker()); // 6
+ } // 7
+ `); // 8
+
+ dbg.memory.allocationSamplingProbability = 1;
+ dbg.memory.trackingAllocationSites = true;
+ g.fnerd();
+ dbg.memory.trackingAllocationSites = false;
+
+ census = saveHeapSnapshotAndTakeCensus(dbg, {
+ breakdown: { by: "objectClass",
+ then: { by: "allocationStack" }
+ }
+ });
+
+ let seen = 0;
+ census.AllocationMarker.forEach((v, k) => {
+ equal(k.functionDisplayName, "fnerd");
+ switch (k.line) {
+ case 4:
+ equal(v.count, 1);
+ equal(v.bytes, sizeOfAM);
+ seen++;
+ break;
+
+ case 6:
+ equal(v.count, 10);
+ equal(v.bytes, 10 * sizeOfAM);
+ seen++;
+ break;
+
+ default:
+ dumpn("Unexpected stack:");
+ k.toString().split(/\n/g).forEach(s => dumpn(s));
+ ok(false);
+ break;
+ }
+ });
+
+ equal(seen, 2);
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_11.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_11.js
new file mode 100644
index 000000000..3d898b2d1
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_11.js
@@ -0,0 +1,116 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that Debugger.Memory.prototype.takeCensus and
+// HeapSnapshot.prototype.takeCensus return the same data for the same heap
+// graph.
+
+function doLiveAndOfflineCensus(g, dbg, opts) {
+ dbg.memory.allocationSamplingProbability = 1;
+ dbg.memory.trackingAllocationSites = true;
+ g.eval(` // 1
+ (function unsafeAtAnySpeed() { // 2
+ for (var i = 0; i < 100; i++) { // 3
+ this.markers.push(allocationMarker()); // 4
+ } // 5
+ }()); // 6
+ `); // 7
+ dbg.memory.trackingAllocationSites = false;
+
+ return {
+ live: dbg.memory.takeCensus(opts),
+ offline: saveHeapSnapshotAndTakeCensus(dbg, opts)
+ };
+}
+
+function run_test() {
+ var g = newGlobal();
+ var dbg = new Debugger(g);
+
+ g.eval("this.markers = []");
+ const markerSize = byteSize(allocationMarker());
+
+ // First, test that we get the same counts and sizes as we allocate and retain
+ // more things.
+
+ let prevCount = 0;
+ let prevBytes = 0;
+
+ for (var i = 0; i < 10; i++) {
+ const { live, offline } = doLiveAndOfflineCensus(g, dbg, {
+ breakdown: { by: "objectClass",
+ then: { by: "count"} }
+ });
+
+ equal(live.AllocationMarker.count, offline.AllocationMarker.count);
+ equal(live.AllocationMarker.bytes, offline.AllocationMarker.bytes);
+ equal(live.AllocationMarker.count, prevCount + 100);
+ equal(live.AllocationMarker.bytes, prevBytes + 100 * markerSize);
+
+ prevCount = live.AllocationMarker.count;
+ prevBytes = live.AllocationMarker.bytes;
+ }
+
+ // Second, test that the reported allocation stacks and counts and sizes at
+ // those allocation stacks match up.
+
+ const { live, offline } = doLiveAndOfflineCensus(g, dbg, {
+ breakdown: { by: "objectClass",
+ then: { by: "allocationStack"} }
+ });
+
+ equal(live.AllocationMarker.size, offline.AllocationMarker.size);
+ // One stack with the loop further above, and another stack featuring the call
+ // right above.
+ equal(live.AllocationMarker.size, 2);
+
+ // Note that because SavedFrame stacks reconstructed from an offline heap
+ // snapshot don't have the same principals as SavedFrame stacks captured from
+ // a live stack, the live and offline allocation stacks won't be identity
+ // equal, but should be structurally the same.
+
+ const liveEntries = [];
+ live.AllocationMarker.forEach((v, k) => {
+ dumpn("Allocation stack:");
+ k.toString().split(/\n/g).forEach(s => dumpn(s));
+
+ equal(k.functionDisplayName, "unsafeAtAnySpeed");
+ equal(k.line, 4);
+
+ liveEntries.push([k.toString(), v]);
+ });
+
+ const offlineEntries = [];
+ offline.AllocationMarker.forEach((v, k) => {
+ dumpn("Allocation stack:");
+ k.toString().split(/\n/g).forEach(s => dumpn(s));
+
+ equal(k.functionDisplayName, "unsafeAtAnySpeed");
+ equal(k.line, 4);
+
+ offlineEntries.push([k.toString(), v]);
+ });
+
+ const sortEntries = (a, b) => {
+ if (a[0] < b[0]) {
+ return -1;
+ } else if (a[0] > b[0]) {
+ return 1;
+ } else {
+ return 0;
+ }
+ };
+ liveEntries.sort(sortEntries);
+ offlineEntries.sort(sortEntries);
+
+ equal(liveEntries.length, live.AllocationMarker.size);
+ equal(liveEntries.length, offlineEntries.length);
+
+ for (let i = 0; i < liveEntries.length; i++) {
+ equal(liveEntries[i][0], offlineEntries[i][0]);
+ equal(liveEntries[i][1].count, offlineEntries[i][1].count);
+ equal(liveEntries[i][1].bytes, offlineEntries[i][1].bytes);
+ }
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_12.js b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_12.js
new file mode 100644
index 000000000..f10dd5b03
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_HeapSnapshot_takeCensus_12.js
@@ -0,0 +1,50 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that when we take a census and get a bucket list of ids that matched the
+// given category, that the returned ids are all in the snapshot and their
+// reported category.
+
+function run_test() {
+ const g = newGlobal();
+ const dbg = new Debugger(g);
+
+ const path = saveNewHeapSnapshot({ debugger: dbg });
+ const snapshot = readHeapSnapshot(path);
+
+ const bucket = { by: "bucket" };
+ const count = { by: "count", count: true, bytes: false };
+ const objectClassCount = { by: "objectClass", then: count, other: count };
+
+ const byClassName = snapshot.takeCensus({
+ breakdown: {
+ by: "objectClass",
+ then: bucket,
+ other: bucket,
+ }
+ });
+
+ const byClassNameCount = snapshot.takeCensus({
+ breakdown: objectClassCount
+ });
+
+ const keys = new Set(Object.keys(byClassName));
+ equal(keys.size, Object.keys(byClassNameCount).length,
+ "Should have the same number of keys.");
+ for (let k of Object.keys(byClassNameCount)) {
+ ok(keys.has(k), "Should not have any unexpected class names");
+ }
+
+ for (let key of Object.keys(byClassName)) {
+ equal(byClassNameCount[key].count, byClassName[key].length,
+ "Length of the bucket and count should be equal");
+
+ for (let id of byClassName[key]) {
+ const desc = snapshot.describeNode(objectClassCount, id);
+ equal(desc[key].count, 1,
+ "Describing the bucketed node confirms that it belongs to the category");
+ }
+ }
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_ReadHeapSnapshot.js b/dom/heapsnapshot/tests/unit/test_ReadHeapSnapshot.js
new file mode 100644
index 000000000..dde139ffd
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_ReadHeapSnapshot.js
@@ -0,0 +1,20 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can read core dumps into HeapSnapshot instances.
+
+if (typeof Debugger != "function") {
+ const { addDebuggerToGlobal } = Cu.import("resource://gre/modules/jsdebugger.jsm", {});
+ addDebuggerToGlobal(this);
+}
+
+function run_test() {
+ const filePath = ChromeUtils.saveHeapSnapshot({ globals: [this] });
+ ok(true, "Should be able to save a snapshot.");
+
+ const snapshot = ChromeUtils.readHeapSnapshot(filePath);
+ ok(snapshot, "Should be able to read a heap snapshot");
+ ok(snapshot instanceof HeapSnapshot, "Should be an instanceof HeapSnapshot");
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_ReadHeapSnapshot_with_allocations.js b/dom/heapsnapshot/tests/unit/test_ReadHeapSnapshot_with_allocations.js
new file mode 100644
index 000000000..d91f36f56
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_ReadHeapSnapshot_with_allocations.js
@@ -0,0 +1,36 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can save a core dump with allocation stacks and read it back
+// into a HeapSnapshot.
+
+if (typeof Debugger != "function") {
+ const { addDebuggerToGlobal } = Cu.import("resource://gre/modules/jsdebugger.jsm", {});
+ addDebuggerToGlobal(this);
+}
+
+function run_test() {
+ // Create a Debugger observing a debuggee's allocations.
+ const debuggee = new Cu.Sandbox(null);
+ const dbg = new Debugger(debuggee);
+ dbg.memory.trackingAllocationSites = true;
+
+ // Allocate some objects in the debuggee that will have their allocation
+ // stacks recorded by the Debugger.
+ debuggee.eval("this.objects = []");
+ for (let i = 0; i < 100; i++) {
+ debuggee.eval("this.objects.push({})");
+ }
+
+ // Now save a snapshot that will include the allocation stacks and read it
+ // back again.
+
+ const filePath = ChromeUtils.saveHeapSnapshot({ runtime: true });
+ ok(true, "Should be able to save a snapshot.");
+
+ const snapshot = ChromeUtils.readHeapSnapshot(filePath);
+ ok(snapshot, "Should be able to read a heap snapshot");
+ ok(snapshot instanceof HeapSnapshot, "Should be an instanceof HeapSnapshot");
+
+ do_test_finished();
+}
diff --git a/dom/heapsnapshot/tests/unit/test_ReadHeapSnapshot_worker.js b/dom/heapsnapshot/tests/unit/test_ReadHeapSnapshot_worker.js
new file mode 100644
index 000000000..76461b694
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_ReadHeapSnapshot_worker.js
@@ -0,0 +1,40 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can read core dumps into HeapSnapshot instances in a worker.
+
+add_task(function* () {
+ const worker = new ChromeWorker("resource://test/heap-snapshot-worker.js");
+ worker.postMessage({});
+
+ let assertionCount = 0;
+ worker.onmessage = e => {
+ if (e.data.type !== "assertion") {
+ return;
+ }
+
+ ok(e.data.passed, e.data.msg + "\n" + e.data.stack);
+ assertionCount++;
+ };
+
+ yield waitForDone(worker);
+
+ ok(assertionCount > 0);
+ worker.terminate();
+});
+
+function waitForDone(w) {
+ return new Promise((resolve, reject) => {
+ w.onerror = e => {
+ reject();
+ ok(false, "Error in worker: " + e);
+ };
+
+ w.addEventListener("message", function listener(e) {
+ if (e.data.type === "done") {
+ w.removeEventListener("message", listener, false);
+ resolve();
+ }
+ }, false);
+ });
+}
diff --git a/dom/heapsnapshot/tests/unit/test_SaveHeapSnapshot.js b/dom/heapsnapshot/tests/unit/test_SaveHeapSnapshot.js
new file mode 100644
index 000000000..affd8d1e4
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_SaveHeapSnapshot.js
@@ -0,0 +1,82 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the ChromeUtils interface.
+
+if (typeof Debugger != "function") {
+ const { addDebuggerToGlobal } = Cu.import("resource://gre/modules/jsdebugger.jsm", {});
+ addDebuggerToGlobal(this);
+}
+
+function run_test() {
+ ok(ChromeUtils, "Should be able to get the ChromeUtils interface");
+
+ testBadParameters();
+ testGoodParameters();
+
+ do_test_finished();
+}
+
+function testBadParameters() {
+ throws(() => ChromeUtils.saveHeapSnapshot(),
+ "Should throw if arguments aren't passed in.");
+
+ throws(() => ChromeUtils.saveHeapSnapshot(null),
+ "Should throw if boundaries isn't an object.");
+
+ throws(() => ChromeUtils.saveHeapSnapshot({}),
+ "Should throw if the boundaries object doesn't have any properties.");
+
+ throws(() => ChromeUtils.saveHeapSnapshot({ runtime: true,
+ globals: [this] }),
+ "Should throw if the boundaries object has more than one property.");
+
+ throws(() => ChromeUtils.saveHeapSnapshot({ debugger: {} }),
+ "Should throw if the debuggees object is not a Debugger object");
+
+ throws(() => ChromeUtils.saveHeapSnapshot({ globals: [{}] }),
+ "Should throw if the globals array contains non-global objects.");
+
+ throws(() => ChromeUtils.saveHeapSnapshot({ runtime: false }),
+ "Should throw if runtime is supplied and is not true.");
+
+ throws(() => ChromeUtils.saveHeapSnapshot({ globals: null }),
+ "Should throw if globals is not an object.");
+
+ throws(() => ChromeUtils.saveHeapSnapshot({ globals: {} }),
+ "Should throw if globals is not an array.");
+
+ throws(() => ChromeUtils.saveHeapSnapshot({ debugger: Debugger.prototype }),
+ "Should throw if debugger is the Debugger.prototype object.");
+
+ throws(() => ChromeUtils.saveHeapSnapshot({ get globals() { return [this]; } }),
+ "Should throw if boundaries property is a getter.");
+}
+
+const makeNewSandbox = () =>
+ Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")());
+
+function testGoodParameters() {
+ let sandbox = makeNewSandbox();
+ let dbg = new Debugger(sandbox);
+
+ ChromeUtils.saveHeapSnapshot({ debugger: dbg });
+ ok(true, "Should be able to save a snapshot for a debuggee global.");
+
+ dbg = new Debugger;
+ let sandboxes = Array(10).fill(null).map(makeNewSandbox);
+ sandboxes.forEach(sb => dbg.addDebuggee(sb));
+
+ ChromeUtils.saveHeapSnapshot({ debugger: dbg });
+ ok(true, "Should be able to save a snapshot for many debuggee globals.");
+
+ dbg = new Debugger;
+ ChromeUtils.saveHeapSnapshot({ debugger: dbg });
+ ok(true, "Should be able to save a snapshot with no debuggee globals.");
+
+ ChromeUtils.saveHeapSnapshot({ globals: [this] });
+ ok(true, "Should be able to save a snapshot for a specific global.");
+
+ ChromeUtils.saveHeapSnapshot({ runtime: true });
+ ok(true, "Should be able to save a snapshot of the full runtime.");
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census-tree-node-01.js b/dom/heapsnapshot/tests/unit/test_census-tree-node-01.js
new file mode 100644
index 000000000..16038c5c4
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census-tree-node-01.js
@@ -0,0 +1,76 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests CensusTreeNode with `internalType` breakdown.
+ */
+
+const BREAKDOWN = {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true }
+};
+
+const REPORT = {
+ "JSObject": {
+ "bytes": 100,
+ "count": 10,
+ },
+ "js::Shape": {
+ "bytes": 500,
+ "count": 50,
+ },
+ "JSString": {
+ "bytes": 10,
+ "count": 1,
+ },
+};
+
+const EXPECTED = {
+ name: null,
+ bytes: 0,
+ totalBytes: 610,
+ count: 0,
+ totalCount: 61,
+ children: [
+ {
+ name: "js::Shape",
+ bytes: 500,
+ totalBytes: 500,
+ count: 50,
+ totalCount: 50,
+ children: undefined,
+ id: 3,
+ parent: 1,
+ reportLeafIndex: 2,
+ },
+ {
+ name: "JSObject",
+ bytes: 100,
+ totalBytes: 100,
+ count: 10,
+ totalCount: 10,
+ children: undefined,
+ id: 2,
+ parent: 1,
+ reportLeafIndex: 1,
+ },
+ {
+ name: "JSString",
+ bytes: 10,
+ totalBytes: 10,
+ count: 1,
+ totalCount: 1,
+ children: undefined,
+ id: 4,
+ parent: 1,
+ reportLeafIndex: 3,
+ },
+ ],
+ id: 1,
+ parent: undefined,
+ reportLeafIndex: undefined,
+};
+
+function run_test() {
+ compareCensusViewData(BREAKDOWN, REPORT, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census-tree-node-02.js b/dom/heapsnapshot/tests/unit/test_census-tree-node-02.js
new file mode 100644
index 000000000..37d039954
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census-tree-node-02.js
@@ -0,0 +1,136 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests CensusTreeNode with `coarseType` breakdown.
+ */
+
+const countBreakdown = { by: "count", count: true, bytes: true };
+
+const BREAKDOWN = {
+ by: "coarseType",
+ objects: { by: "objectClass", then: countBreakdown },
+ strings: countBreakdown,
+ scripts: countBreakdown,
+ other: { by: "internalType", then: countBreakdown },
+};
+
+const REPORT = {
+ "objects": {
+ "Function": { bytes: 10, count: 1 },
+ "Array": { bytes: 20, count: 2 },
+ },
+ "strings": { bytes: 10, count: 1 },
+ "scripts": { bytes: 1, count: 1 },
+ "other": {
+ "js::Shape": { bytes: 30, count: 3 },
+ "js::Shape2": { bytes: 40, count: 4 }
+ },
+};
+
+const EXPECTED = {
+ name: null,
+ bytes: 0,
+ totalBytes: 111,
+ count: 0,
+ totalCount: 12,
+ children: [
+ {
+ name: "other",
+ count: 0,
+ totalCount: 7,
+ bytes: 0,
+ totalBytes: 70,
+ children: [
+ {
+ name: "js::Shape2",
+ bytes: 40,
+ totalBytes: 40,
+ count: 4,
+ totalCount: 4,
+ children: undefined,
+ id: 9,
+ parent: 7,
+ reportLeafIndex: 8,
+ },
+ {
+ name: "js::Shape",
+ bytes: 30,
+ totalBytes: 30,
+ count: 3,
+ totalCount: 3,
+ children: undefined,
+ id: 8,
+ parent: 7,
+ reportLeafIndex: 7,
+ },
+ ],
+ id: 7,
+ parent: 1,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: "objects",
+ count: 0,
+ totalCount: 3,
+ bytes: 0,
+ totalBytes: 30,
+ children: [
+ {
+ name: "Array",
+ bytes: 20,
+ totalBytes: 20,
+ count: 2,
+ totalCount: 2,
+ children: undefined,
+ id: 4,
+ parent: 2,
+ reportLeafIndex: 3,
+ },
+ {
+ name: "Function",
+ bytes: 10,
+ totalBytes: 10,
+ count: 1,
+ totalCount: 1,
+ children: undefined,
+ id: 3,
+ parent: 2,
+ reportLeafIndex: 2,
+ },
+ ],
+ id: 2,
+ parent: 1,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: "strings",
+ count: 1,
+ totalCount: 1,
+ bytes: 10,
+ totalBytes: 10,
+ children: undefined,
+ id: 6,
+ parent: 1,
+ reportLeafIndex: 5,
+ },
+ {
+ name: "scripts",
+ count: 1,
+ totalCount: 1,
+ bytes: 1,
+ totalBytes: 1,
+ children: undefined,
+ id: 5,
+ parent: 1,
+ reportLeafIndex: 4,
+ },
+ ],
+ id: 1,
+ parent: undefined,
+ reportLeafIndex: undefined,
+};
+
+function run_test() {
+ compareCensusViewData(BREAKDOWN, REPORT, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census-tree-node-03.js b/dom/heapsnapshot/tests/unit/test_census-tree-node-03.js
new file mode 100644
index 000000000..bdf932099
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census-tree-node-03.js
@@ -0,0 +1,96 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests CensusTreeNode with `objectClass` breakdown.
+ */
+
+const countBreakdown = { by: "count", count: true, bytes: true };
+
+const BREAKDOWN = {
+ by: "objectClass",
+ then: countBreakdown,
+ other: { by: "internalType", then: countBreakdown }
+};
+
+const REPORT = {
+ "Function": { bytes: 10, count: 10 },
+ "Array": { bytes: 100, count: 1 },
+ "other": {
+ "JIT::CODE::NOW!!!": { bytes: 20, count: 2 },
+ "JIT::CODE::LATER!!!": { bytes: 40, count: 4 }
+ }
+};
+
+const EXPECTED = {
+ name: null,
+ count: 0,
+ totalCount: 17,
+ bytes: 0,
+ totalBytes: 170,
+ children: [
+ {
+ name: "Array",
+ bytes: 100,
+ totalBytes: 100,
+ count: 1,
+ totalCount: 1,
+ children: undefined,
+ id: 3,
+ parent: 1,
+ reportLeafIndex: 2,
+ },
+ {
+ name: "other",
+ count: 0,
+ totalCount: 6,
+ bytes: 0,
+ totalBytes: 60,
+ children: [
+ {
+ name: "JIT::CODE::LATER!!!",
+ bytes: 40,
+ totalBytes: 40,
+ count: 4,
+ totalCount: 4,
+ children: undefined,
+ id: 6,
+ parent: 4,
+ reportLeafIndex: 5,
+ },
+ {
+ name: "JIT::CODE::NOW!!!",
+ bytes: 20,
+ totalBytes: 20,
+ count: 2,
+ totalCount: 2,
+ children: undefined,
+ id: 5,
+ parent: 4,
+ reportLeafIndex: 4,
+ },
+ ],
+ id: 4,
+ parent: 1,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: "Function",
+ bytes: 10,
+ totalBytes: 10,
+ count: 10,
+ totalCount: 10,
+ children: undefined,
+ id: 2,
+ parent: 1,
+ reportLeafIndex: 1,
+ },
+ ],
+ id: 1,
+ parent: undefined,
+ reportLeafIndex: undefined,
+};
+
+function run_test() {
+ compareCensusViewData(BREAKDOWN, REPORT, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census-tree-node-04.js b/dom/heapsnapshot/tests/unit/test_census-tree-node-04.js
new file mode 100644
index 000000000..cc0c3bac0
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census-tree-node-04.js
@@ -0,0 +1,159 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests CensusTreeNode with `allocationStack` breakdown.
+ */
+
+function run_test() {
+ const countBreakdown = { by: "count", count: true, bytes: true };
+
+ const BREAKDOWN = {
+ by: "allocationStack",
+ then: countBreakdown,
+ noStack: countBreakdown,
+ };
+
+ let stack1, stack2, stack3, stack4, stack5;
+
+ (function a() {
+ (function b() {
+ (function c() {
+ stack1 = saveStack(3);
+ }());
+ (function d() {
+ stack2 = saveStack(3);
+ stack3 = saveStack(3);
+ }());
+ stack4 = saveStack(2);
+ }());
+ }());
+
+ stack5 = saveStack(1);
+
+ const REPORT = new Map([
+ [stack1, { bytes: 10, count: 1 }],
+ [stack2, { bytes: 20, count: 2 }],
+ [stack3, { bytes: 30, count: 3 }],
+ [stack4, { bytes: 40, count: 4 }],
+ [stack5, { bytes: 50, count: 5 }],
+ ["noStack", { bytes: 60, count: 6 }],
+ ]);
+
+ const EXPECTED = {
+ name: null,
+ bytes: 0,
+ totalBytes: 210,
+ count: 0,
+ totalCount: 21,
+ children: [
+ {
+ name: stack4.parent,
+ bytes: 0,
+ totalBytes: 100,
+ count: 0,
+ totalCount: 10,
+ children: [
+ {
+ name: stack3.parent,
+ bytes: 0,
+ totalBytes: 50,
+ count: 0,
+ totalCount: 5,
+ children: [
+ {
+ name: stack3,
+ bytes: 30,
+ totalBytes: 30,
+ count: 3,
+ totalCount: 3,
+ children: undefined,
+ id: 7,
+ parent: 5,
+ reportLeafIndex: 3,
+ },
+ {
+ name: stack2,
+ bytes: 20,
+ totalBytes: 20,
+ count: 2,
+ totalCount: 2,
+ children: undefined,
+ id: 6,
+ parent: 5,
+ reportLeafIndex: 2,
+ }
+ ],
+ id: 5,
+ parent: 2,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: stack4,
+ bytes: 40,
+ totalBytes: 40,
+ count: 4,
+ totalCount: 4,
+ children: undefined,
+ id: 8,
+ parent: 2,
+ reportLeafIndex: 4,
+ },
+ {
+ name: stack1.parent,
+ bytes: 0,
+ totalBytes: 10,
+ count: 0,
+ totalCount: 1,
+ children: [
+ {
+ name: stack1,
+ bytes: 10,
+ totalBytes: 10,
+ count: 1,
+ totalCount: 1,
+ children: undefined,
+ id: 4,
+ parent: 3,
+ reportLeafIndex: 1,
+ },
+ ],
+ id: 3,
+ parent: 2,
+ reportLeafIndex: undefined,
+ },
+ ],
+ id: 2,
+ parent: 1,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: "noStack",
+ bytes: 60,
+ totalBytes: 60,
+ count: 6,
+ totalCount: 6,
+ children: undefined,
+ id: 10,
+ parent: 1,
+ reportLeafIndex: 6,
+ },
+ {
+ name: stack5,
+ bytes: 50,
+ totalBytes: 50,
+ count: 5,
+ totalCount: 5,
+ children: undefined,
+ id: 9,
+ parent: 1,
+ reportLeafIndex: 5
+ },
+ ],
+ id: 1,
+ parent: undefined,
+ reportLeafIndex: undefined,
+ };
+
+ compareCensusViewData(BREAKDOWN, REPORT, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census-tree-node-05.js b/dom/heapsnapshot/tests/unit/test_census-tree-node-05.js
new file mode 100644
index 000000000..20fb76bd2
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census-tree-node-05.js
@@ -0,0 +1,145 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests CensusTreeNode with `allocationStack` => `objectClass` breakdown.
+ */
+
+function run_test() {
+ const countBreakdown = { by: "count", count: true, bytes: true };
+
+ const BREAKDOWN = {
+ by: "allocationStack",
+ then: {
+ by: "objectClass",
+ then: countBreakdown,
+ other: countBreakdown
+ },
+ noStack: countBreakdown,
+ };
+
+ let stack;
+
+ (function a() {
+ (function b() {
+ (function c() {
+ stack = saveStack(3);
+ }());
+ }());
+ }());
+
+ const REPORT = new Map([
+ [stack, { Foo: { bytes: 10, count: 1 },
+ Bar: { bytes: 20, count: 2 },
+ Baz: { bytes: 30, count: 3 },
+ other: { bytes: 40, count: 4 }
+ }],
+ ["noStack", { bytes: 50, count: 5 }],
+ ]);
+
+ const EXPECTED = {
+ name: null,
+ bytes: 0,
+ totalBytes: 150,
+ count: 0,
+ totalCount: 15,
+ children: [
+ {
+ name: stack.parent.parent,
+ bytes: 0,
+ totalBytes: 100,
+ count: 0,
+ totalCount: 10,
+ children: [
+ {
+ name: stack.parent,
+ bytes: 0,
+ totalBytes: 100,
+ count: 0,
+ totalCount: 10,
+ children: [
+ {
+ name: stack,
+ bytes: 0,
+ totalBytes: 100,
+ count: 0,
+ totalCount: 10,
+ children: [
+ {
+ name: "other",
+ bytes: 40,
+ totalBytes: 40,
+ count: 4,
+ totalCount: 4,
+ children: undefined,
+ id: 8,
+ parent: 4,
+ reportLeafIndex: 5,
+ },
+ {
+ name: "Baz",
+ bytes: 30,
+ totalBytes: 30,
+ count: 3,
+ totalCount: 3,
+ children: undefined,
+ id: 7,
+ parent: 4,
+ reportLeafIndex: 4,
+ },
+ {
+ name: "Bar",
+ bytes: 20,
+ totalBytes: 20,
+ count: 2,
+ totalCount: 2,
+ children: undefined,
+ id: 6,
+ parent: 4,
+ reportLeafIndex: 3,
+ },
+ {
+ name: "Foo",
+ bytes: 10,
+ totalBytes: 10,
+ count: 1,
+ totalCount: 1,
+ children: undefined,
+ id: 5,
+ parent: 4,
+ reportLeafIndex: 2,
+ },
+ ],
+ id: 4,
+ parent: 3,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 3,
+ parent: 2,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 2,
+ parent: 1,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: "noStack",
+ bytes: 50,
+ totalBytes: 50,
+ count: 5,
+ totalCount: 5,
+ children: undefined,
+ id: 9,
+ parent: 1,
+ reportLeafIndex: 6,
+ },
+ ],
+ id: 1,
+ parent: undefined,
+ reportLeafIndex: undefined,
+ };
+
+ compareCensusViewData(BREAKDOWN, REPORT, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census-tree-node-06.js b/dom/heapsnapshot/tests/unit/test_census-tree-node-06.js
new file mode 100644
index 000000000..eb1801207
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census-tree-node-06.js
@@ -0,0 +1,200 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test inverting CensusTreeNode with a by alloaction stack breakdown.
+ */
+
+function run_test() {
+ const BREAKDOWN = {
+ by: "allocationStack",
+ then: { by: "count", count: true, bytes: true },
+ noStack: { by: "count", count: true, bytes: true },
+ };
+
+ let stack1, stack2, stack3, stack4;
+
+ function a(n) {
+ return b(n);
+ }
+ function b(n) {
+ return c(n);
+ }
+ function c(n) {
+ return saveStack(n);
+ }
+ function d(n) {
+ return b(n);
+ }
+ function e(n) {
+ return c(n);
+ }
+
+ const abc_Stack = a(3);
+ const bc_Stack = b(2);
+ const c_Stack = c(1);
+ const dbc_Stack = d(3);
+ const ec_Stack = e(2);
+
+ const REPORT = new Map([
+ [abc_Stack, { bytes: 10, count: 1 }],
+ [ bc_Stack, { bytes: 10, count: 1 }],
+ [ c_Stack, { bytes: 10, count: 1 }],
+ [dbc_Stack, { bytes: 10, count: 1 }],
+ [ ec_Stack, { bytes: 10, count: 1 }],
+ ["noStack", { bytes: 50, count: 5 }],
+ ]);
+
+ const EXPECTED = {
+ name: null,
+ bytes: 0,
+ totalBytes: 100,
+ count: 0,
+ totalCount: 10,
+ children: [
+ {
+ name: "noStack",
+ bytes: 50,
+ totalBytes: 50,
+ count: 5,
+ totalCount: 5,
+ children: [
+ {
+ name: null,
+ bytes: 0,
+ totalBytes: 100,
+ count: 0,
+ totalCount: 10,
+ children: undefined,
+ id: 16,
+ parent: 15,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 15,
+ parent: 14,
+ reportLeafIndex: 6,
+ },
+ {
+ name: abc_Stack,
+ bytes: 50,
+ totalBytes: 10,
+ count: 5,
+ totalCount: 1,
+ children: [
+ {
+ name: null,
+ bytes: 0,
+ totalBytes: 100,
+ count: 0,
+ totalCount: 10,
+ children: undefined,
+ id: 18,
+ parent: 17,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: abc_Stack.parent,
+ bytes: 0,
+ totalBytes: 10,
+ count: 0,
+ totalCount: 1,
+ children: [
+ {
+ name: null,
+ bytes: 0,
+ totalBytes: 100,
+ count: 0,
+ totalCount: 10,
+ children: undefined,
+ id: 22,
+ parent: 19,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: abc_Stack.parent.parent,
+ bytes: 0,
+ totalBytes: 10,
+ count: 0,
+ totalCount: 1,
+ children: [
+ {
+ name: null,
+ bytes: 0,
+ totalBytes: 100,
+ count: 0,
+ totalCount: 10,
+ children: undefined,
+ id: 21,
+ parent: 20,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 20,
+ parent: 19,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: dbc_Stack.parent.parent,
+ bytes: 0,
+ totalBytes: 10,
+ count: 0,
+ totalCount: 1,
+ children: [
+ {
+ name: null,
+ bytes: 0,
+ totalBytes: 100,
+ count: 0,
+ totalCount: 10,
+ children: undefined,
+ id: 24,
+ parent: 23,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 23,
+ parent: 19,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 19,
+ parent: 17,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: ec_Stack.parent,
+ bytes: 0,
+ totalBytes: 10,
+ count: 0,
+ totalCount: 1,
+ children: [
+ {
+ name: null,
+ bytes: 0,
+ totalBytes: 100,
+ count: 0,
+ totalCount: 10,
+ children: undefined,
+ id: 26,
+ parent: 25,
+ reportLeafIndex: undefined,
+ },
+ ],
+ id: 25,
+ parent: 17,
+ reportLeafIndex: undefined,
+ },
+ ],
+ id: 17,
+ parent: 14,
+ reportLeafIndex: new Set([1, 2, 3, 4, 5]),
+ }
+ ],
+ id: 14,
+ parent: undefined,
+ reportLeafIndex: undefined,
+ };
+
+ compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { invert: true });
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census-tree-node-07.js b/dom/heapsnapshot/tests/unit/test_census-tree-node-07.js
new file mode 100644
index 000000000..6bc085257
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census-tree-node-07.js
@@ -0,0 +1,200 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test inverting CensusTreeNode with a non-allocation stack breakdown.
+ */
+
+function run_test() {
+ const BREAKDOWN = {
+ by: "coarseType",
+ objects: {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+ },
+ scripts: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ strings: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ other:{
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ };
+
+ const REPORT = {
+ objects: {
+ Array: { bytes: 50, count: 5 },
+ other: { bytes: 0, count: 0 },
+ },
+ scripts: {
+ "js::jit::JitScript": { bytes: 30, count: 3 },
+ },
+ strings: {
+ JSAtom: { bytes: 60, count: 6 },
+ },
+ other: {
+ "js::Shape": { bytes: 80, count: 8 },
+ }
+ };
+
+ const EXPECTED = {
+ name: null,
+ bytes: 0,
+ totalBytes: 220,
+ count: 0,
+ totalCount: 22,
+ children: [
+ {
+ name: "js::Shape",
+ bytes: 80,
+ totalBytes: 80,
+ count: 8,
+ totalCount: 8,
+ children: [
+ {
+ name: "other",
+ bytes: 0,
+ totalBytes: 80,
+ count: 0,
+ totalCount: 8,
+ children: [
+ {
+ name: null,
+ bytes: 0,
+ totalBytes: 220,
+ count: 0,
+ totalCount: 22,
+ children: undefined,
+ id: 14,
+ parent: 13,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 13,
+ parent: 12,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 12,
+ parent: 11,
+ reportLeafIndex: 9,
+ },
+ {
+ name: "JSAtom",
+ bytes: 60,
+ totalBytes: 60,
+ count: 6,
+ totalCount: 6,
+ children: [
+ {
+ name: "strings",
+ bytes: 0,
+ totalBytes: 60,
+ count: 0,
+ totalCount: 6,
+ children: [
+ {
+ name: null,
+ bytes: 0,
+ totalBytes: 220,
+ count: 0,
+ totalCount: 22,
+ children: undefined,
+ id: 17,
+ parent: 16,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 16,
+ parent: 15,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 15,
+ parent: 11,
+ reportLeafIndex: 7,
+ },
+ {
+ name: "Array",
+ bytes: 50,
+ totalBytes: 50,
+ count: 5,
+ totalCount: 5,
+ children: [
+ {
+ name: "objects",
+ bytes: 0,
+ totalBytes: 50,
+ count: 0,
+ totalCount: 5,
+ children: [
+ {
+ name: null,
+ bytes: 0,
+ totalBytes: 220,
+ count: 0,
+ totalCount: 22,
+ children: undefined,
+ id: 20,
+ parent: 19,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 19,
+ parent: 18,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 18,
+ parent: 11,
+ reportLeafIndex: 2,
+ },
+ {
+ name: "js::jit::JitScript",
+ bytes: 30,
+ totalBytes: 30,
+ count: 3,
+ totalCount: 3,
+ children: [
+ {
+ name: "scripts",
+ bytes: 0,
+ totalBytes: 30,
+ count: 0,
+ totalCount: 3,
+ children: [
+ {
+ name: null,
+ bytes: 0,
+ totalBytes: 220,
+ count: 0,
+ totalCount: 22,
+ children: undefined,
+ id: 23,
+ parent: 22,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 22,
+ parent: 21,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 21,
+ parent: 11,
+ reportLeafIndex: 5,
+ },
+ ],
+ id: 11,
+ parent: undefined,
+ reportLeafIndex: undefined,
+ };
+
+ compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { invert: true });
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census-tree-node-08.js b/dom/heapsnapshot/tests/unit/test_census-tree-node-08.js
new file mode 100644
index 000000000..1c686c810
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census-tree-node-08.js
@@ -0,0 +1,142 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test inverting CensusTreeNode with a non-allocation stack breakdown.
+ */
+
+function run_test() {
+ const BREAKDOWN = {
+ by: "filename",
+ then: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true }
+ },
+ noFilename: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true }
+ },
+ };
+
+ const REPORT = {
+ "http://example.com/app.js": {
+ JSScript: { count: 10, bytes: 100 }
+ },
+ "http://example.com/ads.js": {
+ "js::LazyScript": { count: 20, bytes: 200 }
+ },
+ "http://example.com/trackers.js": {
+ JSScript: { count: 30, bytes: 300 }
+ },
+ noFilename: {
+ "js::jit::JitCode": { count: 40, bytes: 400 }
+ }
+ };
+
+ const EXPECTED = {
+ name: null,
+ bytes: 0,
+ totalBytes: 1000,
+ count: 0,
+ totalCount: 100,
+ children: [
+ {
+ name: "noFilename",
+ bytes: 0,
+ totalBytes: 400,
+ count: 0,
+ totalCount: 40,
+ children: [
+ {
+ name: "js::jit::JitCode",
+ bytes: 400,
+ totalBytes: 400,
+ count: 40,
+ totalCount: 40,
+ children: undefined,
+ id: 9,
+ parent: 8,
+ reportLeafIndex: 8,
+ }
+ ],
+ id: 8,
+ parent: 1,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: "http://example.com/trackers.js",
+ bytes: 0,
+ totalBytes: 300,
+ count: 0,
+ totalCount: 30,
+ children: [
+ {
+ name: "JSScript",
+ bytes: 300,
+ totalBytes: 300,
+ count: 30,
+ totalCount: 30,
+ children: undefined,
+ id: 7,
+ parent: 6,
+ reportLeafIndex: 6,
+ }
+ ],
+ id: 6,
+ parent: 1,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: "http://example.com/ads.js",
+ bytes: 0,
+ totalBytes: 200,
+ count: 0,
+ totalCount: 20,
+ children: [
+ {
+ name: "js::LazyScript",
+ bytes: 200,
+ totalBytes: 200,
+ count: 20,
+ totalCount: 20,
+ children: undefined,
+ id: 5,
+ parent: 4,
+ reportLeafIndex: 4,
+ }
+ ],
+ id: 4,
+ parent: 1,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: "http://example.com/app.js",
+ bytes: 0,
+ totalBytes: 100,
+ count: 0,
+ totalCount: 10,
+ children: [
+ {
+ name: "JSScript",
+ bytes: 100,
+ totalBytes: 100,
+ count: 10,
+ totalCount: 10,
+ children: undefined,
+ id: 3,
+ parent: 2,
+ reportLeafIndex: 2,
+ }
+ ],
+ id: 2,
+ parent: 1,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 1,
+ parent: undefined,
+ reportLeafIndex: undefined,
+ };
+
+ compareCensusViewData(BREAKDOWN, REPORT, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census-tree-node-09.js b/dom/heapsnapshot/tests/unit/test_census-tree-node-09.js
new file mode 100644
index 000000000..3efed04b0
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census-tree-node-09.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/**
+ * Test that repeatedly converting the same census report to a CensusTreeNode
+ * tree results in the same CensusTreeNode tree.
+ */
+
+function run_test() {
+ const BREAKDOWN = {
+ by: "filename",
+ then: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true }
+ },
+ noFilename: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true }
+ },
+ };
+
+ const REPORT = {
+ "http://example.com/app.js": {
+ JSScript: { count: 10, bytes: 100 }
+ },
+ "http://example.com/ads.js": {
+ "js::LazyScript": { count: 20, bytes: 200 }
+ },
+ "http://example.com/trackers.js": {
+ JSScript: { count: 30, bytes: 300 }
+ },
+ noFilename: {
+ "js::jit::JitCode": { count: 40, bytes: 400 }
+ }
+ };
+
+ const first = censusReportToCensusTreeNode(BREAKDOWN, REPORT);
+ const second = censusReportToCensusTreeNode(BREAKDOWN, REPORT);
+ const third = censusReportToCensusTreeNode(BREAKDOWN, REPORT);
+
+ assertStructurallyEquivalent(first, second);
+ assertStructurallyEquivalent(second, third);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census-tree-node-10.js b/dom/heapsnapshot/tests/unit/test_census-tree-node-10.js
new file mode 100644
index 000000000..b7798f23f
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census-tree-node-10.js
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/**
+ * Test when multiple leaves in the census report map to the same node in an
+ * inverted CensusReportTree.
+ */
+
+function run_test() {
+ const BREAKDOWN = {
+ by: "coarseType",
+ objects: {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: true },
+ },
+ other: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ strings: { by: "count", count: true, bytes: true },
+ scripts: { by: "count", count: true, bytes: true },
+ };
+
+ const REPORT = {
+ objects: {
+ Array: { count: 1, bytes: 10 },
+ },
+ other: {
+ Array: { count: 1, bytes: 10 },
+ },
+ strings: { count: 0, bytes: 0 },
+ scripts: { count: 0, bytes: 0 },
+ };
+
+ const node = censusReportToCensusTreeNode(BREAKDOWN, REPORT, { invert: true });
+
+ equal(node.children[0].name, "Array");
+ equal(node.children[0].reportLeafIndex.size, 2);
+ dumpn(`node.children[0].reportLeafIndex = ${[...node.children[0].reportLeafIndex]}`);
+ ok(node.children[0].reportLeafIndex.has(2));
+ ok(node.children[0].reportLeafIndex.has(6));
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census_diff_01.js b/dom/heapsnapshot/tests/unit/test_census_diff_01.js
new file mode 100644
index 000000000..75977bccb
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census_diff_01.js
@@ -0,0 +1,74 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test diffing census reports of breakdown by "internalType".
+
+const BREAKDOWN = {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true }
+};
+
+const REPORT1 = {
+ "JSObject": {
+ "count": 10,
+ "bytes": 100,
+ },
+ "js::Shape": {
+ "count": 50,
+ "bytes": 500,
+ },
+ "JSString": {
+ "count": 0,
+ "bytes": 0,
+ },
+ "js::LazyScript": {
+ "count": 1,
+ "bytes": 10,
+ },
+};
+
+const REPORT2 = {
+ "JSObject": {
+ "count": 11,
+ "bytes": 110,
+ },
+ "js::Shape": {
+ "count": 51,
+ "bytes": 510,
+ },
+ "JSString": {
+ "count": 1,
+ "bytes": 1,
+ },
+ "js::BaseShape": {
+ "count": 1,
+ "bytes": 42,
+ },
+};
+
+const EXPECTED = {
+ "JSObject": {
+ "count": 1,
+ "bytes": 10,
+ },
+ "js::Shape": {
+ "count": 1,
+ "bytes": 10,
+ },
+ "JSString": {
+ "count": 1,
+ "bytes": 1,
+ },
+ "js::LazyScript": {
+ "count": -1,
+ "bytes": -10,
+ },
+ "js::BaseShape": {
+ "count": 1,
+ "bytes": 42,
+ },
+};
+
+function run_test() {
+ assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census_diff_02.js b/dom/heapsnapshot/tests/unit/test_census_diff_02.js
new file mode 100644
index 000000000..169e3f036
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census_diff_02.js
@@ -0,0 +1,25 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test diffing census reports of breakdown by "count".
+
+const BREAKDOWN = { by: "count", count: true, bytes: true };
+
+const REPORT1 = {
+ "count": 10,
+ "bytes": 100,
+};
+
+const REPORT2 = {
+ "count": 11,
+ "bytes": 110,
+};
+
+const EXPECTED = {
+ "count": 1,
+ "bytes": 10,
+};
+
+function run_test() {
+ assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census_diff_03.js b/dom/heapsnapshot/tests/unit/test_census_diff_03.js
new file mode 100644
index 000000000..6dbca3e40
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census_diff_03.js
@@ -0,0 +1,73 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test diffing census reports of breakdown by "coarseType".
+
+const BREAKDOWN = {
+ by: "coarseType",
+ objects: { by: "count", count: true, bytes: true },
+ scripts: { by: "count", count: true, bytes: true },
+ strings: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+};
+
+const REPORT1 = {
+ objects: {
+ count: 1,
+ bytes: 10,
+ },
+ scripts: {
+ count: 1,
+ bytes: 10,
+ },
+ strings: {
+ count: 1,
+ bytes: 10,
+ },
+ other: {
+ count: 3,
+ bytes: 30,
+ },
+};
+
+const REPORT2 = {
+ objects: {
+ count: 1,
+ bytes: 10,
+ },
+ scripts: {
+ count: 0,
+ bytes: 0,
+ },
+ strings: {
+ count: 2,
+ bytes: 20,
+ },
+ other: {
+ count: 4,
+ bytes: 40,
+ },
+};
+
+const EXPECTED = {
+ objects: {
+ count: 0,
+ bytes: 0,
+ },
+ scripts: {
+ count: -1,
+ bytes: -10,
+ },
+ strings: {
+ count: 1,
+ bytes: 10,
+ },
+ other: {
+ count: 1,
+ bytes: 10,
+ },
+};
+
+function run_test() {
+ assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census_diff_04.js b/dom/heapsnapshot/tests/unit/test_census_diff_04.js
new file mode 100644
index 000000000..a10097945
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census_diff_04.js
@@ -0,0 +1,63 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test diffing census reports of breakdown by "objectClass".
+
+const BREAKDOWN = {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+};
+
+const REPORT1 = {
+ "Array": {
+ count: 1,
+ bytes: 100,
+ },
+ "Function": {
+ count: 10,
+ bytes: 10,
+ },
+ "other": {
+ count: 10,
+ bytes: 100,
+ }
+};
+
+const REPORT2 = {
+ "Object": {
+ count: 1,
+ bytes: 100,
+ },
+ "Function": {
+ count: 20,
+ bytes: 20,
+ },
+ "other": {
+ count: 10,
+ bytes: 100,
+ }
+};
+
+const EXPECTED = {
+ "Array": {
+ count: -1,
+ bytes: -100,
+ },
+ "Function": {
+ count: 10,
+ bytes: 10,
+ },
+ "other": {
+ count: 0,
+ bytes: 0,
+ },
+ "Object": {
+ count: 1,
+ bytes: 100,
+ },
+};
+
+function run_test() {
+ assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census_diff_05.js b/dom/heapsnapshot/tests/unit/test_census_diff_05.js
new file mode 100644
index 000000000..b6d99f823
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census_diff_05.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test diffing census reports of breakdown by "allocationStack".
+
+const BREAKDOWN = {
+ by: "allocationStack",
+ then: { by: "count", count: true, bytes: true },
+ noStack: { by: "count", count: true, bytes: true },
+};
+
+const stack1 = saveStack();
+const stack2 = saveStack();
+const stack3 = saveStack();
+
+const REPORT1 = new Map([
+ [stack1, { "count": 10, "bytes": 100 }],
+ [stack2, { "count": 1, "bytes": 10 }],
+]);
+
+const REPORT2 = new Map([
+ [stack2, { "count": 10, "bytes": 100 }],
+ [stack3, { "count": 1, "bytes": 10 }],
+]);
+
+const EXPECTED = new Map([
+ [stack1, { "count": -10, "bytes": -100 }],
+ [stack2, { "count": 9, "bytes": 90 }],
+ [stack3, { "count": 1, "bytes": 10 }],
+]);
+
+function run_test() {
+ assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census_diff_06.js b/dom/heapsnapshot/tests/unit/test_census_diff_06.js
new file mode 100644
index 000000000..430ff8c9c
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census_diff_06.js
@@ -0,0 +1,137 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test diffing census reports of a "complex" and "realistic" breakdown.
+
+const BREAKDOWN = {
+ by: "coarseType",
+ objects: {
+ by: "allocationStack",
+ then: {
+ by: "objectClass",
+ then: { by: "count", count: false, bytes: true },
+ other: { by: "count", count: false, bytes: true }
+ },
+ noStack: {
+ by: "objectClass",
+ then: { by: "count", count: false, bytes: true },
+ other: { by: "count", count: false, bytes: true }
+ }
+ },
+ strings: {
+ by: "internalType",
+ then: { by: "count", count: false, bytes: true }
+ },
+ scripts: {
+ by: "internalType",
+ then: { by: "count", count: false, bytes: true }
+ },
+ other: {
+ by: "internalType",
+ then: { by: "count", count: false, bytes: true }
+ },
+};
+
+const stack1 = saveStack();
+const stack2 = saveStack();
+const stack3 = saveStack();
+
+const REPORT1 = {
+ objects: new Map([
+ [stack1, { Function: { bytes: 1 },
+ Object: { bytes: 2 },
+ other: { bytes: 0 },
+ }],
+ [stack2, { Array: { bytes: 3 },
+ Date: { bytes: 4 },
+ other: { bytes: 0 },
+ }],
+ ["noStack", { Object: { bytes: 3 }}],
+ ]),
+ strings: {
+ JSAtom: { bytes: 10 },
+ JSLinearString: { bytes: 5 },
+ },
+ scripts: {
+ JSScript: { bytes: 1 },
+ "js::jit::JitCode": { bytes: 2 },
+ },
+ other: {
+ "mozilla::dom::Thing": { bytes: 1 },
+ }
+};
+
+const REPORT2 = {
+ objects: new Map([
+ [stack2, { Array: { bytes: 1 },
+ Date: { bytes: 2 },
+ other: { bytes: 3 },
+ }],
+ [stack3, { Function: { bytes: 1 },
+ Object: { bytes: 2 },
+ other: { bytes: 0 },
+ }],
+ ["noStack", { Object: { bytes: 3 }}],
+ ]),
+ strings: {
+ JSAtom: { bytes: 5 },
+ JSLinearString: { bytes: 10 },
+ },
+ scripts: {
+ JSScript: { bytes: 2 },
+ "js::LazyScript": { bytes: 42 },
+ "js::jit::JitCode": { bytes: 1 },
+ },
+ other: {
+ "mozilla::dom::OtherThing": { bytes: 1 },
+ }
+};
+
+const EXPECTED = {
+ "objects": new Map([
+ [stack1, { Function: { bytes: -1 },
+ Object: { bytes: -2 },
+ other: { bytes: 0 },
+ }],
+ [stack2, { Array: { bytes: -2 },
+ Date: { bytes: -2 },
+ other: { bytes: 3 },
+ }],
+ [stack3, { Function: { bytes: 1 },
+ Object: { bytes: 2 },
+ other: { bytes: 0 },
+ }],
+ ["noStack", { Object: { bytes: 0 }}],
+ ]),
+ "scripts": {
+ "JSScript": {
+ "bytes": 1
+ },
+ "js::jit::JitCode": {
+ "bytes": -1
+ },
+ "js::LazyScript": {
+ "bytes": 42
+ }
+ },
+ "strings": {
+ "JSAtom": {
+ "bytes": -5
+ },
+ "JSLinearString": {
+ "bytes": 5
+ }
+ },
+ "other": {
+ "mozilla::dom::Thing": {
+ "bytes": -1
+ },
+ "mozilla::dom::OtherThing": {
+ "bytes": 1
+ }
+ }
+};
+
+function run_test() {
+ assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census_filtering_01.js b/dom/heapsnapshot/tests/unit/test_census_filtering_01.js
new file mode 100644
index 000000000..57724d7c1
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census_filtering_01.js
@@ -0,0 +1,105 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test filtering basic CensusTreeNode trees.
+
+function run_test() {
+ const BREAKDOWN = {
+ by: "coarseType",
+ objects: {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+ },
+ scripts: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ strings: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ other:{
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ };
+
+ const REPORT = {
+ objects: {
+ Array: { bytes: 50, count: 5 },
+ UInt8Array: { bytes: 80, count: 8 },
+ Int32Array: { bytes: 320, count: 32 },
+ other: { bytes: 0, count: 0 },
+ },
+ scripts: {
+ "js::jit::JitScript": { bytes: 30, count: 3 },
+ },
+ strings: {
+ JSAtom: { bytes: 60, count: 6 },
+ },
+ other: {
+ "js::Shape": { bytes: 80, count: 8 },
+ }
+ };
+
+ const EXPECTED = {
+ name: null,
+ bytes: 0,
+ totalBytes: 620,
+ count: 0,
+ totalCount: 62,
+ children: [
+ {
+ name: "objects",
+ bytes: 0,
+ totalBytes: 450,
+ count: 0,
+ totalCount: 45,
+ children: [
+ {
+ name: "Int32Array",
+ bytes: 320,
+ totalBytes: 320,
+ count: 32,
+ totalCount: 32,
+ children: undefined,
+ id: 15,
+ parent: 14,
+ reportLeafIndex: 4,
+ },
+ {
+ name: "UInt8Array",
+ bytes: 80,
+ totalBytes: 80,
+ count: 8,
+ totalCount: 8,
+ children: undefined,
+ id: 16,
+ parent: 14,
+ reportLeafIndex: 3,
+ },
+ {
+ name: "Array",
+ bytes: 50,
+ totalBytes: 50,
+ count: 5,
+ totalCount: 5,
+ children: undefined,
+ id: 17,
+ parent: 14,
+ reportLeafIndex: 2,
+ }
+ ],
+ id: 14,
+ parent: 13,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 13,
+ parent: undefined,
+ reportLeafIndex: undefined,
+ };
+
+ compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { filter: "Array" });
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census_filtering_02.js b/dom/heapsnapshot/tests/unit/test_census_filtering_02.js
new file mode 100644
index 000000000..0a57ce66d
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census_filtering_02.js
@@ -0,0 +1,124 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test filtering CensusTreeNode trees with an `allocationStack` breakdown.
+
+function run_test() {
+ const countBreakdown = { by: "count", count: true, bytes: true };
+
+ const BREAKDOWN = {
+ by: "allocationStack",
+ then: countBreakdown,
+ noStack: countBreakdown,
+ };
+
+ let stack1, stack2, stack3, stack4, stack5;
+
+ (function foo() {
+ (function bar() {
+ (function baz() {
+ stack1 = saveStack(3);
+ }());
+ (function quux() {
+ stack2 = saveStack(3);
+ stack3 = saveStack(3);
+ }());
+ }());
+ stack4 = saveStack(2);
+ }());
+
+ stack5 = saveStack(1);
+
+ const REPORT = new Map([
+ [stack1, { bytes: 10, count: 1 }],
+ [stack2, { bytes: 20, count: 2 }],
+ [stack3, { bytes: 30, count: 3 }],
+ [stack4, { bytes: 40, count: 4 }],
+ [stack5, { bytes: 50, count: 5 }],
+ ["noStack", { bytes: 60, count: 6 }],
+ ]);
+
+ const EXPECTED = {
+ name: null,
+ bytes: 0,
+ totalBytes: 210,
+ count: 0,
+ totalCount: 21,
+ children: [
+ {
+ name: stack1.parent.parent,
+ bytes: 0,
+ totalBytes: 60,
+ count: 0,
+ totalCount: 6,
+ children: [
+ {
+ name: stack2.parent,
+ bytes: 0,
+ totalBytes: 50,
+ count: 0,
+ totalCount: 5,
+ children: [
+ {
+ name: stack3,
+ bytes: 30,
+ totalBytes: 30,
+ count: 3,
+ totalCount: 3,
+ children: undefined,
+ id: 15,
+ parent: 14,
+ reportLeafIndex: 3,
+ },
+ {
+ name: stack2,
+ bytes: 20,
+ totalBytes: 20,
+ count: 2,
+ totalCount: 2,
+ children: undefined,
+ id: 16,
+ parent: 14,
+ reportLeafIndex: 2,
+ }
+ ],
+ id: 14,
+ parent: 13,
+ reportLeafIndex: undefined,
+ },
+ {
+ name: stack1.parent,
+ bytes: 0,
+ totalBytes: 10,
+ count: 0,
+ totalCount: 1,
+ children: [
+ {
+ name: stack1,
+ bytes: 10,
+ totalBytes: 10,
+ count: 1,
+ totalCount: 1,
+ children: undefined,
+ id: 18,
+ parent: 17,
+ reportLeafIndex: 1,
+ }
+ ],
+ id: 17,
+ parent: 13,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 13,
+ parent: 12,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 12,
+ parent: undefined,
+ reportLeafIndex: undefined,
+ };
+
+ compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { filter: "bar" });
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census_filtering_03.js b/dom/heapsnapshot/tests/unit/test_census_filtering_03.js
new file mode 100644
index 000000000..2c69a14b8
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census_filtering_03.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test filtering with no matches.
+
+function run_test() {
+ const BREAKDOWN = {
+ by: "coarseType",
+ objects: {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+ },
+ scripts: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ strings: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ other:{
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ };
+
+ const REPORT = {
+ objects: {
+ Array: { bytes: 50, count: 5 },
+ UInt8Array: { bytes: 80, count: 8 },
+ Int32Array: { bytes: 320, count: 32 },
+ other: { bytes: 0, count: 0 },
+ },
+ scripts: {
+ "js::jit::JitScript": { bytes: 30, count: 3 },
+ },
+ strings: {
+ JSAtom: { bytes: 60, count: 6 },
+ },
+ other: {
+ "js::Shape": { bytes: 80, count: 8 },
+ }
+ };
+
+ const EXPECTED = {
+ name: null,
+ bytes: 0,
+ totalBytes: 620,
+ count: 0,
+ totalCount: 62,
+ children: undefined,
+ id: 13,
+ parent: undefined,
+ reportLeafIndex: undefined,
+ };
+
+ compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { filter: "zzzzzzzzzzzzzzzzzzzz" });
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census_filtering_04.js b/dom/heapsnapshot/tests/unit/test_census_filtering_04.js
new file mode 100644
index 000000000..c9871436b
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census_filtering_04.js
@@ -0,0 +1,102 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the filtered nodes' counts and bytes are the same as they were when
+// unfiltered.
+
+function run_test() {
+ const COUNT = { by: "count", count: true, bytes: true };
+ const INTERNAL_TYPE = { by: "internalType", then: COUNT };
+
+ const BREAKDOWN = {
+ by: "coarseType",
+ objects: { by: "objectClass", then: COUNT, other: COUNT },
+ strings: COUNT,
+ scripts: {
+ by: "filename",
+ then: INTERNAL_TYPE,
+ noFilename: INTERNAL_TYPE
+ },
+ other: INTERNAL_TYPE,
+ };
+
+ const REPORT = {
+ objects: {
+ Function: {
+ count: 7,
+ bytes: 70
+ },
+ Array: {
+ count: 6,
+ bytes: 60
+ }
+ },
+ scripts: {
+ "http://mozilla.github.io/pdf.js/build/pdf.js": {
+ "js::LazyScript": {
+ count: 4,
+ bytes: 40
+ },
+ }
+ },
+ strings: {
+ count: 2,
+ bytes: 20
+ },
+ other: {
+ "js::Shape": {
+ count: 1,
+ bytes: 10
+ }
+ }
+ };
+
+ const EXPECTED = {
+ name: null,
+ bytes: 0,
+ totalBytes: 200,
+ count: 0,
+ totalCount: 20,
+ parent: undefined,
+ children: [
+ {
+ name: "objects",
+ bytes: 0,
+ totalBytes: 130,
+ count: 0,
+ totalCount: 13,
+ children: [
+ {
+ name: "Function",
+ bytes: 70,
+ totalBytes: 70,
+ count: 7,
+ totalCount: 7,
+ id: 13,
+ parent: 12,
+ children: undefined,
+ reportLeafIndex: 2,
+ },
+ {
+ name: "Array",
+ bytes: 60,
+ totalBytes: 60,
+ count: 6,
+ totalCount: 6,
+ id: 14,
+ parent: 12,
+ children: undefined,
+ reportLeafIndex: 3,
+ },
+ ],
+ id: 12,
+ parent: 11,
+ reportLeafIndex: undefined,
+ }
+ ],
+ id: 11,
+ reportLeafIndex: undefined,
+ };
+
+ compareCensusViewData(BREAKDOWN, REPORT, EXPECTED, { filter: "objects" });
+}
diff --git a/dom/heapsnapshot/tests/unit/test_census_filtering_05.js b/dom/heapsnapshot/tests/unit/test_census_filtering_05.js
new file mode 100644
index 000000000..1d1f4fa55
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_census_filtering_05.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that filtered and inverted allocation stack census trees are sorted
+// properly.
+
+function run_test() {
+ const countBreakdown = { by: "count", count: true, bytes: true };
+
+ const BREAKDOWN = {
+ by: "allocationStack",
+ then: countBreakdown,
+ noStack: countBreakdown,
+ };
+
+ const stacks = [];
+
+ function foo(depth = 1) {
+ stacks.push(saveStack(depth));
+ bar(depth + 1);
+ baz(depth + 1);
+ stacks.push(saveStack(depth));
+ }
+
+ function bar(depth = 1) {
+ stacks.push(saveStack(depth));
+ stacks.push(saveStack(depth));
+ }
+
+ function baz(depth = 1) {
+ stacks.push(saveStack(depth));
+ bang(depth + 1);
+ stacks.push(saveStack(depth));
+ }
+
+ function bang(depth = 1) {
+ stacks.push(saveStack(depth));
+ stacks.push(saveStack(depth));
+ stacks.push(saveStack(depth));
+ }
+
+ foo();
+ bar();
+ baz();
+ bang();
+
+ const REPORT = new Map(stacks.map((s, i) => {
+ return [s, {
+ count: i + 1,
+ bytes: (i + 1) * 10
+ }];
+ }));
+
+ const tree = censusReportToCensusTreeNode(BREAKDOWN, REPORT, {
+ filter: "baz",
+ invert: true
+ });
+
+ dumpn("tree = " + JSON.stringify(tree, savedFrameReplacer, 4));
+
+ (function assertSortedBySelf(node) {
+ if (node.children) {
+ let lastSelfBytes = Infinity;
+ for (let child of node.children) {
+ ok(child.bytes <= lastSelfBytes, `${child.bytes} <= ${lastSelfBytes}`);
+ lastSelfBytes = child.bytes;
+ assertSortedBySelf(child);
+ }
+ }
+ }(tree));
+}
diff --git a/dom/heapsnapshot/tests/unit/test_countToBucketBreakdown_01.js b/dom/heapsnapshot/tests/unit/test_countToBucketBreakdown_01.js
new file mode 100644
index 000000000..e89048c33
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_countToBucketBreakdown_01.js
@@ -0,0 +1,37 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test that we can turn a breakdown with { by: "count" } leaves into a
+// breakdown with { by: "bucket" } leaves.
+
+const COUNT = { by: "count", count: true, bytes: true };
+const BUCKET = { by: "bucket" };
+
+const BREAKDOWN = {
+ by: "coarseType",
+ objects: { by: "objectClass", then: COUNT, other: COUNT },
+ strings: COUNT,
+ scripts: {
+ by: "filename",
+ then: { by: "internalType", then: COUNT },
+ noFilename: { by: "internalType", then: COUNT },
+ },
+ other: { by: "internalType", then: COUNT },
+};
+
+const EXPECTED = {
+ by: "coarseType",
+ objects: { by: "objectClass", then: BUCKET, other: BUCKET },
+ strings: BUCKET,
+ scripts: {
+ by: "filename",
+ then: { by: "internalType", then: BUCKET },
+ noFilename: { by: "internalType", then: BUCKET },
+ },
+ other: { by: "internalType", then: BUCKET },
+};
+
+function run_test() {
+ assertCountToBucketBreakdown(BREAKDOWN, EXPECTED);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_deduplicatePaths_01.js b/dom/heapsnapshot/tests/unit/test_deduplicatePaths_01.js
new file mode 100644
index 000000000..418b49db3
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_deduplicatePaths_01.js
@@ -0,0 +1,113 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test the behavior of the deduplicatePaths utility function.
+
+function edge(from, to, name) {
+ return { from, to, name };
+}
+
+function run_test() {
+ const a = 1;
+ const b = 2;
+ const c = 3;
+ const d = 4;
+ const e = 5;
+ const f = 6;
+ const g = 7;
+
+ dumpn("Single long path");
+ assertDeduplicatedPaths({
+ target: g,
+ paths: [
+ [
+ pathEntry(a, "e1"),
+ pathEntry(b, "e2"),
+ pathEntry(c, "e3"),
+ pathEntry(d, "e4"),
+ pathEntry(e, "e5"),
+ pathEntry(f, "e6"),
+ ]
+ ],
+ expectedNodes: [a, b, c, d, e, f, g],
+ expectedEdges: [
+ edge(a, b, "e1"),
+ edge(b, c, "e2"),
+ edge(c, d, "e3"),
+ edge(d, e, "e4"),
+ edge(e, f, "e5"),
+ edge(f, g, "e6"),
+ ]
+ });
+
+ dumpn("Multiple edges from and to the same nodes");
+ assertDeduplicatedPaths({
+ target: a,
+ paths: [
+ [pathEntry(b, "x")],
+ [pathEntry(b, "y")],
+ [pathEntry(b, "z")],
+ ],
+ expectedNodes: [a, b],
+ expectedEdges: [
+ edge(b, a, "x"),
+ edge(b, a, "y"),
+ edge(b, a, "z"),
+ ]
+ });
+
+ dumpn("Multiple paths sharing some nodes and edges");
+ assertDeduplicatedPaths({
+ target: g,
+ paths: [
+ [
+ pathEntry(a, "a->b"),
+ pathEntry(b, "b->c"),
+ pathEntry(c, "foo"),
+ ],
+ [
+ pathEntry(a, "a->b"),
+ pathEntry(b, "b->d"),
+ pathEntry(d, "bar"),
+ ],
+ [
+ pathEntry(a, "a->b"),
+ pathEntry(b, "b->e"),
+ pathEntry(e, "baz"),
+ ],
+ ],
+ expectedNodes: [a, b, c, d, e, g],
+ expectedEdges: [
+ edge(a, b, "a->b"),
+ edge(b, c, "b->c"),
+ edge(b, d, "b->d"),
+ edge(b, e, "b->e"),
+ edge(c, g, "foo"),
+ edge(d, g, "bar"),
+ edge(e, g, "baz"),
+ ]
+ });
+
+ dumpn("Second shortest path contains target itself");
+ assertDeduplicatedPaths({
+ target: g,
+ paths: [
+ [
+ pathEntry(a, "a->b"),
+ pathEntry(b, "b->g"),
+ ],
+ [
+ pathEntry(a, "a->b"),
+ pathEntry(b, "b->g"),
+ pathEntry(g, "g->f"),
+ pathEntry(f, "f->g"),
+ ],
+ ],
+ expectedNodes: [a, b, g],
+ expectedEdges: [
+ edge(a, b, "a->b"),
+ edge(b, g, "b->g"),
+ ]
+ });
+}
diff --git a/dom/heapsnapshot/tests/unit/test_getCensusIndividuals_01.js b/dom/heapsnapshot/tests/unit/test_getCensusIndividuals_01.js
new file mode 100644
index 000000000..9c4f60991
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_getCensusIndividuals_01.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test basic functionality of `CensusUtils.getCensusIndividuals`.
+
+function run_test() {
+ const stack1 = saveStack(1);
+ const stack2 = saveStack(1);
+ const stack3 = saveStack(1);
+
+ const COUNT = { by: "count", count: true, bytes: true };
+ const INTERNAL_TYPE = { by: "internalType", then: COUNT };
+
+ const BREAKDOWN = {
+ by: "allocationStack",
+ then: INTERNAL_TYPE,
+ noStack: INTERNAL_TYPE,
+ };
+
+ const MOCK_SNAPSHOT = {
+ takeCensus: ({ breakdown }) => {
+ assertStructurallyEquivalent(
+ breakdown,
+ CensusUtils.countToBucketBreakdown(BREAKDOWN));
+
+ // DFS Index
+ return new Map([ // 0
+ [stack1, { // 1
+ JSObject: [101, 102, 103], // 2
+ JSString: [111, 112, 113], // 3
+ }],
+ [stack2, { // 4
+ JSObject: [201, 202, 203], // 5
+ JSString: [211, 212, 213], // 6
+ }],
+ [stack3, { // 7
+ JSObject: [301, 302, 303], // 8
+ JSString: [311, 312, 313], // 9
+ }],
+ ["noStack", { // 10
+ JSObject: [401, 402, 403], // 11
+ JSString: [411, 412, 413], // 12
+ }],
+ ]);
+ }
+ };
+
+ const INDICES = new Set([3, 5, 9]);
+
+ const EXPECTED = new Set([111, 112, 113,
+ 201, 202, 203,
+ 311, 312, 313]);
+
+ const actual = new Set(CensusUtils.getCensusIndividuals(INDICES,
+ BREAKDOWN,
+ MOCK_SNAPSHOT));
+
+ assertStructurallyEquivalent(EXPECTED, actual);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_getReportLeaves_01.js b/dom/heapsnapshot/tests/unit/test_getReportLeaves_01.js
new file mode 100644
index 000000000..4c4298b6a
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_getReportLeaves_01.js
@@ -0,0 +1,114 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test basic functionality of `CensusUtils.getReportLeaves`.
+
+function run_test() {
+ const BREAKDOWN = {
+ by: "coarseType",
+ objects: {
+ by: "objectClass",
+ then: { by: "count", count: true, bytes: true },
+ other: { by: "count", count: true, bytes: true },
+ },
+ strings: { by: "count", count: true, bytes: true },
+ scripts: {
+ by: "filename",
+ then: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ noFilename: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ },
+ other: {
+ by: "internalType",
+ then: { by: "count", count: true, bytes: true },
+ },
+ };
+
+ const REPORT = {
+ objects: {
+ Array: { count: 6, bytes: 60 },
+ Function: { count: 1, bytes: 10 },
+ Object: { count: 1, bytes: 10 },
+ RegExp: { count: 1, bytes: 10 },
+ other: { count: 0, bytes: 0 },
+ },
+ strings: { count: 1, bytes: 10 },
+ scripts: {
+ "foo.js": {
+ JSScript: { count: 1, bytes: 10 },
+ "js::jit::IonScript": { count: 1, bytes: 10 },
+ },
+ noFilename: {
+ JSScript: { count: 1, bytes: 10 },
+ "js::jit::IonScript": { count: 1, bytes: 10 },
+ },
+ },
+ other: {
+ "js::Shape": { count: 7, bytes: 70 },
+ "js::BaseShape": { count: 1, bytes: 10 },
+ },
+ };
+
+ const root = censusReportToCensusTreeNode(BREAKDOWN, REPORT);
+ dumpn("CensusTreeNode tree = " + JSON.stringify(root, null, 4));
+
+ (function assertEveryNodeCanFindItsLeaf(node) {
+ if (node.reportLeafIndex) {
+ const [ leaf ] = CensusUtils.getReportLeaves(new Set([node.reportLeafIndex]),
+ BREAKDOWN,
+ REPORT);
+ ok(leaf, "Should be able to find leaf for a node with a reportLeafIndex = " + node.reportLeafIndex);
+ }
+
+ if (node.children) {
+ for (let child of node.children) {
+ assertEveryNodeCanFindItsLeaf(child);
+ }
+ }
+ }(root));
+
+ // Test finding multiple leaves at a time.
+
+ function find(name, node) {
+ if (node.name === name) {
+ return node;
+ }
+
+ if (node.children) {
+ for (let child of node.children) {
+ const found = find(name, child);
+ if (found) {
+ return found;
+ }
+ }
+ }
+ }
+
+ const arrayNode = find("Array", root);
+ ok(arrayNode);
+ equal(typeof arrayNode.reportLeafIndex, "number");
+
+ const shapeNode = find("js::Shape", root);
+ ok(shapeNode);
+ equal(typeof shapeNode.reportLeafIndex, "number");
+
+ const indices = new Set([arrayNode.reportLeafIndex, shapeNode.reportLeafIndex]);
+ const leaves = CensusUtils.getReportLeaves(indices, BREAKDOWN, REPORT);
+ equal(leaves.length, 2);
+
+ // `getReportLeaves` does not guarantee order of the results, so handle both
+ // cases.
+ ok(leaves.some(l => l === REPORT.objects.Array));
+ ok(leaves.some(l => l === REPORT.other["js::Shape"]));
+
+ // Test that bad indices do not yield results.
+
+ const none = CensusUtils.getReportLeaves(new Set([999999999999]), BREAKDOWN, REPORT);
+ equal(none.length, 0);
+}
diff --git a/dom/heapsnapshot/tests/unit/test_saveHeapSnapshot_e10s_01.js b/dom/heapsnapshot/tests/unit/test_saveHeapSnapshot_e10s_01.js
new file mode 100644
index 000000000..067b9effb
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/test_saveHeapSnapshot_e10s_01.js
@@ -0,0 +1,8 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test saving a heap snapshot in the sandboxed e10s child process.
+
+function run_test() {
+ run_test_in_child("../unit/test_SaveHeapSnapshot.js");
+}
diff --git a/dom/heapsnapshot/tests/unit/xpcshell.ini b/dom/heapsnapshot/tests/unit/xpcshell.ini
new file mode 100644
index 000000000..f84b282d1
--- /dev/null
+++ b/dom/heapsnapshot/tests/unit/xpcshell.ini
@@ -0,0 +1,98 @@
+[DEFAULT]
+tags = devtools heapsnapshot devtools-memory
+head = head_heapsnapshot.js
+tail =
+firefox-appdir = browser
+skip-if = toolkit == 'android'
+
+support-files =
+ Census.jsm
+ dominator-tree-worker.js
+ heap-snapshot-worker.js
+ Match.jsm
+
+[test_census_diff_01.js]
+[test_census_diff_02.js]
+[test_census_diff_03.js]
+[test_census_diff_04.js]
+[test_census_diff_05.js]
+[test_census_diff_06.js]
+[test_census_filtering_01.js]
+[test_census_filtering_02.js]
+[test_census_filtering_03.js]
+[test_census_filtering_04.js]
+[test_census_filtering_05.js]
+[test_census-tree-node-01.js]
+[test_census-tree-node-02.js]
+[test_census-tree-node-03.js]
+[test_census-tree-node-04.js]
+[test_census-tree-node-05.js]
+[test_census-tree-node-06.js]
+[test_census-tree-node-07.js]
+[test_census-tree-node-08.js]
+[test_census-tree-node-09.js]
+[test_census-tree-node-10.js]
+[test_countToBucketBreakdown_01.js]
+[test_deduplicatePaths_01.js]
+[test_DominatorTree_01.js]
+[test_DominatorTree_02.js]
+[test_DominatorTree_03.js]
+[test_DominatorTree_04.js]
+[test_DominatorTree_05.js]
+[test_DominatorTree_06.js]
+[test_DominatorTreeNode_attachShortestPaths_01.js]
+[test_DominatorTreeNode_getNodeByIdAlongPath_01.js]
+[test_DominatorTreeNode_insert_01.js]
+[test_DominatorTreeNode_insert_02.js]
+[test_DominatorTreeNode_insert_03.js]
+[test_DominatorTreeNode_LabelAndShallowSize_01.js]
+[test_DominatorTreeNode_LabelAndShallowSize_02.js]
+[test_DominatorTreeNode_LabelAndShallowSize_03.js]
+[test_DominatorTreeNode_LabelAndShallowSize_04.js]
+[test_DominatorTreeNode_partialTraversal_01.js]
+[test_getCensusIndividuals_01.js]
+[test_getReportLeaves_01.js]
+[test_HeapAnalyses_computeDominatorTree_01.js]
+[test_HeapAnalyses_computeDominatorTree_02.js]
+[test_HeapAnalyses_deleteHeapSnapshot_01.js]
+[test_HeapAnalyses_deleteHeapSnapshot_02.js]
+[test_HeapAnalyses_deleteHeapSnapshot_03.js]
+[test_HeapAnalyses_getCensusIndividuals_01.js]
+[test_HeapAnalyses_getCreationTime_01.js]
+[test_HeapAnalyses_getDominatorTree_01.js]
+[test_HeapAnalyses_getDominatorTree_02.js]
+[test_HeapAnalyses_getImmediatelyDominated_01.js]
+[test_HeapAnalyses_readHeapSnapshot_01.js]
+[test_HeapAnalyses_takeCensusDiff_01.js]
+[test_HeapAnalyses_takeCensusDiff_02.js]
+[test_HeapAnalyses_takeCensus_01.js]
+[test_HeapAnalyses_takeCensus_02.js]
+[test_HeapAnalyses_takeCensus_03.js]
+[test_HeapAnalyses_takeCensus_04.js]
+[test_HeapAnalyses_takeCensus_05.js]
+[test_HeapAnalyses_takeCensus_06.js]
+[test_HeapAnalyses_takeCensus_07.js]
+[test_HeapSnapshot_creationTime_01.js]
+[test_HeapSnapshot_deepStack_01.js]
+[test_HeapSnapshot_describeNode_01.js]
+[test_HeapSnapshot_computeShortestPaths_01.js]
+[test_HeapSnapshot_computeShortestPaths_02.js]
+[test_HeapSnapshot_takeCensus_01.js]
+[test_HeapSnapshot_takeCensus_02.js]
+[test_HeapSnapshot_takeCensus_03.js]
+[test_HeapSnapshot_takeCensus_04.js]
+[test_HeapSnapshot_takeCensus_05.js]
+[test_HeapSnapshot_takeCensus_06.js]
+[test_HeapSnapshot_takeCensus_07.js]
+[test_HeapSnapshot_takeCensus_08.js]
+[test_HeapSnapshot_takeCensus_09.js]
+[test_HeapSnapshot_takeCensus_10.js]
+[test_HeapSnapshot_takeCensus_11.js]
+[test_HeapSnapshot_takeCensus_12.js]
+[test_ReadHeapSnapshot.js]
+[test_ReadHeapSnapshot_with_allocations.js]
+skip-if = os == 'linux' # Bug 1176173
+[test_ReadHeapSnapshot_worker.js]
+skip-if = os == 'linux' # Bug 1176173
+[test_SaveHeapSnapshot.js]
+[test_saveHeapSnapshot_e10s_01.js]
diff --git a/dom/html/HTMLLabelElement.h b/dom/html/HTMLLabelElement.h
index c8385fc53..4057ffef6 100644
--- a/dom/html/HTMLLabelElement.h
+++ b/dom/html/HTMLLabelElement.h
@@ -59,8 +59,6 @@ public:
using nsGenericHTMLElement::Focus;
virtual void Focus(mozilla::ErrorResult& aError) override;
- virtual bool IsDisabled() const override { return false; }
-
// nsIContent
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp
index f3ef20bfc..bc63eab51 100644
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1871,6 +1871,20 @@ nsresult HTMLMediaElement::LoadResource()
// Set the media element's CORS mode only when loading a resource
mCORSMode = AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
+#ifdef MOZ_EME
+ bool isBlob = false;
+ if (mMediaKeys &&
+ Preferences::GetBool("media.eme.mse-only", true) &&
+ // We only want mediaSource URLs, but they are BlobURL, so we have to
+ // check the schema and abort if they are not MediaStream or real Blob.
+ (NS_FAILED(mLoadingSrc->SchemeIs(BLOBURI_SCHEME, &isBlob)) ||
+ !isBlob ||
+ IsMediaStreamURI(mLoadingSrc) ||
+ IsBlobURI(mLoadingSrc))) {
+ return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+ }
+#endif
+
HTMLMediaElement* other = LookupMediaElementURITable(mLoadingSrc);
if (other && other->mDecoder) {
// Clone it.
@@ -4000,7 +4014,6 @@ 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
@@ -4008,6 +4021,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
mWaitingForKeyListener = waitingForKeyProducer->Connect(
AbstractThread::MainThread(), this, &HTMLMediaElement::CannotDecryptWaitingForKey);
}
+#endif
if (mChannelLoader) {
mChannelLoader->Done();
@@ -6476,7 +6490,6 @@ HTMLMediaElement::GetTopLevelPrincipal()
principal = doc->NodePrincipal();
return principal.forget();
}
-#endif //MOZ_EME
void
HTMLMediaElement::CannotDecryptWaitingForKey()
@@ -6495,6 +6508,7 @@ HTMLMediaElement::CannotDecryptWaitingForKey()
UpdateReadyStateInternal();
}
}
+#endif //MOZ_EME
NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged(bool aCapture)
{
diff --git a/dom/html/HTMLObjectElement.h b/dom/html/HTMLObjectElement.h
index 4041b78a3..5226154da 100644
--- a/dom/html/HTMLObjectElement.h
+++ b/dom/html/HTMLObjectElement.h
@@ -77,8 +77,6 @@ public:
NS_IMETHOD Reset() override;
NS_IMETHOD SubmitNamesValues(HTMLFormSubmission *aFormSubmission) override;
- virtual bool IsDisabled() const override { return false; }
-
virtual void DoneAddingChildren(bool aHaveNotified) override;
virtual bool IsDoneAddingChildren() override;
diff --git a/dom/html/HTMLOptGroupElement.cpp b/dom/html/HTMLOptGroupElement.cpp
index 8a044fbf3..9e738961d 100644
--- a/dom/html/HTMLOptGroupElement.cpp
+++ b/dom/html/HTMLOptGroupElement.cpp
@@ -53,15 +53,14 @@ HTMLOptGroupElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
aVisitor.mCanHandle = false;
// Do not process any DOM events if the element is disabled
// XXXsmaug This is not the right thing to do. But what is?
- if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
+ if (IsDisabled()) {
return NS_OK;
}
- nsIFrame* frame = GetPrimaryFrame();
- if (frame) {
- const nsStyleUserInterface* uiStyle = frame->StyleUserInterface();
- if (uiStyle->mUserInput == StyleUserInput::None ||
- uiStyle->mUserInput == StyleUserInput::Disabled) {
+ if (nsIFrame* frame = GetPrimaryFrame()) {
+ // FIXME(emilio): This poking at the style of the frame is broken unless we
+ // flush before every event handling, which we don't really want to.
+ if (frame->StyleUserInterface()->mUserInput == StyleUserInput::None) {
return NS_OK;
}
}
diff --git a/dom/html/HTMLOptGroupElement.h b/dom/html/HTMLOptGroupElement.h
index d53a2e32b..e46a6a953 100644
--- a/dom/html/HTMLOptGroupElement.h
+++ b/dom/html/HTMLOptGroupElement.h
@@ -46,10 +46,6 @@ public:
virtual nsIDOMNode* AsDOMNode() override { return this; }
- virtual bool IsDisabled() const override {
- return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
- }
-
bool Disabled() const
{
return GetBoolAttr(nsGkAtoms::disabled);
diff --git a/dom/html/HTMLOptionElement.h b/dom/html/HTMLOptionElement.h
index e220b84df..4b5e192ff 100644
--- a/dom/html/HTMLOptionElement.h
+++ b/dom/html/HTMLOptionElement.h
@@ -67,10 +67,6 @@ public:
nsresult CopyInnerTo(mozilla::dom::Element* aDest);
- virtual bool IsDisabled() const override {
- return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
- }
-
bool Disabled() const
{
return GetBoolAttr(nsGkAtoms::disabled);
diff --git a/dom/html/HTMLOutputElement.h b/dom/html/HTMLOutputElement.h
index 588262480..6b6c3f66c 100644
--- a/dom/html/HTMLOutputElement.h
+++ b/dom/html/HTMLOutputElement.h
@@ -35,8 +35,6 @@ public:
NS_IMETHOD Reset() override;
NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
- virtual bool IsDisabled() const override { return false; }
-
nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
bool ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
diff --git a/dom/html/HTMLTableCellElement.cpp b/dom/html/HTMLTableCellElement.cpp
index d00d60400..1cf413413 100644
--- a/dom/html/HTMLTableCellElement.cpp
+++ b/dom/html/HTMLTableCellElement.cpp
@@ -390,26 +390,16 @@ HTMLTableCellElement::ParseAttribute(int32_t aNamespaceID,
return aResult.ParseIntWithBounds(aValue, 0);
}
if (aAttribute == nsGkAtoms::colspan) {
- bool res = aResult.ParseIntWithBounds(aValue, -1);
- if (res) {
- int32_t val = aResult.GetIntegerValue();
- // reset large colspan values as IE and opera do
- if (val > MAX_COLSPAN || val <= 0) {
- aResult.SetTo(1, &aValue);
- }
- }
- return res;
+ aResult.ParseClampedNonNegativeInt(aValue, 1, 1, MAX_COLSPAN);
+ return true;
}
if (aAttribute == nsGkAtoms::rowspan) {
- bool res = aResult.ParseIntWithBounds(aValue, -1, MAX_ROWSPAN);
- if (res) {
- int32_t val = aResult.GetIntegerValue();
- // quirks mode does not honor the special html 4 value of 0
- if (val < 0 || (0 == val && InNavQuirksMode(OwnerDoc()))) {
+ aResult.ParseClampedNonNegativeInt(aValue, 1, 0, MAX_ROWSPAN);
+ // quirks mode does not honor the special html 4 value of 0
+ if (aResult.GetIntegerValue() == 0 && InNavQuirksMode(OwnerDoc())) {
aResult.SetTo(1, &aValue);
- }
}
- return res;
+ return true;
}
if (aAttribute == nsGkAtoms::height) {
return aResult.ParseSpecialIntValue(aValue);
diff --git a/dom/html/HTMLTableCellElement.h b/dom/html/HTMLTableCellElement.h
index 916333510..ab7a918eb 100644
--- a/dom/html/HTMLTableCellElement.h
+++ b/dom/html/HTMLTableCellElement.h
@@ -37,7 +37,7 @@ public:
}
void SetColSpan(uint32_t aColSpan, ErrorResult& aError)
{
- SetHTMLIntAttr(nsGkAtoms::colspan, aColSpan, aError);
+ SetUnsignedIntAttr(nsGkAtoms::colspan, aColSpan, 1, aError);
}
uint32_t RowSpan() const
{
@@ -45,7 +45,7 @@ public:
}
void SetRowSpan(uint32_t aRowSpan, ErrorResult& aError)
{
- SetHTMLIntAttr(nsGkAtoms::rowspan, aRowSpan, aError);
+ SetUnsignedIntAttr(nsGkAtoms::rowspan, aRowSpan, 1, aError);
}
//already_AddRefed<nsDOMTokenList> Headers() const;
void GetHeaders(DOMString& aHeaders)
diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp
index 2f890325a..0c8bcc9c8 100644
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -2109,14 +2109,6 @@ nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
}
-/* virtual */
-bool
-nsGenericHTMLFormElement::IsDisabled() const
-{
- return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled) ||
- (mFieldSet && mFieldSet->IsDisabled());
-}
-
void
nsGenericHTMLFormElement::ForgetFieldSet(nsIContent* aFieldset)
{
@@ -2308,14 +2300,13 @@ nsGenericHTMLFormElement::IsElementDisabledForEvents(EventMessage aMessage,
break;
}
- bool disabled = IsDisabled();
- if (!disabled && aFrame) {
- const nsStyleUserInterface* uiStyle = aFrame->StyleUserInterface();
- disabled = uiStyle->mUserInput == StyleUserInput::None ||
- uiStyle->mUserInput == StyleUserInput::Disabled;
-
+ // FIXME(emilio): This poking at the style of the frame is slightly bogus
+ // unless we flush before every event, which we don't really want to do.
+ if (aFrame &&
+ aFrame->StyleUserInterface()->mUserInput == StyleUserInput::None) {
+ return true;
}
- return disabled;
+ return IsDisabled();
}
void
diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h
index 72039f266..acbebe087 100644
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -817,8 +817,8 @@ public:
/**
* Returns the current disabled state of the element.
*/
- virtual bool IsDisabled() const {
- return false;
+ bool IsDisabled() const {
+ return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
}
bool IsHidden() const
@@ -1222,8 +1222,6 @@ public:
virtual nsresult PreHandleEvent(
mozilla::EventChainPreVisitor& aVisitor) override;
- virtual bool IsDisabled() const override;
-
/**
* This callback is called by a fieldest on all its elements whenever its
* disabled attribute is changed so the element knows its disabled state
diff --git a/dom/indexedDB/ActorsChild.cpp b/dom/indexedDB/ActorsChild.cpp
index 30dc9b6da..85f876cdc 100644
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -3291,6 +3291,10 @@ BackgroundCursorChild::HandleResponse(
auto& responses =
const_cast<nsTArray<ObjectStoreCursorResponse>&>(aResponses);
+ // If a new cursor is created, we need to keep a reference to it until the
+ // ResultHelper creates a DOM Binding.
+ RefPtr<IDBCursor> newCursor;
+
for (ObjectStoreCursorResponse& response : responses) {
StructuredCloneReadInfo cloneReadInfo(Move(response.cloneInfo()));
cloneReadInfo.mDatabase = mTransaction->Database();
@@ -3300,8 +3304,6 @@ BackgroundCursorChild::HandleResponse(
nullptr,
cloneReadInfo.mFiles);
- RefPtr<IDBCursor> newCursor;
-
if (mCursor) {
mCursor->Reset(Move(response.key()), Move(cloneReadInfo));
} else {
diff --git a/dom/inputmethod/moz.build b/dom/inputmethod/moz.build
index 84b3cb8ab..e6d994565 100644
--- a/dom/inputmethod/moz.build
+++ b/dom/inputmethod/moz.build
@@ -6,11 +6,8 @@
EXTRA_COMPONENTS += [
'InputMethod.manifest',
- 'MozKeyboard.js',
-]
-
-EXTRA_PP_JS_MODULES += [
'Keyboard.jsm',
+ 'MozKeyboard.js',
]
JAR_MANIFESTS += ['jar.mn']
diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl
index 70ec7e0ae..fcfe407e8 100644
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -1786,7 +1786,7 @@ interface nsIDOMWindowUtils : nsISupports {
/**
* In certain cases the event handling of nodes, form controls in practice,
* may be disabled. Such cases are for example the existence of disabled
- * attribute or -moz-user-input: none/disabled.
+ * attribute or -moz-user-input: none.
*/
boolean isNodeDisabledForEvents(in nsIDOMNode aNode);
diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp
index fdf0fcf3e..6b914372b 100644
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -29,7 +29,6 @@
#include "mozilla/dom/DataTransfer.h"
#include "mozilla/dom/DOMStorageIPC.h"
#include "mozilla/dom/ExternalHelperAppChild.h"
-#include "mozilla/dom/FlyWebPublishedServerIPC.h"
#include "mozilla/dom/GetFilesHelper.h"
#include "mozilla/dom/ProcessGlobal.h"
#include "mozilla/dom/PushNotifier.h"
@@ -150,8 +149,6 @@
#endif
#include "mozilla/dom/File.h"
-#include "mozilla/dom/PPresentationChild.h"
-#include "mozilla/dom/PresentationIPCService.h"
#include "mozilla/ipc/InputStreamUtils.h"
#ifdef MOZ_WEBSPEECH
@@ -1417,65 +1414,6 @@ ContentChild::SendPBlobConstructor(PBlobChild* aActor,
return PContentChild::SendPBlobConstructor(aActor, aParams);
}
-PPresentationChild*
-ContentChild::AllocPPresentationChild()
-{
- MOZ_CRASH("We should never be manually allocating PPresentationChild actors");
- return nullptr;
-}
-
-bool
-ContentChild::DeallocPPresentationChild(PPresentationChild* aActor)
-{
- delete aActor;
- return true;
-}
-
-PFlyWebPublishedServerChild*
-ContentChild::AllocPFlyWebPublishedServerChild(const nsString& name,
- const FlyWebPublishOptions& params)
-{
- MOZ_CRASH("We should never be manually allocating PFlyWebPublishedServerChild actors");
- return nullptr;
-}
-
-bool
-ContentChild::DeallocPFlyWebPublishedServerChild(PFlyWebPublishedServerChild* aActor)
-{
- RefPtr<FlyWebPublishedServerChild> actor =
- dont_AddRef(static_cast<FlyWebPublishedServerChild*>(aActor));
- return true;
-}
-
-bool
-ContentChild::RecvNotifyPresentationReceiverLaunched(PBrowserChild* aIframe,
- const nsString& aSessionId)
-{
- nsCOMPtr<nsIDocShell> docShell =
- do_GetInterface(static_cast<TabChild*>(aIframe)->WebNavigation());
- NS_WARNING_ASSERTION(docShell, "WebNavigation failed");
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- NS_WARNING_ASSERTION(service, "presentation service is missing");
-
- Unused << NS_WARN_IF(NS_FAILED(static_cast<PresentationIPCService*>(service.get())->MonitorResponderLoading(aSessionId, docShell)));
-
- return true;
-}
-
-bool
-ContentChild::RecvNotifyPresentationReceiverCleanUp(const nsString& aSessionId)
-{
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- NS_WARNING_ASSERTION(service, "presentation service is missing");
-
- Unused << NS_WARN_IF(NS_FAILED(service->UntrackSessionInfo(aSessionId, nsIPresentationService::ROLE_RECEIVER)));
-
- return true;
-}
-
bool
ContentChild::RecvNotifyEmptyHTTPCache()
{
diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h
index 4c8f15cc0..2b36560e2 100644
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -297,23 +297,6 @@ public:
virtual bool DeallocPStorageChild(PStorageChild* aActor) override;
- virtual PPresentationChild* AllocPPresentationChild() override;
-
- virtual bool DeallocPPresentationChild(PPresentationChild* aActor) override;
-
- virtual PFlyWebPublishedServerChild*
- AllocPFlyWebPublishedServerChild(const nsString& name,
- const FlyWebPublishOptions& params) override;
-
- virtual bool DeallocPFlyWebPublishedServerChild(PFlyWebPublishedServerChild* aActor) override;
-
- virtual bool
- RecvNotifyPresentationReceiverLaunched(PBrowserChild* aIframe,
- const nsString& aSessionId) override;
-
- virtual bool
- RecvNotifyPresentationReceiverCleanUp(const nsString& aSessionId) override;
-
virtual bool RecvNotifyEmptyHTTPCache() override;
virtual PSpeechSynthesisChild* AllocPSpeechSynthesisChild() override;
diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp
index 97e3a4880..0d11fb889 100644
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -51,10 +51,7 @@
#include "mozilla/dom/ServiceWorkerRegistrar.h"
#include "mozilla/dom/power/PowerManagerService.h"
#include "mozilla/dom/Permissions.h"
-#include "mozilla/dom/PresentationParent.h"
-#include "mozilla/dom/PPresentationParent.h"
#include "mozilla/dom/PushNotifier.h"
-#include "mozilla/dom/FlyWebPublishedServerIPC.h"
#include "mozilla/dom/quota/QuotaManagerService.h"
#include "mozilla/dom/time/DateCacheCleaner.h"
#include "mozilla/embedding/printingui/PrintingParent.h"
@@ -3106,44 +3103,6 @@ ContentParent::DeallocPStorageParent(PStorageParent* aActor)
return true;
}
-PPresentationParent*
-ContentParent::AllocPPresentationParent()
-{
- RefPtr<PresentationParent> actor = new PresentationParent();
- return actor.forget().take();
-}
-
-bool
-ContentParent::DeallocPPresentationParent(PPresentationParent* aActor)
-{
- RefPtr<PresentationParent> actor =
- dont_AddRef(static_cast<PresentationParent*>(aActor));
- return true;
-}
-
-bool
-ContentParent::RecvPPresentationConstructor(PPresentationParent* aActor)
-{
- return static_cast<PresentationParent*>(aActor)->Init(mChildID);
-}
-
-PFlyWebPublishedServerParent*
-ContentParent::AllocPFlyWebPublishedServerParent(const nsString& name,
- const FlyWebPublishOptions& params)
-{
- RefPtr<FlyWebPublishedServerParent> actor =
- new FlyWebPublishedServerParent(name, params);
- return actor.forget().take();
-}
-
-bool
-ContentParent::DeallocPFlyWebPublishedServerParent(PFlyWebPublishedServerParent* aActor)
-{
- RefPtr<FlyWebPublishedServerParent> actor =
- dont_AddRef(static_cast<FlyWebPublishedServerParent*>(aActor));
- return true;
-}
-
PSpeechSynthesisParent*
ContentParent::AllocPSpeechSynthesisParent()
{
diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h
index 26b5c44ac..f6f3e64db 100644
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -800,18 +800,6 @@ private:
virtual bool DeallocPStorageParent(PStorageParent* aActor) override;
- virtual PPresentationParent* AllocPPresentationParent() override;
-
- virtual bool DeallocPPresentationParent(PPresentationParent* aActor) override;
-
- virtual bool RecvPPresentationConstructor(PPresentationParent* aActor) override;
-
- virtual PFlyWebPublishedServerParent*
- AllocPFlyWebPublishedServerParent(const nsString& name,
- const FlyWebPublishOptions& params) override;
-
- virtual bool DeallocPFlyWebPublishedServerParent(PFlyWebPublishedServerParent* aActor) override;
-
virtual PSpeechSynthesisParent* AllocPSpeechSynthesisParent() override;
virtual bool
diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl
index e8fb25aec..5b15433d5 100644
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -43,9 +43,7 @@ include protocol PJavaScript;
include protocol PRemoteSpellcheckEngine;
include protocol PWebBrowserPersistDocument;
include protocol PWebrtcGlobal;
-include protocol PPresentation;
include protocol PVideoDecoderManager;
-include protocol PFlyWebPublishedServer;
include DOMTypes;
include JavaScriptTypes;
include InputStreamParams;
@@ -88,7 +86,6 @@ using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/Structu
using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h";
using mozilla::DocShellOriginAttributes from "mozilla/ipc/BackgroundUtils.h";
using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
-using struct mozilla::dom::FlyWebPublishOptions from "mozilla/dom/FlyWebPublishOptionsIPCSerializer.h";
union ChromeRegistryItem
{
@@ -260,8 +257,6 @@ nested(upto inside_cpow) sync protocol PContent
manages PRemoteSpellcheckEngine;
manages PWebBrowserPersistDocument;
manages PWebrtcGlobal;
- manages PPresentation;
- manages PFlyWebPublishedServer;
both:
// Depending on exactly how the new browser is being created, it might be
@@ -481,18 +476,6 @@ child:
async UpdateWindow(uintptr_t aChildId);
/**
- * Notify the child that presentation receiver has been launched with the
- * correspondent iframe.
- */
- async NotifyPresentationReceiverLaunched(PBrowser aIframe, nsString aSessionId);
-
- /**
- * Notify the child that the info about a presentation receiver needs to be
- * cleaned up.
- */
- async NotifyPresentationReceiverCleanUp(nsString aSessionId);
-
- /**
* Notify the child that cache is emptied.
*/
async NotifyEmptyHTTPCache();
@@ -682,10 +665,6 @@ parent:
async PWebrtcGlobal();
- async PPresentation();
-
- async PFlyWebPublishedServer(nsString name, FlyWebPublishOptions params);
-
// Services remoting
async StartVisitedQuery(URIParams uri);
diff --git a/dom/mathml/nsMathMLElement.cpp b/dom/mathml/nsMathMLElement.cpp
index d6aef876c..2be931682 100644
--- a/dom/mathml/nsMathMLElement.cpp
+++ b/dom/mathml/nsMathMLElement.cpp
@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "mozilla/ArrayUtils.h"
#include "nsGkAtoms.h"
+#include "nsITableCellLayout.h" // for MAX_COLSPAN / MAX_ROWSPAN
#include "nsCRT.h"
#include "nsLayoutStylesheetCache.h"
#include "nsRuleData.h"
@@ -150,8 +151,9 @@ nsMathMLElement::ParseAttribute(int32_t aNamespaceID,
const nsAString& aValue,
nsAttrValue& aResult)
{
+ MOZ_ASSERT(IsMathMLElement());
if (aNamespaceID == kNameSpaceID_None) {
- if (IsMathMLElement(nsGkAtoms::math) && aAttribute == nsGkAtoms::mode) {
+ if (mNodeInfo->Equals(nsGkAtoms::math) && aAttribute == nsGkAtoms::mode) {
WarnDeprecated(nsGkAtoms::mode->GetUTF16String(),
nsGkAtoms::display->GetUTF16String(), OwnerDoc());
}
@@ -165,6 +167,16 @@ nsMathMLElement::ParseAttribute(int32_t aNamespaceID,
aAttribute == nsGkAtoms::mathbackground_) {
return aResult.ParseColor(aValue);
}
+ if (mNodeInfo->Equals(nsGkAtoms::mtd_)) {
+ if (aAttribute == nsGkAtoms::columnspan_) {
+ aResult.ParseClampedNonNegativeInt(aValue, 1, 1, MAX_COLSPAN);
+ return true;
+ }
+ if (aAttribute == nsGkAtoms::rowspan) {
+ aResult.ParseClampedNonNegativeInt(aValue, 1, 0, MAX_ROWSPAN);
+ return true;
+ }
+ }
}
return nsMathMLElementBase::ParseAttribute(aNamespaceID, aAttribute,
@@ -209,6 +221,8 @@ static Element::MappedAttributeEntry sDirStyles[] = {
bool
nsMathMLElement::IsAttributeMapped(const nsIAtom* aAttribute) const
{
+ MOZ_ASSERT(IsMathMLElement());
+
static const MappedAttributeEntry* const mtableMap[] = {
sMtableStyles,
sCommonPresStyles
@@ -240,10 +254,10 @@ nsMathMLElement::IsAttributeMapped(const nsIAtom* aAttribute) const
if (IsAnyOfMathMLElements(nsGkAtoms::mstyle_, nsGkAtoms::math))
return FindAttributeDependence(aAttribute, mstyleMap);
- if (IsMathMLElement(nsGkAtoms::mtable_))
+ if (mNodeInfo->Equals(nsGkAtoms::mtable_))
return FindAttributeDependence(aAttribute, mtableMap);
- if (IsMathMLElement(nsGkAtoms::mrow_))
+ if (mNodeInfo->Equals(nsGkAtoms::mrow_))
return FindAttributeDependence(aAttribute, mrowMap);
if (IsAnyOfMathMLElements(nsGkAtoms::maction_,
diff --git a/dom/media/AbstractMediaDecoder.h b/dom/media/AbstractMediaDecoder.h
index a0f04ec98..6babcce17 100644
--- a/dom/media/AbstractMediaDecoder.h
+++ b/dom/media/AbstractMediaDecoder.h
@@ -31,7 +31,9 @@ class MediaResource;
class ReentrantMonitor;
class VideoFrameContainer;
class MediaDecoderOwner;
+#ifdef MOZ_EME
class CDMProxy;
+#endif
typedef nsDataHashtable<nsCStringHashKey, nsCString> MetadataTags;
diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp
index 223c59c3b..0cce91ccb 100644
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -387,7 +387,9 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
, mLogicalPosition(0.0)
, mDuration(std::numeric_limits<double>::quiet_NaN())
, mResourceCallback(new ResourceCallback())
+#ifdef MOZ_EME
, mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__))
+#endif
, mIgnoreProgressData(false)
, mInfiniteStream(false)
, mOwner(aOwner)
@@ -472,7 +474,9 @@ MediaDecoder::Shutdown()
mResourceCallback->Disconnect();
+#ifdef MOZ_EME
mCDMProxyPromiseHolder.RejectIfExists(true, __func__);
+#endif
DiscardOngoingSeekIfExists();
@@ -1537,6 +1541,7 @@ MediaDecoder::CanPlayThrough()
return GetStatistics().CanPlayThrough();
}
+#ifdef MOZ_EME
RefPtr<MediaDecoder::CDMProxyPromise>
MediaDecoder::RequestCDMProxy() const
{
@@ -1551,6 +1556,7 @@ MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
mCDMProxyPromiseHolder.ResolveIfExists(aProxy, __func__);
}
+#endif
bool
MediaDecoder::IsOpusEnabled()
diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h
index 05e88db8b..298552433 100644
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -8,7 +8,11 @@
#define MediaDecoder_h_
#include "mozilla/Atomics.h"
+
+#ifdef MOZ_EME
#include "mozilla/CDMProxy.h"
+#endif
+
#include "mozilla/MozPromise.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/StateMirroring.h"
@@ -432,6 +436,7 @@ private:
MediaDecoderOwner* GetOwner() const override;
+#ifdef MOZ_EME
typedef MozPromise<RefPtr<CDMProxy>, bool /* aIgnored */, /* IsExclusive = */ true> CDMProxyPromise;
// Resolved when a CDMProxy is available and the capabilities are known or
@@ -439,6 +444,7 @@ private:
RefPtr<CDMProxyPromise> RequestCDMProxy() const;
void SetCDMProxy(CDMProxy* aProxy);
+#endif
static bool IsOggEnabled();
static bool IsOpusEnabled();
@@ -589,8 +595,10 @@ private:
RefPtr<ResourceCallback> mResourceCallback;
+#ifdef MOZ_EME
MozPromiseHolder<CDMProxyPromise> mCDMProxyPromiseHolder;
RefPtr<CDMProxyPromise> mCDMProxyPromise;
+#endif
protected:
// The promise resolving/rejection is queued as a "micro-task" which will be
diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h
index 8a6997826..f53c74689 100644
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -24,7 +24,9 @@
namespace mozilla {
+#ifdef MOZ_EME
class CDMProxy;
+#endif
class MediaDecoderReader;
struct WaitForDataRejectValue
@@ -186,7 +188,9 @@ public:
// when to call SetIdle().
virtual void SetIdle() {}
+#ifdef MOZ_EME
virtual void SetCDMProxy(CDMProxy* aProxy) {}
+#endif
// Tell the reader that the data decoded are not for direct playback, so it
// can accept more files, in particular those which have more channels than
diff --git a/dom/media/MediaDecoderReaderWrapper.h b/dom/media/MediaDecoderReaderWrapper.h
index 92001ca33..1a8d3a68c 100644
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -113,7 +113,9 @@ public:
return mReader->CanonicalBuffered();
}
+#ifdef MOZ_EME
void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); }
+#endif
void SetVideoBlankDecode(bool aIsBlankDecode);
diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp
index 2ed1956c9..63222c22c 100644
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1238,7 +1238,12 @@ DecodeMetadataState::OnMetadataRead(MetadataHolder* aMetadata)
// feeding in the CDM, which we need to decode the first frame (and
// thus get the metadata). We could fix this if we could compute the start
// time by demuxing without necessaring decoding.
- bool waitingForCDM = Info().IsEncrypted() && !mMaster->mCDMProxy;
+ bool waitingForCDM =
+#ifdef MOZ_EME
+ mMaster->Info().IsEncrypted() && !mMaster->mCDMProxy;
+#else
+ false;
+#endif
mMaster->mNotifyMetadataBeforeFirstFrame =
mMaster->mDuration.Ref().isSome() || waitingForCDM;
@@ -1262,7 +1267,9 @@ DormantState::HandlePlayStateChanged(MediaDecoder::PlayState aPlayState)
{
if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
// Exit dormant when the user wants to play.
+#ifdef MOZ_EME
MOZ_ASSERT(!Info().IsEncrypted() || mMaster->mCDMProxy);
+#endif
MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
SetState<SeekingState>(Move(mPendingSeek), EventVisibility::Suppressed);
}
@@ -1575,7 +1582,9 @@ ShutdownState::Enter()
// dispose of the timer.
master->mVideoDecodeSuspendTimer.Reset();
+#ifdef MOZ_EME
master->mCDMProxyPromise.DisconnectIfExists();
+#endif
if (master->IsPlaying()) {
master->StopPlayback();
@@ -2129,10 +2138,12 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoder* aDecoder)
mMediaSink = CreateMediaSink(mAudioCaptured);
+#ifdef MOZ_EME
mCDMProxyPromise.Begin(aDecoder->RequestCDMProxy()->Then(
OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnCDMProxyReady,
&MediaDecoderStateMachine::OnCDMProxyNotReady));
+#endif
nsresult rv = mReader->Init();
NS_ENSURE_SUCCESS(rv, rv);
@@ -3108,6 +3119,7 @@ void MediaDecoderStateMachine::OnMediaSinkAudioError(nsresult aResult)
DecodeError(MediaResult(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, __func__));
}
+#ifdef MOZ_EME
void
MediaDecoderStateMachine::OnCDMProxyReady(RefPtr<CDMProxy> aProxy)
{
@@ -3124,6 +3136,7 @@ MediaDecoderStateMachine::OnCDMProxyNotReady()
MOZ_ASSERT(OnTaskQueue());
mCDMProxyPromise.Complete();
}
+#endif
void
MediaDecoderStateMachine::SetAudioCaptured(bool aCaptured)
diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h
index ff3258ff1..f04f34983 100644
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -768,10 +768,12 @@ private:
// Playback will not start when audio is offloading.
bool mAudioOffloading;
+#ifdef MOZ_EME
void OnCDMProxyReady(RefPtr<CDMProxy> aProxy);
void OnCDMProxyNotReady();
RefPtr<CDMProxy> mCDMProxy;
MozPromiseRequestHolder<MediaDecoder::CDMProxyPromise> mCDMProxyPromise;
+#endif
private:
// The buffered range. Mirrored from the decoder thread.
diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp
index 773434710..396f31e37 100644
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -4,7 +4,10 @@
* 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/. */
+#ifdef MOZ_EME
#include "mozilla/CDMProxy.h"
+#endif
+
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/Preferences.h"
@@ -611,7 +614,6 @@ private:
nsTArray<uint8_t> mInitData;
nsString mInitDataType;
};
-#endif
void
MediaFormatReader::SetCDMProxy(CDMProxy* aProxy)
@@ -624,6 +626,7 @@ MediaFormatReader::SetCDMProxy(CDMProxy* aProxy)
});
OwnerThread()->Dispatch(r.forget());
}
+#endif // MOZ_EME
bool
MediaFormatReader::IsWaitingOnCDMResource() {
diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h
index 4d05ca201..be0b7cd17 100644
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -20,7 +20,9 @@
namespace mozilla {
+#ifdef MOZ_EME
class CDMProxy;
+#endif
class MediaFormatReader final : public MediaDecoderReader
{
@@ -91,7 +93,9 @@ public:
return mTrackDemuxersMayBlock;
}
+#ifdef MOZ_EME
void SetCDMProxy(CDMProxy* aProxy) override;
+#endif
// Returns a string describing the state of the decoder data.
// Used for debugging purposes.
@@ -584,7 +588,9 @@ private:
RefPtr<VideoFrameContainer> mVideoFrameContainer;
layers::ImageContainer* GetImageContainer();
+#ifdef MOZ_EME
RefPtr<CDMProxy> mCDMProxy;
+#endif
RefPtr<GMPCrashHelper> mCrashHelper;
diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js
index 0569b15ae..df36ae83c 100644
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -13,8 +13,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PeerConnectionIdp",
"resource://gre/modules/media/PeerConnectionIdp.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "convertToRTCStatsReport",
"resource://gre/modules/media/RTCStatsReport.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
- "resource://gre/modules/AppConstants.jsm");
const PC_CONTRACT = "@mozilla.org/dom/peerconnection;1";
const PC_OBS_CONTRACT = "@mozilla.org/dom/peerconnectionobserver;1";
diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp
index b293c251b..bf937241c 100644
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -10,7 +10,9 @@
#include "MP4Demuxer.h"
#include "mozilla/Preferences.h"
#include "nsCharSeparatedTokenizer.h"
+#ifdef MOZ_EME
#include "mozilla/CDMProxy.h"
+#endif
#include "mozilla/Logging.h"
#include "mozilla/SharedThreadPool.h"
#include "nsMimeTypes.h"
diff --git a/dom/media/gmp/GMPChild.cpp b/dom/media/gmp/GMPChild.cpp
index 14b06cc72..fa6f2f4c8 100644
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -22,7 +22,9 @@
#include "GMPUtils.h"
#include "prio.h"
#include "base/task.h"
+#ifdef MOZ_EME
#include "widevine-adapter/WidevineAdapter.h"
+#endif
using namespace mozilla::ipc;
@@ -254,9 +256,13 @@ GMPChild::AnswerStartPlugin(const nsString& aAdapter)
return false;
}
+#ifdef MOZ_EME
bool isWidevine = aAdapter.EqualsLiteral("widevine");
GMPAdapter* adapter = (isWidevine) ? new WidevineAdapter() : nullptr;
+#else
+ GMPAdapter* adapter = nullptr;
+#endif
if (!mGMPLoader->Load(libPath.get(),
libPath.Length(),
mNodeId.BeginWriting(),
diff --git a/dom/media/gmp/GMPDecryptorParent.cpp b/dom/media/gmp/GMPDecryptorParent.cpp
index 1f8b9a7a8..4f5402160 100644
--- a/dom/media/gmp/GMPDecryptorParent.cpp
+++ b/dom/media/gmp/GMPDecryptorParent.cpp
@@ -43,11 +43,13 @@ GMPDecryptorParent::~GMPDecryptorParent()
bool
GMPDecryptorParent::RecvSetDecryptorId(const uint32_t& aId)
{
+#ifdef MOZ_EME
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return false;
}
mCallback->SetDecryptorId(aId);
+#endif
return true;
}
@@ -202,6 +204,7 @@ bool
GMPDecryptorParent::RecvSetSessionId(const uint32_t& aCreateSessionId,
const nsCString& aSessionId)
{
+#ifdef MOZ_EME
LOGD(("GMPDecryptorParent[%p]::RecvSetSessionId(token=%u, sessionId='%s')",
this, aCreateSessionId, aSessionId.get()));
@@ -210,6 +213,7 @@ GMPDecryptorParent::RecvSetSessionId(const uint32_t& aCreateSessionId,
return false;
}
mCallback->SetSessionId(aCreateSessionId, aSessionId);
+#endif
return true;
}
@@ -217,6 +221,7 @@ bool
GMPDecryptorParent::RecvResolveLoadSessionPromise(const uint32_t& aPromiseId,
const bool& aSuccess)
{
+#ifdef MOZ_EME
LOGD(("GMPDecryptorParent[%p]::RecvResolveLoadSessionPromise(promiseId=%u)",
this, aPromiseId));
@@ -225,12 +230,14 @@ GMPDecryptorParent::RecvResolveLoadSessionPromise(const uint32_t& aPromiseId,
return false;
}
mCallback->ResolveLoadSessionPromise(aPromiseId, aSuccess);
+#endif
return true;
}
bool
GMPDecryptorParent::RecvResolvePromise(const uint32_t& aPromiseId)
{
+#ifdef MOZ_EME
LOGD(("GMPDecryptorParent[%p]::RecvResolvePromise(promiseId=%u)",
this, aPromiseId));
@@ -239,6 +246,7 @@ GMPDecryptorParent::RecvResolvePromise(const uint32_t& aPromiseId)
return false;
}
mCallback->ResolvePromise(aPromiseId);
+#endif
return true;
}
@@ -266,6 +274,7 @@ GMPDecryptorParent::RecvRejectPromise(const uint32_t& aPromiseId,
const GMPDOMException& aException,
const nsCString& aMessage)
{
+#ifdef MOZ_EME
LOGD(("GMPDecryptorParent[%p]::RecvRejectPromise(promiseId=%u, exception=%d, msg='%s')",
this, aPromiseId, aException, aMessage.get()));
@@ -274,10 +283,11 @@ GMPDecryptorParent::RecvRejectPromise(const uint32_t& aPromiseId,
return false;
}
mCallback->RejectPromise(aPromiseId, GMPExToNsresult(aException), aMessage);
+#endif
return true;
}
-
+#ifdef MOZ_EME
static dom::MediaKeyMessageType
ToMediaKeyMessageType(GMPSessionMessageType aMessageType) {
switch (aMessageType) {
@@ -288,12 +298,14 @@ ToMediaKeyMessageType(GMPSessionMessageType aMessageType) {
default: return dom::MediaKeyMessageType::License_request;
};
};
+#endif
bool
GMPDecryptorParent::RecvSessionMessage(const nsCString& aSessionId,
const GMPSessionMessageType& aMessageType,
nsTArray<uint8_t>&& aMessage)
{
+#ifdef MOZ_EME
LOGD(("GMPDecryptorParent[%p]::RecvSessionMessage(sessionId='%s', type=%d, msg='%s')",
this, aSessionId.get(), aMessageType, ToBase64(aMessage).get()));
@@ -302,6 +314,7 @@ GMPDecryptorParent::RecvSessionMessage(const nsCString& aSessionId,
return false;
}
mCallback->SessionMessage(aSessionId, ToMediaKeyMessageType(aMessageType), aMessage);
+#endif
return true;
}
@@ -309,6 +322,7 @@ bool
GMPDecryptorParent::RecvExpirationChange(const nsCString& aSessionId,
const double& aExpiryTime)
{
+#ifdef MOZ_EME
LOGD(("GMPDecryptorParent[%p]::RecvExpirationChange(sessionId='%s', expiry=%lf)",
this, aSessionId.get(), aExpiryTime));
@@ -317,12 +331,14 @@ GMPDecryptorParent::RecvExpirationChange(const nsCString& aSessionId,
return false;
}
mCallback->ExpirationChange(aSessionId, aExpiryTime);
+#endif
return true;
}
bool
GMPDecryptorParent::RecvSessionClosed(const nsCString& aSessionId)
{
+#ifdef MOZ_EME
LOGD(("GMPDecryptorParent[%p]::RecvSessionClosed(sessionId='%s')",
this, aSessionId.get()));
@@ -331,6 +347,7 @@ GMPDecryptorParent::RecvSessionClosed(const nsCString& aSessionId)
return false;
}
mCallback->SessionClosed(aSessionId);
+#endif
return true;
}
@@ -340,6 +357,7 @@ GMPDecryptorParent::RecvSessionError(const nsCString& aSessionId,
const uint32_t& aSystemCode,
const nsCString& aMessage)
{
+#ifdef MOZ_EME
LOGD(("GMPDecryptorParent[%p]::RecvSessionError(sessionId='%s', exception=%d, sysCode=%d, msg='%s')",
this, aSessionId.get(),
aException, aSystemCode, aMessage.get()));
@@ -352,9 +370,11 @@ GMPDecryptorParent::RecvSessionError(const nsCString& aSessionId,
GMPExToNsresult(aException),
aSystemCode,
aMessage);
+#endif
return true;
}
+#ifdef MOZ_EME
static dom::MediaKeyStatus
ToMediaKeyStatus(GMPMediaKeyStatus aStatus) {
switch (aStatus) {
@@ -368,11 +388,13 @@ ToMediaKeyStatus(GMPMediaKeyStatus aStatus) {
default: return dom::MediaKeyStatus::Internal_error;
}
}
+#endif
bool
GMPDecryptorParent::RecvBatchedKeyStatusChanged(const nsCString& aSessionId,
InfallibleTArray<GMPKeyInformation>&& aKeyInfos)
{
+#ifdef MOZ_EME
LOGD(("GMPDecryptorParent[%p]::RecvBatchedKeyStatusChanged(sessionId='%s', KeyInfos len='%d')",
this, aSessionId.get(), aKeyInfos.Length()));
@@ -392,9 +414,11 @@ GMPDecryptorParent::RecvBatchedKeyStatusChanged(const nsCString& aSessionId,
}
mCallback->BatchedKeyStatusChanged(aSessionId, cdmKeyInfos);
}
+#endif
return true;
}
+#ifdef MOZ_EME
DecryptStatus
ToDecryptStatus(GMPErr aError)
{
@@ -405,12 +429,14 @@ ToDecryptStatus(GMPErr aError)
default: return GenericErr;
}
}
+#endif
bool
GMPDecryptorParent::RecvDecrypted(const uint32_t& aId,
const GMPErr& aErr,
InfallibleTArray<uint8_t>&& aBuffer)
{
+#ifdef MOZ_EME
LOGV(("GMPDecryptorParent[%p]::RecvDecrypted(id=%d, err=%d)",
this, aId, aErr));
@@ -419,6 +445,7 @@ GMPDecryptorParent::RecvDecrypted(const uint32_t& aId,
return false;
}
mCallback->Decrypted(aId, ToDecryptStatus(aErr), aBuffer);
+#endif
return true;
}
diff --git a/dom/media/gmp/GMPDecryptorProxy.h b/dom/media/gmp/GMPDecryptorProxy.h
index 0ef31fd92..ed16755f8 100644
--- a/dom/media/gmp/GMPDecryptorProxy.h
+++ b/dom/media/gmp/GMPDecryptorProxy.h
@@ -6,7 +6,9 @@
#ifndef GMPDecryptorProxy_h_
#define GMPDecryptorProxy_h_
+#ifdef MOZ_EME
#include "mozilla/DecryptorProxyCallback.h"
+#endif
#include "GMPCallbackBase.h"
#include "gmp-decryption.h"
#include "nsString.h"
@@ -15,8 +17,13 @@ namespace mozilla {
class CryptoSample;
} // namespace mozilla
+#ifdef MOZ_EME
class GMPDecryptorProxyCallback : public DecryptorProxyCallback,
public GMPCallbackBase {
+#else
+class GMPDecryptorProxyCallback : public GMPCallbackBase {
+#endif
+
public:
virtual ~GMPDecryptorProxyCallback() {}
};
diff --git a/dom/media/gmp/GMPParent.cpp b/dom/media/gmp/GMPParent.cpp
index 234ed5c05..84603e973 100644
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -30,8 +30,10 @@ using mozilla::ipc::GeckoChildProcessHost;
#include "WMFDecoderModule.h"
#endif
+#ifdef MOZ_EME
#include "mozilla/dom/WidevineCDMManifestBinding.h"
#include "widevine-adapter/WidevineAdapter.h"
+#endif
namespace mozilla {
@@ -654,6 +656,7 @@ GMPParent::ReadGMPMetaData()
return ReadGMPInfoFile(infoFile);
}
+#ifdef MOZ_EME
// Maybe this is the Widevine adapted plugin?
nsCOMPtr<nsIFile> manifestFile;
rv = mDirectory->Clone(getter_AddRefs(manifestFile));
@@ -662,6 +665,9 @@ GMPParent::ReadGMPMetaData()
}
manifestFile->AppendRelativePath(NS_LITERAL_STRING("manifest.json"));
return ReadChromiumManifestFile(manifestFile);
+#else
+ return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+#endif
}
RefPtr<GenericPromise>
@@ -754,6 +760,7 @@ GMPParent::ReadChromiumManifestFile(nsIFile* aFile)
RefPtr<GenericPromise>
GMPParent::ParseChromiumManifest(nsString aJSON)
{
+#ifdef MOZ_EME
LOGD("%s: for '%s'", __FUNCTION__, NS_LossyConvertUTF16toASCII(aJSON).get());
MOZ_ASSERT(NS_IsMainThread());
@@ -791,6 +798,10 @@ GMPParent::ParseChromiumManifest(nsString aJSON)
#endif
return GenericPromise::CreateAndResolve(true, __func__);
+#else // !MOZ_EME
+ MOZ_ASSERT_UNREACHABLE("don't call me if EME isn't enabled");
+ return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+#endif // !MOZ_EME
}
bool
diff --git a/dom/media/gmp/moz.build b/dom/media/gmp/moz.build
index 3b67fb5c9..79de6e1d9 100644
--- a/dom/media/gmp/moz.build
+++ b/dom/media/gmp/moz.build
@@ -35,8 +35,6 @@ EXPORTS += [
'GMPAudioDecoderProxy.h',
'GMPAudioHost.h',
'GMPCallbackBase.h',
- 'GMPCDMCallbackProxy.h',
- 'GMPCDMProxy.h',
'GMPChild.h',
'GMPContentChild.h',
'GMPContentParent.h',
@@ -73,6 +71,12 @@ EXPORTS += [
'GMPVideoPlaneImpl.h',
]
+if CONFIG['MOZ_EME']:
+ EXPORTS += [
+ 'GMPCDMCallbackProxy.h',
+ 'GMPCDMProxy.h',
+ ]
+
# We link GMPLoader into xul on B2G/Fennec as its code does not need to be
# covered by a DRM vendor's voucher.
if CONFIG['OS_TARGET'] == 'Android':
@@ -87,8 +91,6 @@ UNIFIED_SOURCES += [
'GMPAudioDecoderChild.cpp',
'GMPAudioDecoderParent.cpp',
'GMPAudioHost.cpp',
- 'GMPCDMCallbackProxy.cpp',
- 'GMPCDMProxy.cpp',
'GMPChild.cpp',
'GMPContentChild.cpp',
'GMPContentParent.cpp',
@@ -120,10 +122,16 @@ UNIFIED_SOURCES += [
'GMPVideoPlaneImpl.cpp',
]
-DIRS += [
- 'rlz',
- 'widevine-adapter',
-]
+if CONFIG['MOZ_EME']:
+ UNIFIED_SOURCES += [
+ 'GMPCDMCallbackProxy.cpp',
+ 'GMPCDMProxy.cpp',
+ ]
+
+DIRS += ['rlz']
+
+if CONFIG['MOZ_EME']:
+ DIRS += ['widevine-adapter']
IPDL_SOURCES += [
'GMPTypes.ipdlh',
diff --git a/dom/media/gtest/MockMediaDecoderOwner.h b/dom/media/gtest/MockMediaDecoderOwner.h
index 324f18141..1009ca30a 100644
--- a/dom/media/gtest/MockMediaDecoderOwner.h
+++ b/dom/media/gtest/MockMediaDecoderOwner.h
@@ -34,8 +34,10 @@ public:
void DownloadProgressed() override {}
void UpdateReadyState() override {}
void FirstFrameLoaded() override {}
+#ifdef MOZ_EME
void DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
const nsAString& aInitDataType) override {}
+#endif
bool IsActive() const override { return true; }
bool IsHidden() const override { return false; }
void DownloadSuspended() override {}
diff --git a/dom/media/gtest/moz.build b/dom/media/gtest/moz.build
index a7ea73807..ae059962c 100644
--- a/dom/media/gtest/moz.build
+++ b/dom/media/gtest/moz.build
@@ -28,6 +28,11 @@ UNIFIED_SOURCES += [
'TestWebMBuffered.cpp',
]
+if CONFIG['MOZ_EME']:
+ UNIFIED_SOURCES += [
+ 'TestEME.cpp',
+ ]
+
if CONFIG['MOZ_WEBM_ENCODER']:
UNIFIED_SOURCES += [
'TestVideoTrackEncoder.cpp',
diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp
index 21fb158b5..9a2d00ad8 100644
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -84,7 +84,7 @@ private:
nsTArray<uint8_t> mInitData;
nsString mInitDataType;
};
-#endif
+#endif // MOZ_EME
TrackBuffersManager::TrackBuffersManager(MediaSourceDecoder* aParentDecoder,
const nsACString& aType)
diff --git a/dom/media/moz.build b/dom/media/moz.build
index df8cb619d..41267a6ef 100644
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -20,7 +20,6 @@ with Files('GetUserMedia*'):
BUG_COMPONENT = component_av
DIRS += [
- 'eme',
'encoder',
'flac',
'gmp',
@@ -49,6 +48,9 @@ if CONFIG['MOZ_FMP4']:
if CONFIG['MOZ_WEBRTC']:
DIRS += ['bridge']
+if CONFIG['MOZ_EME']:
+ DIRS += ['eme']
+
TEST_DIRS += [
'gtest',
]
diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp
index 5bfdcffb7..6e7241c46 100644
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -24,7 +24,6 @@
#endif
#include "GMPDecoderModule.h"
-#include "mozilla/CDMProxy.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/SharedThreadPool.h"
#include "mozilla/StaticPtr.h"
@@ -37,7 +36,11 @@
#include "H264Converter.h"
#include "AgnosticDecoderModule.h"
+
+#ifdef MOZ_EME
+#include "mozilla/CDMProxy.h"
#include "EMEDecoderModule.h"
+#endif
#include "DecoderDoctorDiagnostics.h"
@@ -450,11 +453,13 @@ PDMFactory::GetDecoder(const TrackInfo& aTrackInfo,
return pdm.forget();
}
+#ifdef MOZ_EME
void
PDMFactory::SetCDMProxy(CDMProxy* aProxy)
{
RefPtr<PDMFactory> m = new PDMFactory();
mEMEPDM = new EMEDecoderModule(aProxy, m);
}
+#endif
} // namespace mozilla
diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h
index 94be7e928..2b43fa1ab 100644
--- a/dom/media/platforms/PDMFactory.h
+++ b/dom/media/platforms/PDMFactory.h
@@ -11,7 +11,9 @@
#include "mozilla/Function.h"
#include "mozilla/StaticMutex.h"
+#ifdef MOZ_EME
class CDMProxy;
+#endif
namespace mozilla {
@@ -38,12 +40,14 @@ public:
bool Supports(const TrackInfo& aTrackInfo,
DecoderDoctorDiagnostics* aDiagnostics) const;
+#ifdef MOZ_EME
// Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or
// decrypt-and-decode EME encrypted content. If the CDM only decrypts and
// does not decode, we create a PDM and use that to create MediaDataDecoders
// that we use on on aTaskQueue to decode the decrypted stream.
// This is called on the decode task queue.
void SetCDMProxy(CDMProxy* aProxy);
+#endif
static constexpr int kYUV400 = 0;
static constexpr int kYUV420 = 1;
diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build
index f5fb72c5d..c46d52e3f 100644
--- a/dom/media/platforms/moz.build
+++ b/dom/media/platforms/moz.build
@@ -30,11 +30,13 @@ UNIFIED_SOURCES += [
]
DIRS += [
- 'agnostic/eme',
'agnostic/gmp',
'omx'
]
+if CONFIG['MOZ_EME']:
+ DIRS += ['agnostic/eme']
+
if CONFIG['MOZ_WMF']:
DIRS += [ 'wmf' ];
diff --git a/dom/moz.build b/dom/moz.build
index 54dc0510e..89c539b4b 100644
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -52,10 +52,10 @@ DIRS += [
'fetch',
'filehandle',
'filesystem',
- 'flyweb',
'gamepad',
'geolocation',
'grid',
+ 'heapsnapshot',
'html',
'json',
'jsurl',
@@ -107,8 +107,6 @@ if CONFIG['OS_ARCH'] == 'WINNT':
if CONFIG['MOZ_SECUREELEMENT']:
DIRS += ['secureelement']
-DIRS += ['presentation']
-
TEST_DIRS += [
'tests',
'imptests',
diff --git a/dom/performance/Performance.h b/dom/performance/Performance.h
index 4debecc90..c40dd8aff 100644
--- a/dom/performance/Performance.h
+++ b/dom/performance/Performance.h
@@ -96,8 +96,10 @@ public:
IMPL_EVENT_HANDLER(resourcetimingbufferfull)
+#ifdef MOZ_DEVTOOLS_SERVER
virtual void GetMozMemory(JSContext *aCx,
JS::MutableHandle<JSObject*> aObj) = 0;
+#endif
virtual nsDOMNavigationTiming* GetDOMTiming() const = 0;
diff --git a/dom/performance/PerformanceMainThread.cpp b/dom/performance/PerformanceMainThread.cpp
index 5a84f5fb1..b95a91ea6 100644
--- a/dom/performance/PerformanceMainThread.cpp
+++ b/dom/performance/PerformanceMainThread.cpp
@@ -11,6 +11,7 @@
namespace mozilla {
namespace dom {
+
NS_IMPL_CYCLE_COLLECTION_CLASS(PerformanceMainThread)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PerformanceMainThread,
@@ -18,8 +19,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PerformanceMainThread,
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTiming,
mNavigation,
mDocEntry)
+#ifdef MOZ_DEVTOOLS_SERVER
tmp->mMozMemory = nullptr;
mozilla::DropJSObjects(this);
+#endif
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PerformanceMainThread,
@@ -31,7 +34,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceMainThread,
Performance)
+#ifdef MOZ_DEVTOOLS_SERVER
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mMozMemory)
+#endif
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_ADDREF_INHERITED(PerformanceMainThread, Performance)
@@ -55,9 +60,12 @@ PerformanceMainThread::PerformanceMainThread(nsPIDOMWindowInner* aWindow,
PerformanceMainThread::~PerformanceMainThread()
{
+#ifdef MOZ_DEVTOOLS_SERVER
mozilla::DropJSObjects(this);
+#endif
}
+#ifdef MOZ_DEVTOOLS_SERVER
void
PerformanceMainThread::GetMozMemory(JSContext *aCx,
JS::MutableHandle<JSObject*> aObj)
@@ -71,6 +79,7 @@ PerformanceMainThread::GetMozMemory(JSContext *aCx,
aObj.set(mMozMemory);
}
+#endif
PerformanceTiming*
PerformanceMainThread::Timing()
diff --git a/dom/performance/PerformanceMainThread.h b/dom/performance/PerformanceMainThread.h
index 9f0e185fc..a90a53520 100644
--- a/dom/performance/PerformanceMainThread.h
+++ b/dom/performance/PerformanceMainThread.h
@@ -34,8 +34,10 @@ public:
DOMHighResTimeStamp CreationTime() const override;
+#ifdef MOZ_DEVTOOLS_SERVER
virtual void GetMozMemory(JSContext *aCx,
JS::MutableHandle<JSObject*> aObj) override;
+#endif
virtual nsDOMNavigationTiming* GetDOMTiming() const override
{
@@ -79,7 +81,9 @@ protected:
nsCOMPtr<nsITimedChannel> mChannel;
RefPtr<PerformanceTiming> mTiming;
RefPtr<PerformanceNavigation> mNavigation;
+#ifdef MOZ_DEVTOOLS_SERVER
JS::Heap<JSObject*> mMozMemory;
+#endif
};
} // namespace dom
diff --git a/dom/performance/PerformanceWorker.h b/dom/performance/PerformanceWorker.h
index 346bdd026..ffe2a1998 100644
--- a/dom/performance/PerformanceWorker.h
+++ b/dom/performance/PerformanceWorker.h
@@ -43,11 +43,13 @@ public:
DOMHighResTimeStamp CreationTime() const override;
+#ifdef MOZ_DEVTOOLS_SERVER
virtual void GetMozMemory(JSContext *aCx,
JS::MutableHandle<JSObject*> aObj) override
{
MOZ_CRASH("This should not be called on workers.");
}
+#endif
virtual nsDOMNavigationTiming* GetDOMTiming() const override
{
diff --git a/dom/plugins/base/PluginPRLibrary.cpp b/dom/plugins/base/PluginPRLibrary.cpp
index ecc55d455..57c6c57ab 100644
--- a/dom/plugins/base/PluginPRLibrary.cpp
+++ b/dom/plugins/base/PluginPRLibrary.cpp
@@ -21,43 +21,10 @@ static int gNotOptimized;
#define CALLING_CONVENTION_HACK
#endif
-#ifdef MOZ_WIDGET_ANDROID
-#include "AndroidBridge.h"
-#include "android_npapi.h"
-#include <android/log.h>
-#undef ALOG
-#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoJavaEnv", ## args)
-#endif
-
using namespace mozilla::layers;
namespace mozilla {
-#ifdef MOZ_WIDGET_ANDROID
-nsresult
-PluginPRLibrary::NP_Initialize(NPNetscapeFuncs* bFuncs,
- NPPluginFuncs* pFuncs, NPError* error)
-{
- JNIEnv* env = jni::GetEnvForThread();
-
- mozilla::AutoLocalJNIFrame jniFrame(env);
-
- if (mNP_Initialize) {
- *error = mNP_Initialize(bFuncs, pFuncs, env);
- } else {
- NP_InitializeFunc pfNP_Initialize = (NP_InitializeFunc)
- PR_FindFunctionSymbol(mLibrary, "NP_Initialize");
- if (!pfNP_Initialize)
- return NS_ERROR_FAILURE;
- *error = pfNP_Initialize(bFuncs, pFuncs, env);
- }
-
- // Save pointers to functions that get called through PluginLibrary itself.
- mNPP_New = pFuncs->newp;
- mNPP_ClearSiteData = pFuncs->clearsitedata;
- mNPP_GetSitesWithData = pFuncs->getsiteswithdata;
- return NS_OK;
-}
-#elif defined(XP_UNIX) && !defined(XP_MACOSX)
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
nsresult
PluginPRLibrary::NP_Initialize(NPNetscapeFuncs* bFuncs,
NPPluginFuncs* pFuncs, NPError* error)
diff --git a/dom/plugins/base/android/ANPAudio.cpp b/dom/plugins/base/android/ANPAudio.cpp
deleted file mode 100644
index bc47e8999..000000000
--- a/dom/plugins/base/android/ANPAudio.cpp
+++ /dev/null
@@ -1,390 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
- * 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 "base/basictypes.h"
-#include "AndroidBridge.h"
-
-#include <android/log.h>
-#include <stdlib.h>
-#include <time.h>
-
-#include "assert.h"
-#include "ANPBase.h"
-#include "nsIThread.h"
-#include "nsThreadUtils.h"
-#include "mozilla/Mutex.h"
-
-#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPluginsAudio" , ## args)
-#define ASSIGN(obj, name) (obj)->name = anp_audio_##name
-
-/* android.media.AudioTrack */
-struct AudioTrack {
- jclass at_class;
- jmethodID constructor;
- jmethodID flush;
- jmethodID pause;
- jmethodID play;
- jmethodID setvol;
- jmethodID stop;
- jmethodID write;
- jmethodID getpos;
- jmethodID getstate;
- jmethodID release;
-};
-
-enum AudioTrackMode {
- MODE_STATIC = 0,
- MODE_STREAM = 1
-};
-
-/* android.media.AudioManager */
-enum AudioManagerStream {
- STREAM_VOICE_CALL = 0,
- STREAM_SYSTEM = 1,
- STREAM_RING = 2,
- STREAM_MUSIC = 3,
- STREAM_ALARM = 4,
- STREAM_NOTIFICATION = 5,
- STREAM_DTMF = 8
-};
-
-/* android.media.AudioFormat */
-enum AudioFormatChannel {
- CHANNEL_OUT_MONO = 4,
- CHANNEL_OUT_STEREO = 12
-};
-
-enum AudioFormatEncoding {
- ENCODING_PCM_16BIT = 2,
- ENCODING_PCM_8BIT = 3
-};
-
-enum AudioFormatState {
- STATE_UNINITIALIZED = 0,
- STATE_INITIALIZED = 1,
- STATE_NO_STATIC_DATA = 2
-};
-
-static struct AudioTrack at;
-
-static jclass
-init_jni_bindings(JNIEnv *jenv) {
- jclass jc =
- (jclass)jenv->NewGlobalRef(jenv->FindClass("android/media/AudioTrack"));
-
- at.constructor = jenv->GetMethodID(jc, "<init>", "(IIIIII)V");
- at.flush = jenv->GetMethodID(jc, "flush", "()V");
- at.pause = jenv->GetMethodID(jc, "pause", "()V");
- at.play = jenv->GetMethodID(jc, "play", "()V");
- at.setvol = jenv->GetMethodID(jc, "setStereoVolume", "(FF)I");
- at.stop = jenv->GetMethodID(jc, "stop", "()V");
- at.write = jenv->GetMethodID(jc, "write", "([BII)I");
- at.getpos = jenv->GetMethodID(jc, "getPlaybackHeadPosition", "()I");
- at.getstate = jenv->GetMethodID(jc, "getState", "()I");
- at.release = jenv->GetMethodID(jc, "release", "()V");
-
- return jc;
-}
-
-struct ANPAudioTrack {
- jobject output_unit;
- jclass at_class;
-
- unsigned int rate;
- unsigned int channels;
- unsigned int bufferSize;
- unsigned int isStopped;
- unsigned int keepGoing;
-
- mozilla::Mutex lock;
-
- void* user;
- ANPAudioCallbackProc proc;
- ANPSampleFormat format;
-
- ANPAudioTrack() : lock("ANPAudioTrack") { }
-};
-
-class AudioRunnable : public mozilla::Runnable
-{
-public:
- NS_DECL_NSIRUNNABLE
-
- AudioRunnable(ANPAudioTrack* aAudioTrack) {
- mTrack = aAudioTrack;
- }
-
- ANPAudioTrack* mTrack;
-};
-
-NS_IMETHODIMP
-AudioRunnable::Run()
-{
- PR_SetCurrentThreadName("Android Audio");
-
- JNIEnv* const jenv = mozilla::jni::GetEnvForThread();
-
- mozilla::AutoLocalJNIFrame autoFrame(jenv, 2);
-
- jbyteArray bytearray = jenv->NewByteArray(mTrack->bufferSize);
- if (!bytearray) {
- LOG("AudioRunnable:: Run. Could not create bytearray");
- return NS_ERROR_FAILURE;
- }
-
- jbyte *byte = jenv->GetByteArrayElements(bytearray, nullptr);
- if (!byte) {
- LOG("AudioRunnable:: Run. Could not create bytearray");
- return NS_ERROR_FAILURE;
- }
-
- ANPAudioBuffer buffer;
- buffer.channelCount = mTrack->channels;
- buffer.format = mTrack->format;
- buffer.bufferData = (void*) byte;
-
- while (true)
- {
- // reset the buffer size
- buffer.size = mTrack->bufferSize;
-
- {
- mozilla::MutexAutoLock lock(mTrack->lock);
-
- if (!mTrack->keepGoing)
- break;
-
- // Get data from the plugin
- mTrack->proc(kMoreData_ANPAudioEvent, mTrack->user, &buffer);
- }
-
- if (buffer.size == 0) {
- LOG("%p - kMoreData_ANPAudioEvent", mTrack);
- continue;
- }
-
- size_t wroteSoFar = 0;
- jint retval;
- do {
- retval = jenv->CallIntMethod(mTrack->output_unit,
- at.write,
- bytearray,
- wroteSoFar,
- buffer.size - wroteSoFar);
- if (retval < 0) {
- LOG("%p - Write failed %d", mTrack, retval);
- break;
- }
-
- wroteSoFar += retval;
-
- } while(wroteSoFar < buffer.size);
- }
-
- jenv->CallVoidMethod(mTrack->output_unit, at.release);
-
- jenv->DeleteGlobalRef(mTrack->output_unit);
- jenv->DeleteGlobalRef(mTrack->at_class);
-
- delete mTrack;
-
- jenv->ReleaseByteArrayElements(bytearray, byte, 0);
-
- return NS_OK;
-}
-
-ANPAudioTrack*
-anp_audio_newTrack(uint32_t sampleRate, // sampling rate in Hz
- ANPSampleFormat format,
- int channelCount, // MONO=1, STEREO=2
- ANPAudioCallbackProc proc,
- void* user)
-{
- ANPAudioTrack *s = new ANPAudioTrack();
- if (s == nullptr) {
- return nullptr;
- }
-
- JNIEnv* const jenv = mozilla::jni::GetEnvForThread();
-
- s->at_class = init_jni_bindings(jenv);
- s->rate = sampleRate;
- s->channels = channelCount;
- s->bufferSize = s->rate * s->channels;
- s->isStopped = true;
- s->keepGoing = false;
- s->user = user;
- s->proc = proc;
- s->format = format;
-
- int jformat;
- switch (format) {
- case kPCM16Bit_ANPSampleFormat:
- jformat = ENCODING_PCM_16BIT;
- break;
- case kPCM8Bit_ANPSampleFormat:
- jformat = ENCODING_PCM_8BIT;
- break;
- default:
- LOG("Unknown audio format. defaulting to 16bit.");
- jformat = ENCODING_PCM_16BIT;
- break;
- }
-
- int jChannels;
- switch (channelCount) {
- case 1:
- jChannels = CHANNEL_OUT_MONO;
- break;
- case 2:
- jChannels = CHANNEL_OUT_STEREO;
- break;
- default:
- LOG("Unknown channel count. defaulting to mono.");
- jChannels = CHANNEL_OUT_MONO;
- break;
- }
-
- mozilla::AutoLocalJNIFrame autoFrame(jenv);
-
- jobject obj = jenv->NewObject(s->at_class,
- at.constructor,
- STREAM_MUSIC,
- s->rate,
- jChannels,
- jformat,
- s->bufferSize,
- MODE_STREAM);
-
- if (autoFrame.CheckForException() || obj == nullptr) {
- jenv->DeleteGlobalRef(s->at_class);
- delete s;
- return nullptr;
- }
-
- jint state = jenv->CallIntMethod(obj, at.getstate);
-
- if (autoFrame.CheckForException() || state == STATE_UNINITIALIZED) {
- jenv->DeleteGlobalRef(s->at_class);
- delete s;
- return nullptr;
- }
-
- s->output_unit = jenv->NewGlobalRef(obj);
- return s;
-}
-
-void
-anp_audio_deleteTrack(ANPAudioTrack* s)
-{
- if (s == nullptr) {
- return;
- }
-
- mozilla::MutexAutoLock lock(s->lock);
- s->keepGoing = false;
-
- // deallocation happens in the AudioThread. There is a
- // potential leak if anp_audio_start is never called, but
- // we do not see that from flash.
-}
-
-void
-anp_audio_start(ANPAudioTrack* s)
-{
- if (s == nullptr || s->output_unit == nullptr) {
- return;
- }
-
- if (s->keepGoing) {
- // we are already playing. Ignore.
- return;
- }
-
- JNIEnv* const jenv = mozilla::jni::GetEnvForThread();
-
- mozilla::AutoLocalJNIFrame autoFrame(jenv, 0);
- jenv->CallVoidMethod(s->output_unit, at.play);
-
- if (autoFrame.CheckForException()) {
- jenv->DeleteGlobalRef(s->at_class);
- delete s;
- return;
- }
-
- s->isStopped = false;
- s->keepGoing = true;
-
- // AudioRunnable now owns the ANPAudioTrack
- RefPtr<AudioRunnable> runnable = new AudioRunnable(s);
-
- nsCOMPtr<nsIThread> thread;
- NS_NewThread(getter_AddRefs(thread), runnable);
-}
-
-void
-anp_audio_pause(ANPAudioTrack* s)
-{
- if (s == nullptr || s->output_unit == nullptr) {
- return;
- }
-
- JNIEnv* const jenv = mozilla::jni::GetEnvForThread();
-
- mozilla::AutoLocalJNIFrame autoFrame(jenv, 0);
- jenv->CallVoidMethod(s->output_unit, at.pause);
-}
-
-void
-anp_audio_stop(ANPAudioTrack* s)
-{
- if (s == nullptr || s->output_unit == nullptr) {
- return;
- }
-
- s->isStopped = true;
- JNIEnv* const jenv = mozilla::jni::GetEnvForThread();
-
- mozilla::AutoLocalJNIFrame autoFrame(jenv, 0);
- jenv->CallVoidMethod(s->output_unit, at.stop);
-}
-
-bool
-anp_audio_isStopped(ANPAudioTrack* s)
-{
- return s->isStopped;
-}
-
-uint32_t
-anp_audio_trackLatency(ANPAudioTrack* s) {
- // Hardcode an estimate of the system's audio latency. Flash hardcodes
- // similar latency estimates for pre-Honeycomb devices that do not support
- // ANPAudioTrackInterfaceV1's trackLatency(). The Android stock browser
- // calls android::AudioTrack::latency(), an internal Android API that is
- // not available in the public NDK:
- // https://github.com/android/platform_external_webkit/commit/49bf866973cb3b2a6c74c0eab864e9562e4cbab1
- return 100; // milliseconds
-}
-
-void InitAudioTrackInterfaceV0(ANPAudioTrackInterfaceV0 *i) {
- _assert(i->inSize == sizeof(*i));
- ASSIGN(i, newTrack);
- ASSIGN(i, deleteTrack);
- ASSIGN(i, start);
- ASSIGN(i, pause);
- ASSIGN(i, stop);
- ASSIGN(i, isStopped);
-}
-
-void InitAudioTrackInterfaceV1(ANPAudioTrackInterfaceV1 *i) {
- _assert(i->inSize == sizeof(*i));
- ASSIGN(i, newTrack);
- ASSIGN(i, deleteTrack);
- ASSIGN(i, start);
- ASSIGN(i, pause);
- ASSIGN(i, stop);
- ASSIGN(i, isStopped);
- ASSIGN(i, trackLatency);
-}
diff --git a/dom/plugins/base/android/ANPBase.h b/dom/plugins/base/android/ANPBase.h
deleted file mode 100644
index f9712dc79..000000000
--- a/dom/plugins/base/android/ANPBase.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- 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/. */
-
-#include <stdlib.h>
-#include "android_npapi.h"
-#include "nsISupportsImpl.h"
-
-#define NOT_IMPLEMENTED_FATAL() do { \
- __android_log_print(ANDROID_LOG_ERROR, "GeckoPlugins", \
- "%s not implemented %s, %d", \
- __PRETTY_FUNCTION__, __FILE__, __LINE__); \
- abort(); \
- } while(0)
-
-#define NOT_IMPLEMENTED() \
- __android_log_print(ANDROID_LOG_ERROR, "GeckoPlugins", \
- "!!!!!!!!!!!!!! %s not implemented %s, %d", \
- __PRETTY_FUNCTION__, __FILE__, __LINE__); \
-
-void InitAudioTrackInterfaceV0(ANPAudioTrackInterfaceV0 *i);
-void InitAudioTrackInterfaceV1(ANPAudioTrackInterfaceV1* i);
-void InitCanvasInterface(ANPCanvasInterfaceV0 *i);
-void InitEventInterface(ANPEventInterfaceV0 *i);
-void InitLogInterface(ANPLogInterfaceV0 *i);
-void InitPaintInterface(ANPPaintInterfaceV0 *i);
-void InitSurfaceInterface(ANPSurfaceInterfaceV0 *i);
-void InitSystemInterfaceV1(ANPSystemInterfaceV1 *i);
-void InitSystemInterfaceV2(ANPSystemInterfaceV2 *i);
-void InitTypeFaceInterface(ANPTypefaceInterfaceV0 *i);
-void InitWindowInterface(ANPWindowInterfaceV0 *i);
-void InitWindowInterfaceV2(ANPWindowInterfaceV2 *i);
-void InitVideoInterfaceV1(ANPVideoInterfaceV1 *i);
-void InitOpenGLInterface(ANPOpenGLInterfaceV0 *i);
-void InitNativeWindowInterface(ANPNativeWindowInterfaceV0 *i);
diff --git a/dom/plugins/base/android/ANPEvent.cpp b/dom/plugins/base/android/ANPEvent.cpp
deleted file mode 100644
index cac8c94f0..000000000
--- a/dom/plugins/base/android/ANPEvent.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- 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/. */
-
-#include "assert.h"
-#include "ANPBase.h"
-#include <android/log.h>
-#include "nsThreadUtils.h"
-#include "nsNPAPIPluginInstance.h"
-#include "nsNPAPIPlugin.h"
-
-#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
-#define ASSIGN(obj, name) (obj)->name = anp_event_##name
-
-void
-anp_event_postEvent(NPP instance, const ANPEvent* event)
-{
- LOG("%s", __PRETTY_FUNCTION__);
-
- nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
- pinst->PostEvent((void*) event);
-
- LOG("returning from %s", __PRETTY_FUNCTION__);
-}
-
-
-void InitEventInterface(ANPEventInterfaceV0 *i) {
- _assert(i->inSize == sizeof(*i));
- ASSIGN(i, postEvent);
-}
diff --git a/dom/plugins/base/android/ANPKeyCodes.h b/dom/plugins/base/android/ANPKeyCodes.h
deleted file mode 100644
index edfe2b95c..000000000
--- a/dom/plugins/base/android/ANPKeyCodes.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2008, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ANPKeyCodes_DEFINED
-#define ANPKeyCodes_DEFINED
-
-/* List the key codes that are set to a plugin in the ANPKeyEvent.
-
- These exactly match the values in android/view/KeyEvent.java and the
- corresponding .h file android/keycodes.h.
-*/
-enum ANPKeyCodes {
- kUnknown_ANPKeyCode = 0,
-
- kSoftLeft_ANPKeyCode = 1,
- kSoftRight_ANPKeyCode = 2,
- kHome_ANPKeyCode = 3,
- kBack_ANPKeyCode = 4,
- kCall_ANPKeyCode = 5,
- kEndCall_ANPKeyCode = 6,
- k0_ANPKeyCode = 7,
- k1_ANPKeyCode = 8,
- k2_ANPKeyCode = 9,
- k3_ANPKeyCode = 10,
- k4_ANPKeyCode = 11,
- k5_ANPKeyCode = 12,
- k6_ANPKeyCode = 13,
- k7_ANPKeyCode = 14,
- k8_ANPKeyCode = 15,
- k9_ANPKeyCode = 16,
- kStar_ANPKeyCode = 17,
- kPound_ANPKeyCode = 18,
- kDpadUp_ANPKeyCode = 19,
- kDpadDown_ANPKeyCode = 20,
- kDpadLeft_ANPKeyCode = 21,
- kDpadRight_ANPKeyCode = 22,
- kDpadCenter_ANPKeyCode = 23,
- kVolumeUp_ANPKeyCode = 24,
- kVolumeDown_ANPKeyCode = 25,
- kPower_ANPKeyCode = 26,
- kCamera_ANPKeyCode = 27,
- kClear_ANPKeyCode = 28,
- kA_ANPKeyCode = 29,
- kB_ANPKeyCode = 30,
- kC_ANPKeyCode = 31,
- kD_ANPKeyCode = 32,
- kE_ANPKeyCode = 33,
- kF_ANPKeyCode = 34,
- kG_ANPKeyCode = 35,
- kH_ANPKeyCode = 36,
- kI_ANPKeyCode = 37,
- kJ_ANPKeyCode = 38,
- kK_ANPKeyCode = 39,
- kL_ANPKeyCode = 40,
- kM_ANPKeyCode = 41,
- kN_ANPKeyCode = 42,
- kO_ANPKeyCode = 43,
- kP_ANPKeyCode = 44,
- kQ_ANPKeyCode = 45,
- kR_ANPKeyCode = 46,
- kS_ANPKeyCode = 47,
- kT_ANPKeyCode = 48,
- kU_ANPKeyCode = 49,
- kV_ANPKeyCode = 50,
- kW_ANPKeyCode = 51,
- kX_ANPKeyCode = 52,
- kY_ANPKeyCode = 53,
- kZ_ANPKeyCode = 54,
- kComma_ANPKeyCode = 55,
- kPeriod_ANPKeyCode = 56,
- kAltLeft_ANPKeyCode = 57,
- kAltRight_ANPKeyCode = 58,
- kShiftLeft_ANPKeyCode = 59,
- kShiftRight_ANPKeyCode = 60,
- kTab_ANPKeyCode = 61,
- kSpace_ANPKeyCode = 62,
- kSym_ANPKeyCode = 63,
- kExplorer_ANPKeyCode = 64,
- kEnvelope_ANPKeyCode = 65,
- kNewline_ANPKeyCode = 66,
- kDel_ANPKeyCode = 67,
- kGrave_ANPKeyCode = 68,
- kMinus_ANPKeyCode = 69,
- kEquals_ANPKeyCode = 70,
- kLeftBracket_ANPKeyCode = 71,
- kRightBracket_ANPKeyCode = 72,
- kBackslash_ANPKeyCode = 73,
- kSemicolon_ANPKeyCode = 74,
- kApostrophe_ANPKeyCode = 75,
- kSlash_ANPKeyCode = 76,
- kAt_ANPKeyCode = 77,
- kNum_ANPKeyCode = 78,
- kHeadSetHook_ANPKeyCode = 79,
- kFocus_ANPKeyCode = 80,
- kPlus_ANPKeyCode = 81,
- kMenu_ANPKeyCode = 82,
- kNotification_ANPKeyCode = 83,
- kSearch_ANPKeyCode = 84,
- kMediaPlayPause_ANPKeyCode = 85,
- kMediaStop_ANPKeyCode = 86,
- kMediaNext_ANPKeyCode = 87,
- kMediaPrevious_ANPKeyCode = 88,
- kMediaRewind_ANPKeyCode = 89,
- kMediaFastForward_ANPKeyCode = 90,
- kMute_ANPKeyCode = 91,
- kPageUp_ANPKeyCode = 92,
- kPageDown_ANPKeyCode = 93,
- kPictsymbols_ANPKeyCode = 94,
- kSwitchCharset_ANPKeyCode = 95,
- kButtonA_ANPKeyCode = 96,
- kButtonB_ANPKeyCode = 97,
- kButtonC_ANPKeyCode = 98,
- kButtonX_ANPKeyCode = 99,
- kButtonY_ANPKeyCode = 100,
- kButtonZ_ANPKeyCode = 101,
- kButtonL1_ANPKeyCode = 102,
- kButtonR1_ANPKeyCode = 103,
- kButtonL2_ANPKeyCode = 104,
- kButtonR2_ANPKeyCode = 105,
- kButtonThumbL_ANPKeyCode = 106,
- kButtonThumbR_ANPKeyCode = 107,
- kButtonStart_ANPKeyCode = 108,
- kButtonSelect_ANPKeyCode = 109,
- kButtonMode_ANPKeyCode = 110,
-
- // NOTE: If you add a new keycode here you must also add it to several other files.
- // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
-};
-
-#endif
diff --git a/dom/plugins/base/android/ANPLog.cpp b/dom/plugins/base/android/ANPLog.cpp
deleted file mode 100644
index 7ce13107b..000000000
--- a/dom/plugins/base/android/ANPLog.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- 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/. */
-
-#include "assert.h"
-#include "ANPBase.h"
-#include <android/log.h>
-
-#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
-#define ASSIGN(obj, name) (obj)->name = anp_log_##name
-
-void
-anp_log_log(ANPLogType type, const char format[], ...) {
-
- va_list argp;
- va_start(argp,format);
- __android_log_vprint(type == kError_ANPLogType ? ANDROID_LOG_ERROR : type == kWarning_ANPLogType ?
- ANDROID_LOG_WARN : ANDROID_LOG_INFO, "GeckoPluginLog", format, argp);
- va_end(argp);
-}
-
-void InitLogInterface(ANPLogInterfaceV0 *i) {
- _assert(i->inSize == sizeof(*i));
- ASSIGN(i, log);
-}
diff --git a/dom/plugins/base/android/ANPNativeWindow.cpp b/dom/plugins/base/android/ANPNativeWindow.cpp
deleted file mode 100644
index 88b43bd4a..000000000
--- a/dom/plugins/base/android/ANPNativeWindow.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- 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/. */
-
-// must include config.h first for webkit to fiddle with new/delete
-#include <android/log.h>
-#include "ANPBase.h"
-#include "nsIPluginInstanceOwner.h"
-#include "nsPluginInstanceOwner.h"
-#include "nsNPAPIPluginInstance.h"
-#include "gfxRect.h"
-
-using namespace mozilla;
-
-#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
-#define ASSIGN(obj, name) (obj)->name = anp_native_window_##name
-
-static ANPNativeWindow anp_native_window_acquireNativeWindow(NPP instance) {
- nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
- return pinst->AcquireContentWindow();
-}
-
-static void anp_native_window_invertPluginContent(NPP instance, bool isContentInverted) {
- // NativeWindow is TopLeft if uninverted.
- gl::OriginPos newOriginPos = gl::OriginPos::TopLeft;
- if (isContentInverted)
- newOriginPos = gl::OriginPos::BottomLeft;
-
- nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
- pinst->SetOriginPos(newOriginPos);
- pinst->RedrawPlugin();
-}
-
-
-void InitNativeWindowInterface(ANPNativeWindowInterfaceV0* i) {
- ASSIGN(i, acquireNativeWindow);
- ASSIGN(i, invertPluginContent);
-}
diff --git a/dom/plugins/base/android/ANPSurface.cpp b/dom/plugins/base/android/ANPSurface.cpp
deleted file mode 100644
index b6a699f28..000000000
--- a/dom/plugins/base/android/ANPSurface.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-/* -*- 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/. */
-
-#include <dlfcn.h>
-#include <android/log.h>
-#include "ANPBase.h"
-
-#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
-#define ASSIGN(obj, name) (obj)->name = anp_surface_##name
-
-#define CLEAR_EXCEPTION(env) if (env->ExceptionOccurred()) env->ExceptionClear();
-
-#define ANDROID_REGION_SIZE 512
-
-enum {
- PIXEL_FORMAT_RGBA_8888 = 1,
- PIXEL_FORMAT_RGB_565 = 4,
-};
-
-struct SurfaceInfo {
- uint32_t w;
- uint32_t h;
- uint32_t s;
- uint32_t usage;
- uint32_t format;
- unsigned char* bits;
- uint32_t reserved[2];
-};
-
-typedef struct ARect {
- int32_t left;
- int32_t top;
- int32_t right;
- int32_t bottom;
-} ARect;
-
-
-// used to cache JNI method and field IDs for Surface Objects
-static struct ANPSurfaceInterfaceJavaGlue {
- bool initialized;
- jmethodID getSurfaceHolder;
- jmethodID getSurface;
- jfieldID surfacePointer;
-} gSurfaceJavaGlue;
-
-static struct ANPSurfaceFunctions {
- bool initialized;
-
- int (* lock)(void*, SurfaceInfo*, void*);
- int (* unlockAndPost)(void*);
-
- void* (* regionConstructor)(void*);
- void (* setRegion)(void*, ARect const&);
-} gSurfaceFunctions;
-
-
-static inline void* getSurface(JNIEnv* env, jobject view) {
- if (!env || !view) {
- return nullptr;
- }
-
- if (!gSurfaceJavaGlue.initialized) {
-
- jclass surfaceViewClass = env->FindClass("android/view/SurfaceView");
- gSurfaceJavaGlue.getSurfaceHolder = env->GetMethodID(surfaceViewClass, "getHolder", "()Landroid/view/SurfaceHolder;");
-
- jclass surfaceHolderClass = env->FindClass("android/view/SurfaceHolder");
- gSurfaceJavaGlue.getSurface = env->GetMethodID(surfaceHolderClass, "getSurface", "()Landroid/view/Surface;");
-
- jclass surfaceClass = env->FindClass("android/view/Surface");
- gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
- "mSurfacePointer", "I");
-
- if (!gSurfaceJavaGlue.surfacePointer) {
- CLEAR_EXCEPTION(env);
-
- // It was something else in 2.2.
- gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
- "mSurface", "I");
-
- if (!gSurfaceJavaGlue.surfacePointer) {
- CLEAR_EXCEPTION(env);
-
- // And something else in 2.3+
- gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
- "mNativeSurface", "I");
-
- CLEAR_EXCEPTION(env);
- }
- }
-
- if (!gSurfaceJavaGlue.surfacePointer) {
- LOG("Failed to acquire surface pointer");
- return nullptr;
- }
-
- env->DeleteLocalRef(surfaceClass);
- env->DeleteLocalRef(surfaceViewClass);
- env->DeleteLocalRef(surfaceHolderClass);
-
- gSurfaceJavaGlue.initialized = (gSurfaceJavaGlue.surfacePointer != nullptr);
- }
-
- jobject holder = env->CallObjectMethod(view, gSurfaceJavaGlue.getSurfaceHolder);
- jobject surface = env->CallObjectMethod(holder, gSurfaceJavaGlue.getSurface);
- jint surfacePointer = env->GetIntField(surface, gSurfaceJavaGlue.surfacePointer);
-
- env->DeleteLocalRef(holder);
- env->DeleteLocalRef(surface);
-
- return (void*)surfacePointer;
-}
-
-static ANPBitmapFormat convertPixelFormat(int32_t format) {
- switch (format) {
- case PIXEL_FORMAT_RGBA_8888: return kRGBA_8888_ANPBitmapFormat;
- case PIXEL_FORMAT_RGB_565: return kRGB_565_ANPBitmapFormat;
- default: return kUnknown_ANPBitmapFormat;
- }
-}
-
-static int bytesPerPixel(int32_t format) {
- switch (format) {
- case PIXEL_FORMAT_RGBA_8888: return 4;
- case PIXEL_FORMAT_RGB_565: return 2;
- default: return -1;
- }
-}
-
-static bool init() {
- if (gSurfaceFunctions.initialized)
- return true;
-
- void* handle = dlopen("libsurfaceflinger_client.so", RTLD_LAZY);
-
- if (!handle) {
- LOG("Failed to open libsurfaceflinger_client.so");
- return false;
- }
-
- gSurfaceFunctions.lock = (int (*)(void*, SurfaceInfo*, void*))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionEb");
- gSurfaceFunctions.unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv");
-
-
- if (!gSurfaceFunctions.lock) {
- // Stuff changed in 3.0/4.0
- handle = dlopen("libgui.so", RTLD_LAZY);
- gSurfaceFunctions.lock = (int (*)(void*, SurfaceInfo*, void*))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionE");
- gSurfaceFunctions.unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv");
- }
-
- handle = dlopen("libui.so", RTLD_LAZY);
- if (!handle) {
- LOG("Failed to open libui.so");
- return false;
- }
-
- gSurfaceFunctions.regionConstructor = (void* (*)(void*))dlsym(handle, "_ZN7android6RegionC1Ev");
- gSurfaceFunctions.setRegion = (void (*)(void*, ARect const&))dlsym(handle, "_ZN7android6Region3setERKNS_4RectE");
-
- gSurfaceFunctions.initialized = (gSurfaceFunctions.lock && gSurfaceFunctions.unlockAndPost &&
- gSurfaceFunctions.regionConstructor && gSurfaceFunctions.setRegion);
- LOG("Initialized? %d\n", gSurfaceFunctions.initialized);
- return gSurfaceFunctions.initialized;
-}
-
-// FIXME: All of this should be changed to use the equivalent things in AndroidBridge, bug 758612
-static bool anp_surface_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) {
- if (!bitmap || !surfaceView) {
- return false;
- }
-
- void* surface = getSurface(env, surfaceView);
-
- if (!bitmap || !surface) {
- return false;
- }
-
- if (!init()) {
- return false;
- }
-
- void* region = nullptr;
- if (dirtyRect) {
- region = malloc(ANDROID_REGION_SIZE);
- gSurfaceFunctions.regionConstructor(region);
-
- ARect rect;
- rect.left = dirtyRect->left;
- rect.top = dirtyRect->top;
- rect.right = dirtyRect->right;
- rect.bottom = dirtyRect->bottom;
-
- gSurfaceFunctions.setRegion(region, rect);
- }
-
- SurfaceInfo info;
- int err = gSurfaceFunctions.lock(surface, &info, region);
- if (err < 0) {
- LOG("Failed to lock surface");
- return false;
- }
-
- // the surface may have expanded the dirty region so we must to pass that
- // information back to the plugin.
- if (dirtyRect) {
- ARect* dirtyBounds = (ARect*)region; // The bounds are the first member, so this should work!
-
- dirtyRect->left = dirtyBounds->left;
- dirtyRect->right = dirtyBounds->right;
- dirtyRect->top = dirtyBounds->top;
- dirtyRect->bottom = dirtyBounds->bottom;
- }
-
- if (region)
- free(region);
-
- int bpr = info.s * bytesPerPixel(info.format);
-
- bitmap->format = convertPixelFormat(info.format);
- bitmap->width = info.w;
- bitmap->height = info.h;
- bitmap->rowBytes = bpr;
-
- if (info.w > 0 && info.h > 0) {
- bitmap->baseAddr = info.bits;
- } else {
- bitmap->baseAddr = nullptr;
- return false;
- }
-
- return true;
-}
-
-static void anp_surface_unlock(JNIEnv* env, jobject surfaceView) {
- if (!surfaceView) {
- return;
- }
-
- if (!init()) {
- return;
- }
-
- void* surface = getSurface(env, surfaceView);
-
- if (!surface) {
- return;
- }
-
- gSurfaceFunctions.unlockAndPost(surface);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-void InitSurfaceInterface(ANPSurfaceInterfaceV0* i) {
- ASSIGN(i, lock);
- ASSIGN(i, unlock);
-
- // setup the java glue struct
- gSurfaceJavaGlue.initialized = false;
-
- // setup the function struct
- gSurfaceFunctions.initialized = false;
-}
diff --git a/dom/plugins/base/android/ANPSystem.cpp b/dom/plugins/base/android/ANPSystem.cpp
deleted file mode 100644
index d5b2a7710..000000000
--- a/dom/plugins/base/android/ANPSystem.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/* -*- 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/. */
-
-#include "base/basictypes.h"
-
-#include "ANPBase.h"
-#include "GeneratedJNIWrappers.h"
-#include "PluginPRLibrary.h"
-#include "assert.h"
-#include "nsNPAPIPluginInstance.h"
-#include "nsNPAPIPlugin.h"
-
-#include <android/log.h>
-
-#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
-#define ASSIGN(obj, name) (obj)->name = anp_system_##name
-
-const char*
-anp_system_getApplicationDataDirectory(NPP instance)
-{
- static const char *dir = nullptr;
- static const char *privateDir = nullptr;
-
- bool isPrivate = false;
-
- if (!dir) {
- dir = getenv("ANDROID_PLUGIN_DATADIR");
- }
-
- if (!privateDir) {
- privateDir = getenv("ANDROID_PLUGIN_DATADIR_PRIVATE");
- }
-
- if (!instance) {
- return dir;
- }
-
- nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
- if (pinst && NS_SUCCEEDED(pinst->IsPrivateBrowsing(&isPrivate)) && isPrivate) {
- return privateDir;
- }
-
- return dir;
-}
-
-const char*
-anp_system_getApplicationDataDirectory()
-{
- return anp_system_getApplicationDataDirectory(nullptr);
-}
-
-jclass anp_system_loadJavaClass(NPP instance, const char* className)
-{
- LOG("%s", __PRETTY_FUNCTION__);
-
- nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
- mozilla::PluginPRLibrary* lib = static_cast<mozilla::PluginPRLibrary*>(pinst->GetPlugin()->GetLibrary());
-
- nsCString libName;
- lib->GetLibraryPath(libName);
-
- return mozilla::java::GeckoAppShell::LoadPluginClass(className, libName).Forget();
-}
-
-void anp_system_setPowerState(NPP instance, ANPPowerState powerState)
-{
- nsNPAPIPluginInstance* pinst = nsNPAPIPluginInstance::GetFromNPP(instance);
-
- if (pinst) {
- pinst->SetWakeLock(powerState == kScreenOn_ANPPowerState);
- }
-}
-
-void InitSystemInterfaceV1(ANPSystemInterfaceV1 *i) {
- _assert(i->inSize == sizeof(*i));
- ASSIGN(i, getApplicationDataDirectory);
- ASSIGN(i, loadJavaClass);
- ASSIGN(i, setPowerState);
-}
-
-void InitSystemInterfaceV2(ANPSystemInterfaceV2 *i) {
- _assert(i->inSize == sizeof(*i));
- ASSIGN(i, getApplicationDataDirectory);
- ASSIGN(i, loadJavaClass);
- ASSIGN(i, setPowerState);
-}
diff --git a/dom/plugins/base/android/ANPVideo.cpp b/dom/plugins/base/android/ANPVideo.cpp
deleted file mode 100644
index 185ab1194..000000000
--- a/dom/plugins/base/android/ANPVideo.cpp
+++ /dev/null
@@ -1,55 +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 <android/log.h>
-#include "ANPBase.h"
-#include "nsIPluginInstanceOwner.h"
-#include "nsPluginInstanceOwner.h"
-#include "nsNPAPIPluginInstance.h"
-#include "gfxRect.h"
-
-#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
-#define ASSIGN(obj, name) (obj)->name = anp_video_##name
-
-using namespace mozilla;
-
-typedef nsNPAPIPluginInstance::VideoInfo VideoInfo;
-
-static ANPNativeWindow anp_video_acquireNativeWindow(NPP instance) {
- nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
-
- return pinst->AcquireVideoWindow();
-}
-
-static void anp_video_setWindowDimensions(NPP instance, const ANPNativeWindow window,
- const ANPRectF* dimensions) {
- nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
-
- gfxRect rect(dimensions->left, dimensions->top,
- dimensions->right - dimensions->left,
- dimensions->bottom - dimensions->top);
-
- pinst->SetVideoDimensions(window, rect);
- pinst->RedrawPlugin();
-}
-
-static void anp_video_releaseNativeWindow(NPP instance, ANPNativeWindow window) {
- nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
- pinst->ReleaseVideoWindow(window);
- pinst->RedrawPlugin();
-}
-
-static void anp_video_setFramerateCallback(NPP instance, const ANPNativeWindow window, ANPVideoFrameCallbackProc callback) {
- // Bug 722682
- NOT_IMPLEMENTED();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-void InitVideoInterfaceV1(ANPVideoInterfaceV1* i) {
- ASSIGN(i, acquireNativeWindow);
- ASSIGN(i, setWindowDimensions);
- ASSIGN(i, releaseNativeWindow);
- ASSIGN(i, setFramerateCallback);
-}
diff --git a/dom/plugins/base/android/ANPWindow.cpp b/dom/plugins/base/android/ANPWindow.cpp
deleted file mode 100644
index e9003aff5..000000000
--- a/dom/plugins/base/android/ANPWindow.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "base/basictypes.h"
-#include "assert.h"
-#include "ANPBase.h"
-#include <android/log.h>
-#include "nsNPAPIPluginInstance.h"
-#include "nsPluginInstanceOwner.h"
-#include "nsWindow.h"
-#include "mozilla/dom/ScreenOrientation.h"
-
-#undef LOG
-#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
-#define ASSIGN(obj, name) (obj)->name = anp_window_##name
-
-using namespace mozilla;
-using namespace mozilla::widget;
-using namespace mozilla::dom;
-
-void
-anp_window_setVisibleRects(NPP instance, const ANPRectI rects[], int32_t count)
-{
- NOT_IMPLEMENTED();
-}
-
-void
-anp_window_clearVisibleRects(NPP instance)
-{
- NOT_IMPLEMENTED();
-}
-
-void
-anp_window_showKeyboard(NPP instance, bool value)
-{
- InputContext context;
- context.mIMEState.mEnabled = value ? IMEState::PLUGIN : IMEState::DISABLED;
- context.mIMEState.mOpen = value ? IMEState::OPEN : IMEState::CLOSED;
- context.mActionHint.Assign(EmptyString());
-
- InputContextAction action;
- action.mCause = InputContextAction::CAUSE_UNKNOWN;
- action.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED;
-
- nsWindow* window = nsWindow::TopWindow();
- if (!window) {
- LOG("Couldn't get top window?");
- return;
- }
-
- window->SetInputContext(context, action);
-}
-
-void
-anp_window_requestFullScreen(NPP instance)
-{
- nsNPAPIPluginInstance* inst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
-
- RefPtr<nsPluginInstanceOwner> owner = inst->GetOwner();
- if (!owner) {
- return;
- }
-
- owner->RequestFullScreen();
-}
-
-void
-anp_window_exitFullScreen(NPP instance)
-{
- nsNPAPIPluginInstance* inst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
-
- RefPtr<nsPluginInstanceOwner> owner = inst->GetOwner();
- if (!owner) {
- return;
- }
-
- owner->ExitFullScreen();
-}
-
-void
-anp_window_requestCenterFitZoom(NPP instance)
-{
- NOT_IMPLEMENTED();
-}
-
-ANPRectI
-anp_window_visibleRect(NPP instance)
-{
- ANPRectI rect = { 0, 0, 0, 0 };
-
- nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
-
- nsIntSize currentSize = pinst->CurrentSize();
- rect.left = rect.top = 0;
- rect.right = currentSize.width;
- rect.bottom = currentSize.height;
-
- return rect;
-}
-
-void anp_window_requestFullScreenOrientation(NPP instance, ANPScreenOrientation orientation)
-{
- short newOrientation;
-
- // Convert to the ActivityInfo equivalent
- switch (orientation) {
- case kFixedLandscape_ANPScreenOrientation:
- newOrientation = eScreenOrientation_LandscapePrimary;
- break;
- case kFixedPortrait_ANPScreenOrientation:
- newOrientation = eScreenOrientation_PortraitPrimary;
- break;
- case kLandscape_ANPScreenOrientation:
- newOrientation = eScreenOrientation_LandscapePrimary |
- eScreenOrientation_LandscapeSecondary;
- break;
- case kPortrait_ANPScreenOrientation:
- newOrientation = eScreenOrientation_PortraitPrimary |
- eScreenOrientation_PortraitSecondary;
- break;
- default:
- newOrientation = eScreenOrientation_None;
- break;
- }
-
- nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
- pinst->SetFullScreenOrientation(newOrientation);
-}
-
-void InitWindowInterface(ANPWindowInterfaceV0 *i) {
- _assert(i->inSize == sizeof(*i));
- ASSIGN(i, setVisibleRects);
- ASSIGN(i, clearVisibleRects);
- ASSIGN(i, showKeyboard);
- ASSIGN(i, requestFullScreen);
- ASSIGN(i, exitFullScreen);
- ASSIGN(i, requestCenterFitZoom);
-}
-
-void InitWindowInterfaceV2(ANPWindowInterfaceV2 *i) {
- _assert(i->inSize == sizeof(*i));
- ASSIGN(i, setVisibleRects);
- ASSIGN(i, clearVisibleRects);
- ASSIGN(i, showKeyboard);
- ASSIGN(i, requestFullScreen);
- ASSIGN(i, exitFullScreen);
- ASSIGN(i, requestCenterFitZoom);
- ASSIGN(i, visibleRect);
- ASSIGN(i, requestFullScreenOrientation);
-}
diff --git a/dom/plugins/base/android/android_npapi.h b/dom/plugins/base/android/android_npapi.h
deleted file mode 100644
index 16463d799..000000000
--- a/dom/plugins/base/android/android_npapi.h
+++ /dev/null
@@ -1,1027 +0,0 @@
-/*
- * Copyright 2009, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/* Defines the android-specific types and functions as part of npapi
-
- In particular, defines the window and event types that are passed to
- NPN_GetValue, NPP_SetWindow and NPP_HandleEvent.
-
- To minimize what native libraries the plugin links against, some
- functionality is provided via function-ptrs (e.g. time, sound)
- */
-
-#ifndef android_npapi_H
-#define android_npapi_H
-
-#include <stdint.h>
-#include <jni.h>
-#include "npapi.h"
-#include "GLDefs.h"
-
-///////////////////////////////////////////////////////////////////////////////
-// General types
-
-enum ANPBitmapFormats {
- kUnknown_ANPBitmapFormat = 0,
- kRGBA_8888_ANPBitmapFormat = 1,
- kRGB_565_ANPBitmapFormat = 2
-};
-typedef int32_t ANPBitmapFormat;
-
-struct ANPPixelPacking {
- uint8_t AShift;
- uint8_t ABits;
- uint8_t RShift;
- uint8_t RBits;
- uint8_t GShift;
- uint8_t GBits;
- uint8_t BShift;
- uint8_t BBits;
-};
-
-struct ANPBitmap {
- void* baseAddr;
- ANPBitmapFormat format;
- int32_t width;
- int32_t height;
- int32_t rowBytes;
-};
-
-struct ANPRectF {
- float left;
- float top;
- float right;
- float bottom;
-};
-
-struct ANPRectI {
- int32_t left;
- int32_t top;
- int32_t right;
- int32_t bottom;
-};
-
-struct ANPCanvas;
-struct ANPMatrix;
-struct ANPPaint;
-struct ANPPath;
-struct ANPTypeface;
-
-///////////////////////////////////////////////////////////////////////////////
-// NPN_GetValue
-
-/** queries for a specific ANPInterface.
-
- Maybe called with NULL for the NPP instance
-
- NPN_GetValue(inst, interface_enum, ANPInterface*)
- */
-#define kLogInterfaceV0_ANPGetValue ((NPNVariable)1000)
-#define kAudioTrackInterfaceV0_ANPGetValue ((NPNVariable)1001)
-#define kCanvasInterfaceV0_ANPGetValue ((NPNVariable)1002)
-#define kMatrixInterfaceV0_ANPGetValue ((NPNVariable)1003)
-#define kPaintInterfaceV0_ANPGetValue ((NPNVariable)1004)
-#define kPathInterfaceV0_ANPGetValue ((NPNVariable)1005)
-#define kTypefaceInterfaceV0_ANPGetValue ((NPNVariable)1006)
-#define kWindowInterfaceV0_ANPGetValue ((NPNVariable)1007)
-#define kBitmapInterfaceV0_ANPGetValue ((NPNVariable)1008)
-#define kSurfaceInterfaceV0_ANPGetValue ((NPNVariable)1009)
-#define kSystemInterfaceV0_ANPGetValue ((NPNVariable)1010)
-#define kEventInterfaceV0_ANPGetValue ((NPNVariable)1011)
-
-#define kAudioTrackInterfaceV1_ANPGetValue ((NPNVariable)1012)
-#define kOpenGLInterfaceV0_ANPGetValue ((NPNVariable)1013)
-#define kWindowInterfaceV1_ANPGetValue ((NPNVariable)1014)
-#define kVideoInterfaceV0_ANPGetValue ((NPNVariable)1015)
-#define kSystemInterfaceV1_ANPGetValue ((NPNVariable)1016)
-#define kSystemInterfaceV2_ANPGetValue ((NPNVariable)1017)
-#define kWindowInterfaceV2_ANPGetValue ((NPNVariable)1018)
-#define kNativeWindowInterfaceV0_ANPGetValue ((NPNVariable)1019)
-#define kVideoInterfaceV1_ANPGetValue ((NPNVariable)1020)
-
-/** queries for the drawing models supported on this device.
-
- NPN_GetValue(inst, kSupportedDrawingModel_ANPGetValue, uint32_t* bits)
- */
-#define kSupportedDrawingModel_ANPGetValue ((NPNVariable)2000)
-
-/** queries for the context (android.content.Context) of the plugin. If no
- instance is specified the application's context is returned. If the instance
- is given then the context returned is identical to the context used to
- create the webview in which that instance resides.
-
- NOTE: Holding onto a non-application context after your instance has been
- destroyed will cause a memory leak. Refer to the android documentation to
- determine what context is best suited for your particular scenario.
-
- NPN_GetValue(inst, kJavaContext_ANPGetValue, jobject context)
- */
-#define kJavaContext_ANPGetValue ((NPNVariable)2001)
-
-///////////////////////////////////////////////////////////////////////////////
-// NPN_SetValue
-
-/** Request to set the drawing model. SetValue will return false if the drawing
- model is not supported or has insufficient information for configuration.
-
- NPN_SetValue(inst, kRequestDrawingModel_ANPSetValue, (void*)foo_ANPDrawingModel)
- */
-#define kRequestDrawingModel_ANPSetValue ((NPPVariable)1000)
-
-/** These are used as bitfields in ANPSupportedDrawingModels_EnumValue,
- and as-is in ANPRequestDrawingModel_EnumValue. The drawing model determines
- how to interpret the ANPDrawingContext provided in the Draw event and how
- to interpret the NPWindow->window field.
- */
-enum ANPDrawingModels {
- /** Draw into a bitmap from the browser thread in response to a Draw event.
- NPWindow->window is reserved (ignore)
- */
- kBitmap_ANPDrawingModel = 1 << 0,
- /** Draw into a surface (e.g. raster, openGL, etc.) using the Java surface
- interface. When this model is used the browser will invoke the Java
- class specified in the plugin's apk manifest. From that class the browser
- will invoke the appropriate method to return an an instance of a android
- Java View. The instance is then embedded in the html. The plugin can then
- manipulate the view as it would any normal Java View in android.
-
- Unlike the bitmap model, a surface model is opaque so no html content
- behind the plugin will be visible. Unless the plugin needs to be
- transparent the surface model should be chosen over the bitmap model as
- it will have better performance.
-
- Further, a plugin can manipulate some surfaces in native code using the
- ANPSurfaceInterface. This interface can be used to manipulate Java
- objects that extend Surface.class by allowing them to access the
- surface's underlying bitmap in native code. For instance, if a raster
- surface is used the plugin can lock, draw directly into the bitmap, and
- unlock the surface in native code without making JNI calls to the Java
- surface object.
- */
- kSurface_ANPDrawingModel = 1 << 1,
- kOpenGL_ANPDrawingModel = 1 << 2,
-};
-typedef int32_t ANPDrawingModel;
-
-/** Request to receive/disable events. If the pointer is NULL then all flags will
- be disabled. Otherwise, the event type will be enabled iff its corresponding
- bit in the EventFlags bit field is set.
-
- NPN_SetValue(inst, ANPAcceptEvents, (void*)EventFlags)
- */
-#define kAcceptEvents_ANPSetValue ((NPPVariable)1001)
-
-/** The EventFlags are a set of bits used to determine which types of events the
- plugin wishes to receive. For example, if the value is 0x03 then both key
- and touch events will be provided to the plugin.
- */
-enum ANPEventFlag {
- kKey_ANPEventFlag = 0x01,
- kTouch_ANPEventFlag = 0x02,
-};
-typedef uint32_t ANPEventFlags;
-
-///////////////////////////////////////////////////////////////////////////////
-// NPP_GetValue
-
-/** Requests that the plugin return a java surface to be displayed. This will
- only be used if the plugin has choosen the kSurface_ANPDrawingModel.
-
- NPP_GetValue(inst, kJavaSurface_ANPGetValue, jobject surface)
- */
-#define kJavaSurface_ANPGetValue ((NPPVariable)2000)
-
-
-///////////////////////////////////////////////////////////////////////////////
-// ANDROID INTERFACE DEFINITIONS
-
-/** Interfaces provide additional functionality to the plugin via function ptrs.
- Once an interface is retrieved, it is valid for the lifetime of the plugin
- (just like browserfuncs).
-
- All ANPInterfaces begin with an inSize field, which must be set by the
- caller (plugin) with the number of bytes allocated for the interface.
- e.g. SomeInterface si; si.inSize = sizeof(si); browser->getvalue(..., &si);
- */
-struct ANPInterface {
- uint32_t inSize; // size (in bytes) of this struct
-};
-
-enum ANPLogTypes {
- kError_ANPLogType = 0, // error
- kWarning_ANPLogType = 1, // warning
- kDebug_ANPLogType = 2 // debug only (informational)
-};
-typedef int32_t ANPLogType;
-
-struct ANPLogInterfaceV0 : ANPInterface {
- /** dumps printf messages to the log file
- e.g. interface->log(instance, kWarning_ANPLogType, "value is %d", value);
- */
- void (*log)(ANPLogType, const char format[], ...);
-};
-
-/** ANPColor is always defined to have the same packing on all platforms, and
- it is always unpremultiplied.
-
- This is in contrast to 32bit format(s) in bitmaps, which are premultiplied,
- and their packing may vary depending on the platform, hence the need for
- ANPBitmapInterface::getPixelPacking()
- */
-typedef uint32_t ANPColor;
-#define ANPColor_ASHIFT 24
-#define ANPColor_RSHIFT 16
-#define ANPColor_GSHIFT 8
-#define ANPColor_BSHIFT 0
-#define ANP_MAKE_COLOR(a, r, g, b) \
- (((a) << ANPColor_ASHIFT) | \
- ((r) << ANPColor_RSHIFT) | \
- ((g) << ANPColor_GSHIFT) | \
- ((b) << ANPColor_BSHIFT))
-
-enum ANPPaintFlag {
- kAntiAlias_ANPPaintFlag = 1 << 0,
- kFilterBitmap_ANPPaintFlag = 1 << 1,
- kDither_ANPPaintFlag = 1 << 2,
- kUnderlineText_ANPPaintFlag = 1 << 3,
- kStrikeThruText_ANPPaintFlag = 1 << 4,
- kFakeBoldText_ANPPaintFlag = 1 << 5,
-};
-typedef uint32_t ANPPaintFlags;
-
-enum ANPPaintStyles {
- kFill_ANPPaintStyle = 0,
- kStroke_ANPPaintStyle = 1,
- kFillAndStroke_ANPPaintStyle = 2
-};
-typedef int32_t ANPPaintStyle;
-
-enum ANPPaintCaps {
- kButt_ANPPaintCap = 0,
- kRound_ANPPaintCap = 1,
- kSquare_ANPPaintCap = 2
-};
-typedef int32_t ANPPaintCap;
-
-enum ANPPaintJoins {
- kMiter_ANPPaintJoin = 0,
- kRound_ANPPaintJoin = 1,
- kBevel_ANPPaintJoin = 2
-};
-typedef int32_t ANPPaintJoin;
-
-enum ANPPaintAligns {
- kLeft_ANPPaintAlign = 0,
- kCenter_ANPPaintAlign = 1,
- kRight_ANPPaintAlign = 2
-};
-typedef int32_t ANPPaintAlign;
-
-enum ANPTextEncodings {
- kUTF8_ANPTextEncoding = 0,
- kUTF16_ANPTextEncoding = 1,
-};
-typedef int32_t ANPTextEncoding;
-
-enum ANPTypefaceStyles {
- kBold_ANPTypefaceStyle = 1 << 0,
- kItalic_ANPTypefaceStyle = 1 << 1
-};
-typedef uint32_t ANPTypefaceStyle;
-
-typedef uint32_t ANPFontTableTag;
-
-struct ANPFontMetrics {
- /** The greatest distance above the baseline for any glyph (will be <= 0) */
- float fTop;
- /** The recommended distance above the baseline (will be <= 0) */
- float fAscent;
- /** The recommended distance below the baseline (will be >= 0) */
- float fDescent;
- /** The greatest distance below the baseline for any glyph (will be >= 0) */
- float fBottom;
- /** The recommended distance to add between lines of text (will be >= 0) */
- float fLeading;
-};
-
-struct ANPTypefaceInterfaceV0 : ANPInterface {
- /** Return a new reference to the typeface that most closely matches the
- requested name and style. Pass null as the name to return
- the default font for the requested style. Will never return null
-
- The 5 generic font names "serif", "sans-serif", "monospace", "cursive",
- "fantasy" are recognized, and will be mapped to their logical font
- automatically by this call.
-
- @param name May be NULL. The name of the font family.
- @param style The style (normal, bold, italic) of the typeface.
- @return reference to the closest-matching typeface. Caller must call
- unref() when they are done with the typeface.
- */
- ANPTypeface* (*createFromName)(const char name[], ANPTypefaceStyle);
-
- /** Return a new reference to the typeface that most closely matches the
- requested typeface and specified Style. Use this call if you want to
- pick a new style from the same family of the existing typeface.
- If family is NULL, this selects from the default font's family.
-
- @param family May be NULL. The name of the existing type face.
- @param s The style (normal, bold, italic) of the type face.
- @return reference to the closest-matching typeface. Call must call
- unref() when they are done.
- */
- ANPTypeface* (*createFromTypeface)(const ANPTypeface* family,
- ANPTypefaceStyle);
-
- /** Return the owner count of the typeface. A newly created typeface has an
- owner count of 1. When the owner count is reaches 0, the typeface is
- deleted.
- */
- int32_t (*getRefCount)(const ANPTypeface*);
-
- /** Increment the owner count on the typeface
- */
- void (*ref)(ANPTypeface*);
-
- /** Decrement the owner count on the typeface. When the count goes to 0,
- the typeface is deleted.
- */
- void (*unref)(ANPTypeface*);
-
- /** Return the style bits for the specified typeface
- */
- ANPTypefaceStyle (*getStyle)(const ANPTypeface*);
-
- /** Some fonts are stored in files. If that is true for the fontID, then
- this returns the byte length of the full file path. If path is not null,
- then the full path is copied into path (allocated by the caller), up to
- length bytes. If index is not null, then it is set to the truetype
- collection index for this font, or 0 if the font is not in a collection.
-
- Note: getFontPath does not assume that path is a null-terminated string,
- so when it succeeds, it only copies the bytes of the file name and
- nothing else (i.e. it copies exactly the number of bytes returned by the
- function. If the caller wants to treat path[] as a C string, it must be
- sure that it is allocated at least 1 byte larger than the returned size,
- and it must copy in the terminating 0.
-
- If the fontID does not correspond to a file, then the function returns
- 0, and the path and index parameters are ignored.
-
- @param fontID The font whose file name is being queried
- @param path Either NULL, or storage for receiving up to length bytes
- of the font's file name. Allocated by the caller.
- @param length The maximum space allocated in path (by the caller).
- Ignored if path is NULL.
- @param index Either NULL, or receives the TTC index for this font.
- If the font is not a TTC, then will be set to 0.
- @return The byte length of th font's file name, or 0 if the font is not
- baked by a file.
- */
- int32_t (*getFontPath)(const ANPTypeface*, char path[], int32_t length,
- int32_t* index);
-
- /** Return a UTF8 encoded path name for the font directory, or NULL if not
- supported. If returned, this string address will be valid for the life
- of the plugin instance. It will always end with a '/' character.
- */
- const char* (*getFontDirectoryPath)();
-};
-
-struct ANPPaintInterfaceV0 : ANPInterface {
- /** Return a new paint object, which holds all of the color and style
- attributes that affect how things (geometry, text, bitmaps) are drawn
- in a ANPCanvas.
-
- The paint that is returned is not tied to any particular plugin
- instance, but it must only be accessed from one thread at a time.
- */
- ANPPaint* (*newPaint)();
- void (*deletePaint)(ANPPaint*);
-
- ANPPaintFlags (*getFlags)(const ANPPaint*);
- void (*setFlags)(ANPPaint*, ANPPaintFlags);
-
- ANPColor (*getColor)(const ANPPaint*);
- void (*setColor)(ANPPaint*, ANPColor);
-
- ANPPaintStyle (*getStyle)(const ANPPaint*);
- void (*setStyle)(ANPPaint*, ANPPaintStyle);
-
- float (*getStrokeWidth)(const ANPPaint*);
- float (*getStrokeMiter)(const ANPPaint*);
- ANPPaintCap (*getStrokeCap)(const ANPPaint*);
- ANPPaintJoin (*getStrokeJoin)(const ANPPaint*);
- void (*setStrokeWidth)(ANPPaint*, float);
- void (*setStrokeMiter)(ANPPaint*, float);
- void (*setStrokeCap)(ANPPaint*, ANPPaintCap);
- void (*setStrokeJoin)(ANPPaint*, ANPPaintJoin);
-
- ANPTextEncoding (*getTextEncoding)(const ANPPaint*);
- ANPPaintAlign (*getTextAlign)(const ANPPaint*);
- float (*getTextSize)(const ANPPaint*);
- float (*getTextScaleX)(const ANPPaint*);
- float (*getTextSkewX)(const ANPPaint*);
- void (*setTextEncoding)(ANPPaint*, ANPTextEncoding);
- void (*setTextAlign)(ANPPaint*, ANPPaintAlign);
- void (*setTextSize)(ANPPaint*, float);
- void (*setTextScaleX)(ANPPaint*, float);
- void (*setTextSkewX)(ANPPaint*, float);
-
- /** Return the typeface ine paint, or null if there is none. This does not
- modify the owner count of the returned typeface.
- */
- ANPTypeface* (*getTypeface)(const ANPPaint*);
-
- /** Set the paint's typeface. If the paint already had a non-null typeface,
- its owner count is decremented. If the new typeface is non-null, its
- owner count is incremented.
- */
- void (*setTypeface)(ANPPaint*, ANPTypeface*);
-
- /** Return the width of the text. If bounds is not null, return the bounds
- of the text in that rectangle.
- */
- float (*measureText)(ANPPaint*, const void* text, uint32_t byteLength,
- ANPRectF* bounds);
-
- /** Return the number of unichars specifed by the text.
- If widths is not null, returns the array of advance widths for each
- unichar.
- If bounds is not null, returns the array of bounds for each unichar.
- */
- int (*getTextWidths)(ANPPaint*, const void* text, uint32_t byteLength,
- float widths[], ANPRectF bounds[]);
-
- /** Return in metrics the spacing values for text, respecting the paint's
- typeface and pointsize, and return the spacing between lines
- (descent - ascent + leading). If metrics is NULL, it will be ignored.
- */
- float (*getFontMetrics)(ANPPaint*, ANPFontMetrics* metrics);
-};
-
-struct ANPCanvasInterfaceV0 : ANPInterface {
- /** Return a canvas that will draw into the specified bitmap. Note: the
- canvas copies the fields of the bitmap, so it need not persist after
- this call, but the canvas DOES point to the same pixel memory that the
- bitmap did, so the canvas should not be used after that pixel memory
- goes out of scope. In the case of creating a canvas to draw into the
- pixels provided by kDraw_ANPEventType, those pixels are only while
- handling that event.
-
- The canvas that is returned is not tied to any particular plugin
- instance, but it must only be accessed from one thread at a time.
- */
- ANPCanvas* (*newCanvas)(const ANPBitmap*);
- void (*deleteCanvas)(ANPCanvas*);
-
- void (*save)(ANPCanvas*);
- void (*restore)(ANPCanvas*);
- void (*translate)(ANPCanvas*, float tx, float ty);
- void (*scale)(ANPCanvas*, float sx, float sy);
- void (*rotate)(ANPCanvas*, float degrees);
- void (*skew)(ANPCanvas*, float kx, float ky);
- void (*concat)(ANPCanvas*, const ANPMatrix*);
- void (*clipRect)(ANPCanvas*, const ANPRectF*);
- void (*clipPath)(ANPCanvas*, const ANPPath*);
-
- /** Return the current matrix on the canvas
- */
- void (*getTotalMatrix)(ANPCanvas*, ANPMatrix*);
- /** Return the current clip bounds in local coordinates, expanding it to
- account for antialiasing edge effects if aa is true. If the
- current clip is empty, return false and ignore the bounds argument.
- */
- bool (*getLocalClipBounds)(ANPCanvas*, ANPRectF* bounds, bool aa);
- /** Return the current clip bounds in device coordinates in bounds. If the
- current clip is empty, return false and ignore the bounds argument.
- */
- bool (*getDeviceClipBounds)(ANPCanvas*, ANPRectI* bounds);
-
- void (*drawColor)(ANPCanvas*, ANPColor);
- void (*drawPaint)(ANPCanvas*, const ANPPaint*);
- void (*drawLine)(ANPCanvas*, float x0, float y0, float x1, float y1,
- const ANPPaint*);
- void (*drawRect)(ANPCanvas*, const ANPRectF*, const ANPPaint*);
- void (*drawOval)(ANPCanvas*, const ANPRectF*, const ANPPaint*);
- void (*drawPath)(ANPCanvas*, const ANPPath*, const ANPPaint*);
- void (*drawText)(ANPCanvas*, const void* text, uint32_t byteLength,
- float x, float y, const ANPPaint*);
- void (*drawPosText)(ANPCanvas*, const void* text, uint32_t byteLength,
- const float xy[], const ANPPaint*);
- void (*drawBitmap)(ANPCanvas*, const ANPBitmap*, float x, float y,
- const ANPPaint*);
- void (*drawBitmapRect)(ANPCanvas*, const ANPBitmap*,
- const ANPRectI* src, const ANPRectF* dst,
- const ANPPaint*);
-};
-
-struct ANPWindowInterfaceV0 : ANPInterface {
- /** Registers a set of rectangles that the plugin would like to keep on
- screen. The rectangles are listed in order of priority with the highest
- priority rectangle in location rects[0]. The browser will attempt to keep
- as many of the rectangles on screen as possible and will scroll them into
- view in response to the invocation of this method and other various events.
- The count specifies how many rectangles are in the array. If the count is
- zero it signals the browser that any existing rectangles should be cleared
- and no rectangles will be tracked.
- */
- void (*setVisibleRects)(NPP instance, const ANPRectI rects[], int32_t count);
- /** Clears any rectangles that are being tracked as a result of a call to
- setVisibleRects. This call is equivalent to setVisibleRect(inst, NULL, 0).
- */
- void (*clearVisibleRects)(NPP instance);
- /** Given a boolean value of true the device will be requested to provide
- a keyboard. A value of false will result in a request to hide the
- keyboard. Further, the on-screen keyboard will not be displayed if a
- physical keyboard is active.
- */
- void (*showKeyboard)(NPP instance, bool value);
- /** Called when a plugin wishes to enter into full screen mode. The plugin's
- Java class (defined in the plugin's apk manifest) will be called
- asynchronously to provide a View object to be displayed full screen.
- */
- void (*requestFullScreen)(NPP instance);
- /** Called when a plugin wishes to exit from full screen mode. As a result,
- the plugin's full screen view will be discarded by the view system.
- */
- void (*exitFullScreen)(NPP instance);
- /** Called when a plugin wishes to be zoomed and centered in the current view.
- */
- void (*requestCenterFitZoom)(NPP instance);
-};
-
-enum ANPScreenOrientations {
- /** No preference specified: let the system decide the best orientation.
- */
- kDefault_ANPScreenOrientation = 0,
- /** Would like to have the screen in a landscape orientation, but it will
- not allow for 180 degree rotations.
- */
- kFixedLandscape_ANPScreenOrientation = 1,
- /** Would like to have the screen in a portrait orientation, but it will
- not allow for 180 degree rotations.
- */
- kFixedPortrait_ANPScreenOrientation = 2,
- /** Would like to have the screen in landscape orientation, but can use the
- sensor to change which direction the screen is facing.
- */
- kLandscape_ANPScreenOrientation = 3,
- /** Would like to have the screen in portrait orientation, but can use the
- sensor to change which direction the screen is facing.
- */
- kPortrait_ANPScreenOrientation = 4
-};
-
-typedef int32_t ANPScreenOrientation;
-
-struct ANPWindowInterfaceV2 : ANPWindowInterfaceV0 {
- /** Returns a rectangle representing the visible area of the plugin on
- screen. The coordinates are relative to the size of the plugin in the
- document and therefore will never be negative or exceed the plugin's size.
- */
- ANPRectI (*visibleRect)(NPP instance);
-
- /** Called when the plugin wants to specify a particular screen orientation
- when entering into full screen mode. The orientation must be set prior
- to entering into full screen. After entering full screen any subsequent
- changes will be updated the next time the plugin goes full screen.
- */
- void (*requestFullScreenOrientation)(NPP instance, ANPScreenOrientation orientation);
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-enum ANPSampleFormats {
- kUnknown_ANPSamleFormat = 0,
- kPCM16Bit_ANPSampleFormat = 1,
- kPCM8Bit_ANPSampleFormat = 2
-};
-typedef int32_t ANPSampleFormat;
-
-/** The audio buffer is passed to the callback proc to request more samples.
- It is owned by the system, and the callback may read it, but should not
- maintain a pointer to it outside of the scope of the callback proc.
- */
-struct ANPAudioBuffer {
- // RO - repeat what was specified in newTrack()
- int32_t channelCount;
- // RO - repeat what was specified in newTrack()
- ANPSampleFormat format;
- /** This buffer is owned by the caller. Inside the callback proc, up to
- "size" bytes of sample data should be written into this buffer. The
- address is only valid for the scope of a single invocation of the
- callback proc.
- */
- void* bufferData;
- /** On input, specifies the maximum number of bytes that can be written
- to "bufferData". On output, specifies the actual number of bytes that
- the callback proc wrote into "bufferData".
- */
- uint32_t size;
-};
-
-enum ANPAudioEvents {
- /** This event is passed to the callback proc when the audio-track needs
- more sample data written to the provided buffer parameter.
- */
- kMoreData_ANPAudioEvent = 0,
- /** This event is passed to the callback proc if the audio system runs out
- of sample data. In this event, no buffer parameter will be specified
- (i.e. NULL will be passed to the 3rd parameter).
- */
- kUnderRun_ANPAudioEvent = 1
-};
-typedef int32_t ANPAudioEvent;
-
-/** Called to feed sample data to the track. This will be called in a separate
- thread. However, you may call trackStop() from the callback (but you
- cannot delete the track).
-
- For example, when you have written the last chunk of sample data, you can
- immediately call trackStop(). This will take effect after the current
- buffer has been played.
-
- The "user" parameter is the same value that was passed to newTrack()
- */
-typedef void (*ANPAudioCallbackProc)(ANPAudioEvent event, void* user,
- ANPAudioBuffer* buffer);
-
-struct ANPAudioTrack; // abstract type for audio tracks
-
-struct ANPAudioTrackInterfaceV0 : ANPInterface {
- /** Create a new audio track, or NULL on failure. The track is initially in
- the stopped state and therefore ANPAudioCallbackProc will not be called
- until the track is started.
- */
- ANPAudioTrack* (*newTrack)(uint32_t sampleRate, // sampling rate in Hz
- ANPSampleFormat,
- int channelCount, // MONO=1, STEREO=2
- ANPAudioCallbackProc,
- void* user);
- /** Deletes a track that was created using newTrack. The track can be
- deleted in any state and it waits for the ANPAudioCallbackProc thread
- to exit before returning.
- */
- void (*deleteTrack)(ANPAudioTrack*);
-
- void (*start)(ANPAudioTrack*);
- void (*pause)(ANPAudioTrack*);
- void (*stop)(ANPAudioTrack*);
- /** Returns true if the track is not playing (e.g. pause or stop was called,
- or start was never called.
- */
- bool (*isStopped)(ANPAudioTrack*);
-};
-
-struct ANPAudioTrackInterfaceV1 : ANPAudioTrackInterfaceV0 {
- /** Returns the track's latency in milliseconds. */
- uint32_t (*trackLatency)(ANPAudioTrack*);
-};
-
-
-///////////////////////////////////////////////////////////////////////////////
-// DEFINITION OF VALUES PASSED THROUGH NPP_HandleEvent
-
-enum ANPEventTypes {
- kNull_ANPEventType = 0,
- kKey_ANPEventType = 1,
- /** Mouse events are triggered by either clicking with the navigational pad
- or by tapping the touchscreen (if the kDown_ANPTouchAction is handled by
- the plugin then no mouse event is generated). The kKey_ANPEventFlag has
- to be set to true in order to receive these events.
- */
- kMouse_ANPEventType = 2,
- /** Touch events are generated when the user touches on the screen. The
- kTouch_ANPEventFlag has to be set to true in order to receive these
- events.
- */
- kTouch_ANPEventType = 3,
- /** Only triggered by a plugin using the kBitmap_ANPDrawingModel. This event
- signals that the plugin needs to redraw itself into the provided bitmap.
- */
- kDraw_ANPEventType = 4,
- kLifecycle_ANPEventType = 5,
-
- /** This event type is completely defined by the plugin.
- When creating an event, the caller must always set the first
- two fields, the remaining data is optional.
- ANPEvent evt;
- evt.inSize = sizeof(ANPEvent);
- evt.eventType = kCustom_ANPEventType
- // other data slots are optional
- evt.other[] = ...;
- To post a copy of the event, call
- eventInterface->postEvent(myNPPInstance, &evt);
- That call makes a copy of the event struct, and post that on the event
- queue for the plugin.
- */
- kCustom_ANPEventType = 6,
-};
-typedef int32_t ANPEventType;
-
-enum ANPKeyActions {
- kDown_ANPKeyAction = 0,
- kUp_ANPKeyAction = 1,
-};
-typedef int32_t ANPKeyAction;
-
-#include "ANPKeyCodes.h"
-typedef int32_t ANPKeyCode;
-
-enum ANPKeyModifiers {
- kAlt_ANPKeyModifier = 1 << 0,
- kShift_ANPKeyModifier = 1 << 1,
-};
-// bit-field containing some number of ANPKeyModifier bits
-typedef uint32_t ANPKeyModifier;
-
-enum ANPMouseActions {
- kDown_ANPMouseAction = 0,
- kUp_ANPMouseAction = 1,
-};
-typedef int32_t ANPMouseAction;
-
-enum ANPTouchActions {
- /** This occurs when the user first touches on the screen. As such, this
- action will always occur prior to any of the other touch actions. If
- the plugin chooses to not handle this action then no other events
- related to that particular touch gesture will be generated.
- */
- kDown_ANPTouchAction = 0,
- kUp_ANPTouchAction = 1,
- kMove_ANPTouchAction = 2,
- kCancel_ANPTouchAction = 3,
- // The web view will ignore the return value from the following actions
- kLongPress_ANPTouchAction = 4,
- kDoubleTap_ANPTouchAction = 5,
-};
-typedef int32_t ANPTouchAction;
-
-enum ANPLifecycleActions {
- /** The web view containing this plugin has been paused. See documentation
- on the android activity lifecycle for more information.
- */
- kPause_ANPLifecycleAction = 0,
- /** The web view containing this plugin has been resumed. See documentation
- on the android activity lifecycle for more information.
- */
- kResume_ANPLifecycleAction = 1,
- /** The plugin has focus and is now the recipient of input events (e.g. key,
- touch, etc.)
- */
- kGainFocus_ANPLifecycleAction = 2,
- /** The plugin has lost focus and will not receive any input events until it
- regains focus. This event is always preceded by a GainFocus action.
- */
- kLoseFocus_ANPLifecycleAction = 3,
- /** The browser is running low on available memory and is requesting that
- the plugin free any unused/inactive resources to prevent a performance
- degradation.
- */
- kFreeMemory_ANPLifecycleAction = 4,
- /** The page has finished loading. This happens when the page's top level
- frame reports that it has completed loading.
- */
- kOnLoad_ANPLifecycleAction = 5,
- /** The browser is honoring the plugin's request to go full screen. Upon
- returning from this event the browser will resize the plugin's java
- surface to full-screen coordinates.
- */
- kEnterFullScreen_ANPLifecycleAction = 6,
- /** The browser has exited from full screen mode. Immediately prior to
- sending this event the browser has resized the plugin's java surface to
- its original coordinates.
- */
- kExitFullScreen_ANPLifecycleAction = 7,
- /** The plugin is visible to the user on the screen. This event will always
- occur after a kOffScreen_ANPLifecycleAction event.
- */
- kOnScreen_ANPLifecycleAction = 8,
- /** The plugin is no longer visible to the user on the screen. This event
- will always occur prior to an kOnScreen_ANPLifecycleAction event.
- */
- kOffScreen_ANPLifecycleAction = 9,
-};
-typedef uint32_t ANPLifecycleAction;
-
-/* This is what is passed to NPP_HandleEvent() */
-struct ANPEvent {
- uint32_t inSize; // size of this struct in bytes
- ANPEventType eventType;
- // use based on the value in eventType
- union {
- struct {
- ANPKeyAction action;
- ANPKeyCode nativeCode;
- int32_t virtualCode; // windows virtual key code
- ANPKeyModifier modifiers;
- int32_t repeatCount; // 0 for initial down (or up)
- int32_t unichar; // 0 if there is no value
- } key;
- struct {
- ANPMouseAction action;
- int32_t x; // relative to your "window" (0...width)
- int32_t y; // relative to your "window" (0...height)
- } mouse;
- struct {
- ANPTouchAction action;
- ANPKeyModifier modifiers;
- int32_t x; // relative to your "window" (0...width)
- int32_t y; // relative to your "window" (0...height)
- } touch;
- struct {
- ANPLifecycleAction action;
- } lifecycle;
- struct {
- ANPDrawingModel model;
- // relative to (0,0) in top-left of your plugin
- ANPRectI clip;
- // use based on the value in model
- union {
- ANPBitmap bitmap;
- struct {
- int32_t width;
- int32_t height;
- } surfaceSize;
- } data;
- } draw;
- } data;
-};
-
-
-struct ANPEventInterfaceV0 : ANPInterface {
- /** Post a copy of the specified event to the plugin. The event will be
- delivered to the plugin in its main thread (the thread that receives
- other ANPEvents). If, after posting before delivery, the NPP instance
- is torn down, the event will be discarded.
- */
- void (*postEvent)(NPP inst, const ANPEvent* event);
-};
-
-struct ANPSurfaceInterfaceV0 : ANPInterface {
- /** Locks the surface from manipulation by other threads and provides a bitmap
- to be written to. The dirtyRect param specifies which portion of the
- bitmap will be written to. If the dirtyRect is NULL then the entire
- surface will be considered dirty. If the lock was successful the function
- will return true and the bitmap will be set to point to a valid bitmap.
- If not the function will return false and the bitmap will be set to NULL.
- */
- bool (*lock)(JNIEnv* env, jobject surface, ANPBitmap* bitmap, ANPRectI* dirtyRect);
- /** Given a locked surface handle (i.e. result of a successful call to lock)
- the surface is unlocked and the contents of the bitmap, specifically
- those inside the dirtyRect are written to the screen.
- */
- void (*unlock)(JNIEnv* env, jobject surface);
-};
-
-/**
- * TODO should we not use EGL and GL data types for ABI safety?
- */
-struct ANPTextureInfo {
- GLuint textureId;
- uint32_t width;
- uint32_t height;
- GLenum internalFormat;
-};
-
-typedef void* ANPEGLContext;
-
-struct ANPOpenGLInterfaceV0 : ANPInterface {
- ANPEGLContext (*acquireContext)(NPP instance);
-
- ANPTextureInfo (*lockTexture)(NPP instance);
-
- void (*releaseTexture)(NPP instance, const ANPTextureInfo*);
-
- /**
- * Invert the contents of the plugin on the y-axis.
- * default is to not be inverted (i.e. use OpenGL coordinates)
- */
- void (*invertPluginContent)(NPP instance, bool isContentInverted);
-};
-
-enum ANPPowerStates {
- kDefault_ANPPowerState = 0,
- kScreenOn_ANPPowerState = 1
-};
-typedef int32_t ANPPowerState;
-
-struct ANPSystemInterfaceV1 : ANPInterface {
- /** Return the path name for the current Application's plugin data directory,
- or NULL if not supported
- */
- const char* (*getApplicationDataDirectory)();
-
- /** A helper function to load java classes from the plugin's apk. The
- function looks for a class given the fully qualified and null terminated
- string representing the className. For example,
-
- const char* className = "com.android.mypackage.MyClass";
-
- If the class cannot be found or there is a problem loading the class
- NULL will be returned.
- */
- jclass (*loadJavaClass)(NPP instance, const char* className);
-
- void (*setPowerState)(NPP instance, ANPPowerState powerState);
-};
-
-struct ANPSystemInterfaceV2 : ANPInterface {
- /** Return the path name for the current Application's plugin data directory,
- or NULL if not supported. This directory will change depending on whether
- or not the plugin is found within an incognito tab.
- */
- const char* (*getApplicationDataDirectory)(NPP instance);
-
- // redeclaration of existing features
- jclass (*loadJavaClass)(NPP instance, const char* className);
- void (*setPowerState)(NPP instance, ANPPowerState powerState);
-};
-
-typedef void* ANPNativeWindow;
-
-/** Called to notify the plugin that a video frame has been composited by the
-* browser for display. This will be called in a separate thread and as such
-* you cannot call releaseNativeWindow from the callback.
-*
-* The timestamp is in nanoseconds, and is monotonically increasing.
-*/
-typedef void (*ANPVideoFrameCallbackProc)(ANPNativeWindow* window, int64_t timestamp);
-
-struct ANPVideoInterfaceV1 : ANPInterface {
-
- /**
- * Constructs a new native window to be used for rendering video content.
- *
- * Subsequent calls will produce new windows, but may also return NULL after
- * n attempts if the browser has reached it's limit. Further, if the browser
- * is unable to acquire the window quickly it may also return NULL in order
- * to not prevent the plugin from executing. A subsequent call will then
- * return the window if it is avaiable.
- *
- * NOTE: The hardware may fail if you try to decode more than the allowable
- * number of videos supported on that device.
- */
- ANPNativeWindow (*acquireNativeWindow)(NPP instance);
-
- /**
- * Sets the rectangle that specifies where the video content is to be drawn.
- * The dimensions are in document space. Further, if the rect is NULL the
- * browser will not attempt to draw the window, therefore do not set the
- * dimensions until you queue the first buffer in the window.
- */
- void (*setWindowDimensions)(NPP instance, const ANPNativeWindow window, const ANPRectF* dimensions);
-
- /**
- */
- void (*releaseNativeWindow)(NPP instance, ANPNativeWindow window);
-
- /** Set a callback to be notified when an ANPNativeWindow is composited by
- * the browser.
- */
- void (*setFramerateCallback)(NPP instance, const ANPNativeWindow window, ANPVideoFrameCallbackProc);
-};
-
-struct ANPNativeWindowInterfaceV0 : ANPInterface {
- /**
- * Constructs a new native window to be used for rendering plugin content.
- *
- * Subsequent calls will return the original constructed window. Further, if
- * the browser is unable to acquire the window quickly it may return NULL in
- * order to not block the plugin indefinitely. A subsequent call will then
- * return the window if it is available.
- */
- ANPNativeWindow (*acquireNativeWindow)(NPP instance);
-
- /**
- * Invert the contents of the plugin on the y-axis.
- * default is to not be inverted (e.g. use OpenGL coordinates)
- */
- void (*invertPluginContent)(NPP instance, bool isContentInverted);
-};
-
-
-#endif
diff --git a/dom/plugins/base/android/moz.build b/dom/plugins/base/android/moz.build
deleted file mode 100644
index d95d20d5b..000000000
--- a/dom/plugins/base/android/moz.build
+++ /dev/null
@@ -1,35 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-EXPORTS += [
- 'android_npapi.h',
- 'ANPKeyCodes.h',
-]
-
-SOURCES += [
- 'ANPAudio.cpp',
- 'ANPEvent.cpp',
- 'ANPLog.cpp',
- 'ANPNativeWindow.cpp',
- 'ANPSurface.cpp',
- 'ANPSystem.cpp',
- 'ANPVideo.cpp',
- 'ANPWindow.cpp',
-]
-
-include('/ipc/chromium/chromium-config.mozbuild')
-
-FINAL_LIBRARY = 'xul'
-LOCAL_INCLUDES += [
- '/dom/plugins/base',
- '/gfx/gl',
- '/widget',
- '/widget/android',
-]
-
-DEFINES['MOZ_APP_NAME'] = '"%s"' % CONFIG['MOZ_APP_NAME']
-
-CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
diff --git a/dom/plugins/base/moz.build b/dom/plugins/base/moz.build
index f43f75f79..a159d6fc1 100644
--- a/dom/plugins/base/moz.build
+++ b/dom/plugins/base/moz.build
@@ -4,9 +4,6 @@
# 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/.
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
- DIRS += ['android']
-
XPIDL_SOURCES += [
'nsIHTTPHeaderListener.idl',
'nsIPluginDocument.idl',
@@ -89,16 +86,10 @@ LOCAL_INCLUDES += [
'/layout/xul',
'/netwerk/base',
'/widget',
- '/widget/android',
'/widget/cocoa',
'/xpcom/base',
]
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
- LOCAL_INCLUDES += [
- '/dom/plugins/base/android',
- ]
-
if CONFIG['OS_ARCH'] == 'WINNT':
LOCAL_INCLUDES += [
'/xpcom/base',
@@ -106,8 +97,6 @@ if CONFIG['OS_ARCH'] == 'WINNT':
include('/ipc/chromium/chromium-config.mozbuild')
-DEFINES['SK_BUILD_FOR_ANDROID_NDK'] = True
-
FINAL_LIBRARY = 'xul'
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
diff --git a/dom/plugins/base/npfunctions.h b/dom/plugins/base/npfunctions.h
index 4c9d66ea0..73097d115 100644
--- a/dom/plugins/base/npfunctions.h
+++ b/dom/plugins/base/npfunctions.h
@@ -9,10 +9,6 @@
#include "npapi.h"
#include "npruntime.h"
-#ifdef MOZ_WIDGET_ANDROID
-#include <jni.h>
-#endif
-
typedef NPError (* NPP_NewProcPtr)(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved);
typedef NPError (* NPP_DestroyProcPtr)(NPP instance, NPSavedData** save);
typedef NPError (* NPP_SetWindowProcPtr)(NPP instance, NPWindow* window);
@@ -261,14 +257,9 @@ NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs);
typedef NPError (*NP_GetEntryPointsFunc)(NPPluginFuncs*);
NP_EXPORT(NPError) NP_GetEntryPoints(NPPluginFuncs* pFuncs);
#else
-#ifdef MOZ_WIDGET_ANDROID
-typedef NPError (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*, JNIEnv* pEnv);
-NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, JNIEnv* pEnv);
-#else
typedef NPError (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*);
NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs);
#endif
-#endif
typedef NPError (*NP_ShutdownFunc)(void);
NP_EXPORT(NPError) NP_Shutdown(void);
typedef NPError (*NP_GetValueFunc)(void *, NPPVariable, void *);
diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp
index 697bfacd4..da4f09914 100644
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -97,15 +97,6 @@ using mozilla::plugins::PluginModuleContentParent;
#endif
#endif
-#ifdef MOZ_WIDGET_ANDROID
-#include <android/log.h>
-#include "android_npapi.h"
-#include "ANPBase.h"
-#include "GeneratedJNIWrappers.h"
-#undef LOG
-#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
-#endif
-
#include "nsIAudioChannelAgent.h"
#include "AudioChannelService.h"
@@ -236,11 +227,7 @@ nsNPAPIPlugin::PluginCrashed(const nsAString& pluginDumpID,
bool
nsNPAPIPlugin::RunPluginOOP(const nsPluginTag *aPluginTag)
{
-#ifdef MOZ_WIDGET_ANDROID
- return false;
-#else
return true;
-#endif
}
inline PluginLibrary*
@@ -282,7 +269,7 @@ nsNPAPIPlugin::CreatePlugin(nsPluginTag *aPluginTag, nsNPAPIPlugin** aResult)
return NS_ERROR_FAILURE;
}
-#if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
+#ifdef XP_MACOSX
if (!pluginLib->HasRequiredFunctions()) {
NS_WARNING("Not all necessary functions exposed by plugin, it will not load.");
delete pluginLib;
@@ -2019,156 +2006,6 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
return NPERR_NO_ERROR;
}
-#ifdef MOZ_WIDGET_ANDROID
- case kLogInterfaceV0_ANPGetValue: {
- LOG("get log interface");
- ANPLogInterfaceV0 *i = (ANPLogInterfaceV0 *) result;
- InitLogInterface(i);
- return NPERR_NO_ERROR;
- }
-
- case kBitmapInterfaceV0_ANPGetValue: {
- LOG("get bitmap interface");
- return NPERR_GENERIC_ERROR;
- }
-
- case kMatrixInterfaceV0_ANPGetValue: {
- LOG("get matrix interface");
- return NPERR_GENERIC_ERROR;
- }
-
- case kPathInterfaceV0_ANPGetValue: {
- LOG("get path interface");
- return NPERR_GENERIC_ERROR;
- }
-
- case kTypefaceInterfaceV0_ANPGetValue: {
- LOG("get typeface interface");
- ANPTypefaceInterfaceV0 *i = (ANPTypefaceInterfaceV0 *) result;
- InitTypeFaceInterface(i);
- return NPERR_NO_ERROR;
- }
-
- case kPaintInterfaceV0_ANPGetValue: {
- LOG("get paint interface");
- ANPPaintInterfaceV0 *i = (ANPPaintInterfaceV0 *) result;
- InitPaintInterface(i);
- return NPERR_NO_ERROR;
- }
-
- case kCanvasInterfaceV0_ANPGetValue: {
- LOG("get canvas interface");
- ANPCanvasInterfaceV0 *i = (ANPCanvasInterfaceV0 *) result;
- InitCanvasInterface(i);
- return NPERR_NO_ERROR;
- }
-
- case kWindowInterfaceV0_ANPGetValue: {
- LOG("get window interface");
- ANPWindowInterfaceV0 *i = (ANPWindowInterfaceV0 *) result;
- InitWindowInterface(i);
- return NPERR_NO_ERROR;
- }
-
- case kAudioTrackInterfaceV0_ANPGetValue: {
- LOG("get audio interface");
- ANPAudioTrackInterfaceV0 *i = (ANPAudioTrackInterfaceV0 *) result;
- InitAudioTrackInterfaceV0(i);
- return NPERR_NO_ERROR;
- }
-
- case kEventInterfaceV0_ANPGetValue: {
- LOG("get event interface");
- ANPEventInterfaceV0 *i = (ANPEventInterfaceV0 *) result;
- InitEventInterface(i);
- return NPERR_NO_ERROR;
- }
-
- case kSystemInterfaceV0_ANPGetValue: {
- LOG("get system interface");
- return NPERR_GENERIC_ERROR;
- }
-
- case kSurfaceInterfaceV0_ANPGetValue: {
- LOG("get surface interface");
- ANPSurfaceInterfaceV0 *i = (ANPSurfaceInterfaceV0 *) result;
- InitSurfaceInterface(i);
- return NPERR_NO_ERROR;
- }
-
- case kSupportedDrawingModel_ANPGetValue: {
- LOG("get supported drawing model");
- return NPERR_GENERIC_ERROR;
- }
-
- case kJavaContext_ANPGetValue: {
- LOG("get java context");
- auto ret = java::GeckoAppShell::GetContext();
- if (!ret)
- return NPERR_GENERIC_ERROR;
-
- *static_cast<jobject*>(result) = ret.Forget();
- return NPERR_NO_ERROR;
- }
-
- case kAudioTrackInterfaceV1_ANPGetValue: {
- LOG("get audio interface v1");
- ANPAudioTrackInterfaceV1 *i = (ANPAudioTrackInterfaceV1 *) result;
- InitAudioTrackInterfaceV1(i);
- return NPERR_NO_ERROR;
- }
-
- case kNativeWindowInterfaceV0_ANPGetValue: {
- LOG("get native window interface v0");
- ANPNativeWindowInterfaceV0* i = (ANPNativeWindowInterfaceV0 *) result;
- InitNativeWindowInterface(i);
- return NPERR_NO_ERROR;
- }
-
- case kOpenGLInterfaceV0_ANPGetValue: {
- LOG("get openGL interface");
- return NPERR_GENERIC_ERROR;
- }
-
- case kWindowInterfaceV1_ANPGetValue: {
- LOG("get Window interface V1");
- return NPERR_GENERIC_ERROR;
- }
-
- case kWindowInterfaceV2_ANPGetValue: {
- LOG("get Window interface V2");
- ANPWindowInterfaceV2 *i = (ANPWindowInterfaceV2 *) result;
- InitWindowInterfaceV2(i);
- return NPERR_NO_ERROR;
- }
-
- case kVideoInterfaceV0_ANPGetValue: {
- LOG("get video interface V0");
- return NPERR_GENERIC_ERROR;
- }
-
- case kVideoInterfaceV1_ANPGetValue: {
- LOG("get video interface V1");
- ANPVideoInterfaceV1 *i = (ANPVideoInterfaceV1*) result;
- InitVideoInterfaceV1(i);
- return NPERR_NO_ERROR;
- }
-
- case kSystemInterfaceV1_ANPGetValue: {
- LOG("get system interface v1");
- ANPSystemInterfaceV1* i = reinterpret_cast<ANPSystemInterfaceV1*>(result);
- InitSystemInterfaceV1(i);
- return NPERR_NO_ERROR;
- }
-
- case kSystemInterfaceV2_ANPGetValue: {
- LOG("get system interface v2");
- ANPSystemInterfaceV2* i = reinterpret_cast<ANPSystemInterfaceV2*>(result);
- InitSystemInterfaceV2(i);
- return NPERR_NO_ERROR;
- }
-#endif
-
// we no longer hand out any XPCOM objects
case NPNVDOMElement:
case NPNVDOMWindow:
@@ -2298,8 +2135,6 @@ _setvalue(NPP npp, NPPVariable variable, void *result)
return NPERR_NO_ERROR;
}
-#ifndef MOZ_WIDGET_ANDROID
- // On android, their 'drawing model' uses the same constant!
case NPPVpluginDrawingModel: {
if (inst) {
inst->SetDrawingModel((NPDrawingModel)NS_PTR_TO_INT32(result));
@@ -2309,7 +2144,6 @@ _setvalue(NPP npp, NPPVariable variable, void *result)
return NPERR_GENERIC_ERROR;
}
}
-#endif
#ifdef XP_MACOSX
case NPPVpluginEventModel: {
@@ -2322,14 +2156,7 @@ _setvalue(NPP npp, NPPVariable variable, void *result)
}
}
#endif
-#ifdef MOZ_WIDGET_ANDROID
- case kRequestDrawingModel_ANPSetValue:
- if (inst)
- inst->SetANPDrawingModel(NS_PTR_TO_INT32(result));
- return NPERR_NO_ERROR;
- case kAcceptEvents_ANPSetValue:
- return NPERR_NO_ERROR;
-#endif
+
default:
return NPERR_GENERIC_ERROR;
}
@@ -2682,13 +2509,8 @@ _unscheduletimer(NPP instance, uint32_t timerID)
return;
}
-#ifdef MOZ_WIDGET_ANDROID
- // Sometimes Flash calls this with a dead NPP instance. Ensure the one we have
- // here is valid and maps to a nsNPAPIPluginInstance.
- nsNPAPIPluginInstance *inst = nsNPAPIPluginInstance::GetFromNPP(instance);
-#else
nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
-#endif
+
if (!inst)
return;
diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp
index 4b211ed7e..ce24b6296 100644
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -5,11 +5,6 @@
#include "mozilla/DebugOnly.h"
-#ifdef MOZ_WIDGET_ANDROID
-// For ScreenOrientation.h and Hal.h
-#include "base/basictypes.h"
-#endif
-
#include "mozilla/Logging.h"
#include "prmem.h"
#include "nscore.h"
@@ -45,64 +40,6 @@
using namespace mozilla;
using namespace mozilla::dom;
-#ifdef MOZ_WIDGET_ANDROID
-#include "ANPBase.h"
-#include <android/log.h>
-#include "android_npapi.h"
-#include "mozilla/Mutex.h"
-#include "mozilla/CondVar.h"
-#include "mozilla/dom/ScreenOrientation.h"
-#include "mozilla/Hal.h"
-#include "GLContextProvider.h"
-#include "GLContext.h"
-#include "TexturePoolOGL.h"
-#include "SurfaceTypes.h"
-#include "EGLUtils.h"
-
-using namespace mozilla;
-using namespace mozilla::gl;
-
-typedef nsNPAPIPluginInstance::VideoInfo VideoInfo;
-
-class PluginEventRunnable : public Runnable
-{
-public:
- PluginEventRunnable(nsNPAPIPluginInstance* instance, ANPEvent* event)
- : mInstance(instance), mEvent(*event), mCanceled(false) {}
-
- virtual nsresult Run() {
- if (mCanceled)
- return NS_OK;
-
- mInstance->HandleEvent(&mEvent, nullptr);
- mInstance->PopPostedEvent(this);
- return NS_OK;
- }
-
- void Cancel() { mCanceled = true; }
-private:
- nsNPAPIPluginInstance* mInstance;
- ANPEvent mEvent;
- bool mCanceled;
-};
-
-static RefPtr<GLContext> sPluginContext = nullptr;
-
-static bool EnsureGLContext()
-{
- if (!sPluginContext) {
- const auto flags = CreateContextFlags::REQUIRE_COMPAT_PROFILE;
- nsCString discardedFailureId;
- sPluginContext = GLContextProvider::CreateHeadless(flags, &discardedFailureId);
- }
-
- return sPluginContext != nullptr;
-}
-
-static std::map<NPP, nsNPAPIPluginInstance*> sPluginNPPMap;
-
-#endif
-
using namespace mozilla;
using namespace mozilla::plugins::parent;
using namespace mozilla::layers;
@@ -113,13 +50,6 @@ NS_IMPL_ISUPPORTS(nsNPAPIPluginInstance, nsIAudioChannelAgentCallback)
nsNPAPIPluginInstance::nsNPAPIPluginInstance()
: mDrawingModel(kDefaultDrawingModel)
-#ifdef MOZ_WIDGET_ANDROID
- , mANPDrawingModel(0)
- , mFullScreenOrientation(dom::eScreenOrientation_LandscapePrimary)
- , mWakeLocked(false)
- , mFullScreen(false)
- , mOriginPos(gl::OriginPos::TopLeft)
-#endif
, mRunning(NOT_STARTED)
, mWindowless(false)
, mTransparent(false)
@@ -132,9 +62,6 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance()
#ifdef XP_MACOSX
, mCurrentPluginEvent(nullptr)
#endif
-#ifdef MOZ_WIDGET_ANDROID
- , mOnScreen(true)
-#endif
, mHaveJavaC2PJSObjectQuirk(false)
, mCachedParamLength(0)
, mCachedParamNames(nullptr)
@@ -145,20 +72,12 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance()
mNPP.ndata = this;
PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this));
-
-#ifdef MOZ_WIDGET_ANDROID
- sPluginNPPMap[&mNPP] = this;
-#endif
}
nsNPAPIPluginInstance::~nsNPAPIPluginInstance()
{
PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance dtor: this=%p\n",this));
-#ifdef MOZ_WIDGET_ANDROID
- sPluginNPPMap.erase(&mNPP);
-#endif
-
if (mMIMEType) {
PR_Free((void *)mMIMEType);
mMIMEType = nullptr;
@@ -195,21 +114,6 @@ nsNPAPIPluginInstance::Destroy()
Stop();
mPlugin = nullptr;
mAudioChannelAgent = nullptr;
-
-#if MOZ_WIDGET_ANDROID
- if (mContentSurface)
- mContentSurface->SetFrameAvailableCallback(nullptr);
-
- mContentSurface = nullptr;
-
- std::map<void*, VideoInfo*>::iterator it;
- for (it = mVideos.begin(); it != mVideos.end(); it++) {
- it->second->mSurfaceTexture->SetFrameAvailableCallback(nullptr);
- delete it->second;
- }
- mVideos.clear();
- SetWakeLock(false);
-#endif
}
TimeStamp
@@ -297,14 +201,6 @@ nsresult nsNPAPIPluginInstance::Stop()
}
mRunning = DESTROYED;
-#if MOZ_WIDGET_ANDROID
- for (uint32_t i = 0; i < mPostedEvents.Length(); i++) {
- mPostedEvents[i]->Cancel();
- }
-
- mPostedEvents.Clear();
-#endif
-
nsJSNPRuntime::OnPluginDestroy(&mNPP);
if (error != NPERR_NO_ERROR)
@@ -404,13 +300,8 @@ nsNPAPIPluginInstance::Start()
mCachedParamValues[i] = ToNewUTF8String(attributes[i].mValue);
}
- // Android expects and empty string instead of null.
mCachedParamNames[attributes.Length()] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
- #ifdef MOZ_WIDGET_ANDROID
- mCachedParamValues[attributes.Length()] = ToNewUTF8String(NS_LITERAL_STRING(""));
- #else
- mCachedParamValues[attributes.Length()] = nullptr;
- #endif
+ mCachedParamValues[attributes.Length()] = nullptr;
for (uint32_t i = 0, pos = attributes.Length() + 1; i < params.Length(); i ++) {
mCachedParamNames[pos] = ToNewUTF8String(params[i].mName);
@@ -738,249 +629,6 @@ void nsNPAPIPluginInstance::SetEventModel(NPEventModel aModel)
}
#endif
-#if defined(MOZ_WIDGET_ANDROID)
-
-static void SendLifecycleEvent(nsNPAPIPluginInstance* aInstance, uint32_t aAction)
-{
- ANPEvent event;
- event.inSize = sizeof(ANPEvent);
- event.eventType = kLifecycle_ANPEventType;
- event.data.lifecycle.action = aAction;
- aInstance->HandleEvent(&event, nullptr);
-}
-
-void nsNPAPIPluginInstance::NotifyForeground(bool aForeground)
-{
- PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetForeground this=%p\n foreground=%d",this, aForeground));
- if (RUNNING != mRunning)
- return;
-
- SendLifecycleEvent(this, aForeground ? kResume_ANPLifecycleAction : kPause_ANPLifecycleAction);
-}
-
-void nsNPAPIPluginInstance::NotifyOnScreen(bool aOnScreen)
-{
- PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetOnScreen this=%p\n onScreen=%d",this, aOnScreen));
- if (RUNNING != mRunning || mOnScreen == aOnScreen)
- return;
-
- mOnScreen = aOnScreen;
- SendLifecycleEvent(this, aOnScreen ? kOnScreen_ANPLifecycleAction : kOffScreen_ANPLifecycleAction);
-}
-
-void nsNPAPIPluginInstance::MemoryPressure()
-{
- PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::MemoryPressure this=%p\n",this));
- if (RUNNING != mRunning)
- return;
-
- SendLifecycleEvent(this, kFreeMemory_ANPLifecycleAction);
-}
-
-void nsNPAPIPluginInstance::NotifyFullScreen(bool aFullScreen)
-{
- PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::NotifyFullScreen this=%p\n",this));
-
- if (RUNNING != mRunning || mFullScreen == aFullScreen)
- return;
-
- mFullScreen = aFullScreen;
- SendLifecycleEvent(this, mFullScreen ? kEnterFullScreen_ANPLifecycleAction : kExitFullScreen_ANPLifecycleAction);
-
- if (mFullScreen && mFullScreenOrientation != dom::eScreenOrientation_None) {
- java::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
- }
-}
-
-void nsNPAPIPluginInstance::NotifySize(nsIntSize size)
-{
- if (kOpenGL_ANPDrawingModel != GetANPDrawingModel() ||
- size == mCurrentSize)
- return;
-
- mCurrentSize = size;
-
- ANPEvent event;
- event.inSize = sizeof(ANPEvent);
- event.eventType = kDraw_ANPEventType;
- event.data.draw.model = kOpenGL_ANPDrawingModel;
- event.data.draw.data.surfaceSize.width = size.width;
- event.data.draw.data.surfaceSize.height = size.height;
-
- HandleEvent(&event, nullptr);
-}
-
-void nsNPAPIPluginInstance::SetANPDrawingModel(uint32_t aModel)
-{
- mANPDrawingModel = aModel;
-}
-
-void* nsNPAPIPluginInstance::GetJavaSurface()
-{
- void* surface = nullptr;
- nsresult rv = GetValueFromPlugin(kJavaSurface_ANPGetValue, &surface);
- if (NS_FAILED(rv))
- return nullptr;
-
- return surface;
-}
-
-void nsNPAPIPluginInstance::PostEvent(void* event)
-{
- PluginEventRunnable *r = new PluginEventRunnable(this, (ANPEvent*)event);
- mPostedEvents.AppendElement(RefPtr<PluginEventRunnable>(r));
-
- NS_DispatchToMainThread(r);
-}
-
-void nsNPAPIPluginInstance::SetFullScreenOrientation(uint32_t orientation)
-{
- if (mFullScreenOrientation == orientation)
- return;
-
- uint32_t oldOrientation = mFullScreenOrientation;
- mFullScreenOrientation = orientation;
-
- if (mFullScreen) {
- // We're already fullscreen so immediately apply the orientation change
-
- if (mFullScreenOrientation != dom::eScreenOrientation_None) {
- java::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
- } else if (oldOrientation != dom::eScreenOrientation_None) {
- // We applied an orientation when we entered fullscreen, but
- // we don't want it anymore
- java::GeckoAppShell::UnlockScreenOrientation();
- }
- }
-}
-
-void nsNPAPIPluginInstance::PopPostedEvent(PluginEventRunnable* r)
-{
- mPostedEvents.RemoveElement(r);
-}
-
-void nsNPAPIPluginInstance::SetWakeLock(bool aLocked)
-{
- if (aLocked == mWakeLocked)
- return;
-
- mWakeLocked = aLocked;
- hal::ModifyWakeLock(NS_LITERAL_STRING("screen"),
- mWakeLocked ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_REMOVE_ONE,
- hal::WAKE_LOCK_NO_CHANGE);
-}
-
-GLContext* nsNPAPIPluginInstance::GLContext()
-{
- if (!EnsureGLContext())
- return nullptr;
-
- return sPluginContext;
-}
-
-already_AddRefed<AndroidSurfaceTexture> nsNPAPIPluginInstance::CreateSurfaceTexture()
-{
- if (!EnsureGLContext())
- return nullptr;
-
- GLuint texture = TexturePoolOGL::AcquireTexture();
- if (!texture)
- return nullptr;
-
- RefPtr<AndroidSurfaceTexture> surface = AndroidSurfaceTexture::Create(TexturePoolOGL::GetGLContext(),
- texture);
- if (!surface) {
- return nullptr;
- }
-
- nsCOMPtr<nsIRunnable> frameCallback = NewRunnableMethod(this, &nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable);
- surface->SetFrameAvailableCallback(frameCallback);
- return surface.forget();
-}
-
-void nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable()
-{
- if (mRunning == RUNNING && mOwner)
- mOwner->Recomposite();
-}
-
-void* nsNPAPIPluginInstance::AcquireContentWindow()
-{
- if (!mContentSurface) {
- mContentSurface = CreateSurfaceTexture();
-
- if (!mContentSurface)
- return nullptr;
- }
-
- return mContentSurface->NativeWindow();
-}
-
-AndroidSurfaceTexture*
-nsNPAPIPluginInstance::AsSurfaceTexture()
-{
- if (!mContentSurface)
- return nullptr;
-
- return mContentSurface;
-}
-
-void* nsNPAPIPluginInstance::AcquireVideoWindow()
-{
- RefPtr<AndroidSurfaceTexture> surface = CreateSurfaceTexture();
- if (!surface) {
- return nullptr;
- }
-
- VideoInfo* info = new VideoInfo(surface);
-
- void* window = info->mSurfaceTexture->NativeWindow();
- mVideos.insert(std::pair<void*, VideoInfo*>(window, info));
-
- return window;
-}
-
-void nsNPAPIPluginInstance::ReleaseVideoWindow(void* window)
-{
- std::map<void*, VideoInfo*>::iterator it = mVideos.find(window);
- if (it == mVideos.end())
- return;
-
- delete it->second;
- mVideos.erase(window);
-}
-
-void nsNPAPIPluginInstance::SetVideoDimensions(void* window, gfxRect aDimensions)
-{
- std::map<void*, VideoInfo*>::iterator it;
-
- it = mVideos.find(window);
- if (it == mVideos.end())
- return;
-
- it->second->mDimensions = aDimensions;
-}
-
-void nsNPAPIPluginInstance::GetVideos(nsTArray<VideoInfo*>& aVideos)
-{
- std::map<void*, VideoInfo*>::iterator it;
- for (it = mVideos.begin(); it != mVideos.end(); it++)
- aVideos.AppendElement(it->second);
-}
-
-nsNPAPIPluginInstance* nsNPAPIPluginInstance::GetFromNPP(NPP npp)
-{
- std::map<NPP, nsNPAPIPluginInstance*>::iterator it;
-
- it = sPluginNPPMap.find(npp);
- if (it == sPluginNPPMap.end())
- return nullptr;
-
- return it->second;
-}
-
-#endif
-
nsresult nsNPAPIPluginInstance::GetDrawingModel(int32_t* aModel)
{
*aModel = (int32_t)mDrawingModel;
@@ -1083,9 +731,8 @@ nsNPAPIPluginInstance::ShouldCache()
nsresult
nsNPAPIPluginInstance::IsWindowless(bool* isWindowless)
{
-#if defined(MOZ_WIDGET_ANDROID) || defined(XP_MACOSX)
+#ifdef XP_MACOSX
// All OS X plugins are windowless.
- // On android, pre-honeycomb, all plugins are treated as windowless.
*isWindowless = true;
#else
*isWindowless = mWindowless;
diff --git a/dom/plugins/base/nsNPAPIPluginInstance.h b/dom/plugins/base/nsNPAPIPluginInstance.h
index 5f0375637..48e62517d 100644
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -18,15 +18,6 @@
#include <prinrval.h>
#include "js/TypeDecls.h"
#include "nsIAudioChannelAgent.h"
-#ifdef MOZ_WIDGET_ANDROID
-#include "nsIRunnable.h"
-#include "GLContextTypes.h"
-#include "AndroidSurfaceTexture.h"
-#include "AndroidBridge.h"
-#include <map>
-class PluginEventRunnable;
-#endif
-
#include "mozilla/EventForwards.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/PluginLibrary.h"
@@ -163,90 +154,6 @@ public:
}
#endif
-#ifdef MOZ_WIDGET_ANDROID
- void NotifyForeground(bool aForeground);
- void NotifyOnScreen(bool aOnScreen);
- void MemoryPressure();
- void NotifyFullScreen(bool aFullScreen);
- void NotifySize(nsIntSize size);
-
- nsIntSize CurrentSize() { return mCurrentSize; }
-
- bool IsOnScreen() {
- return mOnScreen;
- }
-
- uint32_t GetANPDrawingModel() { return mANPDrawingModel; }
- void SetANPDrawingModel(uint32_t aModel);
-
- void* GetJavaSurface();
-
- void PostEvent(void* event);
-
- // These are really mozilla::dom::ScreenOrientation, but it's
- // difficult to include that here
- uint32_t FullScreenOrientation() { return mFullScreenOrientation; }
- void SetFullScreenOrientation(uint32_t orientation);
-
- void SetWakeLock(bool aLock);
-
- mozilla::gl::GLContext* GLContext();
-
- // For ANPOpenGL
- class TextureInfo {
- public:
- TextureInfo() :
- mTexture(0), mWidth(0), mHeight(0), mInternalFormat(0)
- {
- }
-
- TextureInfo(GLuint aTexture, int32_t aWidth, int32_t aHeight, GLuint aInternalFormat) :
- mTexture(aTexture), mWidth(aWidth), mHeight(aHeight), mInternalFormat(aInternalFormat)
- {
- }
-
- GLuint mTexture;
- int32_t mWidth;
- int32_t mHeight;
- GLuint mInternalFormat;
- };
-
- // For ANPNativeWindow
- void* AcquireContentWindow();
-
- mozilla::gl::AndroidSurfaceTexture* AsSurfaceTexture();
-
- // For ANPVideo
- class VideoInfo {
- public:
- VideoInfo(mozilla::gl::AndroidSurfaceTexture* aSurfaceTexture) :
- mSurfaceTexture(aSurfaceTexture)
- {
- }
-
- ~VideoInfo()
- {
- mSurfaceTexture = nullptr;
- }
-
- RefPtr<mozilla::gl::AndroidSurfaceTexture> mSurfaceTexture;
- gfxRect mDimensions;
- };
-
- void* AcquireVideoWindow();
- void ReleaseVideoWindow(void* aWindow);
- void SetVideoDimensions(void* aWindow, gfxRect aDimensions);
-
- void GetVideos(nsTArray<VideoInfo*>& aVideos);
-
- void SetOriginPos(mozilla::gl::OriginPos aOriginPos) {
- mOriginPos = aOriginPos;
- }
- mozilla::gl::OriginPos OriginPos() const { return mOriginPos; }
-
- static nsNPAPIPluginInstance* GetFromNPP(NPP npp);
-#endif
-
nsresult NewStreamListener(const char* aURL, void* notifyData,
nsNPAPIPluginStreamListener** listener);
@@ -347,23 +254,6 @@ protected:
NPDrawingModel mDrawingModel;
-#ifdef MOZ_WIDGET_ANDROID
- uint32_t mANPDrawingModel;
-
- friend class PluginEventRunnable;
-
- nsTArray<RefPtr<PluginEventRunnable>> mPostedEvents;
- void PopPostedEvent(PluginEventRunnable* r);
- void OnSurfaceTextureFrameAvailable();
-
- uint32_t mFullScreenOrientation;
- bool mWakeLocked;
- bool mFullScreen;
- mozilla::gl::OriginPos mOriginPos;
-
- RefPtr<mozilla::gl::AndroidSurfaceTexture> mContentSurface;
-#endif
-
enum {
NOT_STARTED,
RUNNING,
@@ -410,15 +300,6 @@ private:
// This is only valid when the plugin is actually stopped!
mozilla::TimeStamp mStopTime;
-#ifdef MOZ_WIDGET_ANDROID
- already_AddRefed<mozilla::gl::AndroidSurfaceTexture> CreateSurfaceTexture();
-
- std::map<void*, VideoInfo*> mVideos;
- bool mOnScreen;
-
- nsIntSize mCurrentSize;
-#endif
-
// is this instance Java and affected by bug 750480?
bool mHaveJavaC2PJSObjectQuirk;
@@ -434,13 +315,7 @@ private:
bool mMuted;
};
-// On Android, we need to guard against plugin code leaking entries in the local
-// JNI ref table. See https://bugzilla.mozilla.org/show_bug.cgi?id=780831#c21
-#ifdef MOZ_WIDGET_ANDROID
- #define MAIN_THREAD_JNI_REF_GUARD mozilla::AutoLocalJNIFrame jniFrame
-#else
- #define MAIN_THREAD_JNI_REF_GUARD
-#endif
+#define MAIN_THREAD_JNI_REF_GUARD
void NS_NotifyBeginPluginCall(NSPluginCallReentry aReentryState);
void NS_NotifyPluginCall(NSPluginCallReentry aReentryState);
diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp
index c3de136d0..1b98855d1 100644
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -104,11 +104,6 @@
#include "winbase.h"
#endif
-#ifdef ANDROID
-#include <android/log.h>
-#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
-#endif
-
#include "npapi.h"
using namespace mozilla;
@@ -293,10 +288,6 @@ nsPluginHost::nsPluginHost()
if (obsService) {
obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
obsService->AddObserver(this, "blocklist-updated", false);
-#ifdef MOZ_WIDGET_ANDROID
- obsService->AddObserver(this, "application-foreground", false);
- obsService->AddObserver(this, "application-background", false);
-#endif
}
#ifdef PLUGIN_LOGGING
@@ -2306,11 +2297,6 @@ WatchRegKey(uint32_t aRoot, nsCOMPtr<nsIWindowsRegKey>& aKey)
nsresult nsPluginHost::LoadPlugins()
{
-#ifdef ANDROID
- if (XRE_IsContentProcess()) {
- return NS_OK;
- }
-#endif
// do not do anything if it is already done
// use ReloadPlugins() to enforce loading
if (mPluginsLoaded)
@@ -2453,10 +2439,6 @@ nsresult nsPluginHost::FindPlugins(bool aCreatePluginList, bool * aPluginsChange
NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
return NS_OK;
}
- } else {
-#ifdef ANDROID
- LOG("getting plugins dir failed");
-#endif
}
mPluginsLoaded = true; // at this point 'some' plugins have been loaded,
@@ -3069,14 +3051,6 @@ nsPluginHost::ReadPluginInfo()
if (!reader.NextLine())
return rv;
-#if MOZ_WIDGET_ANDROID
- // Flash on Android does not populate the version field, but it is tacked on to the description.
- // For example, "Shockwave Flash 11.1 r115"
- if (PL_strncmp("Shockwave Flash ", description, 16) == 0 && description[16]) {
- version = &description[16];
- }
-#endif
-
const char *name = reader.LinePtr();
if (!reader.NextLine())
return rv;
@@ -3144,31 +3118,6 @@ nsPluginHost::ReadPluginInfo()
mCachedPlugins = tag;
}
-// On Android we always want to try to load a plugin again (Flash). Bug 935676.
-#ifndef MOZ_WIDGET_ANDROID
- if (!ReadSectionHeader(reader, "INVALID")) {
- return rv;
- }
-
- while (reader.NextLine()) {
- const char *fullpath = reader.LinePtr();
- if (!reader.NextLine()) {
- return rv;
- }
-
- const char *lastModifiedTimeStamp = reader.LinePtr();
- int64_t lastmod = nsCRT::atoll(lastModifiedTimeStamp);
-
- RefPtr<nsInvalidPluginTag> invalidTag = new nsInvalidPluginTag(fullpath, lastmod);
-
- invalidTag->mNext = mInvalidPlugins;
- if (mInvalidPlugins) {
- mInvalidPlugins->mPrev = invalidTag;
- }
- mInvalidPlugins = invalidTag;
- }
-#endif
-
return NS_OK;
}
@@ -3491,24 +3440,7 @@ NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
plugin = plugin->mNext;
}
}
-#ifdef MOZ_WIDGET_ANDROID
- if (!strcmp("application-background", aTopic)) {
- for(uint32_t i = 0; i < mInstances.Length(); i++) {
- mInstances[i]->NotifyForeground(false);
- }
- }
- if (!strcmp("application-foreground", aTopic)) {
- for(uint32_t i = 0; i < mInstances.Length(); i++) {
- if (mInstances[i]->IsOnScreen())
- mInstances[i]->NotifyForeground(true);
- }
- }
- if (!strcmp("memory-pressure", aTopic)) {
- for(uint32_t i = 0; i < mInstances.Length(); i++) {
- mInstances[i]->MemoryPressure();
- }
- }
-#endif
+
return NS_OK;
}
diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp
index d5b1eb9ea..22c4783ca 100644
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -87,20 +87,6 @@ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
#include <gtk/gtk.h>
#endif
-#ifdef MOZ_WIDGET_ANDROID
-#include "ANPBase.h"
-#include "AndroidBridge.h"
-#include "ClientLayerManager.h"
-#include "nsWindow.h"
-
-static nsPluginInstanceOwner* sFullScreenInstance = nullptr;
-
-using namespace mozilla::dom;
-
-#include <android/log.h>
-#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
-#endif
-
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layers;
@@ -165,29 +151,6 @@ nsPluginInstanceOwner::NotifyPaintWaiter(nsDisplayListBuilder* aBuilder)
}
}
-#if MOZ_WIDGET_ANDROID
-static void
-AttachToContainerAsSurfaceTexture(ImageContainer* container,
- nsNPAPIPluginInstance* instance,
- const LayoutDeviceRect& rect,
- RefPtr<Image>* out_image)
-{
- MOZ_ASSERT(out_image);
- MOZ_ASSERT(!*out_image);
-
- mozilla::gl::AndroidSurfaceTexture* surfTex = instance->AsSurfaceTexture();
- if (!surfTex) {
- return;
- }
-
- RefPtr<Image> img = new SurfaceTextureImage(
- surfTex,
- gfx::IntSize::Truncate(rect.width, rect.height),
- instance->OriginPos());
- *out_image = img;
-}
-#endif
-
bool
nsPluginInstanceOwner::NeedsScrollImageLayer()
{
@@ -211,27 +174,6 @@ nsPluginInstanceOwner::GetImageContainer()
RefPtr<ImageContainer> container;
-#if MOZ_WIDGET_ANDROID
- LayoutDeviceRect r = GetPluginRect();
-
- // NotifySize() causes Flash to do a bunch of stuff like ask for surfaces to render
- // into, set y-flip flags, etc, so we do this at the beginning.
- float resolution = mPluginFrame->PresContext()->PresShell()->GetCumulativeResolution();
- ScreenSize screenSize = (r * LayoutDeviceToScreenScale(resolution)).Size();
- mInstance->NotifySize(nsIntSize::Truncate(screenSize.width, screenSize.height));
-
- container = LayerManager::CreateImageContainer();
-
- if (r.width && r.height) {
- // Try to get it as an EGLImage first.
- RefPtr<Image> img;
- AttachToContainerAsSurfaceTexture(container, mInstance, r, &img);
-
- if (img) {
- container->SetCurrentImageInTransaction(img);
- }
- }
-#else
if (NeedsScrollImageLayer()) {
// windowed plugin under e10s
#if defined(XP_WIN)
@@ -241,7 +183,6 @@ nsPluginInstanceOwner::GetImageContainer()
// async windowless rendering
mInstance->GetImageContainer(getter_AddRefs(container));
}
-#endif
return container.forget();
}
@@ -358,11 +299,6 @@ nsPluginInstanceOwner::nsPluginInstanceOwner()
mWaitingForPaint = false;
-#ifdef MOZ_WIDGET_ANDROID
- mFullScreen = false;
- mJavaView = nullptr;
-#endif
-
#ifdef XP_WIN
mGotCompositionData = false;
mSentStartComposition = false;
@@ -387,10 +323,6 @@ nsPluginInstanceOwner::~nsPluginInstanceOwner()
PLUG_DeletePluginNativeWindow(mPluginWindow);
mPluginWindow = nullptr;
-#ifdef MOZ_WIDGET_ANDROID
- RemovePluginView();
-#endif
-
if (mInstance) {
mInstance->SetOwner(nullptr);
}
@@ -413,10 +345,6 @@ nsPluginInstanceOwner::SetInstance(nsNPAPIPluginInstance *aInstance)
// from our destructor. This fixes bug 613376.
if (mInstance && !aInstance) {
mInstance->SetOwner(nullptr);
-
-#ifdef MOZ_WIDGET_ANDROID
- RemovePluginView();
-#endif
}
mInstance = aInstance;
@@ -601,7 +529,7 @@ NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
if (!mPluginFrame || !invalidRect || !mWidgetVisible)
return NS_ERROR_FAILURE;
-#if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
+#ifdef XP_MACOSX
// Each time an asynchronously-drawing plugin sends a new surface to display,
// the image in the ImageContainer is updated and InvalidateRect is called.
// There are different side effects for (sync) Android plugins.
@@ -624,6 +552,7 @@ NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
}
}
#endif
+
nsIntRect rect(invalidRect->left,
invalidRect->top,
invalidRect->right - invalidRect->left,
@@ -1485,185 +1414,6 @@ nsPluginInstanceOwner::GetEventloopNestingLevel()
return currentLevel;
}
-#ifdef MOZ_WIDGET_ANDROID
-
-// Modified version of nsFrame::GetOffsetToCrossDoc that stops when it
-// hits an element with a displayport (or runs out of frames). This is
-// not really the right thing to do, but it's better than what was here before.
-static nsPoint
-GetOffsetRootContent(nsIFrame* aFrame)
-{
- // offset will hold the final offset
- // docOffset holds the currently accumulated offset at the current APD, it
- // will be converted and added to offset when the current APD changes.
- nsPoint offset(0, 0), docOffset(0, 0);
- const nsIFrame* f = aFrame;
- int32_t currAPD = aFrame->PresContext()->AppUnitsPerDevPixel();
- int32_t apd = currAPD;
- while (f) {
- if (f->GetContent() && nsLayoutUtils::HasDisplayPort(f->GetContent()))
- break;
-
- docOffset += f->GetPosition();
- nsIFrame* parent = f->GetParent();
- if (parent) {
- f = parent;
- } else {
- nsPoint newOffset(0, 0);
- f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
- int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
- if (!f || newAPD != currAPD) {
- // Convert docOffset to the right APD and add it to offset.
- offset += docOffset.ScaleToOtherAppUnits(currAPD, apd);
- docOffset.x = docOffset.y = 0;
- }
- currAPD = newAPD;
- docOffset += newOffset;
- }
- }
-
- offset += docOffset.ScaleToOtherAppUnits(currAPD, apd);
-
- return offset;
-}
-
-LayoutDeviceRect nsPluginInstanceOwner::GetPluginRect()
-{
- // Get the offset of the content relative to the page
- nsRect bounds = mPluginFrame->GetContentRectRelativeToSelf() + GetOffsetRootContent(mPluginFrame);
- LayoutDeviceIntRect rect = LayoutDeviceIntRect::FromAppUnitsToNearest(bounds, mPluginFrame->PresContext()->AppUnitsPerDevPixel());
- return LayoutDeviceRect(rect);
-}
-
-bool nsPluginInstanceOwner::AddPluginView(const LayoutDeviceRect& aRect /* = LayoutDeviceRect(0, 0, 0, 0) */)
-{
- if (!mJavaView) {
- mJavaView = mInstance->GetJavaSurface();
-
- if (!mJavaView)
- return false;
-
- mJavaView = (void*)jni::GetGeckoThreadEnv()->NewGlobalRef((jobject)mJavaView);
- }
-
- if (mFullScreen) {
- java::GeckoAppShell::AddFullScreenPluginView(jni::Object::Ref::From(jobject(mJavaView)));
- sFullScreenInstance = this;
- }
-
- return true;
-}
-
-void nsPluginInstanceOwner::RemovePluginView()
-{
- if (!mInstance || !mJavaView)
- return;
-
- if (mFullScreen) {
- java::GeckoAppShell::RemoveFullScreenPluginView(jni::Object::Ref::From(jobject(mJavaView)));
- }
- jni::GetGeckoThreadEnv()->DeleteGlobalRef((jobject)mJavaView);
- mJavaView = nullptr;
-
- if (mFullScreen)
- sFullScreenInstance = nullptr;
-}
-
-void
-nsPluginInstanceOwner::GetVideos(nsTArray<nsNPAPIPluginInstance::VideoInfo*>& aVideos)
-{
- if (!mInstance)
- return;
-
- mInstance->GetVideos(aVideos);
-}
-
-already_AddRefed<ImageContainer>
-nsPluginInstanceOwner::GetImageContainerForVideo(nsNPAPIPluginInstance::VideoInfo* aVideoInfo)
-{
- RefPtr<ImageContainer> container = LayerManager::CreateImageContainer();
-
- if (aVideoInfo->mDimensions.width && aVideoInfo->mDimensions.height) {
- RefPtr<Image> img = new SurfaceTextureImage(
- aVideoInfo->mSurfaceTexture,
- gfx::IntSize::Truncate(aVideoInfo->mDimensions.width, aVideoInfo->mDimensions.height),
- gl::OriginPos::BottomLeft);
- container->SetCurrentImageInTransaction(img);
- }
-
- return container.forget();
-}
-
-void nsPluginInstanceOwner::Invalidate() {
- NPRect rect;
- rect.left = rect.top = 0;
- rect.right = mPluginWindow->width;
- rect.bottom = mPluginWindow->height;
- InvalidateRect(&rect);
-}
-
-void nsPluginInstanceOwner::Recomposite() {
- nsIWidget* const widget = mPluginFrame->GetNearestWidget();
- NS_ENSURE_TRUE_VOID(widget);
-
- LayerManager* const lm = widget->GetLayerManager();
- NS_ENSURE_TRUE_VOID(lm);
-
- ClientLayerManager* const clm = lm->AsClientLayerManager();
- NS_ENSURE_TRUE_VOID(clm && clm->GetRoot());
-
- clm->SendInvalidRegion(
- clm->GetRoot()->GetLocalVisibleRegion().ToUnknownRegion().GetBounds());
- clm->Composite();
-}
-
-void nsPluginInstanceOwner::RequestFullScreen() {
- if (mFullScreen)
- return;
-
- // Remove whatever view we currently have (if any, fullscreen or otherwise)
- RemovePluginView();
-
- mFullScreen = true;
- AddPluginView();
-
- mInstance->NotifyFullScreen(mFullScreen);
-}
-
-void nsPluginInstanceOwner::ExitFullScreen() {
- if (!mFullScreen)
- return;
-
- RemovePluginView();
-
- mFullScreen = false;
-
- int32_t model = mInstance->GetANPDrawingModel();
-
- if (model == kSurface_ANPDrawingModel) {
- // We need to do this immediately, otherwise Flash
- // sometimes causes a deadlock (bug 762407)
- AddPluginView(GetPluginRect());
- }
-
- mInstance->NotifyFullScreen(mFullScreen);
-
- // This will cause Paint() to be called, which is where
- // we normally add/update views and layers
- Invalidate();
-}
-
-void nsPluginInstanceOwner::ExitFullScreen(jobject view) {
- JNIEnv* env = jni::GetGeckoThreadEnv();
-
- if (sFullScreenInstance && sFullScreenInstance->mInstance &&
- env->IsSameObject(view, (jobject)sFullScreenInstance->mInstance->GetJavaSurface())) {
- sFullScreenInstance->ExitFullScreen();
- }
-}
-
-#endif
-
void
nsPluginInstanceOwner::NotifyHostAsyncInitFailed()
{
@@ -1705,27 +1455,6 @@ nsPluginInstanceOwner::NotifyDestroyPending()
nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
{
-#ifdef MOZ_WIDGET_ANDROID
- if (mInstance) {
- ANPEvent event;
- event.inSize = sizeof(ANPEvent);
- event.eventType = kLifecycle_ANPEventType;
-
- nsAutoString eventType;
- aFocusEvent->GetType(eventType);
- if (eventType.EqualsLiteral("focus")) {
- event.data.lifecycle.action = kGainFocus_ANPLifecycleAction;
- }
- else if (eventType.EqualsLiteral("blur")) {
- event.data.lifecycle.action = kLoseFocus_ANPLifecycleAction;
- }
- else {
- NS_ASSERTION(false, "nsPluginInstanceOwner::DispatchFocusToPlugin, wierd eventType");
- }
- mInstance->HandleEvent(&event, nullptr);
- }
-#endif
-
#ifndef XP_MACOSX
if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) {
// continue only for cases without child window
@@ -2786,96 +2515,6 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
rv = nsEventStatus_eConsumeNoDefault;
#endif
-#ifdef MOZ_WIDGET_ANDROID
- // this code supports windowless plugins
- {
- // The plugin needs focus to receive keyboard and touch events
- nsIFocusManager* fm = nsFocusManager::GetFocusManager();
- if (fm) {
- nsCOMPtr<nsIDOMElement> elem = do_QueryReferent(mContent);
- fm->SetFocus(elem, 0);
- }
- }
- switch(anEvent.mClass) {
- case eMouseEventClass:
- {
- switch (anEvent.mMessage) {
- case eMouseClick:
- case eMouseDoubleClick:
- case eMouseAuxClick:
- // Button up/down events sent instead.
- return rv;
- default:
- break;
- }
-
- // Get reference point relative to plugin origin.
- const nsPresContext* presContext = mPluginFrame->PresContext();
- nsPoint appPoint =
- nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
- mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
- nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
- presContext->AppUnitsToDevPixels(appPoint.y));
-
- switch (anEvent.mMessage) {
- case eMouseMove:
- {
- // are these going to be touch events?
- // pluginPoint.x;
- // pluginPoint.y;
- }
- break;
- case eMouseDown:
- {
- ANPEvent event;
- event.inSize = sizeof(ANPEvent);
- event.eventType = kMouse_ANPEventType;
- event.data.mouse.action = kDown_ANPMouseAction;
- event.data.mouse.x = pluginPoint.x;
- event.data.mouse.y = pluginPoint.y;
- mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
- }
- break;
- case eMouseUp:
- {
- ANPEvent event;
- event.inSize = sizeof(ANPEvent);
- event.eventType = kMouse_ANPEventType;
- event.data.mouse.action = kUp_ANPMouseAction;
- event.data.mouse.x = pluginPoint.x;
- event.data.mouse.y = pluginPoint.y;
- mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
- }
- break;
- default:
- break;
- }
- }
- break;
-
- case eKeyboardEventClass:
- {
- const WidgetKeyboardEvent& keyEvent = *anEvent.AsKeyboardEvent();
- LOG("Firing eKeyboardEventClass %d %d\n",
- keyEvent.mKeyCode, keyEvent.mCharCode);
- // pluginEvent is initialized by nsWindow::InitKeyEvent().
- const ANPEvent* pluginEvent = static_cast<const ANPEvent*>(keyEvent.mPluginEvent);
- if (pluginEvent) {
- MOZ_ASSERT(pluginEvent->inSize == sizeof(ANPEvent));
- MOZ_ASSERT(pluginEvent->eventType == kKey_ANPEventType);
- mInstance->HandleEvent(const_cast<ANPEvent*>(pluginEvent),
- nullptr,
- NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
- }
- }
- break;
-
- default:
- break;
- }
- rv = nsEventStatus_eConsumeNoDefault;
-#endif
-
return rv;
}
@@ -2922,10 +2561,6 @@ nsPluginInstanceOwner::Destroy()
this, true);
content->RemoveSystemEventListener(NS_LITERAL_STRING("text"), this, true);
-#if MOZ_WIDGET_ANDROID
- RemovePluginView();
-#endif
-
if (mWidget) {
if (mPluginWindow) {
mPluginWindow->SetPluginWidget(nullptr);
@@ -2995,72 +2630,6 @@ void nsPluginInstanceOwner::Paint(const RECT& aDirty, HDC aDC)
}
#endif
-#ifdef MOZ_WIDGET_ANDROID
-
-void nsPluginInstanceOwner::Paint(gfxContext* aContext,
- const gfxRect& aFrameRect,
- const gfxRect& aDirtyRect)
-{
- if (!mInstance || !mPluginFrame || !mPluginDocumentActiveState || mFullScreen)
- return;
-
- int32_t model = mInstance->GetANPDrawingModel();
-
- if (model == kSurface_ANPDrawingModel) {
- if (!AddPluginView(GetPluginRect())) {
- Invalidate();
- }
- return;
- }
-
- if (model != kBitmap_ANPDrawingModel)
- return;
-
-#ifdef ANP_BITMAP_DRAWING_MODEL
- static RefPtr<gfxImageSurface> pluginSurface;
-
- if (pluginSurface == nullptr ||
- aFrameRect.width != pluginSurface->Width() ||
- aFrameRect.height != pluginSurface->Height()) {
-
- pluginSurface = new gfxImageSurface(gfx::IntSize(aFrameRect.width, aFrameRect.height),
- SurfaceFormat::A8R8G8B8_UINT32);
- if (!pluginSurface)
- return;
- }
-
- // Clears buffer. I think this is needed.
- gfxUtils::ClearThebesSurface(pluginSurface);
-
- ANPEvent event;
- event.inSize = sizeof(ANPEvent);
- event.eventType = 4;
- event.data.draw.model = 1;
-
- event.data.draw.clip.top = 0;
- event.data.draw.clip.left = 0;
- event.data.draw.clip.bottom = aFrameRect.width;
- event.data.draw.clip.right = aFrameRect.height;
-
- event.data.draw.data.bitmap.format = kRGBA_8888_ANPBitmapFormat;
- event.data.draw.data.bitmap.width = aFrameRect.width;
- event.data.draw.data.bitmap.height = aFrameRect.height;
- event.data.draw.data.bitmap.baseAddr = pluginSurface->Data();
- event.data.draw.data.bitmap.rowBytes = aFrameRect.width * 4;
-
- if (!mInstance)
- return;
-
- mInstance->HandleEvent(&event, nullptr);
-
- aContext->SetOp(gfx::CompositionOp::OP_SOURCE);
- aContext->SetSource(pluginSurface, gfxPoint(aFrameRect.x, aFrameRect.y));
- aContext->Clip(aFrameRect);
- aContext->Paint();
-#endif
-}
-#endif
-
#if defined(MOZ_X11)
void nsPluginInstanceOwner::Paint(gfxContext* aContext,
const gfxRect& aFrameRect,
@@ -3663,24 +3232,6 @@ nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive)
#ifndef XP_MACOSX
UpdateWindowPositionAndClipRect(true);
-#ifdef MOZ_WIDGET_ANDROID
- if (mInstance) {
- if (!mPluginDocumentActiveState) {
- RemovePluginView();
- }
-
- mInstance->NotifyOnScreen(mPluginDocumentActiveState);
-
- // This is, perhaps, incorrect. It is supposed to be sent
- // when "the webview has paused or resumed". The side effect
- // is that Flash video players pause or resume (if they were
- // playing before) based on the value here. I personally think
- // we want that on Android when switching to another tab, so
- // that's why we call it here.
- mInstance->NotifyForeground(mPluginDocumentActiveState);
- }
-#endif // #ifdef MOZ_WIDGET_ANDROID
-
// We don't have a connection to PluginWidgetParent in the chrome
// process when dealing with tab visibility changes, so this needs
// to be forwarded over after the active state is updated. If we
diff --git a/dom/plugins/base/nsPluginInstanceOwner.h b/dom/plugins/base/nsPluginInstanceOwner.h
index 589bcb02c..2fa67c86e 100644
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -29,7 +29,7 @@ class nsPluginDOMContextMenuListener;
class nsPluginFrame;
class nsDisplayListBuilder;
-#if defined(MOZ_X11) || defined(ANDROID)
+#ifdef MOZ_X11
class gfxContext;
#endif
@@ -108,7 +108,7 @@ public:
void Paint(const gfxRect& aDirtyRect, CGContextRef cgContext);
void RenderCoreAnimation(CGContextRef aCGContext, int aWidth, int aHeight);
void DoCocoaEventDrawRect(const gfxRect& aDrawRect, CGContextRef cgContext);
-#elif defined(MOZ_X11) || defined(ANDROID)
+#elif defined(MOZ_X11)
void Paint(gfxContext* aContext,
const gfxRect& aFrameRect,
const gfxRect& aDirtyRect);
@@ -254,21 +254,6 @@ public:
already_AddRefed<nsIURI> GetBaseURI() const;
-#ifdef MOZ_WIDGET_ANDROID
- // Returns the image container for the specified VideoInfo
- void GetVideos(nsTArray<nsNPAPIPluginInstance::VideoInfo*>& aVideos);
- already_AddRefed<mozilla::layers::ImageContainer> GetImageContainerForVideo(nsNPAPIPluginInstance::VideoInfo* aVideoInfo);
-
- void Invalidate();
- void Recomposite();
-
- void RequestFullScreen();
- void ExitFullScreen();
-
- // Called from nsAppShell when we removed the fullscreen view.
- static void ExitFullScreen(jobject view);
-#endif
-
void NotifyHostAsyncInitFailed();
void NotifyHostCreateWidget();
void NotifyDestroyPending();
@@ -306,16 +291,7 @@ private:
size == nsIntSize(mPluginWindow->width, mPluginWindow->height);
}
-#ifdef MOZ_WIDGET_ANDROID
- mozilla::LayoutDeviceRect GetPluginRect();
- bool AddPluginView(const mozilla::LayoutDeviceRect& aRect = mozilla::LayoutDeviceRect(0, 0, 0, 0));
- void RemovePluginView();
-
- bool mFullScreen;
- void* mJavaView;
-#endif
-
-#if defined(XP_WIN)
+#ifdef XP_WIN
nsIWidget* GetContainingWidgetIfOffset();
already_AddRefed<mozilla::TextComposition> GetTextComposition();
void HandleNoConsumedCompositionMessage(
diff --git a/dom/plugins/base/nsPluginTags.cpp b/dom/plugins/base/nsPluginTags.cpp
index a794c416c..58b413388 100644
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -735,10 +735,6 @@ nsPluginTag::GetNiceName(nsACString & aResult)
NS_IMETHODIMP
nsPluginTag::GetBlocklistState(uint32_t *aResult)
{
-#if defined(MOZ_WIDGET_ANDROID)
- *aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
- return NS_OK;
-#else
if (mCachedBlocklistStateValid) {
*aResult = mCachedBlocklistState;
return NS_OK;
@@ -772,7 +768,6 @@ nsPluginTag::GetBlocklistState(uint32_t *aResult)
mCachedBlocklistState = (uint16_t) *aResult;
mCachedBlocklistStateValid = true;
return NS_OK;
-#endif // defined(MOZ_WIDGET_ANDROID)
}
void
diff --git a/dom/plugins/base/nsPluginsDirUnix.cpp b/dom/plugins/base/nsPluginsDirUnix.cpp
index de3b7a2d1..55a4eb0d6 100644
--- a/dom/plugins/base/nsPluginsDirUnix.cpp
+++ b/dom/plugins/base/nsPluginsDirUnix.cpp
@@ -206,16 +206,6 @@ bool nsPluginsDir::IsPluginFile(nsIFile* file)
if (NS_FAILED(file->GetNativeLeafName(filename)))
return false;
-#ifdef ANDROID
- // It appears that if you load
- // 'libstagefright_honeycomb.so' on froyo, or
- // 'libstagefright_froyo.so' on honeycomb, we will abort.
- // Since these are just helper libs, we can ignore.
- const char *cFile = filename.get();
- if (strstr(cFile, "libstagefright") != nullptr)
- return false;
-#endif
-
NS_NAMED_LITERAL_CSTRING(dllSuffix, LOCAL_PLUGIN_DLL_SUFFIX);
if (filename.Length() > dllSuffix.Length() &&
StringEndsWith(filename, dllSuffix))
diff --git a/dom/plugins/ipc/NPEventAndroid.h b/dom/plugins/ipc/NPEventAndroid.h
deleted file mode 100644
index f664af857..000000000
--- a/dom/plugins/ipc/NPEventAndroid.h
+++ /dev/null
@@ -1,55 +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/. */
-
-// This is a NPEventX11.h derived stub for Android
-// Plugins aren't actually supported yet
-
-#ifndef mozilla_dom_plugins_NPEventAndroid_h
-#define mozilla_dom_plugins_NPEventAndroid_h
-
-#include "npapi.h"
-
-namespace mozilla {
-
-namespace plugins {
-
-struct NPRemoteEvent {
- NPEvent event;
-};
-
-}
-
-}
-
-
-namespace IPC {
-
-template <>
-struct ParamTraits<mozilla::plugins::NPRemoteEvent>
-{
- typedef mozilla::plugins::NPRemoteEvent paramType;
-
- static void Write(Message* aMsg, const paramType& aParam)
- {
- aMsg->WriteBytes(&aParam, sizeof(paramType));
- }
-
- static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
- {
- return aMsg->ReadBytesInto(aIter, aResult, sizeof(paramType));
- }
-
- static void Log(const paramType& aParam, std::wstring* aLog)
- {
- // TODO
- aLog->append(L"(AndroidEvent)");
- }
-};
-
-} // namespace IPC
-
-
-#endif // mozilla_dom_plugins_NPEventAndroid_h
diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp
index 3f2cdbc13..a4f6b6b51 100644
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -1427,8 +1427,6 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
if (mPluginIface->setwindow)
(void) mPluginIface->setwindow(&mData, &mWindow);
-#elif defined(ANDROID)
- // TODO: Need Android impl
#elif defined(MOZ_WIDGET_UIKIT)
// Don't care
#else
diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp
index bdd15ca99..24b1410bc 100644
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -265,9 +265,6 @@ PluginInstanceParent::AnswerNPN_GetValue_NPNVnetscapeWindow(NativeWindowHandle*
XID id;
#elif defined(XP_DARWIN)
intptr_t id;
-#elif defined(ANDROID)
- // TODO: Need Android impl
- int id;
#else
#warning Implement me
#endif
diff --git a/dom/plugins/ipc/PluginMessageUtils.h b/dom/plugins/ipc/PluginMessageUtils.h
index 4532fac93..a9cd52ae2 100644
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -111,7 +111,7 @@ struct NPAudioDeviceChangeDetailsIPC
typedef HWND NativeWindowHandle;
#elif defined(MOZ_X11)
typedef XID NativeWindowHandle;
-#elif defined(XP_DARWIN) || defined(ANDROID)
+#elif defined(XP_DARWIN)
typedef intptr_t NativeWindowHandle; // never actually used, will always be 0
#else
#error Need NativeWindowHandle for this platform
@@ -736,8 +736,6 @@ struct ParamTraits<mozilla::plugins::NPAudioDeviceChangeDetailsIPC>
# include "mozilla/plugins/NPEventOSX.h"
#elif defined(XP_WIN)
# include "mozilla/plugins/NPEventWindows.h"
-#elif defined(ANDROID)
-# include "mozilla/plugins/NPEventAndroid.h"
#elif defined(XP_UNIX)
# include "mozilla/plugins/NPEventUnix.h"
#else
diff --git a/dom/plugins/ipc/moz.build b/dom/plugins/ipc/moz.build
index 15ed6410d..051d5a3b4 100644
--- a/dom/plugins/ipc/moz.build
+++ b/dom/plugins/ipc/moz.build
@@ -17,7 +17,6 @@ EXPORTS.mozilla.plugins += [
'BrowserStreamParent.h',
'ChildAsyncCall.h',
'ChildTimer.h',
- 'NPEventAndroid.h',
'NPEventOSX.h',
'NPEventUnix.h',
'NPEventWindows.h',
diff --git a/dom/presentation/AvailabilityCollection.cpp b/dom/presentation/AvailabilityCollection.cpp
deleted file mode 100644
index 73752c750..000000000
--- a/dom/presentation/AvailabilityCollection.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/* -*- 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/. */
-
-#include "AvailabilityCollection.h"
-
-#include "mozilla/ClearOnShutdown.h"
-#include "PresentationAvailability.h"
-
-namespace mozilla {
-namespace dom {
-
-/* static */
-StaticAutoPtr<AvailabilityCollection>
-AvailabilityCollection::sSingleton;
-static bool gOnceAliveNowDead = false;
-
-/* static */ AvailabilityCollection*
-AvailabilityCollection::GetSingleton()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (!sSingleton && !gOnceAliveNowDead) {
- sSingleton = new AvailabilityCollection();
- ClearOnShutdown(&sSingleton);
- }
-
- return sSingleton;
-}
-
-AvailabilityCollection::AvailabilityCollection()
-{
- MOZ_COUNT_CTOR(AvailabilityCollection);
-}
-
-AvailabilityCollection::~AvailabilityCollection()
-{
- MOZ_COUNT_DTOR(AvailabilityCollection);
- gOnceAliveNowDead = true;
-}
-
-void
-AvailabilityCollection::Add(PresentationAvailability* aAvailability)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (!aAvailability) {
- return;
- }
-
- WeakPtr<PresentationAvailability> availability = aAvailability;
- if (mAvailabilities.Contains(aAvailability)) {
- return;
- }
-
- mAvailabilities.AppendElement(aAvailability);
-}
-
-void
-AvailabilityCollection::Remove(PresentationAvailability* aAvailability)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (!aAvailability) {
- return;
- }
-
- WeakPtr<PresentationAvailability> availability = aAvailability;
- mAvailabilities.RemoveElement(availability);
-}
-
-already_AddRefed<PresentationAvailability>
-AvailabilityCollection::Find(const uint64_t aWindowId, const nsTArray<nsString>& aUrls)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- // Loop backwards to allow removing elements in the loop.
- for (int i = mAvailabilities.Length() - 1; i >= 0; --i) {
- WeakPtr<PresentationAvailability> availability = mAvailabilities[i];
- if (!availability) {
- // The availability object was destroyed. Remove it from the list.
- mAvailabilities.RemoveElementAt(i);
- continue;
- }
-
- if (availability->Equals(aWindowId, aUrls)) {
- RefPtr<PresentationAvailability> matchedAvailability = availability.get();
- return matchedAvailability.forget();
- }
- }
-
-
- return nullptr;
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/AvailabilityCollection.h b/dom/presentation/AvailabilityCollection.h
deleted file mode 100644
index d2faae4c2..000000000
--- a/dom/presentation/AvailabilityCollection.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- 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_AvailabilityCollection_h
-#define mozilla_dom_AvailabilityCollection_h
-
-#include "mozilla/StaticPtr.h"
-#include "mozilla/WeakPtr.h"
-#include "nsString.h"
-#include "nsTArray.h"
-
-namespace mozilla {
-namespace dom {
-
-class PresentationAvailability;
-
-class AvailabilityCollection final
-{
-public:
- static AvailabilityCollection* GetSingleton();
-
- void Add(PresentationAvailability* aAvailability);
-
- void Remove(PresentationAvailability* aAvailability);
-
- already_AddRefed<PresentationAvailability>
- Find(const uint64_t aWindowId, const nsTArray<nsString>& aUrls);
-
-private:
- friend class StaticAutoPtr<AvailabilityCollection>;
-
- AvailabilityCollection();
- virtual ~AvailabilityCollection();
-
- static StaticAutoPtr<AvailabilityCollection> sSingleton;
- nsTArray<WeakPtr<PresentationAvailability>> mAvailabilities;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_AvailabilityCollection_h
diff --git a/dom/presentation/ControllerConnectionCollection.cpp b/dom/presentation/ControllerConnectionCollection.cpp
deleted file mode 100644
index 7d3ffe684..000000000
--- a/dom/presentation/ControllerConnectionCollection.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/* -*- 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/. */
-
-#include "ControllerConnectionCollection.h"
-
-#include "mozilla/ClearOnShutdown.h"
-#include "nsIPresentationService.h"
-#include "PresentationConnection.h"
-
-namespace mozilla {
-namespace dom {
-
-/* static */
-StaticAutoPtr<ControllerConnectionCollection>
-ControllerConnectionCollection::sSingleton;
-
-/* static */ ControllerConnectionCollection*
-ControllerConnectionCollection::GetSingleton()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (!sSingleton) {
- sSingleton = new ControllerConnectionCollection();
- ClearOnShutdown(&sSingleton);
- }
-
- return sSingleton;
-}
-
-ControllerConnectionCollection::ControllerConnectionCollection()
-{
- MOZ_COUNT_CTOR(ControllerConnectionCollection);
-}
-
-ControllerConnectionCollection::~ControllerConnectionCollection()
-{
- MOZ_COUNT_DTOR(ControllerConnectionCollection);
-}
-
-void
-ControllerConnectionCollection::AddConnection(
- PresentationConnection* aConnection,
- const uint8_t aRole)
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
- MOZ_ASSERT(false, "This is allowed only to be called at controller side.");
- return;
- }
-
- if (!aConnection) {
- return;
- }
-
- WeakPtr<PresentationConnection> connection = aConnection;
- if (mConnections.Contains(connection)) {
- return;
- }
-
- mConnections.AppendElement(connection);
-}
-
-void
-ControllerConnectionCollection::RemoveConnection(
- PresentationConnection* aConnection,
- const uint8_t aRole)
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
- MOZ_ASSERT(false, "This is allowed only to be called at controller side.");
- return;
- }
-
- if (!aConnection) {
- return;
- }
-
- WeakPtr<PresentationConnection> connection = aConnection;
- mConnections.RemoveElement(connection);
-}
-
-already_AddRefed<PresentationConnection>
-ControllerConnectionCollection::FindConnection(
- uint64_t aWindowId,
- const nsAString& aId,
- const uint8_t aRole)
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
- MOZ_ASSERT(false, "This is allowed only to be called at controller side.");
- return nullptr;
- }
-
- // Loop backwards to allow removing elements in the loop.
- for (int i = mConnections.Length() - 1; i >= 0; --i) {
- WeakPtr<PresentationConnection> connection = mConnections[i];
- if (!connection) {
- // The connection was destroyed. Remove it from the list.
- mConnections.RemoveElementAt(i);
- continue;
- }
-
- if (connection->Equals(aWindowId, aId)) {
- RefPtr<PresentationConnection> matchedConnection = connection.get();
- return matchedConnection.forget();
- }
- }
-
- return nullptr;
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/ControllerConnectionCollection.h b/dom/presentation/ControllerConnectionCollection.h
deleted file mode 100644
index c5300fe30..000000000
--- a/dom/presentation/ControllerConnectionCollection.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- 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_ControllerConnectionCollection_h
-#define mozilla_dom_ControllerConnectionCollection_h
-
-#include "mozilla/StaticPtr.h"
-#include "mozilla/WeakPtr.h"
-#include "nsString.h"
-#include "nsTArray.h"
-
-namespace mozilla {
-namespace dom {
-
-class PresentationConnection;
-
-class ControllerConnectionCollection final
-{
-public:
- static ControllerConnectionCollection* GetSingleton();
-
- void AddConnection(PresentationConnection* aConnection,
- const uint8_t aRole);
-
- void RemoveConnection(PresentationConnection* aConnection,
- const uint8_t aRole);
-
- already_AddRefed<PresentationConnection>
- FindConnection(uint64_t aWindowId,
- const nsAString& aId,
- const uint8_t aRole);
-
-private:
- friend class StaticAutoPtr<ControllerConnectionCollection>;
-
- ControllerConnectionCollection();
- virtual ~ControllerConnectionCollection();
-
- static StaticAutoPtr<ControllerConnectionCollection> sSingleton;
- nsTArray<WeakPtr<PresentationConnection>> mConnections;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_ControllerConnectionCollection_h
diff --git a/dom/presentation/DCPresentationChannelDescription.cpp b/dom/presentation/DCPresentationChannelDescription.cpp
deleted file mode 100644
index a904dfe3f..000000000
--- a/dom/presentation/DCPresentationChannelDescription.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/* -*- 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/. */
-
-#include "DCPresentationChannelDescription.h"
-
-namespace mozilla {
-namespace dom {
-
-NS_IMPL_ISUPPORTS(DCPresentationChannelDescription,
- nsIPresentationChannelDescription)
-
-NS_IMETHODIMP
-DCPresentationChannelDescription::GetType(uint8_t* aRetVal)
-{
- if (NS_WARN_IF(!aRetVal)) {
- return NS_ERROR_INVALID_POINTER;
- }
-
- *aRetVal = nsIPresentationChannelDescription::TYPE_DATACHANNEL;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DCPresentationChannelDescription::GetTcpAddress(nsIArray** aRetVal)
-{
- return NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP
-DCPresentationChannelDescription::GetTcpPort(uint16_t* aRetVal)
-{
- return NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP
-DCPresentationChannelDescription::GetDataChannelSDP(nsAString& aDataChannelSDP)
-{
- aDataChannelSDP = mSDP;
- return NS_OK;
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/DCPresentationChannelDescription.h b/dom/presentation/DCPresentationChannelDescription.h
deleted file mode 100644
index 63a058f9a..000000000
--- a/dom/presentation/DCPresentationChannelDescription.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- 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_DCPresentationChannelDescription_h
-#define mozilla_dom_DCPresentationChannelDescription_h
-
-#include "nsIPresentationControlChannel.h"
-#include "nsString.h"
-
-namespace mozilla {
-namespace dom {
-
-// PresentationChannelDescription for Data Channel
-class DCPresentationChannelDescription final : public nsIPresentationChannelDescription
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONCHANNELDESCRIPTION
-
- explicit DCPresentationChannelDescription(const nsAString& aSDP)
- : mSDP(aSDP)
- {
- }
-
-private:
- virtual ~DCPresentationChannelDescription() = default;
-
- nsString mSDP;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_DCPresentationChannelDescription_h
diff --git a/dom/presentation/Presentation.cpp b/dom/presentation/Presentation.cpp
deleted file mode 100644
index 07ca12f26..000000000
--- a/dom/presentation/Presentation.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/* -*- 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/. */
-
-#include "Presentation.h"
-
-#include <ctype.h>
-
-#include "mozilla/dom/PresentationBinding.h"
-#include "mozilla/dom/Promise.h"
-#include "nsContentUtils.h"
-#include "nsCycleCollectionParticipant.h"
-#include "nsIDocShell.h"
-#include "nsIPresentationService.h"
-#include "nsIScriptSecurityManager.h"
-#include "nsJSUtils.h"
-#include "nsNetUtil.h"
-#include "nsPIDOMWindow.h"
-#include "nsSandboxFlags.h"
-#include "nsServiceManagerUtils.h"
-#include "PresentationReceiver.h"
-
-namespace mozilla {
-namespace dom {
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Presentation,
- mWindow,
- mDefaultRequest, mReceiver)
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(Presentation)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(Presentation)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Presentation)
- NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
- NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-/* static */ already_AddRefed<Presentation>
-Presentation::Create(nsPIDOMWindowInner* aWindow)
-{
- RefPtr<Presentation> presentation = new Presentation(aWindow);
- return presentation.forget();
-}
-
-Presentation::Presentation(nsPIDOMWindowInner* aWindow)
- : mWindow(aWindow)
-{
-}
-
-Presentation::~Presentation()
-{
-}
-
-/* virtual */ JSObject*
-Presentation::WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto)
-{
- return PresentationBinding::Wrap(aCx, this, aGivenProto);
-}
-
-void
-Presentation::SetDefaultRequest(PresentationRequest* aRequest)
-{
- nsCOMPtr<nsIDocument> doc = mWindow ? mWindow->GetExtantDoc() : nullptr;
- if (NS_WARN_IF(!doc)) {
- return;
- }
-
- if (doc->GetSandboxFlags() & SANDBOXED_PRESENTATION) {
- return;
- }
-
- mDefaultRequest = aRequest;
-}
-
-already_AddRefed<PresentationRequest>
-Presentation::GetDefaultRequest() const
-{
- RefPtr<PresentationRequest> request = mDefaultRequest;
- return request.forget();
-}
-
-already_AddRefed<PresentationReceiver>
-Presentation::GetReceiver()
-{
- // return the same receiver if already created
- if (mReceiver) {
- RefPtr<PresentationReceiver> receiver = mReceiver;
- return receiver.forget();
- }
-
- if (!HasReceiverSupport() || !IsInPresentedContent()) {
- return nullptr;
- }
-
- mReceiver = PresentationReceiver::Create(mWindow);
- if (NS_WARN_IF(!mReceiver)) {
- MOZ_ASSERT(mReceiver);
- return nullptr;
- }
-
- RefPtr<PresentationReceiver> receiver = mReceiver;
- return receiver.forget();
-}
-
-void
-Presentation::SetStartSessionUnsettled(bool aIsUnsettled)
-{
- mStartSessionUnsettled = aIsUnsettled;
-}
-
-bool
-Presentation::IsStartSessionUnsettled() const
-{
- return mStartSessionUnsettled;
-}
-
-bool
-Presentation::HasReceiverSupport() const
-{
- if (!mWindow) {
- return false;
- }
-
- // Grant access to browser receiving pages and their same-origin iframes. (App
- // pages should be controlled by "presentation" permission in app manifests.)
- nsCOMPtr<nsIDocShell> docShell = mWindow->GetDocShell();
- if (!docShell) {
- return false;
- }
-
- if (!Preferences::GetBool("dom.presentation.testing.simulate-receiver") &&
- !docShell->GetIsInMozBrowserOrApp() &&
- !docShell->GetIsTopLevelContentDocShell()) {
- return false;
- }
-
- nsAutoString presentationURL;
- nsContentUtils::GetPresentationURL(docShell, presentationURL);
-
- if (presentationURL.IsEmpty()) {
- return false;
- }
-
- nsCOMPtr<nsIScriptSecurityManager> securityManager =
- nsContentUtils::GetSecurityManager();
- if (!securityManager) {
- return false;
- }
-
- nsCOMPtr<nsIURI> presentationURI;
- nsresult rv = NS_NewURI(getter_AddRefs(presentationURI), presentationURL);
- if (NS_FAILED(rv)) {
- return false;
- }
-
- nsCOMPtr<nsIURI> docURI = mWindow->GetDocumentURI();
- return NS_SUCCEEDED(securityManager->CheckSameOriginURI(presentationURI,
- docURI,
- false));
-}
-
-bool
-Presentation::IsInPresentedContent() const
-{
- if (!mWindow) {
- return false;
- }
-
- nsCOMPtr<nsIDocShell> docShell = mWindow->GetDocShell();
- MOZ_ASSERT(docShell);
-
- nsAutoString presentationURL;
- nsContentUtils::GetPresentationURL(docShell, presentationURL);
-
- return !presentationURL.IsEmpty();
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/Presentation.h b/dom/presentation/Presentation.h
deleted file mode 100644
index 08d0003b3..000000000
--- a/dom/presentation/Presentation.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- 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_Presentation_h
-#define mozilla_dom_Presentation_h
-
-#include "nsCOMPtr.h"
-#include "nsCycleCollectionParticipant.h"
-#include "nsISupportsImpl.h"
-#include "nsWrapperCache.h"
-
-class nsPIDOMWindowInner;
-
-namespace mozilla {
-namespace dom {
-
-class Promise;
-class PresentationReceiver;
-class PresentationRequest;
-
-class Presentation final : public nsISupports
- , public nsWrapperCache
-{
-public:
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Presentation)
-
- static already_AddRefed<Presentation> Create(nsPIDOMWindowInner* aWindow);
-
- virtual JSObject* WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto) override;
-
- nsPIDOMWindowInner* GetParentObject() const
- {
- return mWindow;
- }
-
- // WebIDL (public APIs)
- void SetDefaultRequest(PresentationRequest* aRequest);
-
- already_AddRefed<PresentationRequest> GetDefaultRequest() const;
-
- already_AddRefed<PresentationReceiver> GetReceiver();
-
- // For bookkeeping unsettled start session request
- void SetStartSessionUnsettled(bool aIsUnsettled);
- bool IsStartSessionUnsettled() const;
-
-private:
- explicit Presentation(nsPIDOMWindowInner* aWindow);
-
- virtual ~Presentation();
-
- bool HasReceiverSupport() const;
-
- bool IsInPresentedContent() const;
-
- RefPtr<PresentationRequest> mDefaultRequest;
- RefPtr<PresentationReceiver> mReceiver;
- nsCOMPtr<nsPIDOMWindowInner> mWindow;
- bool mStartSessionUnsettled = false;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_Presentation_h
diff --git a/dom/presentation/PresentationAvailability.cpp b/dom/presentation/PresentationAvailability.cpp
deleted file mode 100644
index 93f27dfbf..000000000
--- a/dom/presentation/PresentationAvailability.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/* -*- 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/. */
-
-#include "PresentationAvailability.h"
-
-#include "mozilla/dom/PresentationAvailabilityBinding.h"
-#include "mozilla/dom/Promise.h"
-#include "mozilla/Unused.h"
-#include "nsCycleCollectionParticipant.h"
-#include "nsIPresentationDeviceManager.h"
-#include "nsIPresentationService.h"
-#include "nsServiceManagerUtils.h"
-#include "PresentationLog.h"
-
-using namespace mozilla;
-using namespace mozilla::dom;
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(PresentationAvailability)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PresentationAvailability, DOMEventTargetHelper)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromises)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PresentationAvailability, DOMEventTargetHelper)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromises);
- tmp->Shutdown();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_ADDREF_INHERITED(PresentationAvailability, DOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(PresentationAvailability, DOMEventTargetHelper)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PresentationAvailability)
- NS_INTERFACE_MAP_ENTRY(nsIPresentationAvailabilityListener)
-NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-
-/* static */ already_AddRefed<PresentationAvailability>
-PresentationAvailability::Create(nsPIDOMWindowInner* aWindow,
- const nsTArray<nsString>& aUrls,
- RefPtr<Promise>& aPromise)
-{
- RefPtr<PresentationAvailability> availability =
- new PresentationAvailability(aWindow, aUrls);
- return NS_WARN_IF(!availability->Init(aPromise)) ? nullptr
- : availability.forget();
-}
-
-PresentationAvailability::PresentationAvailability(nsPIDOMWindowInner* aWindow,
- const nsTArray<nsString>& aUrls)
- : DOMEventTargetHelper(aWindow)
- , mIsAvailable(false)
- , mUrls(aUrls)
-{
- for (uint32_t i = 0; i < mUrls.Length(); ++i) {
- mAvailabilityOfUrl.AppendElement(false);
- }
-}
-
-PresentationAvailability::~PresentationAvailability()
-{
- Shutdown();
-}
-
-bool
-PresentationAvailability::Init(RefPtr<Promise>& aPromise)
-{
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return false;
- }
-
- nsresult rv = service->RegisterAvailabilityListener(mUrls, this);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- // If the user agent is unable to monitor available device,
- // Resolve promise with |value| set to false.
- mIsAvailable = false;
- aPromise->MaybeResolve(this);
- return true;
- }
-
- EnqueuePromise(aPromise);
-
- AvailabilityCollection* collection = AvailabilityCollection::GetSingleton();
- if (collection) {
- collection->Add(this);
- }
-
- return true;
-}
-
-void PresentationAvailability::Shutdown()
-{
- AvailabilityCollection* collection = AvailabilityCollection::GetSingleton();
- if (collection ) {
- collection->Remove(this);
- }
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return;
- }
-
- Unused <<
- NS_WARN_IF(NS_FAILED(service->UnregisterAvailabilityListener(mUrls,
- this)));
-}
-
-/* virtual */ void
-PresentationAvailability::DisconnectFromOwner()
-{
- Shutdown();
- DOMEventTargetHelper::DisconnectFromOwner();
-}
-
-/* virtual */ JSObject*
-PresentationAvailability::WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto)
-{
- return PresentationAvailabilityBinding::Wrap(aCx, this, aGivenProto);
-}
-
-bool
-PresentationAvailability::Equals(const uint64_t aWindowID,
- const nsTArray<nsString>& aUrls) const
-{
- if (GetOwner() && GetOwner()->WindowID() == aWindowID &&
- mUrls.Length() == aUrls.Length()) {
- for (const auto& url : aUrls) {
- if (!mUrls.Contains(url)) {
- return false;
- }
- }
- return true;
- }
-
- return false;
-}
-
-bool
-PresentationAvailability::IsCachedValueReady()
-{
- // All pending promises will be solved when cached value is ready and
- // no promise should be enqueued afterward.
- return mPromises.IsEmpty();
-}
-
-void
-PresentationAvailability::EnqueuePromise(RefPtr<Promise>& aPromise)
-{
- mPromises.AppendElement(aPromise);
-}
-
-bool
-PresentationAvailability::Value() const
-{
- return mIsAvailable;
-}
-
-NS_IMETHODIMP
-PresentationAvailability::NotifyAvailableChange(const nsTArray<nsString>& aAvailabilityUrls,
- bool aIsAvailable)
-{
- bool available = false;
- for (uint32_t i = 0; i < mUrls.Length(); ++i) {
- if (aAvailabilityUrls.Contains(mUrls[i])) {
- mAvailabilityOfUrl[i] = aIsAvailable;
- }
- available |= mAvailabilityOfUrl[i];
- }
-
- return NS_DispatchToCurrentThread(NewRunnableMethod
- <bool>(this,
- &PresentationAvailability::UpdateAvailabilityAndDispatchEvent,
- available));
-}
-
-void
-PresentationAvailability::UpdateAvailabilityAndDispatchEvent(bool aIsAvailable)
-{
- PRES_DEBUG("%s\n", __func__);
- bool isChanged = (aIsAvailable != mIsAvailable);
-
- mIsAvailable = aIsAvailable;
-
- if (!mPromises.IsEmpty()) {
- // Use the first availability change notification to resolve promise.
- do {
- nsTArray<RefPtr<Promise>> promises = Move(mPromises);
- for (auto& promise : promises) {
- promise->MaybeResolve(this);
- }
- // more promises may have been added to mPromises, at least in theory
- } while (!mPromises.IsEmpty());
-
- return;
- }
-
- if (isChanged) {
- Unused <<
- NS_WARN_IF(NS_FAILED(DispatchTrustedEvent(NS_LITERAL_STRING("change"))));
- }
-}
diff --git a/dom/presentation/PresentationAvailability.h b/dom/presentation/PresentationAvailability.h
deleted file mode 100644
index edfae2c02..000000000
--- a/dom/presentation/PresentationAvailability.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- 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_PresentationAvailability_h
-#define mozilla_dom_PresentationAvailability_h
-
-#include "mozilla/DOMEventTargetHelper.h"
-#include "nsIPresentationListener.h"
-#include "nsTArray.h"
-
-namespace mozilla {
-namespace dom {
-
-class Promise;
-
-class PresentationAvailability final : public DOMEventTargetHelper
- , public nsIPresentationAvailabilityListener
- , public SupportsWeakPtr<PresentationAvailability>
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PresentationAvailability,
- DOMEventTargetHelper)
- NS_DECL_NSIPRESENTATIONAVAILABILITYLISTENER
- MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PresentationAvailability)
-
- static already_AddRefed<PresentationAvailability>
- Create(nsPIDOMWindowInner* aWindow,
- const nsTArray<nsString>& aUrls,
- RefPtr<Promise>& aPromise);
-
- virtual void DisconnectFromOwner() override;
-
- virtual JSObject* WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto) override;
-
- bool Equals(const uint64_t aWindowID, const nsTArray<nsString>& aUrls) const;
-
- bool IsCachedValueReady();
-
- void EnqueuePromise(RefPtr<Promise>& aPromise);
-
- // WebIDL (public APIs)
- bool Value() const;
-
- IMPL_EVENT_HANDLER(change);
-
-private:
- explicit PresentationAvailability(nsPIDOMWindowInner* aWindow,
- const nsTArray<nsString>& aUrls);
-
- virtual ~PresentationAvailability();
-
- bool Init(RefPtr<Promise>& aPromise);
-
- void Shutdown();
-
- void UpdateAvailabilityAndDispatchEvent(bool aIsAvailable);
-
- bool mIsAvailable;
-
- nsTArray<RefPtr<Promise>> mPromises;
-
- nsTArray<nsString> mUrls;
- nsTArray<bool> mAvailabilityOfUrl;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationAvailability_h
diff --git a/dom/presentation/PresentationCallbacks.cpp b/dom/presentation/PresentationCallbacks.cpp
deleted file mode 100644
index fd0ffee31..000000000
--- a/dom/presentation/PresentationCallbacks.cpp
+++ /dev/null
@@ -1,282 +0,0 @@
-/* -*- 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/. */
-
-#include "mozilla/dom/Promise.h"
-#include "nsIDocShell.h"
-#include "nsIInterfaceRequestorUtils.h"
-#include "nsIPresentationService.h"
-#include "nsIWebProgress.h"
-#include "nsServiceManagerUtils.h"
-#include "nsThreadUtils.h"
-#include "PresentationCallbacks.h"
-#include "PresentationRequest.h"
-#include "PresentationConnection.h"
-#include "PresentationTransportBuilderConstructor.h"
-
-using namespace mozilla;
-using namespace mozilla::dom;
-
-/*
- * Implementation of PresentationRequesterCallback
- */
-
-NS_IMPL_ISUPPORTS(PresentationRequesterCallback, nsIPresentationServiceCallback)
-
-PresentationRequesterCallback::PresentationRequesterCallback(PresentationRequest* aRequest,
- const nsAString& aSessionId,
- Promise* aPromise)
- : mRequest(aRequest)
- , mSessionId(aSessionId)
- , mPromise(aPromise)
-{
- MOZ_ASSERT(mRequest);
- MOZ_ASSERT(mPromise);
- MOZ_ASSERT(!mSessionId.IsEmpty());
-}
-
-PresentationRequesterCallback::~PresentationRequesterCallback()
-{
-}
-
-// nsIPresentationServiceCallback
-NS_IMETHODIMP
-PresentationRequesterCallback::NotifySuccess(const nsAString& aUrl)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (aUrl.IsEmpty()) {
- return NotifyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- RefPtr<PresentationConnection> connection =
- PresentationConnection::Create(mRequest->GetOwner(), mSessionId, aUrl,
- nsIPresentationService::ROLE_CONTROLLER);
- if (NS_WARN_IF(!connection)) {
- return NotifyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- mRequest->NotifyPromiseSettled();
- mPromise->MaybeResolve(connection);
-
- return mRequest->DispatchConnectionAvailableEvent(connection);
-}
-
-NS_IMETHODIMP
-PresentationRequesterCallback::NotifyError(nsresult aError)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- mRequest->NotifyPromiseSettled();
- mPromise->MaybeReject(aError);
- return NS_OK;
-}
-
-/*
- * Implementation of PresentationRequesterCallback
- */
-
-NS_IMPL_ISUPPORTS_INHERITED0(PresentationReconnectCallback,
- PresentationRequesterCallback)
-
-PresentationReconnectCallback::PresentationReconnectCallback(
- PresentationRequest* aRequest,
- const nsAString& aSessionId,
- Promise* aPromise,
- PresentationConnection* aConnection)
- : PresentationRequesterCallback(aRequest, aSessionId, aPromise)
- , mConnection(aConnection)
-{
-}
-
-PresentationReconnectCallback::~PresentationReconnectCallback()
-{
-}
-
-NS_IMETHODIMP
-PresentationReconnectCallback::NotifySuccess(const nsAString& aUrl)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- nsresult rv = NS_OK;
- // We found a matched connection with the same window ID, URL, and
- // the session ID. Resolve the promise with this connection and dispatch
- // the event.
- if (mConnection) {
- mConnection->NotifyStateChange(
- mSessionId,
- nsIPresentationSessionListener::STATE_CONNECTING,
- NS_OK);
- mPromise->MaybeResolve(mConnection);
- rv = mRequest->DispatchConnectionAvailableEvent(mConnection);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- } else {
- // Use |PresentationRequesterCallback::NotifySuccess| to create a new
- // connection since we don't find one that can be reused.
- rv = PresentationRequesterCallback::NotifySuccess(aUrl);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = service->UpdateWindowIdBySessionId(mSessionId,
- nsIPresentationService::ROLE_CONTROLLER,
- mRequest->GetOwner()->WindowID());
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- }
-
- nsString sessionId = nsString(mSessionId);
- return NS_DispatchToMainThread(
- NS_NewRunnableFunction([sessionId, service]() -> void {
- service->BuildTransport(sessionId,
- nsIPresentationService::ROLE_CONTROLLER);
- }));
-}
-
-NS_IMETHODIMP
-PresentationReconnectCallback::NotifyError(nsresult aError)
-{
- if (mConnection) {
- mConnection->NotifyStateChange(
- mSessionId,
- nsIPresentationSessionListener::STATE_CLOSED,
- aError);
- }
- return PresentationRequesterCallback::NotifyError(aError);
-}
-
-NS_IMPL_ISUPPORTS(PresentationResponderLoadingCallback,
- nsIWebProgressListener,
- nsISupportsWeakReference)
-
-PresentationResponderLoadingCallback::PresentationResponderLoadingCallback(const nsAString& aSessionId)
- : mSessionId(aSessionId)
-{
-}
-
-PresentationResponderLoadingCallback::~PresentationResponderLoadingCallback()
-{
- if (mProgress) {
- mProgress->RemoveProgressListener(this);
- mProgress = nullptr;
- }
-}
-
-nsresult
-PresentationResponderLoadingCallback::Init(nsIDocShell* aDocShell)
-{
- mProgress = do_GetInterface(aDocShell);
- if (NS_WARN_IF(!mProgress)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
- nsresult rv = aDocShell->GetBusyFlags(&busyFlags);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- if ((busyFlags == nsIDocShell::BUSY_FLAGS_NONE) ||
- (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)) {
- // The docshell has finished loading or is receiving data (|STATE_TRANSFERRING|
- // has already been fired), so the page is ready for presentation use.
- return NotifyReceiverReady(/* isLoading = */ true);
- }
-
- // Start to listen to document state change event |STATE_TRANSFERRING|.
- return mProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
-}
-
-nsresult
-PresentationResponderLoadingCallback::NotifyReceiverReady(bool aIsLoading)
-{
- nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(mProgress);
- if (NS_WARN_IF(!window || !window->GetCurrentInnerWindow())) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- uint64_t windowId = window->GetCurrentInnerWindow()->WindowID();
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- nsCOMPtr<nsIPresentationTransportBuilderConstructor> constructor =
- PresentationTransportBuilderConstructor::Create();
- return service->NotifyReceiverReady(mSessionId,
- windowId,aIsLoading,
- constructor);
-}
-
-// nsIWebProgressListener
-NS_IMETHODIMP
-PresentationResponderLoadingCallback::OnStateChange(nsIWebProgress* aWebProgress,
- nsIRequest* aRequest,
- uint32_t aStateFlags,
- nsresult aStatus)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (aStateFlags & (nsIWebProgressListener::STATE_TRANSFERRING |
- nsIWebProgressListener::STATE_STOP)) {
- mProgress->RemoveProgressListener(this);
-
- bool isLoading = aStateFlags & nsIWebProgressListener::STATE_TRANSFERRING;
- return NotifyReceiverReady(isLoading);
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationResponderLoadingCallback::OnProgressChange(nsIWebProgress* aWebProgress,
- nsIRequest* aRequest,
- int32_t aCurSelfProgress,
- int32_t aMaxSelfProgress,
- int32_t aCurTotalProgress,
- int32_t aMaxTotalProgress)
-{
- // Do nothing.
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationResponderLoadingCallback::OnLocationChange(nsIWebProgress* aWebProgress,
- nsIRequest* aRequest,
- nsIURI* aURI,
- uint32_t aFlags)
-{
- // Do nothing.
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationResponderLoadingCallback::OnStatusChange(nsIWebProgress* aWebProgress,
- nsIRequest* aRequest,
- nsresult aStatus,
- const char16_t* aMessage)
-{
- // Do nothing.
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationResponderLoadingCallback::OnSecurityChange(nsIWebProgress* aWebProgress,
- nsIRequest* aRequest,
- uint32_t state)
-{
- // Do nothing.
- return NS_OK;
-}
diff --git a/dom/presentation/PresentationCallbacks.h b/dom/presentation/PresentationCallbacks.h
deleted file mode 100644
index e493b0510..000000000
--- a/dom/presentation/PresentationCallbacks.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* -*- 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_PresentationCallbacks_h
-#define mozilla_dom_PresentationCallbacks_h
-
-#include "mozilla/RefPtr.h"
-#include "nsCOMPtr.h"
-#include "nsIPresentationService.h"
-#include "nsIWebProgressListener.h"
-#include "nsString.h"
-#include "nsWeakReference.h"
-
-class nsIDocShell;
-class nsIWebProgress;
-
-namespace mozilla {
-namespace dom {
-
-class PresentationConnection;
-class PresentationRequest;
-class Promise;
-
-class PresentationRequesterCallback : public nsIPresentationServiceCallback
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONSERVICECALLBACK
-
- PresentationRequesterCallback(PresentationRequest* aRequest,
- const nsAString& aSessionId,
- Promise* aPromise);
-
-protected:
- virtual ~PresentationRequesterCallback();
-
- RefPtr<PresentationRequest> mRequest;
- nsString mSessionId;
- RefPtr<Promise> mPromise;
-};
-
-class PresentationReconnectCallback final : public PresentationRequesterCallback
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_NSIPRESENTATIONSERVICECALLBACK
-
- PresentationReconnectCallback(PresentationRequest* aRequest,
- const nsAString& aSessionId,
- Promise* aPromise,
- PresentationConnection* aConnection);
-
-private:
- virtual ~PresentationReconnectCallback();
-
- RefPtr<PresentationConnection> mConnection;
-};
-
-class PresentationResponderLoadingCallback final : public nsIWebProgressListener
- , public nsSupportsWeakReference
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIWEBPROGRESSLISTENER
-
- explicit PresentationResponderLoadingCallback(const nsAString& aSessionId);
-
- nsresult Init(nsIDocShell* aDocShell);
-
-private:
- ~PresentationResponderLoadingCallback();
-
- nsresult NotifyReceiverReady(bool aIsLoading);
-
- nsString mSessionId;
- nsCOMPtr<nsIWebProgress> mProgress;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationCallbacks_h
diff --git a/dom/presentation/PresentationConnection.cpp b/dom/presentation/PresentationConnection.cpp
deleted file mode 100644
index e9c4a71ca..000000000
--- a/dom/presentation/PresentationConnection.cpp
+++ /dev/null
@@ -1,763 +0,0 @@
-/* -*- 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/. */
-
-#include "PresentationConnection.h"
-
-#include "ControllerConnectionCollection.h"
-#include "mozilla/AsyncEventDispatcher.h"
-#include "mozilla/dom/DOMException.h"
-#include "mozilla/dom/File.h"
-#include "mozilla/dom/MessageEvent.h"
-#include "mozilla/dom/MessageEventBinding.h"
-#include "mozilla/dom/PresentationConnectionCloseEvent.h"
-#include "mozilla/ErrorNames.h"
-#include "mozilla/DebugOnly.h"
-#include "nsContentUtils.h"
-#include "nsCycleCollectionParticipant.h"
-#include "nsIPresentationService.h"
-#include "nsServiceManagerUtils.h"
-#include "nsStringStream.h"
-#include "PresentationConnectionList.h"
-#include "PresentationLog.h"
-
-using namespace mozilla;
-using namespace mozilla::dom;
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(PresentationConnection)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PresentationConnection, DOMEventTargetHelper)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwningConnectionList)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PresentationConnection, DOMEventTargetHelper)
- tmp->Shutdown();
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwningConnectionList)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_ADDREF_INHERITED(PresentationConnection, DOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(PresentationConnection, DOMEventTargetHelper)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PresentationConnection)
- NS_INTERFACE_MAP_ENTRY(nsIPresentationSessionListener)
- NS_INTERFACE_MAP_ENTRY(nsIRequest)
-NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-
-PresentationConnection::PresentationConnection(nsPIDOMWindowInner* aWindow,
- const nsAString& aId,
- const nsAString& aUrl,
- const uint8_t aRole,
- PresentationConnectionList* aList)
- : DOMEventTargetHelper(aWindow)
- , mId(aId)
- , mUrl(aUrl)
- , mState(PresentationConnectionState::Connecting)
- , mOwningConnectionList(aList)
- , mBinaryType(PresentationConnectionBinaryType::Arraybuffer)
-{
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
- mRole = aRole;
-}
-
-/* virtual */ PresentationConnection::~PresentationConnection()
-{
-}
-
-/* static */ already_AddRefed<PresentationConnection>
-PresentationConnection::Create(nsPIDOMWindowInner* aWindow,
- const nsAString& aId,
- const nsAString& aUrl,
- const uint8_t aRole,
- PresentationConnectionList* aList)
-{
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
- RefPtr<PresentationConnection> connection =
- new PresentationConnection(aWindow, aId, aUrl, aRole, aList);
- if (NS_WARN_IF(!connection->Init())) {
- return nullptr;
- }
-
- if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
- ControllerConnectionCollection::GetSingleton()->AddConnection(connection,
- aRole);
- }
-
- return connection.forget();
-}
-
-bool
-PresentationConnection::Init()
-{
- if (NS_WARN_IF(mId.IsEmpty())) {
- return false;
- }
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if(NS_WARN_IF(!service)) {
- return false;
- }
-
- nsresult rv = service->RegisterSessionListener(mId, mRole, this);
- if(NS_WARN_IF(NS_FAILED(rv))) {
- return false;
- }
-
- rv = AddIntoLoadGroup();
- if(NS_WARN_IF(NS_FAILED(rv))) {
- return false;
- }
-
- return true;
-}
-
-void
-PresentationConnection::Shutdown()
-{
- PRES_DEBUG("connection shutdown:id[%s], role[%d]\n",
- NS_ConvertUTF16toUTF8(mId).get(), mRole);
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return;
- }
-
- DebugOnly<nsresult> rv = service->UnregisterSessionListener(mId, mRole);
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "UnregisterSessionListener failed");
-
- DebugOnly<nsresult> rv2 = RemoveFromLoadGroup();
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv2), "RemoveFromLoadGroup failed");
-
- if (mRole == nsIPresentationService::ROLE_CONTROLLER) {
- ControllerConnectionCollection::GetSingleton()->RemoveConnection(this,
- mRole);
- }
-}
-
-/* virtual */ void
-PresentationConnection::DisconnectFromOwner()
-{
- Unused << NS_WARN_IF(NS_FAILED(ProcessConnectionWentAway()));
- DOMEventTargetHelper::DisconnectFromOwner();
-}
-
-/* virtual */ JSObject*
-PresentationConnection::WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto)
-{
- return PresentationConnectionBinding::Wrap(aCx, this, aGivenProto);
-}
-
-void
-PresentationConnection::GetId(nsAString& aId) const
-{
- aId = mId;
-}
-
-void
-PresentationConnection::GetUrl(nsAString& aUrl) const
-{
- aUrl = mUrl;
-}
-
-PresentationConnectionState
-PresentationConnection::State() const
-{
- return mState;
-}
-
-PresentationConnectionBinaryType
-PresentationConnection::BinaryType() const
-{
- return mBinaryType;
-}
-
-void
-PresentationConnection::SetBinaryType(PresentationConnectionBinaryType aType)
-{
- mBinaryType = aType;
-}
-
-void
-PresentationConnection::Send(const nsAString& aData,
- ErrorResult& aRv)
-{
- // Sending is not allowed if the session is not connected.
- if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
- aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return;
- }
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if(NS_WARN_IF(!service)) {
- AsyncCloseConnectionWithErrorMsg(
- NS_LITERAL_STRING("Unable to send message due to an internal error."));
- return;
- }
-
- nsresult rv = service->SendSessionMessage(mId, mRole, aData);
- if(NS_WARN_IF(NS_FAILED(rv))) {
- const uint32_t kMaxMessageLength = 256;
- nsAutoString data(Substring(aData, 0, kMaxMessageLength));
-
- AsyncCloseConnectionWithErrorMsg(
- NS_LITERAL_STRING("Unable to send message: \"") + data +
- NS_LITERAL_STRING("\""));
- }
-}
-
-void
-PresentationConnection::Send(Blob& aData,
- ErrorResult& aRv)
-{
- if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
- aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return;
- }
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if(NS_WARN_IF(!service)) {
- AsyncCloseConnectionWithErrorMsg(
- NS_LITERAL_STRING("Unable to send message due to an internal error."));
- return;
- }
-
- nsresult rv = service->SendSessionBlob(mId, mRole, &aData);
- if(NS_WARN_IF(NS_FAILED(rv))) {
- AsyncCloseConnectionWithErrorMsg(
- NS_LITERAL_STRING("Unable to send binary message for Blob message."));
- }
-}
-
-void
-PresentationConnection::Send(const ArrayBuffer& aData,
- ErrorResult& aRv)
-{
- if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
- aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return;
- }
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if(NS_WARN_IF(!service)) {
- AsyncCloseConnectionWithErrorMsg(
- NS_LITERAL_STRING("Unable to send message due to an internal error."));
- return;
- }
-
- aData.ComputeLengthAndData();
-
- static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
-
- uint32_t length = aData.Length();
- char* data = reinterpret_cast<char*>(aData.Data());
- nsDependentCSubstring msgString(data, length);
-
- nsresult rv = service->SendSessionBinaryMsg(mId, mRole, msgString);
- if(NS_WARN_IF(NS_FAILED(rv))) {
- AsyncCloseConnectionWithErrorMsg(
- NS_LITERAL_STRING("Unable to send binary message for ArrayBuffer message."));
- }
-}
-
-void
-PresentationConnection::Send(const ArrayBufferView& aData,
- ErrorResult& aRv)
-{
- if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
- aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return;
- }
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if(NS_WARN_IF(!service)) {
- AsyncCloseConnectionWithErrorMsg(
- NS_LITERAL_STRING("Unable to send message due to an internal error."));
- return;
- }
-
- aData.ComputeLengthAndData();
-
- static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
-
- uint32_t length = aData.Length();
- char* data = reinterpret_cast<char*>(aData.Data());
- nsDependentCSubstring msgString(data, length);
-
- nsresult rv = service->SendSessionBinaryMsg(mId, mRole, msgString);
- if(NS_WARN_IF(NS_FAILED(rv))) {
- AsyncCloseConnectionWithErrorMsg(
- NS_LITERAL_STRING("Unable to send binary message for ArrayBufferView message."));
- }
-}
-
-void
-PresentationConnection::Close(ErrorResult& aRv)
-{
- // It only works when the state is CONNECTED or CONNECTING.
- if (NS_WARN_IF(mState != PresentationConnectionState::Connected &&
- mState != PresentationConnectionState::Connecting)) {
- return;
- }
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if(NS_WARN_IF(!service)) {
- aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- Unused << NS_WARN_IF(NS_FAILED(
- service->CloseSession(mId,
- mRole,
- nsIPresentationService::CLOSED_REASON_CLOSED)));
-}
-
-void
-PresentationConnection::Terminate(ErrorResult& aRv)
-{
- // It only works when the state is CONNECTED.
- if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
- return;
- }
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if(NS_WARN_IF(!service)) {
- aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- Unused << NS_WARN_IF(NS_FAILED(service->TerminateSession(mId, mRole)));
-}
-
-bool
-PresentationConnection::Equals(uint64_t aWindowId,
- const nsAString& aId)
-{
- return GetOwner() &&
- aWindowId == GetOwner()->WindowID() &&
- mId.Equals(aId);
-}
-
-NS_IMETHODIMP
-PresentationConnection::NotifyStateChange(const nsAString& aSessionId,
- uint16_t aState,
- nsresult aReason)
-{
- PRES_DEBUG("connection state change:id[%s], state[%x], reason[%x], role[%d]\n",
- NS_ConvertUTF16toUTF8(aSessionId).get(), aState,
- aReason, mRole);
-
- if (!aSessionId.Equals(mId)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- // A terminated connection should always remain in terminated.
- if (mState == PresentationConnectionState::Terminated) {
- return NS_OK;
- }
-
- PresentationConnectionState state;
- switch (aState) {
- case nsIPresentationSessionListener::STATE_CONNECTING:
- state = PresentationConnectionState::Connecting;
- break;
- case nsIPresentationSessionListener::STATE_CONNECTED:
- state = PresentationConnectionState::Connected;
- break;
- case nsIPresentationSessionListener::STATE_CLOSED:
- state = PresentationConnectionState::Closed;
- break;
- case nsIPresentationSessionListener::STATE_TERMINATED:
- state = PresentationConnectionState::Terminated;
- break;
- default:
- NS_WARNING("Unknown presentation session state.");
- return NS_ERROR_INVALID_ARG;
- }
-
- if (mState == state) {
- return NS_OK;
- }
- mState = state;
-
- nsresult rv = ProcessStateChanged(aReason);
- if(NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- if (mOwningConnectionList) {
- mOwningConnectionList->NotifyStateChange(aSessionId, this);
- }
-
- return NS_OK;
-}
-
-nsresult
-PresentationConnection::ProcessStateChanged(nsresult aReason)
-{
- switch (mState) {
- case PresentationConnectionState::Connecting:
- return NS_OK;
- case PresentationConnectionState::Connected: {
- RefPtr<AsyncEventDispatcher> asyncDispatcher =
- new AsyncEventDispatcher(this, NS_LITERAL_STRING("connect"), false);
- return asyncDispatcher->PostDOMEvent();
- }
- case PresentationConnectionState::Closed: {
- PresentationConnectionClosedReason reason =
- PresentationConnectionClosedReason::Closed;
-
- nsString errorMsg;
- if (NS_FAILED(aReason)) {
- reason = PresentationConnectionClosedReason::Error;
- nsCString name, message;
-
- // If aReason is not a DOM error, use error name as message.
- if (NS_FAILED(NS_GetNameAndMessageForDOMNSResult(aReason,
- name,
- message))) {
- mozilla::GetErrorName(aReason, message);
- message.InsertLiteral("Internal error: ", 0);
- }
- CopyUTF8toUTF16(message, errorMsg);
- }
-
- Unused <<
- NS_WARN_IF(NS_FAILED(DispatchConnectionCloseEvent(reason, errorMsg)));
-
- return RemoveFromLoadGroup();
- }
- case PresentationConnectionState::Terminated: {
- // Ensure onterminate event is fired.
- RefPtr<AsyncEventDispatcher> asyncDispatcher =
- new AsyncEventDispatcher(this, NS_LITERAL_STRING("terminate"), false);
- Unused << NS_WARN_IF(NS_FAILED(asyncDispatcher->PostDOMEvent()));
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- nsresult rv = service->UnregisterSessionListener(mId, mRole);
- if(NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return RemoveFromLoadGroup();
- }
- default:
- MOZ_CRASH("Unknown presentation session state.");
- return NS_ERROR_INVALID_ARG;
- }
-}
-
-NS_IMETHODIMP
-PresentationConnection::NotifyMessage(const nsAString& aSessionId,
- const nsACString& aData,
- bool aIsBinary)
-{
- PRES_DEBUG("connection %s:id[%s], data[%s], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(aSessionId).get(),
- nsPromiseFlatCString(aData).get(), mRole);
-
- if (!aSessionId.Equals(mId)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- // No message should be expected when the session is not connected.
- if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
- return NS_ERROR_DOM_INVALID_STATE_ERR;
- }
-
- if (NS_WARN_IF(NS_FAILED(DoReceiveMessage(aData, aIsBinary)))) {
- AsyncCloseConnectionWithErrorMsg(
- NS_LITERAL_STRING("Unable to receive a message."));
- return NS_ERROR_FAILURE;
- }
-
- return NS_OK;
-}
-
-nsresult
-PresentationConnection::DoReceiveMessage(const nsACString& aData, bool aIsBinary)
-{
- // Transform the data.
- AutoJSAPI jsapi;
- if (!jsapi.Init(GetOwner())) {
- return NS_ERROR_FAILURE;
- }
- JSContext* cx = jsapi.cx();
- JS::Rooted<JS::Value> jsData(cx);
-
- nsresult rv;
- if (aIsBinary) {
- if (mBinaryType == PresentationConnectionBinaryType::Blob) {
- RefPtr<Blob> blob =
- Blob::CreateStringBlob(GetOwner(), aData, EmptyString());
- MOZ_ASSERT(blob);
-
- if (!ToJSValue(cx, blob, &jsData)) {
- return NS_ERROR_FAILURE;
- }
- } else if (mBinaryType == PresentationConnectionBinaryType::Arraybuffer) {
- JS::Rooted<JSObject*> arrayBuf(cx);
- rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- jsData.setObject(*arrayBuf);
- } else {
- NS_RUNTIMEABORT("Unknown binary type!");
- return NS_ERROR_UNEXPECTED;
- }
- } else {
- NS_ConvertUTF8toUTF16 utf16Data(aData);
- if(NS_WARN_IF(!ToJSValue(cx, utf16Data, &jsData))) {
- return NS_ERROR_FAILURE;
- }
- }
-
- return DispatchMessageEvent(jsData);
-}
-
-nsresult
-PresentationConnection::DispatchConnectionCloseEvent(
- PresentationConnectionClosedReason aReason,
- const nsAString& aMessage,
- bool aDispatchNow)
-{
- if (mState != PresentationConnectionState::Closed) {
- MOZ_ASSERT(false, "The connection state should be closed.");
- return NS_ERROR_FAILURE;
- }
-
- PresentationConnectionCloseEventInit init;
- init.mReason = aReason;
- init.mMessage = aMessage;
-
- RefPtr<PresentationConnectionCloseEvent> closedEvent =
- PresentationConnectionCloseEvent::Constructor(this,
- NS_LITERAL_STRING("close"),
- init);
- closedEvent->SetTrusted(true);
-
- if (aDispatchNow) {
- bool ignore;
- return DOMEventTargetHelper::DispatchEvent(closedEvent, &ignore);
- }
-
- RefPtr<AsyncEventDispatcher> asyncDispatcher =
- new AsyncEventDispatcher(this, static_cast<Event*>(closedEvent));
- return asyncDispatcher->PostDOMEvent();
-}
-
-nsresult
-PresentationConnection::DispatchMessageEvent(JS::Handle<JS::Value> aData)
-{
- nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
- if (NS_WARN_IF(!global)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- // Get the origin.
- nsAutoString origin;
- nsresult rv = nsContentUtils::GetUTFOrigin(global->PrincipalOrNull(), origin);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- RefPtr<MessageEvent> messageEvent = new MessageEvent(this, nullptr, nullptr);
-
- messageEvent->InitMessageEvent(nullptr,
- NS_LITERAL_STRING("message"),
- false, false, aData, origin,
- EmptyString(), nullptr,
- Sequence<OwningNonNull<MessagePort>>());
- messageEvent->SetTrusted(true);
-
- RefPtr<AsyncEventDispatcher> asyncDispatcher =
- new AsyncEventDispatcher(this, static_cast<Event*>(messageEvent));
- return asyncDispatcher->PostDOMEvent();
-}
-
-nsresult
-PresentationConnection::ProcessConnectionWentAway()
-{
- if (mState != PresentationConnectionState::Connected &&
- mState != PresentationConnectionState::Connecting) {
- // If the state is not connected or connecting, do not need to
- // close the session.
- return NS_OK;
- }
-
- mState = PresentationConnectionState::Terminated;
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return service->CloseSession(
- mId, mRole, nsIPresentationService::CLOSED_REASON_WENTAWAY);
-}
-
-NS_IMETHODIMP
-PresentationConnection::GetName(nsACString &aResult)
-{
- aResult.AssignLiteral("about:presentation-connection");
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationConnection::IsPending(bool* aRetval)
-{
- *aRetval = true;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationConnection::GetStatus(nsresult* aStatus)
-{
- *aStatus = NS_OK;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationConnection::Cancel(nsresult aStatus)
-{
- nsCOMPtr<nsIRunnable> event =
- NewRunnableMethod(this, &PresentationConnection::ProcessConnectionWentAway);
- return NS_DispatchToCurrentThread(event);
-}
-NS_IMETHODIMP
-PresentationConnection::Suspend(void)
-{
- return NS_ERROR_NOT_IMPLEMENTED;
-}
-NS_IMETHODIMP
-PresentationConnection::Resume(void)
-{
- return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-PresentationConnection::GetLoadGroup(nsILoadGroup** aLoadGroup)
-{
- *aLoadGroup = nullptr;
-
- nsCOMPtr<nsIDocument> doc = GetOwner() ? GetOwner()->GetExtantDoc() : nullptr;
- if (!doc) {
- return NS_ERROR_FAILURE;
- }
-
- *aLoadGroup = doc->GetDocumentLoadGroup().take();
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationConnection::SetLoadGroup(nsILoadGroup * aLoadGroup)
-{
- return NS_ERROR_UNEXPECTED;
-}
-
-NS_IMETHODIMP
-PresentationConnection::GetLoadFlags(nsLoadFlags* aLoadFlags)
-{
- *aLoadFlags = nsIRequest::LOAD_BACKGROUND;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationConnection::SetLoadFlags(nsLoadFlags aLoadFlags)
-{
- return NS_OK;
-}
-
-nsresult
-PresentationConnection::AddIntoLoadGroup()
-{
- // Avoid adding to loadgroup multiple times
- if (mWeakLoadGroup) {
- return NS_OK;
- }
-
- nsCOMPtr<nsILoadGroup> loadGroup;
- nsresult rv = GetLoadGroup(getter_AddRefs(loadGroup));
- if(NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = loadGroup->AddRequest(this, nullptr);
- if(NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mWeakLoadGroup = do_GetWeakReference(loadGroup);
- return NS_OK;
-}
-
-nsresult
-PresentationConnection::RemoveFromLoadGroup()
-{
- if (!mWeakLoadGroup) {
- return NS_OK;
- }
-
- nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakLoadGroup);
- if (loadGroup) {
- mWeakLoadGroup = nullptr;
- return loadGroup->RemoveRequest(this, nullptr, NS_OK);
- }
-
- return NS_OK;
-}
-
-void
-PresentationConnection::AsyncCloseConnectionWithErrorMsg(const nsAString& aMessage)
-{
- if (mState == PresentationConnectionState::Terminated) {
- return;
- }
-
- nsString message = nsString(aMessage);
- RefPtr<PresentationConnection> self = this;
- nsCOMPtr<nsIRunnable> r =
- NS_NewRunnableFunction([self, message]() -> void {
- // Set |mState| to |PresentationConnectionState::Closed| here to avoid
- // calling |ProcessStateChanged|.
- self->mState = PresentationConnectionState::Closed;
-
- // Make sure dispatching the event and closing the connection are invoked
- // at the same time by setting |aDispatchNow| to true.
- Unused << NS_WARN_IF(NS_FAILED(
- self->DispatchConnectionCloseEvent(PresentationConnectionClosedReason::Error,
- message,
- true)));
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if(NS_WARN_IF(!service)) {
- return;
- }
-
- Unused << NS_WARN_IF(NS_FAILED(
- service->CloseSession(self->mId,
- self->mRole,
- nsIPresentationService::CLOSED_REASON_ERROR)));
- });
-
- Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(r)));
-}
diff --git a/dom/presentation/PresentationConnection.h b/dom/presentation/PresentationConnection.h
deleted file mode 100644
index cecf6c346..000000000
--- a/dom/presentation/PresentationConnection.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* -*- 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_PresentationConnection_h
-#define mozilla_dom_PresentationConnection_h
-
-#include "mozilla/DOMEventTargetHelper.h"
-#include "mozilla/dom/TypedArray.h"
-#include "mozilla/WeakPtr.h"
-#include "mozilla/dom/PresentationConnectionBinding.h"
-#include "mozilla/dom/PresentationConnectionCloseEventBinding.h"
-#include "nsIPresentationListener.h"
-#include "nsIRequest.h"
-#include "nsWeakReference.h"
-
-namespace mozilla {
-namespace dom {
-
-class Blob;
-class PresentationConnectionList;
-
-class PresentationConnection final : public DOMEventTargetHelper
- , public nsIPresentationSessionListener
- , public nsIRequest
- , public SupportsWeakPtr<PresentationConnection>
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PresentationConnection,
- DOMEventTargetHelper)
- NS_DECL_NSIPRESENTATIONSESSIONLISTENER
- NS_DECL_NSIREQUEST
- MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PresentationConnection)
-
- static already_AddRefed<PresentationConnection>
- Create(nsPIDOMWindowInner* aWindow,
- const nsAString& aId,
- const nsAString& aUrl,
- const uint8_t aRole,
- PresentationConnectionList* aList = nullptr);
-
- virtual void DisconnectFromOwner() override;
-
- virtual JSObject* WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto) override;
-
- // WebIDL (public APIs)
- void GetId(nsAString& aId) const;
-
- void GetUrl(nsAString& aUrl) const;
-
- PresentationConnectionState State() const;
-
- PresentationConnectionBinaryType BinaryType() const;
-
- void SetBinaryType(PresentationConnectionBinaryType aType);
-
- void Send(const nsAString& aData,
- ErrorResult& aRv);
-
- void Send(Blob& aData,
- ErrorResult& aRv);
-
- void Send(const ArrayBuffer& aData,
- ErrorResult& aRv);
-
- void Send(const ArrayBufferView& aData,
- ErrorResult& aRv);
-
- void Close(ErrorResult& aRv);
-
- void Terminate(ErrorResult& aRv);
-
- bool
- Equals(uint64_t aWindowId, const nsAString& aId);
-
- IMPL_EVENT_HANDLER(connect);
- IMPL_EVENT_HANDLER(close);
- IMPL_EVENT_HANDLER(terminate);
- IMPL_EVENT_HANDLER(message);
-
-private:
- PresentationConnection(nsPIDOMWindowInner* aWindow,
- const nsAString& aId,
- const nsAString& aUrl,
- const uint8_t aRole,
- PresentationConnectionList* aList);
-
- ~PresentationConnection();
-
- bool Init();
-
- void Shutdown();
-
- nsresult ProcessStateChanged(nsresult aReason);
-
- nsresult DispatchConnectionCloseEvent(PresentationConnectionClosedReason aReason,
- const nsAString& aMessage,
- bool aDispatchNow = false);
-
- nsresult DispatchMessageEvent(JS::Handle<JS::Value> aData);
-
- nsresult ProcessConnectionWentAway();
-
- nsresult AddIntoLoadGroup();
-
- nsresult RemoveFromLoadGroup();
-
- void AsyncCloseConnectionWithErrorMsg(const nsAString& aMessage);
-
- nsresult DoReceiveMessage(const nsACString& aData, bool aIsBinary);
-
- nsString mId;
- nsString mUrl;
- uint8_t mRole;
- PresentationConnectionState mState;
- RefPtr<PresentationConnectionList> mOwningConnectionList;
- nsWeakPtr mWeakLoadGroup;
- PresentationConnectionBinaryType mBinaryType;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationConnection_h
diff --git a/dom/presentation/PresentationConnectionList.cpp b/dom/presentation/PresentationConnectionList.cpp
deleted file mode 100644
index 0e0e7696c..000000000
--- a/dom/presentation/PresentationConnectionList.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/* -*- 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/. */
-
-#include "PresentationConnectionList.h"
-
-#include "mozilla/AsyncEventDispatcher.h"
-#include "mozilla/dom/PresentationConnectionAvailableEvent.h"
-#include "mozilla/dom/PresentationConnectionListBinding.h"
-#include "mozilla/dom/Promise.h"
-#include "PresentationConnection.h"
-
-namespace mozilla {
-namespace dom {
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(PresentationConnectionList, DOMEventTargetHelper,
- mGetConnectionListPromise,
- mConnections)
-
-NS_IMPL_ADDREF_INHERITED(PresentationConnectionList, DOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(PresentationConnectionList, DOMEventTargetHelper)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PresentationConnectionList)
-NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-
-PresentationConnectionList::PresentationConnectionList(nsPIDOMWindowInner* aWindow,
- Promise* aPromise)
- : DOMEventTargetHelper(aWindow)
- , mGetConnectionListPromise(aPromise)
-{
- MOZ_ASSERT(aWindow);
- MOZ_ASSERT(aPromise);
-}
-
-/* virtual */ JSObject*
-PresentationConnectionList::WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto)
-{
- return PresentationConnectionListBinding::Wrap(aCx, this, aGivenProto);
-}
-
-void
-PresentationConnectionList::GetConnections(
- nsTArray<RefPtr<PresentationConnection>>& aConnections) const
-{
- aConnections = mConnections;
-}
-
-nsresult
-PresentationConnectionList::DispatchConnectionAvailableEvent(
- PresentationConnection* aConnection)
-{
- PresentationConnectionAvailableEventInit init;
- init.mConnection = aConnection;
-
- RefPtr<PresentationConnectionAvailableEvent> event =
- PresentationConnectionAvailableEvent::Constructor(
- this,
- NS_LITERAL_STRING("connectionavailable"),
- init);
-
- if (NS_WARN_IF(!event)) {
- return NS_ERROR_FAILURE;
- }
- event->SetTrusted(true);
-
- RefPtr<AsyncEventDispatcher> asyncDispatcher =
- new AsyncEventDispatcher(this, event);
- return asyncDispatcher->PostDOMEvent();
-}
-
-PresentationConnectionList::ConnectionArrayIndex
-PresentationConnectionList::FindConnectionById(
- const nsAString& aId)
-{
- for (ConnectionArrayIndex i = 0; i < mConnections.Length(); i++) {
- nsAutoString id;
- mConnections[i]->GetId(id);
- if (id == nsAutoString(aId)) {
- return i;
- }
- }
-
- return mConnections.NoIndex;
-}
-
-void
-PresentationConnectionList::NotifyStateChange(const nsAString& aSessionId,
- PresentationConnection* aConnection)
-{
- if (!aConnection) {
- MOZ_ASSERT(false, "PresentationConnection can not be null.");
- return;
- }
-
- bool connectionFound =
- FindConnectionById(aSessionId) != mConnections.NoIndex ? true : false;
-
- PresentationConnectionListBinding::ClearCachedConnectionsValue(this);
- switch (aConnection->State()) {
- case PresentationConnectionState::Connected:
- if (!connectionFound) {
- mConnections.AppendElement(aConnection);
- if (mGetConnectionListPromise) {
- mGetConnectionListPromise->MaybeResolve(this);
- mGetConnectionListPromise = nullptr;
- return;
- }
- }
- DispatchConnectionAvailableEvent(aConnection);
- break;
- case PresentationConnectionState::Terminated:
- if (connectionFound) {
- mConnections.RemoveElement(aConnection);
- }
- break;
- default:
- break;
- }
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/PresentationConnectionList.h b/dom/presentation/PresentationConnectionList.h
deleted file mode 100644
index b430219ce..000000000
--- a/dom/presentation/PresentationConnectionList.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- 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_PresentationConnectionList_h
-#define mozilla_dom_PresentationConnectionList_h
-
-#include "mozilla/DOMEventTargetHelper.h"
-#include "nsTArray.h"
-
-namespace mozilla {
-namespace dom {
-
-class PresentationConnection;
-class Promise;
-
-class PresentationConnectionList final : public DOMEventTargetHelper
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PresentationConnectionList,
- DOMEventTargetHelper)
-
- PresentationConnectionList(nsPIDOMWindowInner* aWindow,
- Promise* aPromise);
-
- virtual JSObject* WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto) override;
-
- void GetConnections(nsTArray<RefPtr<PresentationConnection>>& aConnections) const;
-
- void NotifyStateChange(const nsAString& aSessionId, PresentationConnection* aConnection);
-
- IMPL_EVENT_HANDLER(connectionavailable);
-
-private:
- virtual ~PresentationConnectionList() = default;
-
- nsresult DispatchConnectionAvailableEvent(PresentationConnection* aConnection);
-
- typedef nsTArray<RefPtr<PresentationConnection>> ConnectionArray;
- typedef ConnectionArray::index_type ConnectionArrayIndex;
-
- ConnectionArrayIndex FindConnectionById(const nsAString& aId);
-
- RefPtr<Promise> mGetConnectionListPromise;
-
- // This array stores only non-terminsted connections.
- ConnectionArray mConnections;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationConnectionList_h
diff --git a/dom/presentation/PresentationDataChannelSessionTransport.js b/dom/presentation/PresentationDataChannelSessionTransport.js
deleted file mode 100644
index 9af6213cb..000000000
--- a/dom/presentation/PresentationDataChannelSessionTransport.js
+++ /dev/null
@@ -1,378 +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/. */
-
-"use strict";
-
-const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-// Bug 1228209 - plan to remove this eventually
-function log(aMsg) {
- //dump("-*- PresentationDataChannelSessionTransport.js : " + aMsg + "\n");
-}
-
-const PRESENTATIONTRANSPORT_CID = Components.ID("{dd2bbf2f-3399-4389-8f5f-d382afb8b2d6}");
-const PRESENTATIONTRANSPORT_CONTRACTID = "mozilla.org/presentation/datachanneltransport;1";
-
-const PRESENTATIONTRANSPORTBUILDER_CID = Components.ID("{215b2f62-46e2-4004-a3d1-6858e56c20f3}");
-const PRESENTATIONTRANSPORTBUILDER_CONTRACTID = "mozilla.org/presentation/datachanneltransportbuilder;1";
-
-function PresentationDataChannelDescription(aDataChannelSDP) {
- this._dataChannelSDP = JSON.stringify(aDataChannelSDP);
-}
-
-PresentationDataChannelDescription.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
- get type() {
- return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL;
- },
- get tcpAddress() {
- return null;
- },
- get tcpPort() {
- return null;
- },
- get dataChannelSDP() {
- return this._dataChannelSDP;
- }
-};
-
-function PresentationTransportBuilder() {
- log("PresentationTransportBuilder construct");
- this._isControlChannelNeeded = true;
-}
-
-PresentationTransportBuilder.prototype = {
- classID: PRESENTATIONTRANSPORTBUILDER_CID,
- contractID: PRESENTATIONTRANSPORTBUILDER_CONTRACTID,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportBuilder,
- Ci.nsIPresentationDataChannelSessionTransportBuilder,
- Ci.nsITimerCallback]),
-
- buildDataChannelTransport: function(aRole, aWindow, aListener) {
- if (!aRole || !aWindow || !aListener) {
- log("buildDataChannelTransport with illegal parameters");
- throw Cr.NS_ERROR_ILLEGAL_VALUE;
- }
-
- if (this._window) {
- log("buildDataChannelTransport has started.");
- throw Cr.NS_ERROR_UNEXPECTED;
- }
-
- log("buildDataChannelTransport with role " + aRole);
- this._role = aRole;
- this._window = aWindow;
- this._listener = aListener.QueryInterface(Ci.nsIPresentationSessionTransportBuilderListener);
-
- // TODO bug 1227053 set iceServers from |nsIPresentationDevice|
- this._peerConnection = new this._window.RTCPeerConnection();
-
- // |this._listener == null| will throw since the control channel is
- // abnormally closed.
- this._peerConnection.onicecandidate = aEvent => aEvent.candidate &&
- this._listener.sendIceCandidate(JSON.stringify(aEvent.candidate));
-
- this._peerConnection.onnegotiationneeded = () => {
- log("onnegotiationneeded with role " + this._role);
- if (!this._peerConnection) {
- log("ignoring negotiationneeded without PeerConnection");
- return;
- }
- this._peerConnection.createOffer()
- .then(aOffer => this._peerConnection.setLocalDescription(aOffer))
- .then(() => this._listener
- .sendOffer(new PresentationDataChannelDescription(this._peerConnection.localDescription)))
- .catch(e => this._reportError(e));
- }
-
- switch (this._role) {
- case Ci.nsIPresentationService.ROLE_CONTROLLER:
- this._dataChannel = this._peerConnection.createDataChannel("presentationAPI");
- this._setDataChannel();
- break;
-
- case Ci.nsIPresentationService.ROLE_RECEIVER:
- this._peerConnection.ondatachannel = aEvent => {
- this._dataChannel = aEvent.channel;
- // Ensure the binaryType of dataChannel is blob.
- this._dataChannel.binaryType = "blob";
- this._setDataChannel();
- }
- break;
- default:
- throw Cr.NS_ERROR_ILLEGAL_VALUE;
- }
-
- // TODO bug 1228235 we should have a way to let device providers customize
- // the time-out duration.
- let timeout = Services.prefs.getIntPref("presentation.receiver.loading.timeout", 10000);
-
- // The timer is to check if the negotiation finishes on time.
- this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- this._timer.initWithCallback(this, timeout, this._timer.TYPE_ONE_SHOT);
- },
-
- notify: function() {
- if (!this._sessionTransport) {
- this._cleanup(Cr.NS_ERROR_NET_TIMEOUT);
- }
- },
-
- _reportError: function(aError) {
- log("report Error " + aError.name + ":" + aError.message);
- this._cleanup(Cr.NS_ERROR_FAILURE);
- },
-
- _setDataChannel: function() {
- this._dataChannel.onopen = () => {
- log("data channel is open, notify the listener, role " + this._role);
-
- // Handoff the ownership of _peerConnection and _dataChannel to
- // _sessionTransport
- this._sessionTransport = new PresentationTransport();
- this._sessionTransport.init(this._peerConnection, this._dataChannel, this._window);
- this._peerConnection.onicecandidate = null;
- this._peerConnection.onnegotiationneeded = null;
- this._peerConnection = this._dataChannel = null;
-
- this._listener.onSessionTransport(this._sessionTransport);
- this._sessionTransport.callback.notifyTransportReady();
-
- this._cleanup(Cr.NS_OK);
- };
-
- this._dataChannel.onerror = aError => {
- log("data channel onerror " + aError.name + ":" + aError.message);
- this._cleanup(Cr.NS_ERROR_FAILURE);
- }
- },
-
- _cleanup: function(aReason) {
- if (aReason != Cr.NS_OK) {
- this._listener.onError(aReason);
- }
-
- if (this._dataChannel) {
- this._dataChannel.close();
- this._dataChannel = null;
- }
-
- if (this._peerConnection) {
- this._peerConnection.close();
- this._peerConnection = null;
- }
-
- this._role = null;
- this._window = null;
-
- this._listener = null;
- this._sessionTransport = null;
-
- if (this._timer) {
- this._timer.cancel();
- this._timer = null;
- }
- },
-
- // nsIPresentationControlChannelListener
- onOffer: function(aOffer) {
- if (this._role !== Ci.nsIPresentationService.ROLE_RECEIVER ||
- this._sessionTransport) {
- log("onOffer status error");
- this._cleanup(Cr.NS_ERROR_FAILURE);
- }
-
- log("onOffer: " + aOffer.dataChannelSDP + " with role " + this._role);
-
- let offer = new this._window
- .RTCSessionDescription(JSON.parse(aOffer.dataChannelSDP));
-
- this._peerConnection.setRemoteDescription(offer)
- .then(() => this._peerConnection.signalingState == "stable" ||
- this._peerConnection.createAnswer())
- .then(aAnswer => this._peerConnection.setLocalDescription(aAnswer))
- .then(() => {
- this._isControlChannelNeeded = false;
- this._listener
- .sendAnswer(new PresentationDataChannelDescription(this._peerConnection.localDescription))
- }).catch(e => this._reportError(e));
- },
-
- onAnswer: function(aAnswer) {
- if (this._role !== Ci.nsIPresentationService.ROLE_CONTROLLER ||
- this._sessionTransport) {
- log("onAnswer status error");
- this._cleanup(Cr.NS_ERROR_FAILURE);
- }
-
- log("onAnswer: " + aAnswer.dataChannelSDP + " with role " + this._role);
-
- let answer = new this._window
- .RTCSessionDescription(JSON.parse(aAnswer.dataChannelSDP));
-
- this._peerConnection.setRemoteDescription(answer).catch(e => this._reportError(e));
- this._isControlChannelNeeded = false;
- },
-
- onIceCandidate: function(aCandidate) {
- log("onIceCandidate: " + aCandidate + " with role " + this._role);
- if (!this._window || !this._peerConnection) {
- log("ignoring ICE candidate after connection");
- return;
- }
- let candidate = new this._window.RTCIceCandidate(JSON.parse(aCandidate));
- this._peerConnection.addIceCandidate(candidate).catch(e => this._reportError(e));
- },
-
- notifyDisconnected: function(aReason) {
- log("notifyDisconnected reason: " + aReason);
-
- if (aReason != Cr.NS_OK) {
- this._cleanup(aReason);
- } else if (this._isControlChannelNeeded) {
- this._cleanup(Cr.NS_ERROR_FAILURE);
- }
- },
-};
-
-function PresentationTransport() {
- this._messageQueue = [];
- this._closeReason = Cr.NS_OK;
-}
-
-PresentationTransport.prototype = {
- classID: PRESENTATIONTRANSPORT_CID,
- contractID: PRESENTATIONTRANSPORT_CONTRACTID,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransport]),
-
- init: function(aPeerConnection, aDataChannel, aWindow) {
- log("initWithDataChannel");
- this._enableDataNotification = false;
- this._dataChannel = aDataChannel;
- this._peerConnection = aPeerConnection;
- this._window = aWindow;
-
- this._dataChannel.onopen = () => {
- log("data channel reopen. Should never touch here");
- };
-
- this._dataChannel.onclose = () => {
- log("data channel onclose");
- if (this._callback) {
- this._callback.notifyTransportClosed(this._closeReason);
- }
- this._cleanup();
- }
-
- this._dataChannel.onmessage = aEvent => {
- log("data channel onmessage " + aEvent.data);
-
- if (!this._enableDataNotification || !this._callback) {
- log("queue message");
- this._messageQueue.push(aEvent.data);
- return;
- }
- this._doNotifyData(aEvent.data);
- };
-
- this._dataChannel.onerror = aError => {
- log("data channel onerror " + aError.name + ":" + aError.message);
- if (this._callback) {
- this._callback.notifyTransportClosed(Cr.NS_ERROR_FAILURE);
- }
- this._cleanup();
- }
- },
-
- // nsIPresentationTransport
- get selfAddress() {
- throw NS_ERROR_NOT_AVAILABLE;
- },
-
- get callback() {
- return this._callback;
- },
-
- set callback(aCallback) {
- this._callback = aCallback;
- },
-
- send: function(aData) {
- log("send " + aData);
- this._dataChannel.send(aData);
- },
-
- sendBinaryMsg: function(aData) {
- log("sendBinaryMsg");
-
- let array = new Uint8Array(aData.length);
- for (let i = 0; i < aData.length; i++) {
- array[i] = aData.charCodeAt(i);
- }
-
- this._dataChannel.send(array);
- },
-
- sendBlob: function(aBlob) {
- log("sendBlob");
-
- this._dataChannel.send(aBlob);
- },
-
- enableDataNotification: function() {
- log("enableDataNotification");
- if (this._enableDataNotification) {
- return;
- }
-
- if (!this._callback) {
- throw NS_ERROR_NOT_AVAILABLE;
- }
-
- this._enableDataNotification = true;
-
- this._messageQueue.forEach(aData => this._doNotifyData(aData));
- this._messageQueue = [];
- },
-
- close: function(aReason) {
- this._closeReason = aReason;
-
- this._dataChannel.close();
- },
-
- _cleanup: function() {
- this._dataChannel = null;
-
- if (this._peerConnection) {
- this._peerConnection.close();
- this._peerConnection = null;
- }
- this._callback = null;
- this._messageQueue = [];
- this._window = null;
- },
-
- _doNotifyData: function(aData) {
- if (!this._callback) {
- throw NS_ERROR_NOT_AVAILABLE;
- }
-
- if (aData instanceof this._window.Blob) {
- let reader = new this._window.FileReader();
- reader.addEventListener("load", (aEvent) => {
- this._callback.notifyData(aEvent.target.result, true);
- });
- reader.readAsBinaryString(aData);
- } else {
- this._callback.notifyData(aData, false);
- }
- },
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationTransportBuilder,
- PresentationTransport]);
diff --git a/dom/presentation/PresentationDataChannelSessionTransport.manifest b/dom/presentation/PresentationDataChannelSessionTransport.manifest
deleted file mode 100644
index 6838f675f..000000000
--- a/dom/presentation/PresentationDataChannelSessionTransport.manifest
+++ /dev/null
@@ -1,6 +0,0 @@
-# PresentationDataChannelSessionTransport.js
-component {dd2bbf2f-3399-4389-8f5f-d382afb8b2d6} PresentationDataChannelSessionTransport.js
-contract @mozilla.org/presentation/datachanneltransport;1 {dd2bbf2f-3399-4389-8f5f-d382afb8b2d6}
-
-component {215b2f62-46e2-4004-a3d1-6858e56c20f3} PresentationDataChannelSessionTransport.js
-contract @mozilla.org/presentation/datachanneltransportbuilder;1 {215b2f62-46e2-4004-a3d1-6858e56c20f3}
diff --git a/dom/presentation/PresentationDeviceInfoManager.js b/dom/presentation/PresentationDeviceInfoManager.js
deleted file mode 100644
index 29e7d370c..000000000
--- a/dom/presentation/PresentationDeviceInfoManager.js
+++ /dev/null
@@ -1,119 +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/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
-
-function log(aMsg) {
- //dump("-*- PresentationDeviceInfoManager.js : " + aMsg + "\n");
-}
-
-const PRESENTATIONDEVICEINFOMANAGER_CID = Components.ID("{1bd66bef-f643-4be3-b690-0c656353eafd}");
-const PRESENTATIONDEVICEINFOMANAGER_CONTRACTID = "@mozilla.org/presentation-device/deviceInfo;1";
-
-XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
- "@mozilla.org/childprocessmessagemanager;1",
- "nsIMessageSender");
-
-function PresentationDeviceInfoManager() {}
-
-PresentationDeviceInfoManager.prototype = {
- __proto__: DOMRequestIpcHelper.prototype,
-
- classID: PRESENTATIONDEVICEINFOMANAGER_CID,
- contractID: PRESENTATIONDEVICEINFOMANAGER_CONTRACTID,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
- Ci.nsIObserver,
- Ci.nsIDOMGlobalPropertyInitializer]),
-
- receiveMessage: function(aMsg) {
- if (!aMsg || !aMsg.data) {
- return;
- }
-
- let data = aMsg.data;
-
- log("receive aMsg: " + aMsg.name);
- switch (aMsg.name) {
- case "PresentationDeviceInfoManager:OnDeviceChange": {
- let detail = {
- detail: {
- type: data.type,
- deviceInfo: data.deviceInfo,
- }
- };
- let event = new this._window.CustomEvent("devicechange", Cu.cloneInto(detail, this._window));
- this.__DOM_IMPL__.dispatchEvent(event);
- break;
- }
- case "PresentationDeviceInfoManager:GetAll:Result:Ok": {
- let resolver = this.takePromiseResolver(data.requestId);
-
- if (!resolver) {
- return;
- }
-
- resolver.resolve(Cu.cloneInto(data.devices, this._window));
- break;
- }
- case "PresentationDeviceInfoManager:GetAll:Result:Error": {
- let resolver = this.takePromiseResolver(data.requestId);
-
- if (!resolver) {
- return;
- }
-
- resolver.reject(data.error);
- break;
- }
- }
- },
-
- init: function(aWin) {
- log("init");
- this.initDOMRequestHelper(aWin, [
- {name: "PresentationDeviceInfoManager:OnDeviceChange", weakRef: true},
- {name: "PresentationDeviceInfoManager:GetAll:Result:Ok", weakRef: true},
- {name: "PresentationDeviceInfoManager:GetAll:Result:Error", weakRef: true},
- ]);
- },
-
- uninit: function() {
- log("uninit");
- let self = this;
-
- this.forEachPromiseResolver(function(aKey) {
- self.takePromiseResolver(aKey).reject("PresentationDeviceInfoManager got destroyed");
- });
- },
-
- get ondevicechange() {
- return this.__DOM_IMPL__.getEventHandler("ondevicechange");
- },
-
- set ondevicechange(aHandler) {
- this.__DOM_IMPL__.setEventHandler("ondevicechange", aHandler);
- },
-
- getAll: function() {
- log("getAll");
- let self = this;
- return this.createPromiseWithId(function(aResolverId) {
- cpmm.sendAsyncMessage("PresentationDeviceInfoManager:GetAll", {
- requestId: aResolverId,
- });
- });
- },
-
- forceDiscovery: function() {
- cpmm.sendAsyncMessage("PresentationDeviceInfoManager:ForceDiscovery");
- },
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationDeviceInfoManager]);
diff --git a/dom/presentation/PresentationDeviceInfoManager.jsm b/dom/presentation/PresentationDeviceInfoManager.jsm
deleted file mode 100644
index 205982b9c..000000000
--- a/dom/presentation/PresentationDeviceInfoManager.jsm
+++ /dev/null
@@ -1,104 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-this.EXPORTED_SYMBOLS = ["PresentationDeviceInfoService"];
-
-function log(aMsg) {
- //dump("PresentationDeviceInfoManager.jsm: " + aMsg + "\n");
-}
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "presentationDeviceManager",
- "@mozilla.org/presentation-device/manager;1",
- "nsIPresentationDeviceManager");
-
-XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
- "@mozilla.org/parentprocessmessagemanager;1",
- "nsIMessageBroadcaster");
-
-this.PresentationDeviceInfoService = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
- Ci.nsIObserver]),
-
- init: function() {
- log("init");
- ppmm.addMessageListener("PresentationDeviceInfoManager:GetAll", this);
- ppmm.addMessageListener("PresentationDeviceInfoManager:ForceDiscovery", this);
- Services.obs.addObserver(this, "presentation-device-change", false);
- },
-
- getAll: function(aData, aMm) {
- log("getAll");
- let deviceArray = presentationDeviceManager.getAvailableDevices().QueryInterface(Ci.nsIArray);
- if (!deviceArray) {
- aData.error = "DataError";
- aMm.sendAsyncMessage("PresentationDeviceInfoManager:GetAll:Result:Error", aData);
- return;
- }
-
- aData.devices = [];
- for (let i = 0; i < deviceArray.length; i++) {
- let device = deviceArray.queryElementAt(i, Ci.nsIPresentationDevice);
- aData.devices.push({
- id: device.id,
- name: device.name,
- type: device.type,
- });
- }
- aMm.sendAsyncMessage("PresentationDeviceInfoManager:GetAll:Result:Ok", aData);
- },
-
- forceDiscovery: function() {
- log("forceDiscovery");
- presentationDeviceManager.forceDiscovery();
- },
-
- observe: function(aSubject, aTopic, aData) {
- log("observe: " + aTopic);
-
- let device = aSubject.QueryInterface(Ci.nsIPresentationDevice);
- let data = {
- type: aData,
- deviceInfo: {
- id: device.id,
- name: device.name,
- type: device.type,
- },
- };
- ppmm.broadcastAsyncMessage("PresentationDeviceInfoManager:OnDeviceChange", data);
- },
-
- receiveMessage: function(aMessage) {
- if (!aMessage.target.assertPermission("presentation-device-manage")) {
- debug("receive message " + aMessage.name +
- " from a content process with no 'presentation-device-manage' privileges.");
- return null;
- }
-
- let msg = aMessage.data || {};
- let mm = aMessage.target;
-
- log("receiveMessage: " + aMessage.name);
- switch (aMessage.name) {
- case "PresentationDeviceInfoManager:GetAll": {
- this.getAll(msg, mm);
- break;
- }
- case "PresentationDeviceInfoManager:ForceDiscovery": {
- this.forceDiscovery();
- break;
- }
- }
- },
-};
-
-this.PresentationDeviceInfoService.init();
diff --git a/dom/presentation/PresentationDeviceInfoManager.manifest b/dom/presentation/PresentationDeviceInfoManager.manifest
deleted file mode 100644
index ae50b8e6a..000000000
--- a/dom/presentation/PresentationDeviceInfoManager.manifest
+++ /dev/null
@@ -1,3 +0,0 @@
-# PresentationDeviceInfoManager.js
-component {1bd66bef-f643-4be3-b690-0c656353eafd} PresentationDeviceInfoManager.js
-contract @mozilla.org/presentation-device/deviceInfo;1 {1bd66bef-f643-4be3-b690-0c656353eafd}
diff --git a/dom/presentation/PresentationDeviceManager.cpp b/dom/presentation/PresentationDeviceManager.cpp
deleted file mode 100644
index 7e5a4700c..000000000
--- a/dom/presentation/PresentationDeviceManager.cpp
+++ /dev/null
@@ -1,336 +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 "PresentationDeviceManager.h"
-
-#include "mozilla/Services.h"
-#include "MainThreadUtils.h"
-#include "nsArrayUtils.h"
-#include "nsCategoryCache.h"
-#include "nsCOMPtr.h"
-#include "nsIMutableArray.h"
-#include "nsIObserverService.h"
-#include "nsXULAppAPI.h"
-#include "PresentationSessionRequest.h"
-#include "PresentationTerminateRequest.h"
-
-namespace mozilla {
-namespace dom {
-
-NS_IMPL_ISUPPORTS(PresentationDeviceManager,
- nsIPresentationDeviceManager,
- nsIPresentationDeviceListener,
- nsIObserver,
- nsISupportsWeakReference)
-
-PresentationDeviceManager::PresentationDeviceManager()
-{
-}
-
-PresentationDeviceManager::~PresentationDeviceManager()
-{
- UnloadDeviceProviders();
- mDevices.Clear();
-}
-
-void
-PresentationDeviceManager::Init()
-{
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- if (obs) {
- obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
- }
-
- LoadDeviceProviders();
-}
-
-void
-PresentationDeviceManager::Shutdown()
-{
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- if (obs) {
- obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
- }
-
- UnloadDeviceProviders();
-}
-
-void
-PresentationDeviceManager::LoadDeviceProviders()
-{
- MOZ_ASSERT(mProviders.IsEmpty());
-
- nsCategoryCache<nsIPresentationDeviceProvider> providerCache(PRESENTATION_DEVICE_PROVIDER_CATEGORY);
- providerCache.GetEntries(mProviders);
-
- for (uint32_t i = 0; i < mProviders.Length(); ++i) {
- mProviders[i]->SetListener(this);
- }
-}
-
-void
-PresentationDeviceManager::UnloadDeviceProviders()
-{
- for (uint32_t i = 0; i < mProviders.Length(); ++i) {
- mProviders[i]->SetListener(nullptr);
- }
-
- mProviders.Clear();
-}
-
-void
-PresentationDeviceManager::NotifyDeviceChange(nsIPresentationDevice* aDevice,
- const char16_t* aType)
-{
- nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
- if (obs) {
- obs->NotifyObservers(aDevice,
- PRESENTATION_DEVICE_CHANGE_TOPIC,
- aType);
- }
-}
-
-// nsIPresentationDeviceManager
-NS_IMETHODIMP
-PresentationDeviceManager::ForceDiscovery()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- for (uint32_t i = 0; i < mProviders.Length(); ++i) {
- mProviders[i]->ForceDiscovery();
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceManager::AddDeviceProvider(nsIPresentationDeviceProvider* aProvider)
-{
- NS_ENSURE_ARG(aProvider);
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(mProviders.Contains(aProvider))) {
- return NS_OK;
- }
-
- mProviders.AppendElement(aProvider);
- aProvider->SetListener(this);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceManager::RemoveDeviceProvider(nsIPresentationDeviceProvider* aProvider)
-{
- NS_ENSURE_ARG(aProvider);
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!mProviders.RemoveElement(aProvider))) {
- return NS_ERROR_FAILURE;
- }
-
- aProvider->SetListener(nullptr);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceManager::GetDeviceAvailable(bool* aRetVal)
-{
- NS_ENSURE_ARG_POINTER(aRetVal);
- MOZ_ASSERT(NS_IsMainThread());
-
- *aRetVal = !mDevices.IsEmpty();
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceManager::GetAvailableDevices(nsIArray* aPresentationUrls, nsIArray** aRetVal)
-{
- NS_ENSURE_ARG_POINTER(aRetVal);
- MOZ_ASSERT(NS_IsMainThread());
-
- // Bug 1194049: some providers may discontinue discovery after timeout.
- // Call |ForceDiscovery()| here to make sure device lists are updated.
- NS_DispatchToMainThread(
- NewRunnableMethod(this, &PresentationDeviceManager::ForceDiscovery));
-
- nsTArray<nsString> presentationUrls;
- if (aPresentationUrls) {
- uint32_t length;
- nsresult rv = aPresentationUrls->GetLength(&length);
- if (NS_SUCCEEDED(rv)) {
- for (uint32_t i = 0; i < length; ++i) {
- nsCOMPtr<nsISupportsString> isupportStr =
- do_QueryElementAt(aPresentationUrls, i);
-
- nsAutoString presentationUrl;
- rv = isupportStr->GetData(presentationUrl);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- continue;
- }
-
- presentationUrls.AppendElement(presentationUrl);
- }
- }
- }
-
- nsCOMPtr<nsIMutableArray> devices = do_CreateInstance(NS_ARRAY_CONTRACTID);
- for (uint32_t i = 0; i < mDevices.Length(); ++i) {
- if (presentationUrls.IsEmpty()) {
- devices->AppendElement(mDevices[i], false);
- continue;
- }
-
- for (uint32_t j = 0; j < presentationUrls.Length(); ++j) {
- bool isSupported;
- if (NS_SUCCEEDED(mDevices[i]->IsRequestedUrlSupported(presentationUrls[j],
- &isSupported)) &&
- isSupported) {
- devices->AppendElement(mDevices[i], false);
- break;
- }
- }
- }
-
- devices.forget(aRetVal);
-
- return NS_OK;
-}
-
-// nsIPresentationDeviceListener
-NS_IMETHODIMP
-PresentationDeviceManager::AddDevice(nsIPresentationDevice* aDevice)
-{
- NS_ENSURE_ARG(aDevice);
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(mDevices.Contains(aDevice))) {
- return NS_ERROR_FAILURE;
- }
-
- mDevices.AppendElement(aDevice);
-
- NotifyDeviceChange(aDevice, u"add");
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceManager::RemoveDevice(nsIPresentationDevice* aDevice)
-{
- NS_ENSURE_ARG(aDevice);
- MOZ_ASSERT(NS_IsMainThread());
-
- int32_t index = mDevices.IndexOf(aDevice);
- if (NS_WARN_IF(index < 0)) {
- return NS_ERROR_FAILURE;
- }
-
- mDevices.RemoveElementAt(index);
-
- NotifyDeviceChange(aDevice, u"remove");
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceManager::UpdateDevice(nsIPresentationDevice* aDevice)
-{
- NS_ENSURE_ARG(aDevice);
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!mDevices.Contains(aDevice))) {
- return NS_ERROR_FAILURE;
- }
-
- NotifyDeviceChange(aDevice, u"update");
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceManager::OnSessionRequest(nsIPresentationDevice* aDevice,
- const nsAString& aUrl,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel)
-{
- NS_ENSURE_ARG(aDevice);
- NS_ENSURE_ARG(aControlChannel);
-
- nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
- NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
-
- RefPtr<PresentationSessionRequest> request =
- new PresentationSessionRequest(aDevice, aUrl, aPresentationId, aControlChannel);
- obs->NotifyObservers(request,
- PRESENTATION_SESSION_REQUEST_TOPIC,
- nullptr);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceManager::OnTerminateRequest(nsIPresentationDevice* aDevice,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel,
- bool aIsFromReceiver)
-{
- NS_ENSURE_ARG(aDevice);
- NS_ENSURE_ARG(aControlChannel);
-
- nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
- NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
-
- RefPtr<PresentationTerminateRequest> request =
- new PresentationTerminateRequest(aDevice, aPresentationId,
- aControlChannel, aIsFromReceiver);
- obs->NotifyObservers(request,
- PRESENTATION_TERMINATE_REQUEST_TOPIC,
- nullptr);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceManager::OnReconnectRequest(nsIPresentationDevice* aDevice,
- const nsAString& aUrl,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel)
-{
- NS_ENSURE_ARG(aDevice);
- NS_ENSURE_ARG(aControlChannel);
-
- nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
- NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
-
- RefPtr<PresentationSessionRequest> request =
- new PresentationSessionRequest(aDevice, aUrl, aPresentationId, aControlChannel);
- obs->NotifyObservers(request,
- PRESENTATION_RECONNECT_REQUEST_TOPIC,
- nullptr);
-
- return NS_OK;
-}
-
-// nsIObserver
-NS_IMETHODIMP
-PresentationDeviceManager::Observe(nsISupports *aSubject,
- const char *aTopic,
- const char16_t *aData)
-{
- if (!strcmp(aTopic, "profile-after-change")) {
- Init();
- } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
- Shutdown();
- }
-
- return NS_OK;
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/PresentationDeviceManager.h b/dom/presentation/PresentationDeviceManager.h
deleted file mode 100644
index f854ee883..000000000
--- a/dom/presentation/PresentationDeviceManager.h
+++ /dev/null
@@ -1,54 +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_PresentationDeviceManager_h__
-#define mozilla_dom_PresentationDeviceManager_h__
-
-#include "nsIObserver.h"
-#include "nsIPresentationDevice.h"
-#include "nsIPresentationDeviceManager.h"
-#include "nsIPresentationDeviceProvider.h"
-#include "nsCOMArray.h"
-#include "nsWeakReference.h"
-
-namespace mozilla {
-namespace dom {
-
-class PresentationDeviceManager final : public nsIPresentationDeviceManager
- , public nsIPresentationDeviceListener
- , public nsIObserver
- , public nsSupportsWeakReference
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONDEVICEMANAGER
- NS_DECL_NSIPRESENTATIONDEVICELISTENER
- NS_DECL_NSIOBSERVER
-
- PresentationDeviceManager();
-
-private:
- virtual ~PresentationDeviceManager();
-
- void Init();
-
- void Shutdown();
-
- void LoadDeviceProviders();
-
- void UnloadDeviceProviders();
-
- void NotifyDeviceChange(nsIPresentationDevice* aDevice,
- const char16_t* aType);
-
- nsCOMArray<nsIPresentationDeviceProvider> mProviders;
- nsCOMArray<nsIPresentationDevice> mDevices;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif /* mozilla_dom_PresentationDeviceManager_h__ */
diff --git a/dom/presentation/PresentationLog.h b/dom/presentation/PresentationLog.h
deleted file mode 100644
index 96af0c124..000000000
--- a/dom/presentation/PresentationLog.h
+++ /dev/null
@@ -1,26 +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_PresentationLog_h
-#define mozilla_dom_PresentationLog_h
-
-/*
- * MOZ_LOG=Presentation:5
- * For detail, see PresentationService.cpp
- */
-namespace mozilla {
-namespace dom {
-extern mozilla::LazyLogModule gPresentationLog;
-}
-}
-
-#undef PRES_ERROR
-#define PRES_ERROR(...) MOZ_LOG(mozilla::dom::gPresentationLog, mozilla::LogLevel::Error, (__VA_ARGS__))
-
-#undef PRES_DEBUG
-#define PRES_DEBUG(...) MOZ_LOG(mozilla::dom::gPresentationLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
-
-#endif // mozilla_dom_PresentationLog_h
diff --git a/dom/presentation/PresentationNetworkHelper.js b/dom/presentation/PresentationNetworkHelper.js
deleted file mode 100644
index 9b6458daf..000000000
--- a/dom/presentation/PresentationNetworkHelper.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/Messaging.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-const NETWORKHELPER_CID = Components.ID("{5fb96caa-6d49-4f6b-9a4b-65dd0d51f92d}");
-
-function PresentationNetworkHelper() {}
-
-PresentationNetworkHelper.prototype = {
- classID: NETWORKHELPER_CID,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationNetworkHelper]),
-
- getWifiIPAddress: function(aListener) {
- Messaging.sendRequestForResult({type: "Wifi:GetIPAddress"})
- .then(result => aListener.onGetWifiIPAddress(result),
- err => aListener.onError(err));
- }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationNetworkHelper]);
diff --git a/dom/presentation/PresentationNetworkHelper.manifest b/dom/presentation/PresentationNetworkHelper.manifest
deleted file mode 100644
index a061cef08..000000000
--- a/dom/presentation/PresentationNetworkHelper.manifest
+++ /dev/null
@@ -1,3 +0,0 @@
-# PresentationNetworkHelper.js
-component {5fb96caa-6d49-4f6b-9a4b-65dd0d51f92d} PresentationNetworkHelper.js
-contract @mozilla.org/presentation-device/networkHelper;1 {5fb96caa-6d49-4f6b-9a4b-65dd0d51f92d}
diff --git a/dom/presentation/PresentationReceiver.cpp b/dom/presentation/PresentationReceiver.cpp
deleted file mode 100644
index bc1776b45..000000000
--- a/dom/presentation/PresentationReceiver.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/* -*- 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/. */
-
-#include "PresentationReceiver.h"
-
-#include "mozilla/dom/PresentationReceiverBinding.h"
-#include "mozilla/dom/Promise.h"
-#include "nsContentUtils.h"
-#include "nsIPresentationService.h"
-#include "nsPIDOMWindow.h"
-#include "nsServiceManagerUtils.h"
-#include "nsThreadUtils.h"
-#include "PresentationConnection.h"
-#include "PresentationConnectionList.h"
-#include "PresentationLog.h"
-
-namespace mozilla {
-namespace dom {
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PresentationReceiver,
- mOwner,
- mGetConnectionListPromise,
- mConnectionList)
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(PresentationReceiver)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(PresentationReceiver)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PresentationReceiver)
- NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
- NS_INTERFACE_MAP_ENTRY(nsIPresentationRespondingListener)
- NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-/* static */ already_AddRefed<PresentationReceiver>
-PresentationReceiver::Create(nsPIDOMWindowInner* aWindow)
-{
- RefPtr<PresentationReceiver> receiver = new PresentationReceiver(aWindow);
- return NS_WARN_IF(!receiver->Init()) ? nullptr : receiver.forget();
-}
-
-PresentationReceiver::PresentationReceiver(nsPIDOMWindowInner* aWindow)
- : mOwner(aWindow)
-{
- MOZ_ASSERT(aWindow);
-}
-
-PresentationReceiver::~PresentationReceiver()
-{
- Shutdown();
-}
-
-bool
-PresentationReceiver::Init()
-{
- if (NS_WARN_IF(!mOwner)) {
- return false;
- }
- mWindowId = mOwner->WindowID();
-
- nsCOMPtr<nsIDocShell> docShell = mOwner->GetDocShell();
- MOZ_ASSERT(docShell);
-
- nsContentUtils::GetPresentationURL(docShell, mUrl);
- return !mUrl.IsEmpty();
-}
-
-void PresentationReceiver::Shutdown()
-{
- PRES_DEBUG("receiver shutdown:windowId[%d]\n", mWindowId);
-
- // Unregister listener for incoming sessions.
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return;
- }
-
- Unused <<
- NS_WARN_IF(NS_FAILED(service->UnregisterRespondingListener(mWindowId)));
-}
-
-/* virtual */ JSObject*
-PresentationReceiver::WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto)
-{
- return PresentationReceiverBinding::Wrap(aCx, this, aGivenProto);
-}
-
-NS_IMETHODIMP
-PresentationReceiver::NotifySessionConnect(uint64_t aWindowId,
- const nsAString& aSessionId)
-{
- PRES_DEBUG("receiver session connect:id[%s], windowId[%x]\n",
- NS_ConvertUTF16toUTF8(aSessionId).get(), aWindowId);
-
- if (NS_WARN_IF(!mOwner)) {
- return NS_ERROR_FAILURE;
- }
-
- if (NS_WARN_IF(aWindowId != mWindowId)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- if (NS_WARN_IF(!mConnectionList)) {
- return NS_ERROR_FAILURE;
- }
-
- RefPtr<PresentationConnection> connection =
- PresentationConnection::Create(mOwner, aSessionId, mUrl,
- nsIPresentationService::ROLE_RECEIVER,
- mConnectionList);
- if (NS_WARN_IF(!connection)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return NS_OK;
-}
-
-already_AddRefed<Promise>
-PresentationReceiver::GetConnectionList(ErrorResult& aRv)
-{
- nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mOwner);
- if (NS_WARN_IF(!global)) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return nullptr;
- }
-
- if (!mGetConnectionListPromise) {
- mGetConnectionListPromise = Promise::Create(global, aRv);
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
-
- RefPtr<PresentationReceiver> self = this;
- nsresult rv =
- NS_DispatchToMainThread(NS_NewRunnableFunction([self] () -> void {
- self->CreateConnectionList();
- }));
- if (NS_FAILED(rv)) {
- aRv.Throw(rv);
- return nullptr;
- }
- }
-
- RefPtr<Promise> promise = mGetConnectionListPromise;
- return promise.forget();
-}
-
-void
-PresentationReceiver::CreateConnectionList()
-{
- MOZ_ASSERT(mGetConnectionListPromise);
-
- if (mConnectionList) {
- return;
- }
-
- mConnectionList = new PresentationConnectionList(mOwner,
- mGetConnectionListPromise);
-
- // Register listener for incoming sessions.
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- mGetConnectionListPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- nsresult rv = service->RegisterRespondingListener(mWindowId, this);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- mGetConnectionListPromise->MaybeReject(rv);
- }
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/PresentationReceiver.h b/dom/presentation/PresentationReceiver.h
deleted file mode 100644
index ee72f587b..000000000
--- a/dom/presentation/PresentationReceiver.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- 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_PresentationReceiver_h
-#define mozilla_dom_PresentationReceiver_h
-
-#include "mozilla/ErrorResult.h"
-#include "nsCOMPtr.h"
-#include "nsCycleCollectionParticipant.h"
-#include "nsIPresentationListener.h"
-#include "nsWrapperCache.h"
-#include "nsString.h"
-
-class nsPIDOMWindowInner;
-
-namespace mozilla {
-namespace dom {
-
-class PresentationConnection;
-class PresentationConnectionList;
-class Promise;
-
-class PresentationReceiver final : public nsIPresentationRespondingListener
- , public nsWrapperCache
-{
-public:
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PresentationReceiver)
- NS_DECL_NSIPRESENTATIONRESPONDINGLISTENER
-
- static already_AddRefed<PresentationReceiver> Create(nsPIDOMWindowInner* aWindow);
-
- virtual JSObject* WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto) override;
-
- nsPIDOMWindowInner* GetParentObject() const
- {
- return mOwner;
- }
-
- // WebIDL (public APIs)
- already_AddRefed<Promise> GetConnectionList(ErrorResult& aRv);
-
-private:
- explicit PresentationReceiver(nsPIDOMWindowInner* aWindow);
-
- virtual ~PresentationReceiver();
-
- MOZ_IS_CLASS_INIT bool Init();
-
- void Shutdown();
-
- void CreateConnectionList();
-
- // Store the inner window ID for |UnregisterRespondingListener| call in
- // |Shutdown| since the inner window may not exist at that moment.
- uint64_t mWindowId;
-
- nsCOMPtr<nsPIDOMWindowInner> mOwner;
- nsString mUrl;
- RefPtr<Promise> mGetConnectionListPromise;
- RefPtr<PresentationConnectionList> mConnectionList;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationReceiver_h
diff --git a/dom/presentation/PresentationRequest.cpp b/dom/presentation/PresentationRequest.cpp
deleted file mode 100644
index 221684e53..000000000
--- a/dom/presentation/PresentationRequest.cpp
+++ /dev/null
@@ -1,563 +0,0 @@
-/* -*- 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/. */
-
-#include "PresentationRequest.h"
-
-#include "AvailabilityCollection.h"
-#include "ControllerConnectionCollection.h"
-#include "mozilla/BasePrincipal.h"
-#include "mozilla/dom/Navigator.h"
-#include "mozilla/dom/PresentationRequestBinding.h"
-#include "mozilla/dom/PresentationConnectionAvailableEvent.h"
-#include "mozilla/dom/Promise.h"
-#include "mozilla/Move.h"
-#include "mozIThirdPartyUtil.h"
-#include "nsContentSecurityManager.h"
-#include "nsCycleCollectionParticipant.h"
-#include "nsGlobalWindow.h"
-#include "nsIDocument.h"
-#include "nsIPresentationService.h"
-#include "nsIURI.h"
-#include "nsIUUIDGenerator.h"
-#include "nsNetUtil.h"
-#include "nsSandboxFlags.h"
-#include "nsServiceManagerUtils.h"
-#include "Presentation.h"
-#include "PresentationAvailability.h"
-#include "PresentationCallbacks.h"
-#include "PresentationLog.h"
-#include "PresentationTransportBuilderConstructor.h"
-
-using namespace mozilla;
-using namespace mozilla::dom;
-
-NS_IMPL_ADDREF_INHERITED(PresentationRequest, DOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(PresentationRequest, DOMEventTargetHelper)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PresentationRequest)
-NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-
-static nsresult
-GetAbsoluteURL(const nsAString& aUrl,
- nsIURI* aBaseUri,
- nsIDocument* aDocument,
- nsAString& aAbsoluteUrl)
-{
- nsCOMPtr<nsIURI> uri;
- nsresult rv = NS_NewURI(getter_AddRefs(uri),
- aUrl,
- aDocument ? aDocument->GetDocumentCharacterSet().get()
- : nullptr,
- aBaseUri);
-
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- nsAutoCString spec;
- uri->GetSpec(spec);
-
- aAbsoluteUrl = NS_ConvertUTF8toUTF16(spec);
-
- return NS_OK;
-}
-
-/* static */ already_AddRefed<PresentationRequest>
-PresentationRequest::Constructor(const GlobalObject& aGlobal,
- const nsAString& aUrl,
- ErrorResult& aRv)
-{
- Sequence<nsString> urls;
- urls.AppendElement(aUrl, fallible);
- return Constructor(aGlobal, urls, aRv);
-}
-
-/* static */ already_AddRefed<PresentationRequest>
-PresentationRequest::Constructor(const GlobalObject& aGlobal,
- const Sequence<nsString>& aUrls,
- ErrorResult& aRv)
-{
- nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
- if (!window) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return nullptr;
- }
-
- if (aUrls.IsEmpty()) {
- aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
- return nullptr;
- }
-
- // Resolve relative URL to absolute URL
- nsCOMPtr<nsIURI> baseUri = window->GetDocBaseURI();
- nsTArray<nsString> urls;
- for (const auto& url : aUrls) {
- nsAutoString absoluteUrl;
- nsresult rv =
- GetAbsoluteURL(url, baseUri, window->GetExtantDoc(), absoluteUrl);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
- return nullptr;
- }
-
- urls.AppendElement(absoluteUrl);
- }
-
- RefPtr<PresentationRequest> request =
- new PresentationRequest(window, Move(urls));
- return NS_WARN_IF(!request->Init()) ? nullptr : request.forget();
-}
-
-PresentationRequest::PresentationRequest(nsPIDOMWindowInner* aWindow,
- nsTArray<nsString>&& aUrls)
- : DOMEventTargetHelper(aWindow)
- , mUrls(Move(aUrls))
-{
-}
-
-PresentationRequest::~PresentationRequest()
-{
-}
-
-bool
-PresentationRequest::Init()
-{
- return true;
-}
-
-/* virtual */ JSObject*
-PresentationRequest::WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto)
-{
- return PresentationRequestBinding::Wrap(aCx, this, aGivenProto);
-}
-
-already_AddRefed<Promise>
-PresentationRequest::Start(ErrorResult& aRv)
-{
- return StartWithDevice(NullString(), aRv);
-}
-
-already_AddRefed<Promise>
-PresentationRequest::StartWithDevice(const nsAString& aDeviceId,
- ErrorResult& aRv)
-{
- nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
- if (NS_WARN_IF(!global)) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return nullptr;
- }
-
- // Get the origin.
- nsAutoString origin;
- nsresult rv = nsContentUtils::GetUTFOrigin(global->PrincipalOrNull(), origin);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- aRv.Throw(rv);
- return nullptr;
- }
-
- nsCOMPtr<nsIDocument> doc = GetOwner()->GetExtantDoc();
- if (NS_WARN_IF(!doc)) {
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
-
- RefPtr<Promise> promise = Promise::Create(global, aRv);
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
-
- if (IsProhibitMixedSecurityContexts(doc) &&
- !IsAllURLAuthenticated()) {
- promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
- return promise.forget();
- }
-
- if (doc->GetSandboxFlags() & SANDBOXED_PRESENTATION) {
- promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
- return promise.forget();
- }
-
- RefPtr<Navigator> navigator =
- nsGlobalWindow::Cast(GetOwner())->GetNavigator(aRv);
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
-
- RefPtr<Presentation> presentation = navigator->GetPresentation(aRv);
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
-
- if (presentation->IsStartSessionUnsettled()) {
- promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
- return promise.forget();
- }
-
- // Generate a session ID.
- nsCOMPtr<nsIUUIDGenerator> uuidgen =
- do_GetService("@mozilla.org/uuid-generator;1");
- if(NS_WARN_IF(!uuidgen)) {
- promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
- return promise.forget();
- }
-
- nsID uuid;
- uuidgen->GenerateUUIDInPlace(&uuid);
- char buffer[NSID_LENGTH];
- uuid.ToProvidedString(buffer);
- nsAutoString id;
- CopyASCIItoUTF16(buffer, id);
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if(NS_WARN_IF(!service)) {
- promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
- return promise.forget();
- }
-
- presentation->SetStartSessionUnsettled(true);
-
- // Get xul:browser element in parent process or nsWindowRoot object in child
- // process. If it's in child process, the corresponding xul:browser element
- // will be obtained at PresentationRequestParent::DoRequest in its parent
- // process.
- nsCOMPtr<nsIDOMEventTarget> handler =
- do_QueryInterface(GetOwner()->GetChromeEventHandler());
- nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
- nsCOMPtr<nsIPresentationServiceCallback> callback =
- new PresentationRequesterCallback(this, id, promise);
- nsCOMPtr<nsIPresentationTransportBuilderConstructor> constructor =
- PresentationTransportBuilderConstructor::Create();
- rv = service->StartSession(mUrls,
- id,
- origin,
- aDeviceId,
- GetOwner()->WindowID(),
- handler,
- principal,
- callback,
- constructor);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
- NotifyPromiseSettled();
- }
-
- return promise.forget();
-}
-
-already_AddRefed<Promise>
-PresentationRequest::Reconnect(const nsAString& aPresentationId,
- ErrorResult& aRv)
-{
- nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
- if (NS_WARN_IF(!global)) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return nullptr;
- }
-
- nsCOMPtr<nsIDocument> doc = GetOwner()->GetExtantDoc();
- if (NS_WARN_IF(!doc)) {
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
-
- RefPtr<Promise> promise = Promise::Create(global, aRv);
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
-
- if (IsProhibitMixedSecurityContexts(doc) &&
- !IsAllURLAuthenticated()) {
- promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
- return promise.forget();
- }
-
- if (doc->GetSandboxFlags() & SANDBOXED_PRESENTATION) {
- promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
- return promise.forget();
- }
-
- nsString presentationId = nsString(aPresentationId);
- nsCOMPtr<nsIRunnable> r =
- NewRunnableMethod<nsString, RefPtr<Promise>>(
- this,
- &PresentationRequest::FindOrCreatePresentationConnection,
- presentationId,
- promise);
-
- if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(r)))) {
- promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- return promise.forget();
-}
-
-void
-PresentationRequest::FindOrCreatePresentationConnection(
- const nsAString& aPresentationId,
- Promise* aPromise)
-{
- MOZ_ASSERT(aPromise);
-
- if (NS_WARN_IF(!GetOwner())) {
- aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- RefPtr<PresentationConnection> connection =
- ControllerConnectionCollection::GetSingleton()->FindConnection(
- GetOwner()->WindowID(),
- aPresentationId,
- nsIPresentationService::ROLE_CONTROLLER);
-
- if (connection) {
- nsAutoString url;
- connection->GetUrl(url);
- if (mUrls.Contains(url)) {
- switch (connection->State()) {
- case PresentationConnectionState::Closed:
- // We found the matched connection.
- break;
- case PresentationConnectionState::Connecting:
- case PresentationConnectionState::Connected:
- aPromise->MaybeResolve(connection);
- return;
- case PresentationConnectionState::Terminated:
- // A terminated connection cannot be reused.
- connection = nullptr;
- break;
- default:
- MOZ_CRASH("Unknown presentation session state.");
- return;
- }
- } else {
- connection = nullptr;
- }
- }
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if(NS_WARN_IF(!service)) {
- aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- nsCOMPtr<nsIPresentationServiceCallback> callback =
- new PresentationReconnectCallback(this,
- aPresentationId,
- aPromise,
- connection);
-
- nsresult rv =
- service->ReconnectSession(mUrls,
- aPresentationId,
- nsIPresentationService::ROLE_CONTROLLER,
- callback);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
- }
-}
-
-already_AddRefed<Promise>
-PresentationRequest::GetAvailability(ErrorResult& aRv)
-{
- PRES_DEBUG("%s\n", __func__);
- nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
- if (NS_WARN_IF(!global)) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return nullptr;
- }
-
- nsCOMPtr<nsIDocument> doc = GetOwner()->GetExtantDoc();
- if (NS_WARN_IF(!doc)) {
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
-
- RefPtr<Promise> promise = Promise::Create(global, aRv);
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
-
- if (IsProhibitMixedSecurityContexts(doc) &&
- !IsAllURLAuthenticated()) {
- promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
- return promise.forget();
- }
-
- if (doc->GetSandboxFlags() & SANDBOXED_PRESENTATION) {
- promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
- return promise.forget();
- }
-
- FindOrCreatePresentationAvailability(promise);
-
- return promise.forget();
-}
-
-void
-PresentationRequest::FindOrCreatePresentationAvailability(RefPtr<Promise>& aPromise)
-{
- MOZ_ASSERT(aPromise);
-
- if (NS_WARN_IF(!GetOwner())) {
- aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- AvailabilityCollection* collection = AvailabilityCollection::GetSingleton();
- if (NS_WARN_IF(!collection)) {
- aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- RefPtr<PresentationAvailability> availability =
- collection->Find(GetOwner()->WindowID(), mUrls);
-
- if (!availability) {
- availability = PresentationAvailability::Create(GetOwner(), mUrls, aPromise);
- } else {
- PRES_DEBUG(">resolve with same object\n");
-
- // Fetching cached available devices is asynchronous in our implementation,
- // we need to ensure the promise is resolved in order.
- if (availability->IsCachedValueReady()) {
- aPromise->MaybeResolve(availability);
- return;
- }
-
- availability->EnqueuePromise(aPromise);
- }
-
- if (!availability) {
- aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
- return;
- }
-}
-
-nsresult
-PresentationRequest::DispatchConnectionAvailableEvent(PresentationConnection* aConnection)
-{
- PresentationConnectionAvailableEventInit init;
- init.mConnection = aConnection;
-
- RefPtr<PresentationConnectionAvailableEvent> event =
- PresentationConnectionAvailableEvent::Constructor(this,
- NS_LITERAL_STRING("connectionavailable"),
- init);
- if (NS_WARN_IF(!event)) {
- return NS_ERROR_FAILURE;
- }
- event->SetTrusted(true);
-
- RefPtr<AsyncEventDispatcher> asyncDispatcher =
- new AsyncEventDispatcher(this, event);
- return asyncDispatcher->PostDOMEvent();
-}
-
-void
-PresentationRequest::NotifyPromiseSettled()
-{
- PRES_DEBUG("%s\n", __func__);
-
- if (!GetOwner()) {
- return;
- }
-
- ErrorResult rv;
- RefPtr<Navigator> navigator =
- nsGlobalWindow::Cast(GetOwner())->GetNavigator(rv);
- if (!navigator) {
- return;
- }
-
- RefPtr<Presentation> presentation = navigator->GetPresentation(rv);
-
- if (presentation) {
- presentation->SetStartSessionUnsettled(false);
- }
-}
-
-bool
-PresentationRequest::IsProhibitMixedSecurityContexts(nsIDocument* aDocument)
-{
- MOZ_ASSERT(aDocument);
-
- if (nsContentUtils::IsChromeDoc(aDocument)) {
- return true;
- }
-
- nsCOMPtr<nsIDocument> doc = aDocument;
- while (doc && !nsContentUtils::IsChromeDoc(doc)) {
- if (nsContentUtils::HttpsStateIsModern(doc)) {
- return true;
- }
-
- doc = doc->GetParentDocument();
- }
-
- return false;
-}
-
-bool
-PresentationRequest::IsPrioriAuthenticatedURL(const nsAString& aUrl)
-{
- nsCOMPtr<nsIURI> uri;
- if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), aUrl))) {
- return false;
- }
-
- nsAutoCString scheme;
- nsresult rv = uri->GetScheme(scheme);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return false;
- }
-
- if (scheme.EqualsLiteral("data")) {
- return true;
- }
-
- nsAutoCString uriSpec;
- rv = uri->GetSpec(uriSpec);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return false;
- }
-
- if (uriSpec.EqualsLiteral("about:blank") ||
- uriSpec.EqualsLiteral("about:srcdoc")) {
- return true;
- }
-
- PrincipalOriginAttributes attrs;
- nsCOMPtr<nsIPrincipal> principal =
- BasePrincipal::CreateCodebasePrincipal(uri, attrs);
- if (NS_WARN_IF(!principal)) {
- return false;
- }
-
- nsCOMPtr<nsIContentSecurityManager> csm =
- do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
- if (NS_WARN_IF(!csm)) {
- return false;
- }
-
- bool isTrustworthyOrigin = false;
- csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin);
- return isTrustworthyOrigin;
-}
-
-bool
-PresentationRequest::IsAllURLAuthenticated()
-{
- for (const auto& url : mUrls) {
- if (!IsPrioriAuthenticatedURL(url)) {
- return false;
- }
- }
-
- return true;
-}
diff --git a/dom/presentation/PresentationRequest.h b/dom/presentation/PresentationRequest.h
deleted file mode 100644
index ce82f2b44..000000000
--- a/dom/presentation/PresentationRequest.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* -*- 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_PresentationRequest_h
-#define mozilla_dom_PresentationRequest_h
-
-#include "mozilla/dom/BindingDeclarations.h"
-#include "mozilla/DOMEventTargetHelper.h"
-
-class nsIDocument;
-
-namespace mozilla {
-namespace dom {
-
-class Promise;
-class PresentationAvailability;
-class PresentationConnection;
-
-class PresentationRequest final : public DOMEventTargetHelper
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
-
- static already_AddRefed<PresentationRequest> Constructor(
- const GlobalObject& aGlobal,
- const nsAString& aUrl,
- ErrorResult& aRv);
-
- static already_AddRefed<PresentationRequest> Constructor(
- const GlobalObject& aGlobal,
- const Sequence<nsString>& aUrls,
- ErrorResult& aRv);
-
- virtual JSObject* WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto) override;
-
- // WebIDL (public APIs)
- already_AddRefed<Promise> Start(ErrorResult& aRv);
-
- already_AddRefed<Promise> StartWithDevice(const nsAString& aDeviceId,
- ErrorResult& aRv);
-
- already_AddRefed<Promise> Reconnect(const nsAString& aPresentationId,
- ErrorResult& aRv);
-
- already_AddRefed<Promise> GetAvailability(ErrorResult& aRv);
-
- IMPL_EVENT_HANDLER(connectionavailable);
-
- nsresult DispatchConnectionAvailableEvent(PresentationConnection* aConnection);
-
- void NotifyPromiseSettled();
-
-private:
- PresentationRequest(nsPIDOMWindowInner* aWindow,
- nsTArray<nsString>&& aUrls);
-
- ~PresentationRequest();
-
- bool Init();
-
- void FindOrCreatePresentationConnection(const nsAString& aPresentationId,
- Promise* aPromise);
-
- void FindOrCreatePresentationAvailability(RefPtr<Promise>& aPromise);
-
- // Implement https://w3c.github.io/webappsec-mixed-content/#categorize-settings-object
- bool IsProhibitMixedSecurityContexts(nsIDocument* aDocument);
-
- // Implement https://w3c.github.io/webappsec-mixed-content/#a-priori-authenticated-url
- bool IsPrioriAuthenticatedURL(const nsAString& aUrl);
-
- bool IsAllURLAuthenticated();
-
- nsTArray<nsString> mUrls;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationRequest_h
diff --git a/dom/presentation/PresentationService.cpp b/dom/presentation/PresentationService.cpp
deleted file mode 100644
index bc525cdb8..000000000
--- a/dom/presentation/PresentationService.cpp
+++ /dev/null
@@ -1,1188 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 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 "PresentationService.h"
-
-#include "ipc/PresentationIPCService.h"
-#include "mozilla/Services.h"
-#include "nsGlobalWindow.h"
-#include "nsIMutableArray.h"
-#include "nsIObserverService.h"
-#include "nsIPresentationControlChannel.h"
-#include "nsIPresentationDeviceManager.h"
-#include "nsIPresentationDevicePrompt.h"
-#include "nsIPresentationListener.h"
-#include "nsIPresentationRequestUIGlue.h"
-#include "nsIPresentationSessionRequest.h"
-#include "nsIPresentationTerminateRequest.h"
-#include "nsISupportsPrimitives.h"
-#include "nsNetUtil.h"
-#include "nsServiceManagerUtils.h"
-#include "nsThreadUtils.h"
-#include "nsXPCOMCID.h"
-#include "nsXULAppAPI.h"
-#include "PresentationLog.h"
-
-namespace mozilla {
-namespace dom {
-
-static bool
-IsSameDevice(nsIPresentationDevice* aDevice, nsIPresentationDevice* aDeviceAnother) {
- if (!aDevice || !aDeviceAnother) {
- return false;
- }
-
- nsAutoCString deviceId;
- aDevice->GetId(deviceId);
- nsAutoCString anotherId;
- aDeviceAnother->GetId(anotherId);
- if (!deviceId.Equals(anotherId)) {
- return false;
- }
-
- nsAutoCString deviceType;
- aDevice->GetType(deviceType);
- nsAutoCString anotherType;
- aDeviceAnother->GetType(anotherType);
- if (!deviceType.Equals(anotherType)) {
- return false;
- }
-
- return true;
-}
-
-static nsresult
-ConvertURLArrayHelper(const nsTArray<nsString>& aUrls, nsIArray** aResult)
-{
- if (!aResult) {
- return NS_ERROR_INVALID_POINTER;
- }
-
- *aResult = nullptr;
-
- nsresult rv;
- nsCOMPtr<nsIMutableArray> urls =
- do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- for (const auto& url : aUrls) {
- nsCOMPtr<nsISupportsString> isupportsString =
- do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = isupportsString->SetData(url);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = urls->AppendElement(isupportsString, false);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- }
-
- urls.forget(aResult);
- return NS_OK;
-}
-
-/*
- * Implementation of PresentationDeviceRequest
- */
-
-class PresentationDeviceRequest final : public nsIPresentationDeviceRequest
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONDEVICEREQUEST
-
- PresentationDeviceRequest(
- const nsTArray<nsString>& aUrls,
- const nsAString& aId,
- const nsAString& aOrigin,
- uint64_t aWindowId,
- nsIDOMEventTarget* aEventTarget,
- nsIPrincipal* aPrincipal,
- nsIPresentationServiceCallback* aCallback,
- nsIPresentationTransportBuilderConstructor* aBuilderConstructor);
-
-private:
- virtual ~PresentationDeviceRequest() = default;
- nsresult CreateSessionInfo(nsIPresentationDevice* aDevice,
- const nsAString& aSelectedRequestUrl);
-
- nsTArray<nsString> mRequestUrls;
- nsString mId;
- nsString mOrigin;
- uint64_t mWindowId;
- nsWeakPtr mChromeEventHandler;
- nsCOMPtr<nsIPrincipal> mPrincipal;
- nsCOMPtr<nsIPresentationServiceCallback> mCallback;
- nsCOMPtr<nsIPresentationTransportBuilderConstructor> mBuilderConstructor;
-};
-
-LazyLogModule gPresentationLog("Presentation");
-
-NS_IMPL_ISUPPORTS(PresentationDeviceRequest, nsIPresentationDeviceRequest)
-
-PresentationDeviceRequest::PresentationDeviceRequest(
- const nsTArray<nsString>& aUrls,
- const nsAString& aId,
- const nsAString& aOrigin,
- uint64_t aWindowId,
- nsIDOMEventTarget* aEventTarget,
- nsIPrincipal* aPrincipal,
- nsIPresentationServiceCallback* aCallback,
- nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
- : mRequestUrls(aUrls)
- , mId(aId)
- , mOrigin(aOrigin)
- , mWindowId(aWindowId)
- , mChromeEventHandler(do_GetWeakReference(aEventTarget))
- , mPrincipal(aPrincipal)
- , mCallback(aCallback)
- , mBuilderConstructor(aBuilderConstructor)
-{
- MOZ_ASSERT(!mRequestUrls.IsEmpty());
- MOZ_ASSERT(!mId.IsEmpty());
- MOZ_ASSERT(!mOrigin.IsEmpty());
- MOZ_ASSERT(mCallback);
- MOZ_ASSERT(mBuilderConstructor);
-}
-
-NS_IMETHODIMP
-PresentationDeviceRequest::GetOrigin(nsAString& aOrigin)
-{
- aOrigin = mOrigin;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceRequest::GetRequestURLs(nsIArray** aUrls)
-{
- return ConvertURLArrayHelper(mRequestUrls, aUrls);
-}
-
-NS_IMETHODIMP
-PresentationDeviceRequest::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler)
-{
- nsCOMPtr<nsIDOMEventTarget> handler(do_QueryReferent(mChromeEventHandler));
- handler.forget(aChromeEventHandler);
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceRequest::GetPrincipal(nsIPrincipal** aPrincipal)
-{
- nsCOMPtr<nsIPrincipal> principal(mPrincipal);
- principal.forget(aPrincipal);
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceRequest::Select(nsIPresentationDevice* aDevice)
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (NS_WARN_IF(!aDevice)) {
- MOZ_ASSERT(false, "|aDevice| should noe be null.");
- mCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
- return NS_ERROR_INVALID_ARG;
- }
-
- // Select the most suitable URL for starting the presentation.
- nsAutoString selectedRequestUrl;
- for (const auto& url : mRequestUrls) {
- bool isSupported;
- if (NS_SUCCEEDED(aDevice->IsRequestedUrlSupported(url, &isSupported)) &&
- isSupported) {
- selectedRequestUrl.Assign(url);
- break;
- }
- }
-
- if (selectedRequestUrl.IsEmpty()) {
- return mCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
- }
-
- if (NS_WARN_IF(NS_FAILED(CreateSessionInfo(aDevice, selectedRequestUrl)))) {
- return mCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- return mCallback->NotifySuccess(selectedRequestUrl);
-}
-
-nsresult
-PresentationDeviceRequest::CreateSessionInfo(
- nsIPresentationDevice* aDevice,
- const nsAString& aSelectedRequestUrl)
-{
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- // Create the controlling session info
- RefPtr<PresentationSessionInfo> info =
- static_cast<PresentationService*>(service.get())->
- CreateControllingSessionInfo(aSelectedRequestUrl, mId, mWindowId);
- if (NS_WARN_IF(!info)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- info->SetDevice(aDevice);
-
- // Establish a control channel. If we failed to do so, the callback is called
- // with an error message.
- nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
- nsresult rv = aDevice->EstablishControlChannel(getter_AddRefs(ctrlChannel));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- // Initialize the session info with the control channel.
- rv = info->Init(ctrlChannel);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- info->SetTransportBuilderConstructor(mBuilderConstructor);
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationDeviceRequest::Cancel(nsresult aReason)
-{
- return mCallback->NotifyError(aReason);
-}
-
-/*
- * Implementation of PresentationService
- */
-
-NS_IMPL_ISUPPORTS(PresentationService,
- nsIPresentationService,
- nsIObserver)
-
-PresentationService::PresentationService()
-{
-}
-
-PresentationService::~PresentationService()
-{
- HandleShutdown();
-}
-
-bool
-PresentationService::Init()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
- if (NS_WARN_IF(!obs)) {
- return false;
- }
-
- nsresult rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return false;
- }
- rv = obs->AddObserver(this, PRESENTATION_DEVICE_CHANGE_TOPIC, false);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return false;
- }
- rv = obs->AddObserver(this, PRESENTATION_SESSION_REQUEST_TOPIC, false);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return false;
- }
- rv = obs->AddObserver(this, PRESENTATION_TERMINATE_REQUEST_TOPIC, false);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return false;
- }
- rv = obs->AddObserver(this, PRESENTATION_RECONNECT_REQUEST_TOPIC, false);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return false;
- }
-
- return !NS_WARN_IF(NS_FAILED(rv));
-}
-
-NS_IMETHODIMP
-PresentationService::Observe(nsISupports* aSubject,
- const char* aTopic,
- const char16_t* aData)
-{
- if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
- HandleShutdown();
- return NS_OK;
- } else if (!strcmp(aTopic, PRESENTATION_DEVICE_CHANGE_TOPIC)) {
- // Ignore the "update" case here, since we only care about the arrival and
- // removal of the device.
- if (!NS_strcmp(aData, u"add")) {
- nsCOMPtr<nsIPresentationDevice> device = do_QueryInterface(aSubject);
- if (NS_WARN_IF(!device)) {
- return NS_ERROR_FAILURE;
- }
-
- return HandleDeviceAdded(device);
- } else if(!NS_strcmp(aData, u"remove")) {
- return HandleDeviceRemoved();
- }
-
- return NS_OK;
- } else if (!strcmp(aTopic, PRESENTATION_SESSION_REQUEST_TOPIC)) {
- nsCOMPtr<nsIPresentationSessionRequest> request(do_QueryInterface(aSubject));
- if (NS_WARN_IF(!request)) {
- return NS_ERROR_FAILURE;
- }
-
- return HandleSessionRequest(request);
- } else if (!strcmp(aTopic, PRESENTATION_TERMINATE_REQUEST_TOPIC)) {
- nsCOMPtr<nsIPresentationTerminateRequest> request(do_QueryInterface(aSubject));
- if (NS_WARN_IF(!request)) {
- return NS_ERROR_FAILURE;
- }
-
- return HandleTerminateRequest(request);
- } else if (!strcmp(aTopic, PRESENTATION_RECONNECT_REQUEST_TOPIC)) {
- nsCOMPtr<nsIPresentationSessionRequest> request(do_QueryInterface(aSubject));
- if (NS_WARN_IF(!request)) {
- return NS_ERROR_FAILURE;
- }
-
- return HandleReconnectRequest(request);
- } else if (!strcmp(aTopic, "profile-after-change")) {
- // It's expected since we add and entry to |kLayoutCategories| in
- // |nsLayoutModule.cpp| to launch this service earlier.
- return NS_OK;
- }
-
- MOZ_ASSERT(false, "Unexpected topic for PresentationService");
- return NS_ERROR_UNEXPECTED;
-}
-
-void
-PresentationService::HandleShutdown()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- Shutdown();
-
- mAvailabilityManager.Clear();
- mSessionInfoAtController.Clear();
- mSessionInfoAtReceiver.Clear();
-
- nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
- if (obs) {
- obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
- obs->RemoveObserver(this, PRESENTATION_DEVICE_CHANGE_TOPIC);
- obs->RemoveObserver(this, PRESENTATION_SESSION_REQUEST_TOPIC);
- obs->RemoveObserver(this, PRESENTATION_TERMINATE_REQUEST_TOPIC);
- obs->RemoveObserver(this, PRESENTATION_RECONNECT_REQUEST_TOPIC);
- }
-}
-
-nsresult
-PresentationService::HandleDeviceAdded(nsIPresentationDevice* aDevice)
-{
- PRES_DEBUG("%s\n", __func__);
- if (!aDevice) {
- MOZ_ASSERT(false, "aDevice shoud no be null.");
- return NS_ERROR_INVALID_ARG;
- }
-
- // Query for only unavailable URLs while device added.
- nsTArray<nsString> unavailableUrls;
- mAvailabilityManager.GetAvailbilityUrlByAvailability(unavailableUrls, false);
-
- nsTArray<nsString> supportedAvailabilityUrl;
- for (const auto& url : unavailableUrls) {
- bool isSupported;
- if (NS_SUCCEEDED(aDevice->IsRequestedUrlSupported(url, &isSupported)) &&
- isSupported) {
- supportedAvailabilityUrl.AppendElement(url);
- }
- }
-
- if (!supportedAvailabilityUrl.IsEmpty()) {
- return mAvailabilityManager.DoNotifyAvailableChange(supportedAvailabilityUrl,
- true);
- }
-
- return NS_OK;
-}
-
-nsresult
-PresentationService::HandleDeviceRemoved()
-{
- PRES_DEBUG("%s\n", __func__);
-
- // Query for only available URLs while device removed.
- nsTArray<nsString> availabilityUrls;
- mAvailabilityManager.GetAvailbilityUrlByAvailability(availabilityUrls, true);
-
- return UpdateAvailabilityUrlChange(availabilityUrls);
-}
-
-nsresult
-PresentationService::UpdateAvailabilityUrlChange(
- const nsTArray<nsString>& aAvailabilityUrls)
-{
- nsCOMPtr<nsIPresentationDeviceManager> deviceManager =
- do_GetService(PRESENTATION_DEVICE_MANAGER_CONTRACTID);
- if (NS_WARN_IF(!deviceManager)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- nsCOMPtr<nsIArray> devices;
- nsresult rv = deviceManager->GetAvailableDevices(nullptr,
- getter_AddRefs(devices));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- uint32_t numOfDevices;
- devices->GetLength(&numOfDevices);
-
- nsTArray<nsString> supportedAvailabilityUrl;
- for (const auto& url : aAvailabilityUrls) {
- for (uint32_t i = 0; i < numOfDevices; ++i) {
- nsCOMPtr<nsIPresentationDevice> device = do_QueryElementAt(devices, i);
- if (device) {
- bool isSupported;
- if (NS_SUCCEEDED(device->IsRequestedUrlSupported(url, &isSupported)) &&
- isSupported) {
- supportedAvailabilityUrl.AppendElement(url);
- break;
- }
- }
- }
- }
-
- if (supportedAvailabilityUrl.IsEmpty()) {
- return mAvailabilityManager.DoNotifyAvailableChange(aAvailabilityUrls,
- false);
- }
-
- return mAvailabilityManager.DoNotifyAvailableChange(supportedAvailabilityUrl,
- true);
-}
-
-nsresult
-PresentationService::HandleSessionRequest(nsIPresentationSessionRequest* aRequest)
-{
- nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
- nsresult rv = aRequest->GetControlChannel(getter_AddRefs(ctrlChannel));
- if (NS_WARN_IF(NS_FAILED(rv) || !ctrlChannel)) {
- return rv;
- }
-
- nsAutoString url;
- rv = aRequest->GetUrl(url);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ctrlChannel->Disconnect(rv);
- return rv;
- }
-
- nsAutoString sessionId;
- rv = aRequest->GetPresentationId(sessionId);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ctrlChannel->Disconnect(rv);
- return rv;
- }
-
- nsCOMPtr<nsIPresentationDevice> device;
- rv = aRequest->GetDevice(getter_AddRefs(device));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ctrlChannel->Disconnect(rv);
- return rv;
- }
-
- // Create or reuse session info.
- RefPtr<PresentationSessionInfo> info =
- GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);
-
- // This is the case for reconnecting a session.
- // Update the control channel and device of the session info.
- // Call |NotifyResponderReady| to indicate the receiver page is already there.
- if (info) {
- PRES_DEBUG("handle reconnection:id[%s]\n",
- NS_ConvertUTF16toUTF8(sessionId).get());
-
- info->SetControlChannel(ctrlChannel);
- info->SetDevice(device);
- return static_cast<PresentationPresentingInfo*>(
- info.get())->DoReconnect();
- }
-
- // This is the case for a new session.
- PRES_DEBUG("handle new session:url[%d], id[%s]\n",
- NS_ConvertUTF16toUTF8(url).get(),
- NS_ConvertUTF16toUTF8(sessionId).get());
-
- info = new PresentationPresentingInfo(url, sessionId, device);
- rv = info->Init(ctrlChannel);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ctrlChannel->Disconnect(rv);
- return rv;
- }
-
- mSessionInfoAtReceiver.Put(sessionId, info);
-
- // Notify the receiver to launch.
- nsCOMPtr<nsIPresentationRequestUIGlue> glue =
- do_CreateInstance(PRESENTATION_REQUEST_UI_GLUE_CONTRACTID);
- if (NS_WARN_IF(!glue)) {
- ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
- return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
- nsCOMPtr<nsISupports> promise;
- rv = glue->SendRequest(url, sessionId, device, getter_AddRefs(promise));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ctrlChannel->Disconnect(rv);
- return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
- nsCOMPtr<Promise> realPromise = do_QueryInterface(promise);
- static_cast<PresentationPresentingInfo*>(info.get())->SetPromise(realPromise);
-
- return NS_OK;
-}
-
-nsresult
-PresentationService::HandleTerminateRequest(nsIPresentationTerminateRequest* aRequest)
-{
- nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
- nsresult rv = aRequest->GetControlChannel(getter_AddRefs(ctrlChannel));
- if (NS_WARN_IF(NS_FAILED(rv) || !ctrlChannel)) {
- return rv;
- }
-
- nsAutoString sessionId;
- rv = aRequest->GetPresentationId(sessionId);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ctrlChannel->Disconnect(rv);
- return rv;
- }
-
- nsCOMPtr<nsIPresentationDevice> device;
- rv = aRequest->GetDevice(getter_AddRefs(device));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ctrlChannel->Disconnect(rv);
- return rv;
- }
-
- bool isFromReceiver;
- rv = aRequest->GetIsFromReceiver(&isFromReceiver);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ctrlChannel->Disconnect(rv);
- return rv;
- }
-
- RefPtr<PresentationSessionInfo> info;
- if (!isFromReceiver) {
- info = GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);
- } else {
- info = GetSessionInfo(sessionId, nsIPresentationService::ROLE_CONTROLLER);
- }
- if (NS_WARN_IF(!info)) {
- // Cannot terminate non-existed session.
- ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
- return NS_ERROR_DOM_ABORT_ERR;
- }
-
- // Check if terminate request comes from known device.
- RefPtr<nsIPresentationDevice> knownDevice = info->GetDevice();
- if (NS_WARN_IF(!IsSameDevice(device, knownDevice))) {
- ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
- return NS_ERROR_DOM_ABORT_ERR;
- }
-
- PRES_DEBUG("handle termination:id[%s], receiver[%d]\n", __func__,
- sessionId.get(), isFromReceiver);
-
- return info->OnTerminate(ctrlChannel);
-}
-
-nsresult
-PresentationService::HandleReconnectRequest(nsIPresentationSessionRequest* aRequest)
-{
- nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
- nsresult rv = aRequest->GetControlChannel(getter_AddRefs(ctrlChannel));
- if (NS_WARN_IF(NS_FAILED(rv) || !ctrlChannel)) {
- return rv;
- }
-
- nsAutoString sessionId;
- rv = aRequest->GetPresentationId(sessionId);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ctrlChannel->Disconnect(rv);
- return rv;
- }
-
- uint64_t windowId;
- rv = GetWindowIdBySessionIdInternal(sessionId,
- nsIPresentationService::ROLE_RECEIVER,
- &windowId);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ctrlChannel->Disconnect(rv);
- return rv;
- }
-
- RefPtr<PresentationSessionInfo> info =
- GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);
- if (NS_WARN_IF(!info)) {
- // Cannot reconnect non-existed session
- ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
- return NS_ERROR_DOM_ABORT_ERR;
- }
-
- nsAutoString url;
- rv = aRequest->GetUrl(url);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ctrlChannel->Disconnect(rv);
- return rv;
- }
-
- // Make sure the url is the same as the previous one.
- if (NS_WARN_IF(!info->GetUrl().Equals(url))) {
- ctrlChannel->Disconnect(rv);
- return rv;
- }
-
- return HandleSessionRequest(aRequest);
-}
-
-NS_IMETHODIMP
-PresentationService::StartSession(
- const nsTArray<nsString>& aUrls,
- const nsAString& aSessionId,
- const nsAString& aOrigin,
- const nsAString& aDeviceId,
- uint64_t aWindowId,
- nsIDOMEventTarget* aEventTarget,
- nsIPrincipal* aPrincipal,
- nsIPresentationServiceCallback* aCallback,
- nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
-{
- PRES_DEBUG("%s:id[%s]\n", __func__, NS_ConvertUTF16toUTF8(aSessionId).get());
-
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aCallback);
- MOZ_ASSERT(!aSessionId.IsEmpty());
- MOZ_ASSERT(!aUrls.IsEmpty());
-
- nsCOMPtr<nsIPresentationDeviceRequest> request =
- new PresentationDeviceRequest(aUrls,
- aSessionId,
- aOrigin,
- aWindowId,
- aEventTarget,
- aPrincipal,
- aCallback,
- aBuilderConstructor);
-
- if (aDeviceId.IsVoid()) {
- // Pop up a prompt and ask user to select a device.
- nsCOMPtr<nsIPresentationDevicePrompt> prompt =
- do_GetService(PRESENTATION_DEVICE_PROMPT_CONTRACTID);
- if (NS_WARN_IF(!prompt)) {
- return aCallback->NotifyError(NS_ERROR_DOM_INVALID_ACCESS_ERR);
- }
-
- nsresult rv = prompt->PromptDeviceSelection(request);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- return NS_OK;
- }
-
- // Find the designated device from available device list.
- nsCOMPtr<nsIPresentationDeviceManager> deviceManager =
- do_GetService(PRESENTATION_DEVICE_MANAGER_CONTRACTID);
- if (NS_WARN_IF(!deviceManager)) {
- return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- nsCOMPtr<nsIArray> presentationUrls;
- if (NS_WARN_IF(NS_FAILED(
- ConvertURLArrayHelper(aUrls, getter_AddRefs(presentationUrls))))) {
- return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- nsCOMPtr<nsIArray> devices;
- nsresult rv = deviceManager->GetAvailableDevices(presentationUrls, getter_AddRefs(devices));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- nsCOMPtr<nsISimpleEnumerator> enumerator;
- rv = devices->Enumerate(getter_AddRefs(enumerator));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- NS_ConvertUTF16toUTF8 utf8DeviceId(aDeviceId);
- bool hasMore;
- while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
- nsCOMPtr<nsISupports> isupports;
- rv = enumerator->GetNext(getter_AddRefs(isupports));
-
- nsCOMPtr<nsIPresentationDevice> device(do_QueryInterface(isupports));
- MOZ_ASSERT(device);
-
- nsAutoCString id;
- if (NS_SUCCEEDED(device->GetId(id)) && id.Equals(utf8DeviceId)) {
- request->Select(device);
- return NS_OK;
- }
- }
-
- // Reject if designated device is not available.
- return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
-}
-
-already_AddRefed<PresentationSessionInfo>
-PresentationService::CreateControllingSessionInfo(const nsAString& aUrl,
- const nsAString& aSessionId,
- uint64_t aWindowId)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (aSessionId.IsEmpty()) {
- return nullptr;
- }
-
- RefPtr<PresentationSessionInfo> info =
- new PresentationControllingInfo(aUrl, aSessionId);
-
- mSessionInfoAtController.Put(aSessionId, info);
- AddRespondingSessionId(aWindowId,
- aSessionId,
- nsIPresentationService::ROLE_CONTROLLER);
- return info.forget();
-}
-
-NS_IMETHODIMP
-PresentationService::SendSessionMessage(const nsAString& aSessionId,
- uint8_t aRole,
- const nsAString& aData)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!aData.IsEmpty());
- MOZ_ASSERT(!aSessionId.IsEmpty());
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
- if (NS_WARN_IF(!info)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return info->Send(aData);
-}
-
-NS_IMETHODIMP
-PresentationService::SendSessionBinaryMsg(const nsAString& aSessionId,
- uint8_t aRole,
- const nsACString &aData)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!aData.IsEmpty());
- MOZ_ASSERT(!aSessionId.IsEmpty());
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
- if (NS_WARN_IF(!info)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return info->SendBinaryMsg(aData);
-}
-
-NS_IMETHODIMP
-PresentationService::SendSessionBlob(const nsAString& aSessionId,
- uint8_t aRole,
- nsIDOMBlob* aBlob)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!aSessionId.IsEmpty());
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
- MOZ_ASSERT(aBlob);
-
- RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
- if (NS_WARN_IF(!info)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return info->SendBlob(aBlob);
-}
-
-NS_IMETHODIMP
-PresentationService::CloseSession(const nsAString& aSessionId,
- uint8_t aRole,
- uint8_t aClosedReason)
-{
- PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(aSessionId).get(), aClosedReason, aRole);
-
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!aSessionId.IsEmpty());
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
- if (NS_WARN_IF(!info)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- if (aClosedReason == nsIPresentationService::CLOSED_REASON_WENTAWAY) {
- // Remove nsIPresentationSessionListener since we don't want to dispatch
- // PresentationConnectionCloseEvent if the page is went away.
- info->SetListener(nullptr);
- }
-
- return info->Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED);
-}
-
-NS_IMETHODIMP
-PresentationService::TerminateSession(const nsAString& aSessionId,
- uint8_t aRole)
-{
- PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);
-
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!aSessionId.IsEmpty());
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
- if (NS_WARN_IF(!info)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return info->Close(NS_OK, nsIPresentationSessionListener::STATE_TERMINATED);
-}
-
-NS_IMETHODIMP
-PresentationService::ReconnectSession(const nsTArray<nsString>& aUrls,
- const nsAString& aSessionId,
- uint8_t aRole,
- nsIPresentationServiceCallback* aCallback)
-{
- PRES_DEBUG("%s:id[%s]\n", __func__, NS_ConvertUTF16toUTF8(aSessionId).get());
-
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!aSessionId.IsEmpty());
- MOZ_ASSERT(aCallback);
- MOZ_ASSERT(!aUrls.IsEmpty());
-
- if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
- MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
- return NS_ERROR_INVALID_ARG;
- }
-
- if (NS_WARN_IF(!aCallback)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
- if (NS_WARN_IF(!info)) {
- return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
- }
-
- if (NS_WARN_IF(!aUrls.Contains(info->GetUrl()))) {
- return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
- }
-
- return static_cast<PresentationControllingInfo*>(info.get())->Reconnect(aCallback);
-}
-
-NS_IMETHODIMP
-PresentationService::BuildTransport(const nsAString& aSessionId,
- uint8_t aRole)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!aSessionId.IsEmpty());
-
- if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
- MOZ_ASSERT(false, "Only controller can call BuildTransport.");
- return NS_ERROR_INVALID_ARG;
- }
-
- RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
- if (NS_WARN_IF(!info)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return static_cast<PresentationControllingInfo*>(info.get())->BuildTransport();
-}
-
-NS_IMETHODIMP
-PresentationService::RegisterAvailabilityListener(
- const nsTArray<nsString>& aAvailabilityUrls,
- nsIPresentationAvailabilityListener* aListener)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!aAvailabilityUrls.IsEmpty());
- MOZ_ASSERT(aListener);
-
- mAvailabilityManager.AddAvailabilityListener(aAvailabilityUrls, aListener);
- return UpdateAvailabilityUrlChange(aAvailabilityUrls);
-}
-
-NS_IMETHODIMP
-PresentationService::UnregisterAvailabilityListener(
- const nsTArray<nsString>& aAvailabilityUrls,
- nsIPresentationAvailabilityListener* aListener)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- mAvailabilityManager.RemoveAvailabilityListener(aAvailabilityUrls, aListener);
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationService::RegisterSessionListener(const nsAString& aSessionId,
- uint8_t aRole,
- nsIPresentationSessionListener* aListener)
-{
- PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);
-
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aListener);
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
- if (NS_WARN_IF(!info)) {
- // Notify the listener of TERMINATED since no correspondent session info is
- // available possibly due to establishment failure. This would be useful at
- // the receiver side, since a presentation session is created at beginning
- // and here is the place to realize the underlying establishment fails.
- nsresult rv = aListener->NotifyStateChange(aSessionId,
- nsIPresentationSessionListener::STATE_TERMINATED,
- NS_ERROR_NOT_AVAILABLE);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return info->SetListener(aListener);
-}
-
-NS_IMETHODIMP
-PresentationService::UnregisterSessionListener(const nsAString& aSessionId,
- uint8_t aRole)
-{
- PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);
-
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
- if (info) {
- // When content side decide not handling this session anymore, simply
- // close the connection. Session info is kept for reconnection.
- Unused << NS_WARN_IF(NS_FAILED(info->Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED)));
- return info->SetListener(nullptr);
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationService::RegisterRespondingListener(
- uint64_t aWindowId,
- nsIPresentationRespondingListener* aListener)
-{
- PRES_DEBUG("%s:windowId[%lld]\n", __func__, aWindowId);
-
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aListener);
-
- nsCOMPtr<nsIPresentationRespondingListener> listener;
- if (mRespondingListeners.Get(aWindowId, getter_AddRefs(listener))) {
- return (listener == aListener) ? NS_OK : NS_ERROR_DOM_INVALID_STATE_ERR;
- }
-
- nsTArray<nsString> sessionIdArray;
- nsresult rv = mReceiverSessionIdManager.GetSessionIds(aWindowId,
- sessionIdArray);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- for (const auto& id : sessionIdArray) {
- aListener->NotifySessionConnect(aWindowId, id);
- }
-
- mRespondingListeners.Put(aWindowId, aListener);
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationService::UnregisterRespondingListener(uint64_t aWindowId)
-{
- PRES_DEBUG("%s:windowId[%lld]\n", __func__, aWindowId);
-
- MOZ_ASSERT(NS_IsMainThread());
-
- mRespondingListeners.Remove(aWindowId);
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationService::NotifyReceiverReady(
- const nsAString& aSessionId,
- uint64_t aWindowId,
- bool aIsLoading,
- nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
-{
- PRES_DEBUG("%s:id[%s], windowId[%lld], loading[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(aSessionId).get(), aWindowId, aIsLoading);
-
- RefPtr<PresentationSessionInfo> info =
- GetSessionInfo(aSessionId, nsIPresentationService::ROLE_RECEIVER);
- if (NS_WARN_IF(!info)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- AddRespondingSessionId(aWindowId,
- aSessionId,
- nsIPresentationService::ROLE_RECEIVER);
-
- if (!aIsLoading) {
- return static_cast<PresentationPresentingInfo*>(
- info.get())->NotifyResponderFailure();
- }
-
- nsCOMPtr<nsIPresentationRespondingListener> listener;
- if (mRespondingListeners.Get(aWindowId, getter_AddRefs(listener))) {
- nsresult rv = listener->NotifySessionConnect(aWindowId, aSessionId);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- }
-
- info->SetTransportBuilderConstructor(aBuilderConstructor);
- return static_cast<PresentationPresentingInfo*>(info.get())->NotifyResponderReady();
-}
-
-nsresult
-PresentationService::NotifyTransportClosed(const nsAString& aSessionId,
- uint8_t aRole,
- nsresult aReason)
-{
- PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(aSessionId).get(), aReason, aRole);
-
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!aSessionId.IsEmpty());
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
- if (NS_WARN_IF(!info)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return info->NotifyTransportClosed(aReason);
-}
-
-NS_IMETHODIMP
-PresentationService::UntrackSessionInfo(const nsAString& aSessionId,
- uint8_t aRole)
-{
- PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);
-
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
- // Remove the session info.
- if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
- mSessionInfoAtController.Remove(aSessionId);
- } else {
- // Terminate receiver page.
- uint64_t windowId;
- nsresult rv = GetWindowIdBySessionIdInternal(aSessionId, aRole, &windowId);
- if (NS_SUCCEEDED(rv)) {
- NS_DispatchToMainThread(NS_NewRunnableFunction([windowId]() -> void {
- PRES_DEBUG("Attempt to close window[%d]\n", windowId);
-
- if (auto* window = nsGlobalWindow::GetInnerWindowWithId(windowId)) {
- window->Close();
- }
- }));
- }
-
- mSessionInfoAtReceiver.Remove(aSessionId);
- }
-
- // Remove the in-process responding info if there's still any.
- RemoveRespondingSessionId(aSessionId, aRole);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationService::GetWindowIdBySessionId(const nsAString& aSessionId,
- uint8_t aRole,
- uint64_t* aWindowId)
-{
- return GetWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId);
-}
-
-NS_IMETHODIMP
-PresentationService::UpdateWindowIdBySessionId(const nsAString& aSessionId,
- uint8_t aRole,
- const uint64_t aWindowId)
-{
- return UpdateWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId);
-}
-
-bool
-PresentationService::IsSessionAccessible(const nsAString& aSessionId,
- const uint8_t aRole,
- base::ProcessId aProcessId)
-{
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
- RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
- if (NS_WARN_IF(!info)) {
- return false;
- }
- return info->IsAccessible(aProcessId);
-}
-
-} // namespace dom
-} // namespace mozilla
-
-already_AddRefed<nsIPresentationService>
-NS_CreatePresentationService()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- nsCOMPtr<nsIPresentationService> service;
- if (XRE_GetProcessType() == GeckoProcessType_Content) {
- service = new mozilla::dom::PresentationIPCService();
- } else {
- service = new PresentationService();
- if (NS_WARN_IF(!static_cast<PresentationService*>(service.get())->Init())) {
- return nullptr;
- }
- }
-
- return service.forget();
-}
diff --git a/dom/presentation/PresentationService.h b/dom/presentation/PresentationService.h
deleted file mode 100644
index b2d39e691..000000000
--- a/dom/presentation/PresentationService.h
+++ /dev/null
@@ -1,68 +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_PresentationService_h
-#define mozilla_dom_PresentationService_h
-
-#include "nsCOMPtr.h"
-#include "nsIObserver.h"
-#include "PresentationServiceBase.h"
-#include "PresentationSessionInfo.h"
-
-class nsIPresentationSessionRequest;
-class nsIPresentationTerminateRequest;
-class nsIURI;
-class nsIPresentationSessionTransportBuilder;
-
-namespace mozilla {
-namespace dom {
-
-class PresentationDeviceRequest;
-class PresentationRespondingInfo;
-
-class PresentationService final
- : public nsIPresentationService
- , public nsIObserver
- , public PresentationServiceBase<PresentationSessionInfo>
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIOBSERVER
- NS_DECL_NSIPRESENTATIONSERVICE
-
- PresentationService();
- bool Init();
-
- bool IsSessionAccessible(const nsAString& aSessionId,
- const uint8_t aRole,
- base::ProcessId aProcessId);
-
-private:
- friend class PresentationDeviceRequest;
-
- virtual ~PresentationService();
- void HandleShutdown();
- nsresult HandleDeviceAdded(nsIPresentationDevice* aDevice);
- nsresult HandleDeviceRemoved();
- nsresult HandleSessionRequest(nsIPresentationSessionRequest* aRequest);
- nsresult HandleTerminateRequest(nsIPresentationTerminateRequest* aRequest);
- nsresult HandleReconnectRequest(nsIPresentationSessionRequest* aRequest);
-
- // This is meant to be called by PresentationDeviceRequest.
- already_AddRefed<PresentationSessionInfo>
- CreateControllingSessionInfo(const nsAString& aUrl,
- const nsAString& aSessionId,
- uint64_t aWindowId);
-
- // Emumerate all devices to get the availability of each input Urls.
- nsresult UpdateAvailabilityUrlChange(
- const nsTArray<nsString>& aAvailabilityUrls);
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationService_h
diff --git a/dom/presentation/PresentationServiceBase.h b/dom/presentation/PresentationServiceBase.h
deleted file mode 100644
index 227e95430..000000000
--- a/dom/presentation/PresentationServiceBase.h
+++ /dev/null
@@ -1,401 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=8 et 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/. */
-
-#ifndef mozilla_dom_PresentationServiceBase_h
-#define mozilla_dom_PresentationServiceBase_h
-
-#include "mozilla/Unused.h"
-#include "nsClassHashtable.h"
-#include "nsCOMArray.h"
-#include "nsIPresentationListener.h"
-#include "nsIPresentationService.h"
-#include "nsRefPtrHashtable.h"
-#include "nsString.h"
-#include "nsTArray.h"
-
-namespace mozilla {
-namespace dom {
-
-template<class T>
-class PresentationServiceBase
-{
-public:
- PresentationServiceBase() = default;
-
- already_AddRefed<T>
- GetSessionInfo(const nsAString& aSessionId, const uint8_t aRole)
- {
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- RefPtr<T> info;
- if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
- return mSessionInfoAtController.Get(aSessionId, getter_AddRefs(info)) ?
- info.forget() : nullptr;
- } else {
- return mSessionInfoAtReceiver.Get(aSessionId, getter_AddRefs(info)) ?
- info.forget() : nullptr;
- }
- }
-
-protected:
- class SessionIdManager final
- {
- public:
- explicit SessionIdManager()
- {
- MOZ_COUNT_CTOR(SessionIdManager);
- }
-
- ~SessionIdManager()
- {
- MOZ_COUNT_DTOR(SessionIdManager);
- }
-
- nsresult GetWindowId(const nsAString& aSessionId, uint64_t* aWindowId)
- {
- MOZ_ASSERT(NS_IsMainThread());
-
- if (mRespondingWindowIds.Get(aSessionId, aWindowId)) {
- return NS_OK;
- }
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- nsresult GetSessionIds(uint64_t aWindowId, nsTArray<nsString>& aSessionIds)
- {
- MOZ_ASSERT(NS_IsMainThread());
-
- nsTArray<nsString>* sessionIdArray;
- if (!mRespondingSessionIds.Get(aWindowId, &sessionIdArray)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- aSessionIds.Assign(*sessionIdArray);
- return NS_OK;
- }
-
- void AddSessionId(uint64_t aWindowId, const nsAString& aSessionId)
- {
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(aWindowId == 0)) {
- return;
- }
-
- nsTArray<nsString>* sessionIdArray;
- if (!mRespondingSessionIds.Get(aWindowId, &sessionIdArray)) {
- sessionIdArray = new nsTArray<nsString>();
- mRespondingSessionIds.Put(aWindowId, sessionIdArray);
- }
-
- sessionIdArray->AppendElement(nsString(aSessionId));
- mRespondingWindowIds.Put(aSessionId, aWindowId);
- }
-
- void RemoveSessionId(const nsAString& aSessionId)
- {
- MOZ_ASSERT(NS_IsMainThread());
-
- uint64_t windowId = 0;
- if (mRespondingWindowIds.Get(aSessionId, &windowId)) {
- mRespondingWindowIds.Remove(aSessionId);
- nsTArray<nsString>* sessionIdArray;
- if (mRespondingSessionIds.Get(windowId, &sessionIdArray)) {
- sessionIdArray->RemoveElement(nsString(aSessionId));
- if (sessionIdArray->IsEmpty()) {
- mRespondingSessionIds.Remove(windowId);
- }
- }
- }
- }
-
- nsresult UpdateWindowId(const nsAString& aSessionId, const uint64_t aWindowId)
- {
- MOZ_ASSERT(NS_IsMainThread());
-
- RemoveSessionId(aSessionId);
- AddSessionId(aWindowId, aSessionId);
- return NS_OK;
- }
-
- void Clear()
- {
- mRespondingSessionIds.Clear();
- mRespondingWindowIds.Clear();
- }
-
- private:
- nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mRespondingSessionIds;
- nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
- };
-
- class AvailabilityManager final
- {
- public:
- explicit AvailabilityManager()
- {
- MOZ_COUNT_CTOR(AvailabilityManager);
- }
-
- ~AvailabilityManager()
- {
- MOZ_COUNT_DTOR(AvailabilityManager);
- }
-
- void AddAvailabilityListener(
- const nsTArray<nsString>& aAvailabilityUrls,
- nsIPresentationAvailabilityListener* aListener)
- {
- nsTArray<nsString> dummy;
- AddAvailabilityListener(aAvailabilityUrls, aListener, dummy);
- }
-
- void AddAvailabilityListener(
- const nsTArray<nsString>& aAvailabilityUrls,
- nsIPresentationAvailabilityListener* aListener,
- nsTArray<nsString>& aAddedUrls)
- {
- if (!aListener) {
- MOZ_ASSERT(false, "aListener should not be null.");
- return;
- }
-
- if (aAvailabilityUrls.IsEmpty()) {
- MOZ_ASSERT(false, "aAvailabilityUrls should not be empty.");
- return;
- }
-
- aAddedUrls.Clear();
- nsTArray<nsString> knownAvailableUrls;
- for (const auto& url : aAvailabilityUrls) {
- AvailabilityEntry* entry;
- if (!mAvailabilityUrlTable.Get(url, &entry)) {
- entry = new AvailabilityEntry();
- mAvailabilityUrlTable.Put(url, entry);
- aAddedUrls.AppendElement(url);
- }
- if (!entry->mListeners.Contains(aListener)) {
- entry->mListeners.AppendElement(aListener);
- }
- if (entry->mAvailable) {
- knownAvailableUrls.AppendElement(url);
- }
- }
-
- if (!knownAvailableUrls.IsEmpty()) {
- Unused <<
- NS_WARN_IF(
- NS_FAILED(aListener->NotifyAvailableChange(knownAvailableUrls,
- true)));
- } else {
- // If we can't find any known available url and there is no newly
- // added url, we still need to notify the listener of the result.
- // So, the promise returned by |getAvailability| can be resolved.
- if (aAddedUrls.IsEmpty()) {
- Unused <<
- NS_WARN_IF(
- NS_FAILED(aListener->NotifyAvailableChange(aAvailabilityUrls,
- false)));
- }
- }
- }
-
- void RemoveAvailabilityListener(
- const nsTArray<nsString>& aAvailabilityUrls,
- nsIPresentationAvailabilityListener* aListener)
- {
- nsTArray<nsString> dummy;
- RemoveAvailabilityListener(aAvailabilityUrls, aListener, dummy);
- }
-
- void RemoveAvailabilityListener(
- const nsTArray<nsString>& aAvailabilityUrls,
- nsIPresentationAvailabilityListener* aListener,
- nsTArray<nsString>& aRemovedUrls)
- {
- if (!aListener) {
- MOZ_ASSERT(false, "aListener should not be null.");
- return;
- }
-
- if (aAvailabilityUrls.IsEmpty()) {
- MOZ_ASSERT(false, "aAvailabilityUrls should not be empty.");
- return;
- }
-
- aRemovedUrls.Clear();
- for (const auto& url : aAvailabilityUrls) {
- AvailabilityEntry* entry;
- if (mAvailabilityUrlTable.Get(url, &entry)) {
- entry->mListeners.RemoveElement(aListener);
- if (entry->mListeners.IsEmpty()) {
- mAvailabilityUrlTable.Remove(url);
- aRemovedUrls.AppendElement(url);
- }
- }
- }
- }
-
- nsresult DoNotifyAvailableChange(const nsTArray<nsString>& aAvailabilityUrls,
- bool aAvailable)
- {
- typedef nsClassHashtable<nsISupportsHashKey,
- nsTArray<nsString>> ListenerToUrlsMap;
- ListenerToUrlsMap availabilityListenerTable;
- // Create a mapping from nsIPresentationAvailabilityListener to
- // availabilityUrls.
- for (auto it = mAvailabilityUrlTable.ConstIter(); !it.Done(); it.Next()) {
- if (aAvailabilityUrls.Contains(it.Key())) {
- AvailabilityEntry* entry = it.UserData();
- entry->mAvailable = aAvailable;
-
- for (uint32_t i = 0; i < entry->mListeners.Length(); ++i) {
- nsIPresentationAvailabilityListener* listener =
- entry->mListeners.ObjectAt(i);
- nsTArray<nsString>* urlArray;
- if (!availabilityListenerTable.Get(listener, &urlArray)) {
- urlArray = new nsTArray<nsString>();
- availabilityListenerTable.Put(listener, urlArray);
- }
- urlArray->AppendElement(it.Key());
- }
- }
- }
-
- for (auto it = availabilityListenerTable.Iter(); !it.Done(); it.Next()) {
- auto listener =
- static_cast<nsIPresentationAvailabilityListener*>(it.Key());
-
- Unused <<
- NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(*it.UserData(),
- aAvailable)));
- }
- return NS_OK;
- }
-
- void GetAvailbilityUrlByAvailability(nsTArray<nsString>& aOutArray,
- bool aAvailable)
- {
- aOutArray.Clear();
-
- for (auto it = mAvailabilityUrlTable.ConstIter(); !it.Done(); it.Next()) {
- if (it.UserData()->mAvailable == aAvailable) {
- aOutArray.AppendElement(it.Key());
- }
- }
- }
-
- void Clear()
- {
- mAvailabilityUrlTable.Clear();
- }
-
- private:
- struct AvailabilityEntry
- {
- explicit AvailabilityEntry()
- : mAvailable(false)
- {}
-
- bool mAvailable;
- nsCOMArray<nsIPresentationAvailabilityListener> mListeners;
- };
-
- nsClassHashtable<nsStringHashKey, AvailabilityEntry> mAvailabilityUrlTable;
- };
-
- virtual ~PresentationServiceBase() = default;
-
- void Shutdown()
- {
- mRespondingListeners.Clear();
- mControllerSessionIdManager.Clear();
- mReceiverSessionIdManager.Clear();
- }
-
- nsresult GetWindowIdBySessionIdInternal(const nsAString& aSessionId,
- uint8_t aRole,
- uint64_t* aWindowId)
- {
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- if (NS_WARN_IF(!aWindowId)) {
- return NS_ERROR_INVALID_POINTER;
- }
-
- if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
- return mControllerSessionIdManager.GetWindowId(aSessionId, aWindowId);
- }
-
- return mReceiverSessionIdManager.GetWindowId(aSessionId, aWindowId);
- }
-
- void AddRespondingSessionId(uint64_t aWindowId,
- const nsAString& aSessionId,
- uint8_t aRole)
- {
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
- mControllerSessionIdManager.AddSessionId(aWindowId, aSessionId);
- } else {
- mReceiverSessionIdManager.AddSessionId(aWindowId, aSessionId);
- }
- }
-
- void RemoveRespondingSessionId(const nsAString& aSessionId,
- uint8_t aRole)
- {
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
- mControllerSessionIdManager.RemoveSessionId(aSessionId);
- } else {
- mReceiverSessionIdManager.RemoveSessionId(aSessionId);
- }
- }
-
- nsresult UpdateWindowIdBySessionIdInternal(const nsAString& aSessionId,
- uint8_t aRole,
- const uint64_t aWindowId)
- {
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
- return mControllerSessionIdManager.UpdateWindowId(aSessionId, aWindowId);
- }
-
- return mReceiverSessionIdManager.UpdateWindowId(aSessionId, aWindowId);
- }
-
- // Store the responding listener based on the window ID of the (in-process or
- // OOP) receiver page.
- nsRefPtrHashtable<nsUint64HashKey, nsIPresentationRespondingListener>
- mRespondingListeners;
-
- // Store the mapping between the window ID of the in-process and OOP page and the ID
- // of the responding session. It's used for both controller and receiver page
- // to retrieve the correspondent session ID. Besides, also keep the mapping
- // between the responding session ID and the window ID to help look up the
- // window ID.
- SessionIdManager mControllerSessionIdManager;
- SessionIdManager mReceiverSessionIdManager;
-
- nsRefPtrHashtable<nsStringHashKey, T> mSessionInfoAtController;
- nsRefPtrHashtable<nsStringHashKey, T> mSessionInfoAtReceiver;
-
- AvailabilityManager mAvailabilityManager;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationServiceBase_h
diff --git a/dom/presentation/PresentationSessionInfo.cpp b/dom/presentation/PresentationSessionInfo.cpp
deleted file mode 100644
index 1dd92ab69..000000000
--- a/dom/presentation/PresentationSessionInfo.cpp
+++ /dev/null
@@ -1,1617 +0,0 @@
-/* -*- 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/. */
-
-#include "mozilla/dom/ContentParent.h"
-#include "mozilla/dom/HTMLIFrameElementBinding.h"
-#include "mozilla/dom/TabParent.h"
-#include "mozilla/Function.h"
-#include "mozilla/Logging.h"
-#include "mozilla/Move.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/Services.h"
-#include "nsContentUtils.h"
-#include "nsGlobalWindow.h"
-#include "nsIDocShell.h"
-#include "nsFrameLoader.h"
-#include "nsIMutableArray.h"
-#include "nsINetAddr.h"
-#include "nsISocketTransport.h"
-#include "nsISupportsPrimitives.h"
-#include "nsNetCID.h"
-#include "nsServiceManagerUtils.h"
-#include "nsThreadUtils.h"
-#include "PresentationLog.h"
-#include "PresentationService.h"
-#include "PresentationSessionInfo.h"
-
-#ifdef MOZ_WIDGET_ANDROID
-#include "nsIPresentationNetworkHelper.h"
-#endif // MOZ_WIDGET_ANDROID
-
-using namespace mozilla;
-using namespace mozilla::dom;
-using namespace mozilla::services;
-
-/*
- * Implementation of PresentationChannelDescription
- */
-
-namespace mozilla {
-namespace dom {
-
-#ifdef MOZ_WIDGET_ANDROID
-
-namespace {
-
-class PresentationNetworkHelper final : public nsIPresentationNetworkHelperListener
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONNETWORKHELPERLISTENER
-
- using Function = nsresult(PresentationControllingInfo::*)(const nsACString&);
-
- explicit PresentationNetworkHelper(PresentationControllingInfo* aInfo,
- const Function& aFunc);
-
- nsresult GetWifiIPAddress();
-
-private:
- ~PresentationNetworkHelper() = default;
-
- RefPtr<PresentationControllingInfo> mInfo;
- Function mFunc;
-};
-
-NS_IMPL_ISUPPORTS(PresentationNetworkHelper,
- nsIPresentationNetworkHelperListener)
-
-PresentationNetworkHelper::PresentationNetworkHelper(PresentationControllingInfo* aInfo,
- const Function& aFunc)
- : mInfo(aInfo)
- , mFunc(aFunc)
-{
- MOZ_ASSERT(aInfo);
- MOZ_ASSERT(aFunc);
-}
-
-nsresult
-PresentationNetworkHelper::GetWifiIPAddress()
-{
- nsresult rv;
-
- nsCOMPtr<nsIPresentationNetworkHelper> networkHelper =
- do_GetService(PRESENTATION_NETWORK_HELPER_CONTRACTID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return networkHelper->GetWifiIPAddress(this);
-}
-
-NS_IMETHODIMP
-PresentationNetworkHelper::OnError(const nsACString & aReason)
-{
- PRES_ERROR("PresentationNetworkHelper::OnError: %s",
- nsPromiseFlatCString(aReason).get());
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationNetworkHelper::OnGetWifiIPAddress(const nsACString& aIPAddress)
-{
- MOZ_ASSERT(mInfo);
- MOZ_ASSERT(mFunc);
-
- NS_DispatchToMainThread(
- NewRunnableMethod<nsCString>(mInfo,
- mFunc,
- aIPAddress));
- return NS_OK;
-}
-
-} // anonymous namespace
-
-#endif // MOZ_WIDGET_ANDROID
-
-class TCPPresentationChannelDescription final : public nsIPresentationChannelDescription
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONCHANNELDESCRIPTION
-
- TCPPresentationChannelDescription(const nsACString& aAddress,
- uint16_t aPort)
- : mAddress(aAddress)
- , mPort(aPort)
- {
- }
-
-private:
- ~TCPPresentationChannelDescription() {}
-
- nsCString mAddress;
- uint16_t mPort;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-NS_IMPL_ISUPPORTS(TCPPresentationChannelDescription, nsIPresentationChannelDescription)
-
-NS_IMETHODIMP
-TCPPresentationChannelDescription::GetType(uint8_t* aRetVal)
-{
- if (NS_WARN_IF(!aRetVal)) {
- return NS_ERROR_INVALID_POINTER;
- }
-
- *aRetVal = nsIPresentationChannelDescription::TYPE_TCP;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-TCPPresentationChannelDescription::GetTcpAddress(nsIArray** aRetVal)
-{
- if (NS_WARN_IF(!aRetVal)) {
- return NS_ERROR_INVALID_POINTER;
- }
-
- nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
- if (NS_WARN_IF(!array)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
- // TODO bug 1228504 Take all IP addresses in PresentationChannelDescription
- // into account. And at the first stage Presentation API is only exposed on
- // Firefox OS where the first IP appears enough for most scenarios.
- nsCOMPtr<nsISupportsCString> address = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
- if (NS_WARN_IF(!address)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- address->SetData(mAddress);
-
- array->AppendElement(address, false);
- array.forget(aRetVal);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-TCPPresentationChannelDescription::GetTcpPort(uint16_t* aRetVal)
-{
- if (NS_WARN_IF(!aRetVal)) {
- return NS_ERROR_INVALID_POINTER;
- }
-
- *aRetVal = mPort;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-TCPPresentationChannelDescription::GetDataChannelSDP(nsAString& aDataChannelSDP)
-{
- aDataChannelSDP.Truncate();
- return NS_OK;
-}
-
-/*
- * Implementation of PresentationSessionInfo
- */
-
-NS_IMPL_ISUPPORTS(PresentationSessionInfo,
- nsIPresentationSessionTransportCallback,
- nsIPresentationControlChannelListener,
- nsIPresentationSessionTransportBuilderListener);
-
-/* virtual */ nsresult
-PresentationSessionInfo::Init(nsIPresentationControlChannel* aControlChannel)
-{
- SetControlChannel(aControlChannel);
- return NS_OK;
-}
-
-/* virtual */ void
-PresentationSessionInfo::Shutdown(nsresult aReason)
-{
- PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), aReason, mRole);
-
- NS_WARNING_ASSERTION(NS_SUCCEEDED(aReason), "bad reason");
-
- // Close the control channel if any.
- if (mControlChannel) {
- Unused << NS_WARN_IF(NS_FAILED(mControlChannel->Disconnect(aReason)));
- }
-
- // Close the data transport channel if any.
- if (mTransport) {
- // |mIsTransportReady| will be unset once |NotifyTransportClosed| is called.
- Unused << NS_WARN_IF(NS_FAILED(mTransport->Close(aReason)));
- }
-
- mIsResponderReady = false;
- mIsOnTerminating = false;
-
- ResetBuilder();
-}
-
-nsresult
-PresentationSessionInfo::SetListener(nsIPresentationSessionListener* aListener)
-{
- mListener = aListener;
-
- if (mListener) {
- // Enable data notification for the transport channel if it's available.
- if (mTransport) {
- nsresult rv = mTransport->EnableDataNotification();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- }
-
- // The transport might become ready, or might become un-ready again, before
- // the listener has registered. So notify the listener of the state change.
- return mListener->NotifyStateChange(mSessionId, mState, mReason);
- }
-
- return NS_OK;
-}
-
-nsresult
-PresentationSessionInfo::Send(const nsAString& aData)
-{
- if (NS_WARN_IF(!IsSessionReady())) {
- return NS_ERROR_DOM_INVALID_STATE_ERR;
- }
-
- if (NS_WARN_IF(!mTransport)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return mTransport->Send(aData);
-}
-
-nsresult
-PresentationSessionInfo::SendBinaryMsg(const nsACString& aData)
-{
- if (NS_WARN_IF(!IsSessionReady())) {
- return NS_ERROR_DOM_INVALID_STATE_ERR;
- }
-
- if (NS_WARN_IF(!mTransport)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return mTransport->SendBinaryMsg(aData);
-}
-
-nsresult
-PresentationSessionInfo::SendBlob(nsIDOMBlob* aBlob)
-{
- if (NS_WARN_IF(!IsSessionReady())) {
- return NS_ERROR_DOM_INVALID_STATE_ERR;
- }
-
- if (NS_WARN_IF(!mTransport)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return mTransport->SendBlob(aBlob);
-}
-
-nsresult
-PresentationSessionInfo::Close(nsresult aReason,
- uint32_t aState)
-{
- // Do nothing if session is already terminated.
- if (nsIPresentationSessionListener::STATE_TERMINATED == mState) {
- return NS_OK;
- }
-
- SetStateWithReason(aState, aReason);
-
- switch (aState) {
- case nsIPresentationSessionListener::STATE_CLOSED: {
- Shutdown(aReason);
- break;
- }
- case nsIPresentationSessionListener::STATE_TERMINATED: {
- if (!mControlChannel) {
- nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
- nsresult rv = mDevice->EstablishControlChannel(getter_AddRefs(ctrlChannel));
- if (NS_FAILED(rv)) {
- Shutdown(rv);
- return rv;
- }
-
- SetControlChannel(ctrlChannel);
- return rv;
- }
-
- ContinueTermination();
- return NS_OK;
- }
- }
-
- return NS_OK;
-}
-
-nsresult
-PresentationSessionInfo::OnTerminate(nsIPresentationControlChannel* aControlChannel)
-{
- mIsOnTerminating = true; // Mark for terminating transport channel
- SetStateWithReason(nsIPresentationSessionListener::STATE_TERMINATED, NS_OK);
- SetControlChannel(aControlChannel);
-
- return NS_OK;
-}
-
-nsresult
-PresentationSessionInfo::ReplySuccess()
-{
- SetStateWithReason(nsIPresentationSessionListener::STATE_CONNECTED, NS_OK);
- return NS_OK;
-}
-
-nsresult
-PresentationSessionInfo::ReplyError(nsresult aError)
-{
- Shutdown(aError);
-
- // Remove itself since it never succeeds.
- return UntrackFromService();
-}
-
-/* virtual */ nsresult
-PresentationSessionInfo::UntrackFromService()
-{
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- static_cast<PresentationService*>(service.get())->UntrackSessionInfo(mSessionId, mRole);
-
- return NS_OK;
-}
-
-nsPIDOMWindowInner*
-PresentationSessionInfo::GetWindow()
-{
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return nullptr;
- }
- uint64_t windowId = 0;
- if (NS_WARN_IF(NS_FAILED(service->GetWindowIdBySessionId(mSessionId,
- mRole,
- &windowId)))) {
- return nullptr;
- }
-
- auto window = nsGlobalWindow::GetInnerWindowWithId(windowId);
- if (!window) {
- return nullptr;
- }
-
- return window->AsInner();
-}
-
-/* virtual */ bool
-PresentationSessionInfo::IsAccessible(base::ProcessId aProcessId)
-{
- // No restriction by default.
- return true;
-}
-
-void
-PresentationSessionInfo::ContinueTermination()
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mControlChannel);
-
- if (NS_WARN_IF(NS_FAILED(mControlChannel->Terminate(mSessionId)))
- || mIsOnTerminating) {
- Shutdown(NS_OK);
- }
-}
-
-// nsIPresentationSessionTransportCallback
-NS_IMETHODIMP
-PresentationSessionInfo::NotifyTransportReady()
-{
- PRES_DEBUG("%s:id[%s], role[%d], state[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), mRole, mState);
-
- MOZ_ASSERT(NS_IsMainThread());
-
- if (mState != nsIPresentationSessionListener::STATE_CONNECTING &&
- mState != nsIPresentationSessionListener::STATE_CONNECTED) {
- return NS_OK;
- }
-
- mIsTransportReady = true;
-
- // Established RTCDataChannel implies responder is ready.
- if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
- mIsResponderReady = true;
- }
-
- // At sender side, session might not be ready at this point (waiting for
- // receiver's answer). Yet at receiver side, session must be ready at this
- // point since the data transport channel is created after the receiver page
- // is ready for presentation use.
- if (IsSessionReady()) {
- return ReplySuccess();
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationSessionInfo::NotifyTransportClosed(nsresult aReason)
-{
- PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), aReason, mRole);
-
- MOZ_ASSERT(NS_IsMainThread());
-
- // Nullify |mTransport| here so it won't try to re-close |mTransport| in
- // potential subsequent |Shutdown| calls.
- mTransport = nullptr;
-
- if (NS_WARN_IF(!IsSessionReady() &&
- mState == nsIPresentationSessionListener::STATE_CONNECTING)) {
- // It happens before the session is ready. Reply the callback.
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- // Unset |mIsTransportReady| here so it won't affect |IsSessionReady()| above.
- mIsTransportReady = false;
-
- if (mState == nsIPresentationSessionListener::STATE_CONNECTED) {
- // The transport channel is closed unexpectedly (not caused by a |Close| call).
- SetStateWithReason(nsIPresentationSessionListener::STATE_CLOSED, aReason);
- }
-
- Shutdown(aReason);
-
- if (mState == nsIPresentationSessionListener::STATE_TERMINATED) {
- // Directly untrack the session info from the service.
- return UntrackFromService();
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationSessionInfo::NotifyData(const nsACString& aData, bool aIsBinary)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!IsSessionReady())) {
- return NS_ERROR_DOM_INVALID_STATE_ERR;
- }
-
- if (NS_WARN_IF(!mListener)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return mListener->NotifyMessage(mSessionId, aData, aIsBinary);
-}
-
-// nsIPresentationSessionTransportBuilderListener
-NS_IMETHODIMP
-PresentationSessionInfo::OnSessionTransport(nsIPresentationSessionTransport* aTransport)
-{
- PRES_DEBUG("%s:id[%s], role[%d], state[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), mRole, mState);
-
- ResetBuilder();
-
- if (mState != nsIPresentationSessionListener::STATE_CONNECTING) {
- return NS_ERROR_FAILURE;
- }
-
- if (NS_WARN_IF(!aTransport)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- mTransport = aTransport;
-
- nsresult rv = mTransport->SetCallback(this);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- if (mListener) {
- mTransport->EnableDataNotification();
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationSessionInfo::OnError(nsresult aReason)
-{
- PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), aReason, mRole);
-
- ResetBuilder();
- return ReplyError(aReason);
-}
-
-NS_IMETHODIMP
-PresentationSessionInfo::SendOffer(nsIPresentationChannelDescription* aOffer)
-{
- return mControlChannel->SendOffer(aOffer);
-}
-
-NS_IMETHODIMP
-PresentationSessionInfo::SendAnswer(nsIPresentationChannelDescription* aAnswer)
-{
- return mControlChannel->SendAnswer(aAnswer);
-}
-
-NS_IMETHODIMP
-PresentationSessionInfo::SendIceCandidate(const nsAString& candidate)
-{
- return mControlChannel->SendIceCandidate(candidate);
-}
-
-NS_IMETHODIMP
-PresentationSessionInfo::Close(nsresult reason)
-{
- return mControlChannel->Disconnect(reason);
-}
-
-/**
- * Implementation of PresentationControllingInfo
- *
- * During presentation session establishment, the sender expects the following
- * after trying to establish the control channel: (The order between step 3 and
- * 4 is not guaranteed.)
- * 1. |Init| is called to open a socket |mServerSocket| for data transport
- * channel.
- * 2. |NotifyConnected| of |nsIPresentationControlChannelListener| is called to
- * indicate the control channel is ready to use. Then send the offer to the
- * receiver via the control channel.
- * 3.1 |OnSocketAccepted| of |nsIServerSocketListener| is called to indicate the
- * data transport channel is connected. Then initialize |mTransport|.
- * 3.2 |NotifyTransportReady| of |nsIPresentationSessionTransportCallback| is
- * called.
- * 4. |OnAnswer| of |nsIPresentationControlChannelListener| is called to
- * indicate the receiver is ready. Close the control channel since it's no
- * longer needed.
- * 5. Once both step 3 and 4 are done, the presentation session is ready to use.
- * So notify the listener of CONNECTED state.
- */
-
-NS_IMPL_ISUPPORTS_INHERITED(PresentationControllingInfo,
- PresentationSessionInfo,
- nsIServerSocketListener)
-
-nsresult
-PresentationControllingInfo::Init(nsIPresentationControlChannel* aControlChannel)
-{
- PresentationSessionInfo::Init(aControlChannel);
-
- // Initialize |mServerSocket| for bootstrapping the data transport channel and
- // use |this| as the listener.
- mServerSocket = do_CreateInstance(NS_SERVERSOCKET_CONTRACTID);
- if (NS_WARN_IF(!mServerSocket)) {
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- nsresult rv = mServerSocket->Init(-1, false, -1);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = mServerSocket->AsyncListen(this);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- int32_t port;
- rv = mServerSocket->GetPort(&port);
- if (!NS_WARN_IF(NS_FAILED(rv))) {
- PRES_DEBUG("%s:ServerSocket created.port[%d]\n",__func__, port);
- }
-
- return NS_OK;
-}
-
-void
-PresentationControllingInfo::Shutdown(nsresult aReason)
-{
- PresentationSessionInfo::Shutdown(aReason);
-
- // Close the server socket if any.
- if (mServerSocket) {
- Unused << NS_WARN_IF(NS_FAILED(mServerSocket->Close()));
- mServerSocket = nullptr;
- }
-}
-
-nsresult
-PresentationControllingInfo::GetAddress()
-{
-#if defined(MOZ_WIDGET_ANDROID)
- RefPtr<PresentationNetworkHelper> networkHelper =
- new PresentationNetworkHelper(this,
- &PresentationControllingInfo::OnGetAddress);
- nsresult rv = networkHelper->GetWifiIPAddress();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
-#else
- nsCOMPtr<nsINetworkInfoService> networkInfo = do_GetService(NETWORKINFOSERVICE_CONTRACT_ID);
- MOZ_ASSERT(networkInfo);
-
- nsresult rv = networkInfo->ListNetworkAddresses(this);
-
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-#endif
-
- return NS_OK;
-}
-
-nsresult
-PresentationControllingInfo::OnGetAddress(const nsACString& aAddress)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!mServerSocket)) {
- return NS_ERROR_FAILURE;
- }
- if (NS_WARN_IF(!mControlChannel)) {
- return NS_ERROR_FAILURE;
- }
-
- // Prepare and send the offer.
- int32_t port;
- nsresult rv = mServerSocket->GetPort(&port);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- RefPtr<TCPPresentationChannelDescription> description =
- new TCPPresentationChannelDescription(aAddress, static_cast<uint16_t>(port));
- return mControlChannel->SendOffer(description);
-}
-
-// nsIPresentationControlChannelListener
-NS_IMETHODIMP
-PresentationControllingInfo::OnIceCandidate(const nsAString& aCandidate)
-{
- if (mTransportType != nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
- return NS_ERROR_FAILURE;
- }
-
- nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
- builder = do_QueryInterface(mBuilder);
-
- if (NS_WARN_IF(!builder)) {
- return NS_ERROR_FAILURE;
- }
-
- return builder->OnIceCandidate(aCandidate);
-}
-
-NS_IMETHODIMP
-PresentationControllingInfo::OnOffer(nsIPresentationChannelDescription* aDescription)
-{
- MOZ_ASSERT(false, "Sender side should not receive offer.");
- return NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP
-PresentationControllingInfo::OnAnswer(nsIPresentationChannelDescription* aDescription)
-{
- if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
- nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
- builder = do_QueryInterface(mBuilder);
-
- if (NS_WARN_IF(!builder)) {
- return NS_ERROR_FAILURE;
- }
-
- return builder->OnAnswer(aDescription);
- }
-
- mIsResponderReady = true;
-
- // Close the control channel since it's no longer needed.
- nsresult rv = mControlChannel->Disconnect(NS_OK);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- // Session might not be ready at this moment (waiting for the establishment of
- // the data transport channel).
- if (IsSessionReady()){
- return ReplySuccess();
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationControllingInfo::NotifyConnected()
-{
- PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
-
- MOZ_ASSERT(NS_IsMainThread());
-
- switch (mState) {
- case nsIPresentationSessionListener::STATE_CONNECTING: {
- if (mIsReconnecting) {
- return ContinueReconnect();
- }
-
- nsresult rv = mControlChannel->Launch(GetSessionId(), GetUrl());
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- Unused << NS_WARN_IF(NS_FAILED(BuildTransport()));
- break;
- }
- case nsIPresentationSessionListener::STATE_TERMINATED: {
- ContinueTermination();
- break;
- }
- default:
- break;
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationControllingInfo::NotifyReconnected()
-{
- PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
-
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(mState != nsIPresentationSessionListener::STATE_CONNECTING)) {
- return NS_ERROR_FAILURE;
- }
-
- return NotifyReconnectResult(NS_OK);
-}
-
-nsresult
-PresentationControllingInfo::BuildTransport()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (mState != nsIPresentationSessionListener::STATE_CONNECTING) {
- return NS_OK;
- }
-
- if (NS_WARN_IF(!mBuilderConstructor)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- if (!Preferences::GetBool("dom.presentation.session_transport.data_channel.enable")) {
- // Build TCP session transport
- return GetAddress();
- }
- /**
- * Generally transport is maintained by the chrome process. However, data
- * channel should be live with the DOM , which implies RTCDataChannel in an OOP
- * page should be establish in the content process.
- *
- * |mBuilderConstructor| is responsible for creating a builder, which is for
- * building a data channel transport.
- *
- * In the OOP case, |mBuilderConstructor| would create a builder which is
- * an object of |PresentationBuilderParent|. So, |BuildDataChannelTransport|
- * triggers an IPC call to make content process establish a RTCDataChannel
- * transport.
- */
-
- mTransportType = nsIPresentationChannelDescription::TYPE_DATACHANNEL;
- if (NS_WARN_IF(NS_FAILED(
- mBuilderConstructor->CreateTransportBuilder(mTransportType,
- getter_AddRefs(mBuilder))))) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
- dataChannelBuilder(do_QueryInterface(mBuilder));
- if (NS_WARN_IF(!dataChannelBuilder)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- // OOP window would be set from content process
- nsPIDOMWindowInner* window = GetWindow();
-
- nsresult rv = dataChannelBuilder->
- BuildDataChannelTransport(nsIPresentationService::ROLE_CONTROLLER,
- window,
- this);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationControllingInfo::NotifyDisconnected(nsresult aReason)
-{
- PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), aReason, mRole);
-
- MOZ_ASSERT(NS_IsMainThread());
-
- if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
- nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
- builder = do_QueryInterface(mBuilder);
- if (builder) {
- Unused << NS_WARN_IF(NS_FAILED(builder->NotifyDisconnected(aReason)));
- }
- }
-
- // Unset control channel here so it won't try to re-close it in potential
- // subsequent |Shutdown| calls.
- SetControlChannel(nullptr);
-
- if (NS_WARN_IF(NS_FAILED(aReason) || !mIsResponderReady)) {
- // The presentation session instance may already exist.
- // Change the state to CLOSED if it is not terminated.
- if (nsIPresentationSessionListener::STATE_TERMINATED != mState) {
- SetStateWithReason(nsIPresentationSessionListener::STATE_CLOSED, aReason);
- }
-
- // If |aReason| is NS_OK, it implies that the user closes the connection
- // before becomming connected. No need to call |ReplyError| in this case.
- if (NS_FAILED(aReason)) {
- if (mIsReconnecting) {
- NotifyReconnectResult(NS_ERROR_DOM_OPERATION_ERR);
- }
- // Reply error for an abnormal close.
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
- Shutdown(aReason);
- }
-
- // This is the case for reconnecting a connection which is in
- // connecting state and |mTransport| is not ready.
- if (mDoReconnectAfterClose && !mTransport) {
- mDoReconnectAfterClose = false;
- return Reconnect(mReconnectCallback);
- }
-
- return NS_OK;
-}
-
-// nsIServerSocketListener
-NS_IMETHODIMP
-PresentationControllingInfo::OnSocketAccepted(nsIServerSocket* aServerSocket,
- nsISocketTransport* aTransport)
-{
- int32_t port;
- nsresult rv = aTransport->GetPort(&port);
- if (!NS_WARN_IF(NS_FAILED(rv))) {
- PRES_DEBUG("%s:receive from port[%d]\n",__func__, port);
- }
-
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!mBuilderConstructor)) {
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- // Initialize session transport builder and use |this| as the callback.
- nsCOMPtr<nsIPresentationTCPSessionTransportBuilder> builder;
- if (NS_SUCCEEDED(mBuilderConstructor->CreateTransportBuilder(
- nsIPresentationChannelDescription::TYPE_TCP,
- getter_AddRefs(mBuilder)))) {
- builder = do_QueryInterface(mBuilder);
- }
-
- if (NS_WARN_IF(!builder)) {
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- mTransportType = nsIPresentationChannelDescription::TYPE_TCP;
- return builder->BuildTCPSenderTransport(aTransport, this);
-}
-
-NS_IMETHODIMP
-PresentationControllingInfo::OnStopListening(nsIServerSocket* aServerSocket,
- nsresult aStatus)
-{
- PRES_DEBUG("controller %s:status[%x]\n",__func__, aStatus);
-
- MOZ_ASSERT(NS_IsMainThread());
-
- if (aStatus == NS_BINDING_ABORTED) { // The server socket was manually closed.
- return NS_OK;
- }
-
- Shutdown(aStatus);
-
- if (NS_WARN_IF(!IsSessionReady())) {
- // It happens before the session is ready. Reply the callback.
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- // It happens after the session is ready. Change the state to CLOSED.
- SetStateWithReason(nsIPresentationSessionListener::STATE_CLOSED, aStatus);
-
- return NS_OK;
-}
-
-/**
- * The steps to reconnect a session are summarized below:
- * 1. Change |mState| to CONNECTING.
- * 2. Check whether |mControlChannel| is existed or not. Usually we have to
- * create a new control cahnnel.
- * 3.1 |mControlChannel| is null, which means we have to create a new one.
- * |EstablishControlChannel| is called to create a new control channel.
- * At this point, |mControlChannel| is not able to use yet. Set
- * |mIsReconnecting| to true and wait until |NotifyConnected|.
- * 3.2 |mControlChannel| is not null and is avaliable.
- * We can just call |ContinueReconnect| to send reconnect command.
- * 4. |NotifyReconnected| of |nsIPresentationControlChannelListener| is called
- * to indicate the receiver is ready for reconnecting.
- * 5. Once both step 3 and 4 are done, the rest is to build a new data
- * transport channel by following the same steps as starting a
- * new session.
- */
-
-nsresult
-PresentationControllingInfo::Reconnect(nsIPresentationServiceCallback* aCallback)
-{
- PRES_DEBUG("%s:id[%s], role[%d], state[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), mRole, mState);
-
- if (!aCallback) {
- return NS_ERROR_INVALID_ARG;
- }
-
- mReconnectCallback = aCallback;
-
- if (NS_WARN_IF(mState == nsIPresentationSessionListener::STATE_TERMINATED)) {
- return NotifyReconnectResult(NS_ERROR_DOM_INVALID_STATE_ERR);
- }
-
- // If |mState| is not CLOSED, we have to close the connection before
- // reconnecting. The process to reconnect will be continued after
- // |NotifyDisconnected| or |NotifyTransportClosed| is invoked.
- if (mState == nsIPresentationSessionListener::STATE_CONNECTING ||
- mState == nsIPresentationSessionListener::STATE_CONNECTED) {
- mDoReconnectAfterClose = true;
- return Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED);
- }
-
- // Make sure |mState| is closed at this point.
- MOZ_ASSERT(mState == nsIPresentationSessionListener::STATE_CLOSED);
-
- mState = nsIPresentationSessionListener::STATE_CONNECTING;
- mIsReconnecting = true;
-
- nsresult rv = NS_OK;
- if (!mControlChannel) {
- nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
- rv = mDevice->EstablishControlChannel(getter_AddRefs(ctrlChannel));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return NotifyReconnectResult(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- rv = Init(ctrlChannel);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return NotifyReconnectResult(NS_ERROR_DOM_OPERATION_ERR);
- }
- } else {
- return ContinueReconnect();
- }
-
- return NS_OK;
-}
-
-nsresult
-PresentationControllingInfo::ContinueReconnect()
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mControlChannel);
-
- mIsReconnecting = false;
- if (NS_WARN_IF(NS_FAILED(mControlChannel->Reconnect(mSessionId, GetUrl())))) {
- return NotifyReconnectResult(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- return NS_OK;
-}
-
-// nsIListNetworkAddressesListener
-NS_IMETHODIMP
-PresentationControllingInfo::OnListedNetworkAddresses(const char** aAddressArray,
- uint32_t aAddressArraySize)
-{
- if (!aAddressArraySize) {
- return OnListNetworkAddressesFailed();
- }
-
- // TODO bug 1228504 Take all IP addresses in PresentationChannelDescription
- // into account. And at the first stage Presentation API is only exposed on
- // Firefox OS where the first IP appears enough for most scenarios.
-
- nsAutoCString ip;
- ip.Assign(aAddressArray[0]);
-
- // On Firefox desktop, the IP address is retrieved from a callback function.
- // To make consistent code sequence, following function call is dispatched
- // into main thread instead of calling it directly.
- NS_DispatchToMainThread(
- NewRunnableMethod<nsCString>(
- this,
- &PresentationControllingInfo::OnGetAddress,
- ip));
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationControllingInfo::OnListNetworkAddressesFailed()
-{
- PRES_ERROR("PresentationControllingInfo:OnListNetworkAddressesFailed");
-
- // In 1-UA case, transport channel can still be established
- // on loopback interface even if no network address available.
- NS_DispatchToMainThread(
- NewRunnableMethod<nsCString>(
- this,
- &PresentationControllingInfo::OnGetAddress,
- "127.0.0.1"));
-
- return NS_OK;
-}
-
-nsresult
-PresentationControllingInfo::NotifyReconnectResult(nsresult aStatus)
-{
- if (!mReconnectCallback) {
- MOZ_ASSERT(false, "mReconnectCallback can not be null here.");
- return NS_ERROR_FAILURE;
- }
-
- mIsReconnecting = false;
- nsCOMPtr<nsIPresentationServiceCallback> callback =
- mReconnectCallback.forget();
- if (NS_FAILED(aStatus)) {
- return callback->NotifyError(aStatus);
- }
-
- return callback->NotifySuccess(GetUrl());
-}
-
-// nsIPresentationSessionTransportCallback
-NS_IMETHODIMP
-PresentationControllingInfo::NotifyTransportReady()
-{
- return PresentationSessionInfo::NotifyTransportReady();
-}
-
-NS_IMETHODIMP
-PresentationControllingInfo::NotifyTransportClosed(nsresult aReason)
-{
- if (!mDoReconnectAfterClose) {
- return PresentationSessionInfo::NotifyTransportClosed(aReason);;
- }
-
- MOZ_ASSERT(mState == nsIPresentationSessionListener::STATE_CLOSED);
-
- mTransport = nullptr;
- mIsTransportReady = false;
- mDoReconnectAfterClose = false;
- return Reconnect(mReconnectCallback);
-}
-
-NS_IMETHODIMP
-PresentationControllingInfo::NotifyData(const nsACString& aData, bool aIsBinary)
-{
- return PresentationSessionInfo::NotifyData(aData, aIsBinary);
-}
-
-/**
- * Implementation of PresentationPresentingInfo
- *
- * During presentation session establishment, the receiver expects the following
- * after trying to launch the app by notifying "presentation-launch-receiver":
- * (The order between step 2 and 3 is not guaranteed.)
- * 1. |Observe| of |nsIObserver| is called with "presentation-receiver-launched".
- * Then start listen to document |STATE_TRANSFERRING| event.
- * 2. |NotifyResponderReady| is called to indicate the receiver page is ready
- * for presentation use.
- * 3. |OnOffer| of |nsIPresentationControlChannelListener| is called.
- * 4. Once both step 2 and 3 are done, establish the data transport channel and
- * send the answer. (The control channel will be closed by the sender once it
- * receives the answer.)
- * 5. |NotifyTransportReady| of |nsIPresentationSessionTransportCallback| is
- * called. The presentation session is ready to use, so notify the listener
- * of CONNECTED state.
- */
-
-NS_IMPL_ISUPPORTS_INHERITED(PresentationPresentingInfo,
- PresentationSessionInfo,
- nsITimerCallback)
-
-nsresult
-PresentationPresentingInfo::Init(nsIPresentationControlChannel* aControlChannel)
-{
- PresentationSessionInfo::Init(aControlChannel);
-
- // Add a timer to prevent waiting indefinitely in case the receiver page fails
- // to become ready.
- nsresult rv;
- int32_t timeout =
- Preferences::GetInt("presentation.receiver.loading.timeout", 10000);
- mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- rv = mTimer->InitWithCallback(this, timeout, nsITimer::TYPE_ONE_SHOT);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-void
-PresentationPresentingInfo::Shutdown(nsresult aReason)
-{
- PresentationSessionInfo::Shutdown(aReason);
-
- if (mTimer) {
- mTimer->Cancel();
- }
-
- mLoadingCallback = nullptr;
- mRequesterDescription = nullptr;
- mPendingCandidates.Clear();
- mPromise = nullptr;
- mHasFlushPendingEvents = false;
-}
-
-// nsIPresentationSessionTransportBuilderListener
-NS_IMETHODIMP
-PresentationPresentingInfo::OnSessionTransport(nsIPresentationSessionTransport* aTransport)
-{
- nsresult rv = PresentationSessionInfo::OnSessionTransport(aTransport);
-
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- // The session transport is managed by content process
- if (NS_WARN_IF(!aTransport)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- // send answer for TCP session transport
- if (mTransportType == nsIPresentationChannelDescription::TYPE_TCP) {
- // Prepare and send the answer.
- // In the current implementation of |PresentationSessionTransport|,
- // |GetSelfAddress| cannot return the real info when it's initialized via
- // |buildTCPReceiverTransport|. Yet this deficiency only affects the channel
- // description for the answer, which is not actually checked at requester side.
- nsCOMPtr<nsINetAddr> selfAddr;
- rv = mTransport->GetSelfAddress(getter_AddRefs(selfAddr));
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetSelfAddress failed");
-
- nsCString address;
- uint16_t port = 0;
- if (NS_SUCCEEDED(rv)) {
- selfAddr->GetAddress(address);
- selfAddr->GetPort(&port);
- }
- nsCOMPtr<nsIPresentationChannelDescription> description =
- new TCPPresentationChannelDescription(address, port);
-
- return mControlChannel->SendAnswer(description);
- }
-
- return NS_OK;
-}
-
-// Delegate the pending offer and ICE candidates to builder.
-NS_IMETHODIMP
-PresentationPresentingInfo::FlushPendingEvents(nsIPresentationDataChannelSessionTransportBuilder* builder)
-{
- if (NS_WARN_IF(!builder)) {
- return NS_ERROR_FAILURE;
- }
-
- mHasFlushPendingEvents = true;
-
- if (mRequesterDescription) {
- builder->OnOffer(mRequesterDescription);
- }
- mRequesterDescription = nullptr;
-
- for (size_t i = 0; i < mPendingCandidates.Length(); ++i) {
- builder->OnIceCandidate(mPendingCandidates[i]);
- }
- mPendingCandidates.Clear();
- return NS_OK;
-}
-
-nsresult
-PresentationPresentingInfo::InitTransportAndSendAnswer()
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mState == nsIPresentationSessionListener::STATE_CONNECTING);
-
- uint8_t type = 0;
- nsresult rv = mRequesterDescription->GetType(&type);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- if (NS_WARN_IF(!mBuilderConstructor)) {
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- if (NS_WARN_IF(NS_FAILED(
- mBuilderConstructor->CreateTransportBuilder(type,
- getter_AddRefs(mBuilder))))) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- if (type == nsIPresentationChannelDescription::TYPE_TCP) {
- // Establish a data transport channel |mTransport| to the sender and use
- // |this| as the callback.
- nsCOMPtr<nsIPresentationTCPSessionTransportBuilder> builder =
- do_QueryInterface(mBuilder);
- if (NS_WARN_IF(!builder)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- mTransportType = nsIPresentationChannelDescription::TYPE_TCP;
- return builder->BuildTCPReceiverTransport(mRequesterDescription, this);
- }
-
- if (type == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
- if (!Preferences::GetBool("dom.presentation.session_transport.data_channel.enable")) {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- /**
- * Generally transport is maintained by the chrome process. However, data
- * channel should be live with the DOM , which implies RTCDataChannel in an OOP
- * page should be establish in the content process.
- *
- * |mBuilderConstructor| is responsible for creating a builder, which is for
- * building a data channel transport.
- *
- * In the OOP case, |mBuilderConstructor| would create a builder which is
- * an object of |PresentationBuilderParent|. So, |BuildDataChannelTransport|
- * triggers an IPC call to make content process establish a RTCDataChannel
- * transport.
- */
-
- mTransportType = nsIPresentationChannelDescription::TYPE_DATACHANNEL;
-
- nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder> dataChannelBuilder =
- do_QueryInterface(mBuilder);
- if (NS_WARN_IF(!dataChannelBuilder)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- nsPIDOMWindowInner* window = GetWindow();
-
- rv = dataChannelBuilder->
- BuildDataChannelTransport(nsIPresentationService::ROLE_RECEIVER,
- window,
- this);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = FlushPendingEvents(dataChannelBuilder);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
- }
-
- MOZ_ASSERT(false, "Unknown nsIPresentationChannelDescription type!");
- return NS_ERROR_UNEXPECTED;
-}
-
-nsresult
-PresentationPresentingInfo::UntrackFromService()
-{
- // Remove the OOP responding info (if it has never been used).
- if (mContentParent) {
- Unused << NS_WARN_IF(!static_cast<ContentParent*>(mContentParent.get())->SendNotifyPresentationReceiverCleanUp(mSessionId));
- }
-
- // Receiver device might need clean up after session termination.
- if (mDevice) {
- mDevice->Disconnect();
- }
- mDevice = nullptr;
-
- // Remove the session info (and the in-process responding info if there's any).
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- static_cast<PresentationService*>(service.get())->UntrackSessionInfo(mSessionId, mRole);
-
- return NS_OK;
-}
-
-bool
-PresentationPresentingInfo::IsAccessible(base::ProcessId aProcessId)
-{
- // Only the specific content process should access the responder info.
- return (mContentParent) ?
- aProcessId == static_cast<ContentParent*>(mContentParent.get())->OtherPid() :
- false;
-}
-
-nsresult
-PresentationPresentingInfo::NotifyResponderReady()
-{
- PRES_DEBUG("%s:id[%s], role[%d], state[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), mRole, mState);
-
- if (mTimer) {
- mTimer->Cancel();
- mTimer = nullptr;
- }
-
- mIsResponderReady = true;
-
- // Initialize |mTransport| and send the answer to the sender if sender's
- // description is already offered.
- if (mRequesterDescription) {
- nsresult rv = InitTransportAndSendAnswer();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
- }
-
- return NS_OK;
-}
-
-nsresult
-PresentationPresentingInfo::NotifyResponderFailure()
-{
- PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
-
- if (mTimer) {
- mTimer->Cancel();
- mTimer = nullptr;
- }
-
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
-}
-
-nsresult
-PresentationPresentingInfo::DoReconnect()
-{
- PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
-
- MOZ_ASSERT(mState == nsIPresentationSessionListener::STATE_CLOSED);
-
- SetStateWithReason(nsIPresentationSessionListener::STATE_CONNECTING, NS_OK);
-
- return NotifyResponderReady();
-}
-
-// nsIPresentationControlChannelListener
-NS_IMETHODIMP
-PresentationPresentingInfo::OnOffer(nsIPresentationChannelDescription* aDescription)
-{
- if (NS_WARN_IF(mHasFlushPendingEvents)) {
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- if (NS_WARN_IF(!aDescription)) {
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- mRequesterDescription = aDescription;
-
- // Initialize |mTransport| and send the answer to the sender if the receiver
- // page is ready for presentation use.
- if (mIsResponderReady) {
- nsresult rv = InitTransportAndSendAnswer();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationPresentingInfo::OnAnswer(nsIPresentationChannelDescription* aDescription)
-{
- MOZ_ASSERT(false, "Receiver side should not receive answer.");
- return NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP
-PresentationPresentingInfo::OnIceCandidate(const nsAString& aCandidate)
-{
- if (!mBuilder && !mHasFlushPendingEvents) {
- mPendingCandidates.AppendElement(nsString(aCandidate));
- return NS_OK;
- }
-
- if (NS_WARN_IF(!mBuilder && mHasFlushPendingEvents)) {
- return NS_ERROR_FAILURE;
- }
-
- nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
- builder = do_QueryInterface(mBuilder);
-
- return builder->OnIceCandidate(aCandidate);
-}
-
-NS_IMETHODIMP
-PresentationPresentingInfo::NotifyConnected()
-{
- PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), mRole);
-
- if (nsIPresentationSessionListener::STATE_TERMINATED == mState) {
- ContinueTermination();
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationPresentingInfo::NotifyReconnected()
-{
- MOZ_ASSERT(false, "NotifyReconnected should not be called at receiver side.");
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationPresentingInfo::NotifyDisconnected(nsresult aReason)
-{
- PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(mSessionId).get(), aReason, mRole);
-
- MOZ_ASSERT(NS_IsMainThread());
-
- if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
- nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder>
- builder = do_QueryInterface(mBuilder);
- if (builder) {
- Unused << NS_WARN_IF(NS_FAILED(builder->NotifyDisconnected(aReason)));
- }
- }
-
- // Unset control channel here so it won't try to re-close it in potential
- // subsequent |Shutdown| calls.
- SetControlChannel(nullptr);
-
- if (NS_WARN_IF(NS_FAILED(aReason))) {
- // The presentation session instance may already exist.
- // Change the state to TERMINATED since it never succeeds.
- SetStateWithReason(nsIPresentationSessionListener::STATE_TERMINATED, aReason);
-
- // Reply error for an abnormal close.
- return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- }
-
- return NS_OK;
-}
-
-// nsITimerCallback
-NS_IMETHODIMP
-PresentationPresentingInfo::Notify(nsITimer* aTimer)
-{
- MOZ_ASSERT(NS_IsMainThread());
- NS_WARNING("The receiver page fails to become ready before timeout.");
-
- mTimer = nullptr;
- return ReplyError(NS_ERROR_DOM_TIMEOUT_ERR);
-}
-
-// PromiseNativeHandler
-void
-PresentationPresentingInfo::ResolvedCallback(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!aValue.isObject())) {
- ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
- if (NS_WARN_IF(!obj)) {
- ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- // Start to listen to document state change event |STATE_TRANSFERRING|.
- // Use Element to support both HTMLIFrameElement and nsXULElement.
- Element* frame = nullptr;
- nsresult rv = UNWRAP_OBJECT(Element, &obj, frame);
- if (NS_WARN_IF(!frame)) {
- ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- nsCOMPtr<nsIFrameLoaderOwner> owner = do_QueryInterface((nsIFrameLoaderOwner*) frame);
- if (NS_WARN_IF(!owner)) {
- ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- nsCOMPtr<nsIFrameLoader> frameLoader = owner->GetFrameLoader();
- if (NS_WARN_IF(!frameLoader)) {
- ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- RefPtr<TabParent> tabParent = TabParent::GetFrom(frameLoader);
- if (tabParent) {
- // OOP frame
- // Notify the content process that a receiver page has launched, so it can
- // start monitoring the loading progress.
- mContentParent = tabParent->Manager();
- Unused << NS_WARN_IF(!static_cast<ContentParent*>(mContentParent.get())->SendNotifyPresentationReceiverLaunched(tabParent, mSessionId));
- } else {
- // In-process frame
- nsCOMPtr<nsIDocShell> docShell;
- rv = frameLoader->GetDocShell(getter_AddRefs(docShell));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
-
- // Keep an eye on the loading progress of the receiver page.
- mLoadingCallback = new PresentationResponderLoadingCallback(mSessionId);
- rv = mLoadingCallback->Init(docShell);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- ReplyError(NS_ERROR_DOM_OPERATION_ERR);
- return;
- }
- }
-}
-
-void
-PresentationPresentingInfo::RejectedCallback(JSContext* aCx,
- JS::Handle<JS::Value> aValue)
-{
- MOZ_ASSERT(NS_IsMainThread());
- NS_WARNING("Launching the receiver page has been rejected.");
-
- if (mTimer) {
- mTimer->Cancel();
- mTimer = nullptr;
- }
-
- ReplyError(NS_ERROR_DOM_OPERATION_ERR);
-}
diff --git a/dom/presentation/PresentationSessionInfo.h b/dom/presentation/PresentationSessionInfo.h
deleted file mode 100644
index 6338d3c32..000000000
--- a/dom/presentation/PresentationSessionInfo.h
+++ /dev/null
@@ -1,304 +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_PresentationSessionInfo_h
-#define mozilla_dom_PresentationSessionInfo_h
-
-#include "base/process.h"
-#include "mozilla/dom/nsIContentParent.h"
-#include "mozilla/dom/Promise.h"
-#include "mozilla/dom/PromiseNativeHandler.h"
-#include "mozilla/DebugOnly.h"
-#include "mozilla/RefPtr.h"
-#include "nsCOMPtr.h"
-#include "nsINetworkInfoService.h"
-#include "nsIPresentationControlChannel.h"
-#include "nsIPresentationDevice.h"
-#include "nsIPresentationListener.h"
-#include "nsIPresentationService.h"
-#include "nsIPresentationSessionTransport.h"
-#include "nsIPresentationSessionTransportBuilder.h"
-#include "nsIServerSocket.h"
-#include "nsITimer.h"
-#include "nsString.h"
-#include "PresentationCallbacks.h"
-
-namespace mozilla {
-namespace dom {
-
-class PresentationSessionInfo : public nsIPresentationSessionTransportCallback
- , public nsIPresentationControlChannelListener
- , public nsIPresentationSessionTransportBuilderListener
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONSESSIONTRANSPORTCALLBACK
- NS_DECL_NSIPRESENTATIONSESSIONTRANSPORTBUILDERLISTENER
-
- PresentationSessionInfo(const nsAString& aUrl,
- const nsAString& aSessionId,
- const uint8_t aRole)
- : mUrl(aUrl)
- , mSessionId(aSessionId)
- , mIsResponderReady(false)
- , mIsTransportReady(false)
- , mState(nsIPresentationSessionListener::STATE_CONNECTING)
- , mReason(NS_OK)
- {
- MOZ_ASSERT(!mUrl.IsEmpty());
- MOZ_ASSERT(!mSessionId.IsEmpty());
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
- mRole = aRole;
- }
-
- virtual nsresult Init(nsIPresentationControlChannel* aControlChannel);
-
- const nsAString& GetUrl() const
- {
- return mUrl;
- }
-
- const nsAString& GetSessionId() const
- {
- return mSessionId;
- }
-
- uint8_t GetRole() const
- {
- return mRole;
- }
-
- nsresult SetListener(nsIPresentationSessionListener* aListener);
-
- void SetDevice(nsIPresentationDevice* aDevice)
- {
- mDevice = aDevice;
- }
-
- already_AddRefed<nsIPresentationDevice> GetDevice() const
- {
- nsCOMPtr<nsIPresentationDevice> device = mDevice;
- return device.forget();
- }
-
- void SetControlChannel(nsIPresentationControlChannel* aControlChannel)
- {
- if (mControlChannel) {
- mControlChannel->SetListener(nullptr);
- }
-
- mControlChannel = aControlChannel;
- if (mControlChannel) {
- mControlChannel->SetListener(this);
- }
- }
-
- nsresult Send(const nsAString& aData);
-
- nsresult SendBinaryMsg(const nsACString& aData);
-
- nsresult SendBlob(nsIDOMBlob* aBlob);
-
- nsresult Close(nsresult aReason,
- uint32_t aState);
-
- nsresult OnTerminate(nsIPresentationControlChannel* aControlChannel);
-
- nsresult ReplyError(nsresult aReason);
-
- virtual bool IsAccessible(base::ProcessId aProcessId);
-
- void SetTransportBuilderConstructor(
- nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
- {
- mBuilderConstructor = aBuilderConstructor;
- }
-
-protected:
- virtual ~PresentationSessionInfo()
- {
- Shutdown(NS_OK);
- }
-
- virtual void Shutdown(nsresult aReason);
-
- nsresult ReplySuccess();
-
- bool IsSessionReady()
- {
- return mIsResponderReady && mIsTransportReady;
- }
-
- virtual nsresult UntrackFromService();
-
- void SetStateWithReason(uint32_t aState, nsresult aReason)
- {
- if (mState == aState) {
- return;
- }
-
- mState = aState;
- mReason = aReason;
-
- // Notify session state change.
- if (mListener) {
- DebugOnly<nsresult> rv =
- mListener->NotifyStateChange(mSessionId, mState, aReason);
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NotifyStateChanged");
- }
- }
-
- void ContinueTermination();
-
- void ResetBuilder()
- {
- mBuilder = nullptr;
- }
-
- // Should be nsIPresentationChannelDescription::TYPE_TCP/TYPE_DATACHANNEL
- uint8_t mTransportType = 0;
-
- nsPIDOMWindowInner* GetWindow();
-
- nsString mUrl;
- nsString mSessionId;
- // mRole should be nsIPresentationService::ROLE_CONTROLLER
- // or nsIPresentationService::ROLE_RECEIVER.
- uint8_t mRole;
- bool mIsResponderReady;
- bool mIsTransportReady;
- bool mIsOnTerminating = false;
- uint32_t mState; // CONNECTED, CLOSED, TERMINATED
- nsresult mReason;
- nsCOMPtr<nsIPresentationSessionListener> mListener;
- nsCOMPtr<nsIPresentationDevice> mDevice;
- nsCOMPtr<nsIPresentationSessionTransport> mTransport;
- nsCOMPtr<nsIPresentationControlChannel> mControlChannel;
- nsCOMPtr<nsIPresentationSessionTransportBuilder> mBuilder;
- nsCOMPtr<nsIPresentationTransportBuilderConstructor> mBuilderConstructor;
-};
-
-// Session info with controlling browsing context (sender side) behaviors.
-class PresentationControllingInfo final : public PresentationSessionInfo
- , public nsIServerSocketListener
- , public nsIListNetworkAddressesListener
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_NSIPRESENTATIONCONTROLCHANNELLISTENER
- NS_DECL_NSISERVERSOCKETLISTENER
- NS_DECL_NSILISTNETWORKADDRESSESLISTENER
- NS_DECL_NSIPRESENTATIONSESSIONTRANSPORTCALLBACK
-
- PresentationControllingInfo(const nsAString& aUrl,
- const nsAString& aSessionId)
- : PresentationSessionInfo(aUrl,
- aSessionId,
- nsIPresentationService::ROLE_CONTROLLER)
- {}
-
- nsresult Init(nsIPresentationControlChannel* aControlChannel) override;
-
- nsresult Reconnect(nsIPresentationServiceCallback* aCallback);
-
- nsresult BuildTransport();
-
-private:
- ~PresentationControllingInfo()
- {
- Shutdown(NS_OK);
- }
-
- void Shutdown(nsresult aReason) override;
-
- nsresult GetAddress();
-
- nsresult OnGetAddress(const nsACString& aAddress);
-
- nsresult ContinueReconnect();
-
- nsresult NotifyReconnectResult(nsresult aStatus);
-
- nsCOMPtr<nsIServerSocket> mServerSocket;
- nsCOMPtr<nsIPresentationServiceCallback> mReconnectCallback;
- bool mIsReconnecting = false;
- bool mDoReconnectAfterClose = false;
-};
-
-// Session info with presenting browsing context (receiver side) behaviors.
-class PresentationPresentingInfo final : public PresentationSessionInfo
- , public PromiseNativeHandler
- , public nsITimerCallback
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_NSIPRESENTATIONCONTROLCHANNELLISTENER
- NS_DECL_NSITIMERCALLBACK
-
- PresentationPresentingInfo(const nsAString& aUrl,
- const nsAString& aSessionId,
- nsIPresentationDevice* aDevice)
- : PresentationSessionInfo(aUrl,
- aSessionId,
- nsIPresentationService::ROLE_RECEIVER)
- {
- MOZ_ASSERT(aDevice);
- SetDevice(aDevice);
- }
-
- nsresult Init(nsIPresentationControlChannel* aControlChannel) override;
-
- nsresult NotifyResponderReady();
- nsresult NotifyResponderFailure();
-
- NS_IMETHODIMP OnSessionTransport(nsIPresentationSessionTransport* transport) override;
-
- void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
-
- void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
-
- void SetPromise(Promise* aPromise)
- {
- mPromise = aPromise;
- mPromise->AppendNativeHandler(this);
- }
-
- bool IsAccessible(base::ProcessId aProcessId) override;
-
- nsresult DoReconnect();
-
-private:
- ~PresentationPresentingInfo()
- {
- Shutdown(NS_OK);
- }
-
- void Shutdown(nsresult aReason) override;
-
- nsresult InitTransportAndSendAnswer();
-
- nsresult UntrackFromService() override;
-
- NS_IMETHODIMP
- FlushPendingEvents(nsIPresentationDataChannelSessionTransportBuilder* builder);
-
- bool mHasFlushPendingEvents = false;
- RefPtr<PresentationResponderLoadingCallback> mLoadingCallback;
- nsCOMPtr<nsITimer> mTimer;
- nsCOMPtr<nsIPresentationChannelDescription> mRequesterDescription;
- nsTArray<nsString> mPendingCandidates;
- RefPtr<Promise> mPromise;
-
- // The content parent communicating with the content process which the OOP
- // receiver page belongs to.
- nsCOMPtr<nsIContentParent> mContentParent;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationSessionInfo_h
diff --git a/dom/presentation/PresentationSessionRequest.cpp b/dom/presentation/PresentationSessionRequest.cpp
deleted file mode 100644
index 219fbd6a4..000000000
--- a/dom/presentation/PresentationSessionRequest.cpp
+++ /dev/null
@@ -1,72 +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 "PresentationSessionRequest.h"
-#include "nsIPresentationControlChannel.h"
-#include "nsIPresentationDevice.h"
-
-namespace mozilla {
-namespace dom {
-
-NS_IMPL_ISUPPORTS(PresentationSessionRequest, nsIPresentationSessionRequest)
-
-PresentationSessionRequest::PresentationSessionRequest(nsIPresentationDevice* aDevice,
- const nsAString& aUrl,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel)
- : mUrl(aUrl)
- , mPresentationId(aPresentationId)
- , mDevice(aDevice)
- , mControlChannel(aControlChannel)
-{
-}
-
-PresentationSessionRequest::~PresentationSessionRequest()
-{
-}
-
-// nsIPresentationSessionRequest
-
-NS_IMETHODIMP
-PresentationSessionRequest::GetDevice(nsIPresentationDevice** aRetVal)
-{
- NS_ENSURE_ARG_POINTER(aRetVal);
-
- nsCOMPtr<nsIPresentationDevice> device = mDevice;
- device.forget(aRetVal);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationSessionRequest::GetUrl(nsAString& aRetVal)
-{
- aRetVal = mUrl;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationSessionRequest::GetPresentationId(nsAString& aRetVal)
-{
- aRetVal = mPresentationId;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationSessionRequest::GetControlChannel(nsIPresentationControlChannel** aRetVal)
-{
- NS_ENSURE_ARG_POINTER(aRetVal);
-
- nsCOMPtr<nsIPresentationControlChannel> controlChannel = mControlChannel;
- controlChannel.forget(aRetVal);
-
- return NS_OK;
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/PresentationSessionRequest.h b/dom/presentation/PresentationSessionRequest.h
deleted file mode 100644
index c56502d77..000000000
--- a/dom/presentation/PresentationSessionRequest.h
+++ /dev/null
@@ -1,41 +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_PresentationSessionRequest_h__
-#define mozilla_dom_PresentationSessionRequest_h__
-
-#include "nsIPresentationSessionRequest.h"
-#include "nsCOMPtr.h"
-#include "nsString.h"
-
-namespace mozilla {
-namespace dom {
-
-class PresentationSessionRequest final : public nsIPresentationSessionRequest
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONSESSIONREQUEST
-
- PresentationSessionRequest(nsIPresentationDevice* aDevice,
- const nsAString& aUrl,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel);
-
-private:
- virtual ~PresentationSessionRequest();
-
- nsString mUrl;
- nsString mPresentationId;
- nsCOMPtr<nsIPresentationDevice> mDevice;
- nsCOMPtr<nsIPresentationControlChannel> mControlChannel;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif /* mozilla_dom_PresentationSessionRequest_h__ */
-
diff --git a/dom/presentation/PresentationTCPSessionTransport.cpp b/dom/presentation/PresentationTCPSessionTransport.cpp
deleted file mode 100644
index 1ccb8b43c..000000000
--- a/dom/presentation/PresentationTCPSessionTransport.cpp
+++ /dev/null
@@ -1,589 +0,0 @@
-/* -*- 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/. */
-
-#include "nsArrayUtils.h"
-#include "nsIAsyncStreamCopier.h"
-#include "nsIInputStreamPump.h"
-#include "nsIMultiplexInputStream.h"
-#include "nsIMutableArray.h"
-#include "nsIOutputStream.h"
-#include "nsIPresentationControlChannel.h"
-#include "nsIScriptableInputStream.h"
-#include "nsISocketTransport.h"
-#include "nsISocketTransportService.h"
-#include "nsISupportsPrimitives.h"
-#include "nsNetUtil.h"
-#include "nsQueryObject.h"
-#include "nsServiceManagerUtils.h"
-#include "nsStreamUtils.h"
-#include "nsThreadUtils.h"
-#include "PresentationLog.h"
-#include "PresentationTCPSessionTransport.h"
-
-#define BUFFER_SIZE 65536
-
-using namespace mozilla;
-using namespace mozilla::dom;
-
-class CopierCallbacks final : public nsIRequestObserver
-{
-public:
- explicit CopierCallbacks(PresentationTCPSessionTransport* aTransport)
- : mOwner(aTransport)
- {}
-
- NS_DECL_ISUPPORTS
- NS_DECL_NSIREQUESTOBSERVER
-private:
- ~CopierCallbacks() {}
-
- RefPtr<PresentationTCPSessionTransport> mOwner;
-};
-
-NS_IMPL_ISUPPORTS(CopierCallbacks, nsIRequestObserver)
-
-NS_IMETHODIMP
-CopierCallbacks::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-CopierCallbacks::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus)
-{
- mOwner->NotifyCopyComplete(aStatus);
- return NS_OK;
-}
-
-NS_IMPL_CYCLE_COLLECTION(PresentationTCPSessionTransport, mTransport,
- mSocketInputStream, mSocketOutputStream,
- mInputStreamPump, mInputStreamScriptable,
- mMultiplexStream, mMultiplexStreamCopier, mCallback)
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(PresentationTCPSessionTransport)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(PresentationTCPSessionTransport)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PresentationTCPSessionTransport)
- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPresentationSessionTransport)
- NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
- NS_INTERFACE_MAP_ENTRY(nsIPresentationSessionTransport)
- NS_INTERFACE_MAP_ENTRY(nsIPresentationSessionTransportBuilder)
- NS_INTERFACE_MAP_ENTRY(nsIPresentationTCPSessionTransportBuilder)
- NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
- NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
- NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
-NS_INTERFACE_MAP_END
-
-PresentationTCPSessionTransport::PresentationTCPSessionTransport()
- : mReadyState(ReadyState::CLOSED)
- , mAsyncCopierActive(false)
- , mCloseStatus(NS_OK)
- , mDataNotificationEnabled(false)
-{
-}
-
-PresentationTCPSessionTransport::~PresentationTCPSessionTransport()
-{
-}
-
-NS_IMETHODIMP
-PresentationTCPSessionTransport::BuildTCPSenderTransport(nsISocketTransport* aTransport,
- nsIPresentationSessionTransportBuilderListener* aListener)
-{
- if (NS_WARN_IF(!aTransport)) {
- return NS_ERROR_INVALID_ARG;
- }
- mTransport = aTransport;
-
- if (NS_WARN_IF(!aListener)) {
- return NS_ERROR_INVALID_ARG;
- }
- mListener = aListener;
-
- nsresult rv = CreateStream();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mRole = nsIPresentationService::ROLE_CONTROLLER;
-
- nsCOMPtr<nsIPresentationSessionTransport> sessionTransport = do_QueryObject(this);
- nsCOMPtr<nsIRunnable> onSessionTransportRunnable =
- NewRunnableMethod
- <nsIPresentationSessionTransport*>(mListener,
- &nsIPresentationSessionTransportBuilderListener::OnSessionTransport,
- sessionTransport);
-
- NS_DispatchToCurrentThread(onSessionTransportRunnable.forget());
-
- nsCOMPtr<nsIRunnable> setReadyStateRunnable =
- NewRunnableMethod<ReadyState>(this,
- &PresentationTCPSessionTransport::SetReadyState,
- ReadyState::OPEN);
- return NS_DispatchToCurrentThread(setReadyStateRunnable.forget());
-}
-
-NS_IMETHODIMP
-PresentationTCPSessionTransport::BuildTCPReceiverTransport(nsIPresentationChannelDescription* aDescription,
- nsIPresentationSessionTransportBuilderListener* aListener)
-{
- if (NS_WARN_IF(!aDescription)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- if (NS_WARN_IF(!aListener)) {
- return NS_ERROR_INVALID_ARG;
- }
- mListener = aListener;
-
- uint16_t serverPort;
- nsresult rv = aDescription->GetTcpPort(&serverPort);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- nsCOMPtr<nsIArray> serverHosts;
- rv = aDescription->GetTcpAddress(getter_AddRefs(serverHosts));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- // TODO bug 1228504 Take all IP addresses in PresentationChannelDescription
- // into account. And at the first stage Presentation API is only exposed on
- // Firefox OS where the first IP appears enough for most scenarios.
- nsCOMPtr<nsISupportsCString> supportStr = do_QueryElementAt(serverHosts, 0);
- if (NS_WARN_IF(!supportStr)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- nsAutoCString serverHost;
- supportStr->GetData(serverHost);
- if (serverHost.IsEmpty()) {
- return NS_ERROR_INVALID_ARG;
- }
-
- PRES_DEBUG("%s:ServerHost[%s],ServerPort[%d]\n", __func__, serverHost.get(), serverPort);
-
- SetReadyState(ReadyState::CONNECTING);
-
- nsCOMPtr<nsISocketTransportService> sts =
- do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
- if (NS_WARN_IF(!sts)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- rv = sts->CreateTransport(nullptr, 0, serverHost, serverPort, nullptr,
- getter_AddRefs(mTransport));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- nsCOMPtr<nsIThread> mainThread;
- NS_GetMainThread(getter_AddRefs(mainThread));
-
- mTransport->SetEventSink(this, mainThread);
-
- rv = CreateStream();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mRole = nsIPresentationService::ROLE_RECEIVER;
-
- nsCOMPtr<nsIPresentationSessionTransport> sessionTransport = do_QueryObject(this);
- nsCOMPtr<nsIRunnable> runnable =
- NewRunnableMethod
- <nsIPresentationSessionTransport*>(mListener,
- &nsIPresentationSessionTransportBuilderListener::OnSessionTransport,
- sessionTransport);
- return NS_DispatchToCurrentThread(runnable.forget());
-}
-
-nsresult
-PresentationTCPSessionTransport::CreateStream()
-{
- nsresult rv = mTransport->OpenInputStream(0, 0, 0, getter_AddRefs(mSocketInputStream));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- rv = mTransport->OpenOutputStream(nsITransport::OPEN_UNBUFFERED, 0, 0, getter_AddRefs(mSocketOutputStream));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- // If the other side is not listening, we will get an |onInputStreamReady|
- // callback where |available| raises to indicate the connection was refused.
- nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(mSocketInputStream);
- if (NS_WARN_IF(!asyncStream)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- nsCOMPtr<nsIThread> mainThread;
- NS_GetMainThread(getter_AddRefs(mainThread));
-
- rv = asyncStream->AsyncWait(this, nsIAsyncInputStream::WAIT_CLOSURE_ONLY, 0, mainThread);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mInputStreamScriptable = do_CreateInstance("@mozilla.org/scriptableinputstream;1", &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- rv = mInputStreamScriptable->Init(mSocketInputStream);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mMultiplexStream = do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1", &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mMultiplexStreamCopier = do_CreateInstance("@mozilla.org/network/async-stream-copier;1", &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- nsCOMPtr<nsISocketTransportService> sts =
- do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
- if (NS_WARN_IF(!sts)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- nsCOMPtr<nsIEventTarget> target = do_QueryInterface(sts);
- rv = mMultiplexStreamCopier->Init(mMultiplexStream,
- mSocketOutputStream,
- target,
- true, /* source buffered */
- false, /* sink buffered */
- BUFFER_SIZE,
- false, /* close source */
- false); /* close sink */
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-nsresult
-PresentationTCPSessionTransport::CreateInputStreamPump()
-{
- if (NS_WARN_IF(mInputStreamPump)) {
- return NS_OK;
- }
-
- nsresult rv;
- mInputStreamPump = do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = mInputStreamPump->Init(mSocketInputStream, -1, -1, 0, 0, false);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = mInputStreamPump->AsyncRead(this, nullptr);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationTCPSessionTransport::EnableDataNotification()
-{
- if (NS_WARN_IF(!mCallback)) {
- return NS_ERROR_DOM_INVALID_STATE_ERR;
- }
-
- if (mDataNotificationEnabled) {
- return NS_OK;
- }
-
- mDataNotificationEnabled = true;
-
- if (IsReadyToNotifyData()) {
- return CreateInputStreamPump();
- }
-
- return NS_OK;
-}
-
-// nsIPresentationSessionTransportBuilderListener
-NS_IMETHODIMP
-PresentationTCPSessionTransport::GetCallback(nsIPresentationSessionTransportCallback** aCallback)
-{
- nsCOMPtr<nsIPresentationSessionTransportCallback> callback = mCallback;
- callback.forget(aCallback);
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationTCPSessionTransport::SetCallback(nsIPresentationSessionTransportCallback* aCallback)
-{
- mCallback = aCallback;
-
- if (!!mCallback && ReadyState::OPEN == mReadyState) {
- // Notify the transport channel is ready.
- Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportReady()));
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationTCPSessionTransport::GetSelfAddress(nsINetAddr** aSelfAddress)
-{
- if (NS_WARN_IF(!mTransport)) {
- return NS_ERROR_DOM_INVALID_STATE_ERR;
- }
-
- return mTransport->GetScriptableSelfAddr(aSelfAddress);
-}
-
-void
-PresentationTCPSessionTransport::EnsureCopying()
-{
- if (mAsyncCopierActive) {
- return;
- }
-
- mAsyncCopierActive = true;
- RefPtr<CopierCallbacks> callbacks = new CopierCallbacks(this);
- Unused << NS_WARN_IF(NS_FAILED(mMultiplexStreamCopier->AsyncCopy(callbacks, nullptr)));
-}
-
-void
-PresentationTCPSessionTransport::NotifyCopyComplete(nsresult aStatus)
-{
- mAsyncCopierActive = false;
- mMultiplexStream->RemoveStream(0);
- if (NS_WARN_IF(NS_FAILED(aStatus))) {
- if (mReadyState != ReadyState::CLOSED) {
- mCloseStatus = aStatus;
- SetReadyState(ReadyState::CLOSED);
- }
- return;
- }
-
- uint32_t count;
- nsresult rv = mMultiplexStream->GetCount(&count);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return;
- }
-
- if (count) {
- EnsureCopying();
- return;
- }
-
- if (mReadyState == ReadyState::CLOSING) {
- mSocketOutputStream->Close();
- mCloseStatus = NS_OK;
- SetReadyState(ReadyState::CLOSED);
- }
-}
-
-NS_IMETHODIMP
-PresentationTCPSessionTransport::Send(const nsAString& aData)
-{
- if (NS_WARN_IF(mReadyState != ReadyState::OPEN)) {
- return NS_ERROR_DOM_INVALID_STATE_ERR;
- }
-
- nsresult rv;
- nsCOMPtr<nsIStringInputStream> stream =
- do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
- if(NS_WARN_IF(NS_FAILED(rv))) {
- return NS_ERROR_DOM_INVALID_STATE_ERR;
- }
-
- NS_ConvertUTF16toUTF8 msgString(aData);
- rv = stream->SetData(msgString.BeginReading(), msgString.Length());
- if(NS_WARN_IF(NS_FAILED(rv))) {
- return NS_ERROR_DOM_INVALID_STATE_ERR;
- }
-
- mMultiplexStream->AppendStream(stream);
-
- EnsureCopying();
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationTCPSessionTransport::SendBinaryMsg(const nsACString& aData)
-{
- return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
-}
-
-NS_IMETHODIMP
-PresentationTCPSessionTransport::SendBlob(nsIDOMBlob* aBlob)
-{
- return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
-}
-
-NS_IMETHODIMP
-PresentationTCPSessionTransport::Close(nsresult aReason)
-{
- PRES_DEBUG("%s:reason[%x]\n", __func__, aReason);
-
- if (mReadyState == ReadyState::CLOSED || mReadyState == ReadyState::CLOSING) {
- return NS_OK;
- }
-
- mCloseStatus = aReason;
- SetReadyState(ReadyState::CLOSING);
-
- uint32_t count = 0;
- mMultiplexStream->GetCount(&count);
- if (!count) {
- mSocketOutputStream->Close();
- }
-
- mSocketInputStream->Close();
- mDataNotificationEnabled = false;
-
- mListener = nullptr;
-
- return NS_OK;
-}
-
-void
-PresentationTCPSessionTransport::SetReadyState(ReadyState aReadyState)
-{
- mReadyState = aReadyState;
-
- if (mReadyState == ReadyState::OPEN) {
- if (IsReadyToNotifyData()) {
- CreateInputStreamPump();
- }
-
- if (NS_WARN_IF(!mCallback)) {
- return;
- }
-
- // Notify the transport channel is ready.
- Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportReady()));
- } else if (mReadyState == ReadyState::CLOSED && mCallback) {
- if (NS_WARN_IF(!mCallback)) {
- return;
- }
-
- // Notify the transport channel has been shut down.
- Unused <<
- NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportClosed(mCloseStatus)));
- mCallback = nullptr;
- }
-}
-
-// nsITransportEventSink
-NS_IMETHODIMP
-PresentationTCPSessionTransport::OnTransportStatus(nsITransport* aTransport,
- nsresult aStatus,
- int64_t aProgress,
- int64_t aProgressMax)
-{
- PRES_DEBUG("%s:aStatus[%x]\n", __func__, aStatus);
-
- MOZ_ASSERT(NS_IsMainThread());
-
- if (aStatus != NS_NET_STATUS_CONNECTED_TO) {
- return NS_OK;
- }
-
- SetReadyState(ReadyState::OPEN);
-
- return NS_OK;
-}
-
-// nsIInputStreamCallback
-NS_IMETHODIMP
-PresentationTCPSessionTransport::OnInputStreamReady(nsIAsyncInputStream* aStream)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- // Only used for detecting if the connection was refused.
- uint64_t dummy;
- nsresult rv = aStream->Available(&dummy);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- if (mReadyState != ReadyState::CLOSED) {
- mCloseStatus = NS_ERROR_CONNECTION_REFUSED;
- SetReadyState(ReadyState::CLOSED);
- }
- }
-
- return NS_OK;
-}
-
-// nsIRequestObserver
-NS_IMETHODIMP
-PresentationTCPSessionTransport::OnStartRequest(nsIRequest* aRequest,
- nsISupports* aContext)
-{
- // Do nothing.
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationTCPSessionTransport::OnStopRequest(nsIRequest* aRequest,
- nsISupports* aContext,
- nsresult aStatusCode)
-{
- PRES_DEBUG("%s:aStatusCode[%x]\n", __func__, aStatusCode);
-
- MOZ_ASSERT(NS_IsMainThread());
-
- uint32_t count;
- nsresult rv = mMultiplexStream->GetCount(&count);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mInputStreamPump = nullptr;
-
- if (count != 0 && NS_SUCCEEDED(aStatusCode)) {
- // If we have some buffered output still, and status is not an error, the
- // other side has done a half-close, but we don't want to be in the close
- // state until we are done sending everything that was buffered. We also
- // don't want to call |NotifyTransportClosed| yet.
- return NS_OK;
- }
-
- // We call this even if there is no error.
- if (mReadyState != ReadyState::CLOSED) {
- mCloseStatus = aStatusCode;
- SetReadyState(ReadyState::CLOSED);
- }
- return NS_OK;
-}
-
-// nsIStreamListener
-NS_IMETHODIMP
-PresentationTCPSessionTransport::OnDataAvailable(nsIRequest* aRequest,
- nsISupports* aContext,
- nsIInputStream* aStream,
- uint64_t aOffset,
- uint32_t aCount)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!mCallback)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- nsCString data;
- nsresult rv = mInputStreamScriptable->ReadBytes(aCount, data);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- // Pass the incoming data to the listener.
- return mCallback->NotifyData(data, false);
-}
diff --git a/dom/presentation/PresentationTCPSessionTransport.h b/dom/presentation/PresentationTCPSessionTransport.h
deleted file mode 100644
index f36b371a4..000000000
--- a/dom/presentation/PresentationTCPSessionTransport.h
+++ /dev/null
@@ -1,110 +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_PresentationSessionTransport_h
-#define mozilla_dom_PresentationSessionTransport_h
-
-#include "mozilla/RefPtr.h"
-#include "nsCOMPtr.h"
-#include "nsIAsyncInputStream.h"
-#include "nsIPresentationSessionTransport.h"
-#include "nsIPresentationSessionTransportBuilder.h"
-#include "nsIStreamListener.h"
-#include "nsISupportsImpl.h"
-#include "nsITransport.h"
-
-class nsISocketTransport;
-class nsIInputStreamPump;
-class nsIScriptableInputStream;
-class nsIMultiplexInputStream;
-class nsIAsyncStreamCopier;
-class nsIInputStream;
-
-namespace mozilla {
-namespace dom {
-
-/*
- * App-to-App transport channel for the presentation session. It's usually
- * initialized with an |InitWithSocketTransport| call if at the presenting sender
- * side; whereas it's initialized with an |InitWithChannelDescription| if at the
- * presenting receiver side. The lifetime is managed in either
- * |PresentationControllingInfo| (sender side) or |PresentationPresentingInfo|
- * (receiver side) in PresentationSessionInfo.cpp.
- */
-class PresentationTCPSessionTransport final : public nsIPresentationSessionTransport
- , public nsIPresentationTCPSessionTransportBuilder
- , public nsITransportEventSink
- , public nsIInputStreamCallback
- , public nsIStreamListener
-{
-public:
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(PresentationTCPSessionTransport,
- nsIPresentationSessionTransport)
-
- NS_DECL_NSIPRESENTATIONSESSIONTRANSPORT
- NS_DECL_NSIPRESENTATIONSESSIONTRANSPORTBUILDER
- NS_DECL_NSIPRESENTATIONTCPSESSIONTRANSPORTBUILDER
- NS_DECL_NSITRANSPORTEVENTSINK
- NS_DECL_NSIINPUTSTREAMCALLBACK
- NS_DECL_NSIREQUESTOBSERVER
- NS_DECL_NSISTREAMLISTENER
-
- PresentationTCPSessionTransport();
-
- void NotifyCopyComplete(nsresult aStatus);
-
-private:
- ~PresentationTCPSessionTransport();
-
- nsresult CreateStream();
-
- nsresult CreateInputStreamPump();
-
- void EnsureCopying();
-
- enum class ReadyState {
- CONNECTING,
- OPEN,
- CLOSING,
- CLOSED
- };
-
- void SetReadyState(ReadyState aReadyState);
-
- bool IsReadyToNotifyData()
- {
- return mDataNotificationEnabled && mReadyState == ReadyState::OPEN;
- }
-
- ReadyState mReadyState;
- bool mAsyncCopierActive;
- nsresult mCloseStatus;
- bool mDataNotificationEnabled;
-
- uint8_t mRole = 0;
-
- // Raw socket streams
- nsCOMPtr<nsISocketTransport> mTransport;
- nsCOMPtr<nsIInputStream> mSocketInputStream;
- nsCOMPtr<nsIOutputStream> mSocketOutputStream;
-
- // Input stream machinery
- nsCOMPtr<nsIInputStreamPump> mInputStreamPump;
- nsCOMPtr<nsIScriptableInputStream> mInputStreamScriptable;
-
- // Output stream machinery
- nsCOMPtr<nsIMultiplexInputStream> mMultiplexStream;
- nsCOMPtr<nsIAsyncStreamCopier> mMultiplexStreamCopier;
-
- nsCOMPtr<nsIPresentationSessionTransportCallback> mCallback;
- nsCOMPtr<nsIPresentationSessionTransportBuilderListener> mListener;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationSessionTransport_h
diff --git a/dom/presentation/PresentationTerminateRequest.cpp b/dom/presentation/PresentationTerminateRequest.cpp
deleted file mode 100644
index 61fd8403f..000000000
--- a/dom/presentation/PresentationTerminateRequest.cpp
+++ /dev/null
@@ -1,73 +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 "PresentationTerminateRequest.h"
-#include "nsIPresentationControlChannel.h"
-#include "nsIPresentationDevice.h"
-
-namespace mozilla {
-namespace dom {
-
-NS_IMPL_ISUPPORTS(PresentationTerminateRequest, nsIPresentationTerminateRequest)
-
-PresentationTerminateRequest::PresentationTerminateRequest(
- nsIPresentationDevice* aDevice,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel,
- bool aIsFromReceiver)
- : mPresentationId(aPresentationId)
- , mDevice(aDevice)
- , mControlChannel(aControlChannel)
- , mIsFromReceiver(aIsFromReceiver)
-{
-}
-
-PresentationTerminateRequest::~PresentationTerminateRequest()
-{
-}
-
-// nsIPresentationTerminateRequest
-NS_IMETHODIMP
-PresentationTerminateRequest::GetDevice(nsIPresentationDevice** aRetVal)
-{
- NS_ENSURE_ARG_POINTER(aRetVal);
-
- nsCOMPtr<nsIPresentationDevice> device = mDevice;
- device.forget(aRetVal);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationTerminateRequest::GetPresentationId(nsAString& aRetVal)
-{
- aRetVal = mPresentationId;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationTerminateRequest::GetControlChannel(
- nsIPresentationControlChannel** aRetVal)
-{
- NS_ENSURE_ARG_POINTER(aRetVal);
-
- nsCOMPtr<nsIPresentationControlChannel> controlChannel = mControlChannel;
- controlChannel.forget(aRetVal);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationTerminateRequest::GetIsFromReceiver(bool* aRetVal)
-{
- *aRetVal = mIsFromReceiver;
-
- return NS_OK;
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/PresentationTerminateRequest.h b/dom/presentation/PresentationTerminateRequest.h
deleted file mode 100644
index ca3563f8d..000000000
--- a/dom/presentation/PresentationTerminateRequest.h
+++ /dev/null
@@ -1,41 +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_PresentationTerminateRequest_h__
-#define mozilla_dom_PresentationTerminateRequest_h__
-
-#include "nsIPresentationTerminateRequest.h"
-#include "nsCOMPtr.h"
-#include "nsString.h"
-
-namespace mozilla {
-namespace dom {
-
-class PresentationTerminateRequest final : public nsIPresentationTerminateRequest
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONTERMINATEREQUEST
-
- PresentationTerminateRequest(nsIPresentationDevice* aDevice,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel,
- bool aIsFromReceiver);
-
-private:
- virtual ~PresentationTerminateRequest();
-
- nsString mPresentationId;
- nsCOMPtr<nsIPresentationDevice> mDevice;
- nsCOMPtr<nsIPresentationControlChannel> mControlChannel;
- bool mIsFromReceiver;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif /* mozilla_dom_PresentationTerminateRequest_h__ */
-
diff --git a/dom/presentation/PresentationTransportBuilderConstructor.cpp b/dom/presentation/PresentationTransportBuilderConstructor.cpp
deleted file mode 100644
index 98177958d..000000000
--- a/dom/presentation/PresentationTransportBuilderConstructor.cpp
+++ /dev/null
@@ -1,85 +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 "PresentationTransportBuilderConstructor.h"
-
-#include "nsComponentManagerUtils.h"
-#include "nsIPresentationControlChannel.h"
-#include "nsIPresentationSessionTransport.h"
-#include "nsXULAppAPI.h"
-
-namespace mozilla {
-namespace dom {
-
-NS_IMPL_ISUPPORTS(DummyPresentationTransportBuilderConstructor,
- nsIPresentationTransportBuilderConstructor)
-
-NS_IMETHODIMP
-DummyPresentationTransportBuilderConstructor::CreateTransportBuilder(
- uint8_t aType,
- nsIPresentationSessionTransportBuilder** aRetval)
-{
- MOZ_ASSERT(false, "Unexpected to be invoked.");
- return NS_OK;
-}
-
-NS_IMPL_ISUPPORTS_INHERITED0(PresentationTransportBuilderConstructor,
- DummyPresentationTransportBuilderConstructor)
-
-/* static */ already_AddRefed<nsIPresentationTransportBuilderConstructor>
-PresentationTransportBuilderConstructor::Create()
-{
- nsCOMPtr<nsIPresentationTransportBuilderConstructor> constructor;
- if (XRE_IsContentProcess()) {
- constructor = new DummyPresentationTransportBuilderConstructor();
- } else {
- constructor = new PresentationTransportBuilderConstructor();
- }
-
- return constructor.forget();
-}
-
-NS_IMETHODIMP
-PresentationTransportBuilderConstructor::CreateTransportBuilder(
- uint8_t aType,
- nsIPresentationSessionTransportBuilder** aRetval)
-{
- if (NS_WARN_IF(!aRetval)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- *aRetval = nullptr;
-
- if (NS_WARN_IF(aType != nsIPresentationChannelDescription::TYPE_TCP &&
- aType != nsIPresentationChannelDescription::TYPE_DATACHANNEL)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- if (XRE_IsContentProcess()) {
- MOZ_ASSERT(false,
- "CreateTransportBuilder can only be invoked in parent process.");
- return NS_ERROR_FAILURE;
- }
-
- nsCOMPtr<nsIPresentationSessionTransportBuilder> builder;
- if (aType == nsIPresentationChannelDescription::TYPE_TCP) {
- builder =
- do_CreateInstance(PRESENTATION_TCP_SESSION_TRANSPORT_CONTRACTID);
- } else {
- builder =
- do_CreateInstance("@mozilla.org/presentation/datachanneltransportbuilder;1");
- }
-
- if (NS_WARN_IF(!builder)) {
- return NS_ERROR_DOM_OPERATION_ERR;
- }
-
- builder.forget(aRetval);
- return NS_OK;
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/PresentationTransportBuilderConstructor.h b/dom/presentation/PresentationTransportBuilderConstructor.h
deleted file mode 100644
index 4250d61ba..000000000
--- a/dom/presentation/PresentationTransportBuilderConstructor.h
+++ /dev/null
@@ -1,48 +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_PresentationTransportBuilderConstructor_h
-#define mozilla_dom_PresentationTransportBuilderConstructor_h
-
-#include "nsCOMPtr.h"
-#include "nsIPresentationSessionTransportBuilder.h"
-#include "nsISupportsImpl.h"
-
-namespace mozilla {
-namespace dom {
-
-class DummyPresentationTransportBuilderConstructor :
- public nsIPresentationTransportBuilderConstructor
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONTRANSPORTBUILDERCONSTRUCTOR
-
- DummyPresentationTransportBuilderConstructor() = default;
-
-protected:
- virtual ~DummyPresentationTransportBuilderConstructor() = default;
-};
-
-class PresentationTransportBuilderConstructor final :
- public DummyPresentationTransportBuilderConstructor
-{
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_NSIPRESENTATIONTRANSPORTBUILDERCONSTRUCTOR
-
- static already_AddRefed<nsIPresentationTransportBuilderConstructor>
- Create();
-
-private:
- PresentationTransportBuilderConstructor() = default;
- virtual ~PresentationTransportBuilderConstructor() = default;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationTransportBuilderConstructor_h
diff --git a/dom/presentation/interfaces/moz.build b/dom/presentation/interfaces/moz.build
deleted file mode 100644
index 935e39000..000000000
--- a/dom/presentation/interfaces/moz.build
+++ /dev/null
@@ -1,30 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-XPIDL_SOURCES += [
- 'nsIPresentationControlChannel.idl',
- 'nsIPresentationControlService.idl',
- 'nsIPresentationDevice.idl',
- 'nsIPresentationDeviceManager.idl',
- 'nsIPresentationDevicePrompt.idl',
- 'nsIPresentationDeviceProvider.idl',
- 'nsIPresentationListener.idl',
- 'nsIPresentationLocalDevice.idl',
- 'nsIPresentationRequestUIGlue.idl',
- 'nsIPresentationService.idl',
- 'nsIPresentationSessionRequest.idl',
- 'nsIPresentationSessionTransport.idl',
- 'nsIPresentationSessionTransportBuilder.idl',
- 'nsIPresentationTerminateRequest.idl',
-]
-
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
- XPIDL_SOURCES += [
- 'nsIPresentationNetworkHelper.idl',
- ]
-
-XPIDL_MODULE = 'dom_presentation'
-
diff --git a/dom/presentation/interfaces/nsIPresentationControlChannel.idl b/dom/presentation/interfaces/nsIPresentationControlChannel.idl
deleted file mode 100644
index 669e4088e..000000000
--- a/dom/presentation/interfaces/nsIPresentationControlChannel.idl
+++ /dev/null
@@ -1,139 +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 "nsISupports.idl"
-
-interface nsIArray;
-interface nsIInputStream;
-
-[scriptable, uuid(ae318e05-2a4e-4f85-95c0-e8b191ad812c)]
-interface nsIPresentationChannelDescription: nsISupports
-{
- const unsigned short TYPE_TCP = 1;
- const unsigned short TYPE_DATACHANNEL = 2;
-
- // Type of transport channel.
- readonly attribute uint8_t type;
-
- // Addresses for TCP channel (as a list of nsISupportsCString).
- // Should only be used while type == TYPE_TCP.
- readonly attribute nsIArray tcpAddress;
-
- // Port number for TCP channel.
- // Should only be used while type == TYPE_TCP.
- readonly attribute uint16_t tcpPort;
-
- // SDP for Data Channel.
- // Should only be used while type == TYPE_DATACHANNEL.
- readonly attribute DOMString dataChannelSDP;
-};
-
-/*
- * The callbacks for events on control channel.
- */
-[scriptable, uuid(96dd548f-7d0f-43c1-b1ad-28e666cf1e82)]
-interface nsIPresentationControlChannelListener: nsISupports
-{
- /*
- * Callback for receiving offer from remote endpoint.
- * @param offer The received offer.
- */
- void onOffer(in nsIPresentationChannelDescription offer);
-
- /*
- * Callback for receiving answer from remote endpoint.
- * @param answer The received answer.
- */
- void onAnswer(in nsIPresentationChannelDescription answer);
-
- /*
- * Callback for receiving ICE candidate from remote endpoint.
- * @param answer The received answer.
- */
- void onIceCandidate(in DOMString candidate);
-
- /*
- * The callback for notifying channel connected. This should be async called
- * after nsIPresentationDevice::establishControlChannel.
- */
- void notifyConnected();
-
- /*
- * The callback for notifying channel disconnected.
- * @param reason The reason of channel close, NS_OK represents normal close.
- */
- void notifyDisconnected(in nsresult reason);
-
- /*
- * The callback for notifying the reconnect command is acknowledged.
- */
- void notifyReconnected();
-};
-
-/*
- * The control channel for establishing RTCPeerConnection for a presentation
- * session. SDP Offer/Answer will be exchanged through this interface. The
- * control channel should be in-order.
- */
-[scriptable, uuid(e60e208c-a9f5-4bc6-9a3e-47f3e4ae9c57)]
-interface nsIPresentationControlChannel: nsISupports
-{
- // The listener for handling events of this control channel.
- // All the events should be pending until listener is assigned.
- attribute nsIPresentationControlChannelListener listener;
-
- /*
- * Send offer to remote endpoint. |onOffer| should be invoked on remote
- * endpoint.
- * @param offer The offer to send.
- * @throws NS_ERROR_FAILURE on failure
- */
- void sendOffer(in nsIPresentationChannelDescription offer);
-
- /*
- * Send answer to remote endpoint. |onAnswer| should be invoked on remote
- * endpoint.
- * @param answer The answer to send.
- * @throws NS_ERROR_FAILURE on failure
- */
- void sendAnswer(in nsIPresentationChannelDescription answer);
-
- /*
- * Send ICE candidate to remote endpoint. |onIceCandidate| should be invoked
- * on remote endpoint.
- * @param candidate The candidate to send
- * @throws NS_ERROR_FAILURE on failure
- */
- void sendIceCandidate(in DOMString candidate);
-
- /*
- * Launch a presentation on remote endpoint.
- * @param presentationId The Id for representing this session.
- * @param url The URL requested to open by remote device.
- * @throws NS_ERROR_FAILURE on failure
- */
- void launch(in DOMString presentationId, in DOMString url);
-
- /*
- * Terminate a presentation on remote endpoint.
- * @param presentationId The Id for representing this session.
- * @throws NS_ERROR_FAILURE on failure
- */
- void terminate(in DOMString presentationId);
-
- /*
- * Disconnect the control channel.
- * @param reason The reason of disconnecting channel; NS_OK represents normal.
- */
- void disconnect(in nsresult reason);
-
- /*
- * Reconnect a presentation on remote endpoint.
- * Note that only controller is allowed to reconnect a session.
- * @param presentationId The Id for representing this session.
- * @param url The URL requested to open by remote device.
- * @throws NS_ERROR_FAILURE on failure
- */
- void reconnect(in DOMString presentationId, in DOMString url);
-};
diff --git a/dom/presentation/interfaces/nsIPresentationControlService.idl b/dom/presentation/interfaces/nsIPresentationControlService.idl
deleted file mode 100644
index d4b967b00..000000000
--- a/dom/presentation/interfaces/nsIPresentationControlService.idl
+++ /dev/null
@@ -1,156 +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 "nsISupports.idl"
-
-interface nsIPresentationControlChannel;
-
-%{C++
-#define PRESENTATION_CONTROL_SERVICE_CONTACT_ID \
- "@mozilla.org/presentation/control-service;1"
-%}
-
-/*
- * The device information required for establishing control channel.
- */
-[scriptable, uuid(296fd171-e4d0-4de0-99ff-ad8ed52ddef3)]
-interface nsITCPDeviceInfo: nsISupports
-{
- readonly attribute AUTF8String id;
- readonly attribute AUTF8String address;
- readonly attribute uint16_t port;
- // SHA-256 fingerprint of server certificate. Empty string represents
- // server doesn't support TLS or not available.
- readonly attribute AUTF8String certFingerprint;
-};
-
-[scriptable, uuid(09bddfaf-fcc2-4dc9-b33e-a509a1c2fb6d)]
-interface nsIPresentationControlServerListener: nsISupports
-{
- /**
- * Callback while the server is ready or restarted.
- * @param aPort
- * The port of the server socket.
- * @param aCertFingerprint
- * The SHA-256 fingerprint of TLS server certificate.
- * Empty string represents server started without encryption.
- */
- void onServerReady(in uint16_t aPort, in AUTF8String aCertFingerprint);
-
- /**
- * Callback while the server is stopped or fails to start.
- * @param aResult
- * The error cause of server stopped or the reason of
- * start failure.
- * NS_OK means the server is stopped by close.
- */
- void onServerStopped(in nsresult aResult);
-
- /**
- * Callback while the remote host is requesting to start a presentation session.
- * @param aDeviceInfo The device information related to the remote host.
- * @param aUrl The URL requested to open by remote device.
- * @param aPresentationId The Id for representing this session.
- * @param aControlChannel The control channel for this session.
- */
- void onSessionRequest(in nsITCPDeviceInfo aDeviceInfo,
- in DOMString aUrl,
- in DOMString aPresentationId,
- in nsIPresentationControlChannel aControlChannel);
-
- /**
- * Callback while the remote host is requesting to terminate a presentation session.
- * @param aDeviceInfo The device information related to the remote host.
- * @param aPresentationId The Id for representing this session.
- * @param aControlChannel The control channel for this session.
- * @param aIsFromReceiver true if termination is initiated by receiver.
- */
- void onTerminateRequest(in nsITCPDeviceInfo aDeviceInfo,
- in DOMString aPresentationId,
- in nsIPresentationControlChannel aControlChannel,
- in boolean aIsFromReceiver);
-
- /**
- * Callback while the remote host is requesting to reconnect a presentation session.
- * @param aDeviceInfo The device information related to the remote host.
- * @param aUrl The URL requested to open by remote device.
- * @param aPresentationId The Id for representing this session.
- * @param aControlChannel The control channel for this session.
- */
- void onReconnectRequest(in nsITCPDeviceInfo aDeviceInfo,
- in DOMString url,
- in DOMString aPresentationId,
- in nsIPresentationControlChannel aControlChannel);
-};
-
-/**
- * Presentation control service which can be used for both presentation
- * control client and server.
- */
-[scriptable, uuid(55d6b605-2389-4aae-a8fe-60d4440540ea)]
-interface nsIPresentationControlService: nsISupports
-{
- /**
- * This method initializes server socket. Caller should set listener and
- * monitor onServerReady event to get the correct server info.
- * @param aEncrypted
- * True for using TLS control channel.
- * @param aPort
- * The port of the server socket. Pass 0 or opt-out to indicate no
- * preference, and a port will be selected automatically.
- * @throws NS_ERROR_FAILURE if the server socket has been inited or the
- * server socket can not be inited.
- */
- void startServer(in boolean aEncrypted, [optional] in uint16_t aPort);
-
- /**
- * Request connection to designated remote presentation control receiver.
- * @param aDeviceInfo
- * The remtoe device info for establish connection.
- * @returns The control channel for this session.
- * @throws NS_ERROR_FAILURE if the Id hasn't been inited.
- */
- nsIPresentationControlChannel connect(in nsITCPDeviceInfo aDeviceInfo);
-
- /**
- * Check the compatibility to remote presentation control server.
- * @param aVersion
- * The version of remote server.
- */
- boolean isCompatibleServer(in uint32_t aVersion);
-
- /**
- * Close server socket and call |listener.onClose(NS_OK)|
- */
- void close();
-
- /**
- * Get the listen port of the TCP socket, valid after the server is ready.
- * 0 indicates the server socket is not ready or is closed.
- */
- readonly attribute uint16_t port;
-
- /**
- * The protocol version implemented by this server.
- */
- readonly attribute uint32_t version;
-
- /**
- * The id of the TCP presentation server. |requestSession| won't
- * work until the |id| is set.
- */
- attribute AUTF8String id;
-
- /**
- * The fingerprint of the TLS server certificate.
- * Empty string indicates the server is not ready or not encrypted.
- */
- attribute AUTF8String certFingerprint;
-
- /**
- * The listener for handling events of this presentation control server.
- * Listener must be provided before invoke |startServer| and |close|.
- */
- attribute nsIPresentationControlServerListener listener;
-};
diff --git a/dom/presentation/interfaces/nsIPresentationDevice.idl b/dom/presentation/interfaces/nsIPresentationDevice.idl
deleted file mode 100644
index 63e4a52ef..000000000
--- a/dom/presentation/interfaces/nsIPresentationDevice.idl
+++ /dev/null
@@ -1,43 +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 "nsISupports.idl"
-
-interface nsIPresentationControlChannel;
-
-/*
- * Remote device.
- */
-[scriptable, uuid(b1e0a7af-5936-4066-8f2e-f789fb9a7e8f)]
-interface nsIPresentationDevice : nsISupports
-{
- // The unique Id for the device. UUID is recommanded.
- readonly attribute AUTF8String id;
-
- // The human-readable name of this device.
- readonly attribute AUTF8String name;
-
- // TODO expose more info in order to fulfill UX spec
- // The category of this device, could be "wifi", "bluetooth", "hdmi", etc.
- readonly attribute AUTF8String type;
-
- /*
- * Establish a control channel to this device.
- * @returns The control channel for this session.
- * @throws NS_ERROR_FAILURE if the establishment fails
- */
- nsIPresentationControlChannel establishControlChannel();
-
- // Do something when presentation session is disconnected.
- void disconnect();
-
- /*
- * Query if requested presentation URL is supported.
- * @params requestedUrl the designated URL for a presentation request.
- * @returns true if designated URL is supported.
- */
- boolean isRequestedUrlSupported(in DOMString requestedUrl);
-};
-
-
diff --git a/dom/presentation/interfaces/nsIPresentationDeviceManager.idl b/dom/presentation/interfaces/nsIPresentationDeviceManager.idl
deleted file mode 100644
index adff9fc09..000000000
--- a/dom/presentation/interfaces/nsIPresentationDeviceManager.idl
+++ /dev/null
@@ -1,51 +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 "nsISupports.idl"
-
-interface nsIArray;
-interface nsIPresentationDeviceProvider;
-
-%{C++
-#define PRESENTATION_DEVICE_MANAGER_CONTRACTID "@mozilla.org/presentation-device/manager;1"
-#define PRESENTATION_DEVICE_CHANGE_TOPIC "presentation-device-change"
-%}
-
-/*
- * Manager for the device availability. User can observe "presentation-device-change"
- * for any update of the available devices.
- */
-[scriptable, uuid(beb61db5-3d5f-454f-a15a-dbfa0337c569)]
-interface nsIPresentationDeviceManager : nsISupports
-{
- // true if there is any device available.
- readonly attribute boolean deviceAvailable;
-
- /*
- * Register a device provider manually.
- * @param provider The device provider to add.
- */
- void addDeviceProvider(in nsIPresentationDeviceProvider provider);
-
- /*
- * Unregister a device provider manually.
- * @param provider The device provider to remove.
- */
- void removeDeviceProvider(in nsIPresentationDeviceProvider provider);
-
- /*
- * Force all registered device providers to update device information.
- */
- void forceDiscovery();
-
- /*
- * Retrieve all available devices or all available devices that supports
- * designated presentation URLs, return a list of nsIPresentationDevice.
- * The returned list is a cached device list and could be out-of-date.
- * Observe device change events to get following updates.
- * @param presentationUrls the target presentation URLs for device filtering
- */
- nsIArray getAvailableDevices([optional] in nsIArray presentationUrls);
-};
-
diff --git a/dom/presentation/interfaces/nsIPresentationDevicePrompt.idl b/dom/presentation/interfaces/nsIPresentationDevicePrompt.idl
deleted file mode 100644
index 2900eb59c..000000000
--- a/dom/presentation/interfaces/nsIPresentationDevicePrompt.idl
+++ /dev/null
@@ -1,58 +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 "nsISupports.idl"
-
-interface nsIArray;
-interface nsIDOMEventTarget;
-interface nsIPresentationDevice;
-interface nsIPrincipal;
-
-%{C++
-#define PRESENTATION_DEVICE_PROMPT_CONTRACTID "@mozilla.org/presentation-device/prompt;1"
-%}
-
-/*
- * The information and callbacks for device selection
- */
-[scriptable, uuid(b2aa7f6a-9448-446a-bba4-9c29638b0ed4)]
-interface nsIPresentationDeviceRequest : nsISupports
-{
- // The origin which initiate the request.
- readonly attribute DOMString origin;
-
- // The array of candidate URLs.
- readonly attribute nsIArray requestURLs;
-
- // The XUL browser element that the request was originated in.
- readonly attribute nsIDOMEventTarget chromeEventHandler;
-
- // The principal of the request.
- readonly attribute nsIPrincipal principal;
-
- /*
- * Callback after selecting a device
- * @param device The selected device.
- */
- void select(in nsIPresentationDevice device);
-
- /*
- * Callback after selection failed or canceled by user.
- * @param reason The error cause for canceling this request.
- */
- void cancel(in nsresult reason);
-};
-
-/*
- * UI prompt for device selection.
- */
-[scriptable, uuid(ac1a7e44-de86-454f-a9f1-276de2539831)]
-interface nsIPresentationDevicePrompt : nsISupports
-{
- /*
- * Request a device selection.
- * @param request The information and callbacks of this selection request.
- */
- void promptDeviceSelection(in nsIPresentationDeviceRequest request);
-};
diff --git a/dom/presentation/interfaces/nsIPresentationDeviceProvider.idl b/dom/presentation/interfaces/nsIPresentationDeviceProvider.idl
deleted file mode 100644
index b2c5e530c..000000000
--- a/dom/presentation/interfaces/nsIPresentationDeviceProvider.idl
+++ /dev/null
@@ -1,75 +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 "nsISupports.idl"
-
-interface nsIPresentationDevice;
-interface nsIPresentationControlChannel;
-
-%{C++
-#define PRESENTATION_DEVICE_PROVIDER_CATEGORY "presentation-device-provider"
-%}
-
-/*
- * The callbacks for any device updates and session request.
- */
-[scriptable, uuid(46fd372b-2e40-4179-9b36-0478d141e440)]
-interface nsIPresentationDeviceListener: nsISupports
-{
- void addDevice(in nsIPresentationDevice device);
- void removeDevice(in nsIPresentationDevice device);
- void updateDevice(in nsIPresentationDevice device);
-
- /*
- * Callback while the remote device is requesting to start a presentation session.
- * @param device The remote device that sent session request.
- * @param url The URL requested to open by remote device.
- * @param presentationId The Id for representing this session.
- * @param controlChannel The control channel for this session.
- */
- void onSessionRequest(in nsIPresentationDevice device,
- in DOMString url,
- in DOMString presentationId,
- in nsIPresentationControlChannel controlChannel);
-
- /*
- * Callback while the remote device is requesting to terminate a presentation session.
- * @param device The remote device that sent session request.
- * @param presentationId The Id for representing this session.
- * @param controlChannel The control channel for this session.
- * @param aIsFromReceiver true if termination is initiated by receiver.
- */
- void onTerminateRequest(in nsIPresentationDevice device,
- in DOMString presentationId,
- in nsIPresentationControlChannel controlChannel,
- in boolean aIsFromReceiver);
-
- /*
- * Callback while the remote device is requesting to reconnect a presentation session.
- * @param device The remote device that sent session request.
- * @param aUrl The URL requested to open by remote device.
- * @param presentationId The Id for representing this session.
- * @param controlChannel The control channel for this session.
- */
- void onReconnectRequest(in nsIPresentationDevice device,
- in DOMString url,
- in DOMString presentationId,
- in nsIPresentationControlChannel controlChannel);
-};
-
-/*
- * Device provider for any device protocol, can be registered as default
- * providers by adding its contractID to category "presentation-device-provider".
- */
-[scriptable, uuid(3db2578a-0f50-44ad-b01b-28427b71b7bf)]
-interface nsIPresentationDeviceProvider: nsISupports
-{
- // The listener for handling any device update.
- attribute nsIPresentationDeviceListener listener;
-
- /*
- * Force to update device information.
- */
- void forceDiscovery();
-};
diff --git a/dom/presentation/interfaces/nsIPresentationListener.idl b/dom/presentation/interfaces/nsIPresentationListener.idl
deleted file mode 100644
index 546c2fd4b..000000000
--- a/dom/presentation/interfaces/nsIPresentationListener.idl
+++ /dev/null
@@ -1,50 +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 "nsISupports.idl"
-
-[ref] native URLArrayRef(const nsTArray<nsString>);
-
-[uuid(0105f837-4279-4715-9d5b-2dc3f8b65353)]
-interface nsIPresentationAvailabilityListener : nsISupports
-{
- /*
- * Called when device availability changes.
- */
- [noscript] void notifyAvailableChange(in URLArrayRef urls,
- in bool available);
-};
-
-[scriptable, uuid(7dd48df8-8f8c-48c7-ac37-7b9fd1acf2f8)]
-interface nsIPresentationSessionListener : nsISupports
-{
- const unsigned short STATE_CONNECTING = 0;
- const unsigned short STATE_CONNECTED = 1;
- const unsigned short STATE_CLOSED = 2;
- const unsigned short STATE_TERMINATED = 3;
-
- /*
- * Called when session state changes.
- */
- void notifyStateChange(in DOMString sessionId,
- in unsigned short state,
- in nsresult reason);
-
- /*
- * Called when receive messages.
- */
- void notifyMessage(in DOMString sessionId,
- in ACString data,
- in boolean isBinary);
-};
-
-[scriptable, uuid(27f101d7-9ed1-429e-b4f8-43b00e8e111c)]
-interface nsIPresentationRespondingListener : nsISupports
-{
- /*
- * Called when an incoming session connects.
- */
- void notifySessionConnect(in unsigned long long windowId,
- in DOMString sessionId);
-};
diff --git a/dom/presentation/interfaces/nsIPresentationLocalDevice.idl b/dom/presentation/interfaces/nsIPresentationLocalDevice.idl
deleted file mode 100644
index 80e3b4041..000000000
--- a/dom/presentation/interfaces/nsIPresentationLocalDevice.idl
+++ /dev/null
@@ -1,17 +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 "nsIPresentationDevice.idl"
-
-/*
- * Local device.
- * This device is used for 1-UA use case. The result for display is rendered by
- * this host device.
- */
-[scriptable, uuid(dd239720-cab6-4fb5-9025-cba23f1bbc2d)]
-interface nsIPresentationLocalDevice : nsIPresentationDevice
-{
- // (1-UA only) The property is used to get the window ID of 1-UA device.
- readonly attribute AUTF8String windowId;
-};
diff --git a/dom/presentation/interfaces/nsIPresentationNetworkHelper.idl b/dom/presentation/interfaces/nsIPresentationNetworkHelper.idl
deleted file mode 100644
index 514075dfa..000000000
--- a/dom/presentation/interfaces/nsIPresentationNetworkHelper.idl
+++ /dev/null
@@ -1,36 +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 "nsISupports.idl"
-
-%{C++
-#define PRESENTATION_NETWORK_HELPER_CONTRACTID \
- "@mozilla.org/presentation-device/networkHelper;1"
-%}
-
-[scriptable, uuid(0a7e134f-ff80-4e73-91e6-12b3134fe568)]
-interface nsIPresentationNetworkHelperListener : nsISupports
-{
- /**
- * Called when error occurs.
- * @param aReason error message.
- */
- void onError(in AUTF8String aReason);
-
- /**
- * Called when get Wi-Fi IP address.
- * @param aIPAddress the IP address of Wi-Fi interface.
- */
- void onGetWifiIPAddress(in AUTF8String aIPAddress);
-};
-
-[scriptable, uuid(650dc16b-3d9c-49a6-9037-1d6f2d18c90c)]
-interface nsIPresentationNetworkHelper : nsISupports
-{
- /**
- * Get IP address of Wi-Fi interface.
- * @param aListener the callback interface.
- */
- void getWifiIPAddress(in nsIPresentationNetworkHelperListener aListener);
-};
diff --git a/dom/presentation/interfaces/nsIPresentationRequestUIGlue.idl b/dom/presentation/interfaces/nsIPresentationRequestUIGlue.idl
deleted file mode 100644
index dab1991e4..000000000
--- a/dom/presentation/interfaces/nsIPresentationRequestUIGlue.idl
+++ /dev/null
@@ -1,29 +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 "nsISupports.idl"
-
-interface nsIPresentationDevice;
-
-%{C++
-#define PRESENTATION_REQUEST_UI_GLUE_CONTRACTID \
- "@mozilla.org/presentation/requestuiglue;1"
-%}
-
-[scriptable, uuid(faa45119-6fb5-496c-aa4c-f740177a38b5)]
-interface nsIPresentationRequestUIGlue : nsISupports
-{
- /*
- * This method is called to open the responding app/page when
- * a presentation request comes in at receiver side.
- *
- * @param url The url of the request.
- * @param sessionId The session ID of the request.
- *
- * @return A promise that resolves to the opening frame.
- */
- nsISupports sendRequest(in DOMString url,
- in DOMString sessionId,
- in nsIPresentationDevice device);
-};
diff --git a/dom/presentation/interfaces/nsIPresentationService.idl b/dom/presentation/interfaces/nsIPresentationService.idl
deleted file mode 100644
index c3c15bb9f..000000000
--- a/dom/presentation/interfaces/nsIPresentationService.idl
+++ /dev/null
@@ -1,275 +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 "nsISupports.idl"
-
-interface nsIDOMBlob;
-interface nsIDOMEventTarget;
-interface nsIInputStream;
-interface nsIPresentationAvailabilityListener;
-interface nsIPresentationRespondingListener;
-interface nsIPresentationSessionListener;
-interface nsIPresentationTransportBuilderConstructor;
-interface nsIPrincipal;
-
-%{C++
-#define PRESENTATION_SERVICE_CID \
- { 0x1d9bb10c, 0xc0ab, 0x4fe8, \
- { 0x9e, 0x4f, 0x40, 0x58, 0xb8, 0x51, 0x98, 0x32 } }
-#define PRESENTATION_SERVICE_CONTRACTID \
- "@mozilla.org/presentation/presentationservice;1"
-
-#include "nsTArray.h"
-
-class nsString;
-%}
-
-[ref] native URLArrayRef(const nsTArray<nsString>);
-
-[scriptable, uuid(12073206-0065-4b10-9488-a6eb9b23e65b)]
-interface nsIPresentationServiceCallback : nsISupports
-{
- /*
- * Called when the operation succeeds.
- *
- * @param url: the selected request url used to start or reconnect a session.
- */
- void notifySuccess(in DOMString url);
-
- /*
- * Called when the operation fails.
- *
- * @param error: error message.
- */
- void notifyError(in nsresult error);
-};
-
-[scriptable, uuid(de42b741-5619-4650-b961-c2cebb572c95)]
-interface nsIPresentationService : nsISupports
-{
- const unsigned short ROLE_CONTROLLER = 0x1;
- const unsigned short ROLE_RECEIVER = 0x2;
-
- const unsigned short CLOSED_REASON_ERROR = 0x1;
- const unsigned short CLOSED_REASON_CLOSED = 0x2;
- const unsigned short CLOSED_REASON_WENTAWAY = 0x3;
-
- /*
- * Start a new presentation session and display a prompt box which asks users
- * to select a device.
- *
- * @param urls: The candidate Urls of presenting page. Only one url would be used.
- * @param sessionId: An ID to identify presentation session.
- * @param origin: The url of requesting page.
- * @param deviceId: The specified device of handling this request, null string
- * for prompt device selection dialog.
- * @param windowId: The inner window ID associated with the presentation
- * session. (0 implies no window ID since no actual window
- * uses 0 as its ID. Generally it's the case the window is
- * located in different process from this service)
- * @param eventTarget: The chrome event handler, in particular XUL browser
- * element in parent process, that the request was
- * originated in.
- * @param principal: The principal that initiated the session.
- * @param callback: Invoke the callback when the operation is completed.
- * NotifySuccess() is called with |id| if a session is
- * established successfully with the selected device.
- * Otherwise, NotifyError() is called with a error message.
- * @param constructor: The constructor for creating a transport builder.
- */
- [noscript] void startSession(in URLArrayRef urls,
- in DOMString sessionId,
- in DOMString origin,
- in DOMString deviceId,
- in unsigned long long windowId,
- in nsIDOMEventTarget eventTarget,
- in nsIPrincipal principal,
- in nsIPresentationServiceCallback callback,
- in nsIPresentationTransportBuilderConstructor constructor);
-
- /*
- * Send the message to the session.
- *
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- * @param data: the message being sent out.
- */
- void sendSessionMessage(in DOMString sessionId,
- in uint8_t role,
- in DOMString data);
-
- /*
- * Send the binary message to the session.
- *
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- * @param data: the message being sent out.
- */
- void sendSessionBinaryMsg(in DOMString sessionId,
- in uint8_t role,
- in ACString data);
-
- /*
- * Send the blob to the session.
- *
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- * @param blob: The input blob to be sent.
- */
- void sendSessionBlob(in DOMString sessionId,
- in uint8_t role,
- in nsIDOMBlob blob);
-
- /*
- * Close the session.
- *
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- */
- void closeSession(in DOMString sessionId,
- in uint8_t role,
- in uint8_t closedReason);
-
- /*
- * Terminate the session.
- *
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- */
- void terminateSession(in DOMString sessionId,
- in uint8_t role);
-
- /*
- * Reconnect the session.
- *
- * @param url: The request Urls.
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- * @param callback: NotifySuccess() is called when a control channel
- * is opened successfully.
- * Otherwise, NotifyError() is called with a error message.
- */
- [noscript] void reconnectSession(in URLArrayRef urls,
- in DOMString sessionId,
- in uint8_t role,
- in nsIPresentationServiceCallback callback);
-
- /*
- * Register an availability listener. Must be called from the main thread.
- *
- * @param availabilityUrls: The Urls that this listener is interested in.
- * @param listener: The listener to register.
- */
- [noscript] void registerAvailabilityListener(
- in URLArrayRef availabilityUrls,
- in nsIPresentationAvailabilityListener listener);
-
- /*
- * Unregister an availability listener. Must be called from the main thread.
- *
- * @param availabilityUrls: The Urls that are registered before.
- * @param listener: The listener to unregister.
- */
- [noscript] void unregisterAvailabilityListener(
- in URLArrayRef availabilityUrls,
- in nsIPresentationAvailabilityListener listener);
-
- /*
- * Register a session listener. Must be called from the main thread.
- *
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- * @param listener: The listener to register.
- */
- void registerSessionListener(in DOMString sessionId,
- in uint8_t role,
- in nsIPresentationSessionListener listener);
-
- /*
- * Unregister a session listener. Must be called from the main thread.
- *
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- */
- void unregisterSessionListener(in DOMString sessionId,
- in uint8_t role);
-
- /*
- * Register a responding listener. Must be called from the main thread.
- *
- * @param windowId: The window ID associated with the listener.
- * @param listener: The listener to register.
- */
- void registerRespondingListener(in unsigned long long windowId,
- in nsIPresentationRespondingListener listener);
-
- /*
- * Unregister a responding listener. Must be called from the main thread.
- * @param windowId: The window ID associated with the listener.
- */
- void unregisterRespondingListener(in unsigned long long windowId);
-
- /*
- * Notify the receiver page is ready for presentation use.
- *
- * @param sessionId An ID to identify presentation session.
- * @param windowId The inner window ID associated with the presentation
- * session.
- * @param isLoading true if receiver page is loading successfully.
- * @param constructor: The constructor for creating a transport builder.
- */
- void notifyReceiverReady(in DOMString sessionId,
- in unsigned long long windowId,
- in boolean isLoading,
- in nsIPresentationTransportBuilderConstructor constructor);
-
- /*
- * Notify the transport is closed
- *
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- * @param reason: the error message. NS_OK indicates it is closed normally.
- */
- void NotifyTransportClosed(in DOMString sessionId,
- in uint8_t role,
- in nsresult reason);
-
- /*
- * Untrack the relevant info about the presentation session if there's any.
- *
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- */
- void untrackSessionInfo(in DOMString sessionId, in uint8_t role);
-
- /*
- * The windowId for building RTCDataChannel session transport
- *
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- */
- unsigned long long getWindowIdBySessionId(in DOMString sessionId,
- in uint8_t role);
-
- /*
- * Update the mapping of the session ID and window ID.
- *
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- * @param windowId: The inner window ID associated with the presentation
- * session.
- */
- void updateWindowIdBySessionId(in DOMString sessionId,
- in uint8_t role,
- in unsigned long long windowId);
-
- /*
- * To build the session transport.
- * NOTE: This function should be only called at controller side.
- *
- * @param sessionId: An ID to identify presentation session.
- * @param role: Identify the function called by controller or receiver.
- */
- void buildTransport(in DOMString sessionId, in uint8_t role);
-};
diff --git a/dom/presentation/interfaces/nsIPresentationSessionRequest.idl b/dom/presentation/interfaces/nsIPresentationSessionRequest.idl
deleted file mode 100644
index 45a0e314c..000000000
--- a/dom/presentation/interfaces/nsIPresentationSessionRequest.idl
+++ /dev/null
@@ -1,35 +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 "nsISupports.idl"
-
-interface nsIPresentationDevice;
-interface nsIPresentationControlChannel;
-
-%{C++
-#define PRESENTATION_SESSION_REQUEST_TOPIC "presentation-session-request"
-#define PRESENTATION_RECONNECT_REQUEST_TOPIC "presentation-reconnect-request"
-%}
-
-/*
- * The event of a device requesting for starting or reconnecting
- * a presentation session. User can monitor the session request
- * on every device by observing "presentation-sesion-request" for a
- * new session and "presentation-reconnect-request" for reconnecting.
- */
-[scriptable, uuid(d808a084-d0f8-455a-a8df-5879e05a755b)]
-interface nsIPresentationSessionRequest: nsISupports
-{
- // The device which requesting the presentation session.
- readonly attribute nsIPresentationDevice device;
-
- // The URL requested to open by remote device.
- readonly attribute DOMString url;
-
- // The Id for representing this session.
- readonly attribute DOMString presentationId;
-
- // The control channel for this session.
- readonly attribute nsIPresentationControlChannel controlChannel;
-};
diff --git a/dom/presentation/interfaces/nsIPresentationSessionTransport.idl b/dom/presentation/interfaces/nsIPresentationSessionTransport.idl
deleted file mode 100644
index a0b5617d7..000000000
--- a/dom/presentation/interfaces/nsIPresentationSessionTransport.idl
+++ /dev/null
@@ -1,69 +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 "nsISupports.idl"
-
-interface nsIDOMBlob;
-interface nsIInputStream;
-interface nsINetAddr;
-
-%{C++
-#define PRESENTATION_TCP_SESSION_TRANSPORT_CONTRACTID \
- "@mozilla.org/presentation/presentationtcpsessiontransport;1"
-%}
-
-/*
- * The callback for session transport events.
- */
-[scriptable, uuid(9f158786-41a6-4a10-b29b-9497f25d4b67)]
-interface nsIPresentationSessionTransportCallback : nsISupports
-{
- void notifyTransportReady();
- void notifyTransportClosed(in nsresult reason);
- void notifyData(in ACString data, in boolean isBinary);
-};
-
-/*
- * App-to-App transport channel for the presentation session.
- */
-[scriptable, uuid(670b7e1b-65be-42b6-a596-be571907fa18)]
-interface nsIPresentationSessionTransport : nsISupports
-{
- // Should be set once the underlying session transport is built
- attribute nsIPresentationSessionTransportCallback callback;
-
- // valid for TCP session transport
- readonly attribute nsINetAddr selfAddress;
-
- /*
- * Enable the notification for incoming data. |notifyData| of
- * |nsIPresentationSessionTransportCallback| can start getting invoked.
- * Should set callback before |enableDataNotification| is called.
- */
- void enableDataNotification();
-
- /*
- * Send message to the remote endpoint.
- * @param data The message to send.
- */
- void send(in DOMString data);
-
- /*
- * Send the binary message to the remote endpoint.
- * @param data: the message being sent out.
- */
- void sendBinaryMsg(in ACString data);
-
- /*
- * Send the blob to the remote endpoint.
- * @param blob: The input blob to be sent.
- */
- void sendBlob(in nsIDOMBlob blob);
-
- /*
- * Close this session transport.
- * @param reason The reason for closing this session transport.
- */
- void close(in nsresult reason);
-};
diff --git a/dom/presentation/interfaces/nsIPresentationSessionTransportBuilder.idl b/dom/presentation/interfaces/nsIPresentationSessionTransportBuilder.idl
deleted file mode 100644
index 969f37d71..000000000
--- a/dom/presentation/interfaces/nsIPresentationSessionTransportBuilder.idl
+++ /dev/null
@@ -1,80 +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 "nsISupports.idl"
-
-interface nsIPresentationChannelDescription;
-interface nsISocketTransport;
-interface mozIDOMWindow;
-interface nsIPresentationControlChannel;
-interface nsIPresentationSessionTransport;
-
-[scriptable, uuid(673f6de1-e253-41b8-9be8-b7ff161fa8dc)]
-interface nsIPresentationSessionTransportBuilderListener : nsISupports
-{
- // Should set |transport.callback| in |onSessionTransport|.
- void onSessionTransport(in nsIPresentationSessionTransport transport);
- void onError(in nsresult reason);
-
- void sendOffer(in nsIPresentationChannelDescription offer);
- void sendAnswer(in nsIPresentationChannelDescription answer);
- void sendIceCandidate(in DOMString candidate);
- void close(in nsresult reason);
-};
-
-[scriptable, uuid(2fdbe67d-80f9-48dc-8237-5bef8fa19801)]
-interface nsIPresentationSessionTransportBuilder : nsISupports
-{
-};
-
-/**
- * The constructor for creating a transport builder.
- */
-[scriptable, uuid(706482b2-1b51-4bed-a21d-785a9cfcfac7)]
-interface nsIPresentationTransportBuilderConstructor : nsISupports
-{
- nsIPresentationSessionTransportBuilder createTransportBuilder(in uint8_t type);
-};
-
-/**
- * Builder for TCP session transport
- */
-[scriptable, uuid(cde36d6e-f471-4262-a70d-f932a26b21d9)]
-interface nsIPresentationTCPSessionTransportBuilder : nsIPresentationSessionTransportBuilder
-{
- /**
- * The following creation functions will trigger |listener.onSessionTransport|
- * if the session transport is successfully built, |listener.onError| if some
- * error occurs during building session transport.
- */
- void buildTCPSenderTransport(in nsISocketTransport aTransport,
- in nsIPresentationSessionTransportBuilderListener aListener);
-
- void buildTCPReceiverTransport(in nsIPresentationChannelDescription aDescription,
- in nsIPresentationSessionTransportBuilderListener aListener);
-};
-
-/**
- * Builder for WebRTC data channel session transport
- */
-[scriptable, uuid(8131c4e0-3a8c-4bc1-a92a-8431473d2fe8)]
-interface nsIPresentationDataChannelSessionTransportBuilder : nsIPresentationSessionTransportBuilder
-{
- /**
- * The following creation function will trigger |listener.onSessionTransport|
- * if the session transport is successfully built, |listener.onError| if some
- * error occurs during creating session transport. The |notifyConnected| of
- * |aControlChannel| should be called before calling
- * |buildDataChannelTransport|.
- */
- void buildDataChannelTransport(in uint8_t aRole,
- in mozIDOMWindow aWindow,
- in nsIPresentationSessionTransportBuilderListener aListener);
-
- // Bug 1275150 - Merge TCP builder with the following APIs
- void onOffer(in nsIPresentationChannelDescription offer);
- void onAnswer(in nsIPresentationChannelDescription answer);
- void onIceCandidate(in DOMString candidate);
- void notifyDisconnected(in nsresult reason);
-};
diff --git a/dom/presentation/interfaces/nsIPresentationTerminateRequest.idl b/dom/presentation/interfaces/nsIPresentationTerminateRequest.idl
deleted file mode 100644
index a9f86fa0d..000000000
--- a/dom/presentation/interfaces/nsIPresentationTerminateRequest.idl
+++ /dev/null
@@ -1,33 +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 "nsISupports.idl"
-
-interface nsIPresentationDevice;
-interface nsIPresentationControlChannel;
-
-%{C++
-#define PRESENTATION_TERMINATE_REQUEST_TOPIC "presentation-terminate-request"
-%}
-
-/*
- * The event of a device requesting for terminating a presentation session. User can
- * monitor the terminate request on every device by observing "presentation-terminate-request".
- */
-[scriptable, uuid(3ddbf3a4-53ee-4b70-9bbc-58ac90dce6b5)]
-interface nsIPresentationTerminateRequest: nsISupports
-{
- // The device which requesting to terminate presentation session.
- readonly attribute nsIPresentationDevice device;
-
- // The Id for representing this session.
- readonly attribute DOMString presentationId;
-
- // The control channel for this session.
- // Should only use this channel to complete session termination.
- readonly attribute nsIPresentationControlChannel controlChannel;
-
- // True if termination is initiated by receiver.
- readonly attribute boolean isFromReceiver;
-};
diff --git a/dom/presentation/ipc/PPresentation.ipdl b/dom/presentation/ipc/PPresentation.ipdl
deleted file mode 100644
index e0f4d2888..000000000
--- a/dom/presentation/ipc/PPresentation.ipdl
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=8 et 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 PContent;
-include protocol PPresentationRequest;
-include protocol PPresentationBuilder;
-
-include InputStreamParams;
-
-using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
-using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
-
-namespace mozilla {
-namespace dom {
-
-struct StartSessionRequest
-{
- nsString[] urls;
- nsString sessionId;
- nsString origin;
- nsString deviceId;
- uint64_t windowId;
- TabId tabId;
- Principal principal;
-};
-
-struct SendSessionMessageRequest
-{
- nsString sessionId;
- uint8_t role;
- nsString data;
-};
-
-struct CloseSessionRequest
-{
- nsString sessionId;
- uint8_t role;
- uint8_t closedReason;
-};
-
-struct TerminateSessionRequest
-{
- nsString sessionId;
- uint8_t role;
-};
-
-struct ReconnectSessionRequest
-{
- nsString[] urls;
- nsString sessionId;
- uint8_t role;
-};
-
-struct BuildTransportRequest
-{
- nsString sessionId;
- uint8_t role;
-};
-
-union PresentationIPCRequest
-{
- StartSessionRequest;
- SendSessionMessageRequest;
- CloseSessionRequest;
- TerminateSessionRequest;
- ReconnectSessionRequest;
- BuildTransportRequest;
-};
-
-sync protocol PPresentation
-{
- manager PContent;
- manages PPresentationBuilder;
- manages PPresentationRequest;
-
-child:
- async NotifyAvailableChange(nsString[] aAvailabilityUrls,
- bool aAvailable);
- async NotifySessionStateChange(nsString aSessionId,
- uint16_t aState,
- nsresult aReason);
- async NotifyMessage(nsString aSessionId, nsCString aData, bool aIsBinary);
- async NotifySessionConnect(uint64_t aWindowId, nsString aSessionId);
- async NotifyCloseSessionTransport(nsString aSessionId,
- uint8_t aRole,
- nsresult aReason);
-
- async PPresentationBuilder(nsString aSessionId, uint8_t aRole);
-
-parent:
- async __delete__();
-
- async RegisterAvailabilityHandler(nsString[] aAvailabilityUrls);
- async UnregisterAvailabilityHandler(nsString[] aAvailabilityUrls);
-
- async RegisterSessionHandler(nsString aSessionId, uint8_t aRole);
- async UnregisterSessionHandler(nsString aSessionId, uint8_t aRole);
-
- async RegisterRespondingHandler(uint64_t aWindowId);
- async UnregisterRespondingHandler(uint64_t aWindowId);
-
- async PPresentationRequest(PresentationIPCRequest aRequest);
-
- async NotifyReceiverReady(nsString aSessionId, uint64_t aWindowId, bool aIsLoading);
- async NotifyTransportClosed(nsString aSessionId, uint8_t aRole, nsresult aReason);
-};
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/ipc/PPresentationBuilder.ipdl b/dom/presentation/ipc/PPresentationBuilder.ipdl
deleted file mode 100644
index e32b02e8f..000000000
--- a/dom/presentation/ipc/PPresentationBuilder.ipdl
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-include protocol PPresentation;
-
-namespace mozilla {
-namespace dom {
-
-async protocol PPresentationBuilder
-{
- manager PPresentation;
-
-parent:
- async SendOffer(nsString aSDP);
- async SendAnswer(nsString aSDP);
- async SendIceCandidate(nsString aCandidate);
- async Close(nsresult aReason);
-
- async OnSessionTransport();
- async OnSessionTransportError(nsresult aReason);
-
-child:
- async OnOffer(nsString aSDP);
- async OnAnswer(nsString aSDP);
- async OnIceCandidate(nsString aCandidate);
-
- async __delete__();
-};
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/ipc/PPresentationRequest.ipdl b/dom/presentation/ipc/PPresentationRequest.ipdl
deleted file mode 100644
index fa99dfcab..000000000
--- a/dom/presentation/ipc/PPresentationRequest.ipdl
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-include protocol PPresentation;
-
-namespace mozilla {
-namespace dom {
-
-sync protocol PPresentationRequest
-{
- manager PPresentation;
-
-child:
- async __delete__(nsresult result);
- async NotifyRequestUrlSelected(nsString aUrl);
-};
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/ipc/PresentationBuilderChild.cpp b/dom/presentation/ipc/PresentationBuilderChild.cpp
deleted file mode 100644
index 387332e9e..000000000
--- a/dom/presentation/ipc/PresentationBuilderChild.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "DCPresentationChannelDescription.h"
-#include "nsComponentManagerUtils.h"
-#include "nsGlobalWindow.h"
-#include "PresentationBuilderChild.h"
-#include "PresentationIPCService.h"
-#include "nsServiceManagerUtils.h"
-#include "mozilla/Unused.h"
-
-namespace mozilla {
-namespace dom {
-
-NS_IMPL_ISUPPORTS(PresentationBuilderChild,
- nsIPresentationSessionTransportBuilderListener)
-
-PresentationBuilderChild::PresentationBuilderChild(const nsString& aSessionId,
- uint8_t aRole)
- : mSessionId(aSessionId)
- , mRole(aRole)
-{
-}
-
-nsresult PresentationBuilderChild::Init()
-{
- mBuilder = do_CreateInstance("@mozilla.org/presentation/datachanneltransportbuilder;1");
- if (NS_WARN_IF(!mBuilder)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- uint64_t windowId = 0;
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- if (NS_WARN_IF(NS_FAILED(service->GetWindowIdBySessionId(
- mSessionId,
- mRole,
- &windowId)))) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- nsPIDOMWindowInner* window = nsGlobalWindow::GetInnerWindowWithId(windowId)->AsInner();
- if (NS_WARN_IF(!window)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return mBuilder->BuildDataChannelTransport(mRole, window, this);
-}
-
-void
-PresentationBuilderChild::ActorDestroy(ActorDestroyReason aWhy)
-{
- mBuilder = nullptr;
- mActorDestroyed = true;
-}
-
-bool
-PresentationBuilderChild::RecvOnOffer(const nsString& aSDP)
-{
- if (NS_WARN_IF(!mBuilder)) {
- return false;
- }
- RefPtr<DCPresentationChannelDescription> description =
- new DCPresentationChannelDescription(aSDP);
-
- if (NS_WARN_IF(NS_FAILED(mBuilder->OnOffer(description)))) {
- return false;
- }
- return true;
-}
-
-bool
-PresentationBuilderChild::RecvOnAnswer(const nsString& aSDP)
-{
- if (NS_WARN_IF(!mBuilder)) {
- return false;
- }
- RefPtr<DCPresentationChannelDescription> description =
- new DCPresentationChannelDescription(aSDP);
-
- if (NS_WARN_IF(NS_FAILED(mBuilder->OnAnswer(description)))) {
- return false;
- }
- return true;
-}
-
-bool
-PresentationBuilderChild::RecvOnIceCandidate(const nsString& aCandidate)
-{
- if (NS_WARN_IF(mBuilder && NS_FAILED(mBuilder->OnIceCandidate(aCandidate)))) {
- return false;
- }
- return true;
-}
-
-// nsPresentationSessionTransportBuilderListener
-NS_IMETHODIMP
-PresentationBuilderChild::OnSessionTransport(nsIPresentationSessionTransport* aTransport)
-{
- if (NS_WARN_IF(mActorDestroyed || !SendOnSessionTransport())){
- return NS_ERROR_FAILURE;
- }
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- NS_WARNING_ASSERTION(service, "no presentation service");
- if (service) {
- Unused << NS_WARN_IF(NS_FAILED(static_cast<PresentationIPCService*>(service.get())->
- NotifySessionTransport(mSessionId, mRole, aTransport)));
- }
- mBuilder = nullptr;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationBuilderChild::OnError(nsresult reason)
-{
- mBuilder = nullptr;
-
- if (NS_WARN_IF(mActorDestroyed || !SendOnSessionTransportError(reason))){
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationBuilderChild::SendOffer(nsIPresentationChannelDescription* aOffer)
-{
- nsAutoString SDP;
- nsresult rv = aOffer->GetDataChannelSDP(SDP);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- if (NS_WARN_IF(mActorDestroyed || !SendSendOffer(SDP))){
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationBuilderChild::SendAnswer(nsIPresentationChannelDescription* aAnswer)
-{
- nsAutoString SDP;
- nsresult rv = aAnswer->GetDataChannelSDP(SDP);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- if (NS_WARN_IF(mActorDestroyed || !SendSendAnswer(SDP))){
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationBuilderChild::SendIceCandidate(const nsAString& candidate)
-{
- if (NS_WARN_IF(mActorDestroyed || !SendSendIceCandidate(nsString(candidate)))) {
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationBuilderChild::Close(nsresult reason)
-{
- if (NS_WARN_IF(mActorDestroyed || !SendClose(reason))) {
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-} // namespace dom
-} // namespace mozilla
-
diff --git a/dom/presentation/ipc/PresentationBuilderChild.h b/dom/presentation/ipc/PresentationBuilderChild.h
deleted file mode 100644
index 5ada53ab7..000000000
--- a/dom/presentation/ipc/PresentationBuilderChild.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_PresentationBuilderChild_h
-#define mozilla_dom_PresentationBuilderChild_h
-
-#include "mozilla/dom/PPresentationBuilderChild.h"
-#include "nsIPresentationSessionTransportBuilder.h"
-
-namespace mozilla {
-namespace dom {
-
-class PresentationBuilderChild final: public PPresentationBuilderChild
- , public nsIPresentationSessionTransportBuilderListener
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONSESSIONTRANSPORTBUILDERLISTENER
-
- explicit PresentationBuilderChild(const nsString& aSessionId,
- uint8_t aRole);
-
- nsresult Init();
-
- virtual void ActorDestroy(ActorDestroyReason aWhy) override;
-
- virtual bool RecvOnOffer(const nsString& aSDP) override;
-
- virtual bool RecvOnAnswer(const nsString& aSDP) override;
-
- virtual bool RecvOnIceCandidate(const nsString& aCandidate) override;
-
-private:
- virtual ~PresentationBuilderChild() = default;
-
- nsString mSessionId;
- uint8_t mRole;
- bool mActorDestroyed = false;
- nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder> mBuilder;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationBuilderChild_h
diff --git a/dom/presentation/ipc/PresentationBuilderParent.cpp b/dom/presentation/ipc/PresentationBuilderParent.cpp
deleted file mode 100644
index dc784b13c..000000000
--- a/dom/presentation/ipc/PresentationBuilderParent.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "DCPresentationChannelDescription.h"
-#include "PresentationBuilderParent.h"
-#include "PresentationSessionInfo.h"
-
-namespace mozilla {
-namespace dom {
-
-namespace {
-
-class PresentationSessionTransportIPC final :
- public nsIPresentationSessionTransport
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONSESSIONTRANSPORT
-
- PresentationSessionTransportIPC(PresentationParent* aParent,
- const nsAString& aSessionId,
- uint8_t aRole)
- : mParent(aParent)
- , mSessionId(aSessionId)
- , mRole(aRole)
- {
- MOZ_ASSERT(mParent);
- }
-
-private:
- virtual ~PresentationSessionTransportIPC() = default;
-
- RefPtr<PresentationParent> mParent;
- nsString mSessionId;
- uint8_t mRole;
-};
-
-NS_IMPL_ISUPPORTS(PresentationSessionTransportIPC,
- nsIPresentationSessionTransport)
-
-NS_IMETHODIMP
-PresentationSessionTransportIPC::GetCallback(
- nsIPresentationSessionTransportCallback** aCallback)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationSessionTransportIPC::SetCallback(
- nsIPresentationSessionTransportCallback* aCallback)
-{
- if (aCallback) {
- aCallback->NotifyTransportReady();
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationSessionTransportIPC::GetSelfAddress(nsINetAddr** aSelfAddress)
-{
- MOZ_ASSERT(false, "Not expected.");
- return NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP
-PresentationSessionTransportIPC::EnableDataNotification()
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationSessionTransportIPC::Send(const nsAString& aData)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationSessionTransportIPC::SendBinaryMsg(const nsACString& aData)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationSessionTransportIPC::SendBlob(nsIDOMBlob* aBlob)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationSessionTransportIPC::Close(nsresult aReason)
-{
- if (NS_WARN_IF(!mParent->SendNotifyCloseSessionTransport(mSessionId,
- mRole,
- aReason))) {
- return NS_ERROR_FAILURE;
- }
-
- return NS_OK;
-}
-
-} // anonymous namespace
-
-NS_IMPL_ISUPPORTS(PresentationBuilderParent,
- nsIPresentationSessionTransportBuilder,
- nsIPresentationDataChannelSessionTransportBuilder)
-
-PresentationBuilderParent::PresentationBuilderParent(PresentationParent* aParent)
- : mParent(aParent)
-{
- MOZ_COUNT_CTOR(PresentationBuilderParent);
-}
-
-PresentationBuilderParent::~PresentationBuilderParent()
-{
- MOZ_COUNT_DTOR(PresentationBuilderParent);
-
- if (mNeedDestroyActor) {
- Unused << NS_WARN_IF(!Send__delete__(this));
- }
-}
-
-NS_IMETHODIMP
-PresentationBuilderParent::BuildDataChannelTransport(
- uint8_t aRole,
- mozIDOMWindow* aWindow, /* unused */
- nsIPresentationSessionTransportBuilderListener* aListener)
-{
- mBuilderListener = aListener;
-
- RefPtr<PresentationSessionInfo> info = static_cast<PresentationSessionInfo*>(aListener);
- nsAutoString sessionId(info->GetSessionId());
- if (NS_WARN_IF(!mParent->SendPPresentationBuilderConstructor(this,
- sessionId,
- aRole))) {
- return NS_ERROR_FAILURE;
- }
- mIPCSessionTransport = new PresentationSessionTransportIPC(mParent,
- sessionId,
- aRole);
- mNeedDestroyActor = true;
- mParent = nullptr;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationBuilderParent::OnIceCandidate(const nsAString& aCandidate)
-{
- if (NS_WARN_IF(!SendOnIceCandidate(nsString(aCandidate)))){
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationBuilderParent::OnOffer(nsIPresentationChannelDescription* aDescription)
-{
- nsAutoString SDP;
- nsresult rv = aDescription->GetDataChannelSDP(SDP);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- if (NS_WARN_IF(!SendOnOffer(SDP))){
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationBuilderParent::OnAnswer(nsIPresentationChannelDescription* aDescription)
-{
- nsAutoString SDP;
- nsresult rv = aDescription->GetDataChannelSDP(SDP);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- if (NS_WARN_IF(!SendOnAnswer(SDP))){
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationBuilderParent::NotifyDisconnected(nsresult aReason)
-{
- return NS_OK;
-}
-
-void
-PresentationBuilderParent::ActorDestroy(ActorDestroyReason aWhy)
-{
- mNeedDestroyActor = false;
- mParent = nullptr;
- mBuilderListener = nullptr;
-}
-
-bool
-PresentationBuilderParent::RecvSendOffer(const nsString& aSDP)
-{
- RefPtr<DCPresentationChannelDescription> description =
- new DCPresentationChannelDescription(aSDP);
- if (NS_WARN_IF(!mBuilderListener ||
- NS_FAILED(mBuilderListener->SendOffer(description)))) {
- return false;
- }
- return true;
-}
-
-bool
-PresentationBuilderParent::RecvSendAnswer(const nsString& aSDP)
-{
- RefPtr<DCPresentationChannelDescription> description =
- new DCPresentationChannelDescription(aSDP);
- if (NS_WARN_IF(!mBuilderListener ||
- NS_FAILED(mBuilderListener->SendAnswer(description)))) {
- return false;
- }
- return true;
-}
-
-bool
-PresentationBuilderParent::RecvSendIceCandidate(const nsString& aCandidate)
-{
- if (NS_WARN_IF(!mBuilderListener ||
- NS_FAILED(mBuilderListener->SendIceCandidate(aCandidate)))) {
- return false;
- }
- return true;
-}
-
-bool
-PresentationBuilderParent::RecvClose(const nsresult& aReason)
-{
- if (NS_WARN_IF(!mBuilderListener ||
- NS_FAILED(mBuilderListener->Close(aReason)))) {
- return false;
- }
- return true;
-}
-
-// Delegate to nsIPresentationSessionTransportBuilderListener
-bool
-PresentationBuilderParent::RecvOnSessionTransport()
-{
- RefPtr<PresentationBuilderParent> kungFuDeathGrip = this;
- Unused <<
- NS_WARN_IF(!mBuilderListener ||
- NS_FAILED(mBuilderListener->OnSessionTransport(mIPCSessionTransport)));
- return true;
-}
-
-bool
-PresentationBuilderParent::RecvOnSessionTransportError(const nsresult& aReason)
-{
- if (NS_WARN_IF(!mBuilderListener ||
- NS_FAILED(mBuilderListener->OnError(aReason)))) {
- return false;
- }
- return true;
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/ipc/PresentationBuilderParent.h b/dom/presentation/ipc/PresentationBuilderParent.h
deleted file mode 100644
index 7fd211ce5..000000000
--- a/dom/presentation/ipc/PresentationBuilderParent.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_PresentationBuilderParent_h__
-#define mozilla_dom_PresentationBuilderParent_h__
-
-#include "mozilla/dom/PPresentationBuilderParent.h"
-#include "PresentationParent.h"
-#include "nsIPresentationSessionTransportBuilder.h"
-
-namespace mozilla {
-namespace dom {
-
-class PresentationBuilderParent final: public PPresentationBuilderParent
- , public nsIPresentationDataChannelSessionTransportBuilder
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONSESSIONTRANSPORTBUILDER
- NS_DECL_NSIPRESENTATIONDATACHANNELSESSIONTRANSPORTBUILDER
-
- explicit PresentationBuilderParent(PresentationParent* aParent);
-
- virtual bool RecvSendOffer(const nsString& aSDP) override;
-
- virtual bool RecvSendAnswer(const nsString& aSDP) override;
-
- virtual bool RecvSendIceCandidate(const nsString& aCandidate) override;
-
- virtual bool RecvClose(const nsresult& aReason) override;
-
- virtual void ActorDestroy(ActorDestroyReason aWhy) override;
-
- virtual bool RecvOnSessionTransport() override;
-
- virtual bool RecvOnSessionTransportError(const nsresult& aReason) override;
-
-private:
- virtual ~PresentationBuilderParent();
- bool mNeedDestroyActor = false;
- RefPtr<PresentationParent> mParent;
- nsCOMPtr<nsIPresentationSessionTransportBuilderListener> mBuilderListener;
- nsCOMPtr<nsIPresentationSessionTransport> mIPCSessionTransport;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationBuilderParent_h__
diff --git a/dom/presentation/ipc/PresentationChild.cpp b/dom/presentation/ipc/PresentationChild.cpp
deleted file mode 100644
index d24ba9e8c..000000000
--- a/dom/presentation/ipc/PresentationChild.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "DCPresentationChannelDescription.h"
-#include "mozilla/StaticPtr.h"
-#include "PresentationBuilderChild.h"
-#include "PresentationChild.h"
-#include "PresentationIPCService.h"
-#include "nsThreadUtils.h"
-
-using namespace mozilla;
-using namespace mozilla::dom;
-
-/*
- * Implementation of PresentationChild
- */
-
-PresentationChild::PresentationChild(PresentationIPCService* aService)
- : mActorDestroyed(false)
- , mService(aService)
-{
- MOZ_ASSERT(mService);
-
- MOZ_COUNT_CTOR(PresentationChild);
-}
-
-PresentationChild::~PresentationChild()
-{
- MOZ_COUNT_DTOR(PresentationChild);
-
- if (!mActorDestroyed) {
- Send__delete__(this);
- }
- mService = nullptr;
-}
-
-void
-PresentationChild::ActorDestroy(ActorDestroyReason aWhy)
-{
- mActorDestroyed = true;
- mService->NotifyPresentationChildDestroyed();
- mService = nullptr;
-}
-
-PPresentationRequestChild*
-PresentationChild::AllocPPresentationRequestChild(const PresentationIPCRequest& aRequest)
-{
- NS_NOTREACHED("We should never be manually allocating PPresentationRequestChild actors");
- return nullptr;
-}
-
-bool
-PresentationChild::DeallocPPresentationRequestChild(PPresentationRequestChild* aActor)
-{
- delete aActor;
- return true;
-}
-
-bool PresentationChild::RecvPPresentationBuilderConstructor(
- PPresentationBuilderChild* aActor,
- const nsString& aSessionId,
- const uint8_t& aRole)
-{
- // Child will build the session transport
- PresentationBuilderChild* actor = static_cast<PresentationBuilderChild*>(aActor);
- return NS_WARN_IF(NS_FAILED(actor->Init())) ? false : true;
-}
-
-PPresentationBuilderChild*
-PresentationChild::AllocPPresentationBuilderChild(const nsString& aSessionId,
- const uint8_t& aRole)
-{
- RefPtr<PresentationBuilderChild> actor
- = new PresentationBuilderChild(aSessionId, aRole);
-
- return actor.forget().take();
-}
-
-bool
-PresentationChild::DeallocPPresentationBuilderChild(PPresentationBuilderChild* aActor)
-{
- RefPtr<PresentationBuilderChild> actor =
- dont_AddRef(static_cast<PresentationBuilderChild*>(aActor));
- return true;
-}
-
-
-bool
-PresentationChild::RecvNotifyAvailableChange(
- nsTArray<nsString>&& aAvailabilityUrls,
- const bool& aAvailable)
-{
- if (mService) {
- Unused <<
- NS_WARN_IF(NS_FAILED(mService->NotifyAvailableChange(aAvailabilityUrls,
- aAvailable)));
- }
- return true;
-}
-
-bool
-PresentationChild::RecvNotifySessionStateChange(const nsString& aSessionId,
- const uint16_t& aState,
- const nsresult& aReason)
-{
- if (mService) {
- Unused << NS_WARN_IF(NS_FAILED(mService->NotifySessionStateChange(aSessionId,
- aState,
- aReason)));
- }
- return true;
-}
-
-bool
-PresentationChild::RecvNotifyMessage(const nsString& aSessionId,
- const nsCString& aData,
- const bool& aIsBinary)
-{
- if (mService) {
- Unused << NS_WARN_IF(NS_FAILED(mService->NotifyMessage(aSessionId,
- aData,
- aIsBinary)));
- }
- return true;
-}
-
-bool
-PresentationChild::RecvNotifySessionConnect(const uint64_t& aWindowId,
- const nsString& aSessionId)
-{
- if (mService) {
- Unused << NS_WARN_IF(NS_FAILED(mService->NotifySessionConnect(aWindowId, aSessionId)));
- }
- return true;
-}
-
-bool
-PresentationChild::RecvNotifyCloseSessionTransport(const nsString& aSessionId,
- const uint8_t& aRole,
- const nsresult& aReason)
-{
- if (mService) {
- Unused << NS_WARN_IF(NS_FAILED(
- mService->CloseContentSessionTransport(aSessionId, aRole, aReason)));
- }
- return true;
-}
-
-/*
- * Implementation of PresentationRequestChild
- */
-
-PresentationRequestChild::PresentationRequestChild(nsIPresentationServiceCallback* aCallback)
- : mActorDestroyed(false)
- , mCallback(aCallback)
-{
- MOZ_COUNT_CTOR(PresentationRequestChild);
-}
-
-PresentationRequestChild::~PresentationRequestChild()
-{
- MOZ_COUNT_DTOR(PresentationRequestChild);
-
- mCallback = nullptr;
-}
-
-void
-PresentationRequestChild::ActorDestroy(ActorDestroyReason aWhy)
-{
- mActorDestroyed = true;
- mCallback = nullptr;
-}
-
-bool
-PresentationRequestChild::Recv__delete__(const nsresult& aResult)
-{
- if (mActorDestroyed) {
- return true;
- }
-
- if (mCallback) {
- if (NS_FAILED(aResult)) {
- Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifyError(aResult)));
- }
- }
-
- return true;
-}
-
-bool
-PresentationRequestChild::RecvNotifyRequestUrlSelected(const nsString& aUrl)
-{
- Unused << NS_WARN_IF(NS_FAILED(mCallback->NotifySuccess(aUrl)));
- return true;
-}
diff --git a/dom/presentation/ipc/PresentationChild.h b/dom/presentation/ipc/PresentationChild.h
deleted file mode 100644
index 1c625b8ce..000000000
--- a/dom/presentation/ipc/PresentationChild.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_PresentationChild_h
-#define mozilla_dom_PresentationChild_h
-
-#include "mozilla/dom/PPresentationBuilderChild.h"
-#include "mozilla/dom/PPresentationChild.h"
-#include "mozilla/dom/PPresentationRequestChild.h"
-
-class nsIPresentationServiceCallback;
-
-namespace mozilla {
-namespace dom {
-
-class PresentationIPCService;
-
-class PresentationChild final : public PPresentationChild
-{
-public:
- explicit PresentationChild(PresentationIPCService* aService);
-
- virtual void
- ActorDestroy(ActorDestroyReason aWhy) override;
-
- virtual PPresentationRequestChild*
- AllocPPresentationRequestChild(const PresentationIPCRequest& aRequest) override;
-
- virtual bool
- DeallocPPresentationRequestChild(PPresentationRequestChild* aActor) override;
-
- bool RecvPPresentationBuilderConstructor(PPresentationBuilderChild* aActor,
- const nsString& aSessionId,
- const uint8_t& aRole) override;
-
- virtual PPresentationBuilderChild*
- AllocPPresentationBuilderChild(const nsString& aSessionId, const uint8_t& aRole) override;
-
- virtual bool
- DeallocPPresentationBuilderChild(PPresentationBuilderChild* aActor) override;
-
- virtual bool
- RecvNotifyAvailableChange(nsTArray<nsString>&& aAvailabilityUrls,
- const bool& aAvailable) override;
-
- virtual bool
- RecvNotifySessionStateChange(const nsString& aSessionId,
- const uint16_t& aState,
- const nsresult& aReason) override;
-
- virtual bool
- RecvNotifyMessage(const nsString& aSessionId,
- const nsCString& aData,
- const bool& aIsBinary) override;
-
- virtual bool
- RecvNotifySessionConnect(const uint64_t& aWindowId,
- const nsString& aSessionId) override;
-
- virtual bool
- RecvNotifyCloseSessionTransport(const nsString& aSessionId,
- const uint8_t& aRole,
- const nsresult& aReason) override;
-
-private:
- virtual ~PresentationChild();
-
- bool mActorDestroyed = false;
- RefPtr<PresentationIPCService> mService;
-};
-
-class PresentationRequestChild final : public PPresentationRequestChild
-{
- friend class PresentationChild;
-
-public:
- explicit PresentationRequestChild(nsIPresentationServiceCallback* aCallback);
-
- virtual void
- ActorDestroy(ActorDestroyReason aWhy) override;
-
- virtual bool
- Recv__delete__(const nsresult& aResult) override;
-
- virtual bool
- RecvNotifyRequestUrlSelected(const nsString& aUrl) override;
-
-private:
- virtual ~PresentationRequestChild();
-
- bool mActorDestroyed = false;
- nsCOMPtr<nsIPresentationServiceCallback> mCallback;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationChild_h
diff --git a/dom/presentation/ipc/PresentationContentSessionInfo.cpp b/dom/presentation/ipc/PresentationContentSessionInfo.cpp
deleted file mode 100644
index 071ea924f..000000000
--- a/dom/presentation/ipc/PresentationContentSessionInfo.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/* -*- 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/. */
-
-#include "nsServiceManagerUtils.h"
-#include "PresentationContentSessionInfo.h"
-#include "PresentationIPCService.h"
-
-namespace mozilla {
-namespace dom {
-
-NS_IMPL_ISUPPORTS(PresentationContentSessionInfo,
- nsIPresentationSessionTransportCallback);
-
-nsresult
-PresentationContentSessionInfo::Init() {
- if (NS_WARN_IF(NS_FAILED(mTransport->SetCallback(this)))) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- if (NS_WARN_IF(NS_FAILED(mTransport->EnableDataNotification()))) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- return NS_OK;
-}
-
-nsresult
-PresentationContentSessionInfo::Send(const nsAString& aData)
-{
- if (!mTransport) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return mTransport->Send(aData);
-}
-
-nsresult
-PresentationContentSessionInfo::SendBinaryMsg(const nsACString& aData)
-{
- if (NS_WARN_IF(!mTransport)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return mTransport->SendBinaryMsg(aData);
-}
-
-nsresult
-PresentationContentSessionInfo::SendBlob(nsIDOMBlob* aBlob)
-{
- if (NS_WARN_IF(!mTransport)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return mTransport->SendBlob(aBlob);
-}
-
-nsresult
-PresentationContentSessionInfo::Close(nsresult aReason)
-{
- if (!mTransport) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return mTransport->Close(aReason);
-}
-
-// nsIPresentationSessionTransportCallback
-NS_IMETHODIMP
-PresentationContentSessionInfo::NotifyTransportReady()
-{
- // do nothing since |onSessionTransport| implies this
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationContentSessionInfo::NotifyTransportClosed(nsresult aReason)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- // Nullify |mTransport| here so it won't try to re-close |mTransport| in
- // potential subsequent |Shutdown| calls.
- mTransport = nullptr;
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- return static_cast<PresentationIPCService*>(service.get())->
- NotifyTransportClosed(mSessionId, mRole, aReason);
-}
-
-NS_IMETHODIMP
-PresentationContentSessionInfo::NotifyData(const nsACString& aData,
- bool aIsBinary)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- nsCOMPtr<nsIPresentationService> service =
- do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- if (NS_WARN_IF(!service)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- return static_cast<PresentationIPCService*>(service.get())->
- NotifyMessage(mSessionId, aData, aIsBinary);
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/ipc/PresentationContentSessionInfo.h b/dom/presentation/ipc/PresentationContentSessionInfo.h
deleted file mode 100644
index 447485dbd..000000000
--- a/dom/presentation/ipc/PresentationContentSessionInfo.h
+++ /dev/null
@@ -1,62 +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_PresentationContentSessionInfo_h
-#define mozilla_dom_PresentationContentSessionInfo_h
-
-#include "nsCOMPtr.h"
-#include "nsIPresentationSessionTransport.h"
-
-namespace mozilla {
-namespace dom {
-
-/**
- * PresentationContentSessionInfo manages nsIPresentationSessionTransport and
- * delegates the callbacks to PresentationIPCService. Only lives in content
- * process.
- */
-class PresentationContentSessionInfo final : public nsIPresentationSessionTransportCallback
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONSESSIONTRANSPORTCALLBACK
-
- PresentationContentSessionInfo(const nsAString& aSessionId,
- uint8_t aRole,
- nsIPresentationSessionTransport* aTransport)
- : mSessionId(aSessionId)
- , mRole(aRole)
- , mTransport(aTransport)
- {
- MOZ_ASSERT(XRE_IsContentProcess());
- MOZ_ASSERT(!aSessionId.IsEmpty());
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
- MOZ_ASSERT(aTransport);
- }
-
- nsresult Init();
-
- nsresult Send(const nsAString& aData);
-
- nsresult SendBinaryMsg(const nsACString& aData);
-
- nsresult SendBlob(nsIDOMBlob* aBlob);
-
- nsresult Close(nsresult aReason);
-
-private:
- virtual ~PresentationContentSessionInfo() {}
-
- nsString mSessionId;
- uint8_t mRole;
- nsCOMPtr<nsIPresentationSessionTransport> mTransport;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationContentSessionInfo_h
diff --git a/dom/presentation/ipc/PresentationIPCService.cpp b/dom/presentation/ipc/PresentationIPCService.cpp
deleted file mode 100644
index 8c85b239d..000000000
--- a/dom/presentation/ipc/PresentationIPCService.cpp
+++ /dev/null
@@ -1,538 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=8 et 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 "mozilla/dom/ContentChild.h"
-#include "mozilla/dom/PermissionMessageUtils.h"
-#include "mozilla/dom/PPresentation.h"
-#include "mozilla/dom/TabParent.h"
-#include "mozilla/ipc/InputStreamUtils.h"
-#include "mozilla/ipc/URIUtils.h"
-#include "nsGlobalWindow.h"
-#include "nsIPresentationListener.h"
-#include "PresentationCallbacks.h"
-#include "PresentationChild.h"
-#include "PresentationContentSessionInfo.h"
-#include "PresentationIPCService.h"
-#include "PresentationLog.h"
-
-using namespace mozilla;
-using namespace mozilla::dom;
-using namespace mozilla::ipc;
-
-namespace {
-
-PresentationChild* sPresentationChild;
-
-} // anonymous
-
-NS_IMPL_ISUPPORTS(PresentationIPCService,
- nsIPresentationService,
- nsIPresentationAvailabilityListener)
-
-PresentationIPCService::PresentationIPCService()
-{
- ContentChild* contentChild = ContentChild::GetSingleton();
- if (NS_WARN_IF(!contentChild)) {
- return;
- }
- sPresentationChild = new PresentationChild(this);
- Unused <<
- NS_WARN_IF(!contentChild->SendPPresentationConstructor(sPresentationChild));
-}
-
-/* virtual */
-PresentationIPCService::~PresentationIPCService()
-{
- Shutdown();
-
- mSessionListeners.Clear();
- mSessionInfoAtController.Clear();
- mSessionInfoAtReceiver.Clear();
- sPresentationChild = nullptr;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::StartSession(
- const nsTArray<nsString>& aUrls,
- const nsAString& aSessionId,
- const nsAString& aOrigin,
- const nsAString& aDeviceId,
- uint64_t aWindowId,
- nsIDOMEventTarget* aEventTarget,
- nsIPrincipal* aPrincipal,
- nsIPresentationServiceCallback* aCallback,
- nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
-{
- if (aWindowId != 0) {
- AddRespondingSessionId(aWindowId,
- aSessionId,
- nsIPresentationService::ROLE_CONTROLLER);
- }
-
- nsPIDOMWindowInner* window =
- nsGlobalWindow::GetInnerWindowWithId(aWindowId)->AsInner();
- TabId tabId = TabParent::GetTabIdFrom(window->GetDocShell());
-
- return SendRequest(aCallback, StartSessionRequest(aUrls,
- nsString(aSessionId),
- nsString(aOrigin),
- nsString(aDeviceId),
- aWindowId,
- tabId,
- IPC::Principal(aPrincipal)));
-}
-
-NS_IMETHODIMP
-PresentationIPCService::SendSessionMessage(const nsAString& aSessionId,
- uint8_t aRole,
- const nsAString& aData)
-{
- MOZ_ASSERT(!aSessionId.IsEmpty());
- MOZ_ASSERT(!aData.IsEmpty());
-
- RefPtr<PresentationContentSessionInfo> info =
- GetSessionInfo(aSessionId, aRole);
- // data channel session transport is maintained by content process
- if (info) {
- return info->Send(aData);
- }
-
- return SendRequest(nullptr, SendSessionMessageRequest(nsString(aSessionId),
- aRole,
- nsString(aData)));
-}
-
-NS_IMETHODIMP
-PresentationIPCService::SendSessionBinaryMsg(const nsAString& aSessionId,
- uint8_t aRole,
- const nsACString &aData)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!aData.IsEmpty());
- MOZ_ASSERT(!aSessionId.IsEmpty());
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
-
- RefPtr<PresentationContentSessionInfo> info =
- GetSessionInfo(aSessionId, aRole);
- // data channel session transport is maintained by content process
- if (info) {
- return info->SendBinaryMsg(aData);
- }
-
- return NS_ERROR_NOT_AVAILABLE;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::SendSessionBlob(const nsAString& aSessionId,
- uint8_t aRole,
- nsIDOMBlob* aBlob)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!aSessionId.IsEmpty());
- MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
- aRole == nsIPresentationService::ROLE_RECEIVER);
- MOZ_ASSERT(aBlob);
-
- RefPtr<PresentationContentSessionInfo> info =
- GetSessionInfo(aSessionId, aRole);
- // data channel session transport is maintained by content process
- if (info) {
- return info->SendBlob(aBlob);
- }
-
- return NS_ERROR_NOT_AVAILABLE;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::CloseSession(const nsAString& aSessionId,
- uint8_t aRole,
- uint8_t aClosedReason)
-{
- MOZ_ASSERT(!aSessionId.IsEmpty());
-
- nsresult rv = SendRequest(nullptr, CloseSessionRequest(nsString(aSessionId),
- aRole,
- aClosedReason));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- RefPtr<PresentationContentSessionInfo> info =
- GetSessionInfo(aSessionId, aRole);
- if (info) {
- return info->Close(NS_OK);
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::TerminateSession(const nsAString& aSessionId,
- uint8_t aRole)
-{
- MOZ_ASSERT(!aSessionId.IsEmpty());
-
- nsresult rv = SendRequest(nullptr, TerminateSessionRequest(nsString(aSessionId), aRole));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- RefPtr<PresentationContentSessionInfo> info =
- GetSessionInfo(aSessionId, aRole);
- if (info) {
- return info->Close(NS_OK);
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::ReconnectSession(const nsTArray<nsString>& aUrls,
- const nsAString& aSessionId,
- uint8_t aRole,
- nsIPresentationServiceCallback* aCallback)
-{
- MOZ_ASSERT(!aSessionId.IsEmpty());
-
- if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
- MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
- return NS_ERROR_INVALID_ARG;
- }
-
- return SendRequest(aCallback, ReconnectSessionRequest(aUrls,
- nsString(aSessionId),
- aRole));
-}
-
-NS_IMETHODIMP
-PresentationIPCService::BuildTransport(const nsAString& aSessionId,
- uint8_t aRole)
-{
- MOZ_ASSERT(!aSessionId.IsEmpty());
-
- if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
- MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
- return NS_ERROR_INVALID_ARG;
- }
-
- return SendRequest(nullptr, BuildTransportRequest(nsString(aSessionId),
- aRole));
-}
-
-nsresult
-PresentationIPCService::SendRequest(nsIPresentationServiceCallback* aCallback,
- const PresentationIPCRequest& aRequest)
-{
- if (sPresentationChild) {
- PresentationRequestChild* actor = new PresentationRequestChild(aCallback);
- Unused << NS_WARN_IF(!sPresentationChild->SendPPresentationRequestConstructor(actor, aRequest));
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::RegisterAvailabilityListener(
- const nsTArray<nsString>& aAvailabilityUrls,
- nsIPresentationAvailabilityListener* aListener)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!aAvailabilityUrls.IsEmpty());
- MOZ_ASSERT(aListener);
-
- nsTArray<nsString> addedUrls;
- mAvailabilityManager.AddAvailabilityListener(aAvailabilityUrls,
- aListener,
- addedUrls);
-
- if (sPresentationChild && !addedUrls.IsEmpty()) {
- Unused <<
- NS_WARN_IF(
- !sPresentationChild->SendRegisterAvailabilityHandler(addedUrls));
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::UnregisterAvailabilityListener(
- const nsTArray<nsString>& aAvailabilityUrls,
- nsIPresentationAvailabilityListener* aListener)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- nsTArray<nsString> removedUrls;
- mAvailabilityManager.RemoveAvailabilityListener(aAvailabilityUrls,
- aListener,
- removedUrls);
-
- if (sPresentationChild && !removedUrls.IsEmpty()) {
- Unused <<
- NS_WARN_IF(
- !sPresentationChild->SendUnregisterAvailabilityHandler(removedUrls));
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId,
- uint8_t aRole,
- nsIPresentationSessionListener* aListener)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aListener);
-
- nsCOMPtr<nsIPresentationSessionListener> listener;
- if (mSessionListeners.Get(aSessionId, getter_AddRefs(listener))) {
- mSessionListeners.Put(aSessionId, aListener);
- return NS_OK;
- }
-
- mSessionListeners.Put(aSessionId, aListener);
- if (sPresentationChild) {
- Unused <<
- NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(
- nsString(aSessionId), aRole));
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId,
- uint8_t aRole)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- UntrackSessionInfo(aSessionId, aRole);
-
- mSessionListeners.Remove(aSessionId);
- if (sPresentationChild) {
- Unused <<
- NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(
- nsString(aSessionId), aRole));
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::RegisterRespondingListener(uint64_t aWindowId,
- nsIPresentationRespondingListener* aListener)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- mRespondingListeners.Put(aWindowId, aListener);
- if (sPresentationChild) {
- Unused <<
- NS_WARN_IF(!sPresentationChild->SendRegisterRespondingHandler(aWindowId));
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::UnregisterRespondingListener(uint64_t aWindowId)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- mRespondingListeners.Remove(aWindowId);
- if (sPresentationChild) {
- Unused <<
- NS_WARN_IF(!sPresentationChild->SendUnregisterRespondingHandler(
- aWindowId));
- }
- return NS_OK;
-}
-
-nsresult
-PresentationIPCService::NotifySessionTransport(const nsString& aSessionId,
- const uint8_t& aRole,
- nsIPresentationSessionTransport* aTransport)
-{
- RefPtr<PresentationContentSessionInfo> info =
- new PresentationContentSessionInfo(aSessionId, aRole, aTransport);
-
- if (NS_WARN_IF(NS_FAILED(info->Init()))) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
- mSessionInfoAtController.Put(aSessionId, info);
- } else {
- mSessionInfoAtReceiver.Put(aSessionId, info);
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::GetWindowIdBySessionId(const nsAString& aSessionId,
- uint8_t aRole,
- uint64_t* aWindowId)
-{
- return GetWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId);
-}
-
-NS_IMETHODIMP
-PresentationIPCService::UpdateWindowIdBySessionId(const nsAString& aSessionId,
- uint8_t aRole,
- const uint64_t aWindowId)
-{
- return UpdateWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId);
-}
-
-nsresult
-PresentationIPCService::NotifySessionStateChange(const nsAString& aSessionId,
- uint16_t aState,
- nsresult aReason)
-{
- nsCOMPtr<nsIPresentationSessionListener> listener;
- if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) {
- return NS_OK;
- }
-
- return listener->NotifyStateChange(aSessionId, aState, aReason);
-}
-
-// Only used for OOP RTCDataChannel session transport case.
-nsresult
-PresentationIPCService::NotifyMessage(const nsAString& aSessionId,
- const nsACString& aData,
- const bool& aIsBinary)
-{
- nsCOMPtr<nsIPresentationSessionListener> listener;
- if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) {
- return NS_OK;
- }
-
- return listener->NotifyMessage(aSessionId, aData, aIsBinary);
-}
-
-// Only used for OOP RTCDataChannel session transport case.
-nsresult
-PresentationIPCService::NotifyTransportClosed(const nsAString& aSessionId,
- uint8_t aRole,
- nsresult aReason)
-{
- RefPtr<PresentationContentSessionInfo> info =
- GetSessionInfo(aSessionId, aRole);
- if (NS_WARN_IF(!info)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- Unused << NS_WARN_IF(!sPresentationChild->SendNotifyTransportClosed(nsString(aSessionId), aRole, aReason));
- return NS_OK;
-}
-
-nsresult
-PresentationIPCService::NotifySessionConnect(uint64_t aWindowId,
- const nsAString& aSessionId)
-{
- nsCOMPtr<nsIPresentationRespondingListener> listener;
- if (NS_WARN_IF(!mRespondingListeners.Get(aWindowId, getter_AddRefs(listener)))) {
- return NS_OK;
- }
-
- return listener->NotifySessionConnect(aWindowId, aSessionId);
-}
-
-NS_IMETHODIMP
-PresentationIPCService::NotifyAvailableChange(
- const nsTArray<nsString>& aAvailabilityUrls,
- bool aAvailable)
-{
- return mAvailabilityManager.DoNotifyAvailableChange(aAvailabilityUrls,
- aAvailable);
-}
-
-NS_IMETHODIMP
-PresentationIPCService::NotifyReceiverReady(
- const nsAString& aSessionId,
- uint64_t aWindowId,
- bool aIsLoading,
- nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- // No actual window uses 0 as its ID.
- if (NS_WARN_IF(aWindowId == 0)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- // Track the responding info for an OOP receiver page.
- AddRespondingSessionId(aWindowId,
- aSessionId,
- nsIPresentationService::ROLE_RECEIVER);
-
- Unused << NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsString(aSessionId),
- aWindowId,
- aIsLoading));
-
- // Release mCallback after using aSessionId
- // because aSessionId is held by mCallback.
- mCallback = nullptr;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationIPCService::UntrackSessionInfo(const nsAString& aSessionId,
- uint8_t aRole)
-{
- PRES_DEBUG("content %s:id[%s], role[%d]\n", __func__,
- NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);
-
- if (nsIPresentationService::ROLE_RECEIVER == aRole) {
- // Terminate receiver page.
- uint64_t windowId;
- if (NS_SUCCEEDED(GetWindowIdBySessionIdInternal(aSessionId,
- aRole,
- &windowId))) {
- NS_DispatchToMainThread(NS_NewRunnableFunction([windowId]() -> void {
- PRES_DEBUG("Attempt to close window[%d]\n", windowId);
-
- if (auto* window = nsGlobalWindow::GetInnerWindowWithId(windowId)) {
- window->Close();
- }
- }));
- }
- }
-
- // Remove the OOP responding info (if it has never been used).
- RemoveRespondingSessionId(aSessionId, aRole);
-
- if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
- mSessionInfoAtController.Remove(aSessionId);
- } else {
- mSessionInfoAtReceiver.Remove(aSessionId);
- }
-
- return NS_OK;
-}
-
-void
-PresentationIPCService::NotifyPresentationChildDestroyed()
-{
- sPresentationChild = nullptr;
-}
-
-nsresult
-PresentationIPCService::MonitorResponderLoading(const nsAString& aSessionId,
- nsIDocShell* aDocShell)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- mCallback = new PresentationResponderLoadingCallback(aSessionId);
- return mCallback->Init(aDocShell);
-}
-
-nsresult
-PresentationIPCService::CloseContentSessionTransport(const nsString& aSessionId,
- uint8_t aRole,
- nsresult aReason)
-{
- RefPtr<PresentationContentSessionInfo> info =
- GetSessionInfo(aSessionId, aRole);
- if (NS_WARN_IF(!info)) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return info->Close(aReason);
-}
diff --git a/dom/presentation/ipc/PresentationIPCService.h b/dom/presentation/ipc/PresentationIPCService.h
deleted file mode 100644
index 5eab7e68a..000000000
--- a/dom/presentation/ipc/PresentationIPCService.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=8 et 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/. */
-
-#ifndef mozilla_dom_PresentationIPCService_h
-#define mozilla_dom_PresentationIPCService_h
-
-#include "mozilla/dom/PresentationServiceBase.h"
-#include "nsIPresentationListener.h"
-#include "nsIPresentationSessionTransport.h"
-#include "nsIPresentationService.h"
-
-class nsIDocShell;
-
-namespace mozilla {
-namespace dom {
-
-class PresentationIPCRequest;
-class PresentationContentSessionInfo;
-class PresentationResponderLoadingCallback;
-
-class PresentationIPCService final
- : public nsIPresentationAvailabilityListener
- , public nsIPresentationService
- , public PresentationServiceBase<PresentationContentSessionInfo>
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONAVAILABILITYLISTENER
- NS_DECL_NSIPRESENTATIONSERVICE
-
- PresentationIPCService();
-
- nsresult NotifySessionStateChange(const nsAString& aSessionId,
- uint16_t aState,
- nsresult aReason);
-
- nsresult NotifyMessage(const nsAString& aSessionId,
- const nsACString& aData,
- const bool& aIsBinary);
-
- nsresult NotifySessionConnect(uint64_t aWindowId,
- const nsAString& aSessionId);
-
- void NotifyPresentationChildDestroyed();
-
- nsresult MonitorResponderLoading(const nsAString& aSessionId,
- nsIDocShell* aDocShell);
-
- nsresult NotifySessionTransport(const nsString& aSessionId,
- const uint8_t& aRole,
- nsIPresentationSessionTransport* transport);
-
- nsresult CloseContentSessionTransport(const nsString& aSessionId,
- uint8_t aRole,
- nsresult aReason);
-
-private:
- virtual ~PresentationIPCService();
- nsresult SendRequest(nsIPresentationServiceCallback* aCallback,
- const PresentationIPCRequest& aRequest);
-
- nsRefPtrHashtable<nsStringHashKey,
- nsIPresentationSessionListener> mSessionListeners;
- nsRefPtrHashtable<nsUint64HashKey,
- nsIPresentationRespondingListener> mRespondingListeners;
- RefPtr<PresentationResponderLoadingCallback> mCallback;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationIPCService_h
diff --git a/dom/presentation/ipc/PresentationParent.cpp b/dom/presentation/ipc/PresentationParent.cpp
deleted file mode 100644
index 02f60500a..000000000
--- a/dom/presentation/ipc/PresentationParent.cpp
+++ /dev/null
@@ -1,553 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "DCPresentationChannelDescription.h"
-#include "mozilla/dom/ContentProcessManager.h"
-#include "mozilla/ipc/InputStreamUtils.h"
-#include "mozilla/Unused.h"
-#include "nsIPresentationDeviceManager.h"
-#include "nsIPresentationSessionTransport.h"
-#include "nsIPresentationSessionTransportBuilder.h"
-#include "nsServiceManagerUtils.h"
-#include "PresentationBuilderParent.h"
-#include "PresentationParent.h"
-#include "PresentationService.h"
-#include "PresentationSessionInfo.h"
-
-namespace mozilla {
-namespace dom {
-
-namespace {
-
-class PresentationTransportBuilderConstructorIPC final :
- public nsIPresentationTransportBuilderConstructor
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONTRANSPORTBUILDERCONSTRUCTOR
-
- explicit PresentationTransportBuilderConstructorIPC(PresentationParent* aParent)
- : mParent(aParent)
- {
- }
-
-private:
- virtual ~PresentationTransportBuilderConstructorIPC() = default;
-
- RefPtr<PresentationParent> mParent;
-};
-
-NS_IMPL_ISUPPORTS(PresentationTransportBuilderConstructorIPC,
- nsIPresentationTransportBuilderConstructor)
-
-NS_IMETHODIMP
-PresentationTransportBuilderConstructorIPC::CreateTransportBuilder(
- uint8_t aType,
- nsIPresentationSessionTransportBuilder** aRetval)
-{
- if (NS_WARN_IF(!aRetval)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- *aRetval = nullptr;
-
- if (NS_WARN_IF(aType != nsIPresentationChannelDescription::TYPE_TCP &&
- aType != nsIPresentationChannelDescription::TYPE_DATACHANNEL)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- if (XRE_IsContentProcess()) {
- MOZ_ASSERT(false,
- "CreateTransportBuilder can only be invoked in parent process.");
- return NS_ERROR_FAILURE;
- }
-
- nsCOMPtr<nsIPresentationSessionTransportBuilder> builder;
- if (aType == nsIPresentationChannelDescription::TYPE_TCP) {
- builder = do_CreateInstance(PRESENTATION_TCP_SESSION_TRANSPORT_CONTRACTID);
- } else {
- builder = new PresentationBuilderParent(mParent);
- }
-
- if (NS_WARN_IF(!builder)) {
- return NS_ERROR_DOM_OPERATION_ERR;
- }
-
- builder.forget(aRetval);
- return NS_OK;
-}
-
-} // anonymous namespace
-
-/*
- * Implementation of PresentationParent
- */
-
-NS_IMPL_ISUPPORTS(PresentationParent,
- nsIPresentationAvailabilityListener,
- nsIPresentationSessionListener,
- nsIPresentationRespondingListener)
-
-PresentationParent::PresentationParent()
-{
- MOZ_COUNT_CTOR(PresentationParent);
-}
-
-/* virtual */ PresentationParent::~PresentationParent()
-{
- MOZ_COUNT_DTOR(PresentationParent);
-}
-
-bool
-PresentationParent::Init(ContentParentId aContentParentId)
-{
- MOZ_ASSERT(!mService);
- mService = do_GetService(PRESENTATION_SERVICE_CONTRACTID);
- mChildId = aContentParentId;
- return NS_WARN_IF(!mService) ? false : true;
-}
-
-void
-PresentationParent::ActorDestroy(ActorDestroyReason aWhy)
-{
- mActorDestroyed = true;
-
- for (uint32_t i = 0; i < mSessionIdsAtController.Length(); i++) {
- Unused << NS_WARN_IF(NS_FAILED(mService->
- UnregisterSessionListener(mSessionIdsAtController[i],
- nsIPresentationService::ROLE_CONTROLLER)));
- }
- mSessionIdsAtController.Clear();
-
- for (uint32_t i = 0; i < mSessionIdsAtReceiver.Length(); i++) {
- Unused << NS_WARN_IF(NS_FAILED(mService->
- UnregisterSessionListener(mSessionIdsAtReceiver[i], nsIPresentationService::ROLE_RECEIVER)));
- }
- mSessionIdsAtReceiver.Clear();
-
- for (uint32_t i = 0; i < mWindowIds.Length(); i++) {
- Unused << NS_WARN_IF(NS_FAILED(mService->
- UnregisterRespondingListener(mWindowIds[i])));
- }
- mWindowIds.Clear();
-
- if (!mContentAvailabilityUrls.IsEmpty()) {
- mService->UnregisterAvailabilityListener(mContentAvailabilityUrls, this);
- }
- mService = nullptr;
-}
-
-bool
-PresentationParent::RecvPPresentationRequestConstructor(
- PPresentationRequestParent* aActor,
- const PresentationIPCRequest& aRequest)
-{
- PresentationRequestParent* actor = static_cast<PresentationRequestParent*>(aActor);
-
- nsresult rv = NS_ERROR_FAILURE;
- switch (aRequest.type()) {
- case PresentationIPCRequest::TStartSessionRequest:
- rv = actor->DoRequest(aRequest.get_StartSessionRequest());
- break;
- case PresentationIPCRequest::TSendSessionMessageRequest:
- rv = actor->DoRequest(aRequest.get_SendSessionMessageRequest());
- break;
- case PresentationIPCRequest::TCloseSessionRequest:
- rv = actor->DoRequest(aRequest.get_CloseSessionRequest());
- break;
- case PresentationIPCRequest::TTerminateSessionRequest:
- rv = actor->DoRequest(aRequest.get_TerminateSessionRequest());
- break;
- case PresentationIPCRequest::TReconnectSessionRequest:
- rv = actor->DoRequest(aRequest.get_ReconnectSessionRequest());
- break;
- case PresentationIPCRequest::TBuildTransportRequest:
- rv = actor->DoRequest(aRequest.get_BuildTransportRequest());
- break;
- default:
- MOZ_CRASH("Unknown PresentationIPCRequest type");
- }
-
- return NS_WARN_IF(NS_FAILED(rv)) ? false : true;
-}
-
-PPresentationRequestParent*
-PresentationParent::AllocPPresentationRequestParent(
- const PresentationIPCRequest& aRequest)
-{
- MOZ_ASSERT(mService);
- RefPtr<PresentationRequestParent> actor = new PresentationRequestParent(mService, mChildId);
- return actor.forget().take();
-}
-
-bool
-PresentationParent::DeallocPPresentationRequestParent(
- PPresentationRequestParent* aActor)
-{
- RefPtr<PresentationRequestParent> actor =
- dont_AddRef(static_cast<PresentationRequestParent*>(aActor));
- return true;
-}
-
-PPresentationBuilderParent*
-PresentationParent::AllocPPresentationBuilderParent(const nsString& aSessionId,
- const uint8_t& aRole)
-{
- NS_NOTREACHED("We should never be manually allocating AllocPPresentationBuilderParent actors");
- return nullptr;
-}
-
-bool
-PresentationParent::DeallocPPresentationBuilderParent(
- PPresentationBuilderParent* aActor)
-{
- return true;
-}
-
-bool
-PresentationParent::Recv__delete__()
-{
- return true;
-}
-
-bool
-PresentationParent::RecvRegisterAvailabilityHandler(
- nsTArray<nsString>&& aAvailabilityUrls)
-{
- MOZ_ASSERT(mService);
-
- Unused << NS_WARN_IF(NS_FAILED(mService->RegisterAvailabilityListener(
- aAvailabilityUrls,
- this)));
- mContentAvailabilityUrls.AppendElements(aAvailabilityUrls);
- return true;
-}
-
-bool
-PresentationParent::RecvUnregisterAvailabilityHandler(
- nsTArray<nsString>&& aAvailabilityUrls)
-{
- MOZ_ASSERT(mService);
-
- Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterAvailabilityListener(
- aAvailabilityUrls,
- this)));
- for (const auto& url : aAvailabilityUrls) {
- mContentAvailabilityUrls.RemoveElement(url);
- }
- return true;
-}
-
-/* virtual */ bool
-PresentationParent::RecvRegisterSessionHandler(const nsString& aSessionId,
- const uint8_t& aRole)
-{
- MOZ_ASSERT(mService);
-
- // Validate the accessibility (primarily for receiver side) so that a
- // compromised child process can't fake the ID.
- if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
- IsSessionAccessible(aSessionId, aRole, OtherPid()))) {
- return true;
- }
-
- if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
- mSessionIdsAtController.AppendElement(aSessionId);
- } else {
- mSessionIdsAtReceiver.AppendElement(aSessionId);
- }
- Unused << NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, aRole, this)));
- return true;
-}
-
-/* virtual */ bool
-PresentationParent::RecvUnregisterSessionHandler(const nsString& aSessionId,
- const uint8_t& aRole)
-{
- MOZ_ASSERT(mService);
- if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
- mSessionIdsAtController.RemoveElement(aSessionId);
- } else {
- mSessionIdsAtReceiver.RemoveElement(aSessionId);
- }
- Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterSessionListener(aSessionId, aRole)));
- return true;
-}
-
-/* virtual */ bool
-PresentationParent::RecvRegisterRespondingHandler(const uint64_t& aWindowId)
-{
- MOZ_ASSERT(mService);
-
- mWindowIds.AppendElement(aWindowId);
- Unused << NS_WARN_IF(NS_FAILED(mService->RegisterRespondingListener(aWindowId, this)));
- return true;
-}
-
-/* virtual */ bool
-PresentationParent::RecvUnregisterRespondingHandler(const uint64_t& aWindowId)
-{
- MOZ_ASSERT(mService);
- mWindowIds.RemoveElement(aWindowId);
- Unused << NS_WARN_IF(NS_FAILED(mService->UnregisterRespondingListener(aWindowId)));
- return true;
-}
-
-NS_IMETHODIMP
-PresentationParent::NotifyAvailableChange(const nsTArray<nsString>& aAvailabilityUrls,
- bool aAvailable)
-{
- if (NS_WARN_IF(mActorDestroyed ||
- !SendNotifyAvailableChange(aAvailabilityUrls,
- aAvailable))) {
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationParent::NotifyStateChange(const nsAString& aSessionId,
- uint16_t aState,
- nsresult aReason)
-{
- if (NS_WARN_IF(mActorDestroyed ||
- !SendNotifySessionStateChange(nsString(aSessionId),
- aState,
- aReason))) {
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationParent::NotifyMessage(const nsAString& aSessionId,
- const nsACString& aData,
- bool aIsBinary)
-{
- if (NS_WARN_IF(mActorDestroyed ||
- !SendNotifyMessage(nsString(aSessionId),
- nsCString(aData),
- aIsBinary))) {
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-PresentationParent::NotifySessionConnect(uint64_t aWindowId,
- const nsAString& aSessionId)
-{
- if (NS_WARN_IF(mActorDestroyed ||
- !SendNotifySessionConnect(aWindowId, nsString(aSessionId)))) {
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-bool
-PresentationParent::RecvNotifyReceiverReady(const nsString& aSessionId,
- const uint64_t& aWindowId,
- const bool& aIsLoading)
-{
- MOZ_ASSERT(mService);
-
- nsCOMPtr<nsIPresentationTransportBuilderConstructor> constructor =
- new PresentationTransportBuilderConstructorIPC(this);
- Unused << NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId,
- aWindowId,
- aIsLoading,
- constructor)));
- return true;
-}
-
-bool
-PresentationParent::RecvNotifyTransportClosed(const nsString& aSessionId,
- const uint8_t& aRole,
- const nsresult& aReason)
-{
- MOZ_ASSERT(mService);
-
- Unused << NS_WARN_IF(NS_FAILED(mService->NotifyTransportClosed(aSessionId, aRole, aReason)));
- return true;
-}
-
-/*
- * Implementation of PresentationRequestParent
- */
-
-NS_IMPL_ISUPPORTS(PresentationRequestParent, nsIPresentationServiceCallback)
-
-PresentationRequestParent::PresentationRequestParent(nsIPresentationService* aService,
- ContentParentId aContentParentId)
- : mService(aService)
- , mChildId(aContentParentId)
-{
- MOZ_COUNT_CTOR(PresentationRequestParent);
-}
-
-PresentationRequestParent::~PresentationRequestParent()
-{
- MOZ_COUNT_DTOR(PresentationRequestParent);
-}
-
-void
-PresentationRequestParent::ActorDestroy(ActorDestroyReason aWhy)
-{
- mActorDestroyed = true;
- mService = nullptr;
-}
-
-nsresult
-PresentationRequestParent::DoRequest(const StartSessionRequest& aRequest)
-{
- MOZ_ASSERT(mService);
-
- mSessionId = aRequest.sessionId();
-
- nsCOMPtr<nsIDOMEventTarget> eventTarget;
- ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
- RefPtr<TabParent> tp =
- cpm->GetTopLevelTabParentByProcessAndTabId(mChildId, aRequest.tabId());
- if (tp) {
- eventTarget = do_QueryInterface(tp->GetOwnerElement());
- }
-
- RefPtr<PresentationParent> parent = static_cast<PresentationParent*>(Manager());
- nsCOMPtr<nsIPresentationTransportBuilderConstructor> constructor =
- new PresentationTransportBuilderConstructorIPC(parent);
- return mService->StartSession(aRequest.urls(), aRequest.sessionId(),
- aRequest.origin(), aRequest.deviceId(),
- aRequest.windowId(), eventTarget,
- aRequest.principal(), this, constructor);
-}
-
-nsresult
-PresentationRequestParent::DoRequest(const SendSessionMessageRequest& aRequest)
-{
- MOZ_ASSERT(mService);
-
- // Validate the accessibility (primarily for receiver side) so that a
- // compromised child process can't fake the ID.
- if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
- IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
- return SendResponse(NS_ERROR_DOM_SECURITY_ERR);
- }
-
- nsresult rv = mService->SendSessionMessage(aRequest.sessionId(),
- aRequest.role(),
- aRequest.data());
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return SendResponse(rv);
- }
- return SendResponse(NS_OK);
-}
-
-nsresult
-PresentationRequestParent::DoRequest(const CloseSessionRequest& aRequest)
-{
- MOZ_ASSERT(mService);
-
- // Validate the accessibility (primarily for receiver side) so that a
- // compromised child process can't fake the ID.
- if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
- IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
- return SendResponse(NS_ERROR_DOM_SECURITY_ERR);
- }
-
- nsresult rv = mService->CloseSession(aRequest.sessionId(),
- aRequest.role(),
- aRequest.closedReason());
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return SendResponse(rv);
- }
- return SendResponse(NS_OK);
-}
-
-nsresult
-PresentationRequestParent::DoRequest(const TerminateSessionRequest& aRequest)
-{
- MOZ_ASSERT(mService);
-
- // Validate the accessibility (primarily for receiver side) so that a
- // compromised child process can't fake the ID.
- if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
- IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
- return SendResponse(NS_ERROR_DOM_SECURITY_ERR);
- }
-
- nsresult rv = mService->TerminateSession(aRequest.sessionId(), aRequest.role());
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return SendResponse(rv);
- }
- return SendResponse(NS_OK);
-}
-
-nsresult
-PresentationRequestParent::DoRequest(const ReconnectSessionRequest& aRequest)
-{
- MOZ_ASSERT(mService);
-
- // Validate the accessibility (primarily for receiver side) so that a
- // compromised child process can't fake the ID.
- if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
- IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
-
- // NOTE: Return NS_ERROR_DOM_NOT_FOUND_ERR here to match the spec.
- // https://w3c.github.io/presentation-api/#reconnecting-to-a-presentation
- return SendResponse(NS_ERROR_DOM_NOT_FOUND_ERR);
- }
-
- mSessionId = aRequest.sessionId();
- return mService->ReconnectSession(aRequest.urls(),
- aRequest.sessionId(),
- aRequest.role(),
- this);
-}
-
-nsresult
-PresentationRequestParent::DoRequest(const BuildTransportRequest& aRequest)
-{
- MOZ_ASSERT(mService);
-
- // Validate the accessibility (primarily for receiver side) so that a
- // compromised child process can't fake the ID.
- if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
- IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
- return SendResponse(NS_ERROR_DOM_SECURITY_ERR);
- }
-
- nsresult rv = mService->BuildTransport(aRequest.sessionId(), aRequest.role());
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return SendResponse(rv);
- }
- return SendResponse(NS_OK);
-}
-
-NS_IMETHODIMP
-PresentationRequestParent::NotifySuccess(const nsAString& aUrl)
-{
- Unused << SendNotifyRequestUrlSelected(nsString(aUrl));
- return SendResponse(NS_OK);
-}
-
-NS_IMETHODIMP
-PresentationRequestParent::NotifyError(nsresult aError)
-{
- return SendResponse(aError);
-}
-
-nsresult
-PresentationRequestParent::SendResponse(nsresult aResult)
-{
- if (NS_WARN_IF(mActorDestroyed || !Send__delete__(this, aResult))) {
- return NS_ERROR_FAILURE;
- }
-
- return NS_OK;
-}
-
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/ipc/PresentationParent.h b/dom/presentation/ipc/PresentationParent.h
deleted file mode 100644
index b038aa216..000000000
--- a/dom/presentation/ipc/PresentationParent.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_PresentationParent_h__
-#define mozilla_dom_PresentationParent_h__
-
-#include "mozilla/dom/ipc/IdType.h"
-#include "mozilla/dom/PPresentationBuilderParent.h"
-#include "mozilla/dom/PPresentationParent.h"
-#include "mozilla/dom/PPresentationRequestParent.h"
-#include "nsIPresentationListener.h"
-#include "nsIPresentationService.h"
-#include "nsIPresentationSessionTransportBuilder.h"
-
-namespace mozilla {
-namespace dom {
-
-class PresentationParent final : public PPresentationParent
- , public nsIPresentationAvailabilityListener
- , public nsIPresentationSessionListener
- , public nsIPresentationRespondingListener
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONAVAILABILITYLISTENER
- NS_DECL_NSIPRESENTATIONSESSIONLISTENER
- NS_DECL_NSIPRESENTATIONRESPONDINGLISTENER
-
- PresentationParent();
-
- bool Init(ContentParentId aContentParentId);
-
- bool RegisterTransportBuilder(const nsString& aSessionId, const uint8_t& aRole);
-
- virtual void ActorDestroy(ActorDestroyReason aWhy) override;
-
- virtual bool
- RecvPPresentationRequestConstructor(PPresentationRequestParent* aActor,
- const PresentationIPCRequest& aRequest) override;
-
- virtual PPresentationRequestParent*
- AllocPPresentationRequestParent(const PresentationIPCRequest& aRequest) override;
-
- virtual bool
- DeallocPPresentationRequestParent(PPresentationRequestParent* aActor) override;
-
- virtual PPresentationBuilderParent*
- AllocPPresentationBuilderParent(const nsString& aSessionId,
- const uint8_t& aRole) override;
-
- virtual bool
- DeallocPPresentationBuilderParent(
- PPresentationBuilderParent* aActor) override;
-
- virtual bool Recv__delete__() override;
-
- virtual bool RecvRegisterAvailabilityHandler(
- nsTArray<nsString>&& aAvailabilityUrls) override;
-
- virtual bool RecvUnregisterAvailabilityHandler(
- nsTArray<nsString>&& aAvailabilityUrls) override;
-
- virtual bool RecvRegisterSessionHandler(const nsString& aSessionId,
- const uint8_t& aRole) override;
-
- virtual bool RecvUnregisterSessionHandler(const nsString& aSessionId,
- const uint8_t& aRole) override;
-
- virtual bool RecvRegisterRespondingHandler(const uint64_t& aWindowId) override;
-
- virtual bool RecvUnregisterRespondingHandler(const uint64_t& aWindowId) override;
-
- virtual bool RecvNotifyReceiverReady(const nsString& aSessionId,
- const uint64_t& aWindowId,
- const bool& aIsLoading) override;
-
- virtual bool RecvNotifyTransportClosed(const nsString& aSessionId,
- const uint8_t& aRole,
- const nsresult& aReason) override;
-
-private:
- virtual ~PresentationParent();
-
- bool mActorDestroyed = false;
- nsCOMPtr<nsIPresentationService> mService;
- nsTArray<nsString> mSessionIdsAtController;
- nsTArray<nsString> mSessionIdsAtReceiver;
- nsTArray<uint64_t> mWindowIds;
- ContentParentId mChildId;
- nsTArray<nsString> mContentAvailabilityUrls;
-};
-
-class PresentationRequestParent final : public PPresentationRequestParent
- , public nsIPresentationServiceCallback
-{
- friend class PresentationParent;
-
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONSERVICECALLBACK
-
- explicit PresentationRequestParent(nsIPresentationService* aService,
- ContentParentId aContentParentId);
-
- virtual void ActorDestroy(ActorDestroyReason aWhy) override;
-
-private:
- virtual ~PresentationRequestParent();
-
- nsresult SendResponse(nsresult aResult);
-
- nsresult DoRequest(const StartSessionRequest& aRequest);
-
- nsresult DoRequest(const SendSessionMessageRequest& aRequest);
-
- nsresult DoRequest(const CloseSessionRequest& aRequest);
-
- nsresult DoRequest(const TerminateSessionRequest& aRequest);
-
- nsresult DoRequest(const ReconnectSessionRequest& aRequest);
-
- nsresult DoRequest(const BuildTransportRequest& aRequest);
-
- bool mActorDestroyed = false;
- bool mNeedRegisterBuilder = false;
- nsString mSessionId;
- nsCOMPtr<nsIPresentationService> mService;
- ContentParentId mChildId;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_PresentationParent_h__
diff --git a/dom/presentation/moz.build b/dom/presentation/moz.build
deleted file mode 100644
index a7058382f..000000000
--- a/dom/presentation/moz.build
+++ /dev/null
@@ -1,89 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DIRS += ['interfaces', 'provider']
-
-XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
-MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']
-MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini']
-
-EXPORTS.mozilla.dom += [
- 'DCPresentationChannelDescription.h',
- 'ipc/PresentationBuilderChild.h',
- 'ipc/PresentationBuilderParent.h',
- 'ipc/PresentationChild.h',
- 'ipc/PresentationIPCService.h',
- 'ipc/PresentationParent.h',
- 'Presentation.h',
- 'PresentationAvailability.h',
- 'PresentationCallbacks.h',
- 'PresentationConnection.h',
- 'PresentationConnectionList.h',
- 'PresentationDeviceManager.h',
- 'PresentationReceiver.h',
- 'PresentationRequest.h',
- 'PresentationService.h',
- 'PresentationServiceBase.h',
- 'PresentationSessionInfo.h',
- 'PresentationTCPSessionTransport.h',
-]
-
-UNIFIED_SOURCES += [
- 'AvailabilityCollection.cpp',
- 'ControllerConnectionCollection.cpp',
- 'DCPresentationChannelDescription.cpp',
- 'ipc/PresentationBuilderChild.cpp',
- 'ipc/PresentationBuilderParent.cpp',
- 'ipc/PresentationChild.cpp',
- 'ipc/PresentationContentSessionInfo.cpp',
- 'ipc/PresentationIPCService.cpp',
- 'ipc/PresentationParent.cpp',
- 'Presentation.cpp',
- 'PresentationAvailability.cpp',
- 'PresentationCallbacks.cpp',
- 'PresentationConnection.cpp',
- 'PresentationConnectionList.cpp',
- 'PresentationDeviceManager.cpp',
- 'PresentationReceiver.cpp',
- 'PresentationRequest.cpp',
- 'PresentationService.cpp',
- 'PresentationSessionInfo.cpp',
- 'PresentationSessionRequest.cpp',
- 'PresentationTCPSessionTransport.cpp',
- 'PresentationTerminateRequest.cpp',
- 'PresentationTransportBuilderConstructor.cpp'
-]
-
-EXTRA_COMPONENTS += [
- 'PresentationDataChannelSessionTransport.js',
- 'PresentationDataChannelSessionTransport.manifest',
- 'PresentationDeviceInfoManager.js',
- 'PresentationDeviceInfoManager.manifest',
-]
-
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
- EXTRA_COMPONENTS += [
- 'PresentationNetworkHelper.js',
- 'PresentationNetworkHelper.manifest',
- ]
-
-EXTRA_JS_MODULES += [
- 'PresentationDeviceInfoManager.jsm',
-]
-
-IPDL_SOURCES += [
- 'ipc/PPresentation.ipdl',
- 'ipc/PPresentationBuilder.ipdl',
- 'ipc/PPresentationRequest.ipdl'
-]
-
-LOCAL_INCLUDES += [
- '../base'
-]
-
-include('/ipc/chromium/chromium-config.mozbuild')
-
-FINAL_LIBRARY = 'xul'
diff --git a/dom/presentation/provider/AndroidCastDeviceProvider.js b/dom/presentation/provider/AndroidCastDeviceProvider.js
deleted file mode 100644
index cf555f77b..000000000
--- a/dom/presentation/provider/AndroidCastDeviceProvider.js
+++ /dev/null
@@ -1,461 +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/. */
-/* jshint esnext:true, globalstrict:true, moz:true, undef:true, unused:true */
-/* globals Components, dump */
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-// globals XPCOMUtils
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-// globals Services
-Cu.import("resource://gre/modules/Services.jsm");
-// globals Messaging
-Cu.import("resource://gre/modules/Messaging.jsm");
-
-function log(str) {
- // dump("-*- AndroidCastDeviceProvider -*-: " + str + "\n");
-}
-
-// Helper function: transfer nsIPresentationChannelDescription to json
-function descriptionToString(aDescription) {
- let json = {};
- json.type = aDescription.type;
- switch(aDescription.type) {
- case Ci.nsIPresentationChannelDescription.TYPE_TCP:
- let addresses = aDescription.tcpAddress.QueryInterface(Ci.nsIArray);
- json.tcpAddress = [];
- for (let idx = 0; idx < addresses.length; idx++) {
- let address = addresses.queryElementAt(idx, Ci.nsISupportsCString);
- json.tcpAddress.push(address.data);
- }
- json.tcpPort = aDescription.tcpPort;
- break;
- case Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL:
- json.dataChannelSDP = aDescription.dataChannelSDP;
- break;
- }
- return JSON.stringify(json);
-}
-
-const TOPIC_ANDROID_CAST_DEVICE_SYNCDEVICE = "AndroidCastDevice:SyncDevice";
-const TOPIC_ANDROID_CAST_DEVICE_ADDED = "AndroidCastDevice:Added";
-const TOPIC_ANDROID_CAST_DEVICE_REMOVED = "AndroidCastDevice:Removed";
-const TOPIC_ANDROID_CAST_DEVICE_START = "AndroidCastDevice:Start";
-const TOPIC_ANDROID_CAST_DEVICE_STOP = "AndroidCastDevice:Stop";
-const TOPIC_PRESENTATION_VIEW_READY = "presentation-view-ready";
-
-function LocalControlChannel(aProvider, aDeviceId, aRole) {
- log("LocalControlChannel - create new LocalControlChannel for : "
- + aRole);
- this._provider = aProvider;
- this._deviceId = aDeviceId;
- this._role = aRole;
-}
-
-LocalControlChannel.prototype = {
- _listener: null,
- _provider: null,
- _deviceId: null,
- _role: null,
- _isOnTerminating: false,
- _isOnDisconnecting: false,
- _pendingConnected: false,
- _pendingDisconnect: null,
- _pendingOffer: null,
- _pendingCandidate: null,
- /* For the controller, it would be the control channel of the receiver.
- * For the receiver, it would be the control channel of the controller. */
- _correspondingControlChannel: null,
-
- set correspondingControlChannel(aCorrespondingControlChannel) {
- this._correspondingControlChannel = aCorrespondingControlChannel;
- },
-
- get correspondingControlChannel() {
- return this._correspondingControlChannel;
- },
-
- notifyConnected: function LCC_notifyConnected() {
- this._pendingDisconnect = null;
-
- if (!this._listener) {
- this._pendingConnected = true;
- } else {
- this._listener.notifyConnected();
- }
- },
-
- onOffer: function LCC_onOffer(aOffer) {
- if (this._role == Ci.nsIPresentationService.ROLE_CONTROLLER) {
- log("LocalControlChannel - onOffer of controller should not be called.");
- return;
- }
- if (!this._listener) {
- this._pendingOffer = aOffer;
- } else {
- this._listener.onOffer(aOffer);
- }
- },
-
- onAnswer: function LCC_onAnswer(aAnswer) {
- if (this._role == Ci.nsIPresentationService.ROLE_RECEIVER) {
- log("LocalControlChannel - onAnswer of receiver should not be called.");
- return;
- }
- this._listener.onAnswer(aAnswer);
- },
-
- notifyIceCandidate: function LCC_notifyIceCandidate(aCandidate) {
- if (!this._listener) {
- this._pendingCandidate = aCandidate;
- } else {
- this._listener.onIceCandidate(aCandidate);
- }
- },
-
- // nsIPresentationControlChannel
- get listener() {
- return this._listener;
- },
-
- set listener(aListener) {
- this._listener = aListener;
-
- if (!this._listener) {
- return;
- }
-
- if (this._pendingConnected) {
- this.notifyConnected();
- this._pendingConnected = false;
- }
-
- if (this._pendingOffer) {
- this.onOffer(this._pendingOffer);
- this._pendingOffer = null;
- }
-
- if (this._pendingCandidate) {
- this.notifyIceCandidate(this._pendingCandidate);
- this._pendingCandidate = null;
- }
-
- if (this._pendingDisconnect != null) {
- this.disconnect(this._pendingDisconnect);
- this._pendingDisconnect = null;
- }
- },
-
- sendOffer: function LCC_sendOffer(aOffer) {
- if (this._role == Ci.nsIPresentationService.ROLE_RECEIVER) {
- log("LocalControlChannel - sendOffer of receiver should not be called.");
- return;
- }
- log("LocalControlChannel - sendOffer aOffer=" + descriptionToString(aOffer));
- this._correspondingControlChannel.onOffer(aOffer);
- },
-
- sendAnswer: function LCC_sendAnswer(aAnswer) {
- if (this._role == Ci.nsIPresentationService.ROLE_CONTROLLER) {
- log("LocalControlChannel - sendAnswer of controller should not be called.");
- return;
- }
- log("LocalControlChannel - sendAnswer aAnswer=" + descriptionToString(aAnswer));
- this._correspondingControlChannel.onAnswer(aAnswer);
- },
-
- sendIceCandidate: function LCC_sendIceCandidate(aCandidate) {
- log("LocalControlChannel - sendAnswer aCandidate=" + aCandidate);
- this._correspondingControlChannel.notifyIceCandidate(aCandidate);
- },
-
- launch: function LCC_launch(aPresentationId, aUrl) {
- log("LocalControlChannel - launch aPresentationId="
- + aPresentationId + " aUrl=" + aUrl);
- // Create control channel for receiver directly.
- let controlChannel = new LocalControlChannel(this._provider,
- this._deviceId,
- Ci.nsIPresentationService.ROLE_RECEIVER);
-
- // Set up the corresponding control channels for both controller and receiver.
- this._correspondingControlChannel = controlChannel;
- controlChannel._correspondingControlChannel = this;
-
- this._provider.onSessionRequest(this._deviceId,
- aUrl,
- aPresentationId,
- controlChannel);
- controlChannel.notifyConnected();
- },
-
- terminate: function LCC_terminate(aPresentationId) {
- log("LocalControlChannel - terminate aPresentationId="
- + aPresentationId);
-
- if (this._isOnTerminating) {
- return;
- }
-
- // Create control channel for corresponding role directly.
- let correspondingRole = this._role == Ci.nsIPresentationService.ROLE_CONTROLLER
- ? Ci.nsIPresentationService.ROLE_RECEIVER
- : Ci.nsIPresentationService.ROLE_CONTROLLER;
- let controlChannel = new LocalControlChannel(this._provider,
- this._deviceId,
- correspondingRole);
- // Prevent the termination recursion.
- controlChannel._isOnTerminating = true;
-
- // Set up the corresponding control channels for both controller and receiver.
- this._correspondingControlChannel = controlChannel;
- controlChannel._correspondingControlChannel = this;
-
- this._provider.onTerminateRequest(this._deviceId,
- aPresentationId,
- controlChannel,
- this._role == Ci.nsIPresentationService.ROLE_RECEIVER);
- controlChannel.notifyConnected();
- },
-
- disconnect: function LCC_disconnect(aReason) {
- log("LocalControlChannel - disconnect aReason=" + aReason);
-
- if (this._isOnDisconnecting) {
- return;
- }
-
- this._pendingOffer = null;
- this._pendingCandidate = null;
- this._pendingConnected = false;
-
- // this._pendingDisconnect is a nsresult.
- // If it is null, it means no pending disconnect.
- // If it is NS_OK, it means this control channel is disconnected normally.
- // If it is other nsresult value, it means this control channel is
- // disconnected abnormally.
-
- // Remote endpoint closes the control channel with abnormal reason.
- if (aReason == Cr.NS_OK &&
- this._pendingDisconnect != null &&
- this._pendingDisconnect != Cr.NS_OK) {
- aReason = this._pendingDisconnect;
- }
-
- if (!this._listener) {
- this._pendingDisconnect = aReason;
- return;
- }
-
- this._isOnDisconnecting = true;
- this._correspondingControlChannel.disconnect(aReason);
- this._listener.notifyDisconnected(aReason);
- },
-
- reconnect: function LCC_reconnect(aPresentationId, aUrl) {
- log("1-UA on Android doesn't support reconnect.");
- throw Cr.NS_ERROR_FAILURE;
- },
-
- classID: Components.ID("{c9be9450-e5c7-4294-a287-376971b017fd}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
-};
-
-function ChromecastRemoteDisplayDevice(aProvider, aId, aName, aRole) {
- this._provider = aProvider;
- this._id = aId;
- this._name = aName;
- this._role = aRole;
-}
-
-ChromecastRemoteDisplayDevice.prototype = {
- _id: null,
- _name: null,
- _role: null,
- _provider: null,
- _ctrlChannel: null,
-
- update: function CRDD_update(aName) {
- this._name = aName || this._name;
- },
-
- // nsIPresentationDevice
- get id() { return this._id; },
-
- get name() { return this._name; },
-
- get type() { return "chromecast"; },
-
- establishControlChannel: function CRDD_establishControlChannel() {
- this._ctrlChannel = new LocalControlChannel(this._provider,
- this._id,
- this._role);
-
- if (this._role == Ci.nsIPresentationService.ROLE_CONTROLLER) {
- // Only connect to Chromecast for controller.
- // Monitor the receiver being ready.
- Services.obs.addObserver(this, TOPIC_PRESENTATION_VIEW_READY, true);
-
- // Launch Chromecast service in Android.
- Messaging.sendRequestForResult({
- type: TOPIC_ANDROID_CAST_DEVICE_START,
- id: this.id
- }).then(result => {
- log("Chromecast is connected.");
- }).catch(error => {
- log("Can not connect to Chromecast.");
- // If Chromecast can not be launched, remove the observer.
- Services.obs.removeObserver(this, TOPIC_PRESENTATION_VIEW_READY);
- this._ctrlChannel.disconnect(Cr.NS_ERROR_FAILURE);
- });
- } else {
- // If establishControlChannel called from the receiver, we don't need to
- // wait the 'presentation-view-ready' event.
- this._ctrlChannel.notifyConnected();
- }
-
- return this._ctrlChannel;
- },
-
- disconnect: function CRDD_disconnect() {
- // Disconnect from Chromecast.
- Messaging.sendRequestForResult({
- type: TOPIC_ANDROID_CAST_DEVICE_STOP,
- id: this.id
- });
- },
-
- isRequestedUrlSupported: function CRDD_isRequestedUrlSupported(aUrl) {
- let url = Cc["@mozilla.org/network/io-service;1"]
- .getService(Ci.nsIIOService)
- .newURI(aUrl, null, null);
- return url.scheme == "http" || url.scheme == "https";
- },
-
- // nsIPresentationLocalDevice
- get windowId() { return this._id; },
-
- // nsIObserver
- observe: function CRDD_observe(aSubject, aTopic, aData) {
- if (aTopic == TOPIC_PRESENTATION_VIEW_READY) {
- log("ChromecastRemoteDisplayDevice - observe: aTopic="
- + aTopic + " data=" + aData);
- if (this.windowId === aData) {
- Services.obs.removeObserver(this, TOPIC_PRESENTATION_VIEW_READY);
- this._ctrlChannel.notifyConnected();
- }
- }
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice,
- Ci.nsIPresentationLocalDevice,
- Ci.nsISupportsWeakReference,
- Ci.nsIObserver]),
-};
-
-function AndroidCastDeviceProvider() {
-}
-
-AndroidCastDeviceProvider.prototype = {
- _listener: null,
- _deviceList: new Map(),
-
- onSessionRequest: function APDP_onSessionRequest(aDeviceId,
- aUrl,
- aPresentationId,
- aControlChannel) {
- log("AndroidCastDeviceProvider - onSessionRequest"
- + " aDeviceId=" + aDeviceId);
- let device = this._deviceList.get(aDeviceId);
- let receiverDevice = new ChromecastRemoteDisplayDevice(this,
- device.id,
- device.name,
- Ci.nsIPresentationService.ROLE_RECEIVER);
- this._listener.onSessionRequest(receiverDevice,
- aUrl,
- aPresentationId,
- aControlChannel);
- },
-
- onTerminateRequest: function APDP_onTerminateRequest(aDeviceId,
- aPresentationId,
- aControlChannel,
- aIsFromReceiver) {
- log("AndroidCastDeviceProvider - onTerminateRequest"
- + " aDeviceId=" + aDeviceId
- + " aPresentationId=" + aPresentationId
- + " aIsFromReceiver=" + aIsFromReceiver);
- let device = this._deviceList.get(aDeviceId);
- this._listener.onTerminateRequest(device,
- aPresentationId,
- aControlChannel,
- aIsFromReceiver);
- },
-
- // nsIPresentationDeviceProvider
- set listener(aListener) {
- this._listener = aListener;
-
- // When unload this provider.
- if (!this._listener) {
- // remove observer
- Services.obs.removeObserver(this, TOPIC_ANDROID_CAST_DEVICE_ADDED);
- Services.obs.removeObserver(this, TOPIC_ANDROID_CAST_DEVICE_REMOVED);
- return;
- }
-
- // Sync all device already found by Android.
- Services.obs.notifyObservers(null, TOPIC_ANDROID_CAST_DEVICE_SYNCDEVICE, "");
- // Observer registration
- Services.obs.addObserver(this, TOPIC_ANDROID_CAST_DEVICE_ADDED, false);
- Services.obs.addObserver(this, TOPIC_ANDROID_CAST_DEVICE_REMOVED, false);
- },
-
- get listener() {
- return this._listener;
- },
-
- forceDiscovery: function APDP_forceDiscovery() {
- // There is no API to do force discovery in Android SDK.
- },
-
- // nsIObserver
- observe: function APDP_observe(aSubject, aTopic, aData) {
- switch (aTopic) {
- case TOPIC_ANDROID_CAST_DEVICE_ADDED: {
- let deviceInfo = JSON.parse(aData);
- let deviceId = deviceInfo.uuid;
-
- if (!this._deviceList.has(deviceId)) {
- let device = new ChromecastRemoteDisplayDevice(this,
- deviceInfo.uuid,
- deviceInfo.friendlyName,
- Ci.nsIPresentationService.ROLE_CONTROLLER);
- this._deviceList.set(device.id, device);
- this._listener.addDevice(device);
- } else {
- let device = this._deviceList.get(deviceId);
- device.update(deviceInfo.friendlyName);
- this._listener.updateDevice(device);
- }
- break;
- }
- case TOPIC_ANDROID_CAST_DEVICE_REMOVED: {
- let deviceId = aData;
- let device = this._deviceList.get(deviceId);
- this._listener.removeDevice(device);
- this._deviceList.delete(deviceId);
- break;
- }
- }
- },
-
- classID: Components.ID("{7394f24c-dbc3-48c8-8a47-cd10169b7c6b}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
- Ci.nsIPresentationDeviceProvider]),
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AndroidCastDeviceProvider]);
diff --git a/dom/presentation/provider/AndroidCastDeviceProvider.manifest b/dom/presentation/provider/AndroidCastDeviceProvider.manifest
deleted file mode 100644
index db2aa101b..000000000
--- a/dom/presentation/provider/AndroidCastDeviceProvider.manifest
+++ /dev/null
@@ -1,4 +0,0 @@
-# AndroidCastDeviceProvider.js
-component {7394f24c-dbc3-48c8-8a47-cd10169b7c6b} AndroidCastDeviceProvider.js
-contract @mozilla.org/presentation-device/android-cast-device-provider;1 {7394f24c-dbc3-48c8-8a47-cd10169b7c6b}
-category presentation-device-provider AndroidCastDeviceProvider @mozilla.org/presentation-device/android-cast-device-provider;1
diff --git a/dom/presentation/provider/BuiltinProviders.manifest b/dom/presentation/provider/BuiltinProviders.manifest
deleted file mode 100644
index 0ba7bcaa7..000000000
--- a/dom/presentation/provider/BuiltinProviders.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {f4079b8b-ede5-4b90-a112-5b415a931deb} PresentationControlService.js
-contract @mozilla.org/presentation/control-service;1 {f4079b8b-ede5-4b90-a112-5b415a931deb}
diff --git a/dom/presentation/provider/ControllerStateMachine.jsm b/dom/presentation/provider/ControllerStateMachine.jsm
deleted file mode 100644
index b568a8e9a..000000000
--- a/dom/presentation/provider/ControllerStateMachine.jsm
+++ /dev/null
@@ -1,240 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
-/* jshint esnext:true, globalstrict:true, moz:true, undef:true, unused:true */
-/* globals Components, dump */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["ControllerStateMachine"]; // jshint ignore:line
-
-const { utils: Cu } = Components;
-
-/* globals State, CommandType */
-Cu.import("resource://gre/modules/presentation/StateMachineHelper.jsm");
-
-const DEBUG = false;
-function debug(str) {
- dump("-*- ControllerStateMachine: " + str + "\n");
-}
-
-var handlers = [
- function _initHandler(stateMachine, command) {
- // shouldn't receive any command at init state.
- DEBUG && debug("unexpected command: " + JSON.stringify(command)); // jshint ignore:line
- },
- function _connectingHandler(stateMachine, command) {
- switch (command.type) {
- case CommandType.CONNECT_ACK:
- stateMachine.state = State.CONNECTED;
- stateMachine._notifyDeviceConnected();
- break;
- case CommandType.DISCONNECT:
- stateMachine.state = State.CLOSED;
- stateMachine._notifyDisconnected(command.reason);
- break;
- default:
- debug("unexpected command: " + JSON.stringify(command));
- // ignore unexpected command.
- break;
- }
- },
- function _connectedHandler(stateMachine, command) {
- switch (command.type) {
- case CommandType.DISCONNECT:
- stateMachine.state = State.CLOSED;
- stateMachine._notifyDisconnected(command.reason);
- break;
- case CommandType.LAUNCH_ACK:
- stateMachine._notifyLaunch(command.presentationId);
- break;
- case CommandType.TERMINATE:
- stateMachine._notifyTerminate(command.presentationId);
- break;
- case CommandType.TERMINATE_ACK:
- stateMachine._notifyTerminate(command.presentationId);
- break;
- case CommandType.ANSWER:
- case CommandType.ICE_CANDIDATE:
- stateMachine._notifyChannelDescriptor(command);
- break;
- case CommandType.RECONNECT_ACK:
- stateMachine._notifyReconnect(command.presentationId);
- break;
- default:
- debug("unexpected command: " + JSON.stringify(command));
- // ignore unexpected command.
- break;
- }
- },
- function _closingHandler(stateMachine, command) {
- switch (command.type) {
- case CommandType.DISCONNECT:
- stateMachine.state = State.CLOSED;
- stateMachine._notifyDisconnected(command.reason);
- break;
- default:
- debug("unexpected command: " + JSON.stringify(command));
- // ignore unexpected command.
- break;
- }
- },
- function _closedHandler(stateMachine, command) {
- // ignore every command in closed state.
- DEBUG && debug("unexpected command: " + JSON.stringify(command)); // jshint ignore:line
- },
-];
-
-function ControllerStateMachine(channel, deviceId) {
- this.state = State.INIT;
- this._channel = channel;
- this._deviceId = deviceId;
-}
-
-ControllerStateMachine.prototype = {
- launch: function _launch(presentationId, url) {
- if (this.state === State.CONNECTED) {
- this._sendCommand({
- type: CommandType.LAUNCH,
- presentationId: presentationId,
- url: url,
- });
- }
- },
-
- terminate: function _terminate(presentationId) {
- if (this.state === State.CONNECTED) {
- this._sendCommand({
- type: CommandType.TERMINATE,
- presentationId: presentationId,
- });
- }
- },
-
- terminateAck: function _terminateAck(presentationId) {
- if (this.state === State.CONNECTED) {
- this._sendCommand({
- type: CommandType.TERMINATE_ACK,
- presentationId: presentationId,
- });
- }
- },
-
- reconnect: function _reconnect(presentationId, url) {
- if (this.state === State.CONNECTED) {
- this._sendCommand({
- type: CommandType.RECONNECT,
- presentationId: presentationId,
- url: url,
- });
- }
- },
-
- sendOffer: function _sendOffer(offer) {
- if (this.state === State.CONNECTED) {
- this._sendCommand({
- type: CommandType.OFFER,
- offer: offer,
- });
- }
- },
-
- sendAnswer: function _sendAnswer() {
- // answer can only be sent by presenting UA.
- debug("controller shouldn't generate answer");
- },
-
- updateIceCandidate: function _updateIceCandidate(candidate) {
- if (this.state === State.CONNECTED) {
- this._sendCommand({
- type: CommandType.ICE_CANDIDATE,
- candidate: candidate,
- });
- }
- },
-
- onCommand: function _onCommand(command) {
- handlers[this.state](this, command);
- },
-
- onChannelReady: function _onChannelReady() {
- if (this.state === State.INIT) {
- this._sendCommand({
- type: CommandType.CONNECT,
- deviceId: this._deviceId
- });
- this.state = State.CONNECTING;
- }
- },
-
- onChannelClosed: function _onChannelClose(reason, isByRemote) {
- switch (this.state) {
- case State.CONNECTED:
- if (isByRemote) {
- this.state = State.CLOSED;
- this._notifyDisconnected(reason);
- } else {
- this._sendCommand({
- type: CommandType.DISCONNECT,
- reason: reason
- });
- this.state = State.CLOSING;
- this._closeReason = reason;
- }
- break;
- case State.CLOSING:
- if (isByRemote) {
- this.state = State.CLOSED;
- if (this._closeReason) {
- reason = this._closeReason;
- delete this._closeReason;
- }
- this._notifyDisconnected(reason);
- }
- break;
- default:
- DEBUG && debug("unexpected channel close: " + reason + ", " + isByRemote); // jshint ignore:line
- break;
- }
- },
-
- _sendCommand: function _sendCommand(command) {
- this._channel.sendCommand(command);
- },
-
- _notifyDeviceConnected: function _notifyDeviceConnected() {
- //XXX trigger following command
- this._channel.notifyDeviceConnected();
- },
-
- _notifyDisconnected: function _notifyDisconnected(reason) {
- this._channel.notifyDisconnected(reason);
- },
-
- _notifyLaunch: function _notifyLaunch(presentationId) {
- this._channel.notifyLaunch(presentationId);
- },
-
- _notifyTerminate: function _notifyTerminate(presentationId) {
- this._channel.notifyTerminate(presentationId);
- },
-
- _notifyReconnect: function _notifyReconnect(presentationId) {
- this._channel.notifyReconnect(presentationId);
- },
-
- _notifyChannelDescriptor: function _notifyChannelDescriptor(command) {
- switch (command.type) {
- case CommandType.ANSWER:
- this._channel.notifyAnswer(command.answer);
- break;
- case CommandType.ICE_CANDIDATE:
- this._channel.notifyIceCandidate(command.candidate);
- break;
- }
- },
-};
-
-this.ControllerStateMachine = ControllerStateMachine; // jshint ignore:line
diff --git a/dom/presentation/provider/DeviceProviderHelpers.cpp b/dom/presentation/provider/DeviceProviderHelpers.cpp
deleted file mode 100644
index 00b2c12f1..000000000
--- a/dom/presentation/provider/DeviceProviderHelpers.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "DeviceProviderHelpers.h"
-
-#include "nsCOMPtr.h"
-#include "nsIURI.h"
-#include "nsNetUtil.h"
-
-namespace mozilla {
-namespace dom {
-namespace presentation {
-
-static const char* const kFxTVPresentationAppUrls[] = {
- "app://fling-player.gaiamobile.org/index.html",
- "app://notification-receiver.gaiamobile.org/index.html",
- nullptr
-};
-
-/* static */ bool
-DeviceProviderHelpers::IsCommonlySupportedScheme(const nsAString& aUrl)
-{
- nsCOMPtr<nsIURI> uri;
- nsresult rv = NS_NewURI(getter_AddRefs(uri), aUrl);
- if (NS_FAILED(rv) || !uri) {
- return false;
- }
-
- nsAutoCString scheme;
- uri->GetScheme(scheme);
- if (scheme.LowerCaseEqualsLiteral("http") ||
- scheme.LowerCaseEqualsLiteral("https")) {
- return true;
- }
-
- return false;
-}
-
-/* static */ bool
-DeviceProviderHelpers::IsFxTVSupportedAppUrl(const nsAString& aUrl)
-{
- // Check if matched with any presentation Apps on TV.
- for (uint32_t i = 0; kFxTVPresentationAppUrls[i]; i++) {
- if (aUrl.EqualsASCII(kFxTVPresentationAppUrls[i])) {
- return true;
- }
- }
-
- return false;
-}
-
-} // namespace presentation
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/provider/DeviceProviderHelpers.h b/dom/presentation/provider/DeviceProviderHelpers.h
deleted file mode 100644
index 4bde09bed..000000000
--- a/dom/presentation/provider/DeviceProviderHelpers.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_presentation_DeviceProviderHelpers_h
-#define mozilla_dom_presentation_DeviceProviderHelpers_h
-
-#include "nsString.h"
-
-namespace mozilla {
-namespace dom {
-namespace presentation {
-
-class DeviceProviderHelpers final
-{
-public:
- static bool IsCommonlySupportedScheme(const nsAString& aUrl);
- static bool IsFxTVSupportedAppUrl(const nsAString& aUrl);
-
-private:
- DeviceProviderHelpers() = delete;
-};
-
-} // namespace presentation
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_presentation_DeviceProviderHelpers_h
diff --git a/dom/presentation/provider/DisplayDeviceProvider.cpp b/dom/presentation/provider/DisplayDeviceProvider.cpp
deleted file mode 100644
index 3f88aba5e..000000000
--- a/dom/presentation/provider/DisplayDeviceProvider.cpp
+++ /dev/null
@@ -1,580 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "DisplayDeviceProvider.h"
-
-#include "DeviceProviderHelpers.h"
-#include "mozilla/Logging.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/Services.h"
-#include "mozilla/Unused.h"
-#include "nsIObserverService.h"
-#include "nsIServiceManager.h"
-#include "nsIWindowWatcher.h"
-#include "nsNetUtil.h"
-#include "nsPIDOMWindow.h"
-#include "nsSimpleURI.h"
-#include "nsTCPDeviceInfo.h"
-#include "nsThreadUtils.h"
-
-static mozilla::LazyLogModule gDisplayDeviceProviderLog("DisplayDeviceProvider");
-
-#define LOG(format) MOZ_LOG(gDisplayDeviceProviderLog, mozilla::LogLevel::Debug, format)
-
-#define DISPLAY_CHANGED_NOTIFICATION "display-changed"
-#define DEFAULT_CHROME_FEATURES_PREF "toolkit.defaultChromeFeatures"
-#define CHROME_REMOTE_URL_PREF "b2g.multiscreen.chrome_remote_url"
-#define PREF_PRESENTATION_DISCOVERABLE_RETRY_MS "dom.presentation.discoverable.retry_ms"
-
-namespace mozilla {
-namespace dom {
-namespace presentation {
-
-/**
- * This wrapper is used to break circular-reference problem.
- */
-class DisplayDeviceProviderWrappedListener final
- : public nsIPresentationControlServerListener
-{
-public:
- NS_DECL_ISUPPORTS
- NS_FORWARD_SAFE_NSIPRESENTATIONCONTROLSERVERLISTENER(mListener)
-
- explicit DisplayDeviceProviderWrappedListener() = default;
-
- nsresult SetListener(DisplayDeviceProvider* aListener)
- {
- mListener = aListener;
- return NS_OK;
- }
-
-private:
- virtual ~DisplayDeviceProviderWrappedListener() = default;
-
- DisplayDeviceProvider* mListener = nullptr;
-};
-
-NS_IMPL_ISUPPORTS(DisplayDeviceProviderWrappedListener,
- nsIPresentationControlServerListener)
-
-NS_IMPL_ISUPPORTS(DisplayDeviceProvider::HDMIDisplayDevice,
- nsIPresentationDevice,
- nsIPresentationLocalDevice)
-
-// nsIPresentationDevice
-NS_IMETHODIMP
-DisplayDeviceProvider::HDMIDisplayDevice::GetId(nsACString& aId)
-{
- aId = mWindowId;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DisplayDeviceProvider::HDMIDisplayDevice::GetName(nsACString& aName)
-{
- aName = mName;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DisplayDeviceProvider::HDMIDisplayDevice::GetType(nsACString& aType)
-{
- aType = mType;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DisplayDeviceProvider::HDMIDisplayDevice::GetWindowId(nsACString& aWindowId)
-{
- aWindowId = mWindowId;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DisplayDeviceProvider::HDMIDisplayDevice
- ::EstablishControlChannel(nsIPresentationControlChannel** aControlChannel)
-{
- nsresult rv = OpenTopLevelWindow();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- RefPtr<DisplayDeviceProvider> provider = mProvider.get();
- if (NS_WARN_IF(!provider)) {
- return NS_ERROR_FAILURE;
- }
- return provider->Connect(this, aControlChannel);
-}
-
-NS_IMETHODIMP
-DisplayDeviceProvider::HDMIDisplayDevice::Disconnect()
-{
- nsresult rv = CloseTopLevelWindow();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return NS_OK;;
-}
-
-NS_IMETHODIMP
-DisplayDeviceProvider::HDMIDisplayDevice::IsRequestedUrlSupported(
- const nsAString& aRequestedUrl,
- bool* aRetVal)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (!aRetVal) {
- return NS_ERROR_INVALID_POINTER;
- }
-
- // 1-UA device only supports HTTP/HTTPS hosted receiver page.
- *aRetVal = DeviceProviderHelpers::IsCommonlySupportedScheme(aRequestedUrl);
-
- return NS_OK;
-}
-
-nsresult
-DisplayDeviceProvider::HDMIDisplayDevice::OpenTopLevelWindow()
-{
- MOZ_ASSERT(!mWindow);
-
- nsresult rv;
- nsAutoCString flags(Preferences::GetCString(DEFAULT_CHROME_FEATURES_PREF));
- if (flags.IsEmpty()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- flags.AppendLiteral(",mozDisplayId=");
- flags.AppendInt(mScreenId);
-
- nsAutoCString remoteShellURLString(Preferences::GetCString(CHROME_REMOTE_URL_PREF));
- remoteShellURLString.AppendLiteral("#");
- remoteShellURLString.Append(mWindowId);
-
- // URI validation
- nsCOMPtr<nsIURI> remoteShellURL;
- rv = NS_NewURI(getter_AddRefs(remoteShellURL), remoteShellURLString);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = remoteShellURL->GetSpec(remoteShellURLString);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- nsCOMPtr<nsIWindowWatcher> ww = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
- MOZ_ASSERT(ww);
-
- rv = ww->OpenWindow(nullptr,
- remoteShellURLString.get(),
- "_blank",
- flags.get(),
- nullptr,
- getter_AddRefs(mWindow));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-nsresult
-DisplayDeviceProvider::HDMIDisplayDevice::CloseTopLevelWindow()
-{
- MOZ_ASSERT(mWindow);
-
- nsCOMPtr<nsPIDOMWindowOuter> piWindow = nsPIDOMWindowOuter::From(mWindow);
- nsresult rv = piWindow->Close();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-NS_IMPL_ISUPPORTS(DisplayDeviceProvider,
- nsIObserver,
- nsIPresentationDeviceProvider,
- nsIPresentationControlServerListener)
-
-DisplayDeviceProvider::~DisplayDeviceProvider()
-{
- Uninit();
-}
-
-nsresult
-DisplayDeviceProvider::Init()
-{
- // Provider must be initialized only once.
- if (mInitialized) {
- return NS_OK;
- }
-
- nsresult rv;
-
- mServerRetryMs = Preferences::GetUint(PREF_PRESENTATION_DISCOVERABLE_RETRY_MS);
- mServerRetryTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- MOZ_ASSERT(obs);
-
- obs->AddObserver(this, DISPLAY_CHANGED_NOTIFICATION, false);
-
- mDevice = new HDMIDisplayDevice(this);
-
- mWrappedListener = new DisplayDeviceProviderWrappedListener();
- rv = mWrappedListener->SetListener(this);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mPresentationService = do_CreateInstance(PRESENTATION_CONTROL_SERVICE_CONTACT_ID,
- &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = StartTCPService();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mInitialized = true;
- return NS_OK;
-}
-
-nsresult
-DisplayDeviceProvider::Uninit()
-{
- // Provider must be deleted only once.
- if (!mInitialized) {
- return NS_OK;
- }
-
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- if (obs) {
- obs->RemoveObserver(this, DISPLAY_CHANGED_NOTIFICATION);
- }
-
- // Remove device from device manager when the provider is uninit
- RemoveExternalScreen();
-
- AbortServerRetry();
-
- mInitialized = false;
- mWrappedListener->SetListener(nullptr);
- return NS_OK;
-}
-
-nsresult
-DisplayDeviceProvider::StartTCPService()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- nsresult rv;
- rv = mPresentationService->SetId(NS_LITERAL_CSTRING("DisplayDeviceProvider"));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- uint16_t servicePort;
- rv = mPresentationService->GetPort(&servicePort);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- /*
- * If |servicePort| is non-zero, it means PresentationServer is running.
- * Otherwise, we should make it start serving.
- */
- if (servicePort) {
- mPort = servicePort;
- return NS_OK;
- }
-
- rv = mPresentationService->SetListener(mWrappedListener);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- AbortServerRetry();
-
- // 1-UA doesn't need encryption.
- rv = mPresentationService->StartServer(/* aEncrypted = */ false,
- /* aPort = */ 0);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-void
-DisplayDeviceProvider::AbortServerRetry()
-{
- if (mIsServerRetrying) {
- mIsServerRetrying = false;
- mServerRetryTimer->Cancel();
- }
-}
-
-nsresult
-DisplayDeviceProvider::AddExternalScreen()
-{
- MOZ_ASSERT(mDeviceListener);
-
- nsresult rv;
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- rv = GetListener(getter_AddRefs(listener));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = listener->AddDevice(mDevice);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-nsresult
-DisplayDeviceProvider::RemoveExternalScreen()
-{
- MOZ_ASSERT(mDeviceListener);
-
- nsresult rv;
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- rv = GetListener(getter_AddRefs(listener));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = listener->RemoveDevice(mDevice);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mDevice->Disconnect();
- return NS_OK;
-}
-
-// nsIPresentationDeviceProvider
-NS_IMETHODIMP
-DisplayDeviceProvider::GetListener(nsIPresentationDeviceListener** aListener)
-{
- if (NS_WARN_IF(!aListener)) {
- return NS_ERROR_INVALID_POINTER;
- }
-
- nsresult rv;
- nsCOMPtr<nsIPresentationDeviceListener> listener =
- do_QueryReferent(mDeviceListener, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- listener.forget(aListener);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DisplayDeviceProvider::SetListener(nsIPresentationDeviceListener* aListener)
-{
- mDeviceListener = do_GetWeakReference(aListener);
- nsresult rv = mDeviceListener ? Init() : Uninit();
- if(NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DisplayDeviceProvider::ForceDiscovery()
-{
- return NS_OK;
-}
-
-// nsIPresentationControlServerListener
-NS_IMETHODIMP
-DisplayDeviceProvider::OnServerReady(uint16_t aPort,
- const nsACString& aCertFingerprint)
-{
- MOZ_ASSERT(NS_IsMainThread());
- mPort = aPort;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DisplayDeviceProvider::OnServerStopped(nsresult aResult)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- // Try restart server if it is stopped abnormally.
- if (NS_FAILED(aResult)) {
- mIsServerRetrying = true;
- mServerRetryTimer->Init(this, mServerRetryMs, nsITimer::TYPE_ONE_SHOT);
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DisplayDeviceProvider::OnSessionRequest(nsITCPDeviceInfo* aDeviceInfo,
- const nsAString& aUrl,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aDeviceInfo);
- MOZ_ASSERT(aControlChannel);
-
- nsresult rv;
-
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- rv = GetListener(getter_AddRefs(listener));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- MOZ_ASSERT(!listener);
-
- rv = listener->OnSessionRequest(mDevice,
- aUrl,
- aPresentationId,
- aControlChannel);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DisplayDeviceProvider::OnTerminateRequest(nsITCPDeviceInfo* aDeviceInfo,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel,
- bool aIsFromReceiver)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aDeviceInfo);
- MOZ_ASSERT(aControlChannel);
-
- nsresult rv;
-
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- rv = GetListener(getter_AddRefs(listener));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- MOZ_ASSERT(!listener);
-
- rv = listener->OnTerminateRequest(mDevice,
- aPresentationId,
- aControlChannel,
- aIsFromReceiver);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-DisplayDeviceProvider::OnReconnectRequest(nsITCPDeviceInfo* aDeviceInfo,
- const nsAString& aUrl,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aDeviceInfo);
- MOZ_ASSERT(aControlChannel);
-
- nsresult rv;
-
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- rv = GetListener(getter_AddRefs(listener));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- MOZ_ASSERT(!listener);
-
- rv = listener->OnReconnectRequest(mDevice,
- aUrl,
- aPresentationId,
- aControlChannel);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-// nsIObserver
-NS_IMETHODIMP
-DisplayDeviceProvider::Observe(nsISupports* aSubject,
- const char* aTopic,
- const char16_t* aData)
-{
- if (!strcmp(aTopic, DISPLAY_CHANGED_NOTIFICATION)) {
- nsCOMPtr<nsIDisplayInfo> displayInfo = do_QueryInterface(aSubject);
- MOZ_ASSERT(displayInfo);
-
- int32_t type;
- bool isConnected;
- displayInfo->GetConnected(&isConnected);
- // XXX The ID is as same as the type of display.
- // See Bug 1138287 and nsScreenManagerGonk::AddScreen() for more detail.
- displayInfo->GetId(&type);
-
- if (type == DisplayType::DISPLAY_EXTERNAL) {
- nsresult rv = isConnected ? AddExternalScreen() : RemoveExternalScreen();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- }
- } else if (!strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC)) {
- nsCOMPtr<nsITimer> timer = do_QueryInterface(aSubject);
- if (!timer) {
- return NS_ERROR_UNEXPECTED;
- }
-
- if (timer == mServerRetryTimer) {
- mIsServerRetrying = false;
- StartTCPService();
- }
- }
-
- return NS_OK;
-}
-
-nsresult
-DisplayDeviceProvider::Connect(HDMIDisplayDevice* aDevice,
- nsIPresentationControlChannel** aControlChannel)
-{
- MOZ_ASSERT(aDevice);
- MOZ_ASSERT(mPresentationService);
- NS_ENSURE_ARG_POINTER(aControlChannel);
- *aControlChannel = nullptr;
-
- nsCOMPtr<nsITCPDeviceInfo> deviceInfo = new TCPDeviceInfo(aDevice->Id(),
- aDevice->Address(),
- mPort,
- EmptyCString());
-
- return mPresentationService->Connect(deviceInfo, aControlChannel);
-}
-
-} // namespace presentation
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/provider/DisplayDeviceProvider.h b/dom/presentation/provider/DisplayDeviceProvider.h
deleted file mode 100644
index ebd5db394..000000000
--- a/dom/presentation/provider/DisplayDeviceProvider.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_presentation_provider_DisplayDeviceProvider_h
-#define mozilla_dom_presentation_provider_DisplayDeviceProvider_h
-
-#include "mozilla/RefPtr.h"
-#include "mozilla/WeakPtr.h"
-#include "nsCOMPtr.h"
-#include "nsIDOMWindow.h"
-#include "nsIDisplayInfo.h"
-#include "nsIObserver.h"
-#include "nsIPresentationDeviceProvider.h"
-#include "nsIPresentationLocalDevice.h"
-#include "nsIPresentationControlService.h"
-#include "nsITimer.h"
-#include "nsIWindowWatcher.h"
-#include "nsString.h"
-#include "nsTArray.h"
-#include "nsWeakReference.h"
-
-namespace mozilla {
-namespace dom {
-namespace presentation {
-
-// Consistent definition with the definition in
-// widget/gonk/libdisplay/GonkDisplay.h.
-enum DisplayType {
- DISPLAY_PRIMARY,
- DISPLAY_EXTERNAL,
- DISPLAY_VIRTUAL,
- NUM_DISPLAY_TYPES
-};
-
-class DisplayDeviceProviderWrappedListener;
-
-class DisplayDeviceProvider final : public nsIObserver
- , public nsIPresentationDeviceProvider
- , public nsIPresentationControlServerListener
- , public SupportsWeakPtr<DisplayDeviceProvider>
-{
-private:
- class HDMIDisplayDevice final : public nsIPresentationLocalDevice
- {
- public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONDEVICE
- NS_DECL_NSIPRESENTATIONLOCALDEVICE
-
- // mScreenId is as same as the definition of display type.
- explicit HDMIDisplayDevice(DisplayDeviceProvider* aProvider)
- : mScreenId(DisplayType::DISPLAY_EXTERNAL)
- , mName("HDMI")
- , mType("external")
- , mWindowId("hdmi")
- , mAddress("127.0.0.1")
- , mProvider(aProvider)
- {}
-
- nsresult OpenTopLevelWindow();
- nsresult CloseTopLevelWindow();
-
- const nsCString& Id() const { return mWindowId; }
- const nsCString& Address() const { return mAddress; }
-
- private:
- virtual ~HDMIDisplayDevice() = default;
-
- // Due to the limitation of nsWinodw, mScreenId must be an integer.
- // And mScreenId is also align to the display type defined in
- // widget/gonk/libdisplay/GonkDisplay.h.
- // HDMI display is DisplayType::DISPLAY_EXTERNAL.
- uint32_t mScreenId;
- nsCString mName;
- nsCString mType;
- nsCString mWindowId;
- nsCString mAddress;
-
- nsCOMPtr<mozIDOMWindowProxy> mWindow;
- // weak pointer
- // Provider hold a strong pointer to the device. Use weak pointer to prevent
- // the reference cycle.
- WeakPtr<DisplayDeviceProvider> mProvider;
- };
-
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIOBSERVER
- NS_DECL_NSIPRESENTATIONDEVICEPROVIDER
- NS_DECL_NSIPRESENTATIONCONTROLSERVERLISTENER
- // For using WeakPtr when MOZ_REFCOUNTED_LEAK_CHECKING defined
- MOZ_DECLARE_WEAKREFERENCE_TYPENAME(DisplayDeviceProvider)
-
- nsresult Connect(HDMIDisplayDevice* aDevice,
- nsIPresentationControlChannel** aControlChannel);
-private:
- virtual ~DisplayDeviceProvider();
-
- nsresult Init();
- nsresult Uninit();
-
- nsresult AddExternalScreen();
- nsresult RemoveExternalScreen();
-
- nsresult StartTCPService();
-
- void AbortServerRetry();
-
- // Now support HDMI display only and there should be only one HDMI display.
- nsCOMPtr<nsIPresentationLocalDevice> mDevice = nullptr;
- // weak pointer
- // PresentationDeviceManager (mDeviceListener) hold strong pointer to
- // DisplayDeviceProvider. Use nsWeakPtr to avoid reference cycle.
- nsWeakPtr mDeviceListener = nullptr;
- nsCOMPtr<nsIPresentationControlService> mPresentationService;
- // Used to prevent reference cycle between DisplayDeviceProvider and
- // TCPPresentationServer.
- RefPtr<DisplayDeviceProviderWrappedListener> mWrappedListener;
-
- bool mInitialized = false;
- uint16_t mPort;
-
- bool mIsServerRetrying = false;
- uint32_t mServerRetryMs;
- nsCOMPtr<nsITimer> mServerRetryTimer;
-};
-
-} // mozilla
-} // dom
-} // presentation
-
-#endif // mozilla_dom_presentation_provider_DisplayDeviceProvider_h
-
diff --git a/dom/presentation/provider/LegacyMDNSDeviceProvider.cpp b/dom/presentation/provider/LegacyMDNSDeviceProvider.cpp
deleted file mode 100644
index 54849c9e3..000000000
--- a/dom/presentation/provider/LegacyMDNSDeviceProvider.cpp
+++ /dev/null
@@ -1,774 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "LegacyMDNSDeviceProvider.h"
-
-#include "DeviceProviderHelpers.h"
-#include "MainThreadUtils.h"
-#include "mozilla/Logging.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/Services.h"
-#include "mozilla/Unused.h"
-#include "nsComponentManagerUtils.h"
-#include "nsIObserverService.h"
-#include "nsIWritablePropertyBag2.h"
-#include "nsServiceManagerUtils.h"
-#include "nsTCPDeviceInfo.h"
-#include "nsThreadUtils.h"
-#include "nsIPropertyBag2.h"
-
-#define PREF_PRESENTATION_DISCOVERY_LEGACY "dom.presentation.discovery.legacy.enabled"
-#define PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS "dom.presentation.discovery.timeout_ms"
-#define PREF_PRESENTATION_DEVICE_NAME "dom.presentation.device.name"
-
-#define LEGACY_SERVICE_TYPE "_mozilla_papi._tcp"
-
-#define LEGACY_PRESENTATION_CONTROL_SERVICE_CONTACT_ID "@mozilla.org/presentation/legacy-control-service;1"
-
-static mozilla::LazyLogModule sLegacyMDNSProviderLogModule("LegacyMDNSDeviceProvider");
-
-#undef LOG_I
-#define LOG_I(...) MOZ_LOG(sLegacyMDNSProviderLogModule, mozilla::LogLevel::Debug, (__VA_ARGS__))
-#undef LOG_E
-#define LOG_E(...) MOZ_LOG(sLegacyMDNSProviderLogModule, mozilla::LogLevel::Error, (__VA_ARGS__))
-
-namespace mozilla {
-namespace dom {
-namespace presentation {
-namespace legacy {
-
-static const char* kObservedPrefs[] = {
- PREF_PRESENTATION_DISCOVERY_LEGACY,
- PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS,
- PREF_PRESENTATION_DEVICE_NAME,
- nullptr
-};
-
-namespace {
-
-static void
-GetAndroidDeviceName(nsACString& aRetVal)
-{
- nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
- MOZ_ASSERT(infoService, "Could not find a system info service");
-
- Unused << NS_WARN_IF(NS_FAILED(infoService->GetPropertyAsACString(
- NS_LITERAL_STRING("device"), aRetVal)));
-}
-
-} //anonymous namespace
-
-/**
- * This wrapper is used to break circular-reference problem.
- */
-class DNSServiceWrappedListener final
- : public nsIDNSServiceDiscoveryListener
- , public nsIDNSServiceResolveListener
-{
-public:
- NS_DECL_ISUPPORTS
- NS_FORWARD_SAFE_NSIDNSSERVICEDISCOVERYLISTENER(mListener)
- NS_FORWARD_SAFE_NSIDNSSERVICERESOLVELISTENER(mListener)
-
- explicit DNSServiceWrappedListener() = default;
-
- nsresult SetListener(LegacyMDNSDeviceProvider* aListener)
- {
- mListener = aListener;
- return NS_OK;
- }
-
-private:
- virtual ~DNSServiceWrappedListener() = default;
-
- LegacyMDNSDeviceProvider* mListener = nullptr;
-};
-
-NS_IMPL_ISUPPORTS(DNSServiceWrappedListener,
- nsIDNSServiceDiscoveryListener,
- nsIDNSServiceResolveListener)
-
-NS_IMPL_ISUPPORTS(LegacyMDNSDeviceProvider,
- nsIPresentationDeviceProvider,
- nsIDNSServiceDiscoveryListener,
- nsIDNSServiceResolveListener,
- nsIObserver)
-
-LegacyMDNSDeviceProvider::~LegacyMDNSDeviceProvider()
-{
- Uninit();
-}
-
-nsresult
-LegacyMDNSDeviceProvider::Init()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (mInitialized) {
- return NS_OK;
- }
-
- nsresult rv;
-
- mMulticastDNS = do_GetService(DNSSERVICEDISCOVERY_CONTRACT_ID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mWrappedListener = new DNSServiceWrappedListener();
- if (NS_WARN_IF(NS_FAILED(rv = mWrappedListener->SetListener(this)))) {
- return rv;
- }
-
- mPresentationService = do_CreateInstance(LEGACY_PRESENTATION_CONTROL_SERVICE_CONTACT_ID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mDiscoveryTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- Preferences::AddStrongObservers(this, kObservedPrefs);
-
- mDiscoveryEnabled = Preferences::GetBool(PREF_PRESENTATION_DISCOVERY_LEGACY);
- mDiscoveryTimeoutMs = Preferences::GetUint(PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS);
- mServiceName = Preferences::GetCString(PREF_PRESENTATION_DEVICE_NAME);
-
- // FIXME: Bug 1185806 - Provide a common device name setting.
- if (mServiceName.IsEmpty()) {
- GetAndroidDeviceName(mServiceName);
- Unused << Preferences::SetCString(PREF_PRESENTATION_DEVICE_NAME, mServiceName);
- }
-
- Unused << mPresentationService->SetId(mServiceName);
-
- if (mDiscoveryEnabled && NS_WARN_IF(NS_FAILED(rv = ForceDiscovery()))) {
- return rv;
- }
-
- mInitialized = true;
- return NS_OK;
-}
-
-nsresult
-LegacyMDNSDeviceProvider::Uninit()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (!mInitialized) {
- return NS_OK;
- }
-
- ClearDevices();
-
- Preferences::RemoveObservers(this, kObservedPrefs);
-
- StopDiscovery(NS_OK);
-
- mMulticastDNS = nullptr;
-
- if (mWrappedListener) {
- mWrappedListener->SetListener(nullptr);
- mWrappedListener = nullptr;
- }
-
- mInitialized = false;
- return NS_OK;
-}
-
-nsresult
-LegacyMDNSDeviceProvider::StopDiscovery(nsresult aReason)
-{
- LOG_I("StopDiscovery (0x%08x)", aReason);
-
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mDiscoveryTimer);
-
- Unused << mDiscoveryTimer->Cancel();
-
- if (mDiscoveryRequest) {
- mDiscoveryRequest->Cancel(aReason);
- mDiscoveryRequest = nullptr;
- }
-
- return NS_OK;
-}
-
-nsresult
-LegacyMDNSDeviceProvider::Connect(Device* aDevice,
- nsIPresentationControlChannel** aRetVal)
-{
- MOZ_ASSERT(aDevice);
- MOZ_ASSERT(mPresentationService);
-
- RefPtr<TCPDeviceInfo> deviceInfo = new TCPDeviceInfo(aDevice->Id(),
- aDevice->Address(),
- aDevice->Port(),
- EmptyCString());
-
- return mPresentationService->Connect(deviceInfo, aRetVal);
-}
-
-nsresult
-LegacyMDNSDeviceProvider::AddDevice(const nsACString& aId,
- const nsACString& aServiceName,
- const nsACString& aServiceType,
- const nsACString& aAddress,
- const uint16_t aPort)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mPresentationService);
-
- RefPtr<Device> device = new Device(aId, /* ID */
- aServiceName,
- aServiceType,
- aAddress,
- aPort,
- DeviceState::eActive,
- this);
-
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
- Unused << listener->AddDevice(device);
- }
-
- mDevices.AppendElement(device);
-
- return NS_OK;
-}
-
-nsresult
-LegacyMDNSDeviceProvider::UpdateDevice(const uint32_t aIndex,
- const nsACString& aServiceName,
- const nsACString& aServiceType,
- const nsACString& aAddress,
- const uint16_t aPort)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mPresentationService);
-
- if (NS_WARN_IF(aIndex >= mDevices.Length())) {
- return NS_ERROR_INVALID_ARG;
- }
-
- RefPtr<Device> device = mDevices[aIndex];
- device->Update(aServiceName, aServiceType, aAddress, aPort);
- device->ChangeState(DeviceState::eActive);
-
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
- Unused << listener->UpdateDevice(device);
- }
-
- return NS_OK;
-}
-
-nsresult
-LegacyMDNSDeviceProvider::RemoveDevice(const uint32_t aIndex)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mPresentationService);
-
- if (NS_WARN_IF(aIndex >= mDevices.Length())) {
- return NS_ERROR_INVALID_ARG;
- }
-
- RefPtr<Device> device = mDevices[aIndex];
-
- LOG_I("RemoveDevice: %s", device->Id().get());
- mDevices.RemoveElementAt(aIndex);
-
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
- Unused << listener->RemoveDevice(device);
- }
-
- return NS_OK;
-}
-
-bool
-LegacyMDNSDeviceProvider::FindDeviceById(const nsACString& aId,
- uint32_t& aIndex)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- RefPtr<Device> device = new Device(aId,
- /* aName = */ EmptyCString(),
- /* aType = */ EmptyCString(),
- /* aHost = */ EmptyCString(),
- /* aPort = */ 0,
- /* aState = */ DeviceState::eUnknown,
- /* aProvider = */ nullptr);
- size_t index = mDevices.IndexOf(device, 0, DeviceIdComparator());
-
- if (index == mDevices.NoIndex) {
- return false;
- }
-
- aIndex = index;
- return true;
-}
-
-bool
-LegacyMDNSDeviceProvider::FindDeviceByAddress(const nsACString& aAddress,
- uint32_t& aIndex)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- RefPtr<Device> device = new Device(/* aId = */ EmptyCString(),
- /* aName = */ EmptyCString(),
- /* aType = */ EmptyCString(),
- aAddress,
- /* aPort = */ 0,
- /* aState = */ DeviceState::eUnknown,
- /* aProvider = */ nullptr);
- size_t index = mDevices.IndexOf(device, 0, DeviceAddressComparator());
-
- if (index == mDevices.NoIndex) {
- return false;
- }
-
- aIndex = index;
- return true;
-}
-
-void
-LegacyMDNSDeviceProvider::MarkAllDevicesUnknown()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- for (auto& device : mDevices) {
- device->ChangeState(DeviceState::eUnknown);
- }
-}
-
-void
-LegacyMDNSDeviceProvider::ClearUnknownDevices()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- size_t i = mDevices.Length();
- while (i > 0) {
- --i;
- if (mDevices[i]->State() == DeviceState::eUnknown) {
- Unused << NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
- }
- }
-}
-
-void
-LegacyMDNSDeviceProvider::ClearDevices()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- size_t i = mDevices.Length();
- while (i > 0) {
- --i;
- Unused << NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
- }
-}
-
-// nsIPresentationDeviceProvider
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::GetListener(nsIPresentationDeviceListener** aListener)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!aListener)) {
- return NS_ERROR_INVALID_POINTER;
- }
-
- nsresult rv;
- nsCOMPtr<nsIPresentationDeviceListener> listener =
- do_QueryReferent(mDeviceListener, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- listener.forget(aListener);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::SetListener(nsIPresentationDeviceListener* aListener)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- mDeviceListener = do_GetWeakReference(aListener);
-
- nsresult rv;
- if (mDeviceListener) {
- if (NS_WARN_IF(NS_FAILED(rv = Init()))) {
- return rv;
- }
- } else {
- if (NS_WARN_IF(NS_FAILED(rv = Uninit()))) {
- return rv;
- }
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::ForceDiscovery()
-{
- LOG_I("ForceDiscovery (%d)", mDiscoveryEnabled);
- MOZ_ASSERT(NS_IsMainThread());
-
- if (!mDiscoveryEnabled) {
- return NS_OK;
- }
-
- MOZ_ASSERT(mDiscoveryTimer);
- MOZ_ASSERT(mMulticastDNS);
-
- // if it's already discovering, extend existing discovery timeout.
- nsresult rv;
- if (mIsDiscovering) {
- Unused << mDiscoveryTimer->Cancel();
-
- if (NS_WARN_IF(NS_FAILED( rv = mDiscoveryTimer->Init(this,
- mDiscoveryTimeoutMs,
- nsITimer::TYPE_ONE_SHOT)))) {
- return rv;
- }
- return NS_OK;
- }
-
- StopDiscovery(NS_OK);
-
- if (NS_WARN_IF(NS_FAILED(rv = mMulticastDNS->StartDiscovery(
- NS_LITERAL_CSTRING(LEGACY_SERVICE_TYPE),
- mWrappedListener,
- getter_AddRefs(mDiscoveryRequest))))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-// nsIDNSServiceDiscoveryListener
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::OnDiscoveryStarted(const nsACString& aServiceType)
-{
- LOG_I("OnDiscoveryStarted");
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mDiscoveryTimer);
-
- MarkAllDevicesUnknown();
-
- nsresult rv;
- if (NS_WARN_IF(NS_FAILED(rv = mDiscoveryTimer->Init(this,
- mDiscoveryTimeoutMs,
- nsITimer::TYPE_ONE_SHOT)))) {
- return rv;
- }
-
- mIsDiscovering = true;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::OnDiscoveryStopped(const nsACString& aServiceType)
-{
- LOG_I("OnDiscoveryStopped");
- MOZ_ASSERT(NS_IsMainThread());
-
- ClearUnknownDevices();
-
- mIsDiscovering = false;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::OnServiceFound(nsIDNSServiceInfo* aServiceInfo)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!aServiceInfo)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- nsresult rv ;
-
- nsAutoCString serviceName;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(serviceName)))) {
- return rv;
- }
-
- LOG_I("OnServiceFound: %s", serviceName.get());
-
- if (mMulticastDNS) {
- if (NS_WARN_IF(NS_FAILED(rv = mMulticastDNS->ResolveService(
- aServiceInfo, mWrappedListener)))) {
- return rv;
- }
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::OnServiceLost(nsIDNSServiceInfo* aServiceInfo)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!aServiceInfo)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- nsresult rv;
-
- nsAutoCString serviceName;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(serviceName)))) {
- return rv;
- }
-
- LOG_I("OnServiceLost: %s", serviceName.get());
-
- nsAutoCString host;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetHost(host)))) {
- return rv;
- }
-
- uint32_t index;
- if (!FindDeviceById(host, index)) {
- // given device was not found
- return NS_OK;
- }
-
- if (NS_WARN_IF(NS_FAILED(rv = RemoveDevice(index)))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::OnStartDiscoveryFailed(const nsACString& aServiceType,
- int32_t aErrorCode)
-{
- LOG_E("OnStartDiscoveryFailed: %d", aErrorCode);
- MOZ_ASSERT(NS_IsMainThread());
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::OnStopDiscoveryFailed(const nsACString& aServiceType,
- int32_t aErrorCode)
-{
- LOG_E("OnStopDiscoveryFailed: %d", aErrorCode);
- MOZ_ASSERT(NS_IsMainThread());
-
- return NS_OK;
-}
-
-// nsIDNSServiceResolveListener
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::OnServiceResolved(nsIDNSServiceInfo* aServiceInfo)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!aServiceInfo)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- nsresult rv;
-
- nsAutoCString serviceName;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(serviceName)))) {
- return rv;
- }
-
- LOG_I("OnServiceResolved: %s", serviceName.get());
-
- nsAutoCString host;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetHost(host)))) {
- return rv;
- }
-
- nsAutoCString address;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetAddress(address)))) {
- return rv;
- }
-
- uint16_t port;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetPort(&port)))) {
- return rv;
- }
-
- nsAutoCString serviceType;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceType(serviceType)))) {
- return rv;
- }
-
- uint32_t index;
- if (FindDeviceById(host, index)) {
- return UpdateDevice(index,
- serviceName,
- serviceType,
- address,
- port);
- } else {
- return AddDevice(host,
- serviceName,
- serviceType,
- address,
- port);
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::OnResolveFailed(nsIDNSServiceInfo* aServiceInfo,
- int32_t aErrorCode)
-{
- LOG_E("OnResolveFailed: %d", aErrorCode);
- MOZ_ASSERT(NS_IsMainThread());
-
- return NS_OK;
-}
-
-// nsIObserver
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::Observe(nsISupports* aSubject,
- const char* aTopic,
- const char16_t* aData)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- NS_ConvertUTF16toUTF8 data(aData);
- LOG_I("Observe: topic = %s, data = %s", aTopic, data.get());
-
- if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
- if (data.EqualsLiteral(PREF_PRESENTATION_DISCOVERY_LEGACY)) {
- OnDiscoveryChanged(Preferences::GetBool(PREF_PRESENTATION_DISCOVERY_LEGACY));
- } else if (data.EqualsLiteral(PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS)) {
- OnDiscoveryTimeoutChanged(Preferences::GetUint(PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS));
- } else if (data.EqualsLiteral(PREF_PRESENTATION_DEVICE_NAME)) {
- nsAdoptingCString newServiceName = Preferences::GetCString(PREF_PRESENTATION_DEVICE_NAME);
- if (!mServiceName.Equals(newServiceName)) {
- OnServiceNameChanged(newServiceName);
- }
- }
- } else if (!strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC)) {
- StopDiscovery(NS_OK);
- }
-
- return NS_OK;
-}
-
-nsresult
-LegacyMDNSDeviceProvider::OnDiscoveryChanged(bool aEnabled)
-{
- LOG_I("DiscoveryEnabled = %d\n", aEnabled);
- MOZ_ASSERT(NS_IsMainThread());
-
- mDiscoveryEnabled = aEnabled;
-
- if (mDiscoveryEnabled) {
- return ForceDiscovery();
- }
-
- return StopDiscovery(NS_OK);
-}
-
-nsresult
-LegacyMDNSDeviceProvider::OnDiscoveryTimeoutChanged(uint32_t aTimeoutMs)
-{
- LOG_I("OnDiscoveryTimeoutChanged = %d\n", aTimeoutMs);
- MOZ_ASSERT(NS_IsMainThread());
-
- mDiscoveryTimeoutMs = aTimeoutMs;
-
- return NS_OK;
-}
-
-nsresult
-LegacyMDNSDeviceProvider::OnServiceNameChanged(const nsACString& aServiceName)
-{
- LOG_I("serviceName = %s\n", PromiseFlatCString(aServiceName).get());
- MOZ_ASSERT(NS_IsMainThread());
-
- mServiceName = aServiceName;
- mPresentationService->SetId(mServiceName);
-
- return NS_OK;
-}
-
-// LegacyMDNSDeviceProvider::Device
-NS_IMPL_ISUPPORTS(LegacyMDNSDeviceProvider::Device,
- nsIPresentationDevice)
-
-// nsIPresentationDevice
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::Device::GetId(nsACString& aId)
-{
- aId = mId;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::Device::GetName(nsACString& aName)
-{
- aName = mName;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::Device::GetType(nsACString& aType)
-{
- aType = mType;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::Device::EstablishControlChannel(
- nsIPresentationControlChannel** aRetVal)
-{
- if (!mProvider) {
- return NS_ERROR_FAILURE;
- }
-
- return mProvider->Connect(this, aRetVal);
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::Device::Disconnect()
-{
- // No need to do anything when disconnect.
- return NS_OK;
-}
-
-NS_IMETHODIMP
-LegacyMDNSDeviceProvider::Device::IsRequestedUrlSupported(
- const nsAString& aRequestedUrl,
- bool* aRetVal)
-{
- if (!aRetVal) {
- return NS_ERROR_INVALID_POINTER;
- }
-
- // Legacy TV 2.5 device only support a fixed set of presentation Apps.
- *aRetVal = DeviceProviderHelpers::IsFxTVSupportedAppUrl(aRequestedUrl);
-
- return NS_OK;
-}
-
-} // namespace legacy
-} // namespace presentation
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/provider/LegacyMDNSDeviceProvider.h b/dom/presentation/provider/LegacyMDNSDeviceProvider.h
deleted file mode 100644
index 33ba877d3..000000000
--- a/dom/presentation/provider/LegacyMDNSDeviceProvider.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_presentation_provider_LegacyMDNSDeviceProvider_h
-#define mozilla_dom_presentation_provider_LegacyMDNSDeviceProvider_h
-
-#include "mozilla/RefPtr.h"
-#include "nsCOMPtr.h"
-#include "nsICancelable.h"
-#include "nsIDNSServiceDiscovery.h"
-#include "nsIObserver.h"
-#include "nsIPresentationDevice.h"
-#include "nsIPresentationDeviceProvider.h"
-#include "nsIPresentationControlService.h"
-#include "nsITimer.h"
-#include "nsString.h"
-#include "nsTArray.h"
-#include "nsWeakPtr.h"
-
-namespace mozilla {
-namespace dom {
-namespace presentation {
-namespace legacy {
-
-class DNSServiceWrappedListener;
-class MulticastDNSService;
-
-class LegacyMDNSDeviceProvider final
- : public nsIPresentationDeviceProvider
- , public nsIDNSServiceDiscoveryListener
- , public nsIDNSServiceResolveListener
- , public nsIObserver
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONDEVICEPROVIDER
- NS_DECL_NSIDNSSERVICEDISCOVERYLISTENER
- NS_DECL_NSIDNSSERVICERESOLVELISTENER
- NS_DECL_NSIOBSERVER
-
- explicit LegacyMDNSDeviceProvider() = default;
- nsresult Init();
- nsresult Uninit();
-
-private:
- enum class DeviceState : uint32_t {
- eUnknown,
- eActive
- };
-
- class Device final : public nsIPresentationDevice
- {
- public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONDEVICE
-
- explicit Device(const nsACString& aId,
- const nsACString& aName,
- const nsACString& aType,
- const nsACString& aAddress,
- const uint16_t aPort,
- DeviceState aState,
- LegacyMDNSDeviceProvider* aProvider)
- : mId(aId)
- , mName(aName)
- , mType(aType)
- , mAddress(aAddress)
- , mPort(aPort)
- , mState(aState)
- , mProvider(aProvider)
- {
- }
-
- const nsCString& Id() const
- {
- return mId;
- }
-
- const nsCString& Address() const
- {
- return mAddress;
- }
-
- uint16_t Port() const
- {
- return mPort;
- }
-
- DeviceState State() const
- {
- return mState;
- }
-
- void ChangeState(DeviceState aState)
- {
- mState = aState;
- }
-
- void Update(const nsACString& aName,
- const nsACString& aType,
- const nsACString& aAddress,
- const uint16_t aPort)
- {
- mName = aName;
- mType = aType;
- mAddress = aAddress;
- mPort = aPort;
- }
-
- private:
- virtual ~Device() = default;
-
- nsCString mId;
- nsCString mName;
- nsCString mType;
- nsCString mAddress;
- uint16_t mPort;
- DeviceState mState;
- LegacyMDNSDeviceProvider* mProvider;
- };
-
- struct DeviceIdComparator {
- bool Equals(const RefPtr<Device>& aA, const RefPtr<Device>& aB) const {
- return aA->Id() == aB->Id();
- }
- };
-
- struct DeviceAddressComparator {
- bool Equals(const RefPtr<Device>& aA, const RefPtr<Device>& aB) const {
- return aA->Address() == aB->Address();
- }
- };
-
- virtual ~LegacyMDNSDeviceProvider();
- nsresult StopDiscovery(nsresult aReason);
- nsresult Connect(Device* aDevice,
- nsIPresentationControlChannel** aRetVal);
-
- // device manipulation
- nsresult AddDevice(const nsACString& aId,
- const nsACString& aServiceName,
- const nsACString& aServiceType,
- const nsACString& aAddress,
- const uint16_t aPort);
- nsresult UpdateDevice(const uint32_t aIndex,
- const nsACString& aServiceName,
- const nsACString& aServiceType,
- const nsACString& aAddress,
- const uint16_t aPort);
- nsresult RemoveDevice(const uint32_t aIndex);
- bool FindDeviceById(const nsACString& aId,
- uint32_t& aIndex);
-
- bool FindDeviceByAddress(const nsACString& aAddress,
- uint32_t& aIndex);
-
- void MarkAllDevicesUnknown();
- void ClearUnknownDevices();
- void ClearDevices();
-
- // preferences
- nsresult OnDiscoveryChanged(bool aEnabled);
- nsresult OnDiscoveryTimeoutChanged(uint32_t aTimeoutMs);
- nsresult OnServiceNameChanged(const nsACString& aServiceName);
-
- bool mInitialized = false;
- nsWeakPtr mDeviceListener;
- nsCOMPtr<nsIPresentationControlService> mPresentationService;
- nsCOMPtr<nsIDNSServiceDiscovery> mMulticastDNS;
- RefPtr<DNSServiceWrappedListener> mWrappedListener;
-
- nsCOMPtr<nsICancelable> mDiscoveryRequest;
-
- nsTArray<RefPtr<Device>> mDevices;
-
- bool mDiscoveryEnabled = false;
- bool mIsDiscovering = false;
- uint32_t mDiscoveryTimeoutMs;
- nsCOMPtr<nsITimer> mDiscoveryTimer;
-
- nsCString mServiceName;
-};
-
-} // namespace legacy
-} // namespace presentation
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_presentation_provider_LegacyMDNSDeviceProvider_h
diff --git a/dom/presentation/provider/LegacyPresentationControlService.js b/dom/presentation/provider/LegacyPresentationControlService.js
deleted file mode 100644
index b27177b63..000000000
--- a/dom/presentation/provider/LegacyPresentationControlService.js
+++ /dev/null
@@ -1,488 +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/. */
-/* jshint esnext:true, globalstrict:true, moz:true, undef:true, unused:true */
-/* globals Components, dump */
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-/* globals XPCOMUtils */
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-/* globals Services */
-Cu.import("resource://gre/modules/Services.jsm");
-/* globals NetUtil */
-Cu.import("resource://gre/modules/NetUtil.jsm");
-
-const DEBUG = Services.prefs.getBoolPref("dom.presentation.tcp_server.debug");
-function log(aMsg) {
- dump("-*- LegacyPresentationControlService.js: " + aMsg + "\n");
-}
-
-function LegacyPresentationControlService() {
- DEBUG && log("LegacyPresentationControlService - ctor"); //jshint ignore:line
- this._id = null;
-}
-
-LegacyPresentationControlService.prototype = {
- startServer: function() {
- DEBUG && log("LegacyPresentationControlService - doesn't support receiver mode"); //jshint ignore:line
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- get id() {
- return this._id;
- },
-
- set id(aId) {
- this._id = aId;
- },
-
- get port() {
- return 0;
- },
-
- get version() {
- return 0;
- },
-
- set listener(aListener) { //jshint ignore:line
- DEBUG && log("LegacyPresentationControlService - doesn't support receiver mode"); //jshint ignore:line
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- get listener() {
- return null;
- },
-
- connect: function(aDeviceInfo) {
- if (!this.id) {
- DEBUG && log("LegacyPresentationControlService - Id has not initialized; requestSession fails"); //jshint ignore:line
- return null;
- }
- DEBUG && log("LegacyPresentationControlService - requestSession to " + aDeviceInfo.id); //jshint ignore:line
-
- let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
- .getService(Ci.nsISocketTransportService);
-
- let socketTransport;
- try {
- socketTransport = sts.createTransport(null,
- 0,
- aDeviceInfo.address,
- aDeviceInfo.port,
- null);
- } catch (e) {
- DEBUG && log("LegacyPresentationControlService - createTransport throws: " + e); //jshint ignore:line
- // Pop the exception to |TCPDevice.establishControlChannel|
- throw Cr.NS_ERROR_FAILURE;
- }
- return new LegacyTCPControlChannel(this.id,
- socketTransport,
- aDeviceInfo);
- },
-
- close: function() {
- DEBUG && log("LegacyPresentationControlService - close"); //jshint ignore:line
- },
-
- classID: Components.ID("{b21816fe-8aff-4811-86d2-85a7444c557e}"),
- QueryInterface : XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
-};
-
-function ChannelDescription(aInit) {
- this._type = aInit.type;
- switch (this._type) {
- case Ci.nsIPresentationChannelDescription.TYPE_TCP:
- this._tcpAddresses = Cc["@mozilla.org/array;1"]
- .createInstance(Ci.nsIMutableArray);
- for (let address of aInit.tcpAddress) {
- let wrapper = Cc["@mozilla.org/supports-cstring;1"]
- .createInstance(Ci.nsISupportsCString);
- wrapper.data = address;
- this._tcpAddresses.appendElement(wrapper, false);
- }
-
- this._tcpPort = aInit.tcpPort;
- break;
- case Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL:
- this._dataChannelSDP = aInit.dataChannelSDP;
- break;
- }
-}
-
-ChannelDescription.prototype = {
- _type: 0,
- _tcpAddresses: null,
- _tcpPort: 0,
- _dataChannelSDP: "",
-
- get type() {
- return this._type;
- },
-
- get tcpAddress() {
- return this._tcpAddresses;
- },
-
- get tcpPort() {
- return this._tcpPort;
- },
-
- get dataChannelSDP() {
- return this._dataChannelSDP;
- },
-
- classID: Components.ID("{d69fc81c-4f40-47a3-97e6-b4cf5db2294e}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
-};
-
-// Helper function: transfer nsIPresentationChannelDescription to json
-function discriptionAsJson(aDescription) {
- let json = {};
- json.type = aDescription.type;
- switch(aDescription.type) {
- case Ci.nsIPresentationChannelDescription.TYPE_TCP:
- let addresses = aDescription.tcpAddress.QueryInterface(Ci.nsIArray);
- json.tcpAddress = [];
- for (let idx = 0; idx < addresses.length; idx++) {
- let address = addresses.queryElementAt(idx, Ci.nsISupportsCString);
- json.tcpAddress.push(address.data);
- }
- json.tcpPort = aDescription.tcpPort;
- break;
- case Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL:
- json.dataChannelSDP = aDescription.dataChannelSDP;
- break;
- }
- return json;
-}
-
-function LegacyTCPControlChannel(id,
- transport,
- deviceInfo) {
- DEBUG && log("create LegacyTCPControlChannel"); //jshint ignore:line
- this._deviceInfo = deviceInfo;
- this._transport = transport;
-
- this._id = id;
-
- let currentThread = Services.tm.currentThread;
- transport.setEventSink(this, currentThread);
-
- this._input = this._transport.openInputStream(0, 0, 0)
- .QueryInterface(Ci.nsIAsyncInputStream);
- this._input.asyncWait(this.QueryInterface(Ci.nsIStreamListener),
- Ci.nsIAsyncInputStream.WAIT_CLOSURE_ONLY,
- 0,
- currentThread);
-
- this._output = this._transport
- .openOutputStream(Ci.nsITransport.OPEN_UNBUFFERED, 0, 0);
-}
-
-LegacyTCPControlChannel.prototype = {
- _connected: false,
- _pendingOpen: false,
- _pendingAnswer: null,
- _pendingClose: null,
- _pendingCloseReason: null,
-
- _sendMessage: function(aJSONData, aOnThrow) {
- if (!aOnThrow) {
- aOnThrow = function(e) {throw e.result;};
- }
-
- if (!aJSONData) {
- aOnThrow();
- return;
- }
-
- if (!this._connected) {
- DEBUG && log("LegacyTCPControlChannel - send" + aJSONData.type + " fails"); //jshint ignore:line
- throw Cr.NS_ERROR_FAILURE;
- }
-
- try {
- this._send(aJSONData);
- } catch (e) {
- aOnThrow(e);
- }
- },
-
- _sendInit: function() {
- let msg = {
- type: "requestSession:Init",
- presentationId: this._presentationId,
- url: this._url,
- id: this._id,
- };
-
- this._sendMessage(msg, function(e) {
- this.disconnect();
- this._notifyDisconnected(e.result);
- });
- },
-
- launch: function(aPresentationId, aUrl) {
- this._presentationId = aPresentationId;
- this._url = aUrl;
-
- this._sendInit();
- },
-
- terminate: function() {
- // Legacy protocol doesn't support extra terminate protocol.
- // Trigger error handling for browser to shutdown all the resource locally.
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- sendOffer: function(aOffer) {
- let msg = {
- type: "requestSession:Offer",
- presentationId: this._presentationId,
- offer: discriptionAsJson(aOffer),
- };
- this._sendMessage(msg);
- },
-
- sendAnswer: function(aAnswer) { //jshint ignore:line
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- sendIceCandidate: function(aCandidate) {
- let msg = {
- type: "requestSession:IceCandidate",
- presentationId: this._presentationId,
- iceCandidate: aCandidate,
- };
- this._sendMessage(msg);
- },
- // may throw an exception
- _send: function(aMsg) {
- DEBUG && log("LegacyTCPControlChannel - Send: " + JSON.stringify(aMsg, null, 2)); //jshint ignore:line
-
- /**
- * XXX In TCP streaming, it is possible that more than one message in one
- * TCP packet. We use line delimited JSON to identify where one JSON encoded
- * object ends and the next begins. Therefore, we do not allow newline
- * characters whithin the whole message, and add a newline at the end.
- * Please see the parser code in |onDataAvailable|.
- */
- let message = JSON.stringify(aMsg).replace(["\n"], "") + "\n";
- try {
- this._output.write(message, message.length);
- } catch(e) {
- DEBUG && log("LegacyTCPControlChannel - Failed to send message: " + e.name); //jshint ignore:line
- throw e;
- }
- },
-
- // nsIAsyncInputStream (Triggered by nsIInputStream.asyncWait)
- // Only used for detecting connection refused
- onInputStreamReady: function(aStream) {
- try {
- aStream.available();
- } catch (e) {
- DEBUG && log("LegacyTCPControlChannel - onInputStreamReady error: " + e.name); //jshint ignore:line
- // NS_ERROR_CONNECTION_REFUSED
- this._listener.notifyDisconnected(e.result);
- }
- },
-
- // nsITransportEventSink (Triggered by nsISocketTransport.setEventSink)
- onTransportStatus: function(aTransport, aStatus, aProg, aProgMax) { //jshint ignore:line
- DEBUG && log("LegacyTCPControlChannel - onTransportStatus: "
- + aStatus.toString(16)); //jshint ignore:line
- if (aStatus === Ci.nsISocketTransport.STATUS_CONNECTED_TO) {
- this._connected = true;
-
- if (!this._pump) {
- this._createInputStreamPump();
- }
-
- this._notifyConnected();
- }
- },
-
- // nsIRequestObserver (Triggered by nsIInputStreamPump.asyncRead)
- onStartRequest: function() {
- DEBUG && log("LegacyTCPControlChannel - onStartRequest"); //jshint ignore:line
- },
-
- // nsIRequestObserver (Triggered by nsIInputStreamPump.asyncRead)
- onStopRequest: function(aRequest, aContext, aStatus) {
- DEBUG && log("LegacyTCPControlChannel - onStopRequest: " + aStatus); //jshint ignore:line
- this.disconnect(aStatus);
- this._notifyDisconnected(aStatus);
- },
-
- // nsIStreamListener (Triggered by nsIInputStreamPump.asyncRead)
- onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) { //jshint ignore:line
- let data = NetUtil.readInputStreamToString(aInputStream,
- aInputStream.available());
- DEBUG && log("LegacyTCPControlChannel - onDataAvailable: " + data); //jshint ignore:line
-
- // Parser of line delimited JSON. Please see |_send| for more informaiton.
- let jsonArray = data.split("\n");
- jsonArray.pop();
- for (let json of jsonArray) {
- let msg;
- try {
- msg = JSON.parse(json);
- } catch (e) {
- DEBUG && log("LegacyTCPSignalingChannel - error in parsing json: " + e); //jshint ignore:line
- }
-
- this._handleMessage(msg);
- }
- },
-
- _createInputStreamPump: function() {
- DEBUG && log("LegacyTCPControlChannel - create pump"); //jshint ignore:line
- this._pump = Cc["@mozilla.org/network/input-stream-pump;1"].
- createInstance(Ci.nsIInputStreamPump);
- this._pump.init(this._input, -1, -1, 0, 0, false);
- this._pump.asyncRead(this, null);
- },
-
- // Handle command from remote side
- _handleMessage: function(aMsg) {
- DEBUG && log("LegacyTCPControlChannel - handleMessage from "
- + JSON.stringify(this._deviceInfo) + ": " + JSON.stringify(aMsg)); //jshint ignore:line
- switch (aMsg.type) {
- case "requestSession:Answer": {
- this._onAnswer(aMsg.answer);
- break;
- }
- case "requestSession:IceCandidate": {
- this._listener.onIceCandidate(aMsg.iceCandidate);
- break;
- }
- case "requestSession:CloseReason": {
- this._pendingCloseReason = aMsg.reason;
- break;
- }
- }
- },
-
- get listener() {
- return this._listener;
- },
-
- set listener(aListener) {
- DEBUG && log("LegacyTCPControlChannel - set listener: " + aListener); //jshint ignore:line
- if (!aListener) {
- this._listener = null;
- return;
- }
-
- this._listener = aListener;
- if (this._pendingOpen) {
- this._pendingOpen = false;
- DEBUG && log("LegacyTCPControlChannel - notify pending opened"); //jshint ignore:line
- this._listener.notifyConnected();
- }
-
- if (this._pendingAnswer) {
- let answer = this._pendingAnswer;
- DEBUG && log("LegacyTCPControlChannel - notify pending answer: " +
- JSON.stringify(answer)); // jshint ignore:line
- this._listener.onAnswer(new ChannelDescription(answer));
- this._pendingAnswer = null;
- }
-
- if (this._pendingClose) {
- DEBUG && log("LegacyTCPControlChannel - notify pending closed"); //jshint ignore:line
- this._notifyDisconnected(this._pendingCloseReason);
- this._pendingClose = null;
- }
- },
-
- /**
- * These functions are designed to handle the interaction with listener
- * appropriately. |_FUNC| is to handle |this._listener.FUNC|.
- */
- _onAnswer: function(aAnswer) {
- if (!this._connected) {
- return;
- }
- if (!this._listener) {
- this._pendingAnswer = aAnswer;
- return;
- }
- DEBUG && log("LegacyTCPControlChannel - notify answer: " + JSON.stringify(aAnswer)); //jshint ignore:line
- this._listener.onAnswer(new ChannelDescription(aAnswer));
- },
-
- _notifyConnected: function() {
- this._connected = true;
- this._pendingClose = false;
- this._pendingCloseReason = Cr.NS_OK;
-
- if (!this._listener) {
- this._pendingOpen = true;
- return;
- }
-
- DEBUG && log("LegacyTCPControlChannel - notify opened"); //jshint ignore:line
- this._listener.notifyConnected();
- },
-
- _notifyDisconnected: function(aReason) {
- this._connected = false;
- this._pendingOpen = false;
- this._pendingAnswer = null;
-
- // Remote endpoint closes the control channel with abnormal reason.
- if (aReason == Cr.NS_OK && this._pendingCloseReason != Cr.NS_OK) {
- aReason = this._pendingCloseReason;
- }
-
- if (!this._listener) {
- this._pendingClose = true;
- this._pendingCloseReason = aReason;
- return;
- }
-
- DEBUG && log("LegacyTCPControlChannel - notify closed"); //jshint ignore:line
- this._listener.notifyDisconnected(aReason);
- },
-
- disconnect: function(aReason) {
- DEBUG && log("LegacyTCPControlChannel - close with reason: " + aReason); //jshint ignore:line
-
- if (this._connected) {
- // default reason is NS_OK
- if (typeof aReason !== "undefined" && aReason !== Cr.NS_OK) {
- let msg = {
- type: "requestSession:CloseReason",
- presentationId: this._presentationId,
- reason: aReason,
- };
- this._sendMessage(msg);
- this._pendingCloseReason = aReason;
- }
-
- this._transport.setEventSink(null, null);
- this._pump = null;
-
- this._input.close();
- this._output.close();
-
- this._connected = false;
- }
- },
-
- reconnect: function() {
- // Legacy protocol doesn't support extra reconnect protocol.
- // Trigger error handling for browser to shutdown all the resource locally.
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- classID: Components.ID("{4027ce3d-06e3-4d06-a235-df329cb0d411}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel,
- Ci.nsIStreamListener]),
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([LegacyPresentationControlService]); //jshint ignore:line
diff --git a/dom/presentation/provider/LegacyProviders.manifest b/dom/presentation/provider/LegacyProviders.manifest
deleted file mode 100644
index 9408da063..000000000
--- a/dom/presentation/provider/LegacyProviders.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {b21816fe-8aff-4811-86d2-85a7444c557e} LegacyPresentationControlService.js
-contract @mozilla.org/presentation/legacy-control-service;1 {b21816fe-8aff-4811-86d2-85a7444c557e}
diff --git a/dom/presentation/provider/MulticastDNSDeviceProvider.cpp b/dom/presentation/provider/MulticastDNSDeviceProvider.cpp
deleted file mode 100644
index 0cab915ac..000000000
--- a/dom/presentation/provider/MulticastDNSDeviceProvider.cpp
+++ /dev/null
@@ -1,1249 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "MulticastDNSDeviceProvider.h"
-
-#include "DeviceProviderHelpers.h"
-#include "MainThreadUtils.h"
-#include "mozilla/Logging.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/Services.h"
-#include "mozilla/Unused.h"
-#include "nsComponentManagerUtils.h"
-#include "nsIObserverService.h"
-#include "nsIWritablePropertyBag2.h"
-#include "nsServiceManagerUtils.h"
-#include "nsTCPDeviceInfo.h"
-#include "nsThreadUtils.h"
-
-#ifdef MOZ_WIDGET_ANDROID
-#include "nsIPropertyBag2.h"
-#endif // MOZ_WIDGET_ANDROID
-
-#define PREF_PRESENTATION_DISCOVERY "dom.presentation.discovery.enabled"
-#define PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS "dom.presentation.discovery.timeout_ms"
-#define PREF_PRESENTATION_DISCOVERABLE "dom.presentation.discoverable"
-#define PREF_PRESENTATION_DISCOVERABLE_ENCRYPTED "dom.presentation.discoverable.encrypted"
-#define PREF_PRESENTATION_DISCOVERABLE_RETRY_MS "dom.presentation.discoverable.retry_ms"
-#define PREF_PRESENTATION_DEVICE_NAME "dom.presentation.device.name"
-
-#define SERVICE_TYPE "_presentation-ctrl._tcp"
-#define PROTOCOL_VERSION_TAG "version"
-#define CERT_FINGERPRINT_TAG "certFingerprint"
-
-static mozilla::LazyLogModule sMulticastDNSProviderLogModule("MulticastDNSDeviceProvider");
-
-#undef LOG_I
-#define LOG_I(...) MOZ_LOG(sMulticastDNSProviderLogModule, mozilla::LogLevel::Debug, (__VA_ARGS__))
-#undef LOG_E
-#define LOG_E(...) MOZ_LOG(sMulticastDNSProviderLogModule, mozilla::LogLevel::Error, (__VA_ARGS__))
-
-namespace mozilla {
-namespace dom {
-namespace presentation {
-
-static const char* kObservedPrefs[] = {
- PREF_PRESENTATION_DISCOVERY,
- PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS,
- PREF_PRESENTATION_DISCOVERABLE,
- PREF_PRESENTATION_DEVICE_NAME,
- nullptr
-};
-
-namespace {
-
-#ifdef MOZ_WIDGET_ANDROID
-static void
-GetAndroidDeviceName(nsACString& aRetVal)
-{
- nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
- MOZ_ASSERT(infoService, "Could not find a system info service");
-
- Unused << NS_WARN_IF(NS_FAILED(infoService->GetPropertyAsACString(
- NS_LITERAL_STRING("device"), aRetVal)));
-}
-#endif // MOZ_WIDGET_ANDROID
-
-} //anonymous namespace
-
-/**
- * This wrapper is used to break circular-reference problem.
- */
-class DNSServiceWrappedListener final
- : public nsIDNSServiceDiscoveryListener
- , public nsIDNSRegistrationListener
- , public nsIDNSServiceResolveListener
- , public nsIPresentationControlServerListener
-{
-public:
- NS_DECL_ISUPPORTS
- NS_FORWARD_SAFE_NSIDNSSERVICEDISCOVERYLISTENER(mListener)
- NS_FORWARD_SAFE_NSIDNSREGISTRATIONLISTENER(mListener)
- NS_FORWARD_SAFE_NSIDNSSERVICERESOLVELISTENER(mListener)
- NS_FORWARD_SAFE_NSIPRESENTATIONCONTROLSERVERLISTENER(mListener)
-
- explicit DNSServiceWrappedListener() = default;
-
- nsresult SetListener(MulticastDNSDeviceProvider* aListener)
- {
- mListener = aListener;
- return NS_OK;
- }
-
-private:
- virtual ~DNSServiceWrappedListener() = default;
-
- MulticastDNSDeviceProvider* mListener = nullptr;
-};
-
-NS_IMPL_ISUPPORTS(DNSServiceWrappedListener,
- nsIDNSServiceDiscoveryListener,
- nsIDNSRegistrationListener,
- nsIDNSServiceResolveListener,
- nsIPresentationControlServerListener)
-
-NS_IMPL_ISUPPORTS(MulticastDNSDeviceProvider,
- nsIPresentationDeviceProvider,
- nsIDNSServiceDiscoveryListener,
- nsIDNSRegistrationListener,
- nsIDNSServiceResolveListener,
- nsIPresentationControlServerListener,
- nsIObserver)
-
-MulticastDNSDeviceProvider::~MulticastDNSDeviceProvider()
-{
- Uninit();
-}
-
-nsresult
-MulticastDNSDeviceProvider::Init()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (mInitialized) {
- return NS_OK;
- }
-
- nsresult rv;
-
- mMulticastDNS = do_GetService(DNSSERVICEDISCOVERY_CONTRACT_ID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mWrappedListener = new DNSServiceWrappedListener();
- if (NS_WARN_IF(NS_FAILED(rv = mWrappedListener->SetListener(this)))) {
- return rv;
- }
-
- mPresentationService = do_CreateInstance(PRESENTATION_CONTROL_SERVICE_CONTACT_ID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mDiscoveryTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mServerRetryTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- Preferences::AddStrongObservers(this, kObservedPrefs);
-
- mDiscoveryEnabled = Preferences::GetBool(PREF_PRESENTATION_DISCOVERY);
- mDiscoveryTimeoutMs = Preferences::GetUint(PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS);
- mDiscoverable = Preferences::GetBool(PREF_PRESENTATION_DISCOVERABLE);
- mDiscoverableEncrypted = Preferences::GetBool(PREF_PRESENTATION_DISCOVERABLE_ENCRYPTED);
- mServerRetryMs = Preferences::GetUint(PREF_PRESENTATION_DISCOVERABLE_RETRY_MS);
- mServiceName = Preferences::GetCString(PREF_PRESENTATION_DEVICE_NAME);
-
-#ifdef MOZ_WIDGET_ANDROID
- // FIXME: Bug 1185806 - Provide a common device name setting.
- if (mServiceName.IsEmpty()) {
- GetAndroidDeviceName(mServiceName);
- Unused << Preferences::SetCString(PREF_PRESENTATION_DEVICE_NAME, mServiceName);
- }
-#endif // MOZ_WIDGET_ANDROID
-
- Unused << mPresentationService->SetId(mServiceName);
-
- if (mDiscoveryEnabled && NS_WARN_IF(NS_FAILED(rv = ForceDiscovery()))) {
- return rv;
- }
-
- if (mDiscoverable && NS_WARN_IF(NS_FAILED(rv = StartServer()))) {
- return rv;
- }
-
- mInitialized = true;
- return NS_OK;
-}
-
-nsresult
-MulticastDNSDeviceProvider::Uninit()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (!mInitialized) {
- return NS_OK;
- }
-
- ClearDevices();
-
- Preferences::RemoveObservers(this, kObservedPrefs);
-
- StopDiscovery(NS_OK);
- StopServer();
-
- mMulticastDNS = nullptr;
-
- if (mWrappedListener) {
- mWrappedListener->SetListener(nullptr);
- mWrappedListener = nullptr;
- }
-
- mInitialized = false;
- return NS_OK;
-}
-
-nsresult
-MulticastDNSDeviceProvider::StartServer()
-{
- LOG_I("StartServer: %s (%d)", mServiceName.get(), mDiscoverable);
- MOZ_ASSERT(NS_IsMainThread());
-
- if (!mDiscoverable) {
- return NS_OK;
- }
-
- nsresult rv;
-
- uint16_t servicePort;
- if (NS_WARN_IF(NS_FAILED(rv = mPresentationService->GetPort(&servicePort)))) {
- return rv;
- }
-
- /**
- * If |servicePort| is non-zero, it means PresentationControlService is running.
- * Otherwise, we should make it start serving.
- */
- if (servicePort) {
- return RegisterMDNSService();
- }
-
- if (NS_WARN_IF(NS_FAILED(rv = mPresentationService->SetListener(mWrappedListener)))) {
- return rv;
- }
-
- AbortServerRetry();
-
- if (NS_WARN_IF(NS_FAILED(rv = mPresentationService->StartServer(mDiscoverableEncrypted, 0)))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-nsresult
-MulticastDNSDeviceProvider::StopServer()
-{
- LOG_I("StopServer: %s", mServiceName.get());
- MOZ_ASSERT(NS_IsMainThread());
-
- UnregisterMDNSService(NS_OK);
-
- AbortServerRetry();
-
- if (mPresentationService) {
- mPresentationService->SetListener(nullptr);
- mPresentationService->Close();
- }
-
- return NS_OK;
-}
-
-void
-MulticastDNSDeviceProvider::AbortServerRetry()
-{
- if (mIsServerRetrying) {
- mIsServerRetrying = false;
- mServerRetryTimer->Cancel();
- }
-}
-
-nsresult
-MulticastDNSDeviceProvider::RegisterMDNSService()
-{
- LOG_I("RegisterMDNSService: %s", mServiceName.get());
-
- if (!mDiscoverable) {
- return NS_OK;
- }
-
- // Cancel on going service registration.
- UnregisterMDNSService(NS_OK);
-
- nsresult rv;
-
- uint16_t servicePort;
- if (NS_FAILED(rv = mPresentationService->GetPort(&servicePort)) ||
- !servicePort) {
- // Abort service registration if server port is not available.
- return rv;
- }
-
- /**
- * Register the presentation control channel server as an mDNS service.
- */
- nsCOMPtr<nsIDNSServiceInfo> serviceInfo =
- do_CreateInstance(DNSSERVICEINFO_CONTRACT_ID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- if (NS_WARN_IF(NS_FAILED(rv = serviceInfo->SetServiceType(
- NS_LITERAL_CSTRING(SERVICE_TYPE))))) {
- return rv;
- }
- if (NS_WARN_IF(NS_FAILED(rv = serviceInfo->SetServiceName(mServiceName)))) {
- return rv;
- }
- if (NS_WARN_IF(NS_FAILED(rv = serviceInfo->SetPort(servicePort)))) {
- return rv;
- }
-
- nsCOMPtr<nsIWritablePropertyBag2> propBag =
- do_CreateInstance("@mozilla.org/hash-property-bag;1");
- MOZ_ASSERT(propBag);
-
- uint32_t version;
- rv = mPresentationService->GetVersion(&version);
- MOZ_ASSERT(NS_SUCCEEDED(rv));
-
- rv = propBag->SetPropertyAsUint32(NS_LITERAL_STRING(PROTOCOL_VERSION_TAG),
- version);
- MOZ_ASSERT(NS_SUCCEEDED(rv));
-
- if (mDiscoverableEncrypted) {
- nsAutoCString certFingerprint;
- rv = mPresentationService->GetCertFingerprint(certFingerprint);
- MOZ_ASSERT(NS_SUCCEEDED(rv));
-
- rv = propBag->SetPropertyAsACString(NS_LITERAL_STRING(CERT_FINGERPRINT_TAG),
- certFingerprint);
- MOZ_ASSERT(NS_SUCCEEDED(rv));
- }
-
- if (NS_WARN_IF(NS_FAILED(rv = serviceInfo->SetAttributes(propBag)))) {
- return rv;
- }
-
- return mMulticastDNS->RegisterService(serviceInfo,
- mWrappedListener,
- getter_AddRefs(mRegisterRequest));
-}
-
-nsresult
-MulticastDNSDeviceProvider::UnregisterMDNSService(nsresult aReason)
-{
- LOG_I("UnregisterMDNSService: %s (0x%08x)", mServiceName.get(), aReason);
- MOZ_ASSERT(NS_IsMainThread());
-
- if (mRegisterRequest) {
- mRegisterRequest->Cancel(aReason);
- mRegisterRequest = nullptr;
- }
-
- return NS_OK;
-}
-
-nsresult
-MulticastDNSDeviceProvider::StopDiscovery(nsresult aReason)
-{
- LOG_I("StopDiscovery (0x%08x)", aReason);
-
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mDiscoveryTimer);
-
- Unused << mDiscoveryTimer->Cancel();
-
- if (mDiscoveryRequest) {
- mDiscoveryRequest->Cancel(aReason);
- mDiscoveryRequest = nullptr;
- }
-
- return NS_OK;
-}
-
-nsresult
-MulticastDNSDeviceProvider::Connect(Device* aDevice,
- nsIPresentationControlChannel** aRetVal)
-{
- MOZ_ASSERT(aDevice);
- MOZ_ASSERT(mPresentationService);
-
- RefPtr<TCPDeviceInfo> deviceInfo = new TCPDeviceInfo(aDevice->Id(),
- aDevice->Address(),
- aDevice->Port(),
- aDevice->CertFingerprint());
-
- return mPresentationService->Connect(deviceInfo, aRetVal);
-}
-
-bool
-MulticastDNSDeviceProvider::IsCompatibleServer(nsIDNSServiceInfo* aServiceInfo)
-{
- MOZ_ASSERT(aServiceInfo);
-
- nsCOMPtr<nsIPropertyBag2> propBag;
- if (NS_WARN_IF(NS_FAILED(
- aServiceInfo->GetAttributes(getter_AddRefs(propBag)))) || !propBag) {
- return false;
- }
-
- uint32_t remoteVersion;
- if (NS_WARN_IF(NS_FAILED(
- propBag->GetPropertyAsUint32(NS_LITERAL_STRING(PROTOCOL_VERSION_TAG),
- &remoteVersion)))) {
- return false;
- }
-
- bool isCompatible = false;
- Unused << NS_WARN_IF(NS_FAILED(
- mPresentationService->IsCompatibleServer(remoteVersion,
- &isCompatible)));
-
- return isCompatible;
-}
-
-nsresult
-MulticastDNSDeviceProvider::AddDevice(const nsACString& aId,
- const nsACString& aServiceName,
- const nsACString& aServiceType,
- const nsACString& aAddress,
- const uint16_t aPort,
- const nsACString& aCertFingerprint)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mPresentationService);
-
- RefPtr<Device> device = new Device(aId, /* ID */
- aServiceName,
- aServiceType,
- aAddress,
- aPort,
- aCertFingerprint,
- DeviceState::eActive,
- this);
-
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
- Unused << listener->AddDevice(device);
- }
-
- mDevices.AppendElement(device);
-
- return NS_OK;
-}
-
-nsresult
-MulticastDNSDeviceProvider::UpdateDevice(const uint32_t aIndex,
- const nsACString& aServiceName,
- const nsACString& aServiceType,
- const nsACString& aAddress,
- const uint16_t aPort,
- const nsACString& aCertFingerprint)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mPresentationService);
-
- if (NS_WARN_IF(aIndex >= mDevices.Length())) {
- return NS_ERROR_INVALID_ARG;
- }
-
- RefPtr<Device> device = mDevices[aIndex];
- device->Update(aServiceName, aServiceType, aAddress, aPort, aCertFingerprint);
- device->ChangeState(DeviceState::eActive);
-
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
- Unused << listener->UpdateDevice(device);
- }
-
- return NS_OK;
-}
-
-nsresult
-MulticastDNSDeviceProvider::RemoveDevice(const uint32_t aIndex)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mPresentationService);
-
- if (NS_WARN_IF(aIndex >= mDevices.Length())) {
- return NS_ERROR_INVALID_ARG;
- }
-
- RefPtr<Device> device = mDevices[aIndex];
-
- LOG_I("RemoveDevice: %s", device->Id().get());
- mDevices.RemoveElementAt(aIndex);
-
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
- Unused << listener->RemoveDevice(device);
- }
-
- return NS_OK;
-}
-
-bool
-MulticastDNSDeviceProvider::FindDeviceById(const nsACString& aId,
- uint32_t& aIndex)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- RefPtr<Device> device = new Device(aId,
- /* aName = */ EmptyCString(),
- /* aType = */ EmptyCString(),
- /* aHost = */ EmptyCString(),
- /* aPort = */ 0,
- /* aCertFingerprint */ EmptyCString(),
- /* aState = */ DeviceState::eUnknown,
- /* aProvider = */ nullptr);
- size_t index = mDevices.IndexOf(device, 0, DeviceIdComparator());
-
- if (index == mDevices.NoIndex) {
- return false;
- }
-
- aIndex = index;
- return true;
-}
-
-bool
-MulticastDNSDeviceProvider::FindDeviceByAddress(const nsACString& aAddress,
- uint32_t& aIndex)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- RefPtr<Device> device = new Device(/* aId = */ EmptyCString(),
- /* aName = */ EmptyCString(),
- /* aType = */ EmptyCString(),
- aAddress,
- /* aPort = */ 0,
- /* aCertFingerprint */ EmptyCString(),
- /* aState = */ DeviceState::eUnknown,
- /* aProvider = */ nullptr);
- size_t index = mDevices.IndexOf(device, 0, DeviceAddressComparator());
-
- if (index == mDevices.NoIndex) {
- return false;
- }
-
- aIndex = index;
- return true;
-}
-
-void
-MulticastDNSDeviceProvider::MarkAllDevicesUnknown()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- for (auto& device : mDevices) {
- device->ChangeState(DeviceState::eUnknown);
- }
-}
-
-void
-MulticastDNSDeviceProvider::ClearUnknownDevices()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- size_t i = mDevices.Length();
- while (i > 0) {
- --i;
- if (mDevices[i]->State() == DeviceState::eUnknown) {
- Unused << NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
- }
- }
-}
-
-void
-MulticastDNSDeviceProvider::ClearDevices()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- size_t i = mDevices.Length();
- while (i > 0) {
- --i;
- Unused << NS_WARN_IF(NS_FAILED(RemoveDevice(i)));
- }
-}
-
-// nsIPresentationDeviceProvider
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::GetListener(nsIPresentationDeviceListener** aListener)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!aListener)) {
- return NS_ERROR_INVALID_POINTER;
- }
-
- nsresult rv;
- nsCOMPtr<nsIPresentationDeviceListener> listener =
- do_QueryReferent(mDeviceListener, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- listener.forget(aListener);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::SetListener(nsIPresentationDeviceListener* aListener)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- mDeviceListener = do_GetWeakReference(aListener);
-
- nsresult rv;
- if (mDeviceListener) {
- if (NS_WARN_IF(NS_FAILED(rv = Init()))) {
- return rv;
- }
- } else {
- if (NS_WARN_IF(NS_FAILED(rv = Uninit()))) {
- return rv;
- }
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::ForceDiscovery()
-{
- LOG_I("ForceDiscovery (%d)", mDiscoveryEnabled);
- MOZ_ASSERT(NS_IsMainThread());
-
- if (!mDiscoveryEnabled) {
- return NS_OK;
- }
-
- MOZ_ASSERT(mDiscoveryTimer);
- MOZ_ASSERT(mMulticastDNS);
-
- // if it's already discovering, extend existing discovery timeout.
- nsresult rv;
- if (mIsDiscovering) {
- Unused << mDiscoveryTimer->Cancel();
-
- if (NS_WARN_IF(NS_FAILED( rv = mDiscoveryTimer->Init(this,
- mDiscoveryTimeoutMs,
- nsITimer::TYPE_ONE_SHOT)))) {
- return rv;
- }
- return NS_OK;
- }
-
- StopDiscovery(NS_OK);
-
- if (NS_WARN_IF(NS_FAILED(rv = mMulticastDNS->StartDiscovery(
- NS_LITERAL_CSTRING(SERVICE_TYPE),
- mWrappedListener,
- getter_AddRefs(mDiscoveryRequest))))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-// nsIDNSServiceDiscoveryListener
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnDiscoveryStarted(const nsACString& aServiceType)
-{
- LOG_I("OnDiscoveryStarted");
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mDiscoveryTimer);
-
- MarkAllDevicesUnknown();
-
- nsresult rv;
- if (NS_WARN_IF(NS_FAILED(rv = mDiscoveryTimer->Init(this,
- mDiscoveryTimeoutMs,
- nsITimer::TYPE_ONE_SHOT)))) {
- return rv;
- }
-
- mIsDiscovering = true;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnDiscoveryStopped(const nsACString& aServiceType)
-{
- LOG_I("OnDiscoveryStopped");
- MOZ_ASSERT(NS_IsMainThread());
-
- ClearUnknownDevices();
-
- mIsDiscovering = false;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnServiceFound(nsIDNSServiceInfo* aServiceInfo)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!aServiceInfo)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- nsresult rv ;
-
- nsAutoCString serviceName;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(serviceName)))) {
- return rv;
- }
-
- LOG_I("OnServiceFound: %s", serviceName.get());
-
- if (mMulticastDNS) {
- if (NS_WARN_IF(NS_FAILED(rv = mMulticastDNS->ResolveService(
- aServiceInfo, mWrappedListener)))) {
- return rv;
- }
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnServiceLost(nsIDNSServiceInfo* aServiceInfo)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!aServiceInfo)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- nsresult rv;
-
- nsAutoCString serviceName;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(serviceName)))) {
- return rv;
- }
-
- LOG_I("OnServiceLost: %s", serviceName.get());
-
- nsAutoCString host;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetHost(host)))) {
- return rv;
- }
-
- uint32_t index;
- if (!FindDeviceById(host, index)) {
- // given device was not found
- return NS_OK;
- }
-
- if (NS_WARN_IF(NS_FAILED(rv = RemoveDevice(index)))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnStartDiscoveryFailed(const nsACString& aServiceType,
- int32_t aErrorCode)
-{
- LOG_E("OnStartDiscoveryFailed: %d", aErrorCode);
- MOZ_ASSERT(NS_IsMainThread());
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnStopDiscoveryFailed(const nsACString& aServiceType,
- int32_t aErrorCode)
-{
- LOG_E("OnStopDiscoveryFailed: %d", aErrorCode);
- MOZ_ASSERT(NS_IsMainThread());
-
- return NS_OK;
-}
-
-// nsIDNSRegistrationListener
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnServiceRegistered(nsIDNSServiceInfo* aServiceInfo)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!aServiceInfo)) {
- return NS_ERROR_INVALID_ARG;
- }
- nsresult rv;
-
- nsAutoCString name;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(name)))) {
- return rv;
- }
-
- LOG_I("OnServiceRegistered (%s)", name.get());
- mRegisteredName = name;
-
- if (mMulticastDNS) {
- if (NS_WARN_IF(NS_FAILED(rv = mMulticastDNS->ResolveService(
- aServiceInfo, mWrappedListener)))) {
- return rv;
- }
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnServiceUnregistered(nsIDNSServiceInfo* aServiceInfo)
-{
- LOG_I("OnServiceUnregistered");
- MOZ_ASSERT(NS_IsMainThread());
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnRegistrationFailed(nsIDNSServiceInfo* aServiceInfo,
- int32_t aErrorCode)
-{
- LOG_E("OnRegistrationFailed: %d", aErrorCode);
- MOZ_ASSERT(NS_IsMainThread());
-
- mRegisterRequest = nullptr;
-
- if (aErrorCode == nsIDNSRegistrationListener::ERROR_SERVICE_NOT_RUNNING) {
- return NS_DispatchToMainThread(
- NewRunnableMethod(this, &MulticastDNSDeviceProvider::RegisterMDNSService));
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnUnregistrationFailed(nsIDNSServiceInfo* aServiceInfo,
- int32_t aErrorCode)
-{
- LOG_E("OnUnregistrationFailed: %d", aErrorCode);
- MOZ_ASSERT(NS_IsMainThread());
-
- return NS_OK;
-}
-
-// nsIDNSServiceResolveListener
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnServiceResolved(nsIDNSServiceInfo* aServiceInfo)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (NS_WARN_IF(!aServiceInfo)) {
- return NS_ERROR_INVALID_ARG;
- }
-
- nsresult rv;
-
- nsAutoCString serviceName;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(serviceName)))) {
- return rv;
- }
-
- LOG_I("OnServiceResolved: %s", serviceName.get());
-
- nsAutoCString host;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetHost(host)))) {
- return rv;
- }
-
- if (mRegisteredName == serviceName) {
- LOG_I("ignore self");
-
- if (NS_WARN_IF(NS_FAILED(rv = mPresentationService->SetId(host)))) {
- return rv;
- }
-
- return NS_OK;
- }
-
- if (!IsCompatibleServer(aServiceInfo)) {
- LOG_I("ignore incompatible service: %s", serviceName.get());
- return NS_OK;
- }
-
- nsAutoCString address;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetAddress(address)))) {
- return rv;
- }
-
- uint16_t port;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetPort(&port)))) {
- return rv;
- }
-
- nsAutoCString serviceType;
- if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceType(serviceType)))) {
- return rv;
- }
-
- nsCOMPtr<nsIPropertyBag2> propBag;
- if (NS_WARN_IF(NS_FAILED(
- aServiceInfo->GetAttributes(getter_AddRefs(propBag)))) || !propBag) {
- return rv;
- }
-
- nsAutoCString certFingerprint;
- Unused << propBag->GetPropertyAsACString(NS_LITERAL_STRING(CERT_FINGERPRINT_TAG),
- certFingerprint);
-
- uint32_t index;
- if (FindDeviceById(host, index)) {
- return UpdateDevice(index,
- serviceName,
- serviceType,
- address,
- port,
- certFingerprint);
- } else {
- return AddDevice(host,
- serviceName,
- serviceType,
- address,
- port,
- certFingerprint);
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnResolveFailed(nsIDNSServiceInfo* aServiceInfo,
- int32_t aErrorCode)
-{
- LOG_E("OnResolveFailed: %d", aErrorCode);
- MOZ_ASSERT(NS_IsMainThread());
-
- return NS_OK;
-}
-
-// nsIPresentationControlServerListener
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnServerReady(uint16_t aPort,
- const nsACString& aCertFingerprint)
-{
- LOG_I("OnServerReady: %d, %s", aPort, PromiseFlatCString(aCertFingerprint).get());
- MOZ_ASSERT(NS_IsMainThread());
-
- if (mDiscoverable) {
- RegisterMDNSService();
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnServerStopped(nsresult aResult)
-{
- LOG_I("OnServerStopped: (0x%08x)", aResult);
-
- UnregisterMDNSService(aResult);
-
- // Try restart server if it is stopped abnormally.
- if (NS_FAILED(aResult) && mDiscoverable) {
- mIsServerRetrying = true;
- mServerRetryTimer->Init(this, mServerRetryMs, nsITimer::TYPE_ONE_SHOT);
- }
-
- return NS_OK;
-}
-
-// Create a new device if we were unable to find one with the address.
-already_AddRefed<MulticastDNSDeviceProvider::Device>
-MulticastDNSDeviceProvider::GetOrCreateDevice(nsITCPDeviceInfo* aDeviceInfo)
-{
- nsAutoCString address;
- Unused << aDeviceInfo->GetAddress(address);
-
- RefPtr<Device> device;
- uint32_t index;
- if (FindDeviceByAddress(address, index)) {
- device = mDevices[index];
- } else {
- // Create a one-time device object for non-discoverable controller.
- // This device will not be in the list of available devices and cannot
- // be used for requesting session.
- nsAutoCString id;
- Unused << aDeviceInfo->GetId(id);
- uint16_t port;
- Unused << aDeviceInfo->GetPort(&port);
-
- device = new Device(id,
- /* aName = */ id,
- /* aType = */ EmptyCString(),
- address,
- port,
- /* aCertFingerprint */ EmptyCString(),
- DeviceState::eActive,
- /* aProvider = */ nullptr);
- }
-
- return device.forget();
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnSessionRequest(nsITCPDeviceInfo* aDeviceInfo,
- const nsAString& aUrl,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- nsAutoCString address;
- Unused << aDeviceInfo->GetAddress(address);
-
- LOG_I("OnSessionRequest: %s", address.get());
-
- RefPtr<Device> device = GetOrCreateDevice(aDeviceInfo);
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
- Unused << listener->OnSessionRequest(device, aUrl, aPresentationId,
- aControlChannel);
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnTerminateRequest(nsITCPDeviceInfo* aDeviceInfo,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel,
- bool aIsFromReceiver)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- nsAutoCString address;
- Unused << aDeviceInfo->GetAddress(address);
-
- LOG_I("OnTerminateRequest: %s", address.get());
-
- RefPtr<Device> device = GetOrCreateDevice(aDeviceInfo);
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
- Unused << listener->OnTerminateRequest(device, aPresentationId,
- aControlChannel, aIsFromReceiver);
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::OnReconnectRequest(nsITCPDeviceInfo* aDeviceInfo,
- const nsAString& aUrl,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel* aControlChannel)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- nsAutoCString address;
- Unused << aDeviceInfo->GetAddress(address);
-
- LOG_I("OnReconnectRequest: %s", address.get());
-
- RefPtr<Device> device = GetOrCreateDevice(aDeviceInfo);
- nsCOMPtr<nsIPresentationDeviceListener> listener;
- if (NS_SUCCEEDED(GetListener(getter_AddRefs(listener))) && listener) {
- Unused << listener->OnReconnectRequest(device, aUrl, aPresentationId,
- aControlChannel);
- }
-
- return NS_OK;
-}
-
-// nsIObserver
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::Observe(nsISupports* aSubject,
- const char* aTopic,
- const char16_t* aData)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- NS_ConvertUTF16toUTF8 data(aData);
- LOG_I("Observe: topic = %s, data = %s", aTopic, data.get());
-
- if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
- if (data.EqualsLiteral(PREF_PRESENTATION_DISCOVERY)) {
- OnDiscoveryChanged(Preferences::GetBool(PREF_PRESENTATION_DISCOVERY));
- } else if (data.EqualsLiteral(PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS)) {
- OnDiscoveryTimeoutChanged(Preferences::GetUint(PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS));
- } else if (data.EqualsLiteral(PREF_PRESENTATION_DISCOVERABLE)) {
- OnDiscoverableChanged(Preferences::GetBool(PREF_PRESENTATION_DISCOVERABLE));
- } else if (data.EqualsLiteral(PREF_PRESENTATION_DEVICE_NAME)) {
- nsAdoptingCString newServiceName = Preferences::GetCString(PREF_PRESENTATION_DEVICE_NAME);
- if (!mServiceName.Equals(newServiceName)) {
- OnServiceNameChanged(newServiceName);
- }
- }
- } else if (!strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC)) {
- nsCOMPtr<nsITimer> timer = do_QueryInterface(aSubject);
- if (!timer) {
- return NS_ERROR_UNEXPECTED;
- }
-
- if (timer == mDiscoveryTimer) {
- StopDiscovery(NS_OK);
- } else if (timer == mServerRetryTimer) {
- mIsServerRetrying = false;
- StartServer();
- }
- }
-
- return NS_OK;
-}
-
-nsresult
-MulticastDNSDeviceProvider::OnDiscoveryChanged(bool aEnabled)
-{
- LOG_I("DiscoveryEnabled = %d\n", aEnabled);
- MOZ_ASSERT(NS_IsMainThread());
-
- mDiscoveryEnabled = aEnabled;
-
- if (mDiscoveryEnabled) {
- return ForceDiscovery();
- }
-
- return StopDiscovery(NS_OK);
-}
-
-nsresult
-MulticastDNSDeviceProvider::OnDiscoveryTimeoutChanged(uint32_t aTimeoutMs)
-{
- LOG_I("OnDiscoveryTimeoutChanged = %d\n", aTimeoutMs);
- MOZ_ASSERT(NS_IsMainThread());
-
- mDiscoveryTimeoutMs = aTimeoutMs;
-
- return NS_OK;
-}
-
-nsresult
-MulticastDNSDeviceProvider::OnDiscoverableChanged(bool aEnabled)
-{
- LOG_I("Discoverable = %d\n", aEnabled);
- MOZ_ASSERT(NS_IsMainThread());
-
- mDiscoverable = aEnabled;
-
- if (mDiscoverable) {
- return StartServer();
- }
-
- return StopServer();
-}
-
-nsresult
-MulticastDNSDeviceProvider::OnServiceNameChanged(const nsACString& aServiceName)
-{
- LOG_I("serviceName = %s\n", PromiseFlatCString(aServiceName).get());
- MOZ_ASSERT(NS_IsMainThread());
-
- mServiceName = aServiceName;
-
- nsresult rv;
- if (NS_WARN_IF(NS_FAILED(rv = UnregisterMDNSService(NS_OK)))) {
- return rv;
- }
-
- if (mDiscoverable) {
- return RegisterMDNSService();
- }
-
- return NS_OK;
-}
-
-// MulticastDNSDeviceProvider::Device
-NS_IMPL_ISUPPORTS(MulticastDNSDeviceProvider::Device,
- nsIPresentationDevice)
-
-// nsIPresentationDevice
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::Device::GetId(nsACString& aId)
-{
- aId = mId;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::Device::GetName(nsACString& aName)
-{
- aName = mName;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::Device::GetType(nsACString& aType)
-{
- aType = mType;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::Device::EstablishControlChannel(
- nsIPresentationControlChannel** aRetVal)
-{
- if (!mProvider) {
- return NS_ERROR_FAILURE;
- }
-
- return mProvider->Connect(this, aRetVal);
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::Device::Disconnect()
-{
- // No need to do anything when disconnect.
- return NS_OK;
-}
-
-NS_IMETHODIMP
-MulticastDNSDeviceProvider::Device::IsRequestedUrlSupported(
- const nsAString& aRequestedUrl,
- bool* aRetVal)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (!aRetVal) {
- return NS_ERROR_INVALID_POINTER;
- }
-
- // TV 2.6 also supports presentation Apps and HTTP/HTTPS hosted receiver page.
- if (DeviceProviderHelpers::IsFxTVSupportedAppUrl(aRequestedUrl) ||
- DeviceProviderHelpers::IsCommonlySupportedScheme(aRequestedUrl)) {
- *aRetVal = true;
- }
-
- return NS_OK;
-}
-
-} // namespace presentation
-} // namespace dom
-} // namespace mozilla
diff --git a/dom/presentation/provider/MulticastDNSDeviceProvider.h b/dom/presentation/provider/MulticastDNSDeviceProvider.h
deleted file mode 100644
index c6a91b3d8..000000000
--- a/dom/presentation/provider/MulticastDNSDeviceProvider.h
+++ /dev/null
@@ -1,225 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_presentation_provider_MulticastDNSDeviceProvider_h
-#define mozilla_dom_presentation_provider_MulticastDNSDeviceProvider_h
-
-#include "mozilla/RefPtr.h"
-#include "nsCOMPtr.h"
-#include "nsICancelable.h"
-#include "nsIDNSServiceDiscovery.h"
-#include "nsIObserver.h"
-#include "nsIPresentationDevice.h"
-#include "nsIPresentationDeviceProvider.h"
-#include "nsIPresentationControlService.h"
-#include "nsITimer.h"
-#include "nsString.h"
-#include "nsTArray.h"
-#include "nsWeakPtr.h"
-
-class nsITCPDeviceInfo;
-
-namespace mozilla {
-namespace dom {
-namespace presentation {
-
-class DNSServiceWrappedListener;
-class MulticastDNSService;
-
-class MulticastDNSDeviceProvider final
- : public nsIPresentationDeviceProvider
- , public nsIDNSServiceDiscoveryListener
- , public nsIDNSRegistrationListener
- , public nsIDNSServiceResolveListener
- , public nsIPresentationControlServerListener
- , public nsIObserver
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONDEVICEPROVIDER
- NS_DECL_NSIDNSSERVICEDISCOVERYLISTENER
- NS_DECL_NSIDNSREGISTRATIONLISTENER
- NS_DECL_NSIDNSSERVICERESOLVELISTENER
- NS_DECL_NSIPRESENTATIONCONTROLSERVERLISTENER
- NS_DECL_NSIOBSERVER
-
- explicit MulticastDNSDeviceProvider() = default;
- nsresult Init();
- nsresult Uninit();
-
-private:
- enum class DeviceState : uint32_t {
- eUnknown,
- eActive
- };
-
- class Device final : public nsIPresentationDevice
- {
- public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIPRESENTATIONDEVICE
-
- explicit Device(const nsACString& aId,
- const nsACString& aName,
- const nsACString& aType,
- const nsACString& aAddress,
- const uint16_t aPort,
- const nsACString& aCertFingerprint,
- DeviceState aState,
- MulticastDNSDeviceProvider* aProvider)
- : mId(aId)
- , mName(aName)
- , mType(aType)
- , mAddress(aAddress)
- , mPort(aPort)
- , mCertFingerprint(aCertFingerprint)
- , mState(aState)
- , mProvider(aProvider)
- {
- }
-
- const nsCString& Id() const
- {
- return mId;
- }
-
- const nsCString& Address() const
- {
- return mAddress;
- }
-
- uint16_t Port() const
- {
- return mPort;
- }
-
- const nsCString& CertFingerprint() const
- {
- return mCertFingerprint;
- }
-
- DeviceState State() const
- {
- return mState;
- }
-
- void ChangeState(DeviceState aState)
- {
- mState = aState;
- }
-
- void Update(const nsACString& aName,
- const nsACString& aType,
- const nsACString& aAddress,
- const uint16_t aPort,
- const nsACString& aCertFingerprint)
- {
- mName = aName;
- mType = aType;
- mAddress = aAddress;
- mPort = aPort;
- mCertFingerprint = aCertFingerprint;
- }
-
- private:
- virtual ~Device() = default;
-
- nsCString mId;
- nsCString mName;
- nsCString mType;
- nsCString mAddress;
- uint16_t mPort;
- nsCString mCertFingerprint;
- DeviceState mState;
- MulticastDNSDeviceProvider* mProvider;
- };
-
- struct DeviceIdComparator {
- bool Equals(const RefPtr<Device>& aA, const RefPtr<Device>& aB) const {
- return aA->Id() == aB->Id();
- }
- };
-
- struct DeviceAddressComparator {
- bool Equals(const RefPtr<Device>& aA, const RefPtr<Device>& aB) const {
- return aA->Address() == aB->Address();
- }
- };
-
- virtual ~MulticastDNSDeviceProvider();
- nsresult StartServer();
- nsresult StopServer();
- void AbortServerRetry();
- nsresult RegisterMDNSService();
- nsresult UnregisterMDNSService(nsresult aReason);
- nsresult StopDiscovery(nsresult aReason);
- nsresult Connect(Device* aDevice,
- nsIPresentationControlChannel** aRetVal);
- bool IsCompatibleServer(nsIDNSServiceInfo* aServiceInfo);
-
- // device manipulation
- nsresult AddDevice(const nsACString& aId,
- const nsACString& aServiceName,
- const nsACString& aServiceType,
- const nsACString& aAddress,
- const uint16_t aPort,
- const nsACString& aCertFingerprint);
- nsresult UpdateDevice(const uint32_t aIndex,
- const nsACString& aServiceName,
- const nsACString& aServiceType,
- const nsACString& aAddress,
- const uint16_t aPort,
- const nsACString& aCertFingerprint);
- nsresult RemoveDevice(const uint32_t aIndex);
- bool FindDeviceById(const nsACString& aId,
- uint32_t& aIndex);
-
- bool FindDeviceByAddress(const nsACString& aAddress,
- uint32_t& aIndex);
-
- already_AddRefed<Device>
- GetOrCreateDevice(nsITCPDeviceInfo* aDeviceInfo);
-
- void MarkAllDevicesUnknown();
- void ClearUnknownDevices();
- void ClearDevices();
-
- // preferences
- nsresult OnDiscoveryChanged(bool aEnabled);
- nsresult OnDiscoveryTimeoutChanged(uint32_t aTimeoutMs);
- nsresult OnDiscoverableChanged(bool aEnabled);
- nsresult OnServiceNameChanged(const nsACString& aServiceName);
-
- bool mInitialized = false;
- nsWeakPtr mDeviceListener;
- nsCOMPtr<nsIPresentationControlService> mPresentationService;
- nsCOMPtr<nsIDNSServiceDiscovery> mMulticastDNS;
- RefPtr<DNSServiceWrappedListener> mWrappedListener;
-
- nsCOMPtr<nsICancelable> mDiscoveryRequest;
- nsCOMPtr<nsICancelable> mRegisterRequest;
-
- nsTArray<RefPtr<Device>> mDevices;
-
- bool mDiscoveryEnabled = false;
- bool mIsDiscovering = false;
- uint32_t mDiscoveryTimeoutMs;
- nsCOMPtr<nsITimer> mDiscoveryTimer;
-
- bool mDiscoverable = false;
- bool mDiscoverableEncrypted = false;
- bool mIsServerRetrying = false;
- uint32_t mServerRetryMs;
- nsCOMPtr<nsITimer> mServerRetryTimer;
-
- nsCString mServiceName;
- nsCString mRegisteredName;
-};
-
-} // namespace presentation
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_presentation_provider_MulticastDNSDeviceProvider_h
diff --git a/dom/presentation/provider/PresentationControlService.js b/dom/presentation/provider/PresentationControlService.js
deleted file mode 100644
index e9f92247f..000000000
--- a/dom/presentation/provider/PresentationControlService.js
+++ /dev/null
@@ -1,960 +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/. */
-/* jshint esnext:true, globalstrict:true, moz:true, undef:true, unused:true */
-/* globals Components, dump */
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-/* globals XPCOMUtils */
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-/* globals Services */
-Cu.import("resource://gre/modules/Services.jsm");
-/* globals NetUtil */
-Cu.import("resource://gre/modules/NetUtil.jsm");
-/* globals setTimeout, clearTimeout */
-Cu.import("resource://gre/modules/Timer.jsm");
-
-/* globals ControllerStateMachine */
-XPCOMUtils.defineLazyModuleGetter(this, "ControllerStateMachine", // jshint ignore:line
- "resource://gre/modules/presentation/ControllerStateMachine.jsm");
-/* global ReceiverStateMachine */
-XPCOMUtils.defineLazyModuleGetter(this, "ReceiverStateMachine", // jshint ignore:line
- "resource://gre/modules/presentation/ReceiverStateMachine.jsm");
-
-const kProtocolVersion = 1; // need to review isCompatibleServer while fiddling the version number.
-const kLocalCertName = "presentation";
-
-const DEBUG = Services.prefs.getBoolPref("dom.presentation.tcp_server.debug");
-function log(aMsg) {
- dump("-*- PresentationControlService.js: " + aMsg + "\n");
-}
-
-function TCPDeviceInfo(aAddress, aPort, aId, aCertFingerprint) {
- this.address = aAddress;
- this.port = aPort;
- this.id = aId;
- this.certFingerprint = aCertFingerprint || "";
-}
-
-function PresentationControlService() {
- this._id = null;
- this._port = 0;
- this._serverSocket = null;
-}
-
-PresentationControlService.prototype = {
- /**
- * If a user agent connects to this server, we create a control channel but
- * hand it to |TCPDevice.listener| when the initial information exchange
- * finishes. Therefore, we hold the control channels in this period.
- */
- _controlChannels: [],
-
- startServer: function(aEncrypted, aPort) {
- if (this._isServiceInit()) {
- DEBUG && log("PresentationControlService - server socket has been initialized"); // jshint ignore:line
- throw Cr.NS_ERROR_FAILURE;
- }
-
- /**
- * 0 or undefined indicates opt-out parameter, and a port will be selected
- * automatically.
- */
- let serverSocketPort = (typeof aPort !== "undefined" && aPort !== 0) ? aPort : -1;
-
- if (aEncrypted) {
- let self = this;
- let localCertService = Cc["@mozilla.org/security/local-cert-service;1"]
- .getService(Ci.nsILocalCertService);
- localCertService.getOrCreateCert(kLocalCertName, {
- handleCert: function(aCert, aRv) {
- DEBUG && log("PresentationControlService - handleCert"); // jshint ignore:line
- if (aRv) {
- self._notifyServerStopped(aRv);
- } else {
- self._serverSocket = Cc["@mozilla.org/network/tls-server-socket;1"]
- .createInstance(Ci.nsITLSServerSocket);
-
- self._serverSocketInit(serverSocketPort, aCert);
- }
- }
- });
- } else {
- this._serverSocket = Cc["@mozilla.org/network/server-socket;1"]
- .createInstance(Ci.nsIServerSocket);
-
- this._serverSocketInit(serverSocketPort, null);
- }
- },
-
- _serverSocketInit: function(aPort, aCert) {
- if (!this._serverSocket) {
- DEBUG && log("PresentationControlService - create server socket fail."); // jshint ignore:line
- throw Cr.NS_ERROR_FAILURE;
- }
-
- try {
- this._serverSocket.init(aPort, false, -1);
-
- if (aCert) {
- this._serverSocket.serverCert = aCert;
- this._serverSocket.setSessionTickets(false);
- let requestCert = Ci.nsITLSServerSocket.REQUEST_NEVER;
- this._serverSocket.setRequestClientCertificate(requestCert);
- }
-
- this._serverSocket.asyncListen(this);
- } catch (e) {
- // NS_ERROR_SOCKET_ADDRESS_IN_USE
- DEBUG && log("PresentationControlService - init server socket fail: " + e); // jshint ignore:line
- throw Cr.NS_ERROR_FAILURE;
- }
-
- this._port = this._serverSocket.port;
-
- DEBUG && log("PresentationControlService - service start on port: " + this._port); // jshint ignore:line
-
- // Monitor network interface change to restart server socket.
- Services.obs.addObserver(this, "network:offline-status-changed", false);
-
- this._notifyServerReady();
- },
-
- _notifyServerReady: function() {
- Services.tm.mainThread.dispatch(() => {
- if (this._listener) {
- this._listener.onServerReady(this._port, this.certFingerprint);
- }
- }, Ci.nsIThread.DISPATCH_NORMAL);
- },
-
- _notifyServerStopped: function(aRv) {
- Services.tm.mainThread.dispatch(() => {
- if (this._listener) {
- this._listener.onServerStopped(aRv);
- }
- }, Ci.nsIThread.DISPATCH_NORMAL);
- },
-
- isCompatibleServer: function(aVersion) {
- // No compatibility issue for the first version of control protocol
- return this.version === aVersion;
- },
-
- get id() {
- return this._id;
- },
-
- set id(aId) {
- this._id = aId;
- },
-
- get port() {
- return this._port;
- },
-
- get version() {
- return kProtocolVersion;
- },
-
- get certFingerprint() {
- if (!this._serverSocket.serverCert) {
- return null;
- }
-
- return this._serverSocket.serverCert.sha256Fingerprint;
- },
-
- set listener(aListener) {
- this._listener = aListener;
- },
-
- get listener() {
- return this._listener;
- },
-
- _isServiceInit: function() {
- return this._serverSocket !== null;
- },
-
- connect: function(aDeviceInfo) {
- if (!this.id) {
- DEBUG && log("PresentationControlService - Id has not initialized; connect fails"); // jshint ignore:line
- return null;
- }
- DEBUG && log("PresentationControlService - connect to " + aDeviceInfo.id); // jshint ignore:line
-
- let socketTransport = this._attemptConnect(aDeviceInfo);
- return new TCPControlChannel(this,
- socketTransport,
- aDeviceInfo,
- "sender");
- },
-
- _attemptConnect: function(aDeviceInfo) {
- let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
- .getService(Ci.nsISocketTransportService);
-
- let socketTransport;
- try {
- if (aDeviceInfo.certFingerprint) {
- let overrideService = Cc["@mozilla.org/security/certoverride;1"]
- .getService(Ci.nsICertOverrideService);
- overrideService.rememberTemporaryValidityOverrideUsingFingerprint(
- aDeviceInfo.address,
- aDeviceInfo.port,
- aDeviceInfo.certFingerprint,
- Ci.nsICertOverrideService.ERROR_UNTRUSTED | Ci.nsICertOverrideService.ERROR_MISMATCH);
-
- socketTransport = sts.createTransport(["ssl"],
- 1,
- aDeviceInfo.address,
- aDeviceInfo.port,
- null);
- } else {
- socketTransport = sts.createTransport(null,
- 0,
- aDeviceInfo.address,
- aDeviceInfo.port,
- null);
- }
- // Shorten the connection failure procedure.
- socketTransport.setTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT, 2);
- } catch (e) {
- DEBUG && log("PresentationControlService - createTransport throws: " + e); // jshint ignore:line
- // Pop the exception to |TCPDevice.establishControlChannel|
- throw Cr.NS_ERROR_FAILURE;
- }
- return socketTransport;
- },
-
- responseSession: function(aDeviceInfo, aSocketTransport) {
- if (!this._isServiceInit()) {
- DEBUG && log("PresentationControlService - should never receive remote " +
- "session request before server socket initialization"); // jshint ignore:line
- return null;
- }
- DEBUG && log("PresentationControlService - responseSession to " +
- JSON.stringify(aDeviceInfo)); // jshint ignore:line
- return new TCPControlChannel(this,
- aSocketTransport,
- aDeviceInfo,
- "receiver");
- },
-
- // Triggered by TCPControlChannel
- onSessionRequest: function(aDeviceInfo, aUrl, aPresentationId, aControlChannel) {
- DEBUG && log("PresentationControlService - onSessionRequest: " +
- aDeviceInfo.address + ":" + aDeviceInfo.port); // jshint ignore:line
- if (!this.listener) {
- this.releaseControlChannel(aControlChannel);
- return;
- }
-
- this.listener.onSessionRequest(aDeviceInfo,
- aUrl,
- aPresentationId,
- aControlChannel);
- this.releaseControlChannel(aControlChannel);
- },
-
- onSessionTerminate: function(aDeviceInfo, aPresentationId, aControlChannel, aIsFromReceiver) {
- DEBUG && log("TCPPresentationServer - onSessionTerminate: " +
- aDeviceInfo.address + ":" + aDeviceInfo.port); // jshint ignore:line
- if (!this.listener) {
- this.releaseControlChannel(aControlChannel);
- return;
- }
-
- this.listener.onTerminateRequest(aDeviceInfo,
- aPresentationId,
- aControlChannel,
- aIsFromReceiver);
- this.releaseControlChannel(aControlChannel);
- },
-
- onSessionReconnect: function(aDeviceInfo, aUrl, aPresentationId, aControlChannel) {
- DEBUG && log("TCPPresentationServer - onSessionReconnect: " +
- aDeviceInfo.address + ":" + aDeviceInfo.port); // jshint ignore:line
- if (!this.listener) {
- this.releaseControlChannel(aControlChannel);
- return;
- }
-
- this.listener.onReconnectRequest(aDeviceInfo,
- aUrl,
- aPresentationId,
- aControlChannel);
- this.releaseControlChannel(aControlChannel);
- },
-
- // nsIServerSocketListener (Triggered by nsIServerSocket.init)
- onSocketAccepted: function(aServerSocket, aClientSocket) {
- DEBUG && log("PresentationControlService - onSocketAccepted: " +
- aClientSocket.host + ":" + aClientSocket.port); // jshint ignore:line
- let deviceInfo = new TCPDeviceInfo(aClientSocket.host, aClientSocket.port);
- this.holdControlChannel(this.responseSession(deviceInfo, aClientSocket));
- },
-
- holdControlChannel: function(aControlChannel) {
- this._controlChannels.push(aControlChannel);
- },
-
- releaseControlChannel: function(aControlChannel) {
- let index = this._controlChannels.indexOf(aControlChannel);
- if (index !== -1) {
- delete this._controlChannels[index];
- }
- },
-
- // nsIServerSocketListener (Triggered by nsIServerSocket.init)
- onStopListening: function(aServerSocket, aStatus) {
- DEBUG && log("PresentationControlService - onStopListening: " + aStatus); // jshint ignore:line
- },
-
- close: function() {
- DEBUG && log("PresentationControlService - close"); // jshint ignore:line
- if (this._isServiceInit()) {
- DEBUG && log("PresentationControlService - close server socket"); // jshint ignore:line
- this._serverSocket.close();
- this._serverSocket = null;
-
- Services.obs.removeObserver(this, "network:offline-status-changed");
-
- this._notifyServerStopped(Cr.NS_OK);
- }
- this._port = 0;
- },
-
- // nsIObserver
- observe: function(aSubject, aTopic, aData) {
- DEBUG && log("PresentationControlService - observe: " + aTopic); // jshint ignore:line
- switch (aTopic) {
- case "network:offline-status-changed": {
- if (aData == "offline") {
- DEBUG && log("network offline"); // jshint ignore:line
- return;
- }
- this._restartServer();
- break;
- }
- }
- },
-
- _restartServer: function() {
- DEBUG && log("PresentationControlService - restart service"); // jshint ignore:line
-
- // restart server socket
- if (this._isServiceInit()) {
- this.close();
-
- try {
- this.startServer();
- } catch (e) {
- DEBUG && log("PresentationControlService - restart service fail: " + e); // jshint ignore:line
- }
- }
- },
-
- classID: Components.ID("{f4079b8b-ede5-4b90-a112-5b415a931deb}"),
- QueryInterface : XPCOMUtils.generateQI([Ci.nsIServerSocketListener,
- Ci.nsIPresentationControlService,
- Ci.nsIObserver]),
-};
-
-function ChannelDescription(aInit) {
- this._type = aInit.type;
- switch (this._type) {
- case Ci.nsIPresentationChannelDescription.TYPE_TCP:
- this._tcpAddresses = Cc["@mozilla.org/array;1"]
- .createInstance(Ci.nsIMutableArray);
- for (let address of aInit.tcpAddress) {
- let wrapper = Cc["@mozilla.org/supports-cstring;1"]
- .createInstance(Ci.nsISupportsCString);
- wrapper.data = address;
- this._tcpAddresses.appendElement(wrapper, false);
- }
-
- this._tcpPort = aInit.tcpPort;
- break;
- case Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL:
- this._dataChannelSDP = aInit.dataChannelSDP;
- break;
- }
-}
-
-ChannelDescription.prototype = {
- _type: 0,
- _tcpAddresses: null,
- _tcpPort: 0,
- _dataChannelSDP: "",
-
- get type() {
- return this._type;
- },
-
- get tcpAddress() {
- return this._tcpAddresses;
- },
-
- get tcpPort() {
- return this._tcpPort;
- },
-
- get dataChannelSDP() {
- return this._dataChannelSDP;
- },
-
- classID: Components.ID("{82507aea-78a2-487e-904a-858a6c5bf4e1}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
-};
-
-// Helper function: transfer nsIPresentationChannelDescription to json
-function discriptionAsJson(aDescription) {
- let json = {};
- json.type = aDescription.type;
- switch(aDescription.type) {
- case Ci.nsIPresentationChannelDescription.TYPE_TCP:
- let addresses = aDescription.tcpAddress.QueryInterface(Ci.nsIArray);
- json.tcpAddress = [];
- for (let idx = 0; idx < addresses.length; idx++) {
- let address = addresses.queryElementAt(idx, Ci.nsISupportsCString);
- json.tcpAddress.push(address.data);
- }
- json.tcpPort = aDescription.tcpPort;
- break;
- case Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL:
- json.dataChannelSDP = aDescription.dataChannelSDP;
- break;
- }
- return json;
-}
-
-const kDisconnectTimeout = 5000;
-const kTerminateTimeout = 5000;
-
-function TCPControlChannel(presentationService,
- transport,
- deviceInfo,
- direction) {
- DEBUG && log("create TCPControlChannel for : " + direction); // jshint ignore:line
- this._deviceInfo = deviceInfo;
- this._direction = direction;
- this._transport = transport;
-
- this._presentationService = presentationService;
-
- if (direction === "receiver") {
- // Need to set security observer before I/O stream operation.
- this._setSecurityObserver(this);
- }
-
- let currentThread = Services.tm.currentThread;
- transport.setEventSink(this, currentThread);
-
- this._input = this._transport.openInputStream(0, 0, 0)
- .QueryInterface(Ci.nsIAsyncInputStream);
- this._input.asyncWait(this.QueryInterface(Ci.nsIStreamListener),
- Ci.nsIAsyncInputStream.WAIT_CLOSURE_ONLY,
- 0,
- currentThread);
-
- this._output = this._transport
- .openOutputStream(Ci.nsITransport.OPEN_UNBUFFERED, 0, 0)
- .QueryInterface(Ci.nsIAsyncOutputStream);
-
- this._outgoingMsgs = [];
-
-
- this._stateMachine =
- (direction === "sender") ? new ControllerStateMachine(this, presentationService.id)
- : new ReceiverStateMachine(this);
-
- if (direction === "receiver" && !transport.securityInfo) {
- // Since the transport created by server socket is already CONNECTED_TO.
- this._outgoingEnabled = true;
- this._createInputStreamPump();
- }
-}
-
-TCPControlChannel.prototype = {
- _outgoingEnabled: false,
- _incomingEnabled: false,
- _pendingOpen: false,
- _pendingOffer: null,
- _pendingAnswer: null,
- _pendingClose: null,
- _pendingCloseReason: null,
- _pendingReconnect: false,
-
- sendOffer: function(aOffer) {
- this._stateMachine.sendOffer(discriptionAsJson(aOffer));
- },
-
- sendAnswer: function(aAnswer) {
- this._stateMachine.sendAnswer(discriptionAsJson(aAnswer));
- },
-
- sendIceCandidate: function(aCandidate) {
- this._stateMachine.updateIceCandidate(aCandidate);
- },
-
- launch: function(aPresentationId, aUrl) {
- this._stateMachine.launch(aPresentationId, aUrl);
- },
-
- terminate: function(aPresentationId) {
- if (!this._terminatingId) {
- this._terminatingId = aPresentationId;
- this._stateMachine.terminate(aPresentationId);
-
- // Start a guard timer to ensure terminateAck is processed.
- this._terminateTimer = setTimeout(() => {
- DEBUG && log("TCPControlChannel - terminate timeout: " + aPresentationId); // jshint ignore:line
- delete this._terminateTimer;
- if (this._pendingDisconnect) {
- this._pendingDisconnect();
- } else {
- this.disconnect(Cr.NS_OK);
- }
- }, kTerminateTimeout);
- } else {
- this._stateMachine.terminateAck(aPresentationId);
- delete this._terminatingId;
- }
- },
-
- _flushOutgoing: function() {
- if (!this._outgoingEnabled || this._outgoingMsgs.length === 0) {
- return;
- }
-
- this._output.asyncWait(this, 0, 0, Services.tm.currentThread);
- },
-
- // may throw an exception
- _send: function(aMsg) {
- DEBUG && log("TCPControlChannel - Send: " + JSON.stringify(aMsg, null, 2)); // jshint ignore:line
-
- /**
- * XXX In TCP streaming, it is possible that more than one message in one
- * TCP packet. We use line delimited JSON to identify where one JSON encoded
- * object ends and the next begins. Therefore, we do not allow newline
- * characters whithin the whole message, and add a newline at the end.
- * Please see the parser code in |onDataAvailable|.
- */
- let message = JSON.stringify(aMsg).replace(["\n"], "") + "\n";
- try {
- this._output.write(message, message.length);
- } catch(e) {
- DEBUG && log("TCPControlChannel - Failed to send message: " + e.name); // jshint ignore:line
- throw e;
- }
- },
-
- _setSecurityObserver: function(observer) {
- if (this._transport && this._transport.securityInfo) {
- DEBUG && log("TCPControlChannel - setSecurityObserver: " + observer); // jshint ignore:line
- let connectionInfo = this._transport.securityInfo
- .QueryInterface(Ci.nsITLSServerConnectionInfo);
- connectionInfo.setSecurityObserver(observer);
- }
- },
-
- // nsITLSServerSecurityObserver
- onHandshakeDone: function(socket, clientStatus) {
- log("TCPControlChannel - onHandshakeDone: TLS version: " + clientStatus.tlsVersionUsed.toString(16));
- this._setSecurityObserver(null);
-
- // Process input/output after TLS handshake is complete.
- this._outgoingEnabled = true;
- this._createInputStreamPump();
- },
-
- // nsIAsyncOutputStream
- onOutputStreamReady: function() {
- DEBUG && log("TCPControlChannel - onOutputStreamReady"); // jshint ignore:line
- if (this._outgoingMsgs.length === 0) {
- return;
- }
-
- try {
- this._send(this._outgoingMsgs[0]);
- } catch (e) {
- if (e.result === Cr.NS_BASE_STREAM_WOULD_BLOCK) {
- this._output.asyncWait(this, 0, 0, Services.tm.currentThread);
- return;
- }
-
- this._closeTransport();
- return;
- }
- this._outgoingMsgs.shift();
- this._flushOutgoing();
- },
-
- // nsIAsyncInputStream (Triggered by nsIInputStream.asyncWait)
- // Only used for detecting connection refused
- onInputStreamReady: function(aStream) {
- DEBUG && log("TCPControlChannel - onInputStreamReady"); // jshint ignore:line
- try {
- aStream.available();
- } catch (e) {
- DEBUG && log("TCPControlChannel - onInputStreamReady error: " + e.name); // jshint ignore:line
- // NS_ERROR_CONNECTION_REFUSED
- this._notifyDisconnected(e.result);
- }
- },
-
- // nsITransportEventSink (Triggered by nsISocketTransport.setEventSink)
- onTransportStatus: function(aTransport, aStatus) {
- DEBUG && log("TCPControlChannel - onTransportStatus: " + aStatus.toString(16) +
- " with role: " + this._direction); // jshint ignore:line
- if (aStatus === Ci.nsISocketTransport.STATUS_CONNECTED_TO) {
- this._outgoingEnabled = true;
- this._createInputStreamPump();
- }
- },
-
- // nsIRequestObserver (Triggered by nsIInputStreamPump.asyncRead)
- onStartRequest: function() {
- DEBUG && log("TCPControlChannel - onStartRequest with role: " +
- this._direction); // jshint ignore:line
- this._incomingEnabled = true;
- },
-
- // nsIRequestObserver (Triggered by nsIInputStreamPump.asyncRead)
- onStopRequest: function(aRequest, aContext, aStatus) {
- DEBUG && log("TCPControlChannel - onStopRequest: " + aStatus +
- " with role: " + this._direction); // jshint ignore:line
- this._stateMachine.onChannelClosed(aStatus, true);
- },
-
- // nsIStreamListener (Triggered by nsIInputStreamPump.asyncRead)
- onDataAvailable: function(aRequest, aContext, aInputStream) {
- let data = NetUtil.readInputStreamToString(aInputStream,
- aInputStream.available());
- DEBUG && log("TCPControlChannel - onDataAvailable: " + data); // jshint ignore:line
-
- // Parser of line delimited JSON. Please see |_send| for more informaiton.
- let jsonArray = data.split("\n");
- jsonArray.pop();
- for (let json of jsonArray) {
- let msg;
- try {
- msg = JSON.parse(json);
- } catch (e) {
- DEBUG && log("TCPSignalingChannel - error in parsing json: " + e); // jshint ignore:line
- }
-
- this._handleMessage(msg);
- }
- },
-
- _createInputStreamPump: function() {
- if (this._pump) {
- return;
- }
-
- DEBUG && log("TCPControlChannel - create pump with role: " +
- this._direction); // jshint ignore:line
- this._pump = Cc["@mozilla.org/network/input-stream-pump;1"].
- createInstance(Ci.nsIInputStreamPump);
- this._pump.init(this._input, -1, -1, 0, 0, false);
- this._pump.asyncRead(this, null);
- this._stateMachine.onChannelReady();
- },
-
- // Handle command from remote side
- _handleMessage: function(aMsg) {
- DEBUG && log("TCPControlChannel - handleMessage from " +
- JSON.stringify(this._deviceInfo) + ": " + JSON.stringify(aMsg)); // jshint ignore:line
- this._stateMachine.onCommand(aMsg);
- },
-
- get listener() {
- return this._listener;
- },
-
- set listener(aListener) {
- DEBUG && log("TCPControlChannel - set listener: " + aListener); // jshint ignore:line
- if (!aListener) {
- this._listener = null;
- return;
- }
-
- this._listener = aListener;
- if (this._pendingOpen) {
- this._pendingOpen = false;
- DEBUG && log("TCPControlChannel - notify pending opened"); // jshint ignore:line
- this._listener.notifyConnected();
- }
-
- if (this._pendingOffer) {
- let offer = this._pendingOffer;
- DEBUG && log("TCPControlChannel - notify pending offer: " +
- JSON.stringify(offer)); // jshint ignore:line
- this._listener.onOffer(new ChannelDescription(offer));
- this._pendingOffer = null;
- }
-
- if (this._pendingAnswer) {
- let answer = this._pendingAnswer;
- DEBUG && log("TCPControlChannel - notify pending answer: " +
- JSON.stringify(answer)); // jshint ignore:line
- this._listener.onAnswer(new ChannelDescription(answer));
- this._pendingAnswer = null;
- }
-
- if (this._pendingClose) {
- DEBUG && log("TCPControlChannel - notify pending closed"); // jshint ignore:line
- this._notifyDisconnected(this._pendingCloseReason);
- this._pendingClose = null;
- }
-
- if (this._pendingReconnect) {
- DEBUG && log("TCPControlChannel - notify pending reconnected"); // jshint ignore:line
- this._notifyReconnected();
- this._pendingReconnect = false;
- }
- },
-
- /**
- * These functions are designed to handle the interaction with listener
- * appropriately. |_FUNC| is to handle |this._listener.FUNC|.
- */
- _onOffer: function(aOffer) {
- if (!this._incomingEnabled) {
- return;
- }
- if (!this._listener) {
- this._pendingOffer = aOffer;
- return;
- }
- DEBUG && log("TCPControlChannel - notify offer: " +
- JSON.stringify(aOffer)); // jshint ignore:line
- this._listener.onOffer(new ChannelDescription(aOffer));
- },
-
- _onAnswer: function(aAnswer) {
- if (!this._incomingEnabled) {
- return;
- }
- if (!this._listener) {
- this._pendingAnswer = aAnswer;
- return;
- }
- DEBUG && log("TCPControlChannel - notify answer: " +
- JSON.stringify(aAnswer)); // jshint ignore:line
- this._listener.onAnswer(new ChannelDescription(aAnswer));
- },
-
- _notifyConnected: function() {
- this._pendingClose = false;
- this._pendingCloseReason = Cr.NS_OK;
-
- if (!this._listener) {
- this._pendingOpen = true;
- return;
- }
-
- DEBUG && log("TCPControlChannel - notify opened with role: " +
- this._direction); // jshint ignore:line
- this._listener.notifyConnected();
- },
-
- _notifyDisconnected: function(aReason) {
- this._pendingOpen = false;
- this._pendingOffer = null;
- this._pendingAnswer = null;
-
- // Remote endpoint closes the control channel with abnormal reason.
- if (aReason == Cr.NS_OK && this._pendingCloseReason != Cr.NS_OK) {
- aReason = this._pendingCloseReason;
- }
-
- if (!this._listener) {
- this._pendingClose = true;
- this._pendingCloseReason = aReason;
- return;
- }
-
- DEBUG && log("TCPControlChannel - notify closed with role: " +
- this._direction); // jshint ignore:line
- this._listener.notifyDisconnected(aReason);
- },
-
- _notifyReconnected: function() {
- if (!this._listener) {
- this._pendingReconnect = true;
- return;
- }
-
- DEBUG && log("TCPControlChannel - notify reconnected with role: " +
- this._direction); // jshint ignore:line
- this._listener.notifyReconnected();
- },
-
- _closeOutgoing: function() {
- if (this._outgoingEnabled) {
- this._output.close();
- this._outgoingEnabled = false;
- }
- },
- _closeIncoming: function() {
- if (this._incomingEnabled) {
- this._pump = null;
- this._input.close();
- this._incomingEnabled = false;
- }
- },
- _closeTransport: function() {
- if (this._disconnectTimer) {
- clearTimeout(this._disconnectTimer);
- delete this._disconnectTimer;
- }
-
- if (this._terminateTimer) {
- clearTimeout(this._terminateTimer);
- delete this._terminateTimer;
- }
-
- delete this._pendingDisconnect;
-
- this._transport.setEventSink(null, null);
-
- this._closeIncoming();
- this._closeOutgoing();
- this._presentationService.releaseControlChannel(this);
- },
-
- disconnect: function(aReason) {
- DEBUG && log("TCPControlChannel - disconnect with reason: " + aReason); // jshint ignore:line
-
- // Pending disconnect during termination procedure.
- if (this._terminateTimer) {
- // Store only the first disconnect action.
- if (!this._pendingDisconnect) {
- this._pendingDisconnect = this.disconnect.bind(this, aReason);
- }
- return;
- }
-
- if (this._outgoingEnabled && !this._disconnectTimer) {
- // default reason is NS_OK
- aReason = !aReason ? Cr.NS_OK : aReason;
-
- this._stateMachine.onChannelClosed(aReason, false);
-
- // Start a guard timer to ensure the transport will be closed.
- this._disconnectTimer = setTimeout(() => {
- DEBUG && log("TCPControlChannel - disconnect timeout"); // jshint ignore:line
- this._closeTransport();
- }, kDisconnectTimeout);
- }
- },
-
- reconnect: function(aPresentationId, aUrl) {
- DEBUG && log("TCPControlChannel - reconnect with role: " +
- this._direction); // jshint ignore:line
- if (this._direction != "sender") {
- return Cr.NS_ERROR_FAILURE;
- }
-
- this._stateMachine.reconnect(aPresentationId, aUrl);
- },
-
- // callback from state machine
- sendCommand: function(command) {
- this._outgoingMsgs.push(command);
- this._flushOutgoing();
- },
-
- notifyDeviceConnected: function(deviceId) {
- switch (this._direction) {
- case "receiver":
- this._deviceInfo.id = deviceId;
- break;
- }
- this._notifyConnected();
- },
-
- notifyDisconnected: function(reason) {
- this._closeTransport();
- this._notifyDisconnected(reason);
- },
-
- notifyLaunch: function(presentationId, url) {
- switch (this._direction) {
- case "receiver":
- this._presentationService.onSessionRequest(this._deviceInfo,
- url,
- presentationId,
- this);
- break;
- }
- },
-
- notifyTerminate: function(presentationId) {
- if (!this._terminatingId) {
- this._terminatingId = presentationId;
- this._presentationService.onSessionTerminate(this._deviceInfo,
- presentationId,
- this,
- this._direction === "sender");
- return;
- }
-
- // Cancel terminate guard timer after receiving terminate-ack.
- if (this._terminateTimer) {
- clearTimeout(this._terminateTimer);
- delete this._terminateTimer;
- }
-
- if (this._terminatingId !== presentationId) {
- // Requested presentation Id doesn't matched with the one in ACK.
- // Disconnect the control channel with error.
- DEBUG && log("TCPControlChannel - unmatched terminatingId: " + presentationId); // jshint ignore:line
- this.disconnect(Cr.NS_ERROR_FAILURE);
- }
-
- delete this._terminatingId;
- if (this._pendingDisconnect) {
- this._pendingDisconnect();
- }
- },
-
- notifyReconnect: function(presentationId, url) {
- switch (this._direction) {
- case "receiver":
- this._presentationService.onSessionReconnect(this._deviceInfo,
- url,
- presentationId,
- this);
- break;
- case "sender":
- this._notifyReconnected();
- break;
- }
- },
-
- notifyOffer: function(offer) {
- this._onOffer(offer);
- },
-
- notifyAnswer: function(answer) {
- this._onAnswer(answer);
- },
-
- notifyIceCandidate: function(candidate) {
- this._listener.onIceCandidate(candidate);
- },
-
- classID: Components.ID("{fefb8286-0bdc-488b-98bf-0c11b485c955}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel,
- Ci.nsIStreamListener]),
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationControlService]); // jshint ignore:line
diff --git a/dom/presentation/provider/PresentationDeviceProviderModule.cpp b/dom/presentation/provider/PresentationDeviceProviderModule.cpp
deleted file mode 100644
index 9c084e7db..000000000
--- a/dom/presentation/provider/PresentationDeviceProviderModule.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "DisplayDeviceProvider.h"
-#include "MulticastDNSDeviceProvider.h"
-#include "mozilla/ModuleUtils.h"
-
-#ifdef MOZ_WIDGET_ANDROID
-#include "LegacyMDNSDeviceProvider.h"
-#endif //MOZ_WIDGET_ANDROID
-
-#define MULTICAST_DNS_PROVIDER_CID \
- {0x814f947a, 0x52f7, 0x41c9, \
- { 0x94, 0xa1, 0x36, 0x84, 0x79, 0x72, 0x84, 0xac }}
-#define DISPLAY_DEVICE_PROVIDER_CID \
- { 0x515d9879, 0xfe0b, 0x4d9f, \
- { 0x89, 0x49, 0x7f, 0xa7, 0x65, 0x6c, 0x01, 0x0e } }
-
-#ifdef MOZ_WIDGET_ANDROID
-#define LEGACY_MDNS_PROVIDER_CID \
- { 0x6885ff39, 0xd98c, 0x4356, \
- { 0x9e, 0xb3, 0x56, 0x56, 0x31, 0x63, 0x0a, 0xf6 } }
-#endif //MOZ_WIDGET_ANDROID
-
-#define DISPLAY_DEVICE_PROVIDER_CONTRACT_ID "@mozilla.org/presentation-device/displaydevice-provider;1"
-#define MULTICAST_DNS_PROVIDER_CONTRACT_ID "@mozilla.org/presentation-device/multicastdns-provider;1"
-
-#ifdef MOZ_WIDGET_ANDROID
-#define LEGACY_MDNS_PROVIDER_CONTRACT_ID "@mozilla.org/presentation-device/legacy-mdns-provider;1"
-#endif //MOZ_WIDGET_ANDROID
-
-using mozilla::dom::presentation::MulticastDNSDeviceProvider;
-using mozilla::dom::presentation::DisplayDeviceProvider;
-
-#ifdef MOZ_WIDGET_ANDROID
-using mozilla::dom::presentation::legacy::LegacyMDNSDeviceProvider;
-#endif //MOZ_WIDGET_ANDROID
-
-NS_GENERIC_FACTORY_CONSTRUCTOR(MulticastDNSDeviceProvider)
-NS_DEFINE_NAMED_CID(MULTICAST_DNS_PROVIDER_CID);
-
-NS_GENERIC_FACTORY_CONSTRUCTOR(DisplayDeviceProvider)
-NS_DEFINE_NAMED_CID(DISPLAY_DEVICE_PROVIDER_CID);
-
-#ifdef MOZ_WIDGET_ANDROID
-NS_GENERIC_FACTORY_CONSTRUCTOR(LegacyMDNSDeviceProvider)
-NS_DEFINE_NAMED_CID(LEGACY_MDNS_PROVIDER_CID);
-#endif //MOZ_WIDGET_ANDROID
-
-static const mozilla::Module::CIDEntry kPresentationDeviceProviderCIDs[] = {
- { &kMULTICAST_DNS_PROVIDER_CID, false, nullptr, MulticastDNSDeviceProviderConstructor },
- { &kDISPLAY_DEVICE_PROVIDER_CID, false, nullptr, DisplayDeviceProviderConstructor },
-#ifdef MOZ_WIDGET_ANDROID
- { &kLEGACY_MDNS_PROVIDER_CID, false, nullptr, LegacyMDNSDeviceProviderConstructor },
-#endif //MOZ_WIDGET_ANDROID
- { nullptr }
-};
-
-static const mozilla::Module::ContractIDEntry kPresentationDeviceProviderContracts[] = {
- { MULTICAST_DNS_PROVIDER_CONTRACT_ID, &kMULTICAST_DNS_PROVIDER_CID },
- { DISPLAY_DEVICE_PROVIDER_CONTRACT_ID, &kDISPLAY_DEVICE_PROVIDER_CID },
-#ifdef MOZ_WIDGET_ANDROID
- { LEGACY_MDNS_PROVIDER_CONTRACT_ID, &kLEGACY_MDNS_PROVIDER_CID },
-#endif //MOZ_WIDGET_ANDROID
- { nullptr }
-};
-
-static const mozilla::Module::CategoryEntry kPresentationDeviceProviderCategories[] = {
-#if defined(MOZ_WIDGET_COCOA) || defined(MOZ_WIDGET_ANDROID)
- { PRESENTATION_DEVICE_PROVIDER_CATEGORY, "MulticastDNSDeviceProvider", MULTICAST_DNS_PROVIDER_CONTRACT_ID },
-#endif
-#ifdef MOZ_WIDGET_ANDROID
- { PRESENTATION_DEVICE_PROVIDER_CATEGORY, "LegacyMDNSDeviceProvider", LEGACY_MDNS_PROVIDER_CONTRACT_ID },
-#endif //MOZ_WIDGET_ANDROID
- { nullptr }
-};
-
-static const mozilla::Module kPresentationDeviceProviderModule = {
- mozilla::Module::kVersion,
- kPresentationDeviceProviderCIDs,
- kPresentationDeviceProviderContracts,
- kPresentationDeviceProviderCategories
-};
-
-NSMODULE_DEFN(PresentationDeviceProviderModule) = &kPresentationDeviceProviderModule;
diff --git a/dom/presentation/provider/ReceiverStateMachine.jsm b/dom/presentation/provider/ReceiverStateMachine.jsm
deleted file mode 100644
index 23ebb5a4e..000000000
--- a/dom/presentation/provider/ReceiverStateMachine.jsm
+++ /dev/null
@@ -1,238 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
-/* jshint esnext:true, globalstrict:true, moz:true, undef:true, unused:true */
-/* globals Components, dump */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["ReceiverStateMachine"]; // jshint ignore:line
-
-const { utils: Cu } = Components;
-
-/* globals State, CommandType */
-Cu.import("resource://gre/modules/presentation/StateMachineHelper.jsm");
-
-const DEBUG = false;
-function debug(str) {
- dump("-*- ReceiverStateMachine: " + str + "\n");
-}
-
-var handlers = [
- function _initHandler(stateMachine, command) {
- // shouldn't receive any command at init state
- DEBUG && debug("unexpected command: " + JSON.stringify(command)); // jshint ignore:line
- },
- function _connectingHandler(stateMachine, command) {
- switch (command.type) {
- case CommandType.CONNECT:
- stateMachine._sendCommand({
- type: CommandType.CONNECT_ACK
- });
- stateMachine.state = State.CONNECTED;
- stateMachine._notifyDeviceConnected(command.deviceId);
- break;
- case CommandType.DISCONNECT:
- stateMachine.state = State.CLOSED;
- stateMachine._notifyDisconnected(command.reason);
- break;
- default:
- debug("unexpected command: " + JSON.stringify(command));
- // ignore unexpected command
- break;
- }
- },
- function _connectedHandler(stateMachine, command) {
- switch (command.type) {
- case CommandType.DISCONNECT:
- stateMachine.state = State.CLOSED;
- stateMachine._notifyDisconnected(command.reason);
- break;
- case CommandType.LAUNCH:
- stateMachine._notifyLaunch(command.presentationId,
- command.url);
- stateMachine._sendCommand({
- type: CommandType.LAUNCH_ACK,
- presentationId: command.presentationId
- });
- break;
- case CommandType.TERMINATE:
- stateMachine._notifyTerminate(command.presentationId);
- break;
- case CommandType.TERMINATE_ACK:
- stateMachine._notifyTerminate(command.presentationId);
- break;
- case CommandType.OFFER:
- case CommandType.ICE_CANDIDATE:
- stateMachine._notifyChannelDescriptor(command);
- break;
- case CommandType.RECONNECT:
- stateMachine._notifyReconnect(command.presentationId,
- command.url);
- stateMachine._sendCommand({
- type: CommandType.RECONNECT_ACK,
- presentationId: command.presentationId
- });
- break;
- default:
- debug("unexpected command: " + JSON.stringify(command));
- // ignore unexpected command
- break;
- }
- },
- function _closingHandler(stateMachine, command) {
- switch (command.type) {
- case CommandType.DISCONNECT:
- stateMachine.state = State.CLOSED;
- stateMachine._notifyDisconnected(command.reason);
- break;
- default:
- debug("unexpected command: " + JSON.stringify(command));
- // ignore unexpected command
- break;
- }
- },
- function _closedHandler(stateMachine, command) {
- // ignore every command in closed state.
- DEBUG && debug("unexpected command: " + JSON.stringify(command)); // jshint ignore:line
- },
-];
-
-function ReceiverStateMachine(channel) {
- this.state = State.INIT;
- this._channel = channel;
-}
-
-ReceiverStateMachine.prototype = {
- launch: function _launch() {
- // presentation session can only be launched by controlling UA.
- debug("receiver shouldn't trigger launch");
- },
-
- terminate: function _terminate(presentationId) {
- if (this.state === State.CONNECTED) {
- this._sendCommand({
- type: CommandType.TERMINATE,
- presentationId: presentationId,
- });
- }
- },
-
- terminateAck: function _terminateAck(presentationId) {
- if (this.state === State.CONNECTED) {
- this._sendCommand({
- type: CommandType.TERMINATE_ACK,
- presentationId: presentationId,
- });
- }
- },
-
- reconnect: function _reconnect() {
- debug("receiver shouldn't trigger reconnect");
- },
-
- sendOffer: function _sendOffer() {
- // offer can only be sent by controlling UA.
- debug("receiver shouldn't generate offer");
- },
-
- sendAnswer: function _sendAnswer(answer) {
- if (this.state === State.CONNECTED) {
- this._sendCommand({
- type: CommandType.ANSWER,
- answer: answer,
- });
- }
- },
-
- updateIceCandidate: function _updateIceCandidate(candidate) {
- if (this.state === State.CONNECTED) {
- this._sendCommand({
- type: CommandType.ICE_CANDIDATE,
- candidate: candidate,
- });
- }
- },
-
- onCommand: function _onCommand(command) {
- handlers[this.state](this, command);
- },
-
- onChannelReady: function _onChannelReady() {
- if (this.state === State.INIT) {
- this.state = State.CONNECTING;
- }
- },
-
- onChannelClosed: function _onChannelClose(reason, isByRemote) {
- switch (this.state) {
- case State.CONNECTED:
- if (isByRemote) {
- this.state = State.CLOSED;
- this._notifyDisconnected(reason);
- } else {
- this._sendCommand({
- type: CommandType.DISCONNECT,
- reason: reason
- });
- this.state = State.CLOSING;
- this._closeReason = reason;
- }
- break;
- case State.CLOSING:
- if (isByRemote) {
- this.state = State.CLOSED;
- if (this._closeReason) {
- reason = this._closeReason;
- delete this._closeReason;
- }
- this._notifyDisconnected(reason);
- } else {
- // do nothing and wait for remote channel closed.
- }
- break;
- default:
- DEBUG && debug("unexpected channel close: " + reason + ", " + isByRemote); // jshint ignore:line
- break;
- }
- },
-
- _sendCommand: function _sendCommand(command) {
- this._channel.sendCommand(command);
- },
-
- _notifyDeviceConnected: function _notifyDeviceConnected(deviceName) {
- this._channel.notifyDeviceConnected(deviceName);
- },
-
- _notifyDisconnected: function _notifyDisconnected(reason) {
- this._channel.notifyDisconnected(reason);
- },
-
- _notifyLaunch: function _notifyLaunch(presentationId, url) {
- this._channel.notifyLaunch(presentationId, url);
- },
-
- _notifyTerminate: function _notifyTerminate(presentationId) {
- this._channel.notifyTerminate(presentationId);
- },
-
- _notifyReconnect: function _notifyReconnect(presentationId, url) {
- this._channel.notifyReconnect(presentationId, url);
- },
-
- _notifyChannelDescriptor: function _notifyChannelDescriptor(command) {
- switch (command.type) {
- case CommandType.OFFER:
- this._channel.notifyOffer(command.offer);
- break;
- case CommandType.ICE_CANDIDATE:
- this._channel.notifyIceCandidate(command.candidate);
- break;
- }
- },
-};
-
-this.ReceiverStateMachine = ReceiverStateMachine; // jshint ignore:line
diff --git a/dom/presentation/provider/StateMachineHelper.jsm b/dom/presentation/provider/StateMachineHelper.jsm
deleted file mode 100644
index 6e07863d4..000000000
--- a/dom/presentation/provider/StateMachineHelper.jsm
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
-/* jshint esnext:true, globalstrict:true, moz:true, undef:true, unused:true */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["State", "CommandType"]; // jshint ignore:line
-
-const State = Object.freeze({
- INIT: 0,
- CONNECTING: 1,
- CONNECTED: 2,
- CLOSING: 3,
- CLOSED: 4,
-});
-
-const CommandType = Object.freeze({
- // control channel life cycle
- CONNECT: "connect", // { deviceId: <string> }
- CONNECT_ACK: "connect-ack", // { presentationId: <string> }
- DISCONNECT: "disconnect", // { reason: <int> }
- // presentation session life cycle
- LAUNCH: "launch", // { presentationId: <string>, url: <string> }
- LAUNCH_ACK: "launch-ack", // { presentationId: <string> }
- TERMINATE: "terminate", // { presentationId: <string> }
- TERMINATE_ACK: "terminate-ack", // { presentationId: <string> }
- RECONNECT: "reconnect", // { presentationId: <string> }
- RECONNECT_ACK: "reconnect-ack", // { presentationId: <string> }
- // session transport establishment
- OFFER: "offer", // { offer: <json> }
- ANSWER: "answer", // { answer: <json> }
- ICE_CANDIDATE: "ice-candidate", // { candidate: <string> }
-});
-
-this.State = State; // jshint ignore:line
-this.CommandType = CommandType; // jshint ignore:line
diff --git a/dom/presentation/provider/moz.build b/dom/presentation/provider/moz.build
deleted file mode 100644
index 18428b50e..000000000
--- a/dom/presentation/provider/moz.build
+++ /dev/null
@@ -1,40 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-EXTRA_COMPONENTS += [
- 'BuiltinProviders.manifest',
- 'PresentationControlService.js'
-]
-
-UNIFIED_SOURCES += [
- 'DeviceProviderHelpers.cpp',
- 'DisplayDeviceProvider.cpp',
- 'MulticastDNSDeviceProvider.cpp',
- 'PresentationDeviceProviderModule.cpp',
-]
-
-EXTRA_JS_MODULES.presentation += [
- 'ControllerStateMachine.jsm',
- 'ReceiverStateMachine.jsm',
- 'StateMachineHelper.jsm',
-]
-
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
- EXTRA_COMPONENTS += [
- # For android presentation device
- 'AndroidCastDeviceProvider.js',
- 'AndroidCastDeviceProvider.manifest',
- # for TV 2.5 device backward capability
- 'LegacyPresentationControlService.js',
- 'LegacyProviders.manifest',
- ]
-
- UNIFIED_SOURCES += [
- 'LegacyMDNSDeviceProvider.cpp',
- ]
-
-include('/ipc/chromium/chromium-config.mozbuild')
-FINAL_LIBRARY = 'xul'
diff --git a/dom/presentation/provider/nsTCPDeviceInfo.h b/dom/presentation/provider/nsTCPDeviceInfo.h
deleted file mode 100644
index 118f6c8ac..000000000
--- a/dom/presentation/provider/nsTCPDeviceInfo.h
+++ /dev/null
@@ -1,77 +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 __TCPDeviceInfo_h__
-#define __TCPDeviceInfo_h__
-
-namespace mozilla {
-namespace dom {
-namespace presentation {
-
-class TCPDeviceInfo final : public nsITCPDeviceInfo
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSITCPDEVICEINFO
-
- explicit TCPDeviceInfo(const nsACString& aId,
- const nsACString& aAddress,
- const uint16_t aPort,
- const nsACString& aCertFingerprint)
- : mId(aId)
- , mAddress(aAddress)
- , mPort(aPort)
- , mCertFingerprint(aCertFingerprint)
- {
- }
-
-private:
- virtual ~TCPDeviceInfo() {}
-
- nsCString mId;
- nsCString mAddress;
- uint16_t mPort;
- nsCString mCertFingerprint;
-};
-
-NS_IMPL_ISUPPORTS(TCPDeviceInfo,
- nsITCPDeviceInfo)
-
-// nsITCPDeviceInfo
-NS_IMETHODIMP
-TCPDeviceInfo::GetId(nsACString& aId)
-{
- aId = mId;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-TCPDeviceInfo::GetAddress(nsACString& aAddress)
-{
- aAddress = mAddress;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-TCPDeviceInfo::GetPort(uint16_t* aPort)
-{
- *aPort = mPort;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-TCPDeviceInfo::GetCertFingerprint(nsACString& aCertFingerprint)
-{
- aCertFingerprint = mCertFingerprint;
- return NS_OK;
-}
-
-} // namespace presentation
-} // namespace dom
-} // namespace mozilla
-
-#endif /* !__TCPDeviceInfo_h__ */
-
diff --git a/dom/presentation/tests/mochitest/PresentationDeviceInfoChromeScript.js b/dom/presentation/tests/mochitest/PresentationDeviceInfoChromeScript.js
deleted file mode 100644
index 2bc069f6b..000000000
--- a/dom/presentation/tests/mochitest/PresentationDeviceInfoChromeScript.js
+++ /dev/null
@@ -1,150 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-'use strict';
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import('resource://gre/modules/PresentationDeviceInfoManager.jsm');
-
-const { XPCOMUtils } = Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-
-const manager = Cc['@mozilla.org/presentation-device/manager;1']
- .getService(Ci.nsIPresentationDeviceManager);
-
-var testProvider = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceProvider]),
- forceDiscovery: function() {
- sendAsyncMessage('force-discovery');
- },
- listener: null,
-};
-
-var testDevice = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
- establishControlChannel: function() {
- return null;
- },
- disconnect: function() {},
- isRequestedUrlSupported: function(requestedUrl) {
- return true;
- },
- id: null,
- name: null,
- type: null,
- listener: null,
-};
-
-var testDevice1 = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
- id: 'dummyid',
- name: 'dummyName',
- type: 'dummyType',
- establishControlChannel: function(url, presentationId) {
- return null;
- },
- disconnect: function() {},
- isRequestedUrlSupported: function(requestedUrl) {
- return true;
- },
-};
-
-var testDevice2 = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
- id: 'dummyid',
- name: 'dummyName',
- type: 'dummyType',
- establishControlChannel: function(url, presentationId) {
- return null;
- },
- disconnect: function() {},
- isRequestedUrlSupported: function(requestedUrl) {
- return true;
- },
-};
-
-var mockedDeviceWithoutSupportedURL = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
- id: 'dummyid',
- name: 'dummyName',
- type: 'dummyType',
- establishControlChannel: function(url, presentationId) {
- return null;
- },
- disconnect: function() {},
- isRequestedUrlSupported: function(requestedUrl) {
- return false;
- },
-};
-
-var mockedDeviceSupportHttpsURL = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
- id: 'dummyid',
- name: 'dummyName',
- type: 'dummyType',
- establishControlChannel: function(url, presentationId) {
- return null;
- },
- disconnect: function() {},
- isRequestedUrlSupported: function(requestedUrl) {
- if (requestedUrl.indexOf("https://") != -1) {
- return true;
- }
- return false;
- },
-};
-
-addMessageListener('setup', function() {
- manager.addDeviceProvider(testProvider);
-
- sendAsyncMessage('setup-complete');
-});
-
-addMessageListener('trigger-device-add', function(device) {
- testDevice.id = device.id;
- testDevice.name = device.name;
- testDevice.type = device.type;
- manager.addDevice(testDevice);
-});
-
-addMessageListener('trigger-add-unsupport-url-device', function() {
- manager.addDevice(mockedDeviceWithoutSupportedURL);
-});
-
-addMessageListener('trigger-add-multiple-devices', function() {
- manager.addDevice(testDevice1);
- manager.addDevice(testDevice2);
-});
-
-addMessageListener('trigger-add-https-devices', function() {
- manager.addDevice(mockedDeviceSupportHttpsURL);
-});
-
-
-addMessageListener('trigger-device-update', function(device) {
- testDevice.id = device.id;
- testDevice.name = device.name;
- testDevice.type = device.type;
- manager.updateDevice(testDevice);
-});
-
-addMessageListener('trigger-device-remove', function() {
- manager.removeDevice(testDevice);
-});
-
-addMessageListener('trigger-remove-unsupported-device', function() {
- manager.removeDevice(mockedDeviceWithoutSupportedURL);
-});
-
-addMessageListener('trigger-remove-multiple-devices', function() {
- manager.removeDevice(testDevice1);
- manager.removeDevice(testDevice2);
-});
-
-addMessageListener('trigger-remove-https-devices', function() {
- manager.removeDevice(mockedDeviceSupportHttpsURL);
-});
-
-addMessageListener('teardown', function() {
- manager.removeDeviceProvider(testProvider);
-});
diff --git a/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js b/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
deleted file mode 100644
index 3052bdcb1..000000000
--- a/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
+++ /dev/null
@@ -1,470 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-'use strict';
-
-const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
-Cu.import('resource://gre/modules/Timer.jsm');
-
-const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator);
-
-function registerMockedFactory(contractId, mockedClassId, mockedFactory) {
- var originalClassId, originalFactory;
-
- var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
- if (!registrar.isCIDRegistered(mockedClassId)) {
- try {
- originalClassId = registrar.contractIDToCID(contractId);
- originalFactory = Cm.getClassObject(Cc[contractId], Ci.nsIFactory);
- } catch (ex) {
- originalClassId = "";
- originalFactory = null;
- }
- if (originalFactory) {
- registrar.unregisterFactory(originalClassId, originalFactory);
- }
- registrar.registerFactory(mockedClassId, "", contractId, mockedFactory);
- }
-
- return { contractId: contractId,
- mockedClassId: mockedClassId,
- mockedFactory: mockedFactory,
- originalClassId: originalClassId,
- originalFactory: originalFactory };
-}
-
-function registerOriginalFactory(contractId, mockedClassId, mockedFactory, originalClassId, originalFactory) {
- if (originalFactory) {
- var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
- registrar.unregisterFactory(mockedClassId, mockedFactory);
- registrar.registerFactory(originalClassId, "", contractId, originalFactory);
- }
-}
-
-var sessionId = 'test-session-id-' + uuidGenerator.generateUUID().toString();
-
-const address = Cc["@mozilla.org/supports-cstring;1"]
- .createInstance(Ci.nsISupportsCString);
-address.data = "127.0.0.1";
-const addresses = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
-addresses.appendElement(address, false);
-
-const mockedChannelDescription = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
- get type() {
- if (Services.prefs.getBoolPref("dom.presentation.session_transport.data_channel.enable")) {
- return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL;
- }
- return Ci.nsIPresentationChannelDescription.TYPE_TCP;
- },
- tcpAddress: addresses,
- tcpPort: 1234,
-};
-
-const mockedServerSocket = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIServerSocket,
- Ci.nsIFactory]),
- createInstance: function(aOuter, aIID) {
- if (aOuter) {
- throw Components.results.NS_ERROR_NO_AGGREGATION;
- }
- return this.QueryInterface(aIID);
- },
- get port() {
- return this._port;
- },
- set listener(listener) {
- this._listener = listener;
- },
- init: function(port, loopbackOnly, backLog) {
- if (port != -1) {
- this._port = port;
- } else {
- this._port = 5678;
- }
- },
- asyncListen: function(listener) {
- this._listener = listener;
- },
- close: function() {
- this._listener.onStopListening(this, Cr.NS_BINDING_ABORTED);
- },
- simulateOnSocketAccepted: function(serverSocket, socketTransport) {
- this._listener.onSocketAccepted(serverSocket, socketTransport);
- }
-};
-
-const mockedSocketTransport = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISocketTransport]),
-};
-
-const mockedControlChannel = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
- set listener(listener) {
- this._listener = listener;
- },
- get listener() {
- return this._listener;
- },
- sendOffer: function(offer) {
- sendAsyncMessage('offer-sent', this._isValidSDP(offer));
- },
- sendAnswer: function(answer) {
- sendAsyncMessage('answer-sent', this._isValidSDP(answer));
-
- if (answer.type == Ci.nsIPresentationChannelDescription.TYPE_TCP) {
- this._listener.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportReady();
- }
- },
- _isValidSDP: function(aSDP) {
- var isValid = false;
- if (aSDP.type == Ci.nsIPresentationChannelDescription.TYPE_TCP) {
- try {
- var addresses = aSDP.tcpAddress;
- if (addresses.length > 0) {
- for (var i = 0; i < addresses.length; i++) {
- // Ensure CString addresses are used. Otherwise, an error will be thrown.
- addresses.queryElementAt(i, Ci.nsISupportsCString);
- }
-
- isValid = true;
- }
- } catch (e) {
- isValid = false;
- }
- } else if (aSDP.type == Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL) {
- isValid = (aSDP.dataChannelSDP == "test-sdp");
- }
- return isValid;
- },
- launch: function(presentationId, url) {
- sessionId = presentationId;
- },
- terminate: function(presentationId) {
- sendAsyncMessage('sender-terminate', presentationId);
- },
- reconnect: function(presentationId, url) {
- sendAsyncMessage('start-reconnect', url);
- },
- notifyReconnected: function() {
- this._listener
- .QueryInterface(Ci.nsIPresentationControlChannelListener)
- .notifyReconnected();
- },
- disconnect: function(reason) {
- sendAsyncMessage('control-channel-closed', reason);
- this._listener.QueryInterface(Ci.nsIPresentationControlChannelListener).notifyDisconnected(reason);
- },
- simulateReceiverReady: function() {
- this._listener.QueryInterface(Ci.nsIPresentationControlChannelListener).notifyReceiverReady();
- },
- simulateOnOffer: function() {
- sendAsyncMessage('offer-received');
- this._listener.QueryInterface(Ci.nsIPresentationControlChannelListener).onOffer(mockedChannelDescription);
- },
- simulateOnAnswer: function() {
- sendAsyncMessage('answer-received');
- this._listener.QueryInterface(Ci.nsIPresentationControlChannelListener).onAnswer(mockedChannelDescription);
- },
- simulateNotifyConnected: function() {
- sendAsyncMessage('control-channel-opened');
- this._listener.QueryInterface(Ci.nsIPresentationControlChannelListener).notifyConnected();
- },
-};
-
-const mockedDevice = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
- id: 'id',
- name: 'name',
- type: 'type',
- establishControlChannel: function(url, presentationId) {
- sendAsyncMessage('control-channel-established');
- return mockedControlChannel;
- },
- disconnect: function() {},
- isRequestedUrlSupported: function(requestedUrl) {
- return true;
- },
-};
-
-const mockedDevicePrompt = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt,
- Ci.nsIFactory]),
- createInstance: function(aOuter, aIID) {
- if (aOuter) {
- throw Components.results.NS_ERROR_NO_AGGREGATION;
- }
- return this.QueryInterface(aIID);
- },
- set request(request) {
- this._request = request;
- },
- get request() {
- return this._request;
- },
- promptDeviceSelection: function(request) {
- this._request = request;
- sendAsyncMessage('device-prompt');
- },
- simulateSelect: function() {
- this._request.select(mockedDevice);
- },
- simulateCancel: function(result) {
- this._request.cancel(result);
- }
-};
-
-const mockedSessionTransport = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransport,
- Ci.nsIPresentationSessionTransportBuilder,
- Ci.nsIPresentationTCPSessionTransportBuilder,
- Ci.nsIPresentationDataChannelSessionTransportBuilder,
- Ci.nsIPresentationControlChannelListener,
- Ci.nsIFactory]),
- createInstance: function(aOuter, aIID) {
- if (aOuter) {
- throw Components.results.NS_ERROR_NO_AGGREGATION;
- }
- return this.QueryInterface(aIID);
- },
- set callback(callback) {
- this._callback = callback;
- },
- get callback() {
- return this._callback;
- },
- get selfAddress() {
- return this._selfAddress;
- },
- buildTCPSenderTransport: function(transport, listener) {
- this._listener = listener;
- this._role = Ci.nsIPresentationService.ROLE_CONTROLLER;
- this._listener.onSessionTransport(this);
- this._listener = null;
- sendAsyncMessage('data-transport-initialized');
-
- setTimeout(()=>{
- this.simulateTransportReady();
- }, 0);
- },
- buildTCPReceiverTransport: function(description, listener) {
- this._listener = listener;
- this._role = Ci.nsIPresentationService.ROLE_RECEIVER;
-
- var addresses = description.QueryInterface(Ci.nsIPresentationChannelDescription).tcpAddress;
- this._selfAddress = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsINetAddr]),
- address: (addresses.length > 0) ?
- addresses.queryElementAt(0, Ci.nsISupportsCString).data : "",
- port: description.QueryInterface(Ci.nsIPresentationChannelDescription).tcpPort,
- };
-
- setTimeout(()=>{
- this._listener.onSessionTransport(this);
- this._listener = null;
- }, 0);
- },
- // in-process case
- buildDataChannelTransport: function(role, window, listener) {
- this._listener = listener;
- this._role = role;
-
- var hasNavigator = window ? (typeof window.navigator != "undefined") : false;
- sendAsyncMessage('check-navigator', hasNavigator);
-
- setTimeout(()=>{
- this._listener.onSessionTransport(this);
- this._listener = null;
- this.simulateTransportReady();
- }, 0);
- },
- enableDataNotification: function() {
- sendAsyncMessage('data-transport-notification-enabled');
- },
- send: function(data) {
- sendAsyncMessage('message-sent', data);
- },
- close: function(reason) {
- sendAsyncMessage('data-transport-closed', reason);
- this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportClosed(reason);
- },
- simulateTransportReady: function() {
- this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportReady();
- },
- simulateIncomingMessage: function(message) {
- this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message, false);
- },
- onOffer: function(aOffer) {
- },
- onAnswer: function(aAnswer) {
- }
-};
-
-const mockedNetworkInfo = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInfo]),
- getAddresses: function(ips, prefixLengths) {
- ips.value = ["127.0.0.1"];
- prefixLengths.value = [0];
- return 1;
- },
-};
-
-const mockedNetworkManager = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkManager,
- Ci.nsIFactory]),
- createInstance: function(aOuter, aIID) {
- if (aOuter) {
- throw Components.results.NS_ERROR_NO_AGGREGATION;
- }
- return this.QueryInterface(aIID);
- },
- get activeNetworkInfo() {
- return mockedNetworkInfo;
- },
-};
-
-var requestPromise = null;
-
-const mockedRequestUIGlue = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationRequestUIGlue,
- Ci.nsIFactory]),
- createInstance: function(aOuter, aIID) {
- if (aOuter) {
- throw Components.results.NS_ERROR_NO_AGGREGATION;
- }
- return this.QueryInterface(aIID);
- },
- sendRequest: function(aUrl, aSessionId) {
- sendAsyncMessage('receiver-launching', aSessionId);
- return requestPromise;
- },
-};
-
-// Register mocked factories.
-const originalFactoryData = [];
-originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation-device/prompt;1",
- uuidGenerator.generateUUID(),
- mockedDevicePrompt));
-originalFactoryData.push(registerMockedFactory("@mozilla.org/network/server-socket;1",
- uuidGenerator.generateUUID(),
- mockedServerSocket));
-originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/presentationtcpsessiontransport;1",
- uuidGenerator.generateUUID(),
- mockedSessionTransport));
-originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/datachanneltransportbuilder;1",
- uuidGenerator.generateUUID(),
- mockedSessionTransport));
-originalFactoryData.push(registerMockedFactory("@mozilla.org/network/manager;1",
- uuidGenerator.generateUUID(),
- mockedNetworkManager));
-originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/requestuiglue;1",
- uuidGenerator.generateUUID(),
- mockedRequestUIGlue));
-
-function tearDown() {
- requestPromise = null;
- mockedServerSocket.listener = null;
- mockedControlChannel.listener = null;
- mockedDevice.listener = null;
- mockedDevicePrompt.request = null;
- mockedSessionTransport.callback = null;
-
- var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
- .getService(Ci.nsIPresentationDeviceManager);
- deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener).removeDevice(mockedDevice);
-
- // Register original factories.
- for (var data of originalFactoryData) {
- registerOriginalFactory(data.contractId, data.mockedClassId,
- data.mockedFactory, data.originalClassId,
- data.originalFactory);
- }
-
- sendAsyncMessage('teardown-complete');
-}
-
-addMessageListener('trigger-device-add', function() {
- var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
- .getService(Ci.nsIPresentationDeviceManager);
- deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener).addDevice(mockedDevice);
-});
-
-addMessageListener('trigger-device-prompt-select', function() {
- mockedDevicePrompt.simulateSelect();
-});
-
-addMessageListener('trigger-device-prompt-cancel', function(result) {
- mockedDevicePrompt.simulateCancel(result);
-});
-
-addMessageListener('trigger-incoming-session-request', function(url) {
- var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
- .getService(Ci.nsIPresentationDeviceManager);
- deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
- .onSessionRequest(mockedDevice, url, sessionId, mockedControlChannel);
-});
-
-addMessageListener('trigger-incoming-terminate-request', function() {
- var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
- .getService(Ci.nsIPresentationDeviceManager);
- deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
- .onTerminateRequest(mockedDevice, sessionId, mockedControlChannel, true);
-});
-
-addMessageListener('trigger-reconnected-acked', function(url) {
- mockedControlChannel.notifyReconnected();
-});
-
-addMessageListener('trigger-incoming-offer', function() {
- mockedControlChannel.simulateOnOffer();
-});
-
-addMessageListener('trigger-incoming-answer', function() {
- mockedControlChannel.simulateOnAnswer();
-});
-
-addMessageListener('trigger-incoming-transport', function() {
- mockedServerSocket.simulateOnSocketAccepted(mockedServerSocket, mockedSocketTransport);
-});
-
-addMessageListener('trigger-control-channel-open', function(reason) {
- mockedControlChannel.simulateNotifyConnected();
-});
-
-addMessageListener('trigger-control-channel-close', function(reason) {
- mockedControlChannel.disconnect(reason);
-});
-
-addMessageListener('trigger-data-transport-close', function(reason) {
- mockedSessionTransport.close(reason);
-});
-
-addMessageListener('trigger-incoming-message', function(message) {
- mockedSessionTransport.simulateIncomingMessage(message);
-});
-
-addMessageListener('teardown', function() {
- tearDown();
-});
-
-var controlChannelListener;
-addMessageListener('save-control-channel-listener', function() {
- controlChannelListener = mockedControlChannel.listener;
-});
-
-addMessageListener('restore-control-channel-listener', function(message) {
- mockedControlChannel.listener = controlChannelListener;
- controlChannelListener = null;
-});
-
-var obs = Cc["@mozilla.org/observer-service;1"]
- .getService(Ci.nsIObserverService);
-obs.addObserver(function observer(aSubject, aTopic, aData) {
- obs.removeObserver(observer, aTopic);
-
- requestPromise = aSubject;
-}, 'setup-request-promise', false);
diff --git a/dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js b/dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js
deleted file mode 100644
index 82d7362b2..000000000
--- a/dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js
+++ /dev/null
@@ -1,366 +0,0 @@
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
-* You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-'use strict';
-
-const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
-
-const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator);
-
-function debug(str) {
- // dump('DEBUG -*- PresentationSessionChromeScript1UA -*-: ' + str + '\n');
-}
-
-const originalFactoryData = [];
-var sessionId; // Store the uuid generated by PresentationRequest.
-var triggerControlChannelError = false; // For simulating error during control channel establishment.
-
-// control channel of sender
-const mockControlChannelOfSender = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
- set listener(listener) {
- // PresentationControllingInfo::SetControlChannel
- if (listener) {
- debug('set listener for mockControlChannelOfSender without null');
- } else {
- debug('set listener for mockControlChannelOfSender with null');
- }
- this._listener = listener;
- },
- get listener() {
- return this._listener;
- },
- notifyConnected: function() {
- // send offer after notifyConnected immediately
- this._listener
- .QueryInterface(Ci.nsIPresentationControlChannelListener)
- .notifyConnected();
- },
- notifyReconnected: function() {
- // send offer after notifyOpened immediately
- this._listener
- .QueryInterface(Ci.nsIPresentationControlChannelListener)
- .notifyReconnected();
- },
- sendOffer: function(offer) {
- Services.tm.mainThread.dispatch(() => {
- mockControlChannelOfReceiver.onOffer(offer);
- }, Ci.nsIThread.DISPATCH_NORMAL);
- },
- onAnswer: function(answer) {
- this._listener
- .QueryInterface(Ci.nsIPresentationControlChannelListener)
- .onAnswer(answer);
- },
- launch: function(presentationId, url) {
- sessionId = presentationId;
- sendAsyncMessage('sender-launch', url);
- },
- disconnect: function(reason) {
- if (!this._listener) {
- return;
- }
- this._listener
- .QueryInterface(Ci.nsIPresentationControlChannelListener)
- .notifyDisconnected(reason);
- mockControlChannelOfReceiver.disconnect();
- },
- terminate: function(presentationId) {
- sendAsyncMessage('sender-terminate');
- },
- reconnect: function(presentationId, url) {
- sendAsyncMessage('start-reconnect', url);
- },
- sendIceCandidate: function(candidate) {
- mockControlChannelOfReceiver.notifyIceCandidate(candidate);
- },
- notifyIceCandidate: function(candidate) {
- if (!this._listener) {
- return;
- }
-
- this._listener
- .QueryInterface(Ci.nsIPresentationControlChannelListener)
- .onIceCandidate(candidate);
- },
-};
-
-// control channel of receiver
-const mockControlChannelOfReceiver = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
- set listener(listener) {
- // PresentationPresentingInfo::SetControlChannel
- if (listener) {
- debug('set listener for mockControlChannelOfReceiver without null');
- } else {
- debug('set listener for mockControlChannelOfReceiver with null');
- }
- this._listener = listener;
-
- if (this._pendingOpened) {
- this._pendingOpened = false;
- this.notifyConnected();
- }
- },
- get listener() {
- return this._listener;
- },
- notifyConnected: function() {
- // do nothing
- if (!this._listener) {
- this._pendingOpened = true;
- return;
- }
- this._listener
- .QueryInterface(Ci.nsIPresentationControlChannelListener)
- .notifyConnected();
- },
- onOffer: function(offer) {
- this._listener
- .QueryInterface(Ci.nsIPresentationControlChannelListener)
- .onOffer(offer);
- },
- sendAnswer: function(answer) {
- Services.tm.mainThread.dispatch(() => {
- mockControlChannelOfSender.onAnswer(answer);
- }, Ci.nsIThread.DISPATCH_NORMAL);
- },
- disconnect: function(reason) {
- if (!this._listener) {
- return;
- }
-
- this._listener
- .QueryInterface(Ci.nsIPresentationControlChannelListener)
- .notifyDisconnected(reason);
- sendAsyncMessage('control-channel-receiver-closed', reason);
- },
- terminate: function(presentaionId) {
- },
- sendIceCandidate: function(candidate) {
- mockControlChannelOfReceiver.notifyIceCandidate(candidate);
- },
- notifyIceCandidate: function(candidate) {
- if (!this._listener) {
- return;
- }
-
- this._listener
- .QueryInterface(Ci.nsIPresentationControlChannelListener)
- .onIceCandidate(candidate);
- },
-};
-
-const mockDevice = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
- id: 'id',
- name: 'name',
- type: 'type',
- establishControlChannel: function(url, presentationId) {
- if (triggerControlChannelError) {
- throw Cr.NS_ERROR_FAILURE;
- }
- sendAsyncMessage('control-channel-established');
- return mockControlChannelOfSender;
- },
- disconnect: function() {
- sendAsyncMessage('device-disconnected');
- },
- isRequestedUrlSupported: function(requestedUrl) {
- return true;
- },
-};
-
-const mockDevicePrompt = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt,
- Ci.nsIFactory]),
- createInstance: function(aOuter, aIID) {
- if (aOuter) {
- throw Components.results.NS_ERROR_NO_AGGREGATION;
- }
- return this.QueryInterface(aIID);
- },
- set request(request) {
- this._request = request;
- },
- get request() {
- return this._request;
- },
- promptDeviceSelection: function(request) {
- this._request = request;
- sendAsyncMessage('device-prompt');
- },
- simulateSelect: function() {
- this._request.select(mockDevice);
- },
- simulateCancel: function() {
- this._request.cancel();
- }
-};
-
-const mockRequestUIGlue = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationRequestUIGlue,
- Ci.nsIFactory]),
- set promise(aPromise) {
- this._promise = aPromise
- },
- get promise() {
- return this._promise;
- },
- createInstance: function(aOuter, aIID) {
- if (aOuter) {
- throw Components.results.NS_ERROR_NO_AGGREGATION;
- }
- return this.QueryInterface(aIID);
- },
- sendRequest: function(aUrl, aSessionId) {
- return this.promise;
- },
-};
-
-function initMockAndListener() {
-
- function registerMockFactory(contractId, mockClassId, mockFactory) {
- var originalClassId, originalFactory;
-
- var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
- if (!registrar.isCIDRegistered(mockClassId)) {
- try {
- originalClassId = registrar.contractIDToCID(contractId);
- originalFactory = Cm.getClassObject(Cc[contractId], Ci.nsIFactory);
- } catch (ex) {
- originalClassId = "";
- originalFactory = null;
- }
- if (originalFactory) {
- registrar.unregisterFactory(originalClassId, originalFactory);
- }
- registrar.registerFactory(mockClassId, "", contractId, mockFactory);
- }
-
- return { contractId: contractId,
- mockClassId: mockClassId,
- mockFactory: mockFactory,
- originalClassId: originalClassId,
- originalFactory: originalFactory };
- }
- // Register mock factories.
- const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator);
- originalFactoryData.push(registerMockFactory("@mozilla.org/presentation-device/prompt;1",
- uuidGenerator.generateUUID(),
- mockDevicePrompt));
- originalFactoryData.push(registerMockFactory("@mozilla.org/presentation/requestuiglue;1",
- uuidGenerator.generateUUID(),
- mockRequestUIGlue));
-
- addMessageListener('trigger-device-add', function() {
- debug('Got message: trigger-device-add');
- var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
- .getService(Ci.nsIPresentationDeviceManager);
- deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
- .addDevice(mockDevice);
- });
-
- addMessageListener('trigger-device-prompt-select', function() {
- debug('Got message: trigger-device-prompt-select');
- mockDevicePrompt.simulateSelect();
- });
-
- addMessageListener('trigger-on-session-request', function(url) {
- debug('Got message: trigger-on-session-request');
- var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
- .getService(Ci.nsIPresentationDeviceManager);
- deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
- .onSessionRequest(mockDevice,
- url,
- sessionId,
- mockControlChannelOfReceiver);
- });
-
- addMessageListener('trigger-on-terminate-request', function() {
- debug('Got message: trigger-on-terminate-request');
- var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
- .getService(Ci.nsIPresentationDeviceManager);
- deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
- .onTerminateRequest(mockDevice,
- sessionId,
- mockControlChannelOfReceiver,
- false);
- });
-
- addMessageListener('trigger-control-channel-open', function(reason) {
- debug('Got message: trigger-control-channel-open');
- mockControlChannelOfSender.notifyConnected();
- mockControlChannelOfReceiver.notifyConnected();
- });
-
- addMessageListener('trigger-control-channel-error', function(reason) {
- debug('Got message: trigger-control-channel-open');
- triggerControlChannelError = true;
- });
-
- addMessageListener('trigger-reconnected-acked', function(url) {
- debug('Got message: trigger-reconnected-acked');
- mockControlChannelOfSender.notifyReconnected();
- var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
- .getService(Ci.nsIPresentationDeviceManager);
- deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
- .onReconnectRequest(mockDevice,
- url,
- sessionId,
- mockControlChannelOfReceiver);
- });
-
- // Used to call sendAsyncMessage in chrome script from receiver.
- addMessageListener('forward-command', function(command_data) {
- let command = JSON.parse(command_data);
- sendAsyncMessage(command.name, command.data);
- });
-
- addMessageListener('teardown', teardown);
-
- var obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
- obs.addObserver(function setupRequestPromiseHandler(aSubject, aTopic, aData) {
- debug('Got observer: setup-request-promise');
- obs.removeObserver(setupRequestPromiseHandler, aTopic);
- mockRequestUIGlue.promise = aSubject;
- sendAsyncMessage('promise-setup-ready');
- }, 'setup-request-promise', false);
-}
-
-function teardown() {
-
- function registerOriginalFactory(contractId, mockedClassId, mockedFactory, originalClassId, originalFactory) {
- if (originalFactory) {
- var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
- registrar.unregisterFactory(mockedClassId, mockedFactory);
- registrar.registerFactory(originalClassId, "", contractId, originalFactory);
- }
- }
-
- mockRequestUIGlue.promise = null;
- mockControlChannelOfSender.listener = null;
- mockControlChannelOfReceiver.listener = null;
- mockDevicePrompt.request = null;
-
- var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
- .getService(Ci.nsIPresentationDeviceManager);
- deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
- .removeDevice(mockDevice);
- // Register original factories.
- for (var data of originalFactoryData) {
- registerOriginalFactory(data.contractId, data.mockClassId,
- data.mockFactory, data.originalClassId,
- data.originalFactory);
- }
- sendAsyncMessage('teardown-complete');
-}
-
-initMockAndListener();
diff --git a/dom/presentation/tests/mochitest/PresentationSessionFrameScript.js b/dom/presentation/tests/mochitest/PresentationSessionFrameScript.js
deleted file mode 100644
index 77240ab5f..000000000
--- a/dom/presentation/tests/mochitest/PresentationSessionFrameScript.js
+++ /dev/null
@@ -1,258 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-function loadPrivilegedScriptTest() {
- /**
- * The script is loaded as
- * (a) a privileged script in content process for dc_sender.html
- * (b) a frame script in the remote iframe process for dc_receiver_oop.html
- * |type port == "undefined"| indicates the script is load by
- * |loadPrivilegedScript| which is the first case.
- */
- function sendMessage(type, data) {
- if (typeof port == "undefined") {
- sendAsyncMessage(type, {'data': data});
- } else {
- port.postMessage({'type': type,
- 'data': data
- });
- }
- }
-
- if (typeof port != "undefined") {
- /**
- * When the script is loaded by |loadPrivilegedScript|, these APIs
- * are exposed to this script.
- */
- port.onmessage = (e) => {
- var type = e.data['type'];
- if (!handlers.hasOwnProperty(type)) {
- return;
- }
- var args = [e];
- handlers[type].forEach(handler => handler.apply(null, args));
- };
- var handlers = {};
- addMessageListener = function(message, handler) {
- if (handlers.hasOwnProperty(message)) {
- handlers[message].push(handler);
- } else {
- handlers[message] = [handler];
- }
- };
- removeMessageListener = function(message, handler) {
- if (!handler || !handlers.hasOwnProperty(message)) {
- return;
- }
- var index = handlers[message].indexOf(handler);
- if (index != -1) {
- handlers[message].splice(index, 1);
- }
- };
- }
-
- const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
-
- const mockedChannelDescription = {
- QueryInterface : function (iid) {
- const interfaces = [Ci.nsIPresentationChannelDescription];
-
- if (!interfaces.some(v => iid.equals(v))) {
- throw Cr.NS_ERROR_NO_INTERFACE;
- }
- return this;
- },
- get type() {
- if (Services.prefs.getBoolPref("dom.presentation.session_transport.data_channel.enable")) {
- return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL;
- }
- return Ci.nsIPresentationChannelDescription.TYPE_TCP;
- },
- get dataChannelSDP() {
- return "test-sdp";
- }
- };
-
- function setTimeout(callback, delay) {
- let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- timer.initWithCallback({ notify: callback },
- delay,
- Ci.nsITimer.TYPE_ONE_SHOT);
- return timer;
- }
-
- const mockedSessionTransport = {
- QueryInterface : function (iid) {
- const interfaces = [Ci.nsIPresentationSessionTransport,
- Ci.nsIPresentationDataChannelSessionTransportBuilder,
- Ci.nsIFactory];
-
- if (!interfaces.some(v => iid.equals(v))) {
- throw Cr.NS_ERROR_NO_INTERFACE;
- }
- return this;
- },
- createInstance: function(aOuter, aIID) {
- if (aOuter) {
- throw Components.results.NS_ERROR_NO_AGGREGATION;
- }
- return this.QueryInterface(aIID);
- },
- set callback(callback) {
- this._callback = callback;
- },
- get callback() {
- return this._callback;
- },
- /* OOP case */
- buildDataChannelTransport: function(role, window, listener) {
- dump("PresentationSessionFrameScript: build data channel transport\n");
- this._listener = listener;
- this._role = role;
-
- var hasNavigator = window ? (typeof window.navigator != "undefined") : false;
- sendMessage('check-navigator', hasNavigator);
-
- if (this._role == Ci.nsIPresentationService.ROLE_CONTROLLER) {
- this._listener.sendOffer(mockedChannelDescription);
- }
- },
-
- enableDataNotification: function() {
- sendMessage('data-transport-notification-enabled');
- },
- send: function(data) {
- sendMessage('message-sent', data);
- },
- close: function(reason) {
- sendMessage('data-transport-closed', reason);
- this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportClosed(reason);
- this._callback = null;
- },
- simulateTransportReady: function() {
- this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportReady();
- },
- simulateIncomingMessage: function(message) {
- this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message, false);
- },
- onOffer: function(aOffer) {
- this._listener.sendAnswer(mockedChannelDescription);
- this._onSessionTransport();
- },
- onAnswer: function(aAnswer) {
- this._onSessionTransport();
- },
- _onSessionTransport: function() {
- setTimeout(()=>{
- this._listener.onSessionTransport(this);
- this.simulateTransportReady();
- this._listener = null;
- }, 0);
- }
- };
-
-
- function tearDown() {
- mockedSessionTransport.callback = null;
-
- /* Register original factories. */
- for (var data of originalFactoryData) {
- registerOriginalFactory(data.contractId, data.mockedClassId,
- data.mockedFactory, data.originalClassId,
- data.originalFactory);
- }
- sendMessage("teardown-complete");
- }
-
-
- function registerMockedFactory(contractId, mockedClassId, mockedFactory) {
- var originalClassId, originalFactory;
- var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
-
- if (!registrar.isCIDRegistered(mockedClassId)) {
- try {
- originalClassId = registrar.contractIDToCID(contractId);
- originalFactory = Cm.getClassObject(Cc[contractId], Ci.nsIFactory);
- } catch (ex) {
- originalClassId = "";
- originalFactory = null;
- }
- if (originalFactory) {
- registrar.unregisterFactory(originalClassId, originalFactory);
- }
- registrar.registerFactory(mockedClassId, "", contractId, mockedFactory);
- }
-
- return { contractId: contractId,
- mockedClassId: mockedClassId,
- mockedFactory: mockedFactory,
- originalClassId: originalClassId,
- originalFactory: originalFactory };
- }
-
- function registerOriginalFactory(contractId, mockedClassId, mockedFactory, originalClassId, originalFactory) {
- if (originalFactory) {
- var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
- registrar.unregisterFactory(mockedClassId, mockedFactory);
- registrar.registerFactory(originalClassId, "", contractId, originalFactory);
- }
- }
-
- /* Register mocked factories. */
- const originalFactoryData = [];
- const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator);
- originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/datachanneltransportbuilder;1",
- uuidGenerator.generateUUID(),
- mockedSessionTransport));
-
- addMessageListener('trigger-incoming-message', function(event) {
- mockedSessionTransport.simulateIncomingMessage(event.data.data);
- });
- addMessageListener('teardown', ()=>tearDown());
-}
-
-// Exposed to the caller of |loadPrivilegedScript|
-var contentScript = {
- handlers: {},
- addMessageListener: function(message, handler) {
- if (this.handlers.hasOwnProperty(message)) {
- this.handlers[message].push(handler);
- } else {
- this.handlers[message] = [handler];
- }
- },
- removeMessageListener: function(message, handler) {
- if (!handler || !this.handlers.hasOwnProperty(message)) {
- return;
- }
- var index = this.handlers[message].indexOf(handler);
- if (index != -1) {
- this.handlers[message].splice(index, 1);
- }
- },
- sendAsyncMessage: function(message, data) {
- port.postMessage({'type': message,
- 'data': data
- });
- }
-}
-
-if (!SpecialPowers.isMainProcess()) {
- var port;
- try {
- port = SpecialPowers.loadPrivilegedScript(loadPrivilegedScriptTest.toSource());
- } catch (e) {
- ok(false, "loadPrivilegedScript shoulde not throw" + e);
- }
-
- port.onmessage = (e) => {
- var type = e.data['type'];
- if (!contentScript.handlers.hasOwnProperty(type)) {
- return;
- }
- var args = [e.data['data']];
- contentScript.handlers[type].forEach(handler => handler.apply(null, args));
- };
-}
diff --git a/dom/presentation/tests/mochitest/chrome.ini b/dom/presentation/tests/mochitest/chrome.ini
deleted file mode 100644
index 83841f4f8..000000000
--- a/dom/presentation/tests/mochitest/chrome.ini
+++ /dev/null
@@ -1,14 +0,0 @@
-[DEFAULT]
-support-files =
- PresentationDeviceInfoChromeScript.js
- PresentationSessionChromeScript.js
-
-[test_presentation_datachannel_sessiontransport.html]
-skip-if = os == 'android'
-[test_presentation_device_info.html]
-[test_presentation_sender_startWithDevice.html]
-skip-if = toolkit == 'android' # Bug 1129785
-[test_presentation_tcp_sender.html]
-skip-if = toolkit == 'android' # Bug 1129785
-[test_presentation_tcp_sender_default_request.html]
-skip-if = toolkit == 'android' # Bug 1129785
diff --git a/dom/presentation/tests/mochitest/file_presentation_1ua_receiver.html b/dom/presentation/tests/mochitest/file_presentation_1ua_receiver.html
deleted file mode 100644
index cf02d2b2c..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_1ua_receiver.html
+++ /dev/null
@@ -1,220 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <head>
- <meta charset="utf-8">
- <title>Test for B2G PresentationReceiver at receiver side</title>
- </head>
- <body>
- <div id="content"></div>
-<script type="application/javascript;version=1.7">
-
-"use strict";
-
-function is(a, b, msg) {
- if (a === b) {
- alert('OK ' + msg);
- } else {
- alert('KO ' + msg + ' | reason: ' + a + ' != ' + b);
- }
-}
-
-function ok(a, msg) {
- alert((a ? 'OK ' : 'KO ') + msg);
-}
-
-function info(msg) {
- alert('INFO ' + msg);
-}
-
-function command(name, data) {
- alert('COMMAND ' + JSON.stringify({name: name, data: data}));
-}
-
-function finish() {
- alert('DONE');
-}
-
-var connection;
-const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0];
-const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length);
-const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER);
-TYPED_DATA_ARRAY.set(DATA_ARRAY);
-
-function is_same_buffer(recv_data, expect_data) {
- let recv_dataview = new Uint8Array(recv_data);
- let expected_dataview = new Uint8Array(expect_data);
-
- if (recv_dataview.length !== expected_dataview.length) {
- return false;
- }
-
- for (let i = 0; i < recv_dataview.length; i++) {
- if (recv_dataview[i] != expected_dataview[i]) {
- info('discover byte differenct at ' + i);
- return false;
- }
- }
- return true;
-}
-
-function testConnectionAvailable() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testConnectionAvailable ---');
- ok(navigator.presentation, "Receiver: navigator.presentation should be available.");
- ok(navigator.presentation.receiver, "Receiver: navigator.presentation.receiver should be available.");
- is(navigator.presentation.defaultRequest, null, "Receiver: navigator.presentation.defaultRequest should be null.");
-
- navigator.presentation.receiver.connectionList
- .then((aList) => {
- is(aList.connections.length, 1, "Should get one conncetion.");
- connection = aList.connections[0];
- ok(connection.id, "Connection ID should be set: " + connection.id);
- is(connection.state, "connected", "Connection state at receiver side should be connected.");
- aResolve();
- })
- .catch((aError) => {
- ok(false, "Receiver: Error occurred when getting the connection: " + aError);
- finish();
- aReject();
- });
- });
-}
-
-function testConnectionReady() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testConnectionReady ---');
- connection.onconnect = function() {
- connection.onconnect = null;
- ok(false, "Should not get |onconnect| event.")
- aReject();
- };
- if (connection.state === "connected") {
- connection.onconnect = null;
- is(connection.state, "connected", "Receiver: Connection state should become connected.");
- aResolve();
- }
- });
-}
-
-function testIncomingMessage() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testIncomingMessage ---');
- connection.addEventListener('message', function messageHandler(evt) {
- connection.removeEventListener('message', messageHandler);
- let msg = evt.data;
- is(msg, 'msg-sender-to-receiver', 'Receiver: Receiver should receive message from sender.');
- command('forward-command', JSON.stringify({ name: 'message-from-sender-received' }));
- aResolve();
- });
- command('forward-command', JSON.stringify({ name: 'trigger-message-from-sender' }));
- });
-}
-
-function testSendMessage() {
- return new Promise(function(aResolve, aReject) {
- window.addEventListener('hashchange', function hashchangeHandler(evt) {
- var message = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
- if (message.type === 'trigger-message-from-receiver') {
- info('Receiver: --- testSendMessage ---');
- connection.send('msg-receiver-to-sender');
- }
- if (message.type === 'message-from-receiver-received') {
- window.removeEventListener('hashchange', hashchangeHandler);
- aResolve();
- }
- });
- });
-}
-
-function testIncomingBlobMessage() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testIncomingBlobMessage ---');
- connection.send('testIncomingBlobMessage');
- connection.addEventListener('message', function messageHandler(evt) {
- connection.removeEventListener('message', messageHandler);
- let recvData= String.fromCharCode.apply(null, new Uint8Array(evt.data));
- is(recvData, "Hello World", 'expected same string data');
- aResolve();
- });
- });
-}
-
-function testConnectionClosed() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testConnectionClosed ---');
- connection.onclose = function() {
- connection.onclose = null;
- is(connection.state, "closed", "Receiver: Connection should be closed.");
- command('forward-command', JSON.stringify({ name: 'receiver-closed' }));
- aResolve();
- };
- command('forward-command', JSON.stringify({ name: 'ready-to-close' }));
- });
-}
-
-function testReconnectConnection() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testReconnectConnection ---');
- window.addEventListener('hashchange', function hashchangeHandler(evt) {
- var message = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
- if (message.type === 'prepare-for-reconnect') {
- command('forward-command', JSON.stringify({ name: 'ready-to-reconnect' }));
- }
- });
- connection.onconnect = function() {
- connection.onconnect = null;
- ok(true, "The connection is reconnected.")
- aResolve();
- };
- });
-}
-
-function testIncomingArrayBuffer() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testIncomingArrayBuffer ---');
- connection.binaryType = "blob";
- connection.send('testIncomingArrayBuffer');
- connection.addEventListener('message', function messageHandler(evt) {
- connection.removeEventListener('message', messageHandler);
- var fileReader = new FileReader();
- fileReader.onload = function() {
- ok(is_same_buffer(DATA_ARRAY_BUFFER, this.result), "expected same buffer data");
- aResolve();
- };
- fileReader.readAsArrayBuffer(evt.data);
- });
- });
-}
-
-function testIncomingArrayBufferView() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testIncomingArrayBufferView ---');
- connection.binaryType = "arraybuffer";
- connection.send('testIncomingArrayBufferView');
- connection.addEventListener('message', function messageHandler(evt) {
- connection.removeEventListener('message', messageHandler);
- ok(is_same_buffer(evt.data, TYPED_DATA_ARRAY), "expected same buffer data");
- aResolve();
- });
- });
-}
-
-function runTests() {
- testConnectionAvailable()
- .then(testConnectionReady)
- .then(testIncomingMessage)
- .then(testSendMessage)
- .then(testIncomingBlobMessage)
- .then(testConnectionClosed)
- .then(testReconnectConnection)
- .then(testIncomingArrayBuffer)
- .then(testIncomingArrayBufferView)
- .then(testConnectionClosed);
-}
-
-runTests();
-
-</script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_1ua_wentaway.html b/dom/presentation/tests/mochitest/file_presentation_1ua_wentaway.html
deleted file mode 100644
index 370cb92e1..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_1ua_wentaway.html
+++ /dev/null
@@ -1,95 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <head>
- <meta charset="utf-8">
- <title>Test for B2G PresentationReceiver at receiver side</title>
- </head>
- <body>
- <div id="content"></div>
-<script type="application/javascript;version=1.7">
-
-"use strict";
-
-function is(a, b, msg) {
- if (a === b) {
- alert('OK ' + msg);
- } else {
- alert('KO ' + msg + ' | reason: ' + a + ' != ' + b);
- }
-}
-
-function ok(a, msg) {
- alert((a ? 'OK ' : 'KO ') + msg);
-}
-
-function info(msg) {
- alert('INFO ' + msg);
-}
-
-function command(name, data) {
- alert('COMMAND ' + JSON.stringify({name: name, data: data}));
-}
-
-function finish() {
- alert('DONE');
-}
-
-var connection;
-
-function testConnectionAvailable() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testConnectionAvailable ---');
- ok(navigator.presentation, "Receiver: navigator.presentation should be available.");
- ok(navigator.presentation.receiver, "Receiver: navigator.presentation.receiver should be available.");
-
- navigator.presentation.receiver.connectionList
- .then((aList) => {
- is(aList.connections.length, 1, "Should get one conncetion.");
- connection = aList.connections[0];
- ok(connection.id, "Connection ID should be set: " + connection.id);
- is(connection.state, "connected", "Connection state at receiver side should be connected.");
- aResolve();
- })
- .catch((aError) => {
- ok(false, "Receiver: Error occurred when getting the connection: " + aError);
- finish();
- aReject();
- });
- });
-}
-
-function testConnectionReady() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testConnectionReady ---');
- connection.onconnect = function() {
- connection.onconnect = null;
- ok(false, "Should not get |onconnect| event.")
- aReject();
- };
- if (connection.state === "connected") {
- connection.onconnect = null;
- is(connection.state, "connected", "Receiver: Connection state should become connected.");
- aResolve();
- }
- });
-}
-
-function testConnectionWentaway() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testConnectionWentaway ---\n');
- command('forward-command', JSON.stringify({ name: 'ready-to-remove-receiverFrame' }));
- });
-}
-
-function runTests() {
- testConnectionAvailable()
- .then(testConnectionReady)
- .then(testConnectionWentaway);
-}
-
-runTests();
-
-</script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_mixed_security_contexts.html b/dom/presentation/tests/mochitest/file_presentation_mixed_security_contexts.html
deleted file mode 100644
index f042d2994..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_mixed_security_contexts.html
+++ /dev/null
@@ -1,159 +0,0 @@
-
-<!DOCTYPE HTML>
-<html>
-<head>
-<meta charset="utf-8">
-<title>Test allow-presentation sandboxing flag</title>
-<script type="application/javascript;version=1.8">
-
-"use strict";
-
-function is(a, b, msg) {
- window.parent.postMessage((a === b ? "OK " : "KO ") + msg, "*");
-}
-
-function ok(a, msg) {
- window.parent.postMessage((a ? "OK " : "KO ") + msg, "*");
-}
-
-function info(msg) {
- window.parent.postMessage("INFO " + msg, "*");
-}
-
-function command(msg) {
- window.parent.postMessage("COMMAND " + JSON.stringify(msg), "*");
-}
-
-function finish() {
- window.parent.postMessage("DONE", "*");
-}
-
-function testGetAvailability() {
- return new Promise(function(aResolve, aReject) {
- ok(navigator.presentation, "navigator.presentation should be available.");
- var request = new PresentationRequest("http://example.com");
-
- request.getAvailability().then(
- function(aAvailability) {
- ok(false, "Unexpected success, should get a security error.");
- aReject();
- },
- function(aError) {
- is(aError.name, "SecurityError", "Should get a security error.");
- aResolve();
- }
- );
- });
-}
-
-function testStartRequest() {
- return new Promise(function(aResolve, aReject) {
- var request = new PresentationRequest("http://example.com");
-
- request.start().then(
- function(aAvailability) {
- ok(false, "Unexpected success, should get a security error.");
- aReject();
- },
- function(aError) {
- is(aError.name, "SecurityError", "Should get a security error.");
- aResolve();
- }
- );
- });
-}
-
-function testReconnectRequest() {
- return new Promise(function(aResolve, aReject) {
- var request = new PresentationRequest("http://example.com");
-
- request.reconnect("dummyId").then(
- function(aConnection) {
- ok(false, "Unexpected success, should get a security error.");
- aReject();
- },
- function(aError) {
- is(aError.name, "SecurityError", "Should get a security error.");
- aResolve();
- }
- );
- });
-}
-
-function testGetAvailabilityForAboutBlank() {
- return new Promise(function(aResolve, aReject) {
- var request = new PresentationRequest("about:blank");
-
- request.getAvailability().then(
- function(aAvailability) {
- ok(true, "Success due to a priori authenticated URL.");
- aResolve();
- },
- function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- aReject();
- }
- );
- });
-}
-
-function testGetAvailabilityForAboutSrcdoc() {
- return new Promise(function(aResolve, aReject) {
- var request = new PresentationRequest("about:srcdoc");
-
- request.getAvailability().then(
- function(aAvailability) {
- ok(true, "Success due to a priori authenticated URL.");
- aResolve();
- },
- function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- aReject();
- }
- );
- });
-}
-
-function testGetAvailabilityForDataURL() {
- return new Promise(function(aResolve, aReject) {
- var request = new PresentationRequest("data:text/html,1");
-
- request.getAvailability().then(
- function(aAvailability) {
- ok(true, "Success due to a priori authenticated URL.");
- aResolve();
- },
- function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- aReject();
- }
- );
- });
-}
-
-function runTest() {
- testGetAvailability()
- .then(testStartRequest)
- .then(testReconnectRequest)
- .then(testGetAvailabilityForAboutBlank)
- .then(testGetAvailabilityForAboutSrcdoc)
- .then(testGetAvailabilityForDataURL)
- .then(finish);
-}
-
-window.addEventListener("message", function onMessage(evt) {
- window.removeEventListener("message", onMessage);
- if (evt.data === "start") {
- runTest();
- }
-}, false);
-
-window.setTimeout(function() {
- command("ready-to-start");
-}, 3000);
-
-</script>
-</head>
-<body>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_non_receiver.html b/dom/presentation/tests/mochitest/file_presentation_non_receiver.html
deleted file mode 100644
index 1203523ac..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_non_receiver.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <meta charset="utf-8">
- <title>Test for B2G PresentationReceiver on a non-receiver page at receiver side</title>
-</head>
-<body>
-<div id="content"></div>
-<script type="application/javascript;version=1.7">
-
-"use strict";
-
-function is(a, b, msg) {
- alert((a === b ? 'OK ' : 'KO ') + msg);
-}
-
-function ok(a, msg) {
- alert((a ? 'OK ' : 'KO ') + msg);
-}
-
-function info(msg) {
- alert('INFO ' + msg);
-}
-
-function finish() {
- alert('DONE');
-}
-
-function testConnectionAvailable() {
- return new Promise(function(aResolve, aReject) {
- is(navigator.presentation.receiver, null, "navigator.presentation.receiver shouldn't be available in non-receiving pages.");
- aResolve();
- });
-}
-
-testConnectionAvailable().
-then(finish);
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_non_receiver_inner_iframe.html b/dom/presentation/tests/mochitest/file_presentation_non_receiver_inner_iframe.html
deleted file mode 100644
index c95eddf57..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_non_receiver_inner_iframe.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <meta charset="utf-8">
- <title>Test for B2G PresentationReceiver on a non-receiver inner iframe of the receiver page at receiver side</title>
-</head>
-<body onload="testConnectionAvailable()">
-<div id="content"></div>
-<script type="application/javascript;version=1.7">
-
-"use strict";
-
-function ok(a, msg) {
- alert((a ? 'OK ' : 'KO ') + msg);
-}
-
-function testConnectionAvailable() {
- return new Promise(function(aResolve, aReject) {
- is(navigator.presentation.receiver, null, "navigator.presentation.receiver shouldn't be available in inner iframes with different origins from receiving pages.");
- aResolve();
- });
-}
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_receiver.html b/dom/presentation/tests/mochitest/file_presentation_receiver.html
deleted file mode 100644
index 46a330b5f..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_receiver.html
+++ /dev/null
@@ -1,140 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <meta charset="utf-8">
- <title>Test for B2G PresentationReceiver at receiver side</title>
-</head>
-<body>
-<div id="content"></div>
-<script type="application/javascript;version=1.7">
-
-"use strict";
-
-function is(a, b, msg) {
- alert((a === b ? 'OK ' : 'KO ') + msg);
-}
-
-function ok(a, msg) {
- alert((a ? 'OK ' : 'KO ') + msg);
-}
-
-function info(msg) {
- alert('INFO ' + msg);
-}
-
-function command(msg) {
- alert('COMMAND ' + JSON.stringify(msg));
-}
-
-function finish() {
- alert('DONE');
-}
-
-var connection;
-
-function testConnectionAvailable() {
- return new Promise(function(aResolve, aReject) {
- ok(navigator.presentation, "navigator.presentation should be available in receiving pages.");
- ok(navigator.presentation.receiver, "navigator.presentation.receiver should be available in receiving pages.");
-
- navigator.presentation.receiver.connectionList.then(
- function(aList) {
- is(aList.connections.length, 1, "Should get one conncetion.");
- connection = aList.connections[0];
- ok(connection.id, "Connection ID should be set: " + connection.id);
- is(connection.state, "connected", "Connection state at receiver side should be connected.");
- aResolve();
- },
- function(aError) {
- ok(false, "Error occurred when getting the connection list: " + aError);
- finish();
- aReject();
- }
- );
- command({ name: 'trigger-incoming-offer' });
- });
-}
-
-function testDefaultRequestIsUndefined() {
- return new Promise(function(aResolve, aReject) {
- is(navigator.presentation.defaultRequest, undefined, "navigator.presentation.defaultRequest should not be available in receiving UA");
- aResolve();
- });
-}
-
-function testConnectionAvailableSameOriginInnerIframe() {
- return new Promise(function(aResolve, aReject) {
- var iframe = document.createElement('iframe');
- iframe.setAttribute('src', './file_presentation_receiver_inner_iframe.html');
- document.body.appendChild(iframe);
-
- aResolve();
- });
-}
-
-function testConnectionUnavailableDiffOriginInnerIframe() {
- return new Promise(function(aResolve, aReject) {
- var iframe = document.createElement('iframe');
- iframe.setAttribute('src', 'http://example.com/tests/dom/presentation/tests/mochitest/file_presentation_non_receiver_inner_iframe.html');
- document.body.appendChild(iframe);
-
- aResolve();
- });
-}
-
-function testConnectionListSameObject() {
- return new Promise(function(aResolve, aReject) {
- is(navigator.presentation.receiver.connectionList, navigator.presentation.receiver.connectionList, "The promise should be the same object.");
- var promise = navigator.presentation.receiver.connectionList.then(
- function(aList) {
- is(connection, aList.connections[0], "The connection from list and the one from |connectionavailable| event should be the same.");
- aResolve();
- },
- function(aError) {
- ok(false, "Error occurred when getting the connection list: " + aError);
- finish();
- aReject();
- }
- );
- });
-}
-
-function testIncomingMessage() {
- return new Promise(function(aResolve, aReject) {
- const incomingMessage = "test incoming message";
-
- connection.addEventListener('message', function messageHandler(aEvent) {
- connection.removeEventListener('message', messageHandler);
- is(aEvent.data, incomingMessage, "An incoming message should be received.");
- aResolve();
- });
-
- command({ name: 'trigger-incoming-message',
- data: incomingMessage });
- });
-}
-
-function testCloseConnection() {
- return new Promise(function(aResolve, aReject) {
- connection.onclose = function() {
- connection.onclose = null;
- is(connection.state, "closed", "Connection should be closed.");
- aResolve();
- };
-
- connection.close();
- });
-}
-
-testConnectionAvailable().
-then(testDefaultRequestIsUndefined).
-then(testConnectionAvailableSameOriginInnerIframe).
-then(testConnectionUnavailableDiffOriginInnerIframe).
-then(testConnectionListSameObject).
-then(testIncomingMessage).
-then(testCloseConnection).
-then(finish);
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_receiver_auxiliary_navigation.html b/dom/presentation/tests/mochitest/file_presentation_receiver_auxiliary_navigation.html
deleted file mode 100644
index 3a6060310..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_receiver_auxiliary_navigation.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <meta charset="utf-8">
- <title>Test for sandboxed auxiliary navigation flag in receiver page</title>
-</head>
-<body>
-<div id="content"></div>
-<script type="application/javascript;version=1.7">
-
-"use strict";
-
-function is(a, b, msg) {
- alert((a === b ? 'OK ' : 'KO ') + msg);
-}
-
-function ok(a, msg) {
- alert((a ? 'OK ' : 'KO ') + msg);
-}
-
-function info(msg) {
- alert('INFO ' + msg);
-}
-
-function command(msg) {
- alert('COMMAND ' + JSON.stringify(msg));
-}
-
-function finish() {
- alert('DONE');
-}
-
-function testConnectionAvailable() {
- return new Promise(function(aResolve, aReject) {
- ok(navigator.presentation, "navigator.presentation should be available in OOP receiving pages.");
- ok(navigator.presentation.receiver, "navigator.presentation.receiver should be available in receiving pages.");
-
- aResolve();
- });
-}
-
-function testOpenWindow() {
- return new Promise(function(aResolve, aReject) {
- try {
- window.open("http://example.com");
- ok(false, "receiver page should not be able to open a new window.");
- } catch(e) {
- ok(true, "receiver page should not be able to open a new window.");
- aResolve();
- }
- });
-}
-
-testConnectionAvailable().
-then(testOpenWindow).
-then(finish);
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_receiver_establish_connection_error.html b/dom/presentation/tests/mochitest/file_presentation_receiver_establish_connection_error.html
deleted file mode 100644
index 6b1f2152f..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_receiver_establish_connection_error.html
+++ /dev/null
@@ -1,79 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <meta charset="utf-8">
- <title>Test for connection establishing errors of B2G Presentation API at receiver side</title>
-</head>
-<body>
-<div id="content"></div>
-<script type="application/javascript;version=1.7">
-
-"use strict";
-
-function is(a, b, msg) {
- if (a === b) {
- alert('OK ' + msg);
- } else {
- alert('KO ' + msg + ' | reason: ' + a + ' != ' + b);
- }
-}
-
-function ok(a, msg) {
- alert((a ? 'OK ' : 'KO ') + msg);
-}
-
-function info(msg) {
- alert('INFO ' + msg);
-}
-
-function command(name, data) {
- alert('COMMAND ' + JSON.stringify({name: name, data: data}));
-}
-
-function finish() {
- alert('DONE');
-}
-
-function testConnectionAvailable() {
- return new Promise(function(aResolve, aReject) {
- ok(navigator.presentation, "navigator.presentation should be available.");
- ok(navigator.presentation.receiver, "navigator.presentation.receiver should be available.");
- aResolve();
- });
-}
-
-function testUnexpectedControlChannelClose() {
- // Trigger the control channel to be closed with error code.
- command({ name: 'trigger-control-channel-close', data: 0x80004004 /* NS_ERROR_ABORT */ });
-
- return new Promise(function(aResolve, aReject) {
- return Promise.race([
- navigator.presentation.receiver.connectionList.then(
- (aList) => {
- ok(false, "Should not get a connection list.")
- aReject();
- },
- (aError) => {
- ok(false, "Error occurred when getting the connection list: " + aError);
- aReject();
- }
- ),
- new Promise(
- () => {
- setTimeout(() => {
- ok(true, "Not getting a conenction list.");
- aResolve();
- }, 3000);
- }
- ),
- ]);
- });
-}
-
-testConnectionAvailable().
-then(testUnexpectedControlChannelClose).
-then(finish);
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_receiver_inner_iframe.html b/dom/presentation/tests/mochitest/file_presentation_receiver_inner_iframe.html
deleted file mode 100644
index 3bd5ac4b1..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_receiver_inner_iframe.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <meta charset="utf-8">
- <title>Test for B2G PresentationReceiver in an inner iframe of the receiver page at receiver side</title>
-</head>
-<body onload="testConnectionAvailable()">
-<div id="content"></div>
-<script type="application/javascript;version=1.7">
-
-"use strict";
-
-function ok(a, msg) {
- alert((a ? 'OK ' : 'KO ') + msg);
-}
-
-function testConnectionAvailable() {
- return new Promise(function(aResolve, aReject) {
- ok(navigator.presentation.receiver, "navigator.presentation.receiver should be available in same-origin inner iframes of receiving pages.");
- aResolve();
- });
-}
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_reconnect.html b/dom/presentation/tests/mochitest/file_presentation_reconnect.html
deleted file mode 100644
index 174ccd3f3..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_reconnect.html
+++ /dev/null
@@ -1,102 +0,0 @@
-
-<!DOCTYPE HTML>
-<html>
-<head>
-<meta charset="utf-8">
-<title>Test allow-presentation sandboxing flag</title>
-<script type="application/javascript;version=1.8">
-
-"use strict";
-
-function is(a, b, msg) {
- window.parent.postMessage((a === b ? "OK " : "KO ") + msg, "*");
-}
-
-function ok(a, msg) {
- window.parent.postMessage((a ? "OK " : "KO ") + msg, "*");
-}
-
-function info(msg) {
- window.parent.postMessage("INFO " + msg, "*");
-}
-
-function command(msg) {
- window.parent.postMessage("COMMAND " + JSON.stringify(msg), "*");
-}
-
-function finish() {
- window.parent.postMessage("DONE", "*");
-}
-
-var request;
-var connection;
-
-function testStartRequest() {
- return new Promise(function(aResolve, aReject) {
- ok(navigator.presentation, "navigator.presentation should be available.");
- request = new PresentationRequest("http://example1.com");
-
- request.start().then(
- function(aConnection) {
- connection = aConnection;
- ok(connection, "Connection should be available.");
- ok(connection.id, "Connection ID should be set.");
- is(connection.state, "connecting", "The initial state should be connecting.");
-
- connection.onclose = function() {
- connection.onclose = null;
- command({ name: "notify-connection-closed", id: connection.id });
- };
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, "connected", "Connection should be connected.");
- aResolve();
- };
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testCloseConnection() {
- return new Promise(function(aResolve, aReject) {
- if (connection.state === "closed") {
- aResolve();
- return;
- }
- connection.onclose = function() {
- connection.onclose = null;
- is(connection.state, "closed", "The connection should be closed.");
- aResolve();
- };
-
- connection.close();
- });
-}
-
-window.addEventListener("message", function onMessage(evt) {
- if (evt.data === "startConnection") {
- testStartRequest().then(
- function () {
- command({ name: "connection-connected", id: connection.id });
- }
- );
- }
- else if (evt.data === "closeConnection") {
- testCloseConnection().then(
- function () {
- command({ name: "connection-closed", id: connection.id });
- }
- );
- }
-}, false);
-
-</script>
-</head>
-<body>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_sandboxed_presentation.html b/dom/presentation/tests/mochitest/file_presentation_sandboxed_presentation.html
deleted file mode 100644
index 369621cee..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_sandboxed_presentation.html
+++ /dev/null
@@ -1,114 +0,0 @@
-
-<!DOCTYPE HTML>
-<html>
-<head>
-<meta charset="utf-8">
-<title>Test allow-presentation sandboxing flag</title>
-<script type="application/javascript;version=1.8">
-
-"use strict";
-
-function is(a, b, msg) {
- window.parent.postMessage((a === b ? "OK " : "KO ") + msg, "*");
-}
-
-function ok(a, msg) {
- window.parent.postMessage((a ? "OK " : "KO ") + msg, "*");
-}
-
-function info(msg) {
- window.parent.postMessage("INFO " + msg, "*");
-}
-
-function command(msg) {
- window.parent.postMessage("COMMAND " + JSON.stringify(msg), "*");
-}
-
-function finish() {
- window.parent.postMessage("DONE", "*");
-}
-
-function testGetAvailability() {
- return new Promise(function(aResolve, aReject) {
- ok(navigator.presentation, "navigator.presentation should be available.");
- var request = new PresentationRequest("http://example.com");
-
- request.getAvailability().then(
- function(aAvailability) {
- ok(false, "Unexpected success, should get a security error.");
- aReject();
- },
- function(aError) {
- is(aError.name, "SecurityError", "Should get a security error.");
- aResolve();
- }
- );
- });
-}
-
-function testStartRequest() {
- return new Promise(function(aResolve, aReject) {
- var request = new PresentationRequest("http://example.com");
-
- request.start().then(
- function(aAvailability) {
- ok(false, "Unexpected success, should get a security error.");
- aReject();
- },
- function(aError) {
- is(aError.name, "SecurityError", "Should get a security error.");
- aResolve();
- }
- );
- });
-}
-
-function testDefaultRequest() {
- return new Promise(function(aResolve, aReject) {
- navigator.presentation.defaultRequest = new PresentationRequest("http://example.com");
- is(navigator.presentation.defaultRequest, null, "DefaultRequest shoud be null.");
- aResolve();
- });
-}
-
-function testReconnectRequest() {
- return new Promise(function(aResolve, aReject) {
- var request = new PresentationRequest("http://example.com");
-
- request.reconnect("dummyId").then(
- function(aConnection) {
- ok(false, "Unexpected success, should get a security error.");
- aReject();
- },
- function(aError) {
- is(aError.name, "SecurityError", "Should get a security error.");
- aResolve();
- }
- );
- });
-}
-
-function runTest() {
- testGetAvailability()
- .then(testStartRequest)
- .then(testDefaultRequest)
- .then(testReconnectRequest)
- .then(finish);
-}
-
-window.addEventListener("message", function onMessage(evt) {
- window.removeEventListener("message", onMessage);
- if (evt.data === "start") {
- runTest();
- }
-}, false);
-
-window.setTimeout(function() {
- command("ready-to-start");
-}, 3000);
-
-</script>
-</head>
-<body>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_terminate.html b/dom/presentation/tests/mochitest/file_presentation_terminate.html
deleted file mode 100644
index a26a44b90..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_terminate.html
+++ /dev/null
@@ -1,104 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <head>
- <meta charset='utf-8'>
- <title>Test for B2G PresentationReceiver at receiver side</title>
- </head>
- <body>
- <div id='content'></div>
-<script type='application/javascript;version=1.7'>
-
-'use strict';
-
-function is(a, b, msg) {
- if (a === b) {
- alert('OK ' + msg);
- } else {
- alert('KO ' + msg + ' | reason: ' + a + ' != ' + b);
- }
-}
-
-function ok(a, msg) {
- alert((a ? 'OK ' : 'KO ') + msg);
-}
-
-function info(msg) {
- alert('INFO ' + msg);
-}
-
-function command(name, data) {
- alert('COMMAND ' + JSON.stringify({name: name, data: data}));
-}
-
-function finish() {
- alert('DONE');
-}
-
-var connection;
-
-function testConnectionAvailable() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testConnectionAvailable ---');
- ok(navigator.presentation, 'Receiver: navigator.presentation should be available.');
- ok(navigator.presentation.receiver, 'Receiver: navigator.presentation.receiver should be available.');
-
- navigator.presentation.receiver.connectionList
- .then((aList) => {
- is(aList.connections.length, 1, 'Should get one conncetion.');
- connection = aList.connections[0];
- ok(connection.id, 'Connection ID should be set: ' + connection.id);
- is(connection.state, 'connected', 'Connection state at receiver side should be connected.');
- aResolve();
- })
- .catch((aError) => {
- ok(false, 'Receiver: Error occurred when getting the connection: ' + aError);
- finish();
- aReject();
- });
- });
-}
-
-function testConnectionReady() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testConnectionReady ---');
- connection.onconnect = function() {
- connection.onconnect = null;
- ok(false, 'Should not get |onconnect| event.')
- aReject();
- };
- if (connection.state === 'connected') {
- connection.onconnect = null;
- is(connection.state, 'connected', 'Receiver: Connection state should become connected.');
- aResolve();
- }
- });
-}
-
-function testConnectionTerminate() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testConnectionTerminate ---');
- connection.onterminate = function() {
- connection.onterminate = null;
- // Using window.alert at this stage will cause window.close() fail.
- // Only trigger it if verdict fail.
- if (connection.state !== 'terminated') {
- is(connection.state, 'terminated', 'Receiver: Connection should be terminated.');
- }
- aResolve();
- };
- command('forward-command', JSON.stringify({ name: 'ready-to-terminate' }));
- });
-}
-
-function runTests() {
- testConnectionAvailable()
- .then(testConnectionReady)
- .then(testConnectionTerminate)
-}
-
-runTests();
-
-</script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_terminate_establish_connection_error.html b/dom/presentation/tests/mochitest/file_presentation_terminate_establish_connection_error.html
deleted file mode 100644
index d8df8a1a6..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_terminate_establish_connection_error.html
+++ /dev/null
@@ -1,114 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <head>
- <meta charset='utf-8'>
- <title>Test for B2G PresentationReceiver at receiver side</title>
- </head>
- <body>
- <div id='content'></div>
-<script type='application/javascript;version=1.7'>
-
-'use strict';
-
-function is(a, b, msg) {
- if (a === b) {
- alert('OK ' + msg);
- } else {
- alert('KO ' + msg + ' | reason: ' + a + ' != ' + b);
- }
-}
-
-function ok(a, msg) {
- alert((a ? 'OK ' : 'KO ') + msg);
-}
-
-function info(msg) {
- alert('INFO ' + msg);
-}
-
-function command(name, data) {
- alert('COMMAND ' + JSON.stringify({name: name, data: data}));
-}
-
-function finish() {
- alert('DONE');
-}
-
-var connection;
-
-function testConnectionAvailable() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testConnectionAvailable ---');
- ok(navigator.presentation, 'Receiver: navigator.presentation should be available.');
- ok(navigator.presentation.receiver, 'Receiver: navigator.presentation.receiver should be available.');
-
- navigator.presentation.receiver.connectionList
- .then((aList) => {
- is(aList.connections.length, 1, 'Should get one connection.');
- connection = aList.connections[0];
- ok(connection.id, 'Connection ID should be set: ' + connection.id);
- is(connection.state, 'connected', 'Connection state at receiver side should be connected.');
- aResolve();
- })
- .catch((aError) => {
- ok(false, 'Receiver: Error occurred when getting the connection: ' + aError);
- finish();
- aReject();
- });
- });
-}
-
-function testConnectionReady() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testConnectionReady ---');
- connection.onconnect = function() {
- connection.onconnect = null;
- ok(false, 'Should not get |onconnect| event.')
- aReject();
- };
- if (connection.state === 'connected') {
- connection.onconnect = null;
- is(connection.state, 'connected', 'Receiver: Connection state should become connected.');
- aResolve();
- }
- });
-}
-
-function testConnectionTerminate() {
- return new Promise(function(aResolve, aReject) {
- info('Receiver: --- testConnectionTerminate ---');
- connection.onterminate = function() {
- connection.onterminate = null;
- // Using window.alert at this stage will cause window.close() fail.
- // Only trigger it if verdict fail.
- if (connection.state !== 'terminated') {
- is(connection.state, 'terminated', 'Receiver: Connection should be terminated.');
- }
- aResolve();
- };
-
- window.addEventListener('hashchange', function hashchangeHandler(evt) {
- var message = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
- if (message.type === 'ready-to-terminate') {
- info('Receiver: --- ready-to-terminate ---');
- connection.terminate();
- }
- });
-
-
- command('forward-command', JSON.stringify({ name: 'prepare-for-terminate' }));
- });
-}
-
-function runTests() {
- testConnectionAvailable()
- .then(testConnectionReady)
- .then(testConnectionTerminate)
-}
-
-runTests();
-
-</script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/file_presentation_unknown_content_type.test b/dom/presentation/tests/mochitest/file_presentation_unknown_content_type.test
deleted file mode 100644
index 8b1378917..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_unknown_content_type.test
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/dom/presentation/tests/mochitest/file_presentation_unknown_content_type.test^headers^ b/dom/presentation/tests/mochitest/file_presentation_unknown_content_type.test^headers^
deleted file mode 100644
index fc044e3c4..000000000
--- a/dom/presentation/tests/mochitest/file_presentation_unknown_content_type.test^headers^
+++ /dev/null
@@ -1 +0,0 @@
-Content-Type: application/unknown
diff --git a/dom/presentation/tests/mochitest/mochitest.ini b/dom/presentation/tests/mochitest/mochitest.ini
deleted file mode 100644
index f96e07f1e..000000000
--- a/dom/presentation/tests/mochitest/mochitest.ini
+++ /dev/null
@@ -1,77 +0,0 @@
-[DEFAULT]
-support-files =
- PresentationDeviceInfoChromeScript.js
- PresentationSessionChromeScript.js
- PresentationSessionFrameScript.js
- PresentationSessionChromeScript1UA.js
- file_presentation_1ua_receiver.html
- test_presentation_1ua_sender_and_receiver.js
- file_presentation_non_receiver_inner_iframe.html
- file_presentation_non_receiver.html
- file_presentation_receiver.html
- file_presentation_receiver_establish_connection_error.html
- file_presentation_receiver_inner_iframe.html
- file_presentation_1ua_wentaway.html
- test_presentation_1ua_connection_wentaway.js
- file_presentation_receiver_auxiliary_navigation.html
- test_presentation_receiver_auxiliary_navigation.js
- file_presentation_sandboxed_presentation.html
- file_presentation_terminate.html
- test_presentation_terminate.js
- file_presentation_terminate_establish_connection_error.html
- test_presentation_terminate_establish_connection_error.js
- file_presentation_reconnect.html
- file_presentation_unknown_content_type.test
- file_presentation_unknown_content_type.test^headers^
- test_presentation_tcp_receiver_establish_connection_unknown_content_type.js
- file_presentation_mixed_security_contexts.html
-
-[test_presentation_dc_sender.html]
-[test_presentation_dc_receiver.html]
-skip-if = (e10s || toolkit == 'android') # Bug 1129785
-[test_presentation_dc_receiver_oop.html]
-skip-if = (e10s || toolkit == 'android') # Bug 1129785
-[test_presentation_1ua_sender_and_receiver_inproc.html]
-skip-if = (e10s || toolkit == 'android') # Bug 1129785
-[test_presentation_1ua_sender_and_receiver_oop.html]
-skip-if = (e10s || toolkit == 'android') # Bug 1129785
-[test_presentation_1ua_connection_wentaway_inproc.html]
-skip-if = (e10s || toolkit == 'android') # Bug 1129785
-[test_presentation_1ua_connection_wentaway_oop.html]
-skip-if = (e10s || toolkit == 'android') # Bug 1129785
-[test_presentation_device_info_permission.html]
-[test_presentation_tcp_sender_disconnect.html]
-skip-if = toolkit == 'android' # Bug 1129785
-[test_presentation_tcp_sender_establish_connection_error.html]
-skip-if = toolkit == 'android' # Bug 1129785
-[test_presentation_tcp_receiver_establish_connection_error.html]
-skip-if = (e10s || toolkit == 'android' || os == 'mac' || os == 'win') # Bug 1129785, Bug 1204709
-[test_presentation_tcp_receiver_establish_connection_timeout.html]
-skip-if = (e10s || toolkit == 'android') # Bug 1129785
-[test_presentation_tcp_receiver_establish_connection_unknown_content_type_inproc.html]
-skip-if = (e10s || toolkit == 'android')
-[test_presentation_tcp_receiver_establish_connection_unknown_content_type_oop.html]
-skip-if = (e10s || toolkit == 'android')
-[test_presentation_tcp_receiver.html]
-skip-if = (e10s || toolkit == 'android') # Bug 1129785
-[test_presentation_tcp_receiver_oop.html]
-skip-if = (e10s || toolkit == 'android') # Bug 1129785
-[test_presentation_receiver_auxiliary_navigation_inproc.html]
-skip-if = e10s
-[test_presentation_receiver_auxiliary_navigation_oop.html]
-skip-if = e10s
-[test_presentation_terminate_inproc.html]
-skip-if = (e10s || toolkit == 'android')
-[test_presentation_terminate_oop.html]
-skip-if = (e10s || toolkit == 'android')
-[test_presentation_terminate_establish_connection_error_inproc.html]
-skip-if = (e10s || toolkit == 'android')
-[test_presentation_terminate_establish_connection_error_oop.html]
-skip-if = (e10s || toolkit == 'android')
-[test_presentation_sender_on_terminate_request.html]
-skip-if = toolkit == 'android'
-[test_presentation_sandboxed_presentation.html]
-skip-if = true # bug 1315867
-[test_presentation_reconnect.html]
-[test_presentation_mixed_security_contexts.html]
-[test_presentation_availability.html]
diff --git a/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway.js b/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway.js
deleted file mode 100644
index dbeb4ffcc..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway.js
+++ /dev/null
@@ -1,175 +0,0 @@
-'use strict';
-
-SimpleTest.waitForExplicitFinish();
-SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event');
-
-function debug(str) {
- // info(str);
-}
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript1UA.js'));
-var receiverUrl = SimpleTest.getTestFileURL('file_presentation_1ua_wentaway.html');
-var request;
-var connection;
-var receiverIframe;
-
-function setup() {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- debug('Got message: device-prompt');
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- });
-
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established',
- controlChannelEstablishedHandler);
- gScript.sendAsyncMessage("trigger-control-channel-open");
- });
-
- gScript.addMessageListener('sender-launch', function senderLaunchHandler(url) {
- debug('Got message: sender-launch');
- gScript.removeMessageListener('sender-launch', senderLaunchHandler);
- is(url, receiverUrl, 'Receiver: should receive the same url');
- receiverIframe = document.createElement('iframe');
- receiverIframe.setAttribute("mozbrowser", "true");
- receiverIframe.setAttribute("mozpresentation", receiverUrl);
- var oop = location.pathname.indexOf('_inproc') == -1;
- receiverIframe.setAttribute("remote", oop);
-
- receiverIframe.setAttribute('src', receiverUrl);
- receiverIframe.addEventListener("mozbrowserloadend", function mozbrowserloadendHander() {
- receiverIframe.removeEventListener("mozbrowserloadend", mozbrowserloadendHander);
- info("Receiver loaded.");
- });
-
- // This event is triggered when the iframe calls "alert".
- receiverIframe.addEventListener("mozbrowsershowmodalprompt", function receiverListener(evt) {
- var message = evt.detail.message;
- if (/^OK /.exec(message)) {
- ok(true, message.replace(/^OK /, ""));
- } else if (/^KO /.exec(message)) {
- ok(false, message.replace(/^KO /, ""));
- } else if (/^INFO /.exec(message)) {
- info(message.replace(/^INFO /, ""));
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ""));
- gScript.sendAsyncMessage(command.name, command.data);
- } else if (/^DONE$/.exec(message)) {
- receiverIframe.removeEventListener("mozbrowsershowmodalprompt",
- receiverListener);
- teardown();
- }
- }, false);
-
- var promise = new Promise(function(aResolve, aReject) {
- document.body.appendChild(receiverIframe);
- aResolve(receiverIframe);
- });
-
- var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
- .getService(SpecialPowers.Ci.nsIObserverService);
- obs.notifyObservers(promise, 'setup-request-promise', null);
- });
-
- gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
- debug('Got message: promise-setup-ready');
- gScript.removeMessageListener('promise-setup-ready',
- promiseSetupReadyHandler);
- gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
- });
-
- return Promise.resolve();
-}
-
-function testCreateRequest() {
- return new Promise(function(aResolve, aReject) {
- info('Sender: --- testCreateRequest ---');
- request = new PresentationRequest(receiverUrl);
- request.getAvailability().then((aAvailability) => {
- is(aAvailability.value, false, "Sender: should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, "Sender: Device should be available.");
- aResolve();
- }
-
- gScript.sendAsyncMessage('trigger-device-add');
- }).catch((aError) => {
- ok(false, "Sender: Error occurred when getting availability: " + aError);
- teardown();
- aReject();
- });
- });
-}
-
-function testStartConnection() {
- return new Promise(function(aResolve, aReject) {
- request.start().then((aConnection) => {
- connection = aConnection;
- ok(connection, "Sender: Connection should be available.");
- ok(connection.id, "Sender: Connection ID should be set.");
- is(connection.state, "connecting", "Sender: The initial state should be connecting.");
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, "connected", "Connection should be connected.");
- aResolve();
- };
- }).catch((aError) => {
- ok(false, "Sender: Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- });
- });
-}
-
-function testConnectionWentaway() {
- return new Promise(function(aResolve, aReject) {
- info('Sender: --- testConnectionWentaway ---');
- connection.onclose = function() {
- connection.onclose = null;
- is(connection.state, "closed", "Sender: Connection should be closed.");
- receiverIframe.addEventListener('mozbrowserclose', function closeHandler() {
- ok(false, 'wentaway should not trigger receiver close');
- aResolve();
- });
- setTimeout(aResolve, 3000);
- };
- gScript.addMessageListener('ready-to-remove-receiverFrame', function onReadyToRemove() {
- gScript.removeMessageListener('ready-to-remove-receiverFrame', onReadyToRemove);
- receiverIframe.src = "http://example.com";
- });
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- debug('Got message: teardown-complete');
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- setup().then(testCreateRequest)
- .then(testStartConnection)
- .then(testConnectionWentaway)
- .then(teardown);
-}
-
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
- {type: "browser", allow: true, context: document},
-], () => {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.receiver.enabled", true],
- ["dom.presentation.test.enabled", true],
- ["dom.mozBrowserFramesEnabled", true],
- ["dom.ipc.tabs.disabled", false],
- ["network.disable.ipc.security", true],
- ["dom.presentation.test.stage", 0]]},
- runTests);
-});
diff --git a/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway_inproc.html b/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway_inproc.html
deleted file mode 100644
index 68491d81b..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway_inproc.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
- <head>
- <meta charset="utf-8">
- <title>Test for B2G Presentation API when sender and receiver at the same side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- </head>
- <body>
- <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1258600">
- Test for PresentationConnectionCloseEvent with wentaway reason</a>
- <script type="application/javascript;version=1.8" src="test_presentation_1ua_connection_wentaway.js">
- </script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway_oop.html b/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway_oop.html
deleted file mode 100644
index 68491d81b..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway_oop.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
- <head>
- <meta charset="utf-8">
- <title>Test for B2G Presentation API when sender and receiver at the same side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- </head>
- <body>
- <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1258600">
- Test for PresentationConnectionCloseEvent with wentaway reason</a>
- <script type="application/javascript;version=1.8" src="test_presentation_1ua_connection_wentaway.js">
- </script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js b/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js
deleted file mode 100644
index 8a7787b40..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js
+++ /dev/null
@@ -1,370 +0,0 @@
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
-* You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-'use strict';
-
-function debug(str) {
- // info(str);
-}
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript1UA.js'));
-var receiverUrl = SimpleTest.getTestFileURL('file_presentation_1ua_receiver.html');
-var request;
-var connection;
-var receiverIframe;
-var presentationId;
-const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0];
-const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length);
-const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER);
-TYPED_DATA_ARRAY.set(DATA_ARRAY);
-
-function postMessageToIframe(aType) {
- receiverIframe.src = receiverUrl + "#" +
- encodeURIComponent(JSON.stringify({ type: aType }));
-}
-
-function setup() {
-
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- debug('Got message: device-prompt');
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- });
-
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established',
- controlChannelEstablishedHandler);
- gScript.sendAsyncMessage("trigger-control-channel-open");
- });
-
- gScript.addMessageListener('sender-launch', function senderLaunchHandler(url) {
- debug('Got message: sender-launch');
- gScript.removeMessageListener('sender-launch', senderLaunchHandler);
- is(url, receiverUrl, 'Receiver: should receive the same url');
- receiverIframe = document.createElement('iframe');
- receiverIframe.setAttribute('src', receiverUrl);
- receiverIframe.setAttribute("mozbrowser", "true");
- receiverIframe.setAttribute("mozpresentation", receiverUrl);
- var oop = location.pathname.indexOf('_inproc') == -1;
- receiverIframe.setAttribute("remote", oop);
-
- // This event is triggered when the iframe calls "alert".
- receiverIframe.addEventListener("mozbrowsershowmodalprompt", function receiverListener(evt) {
- var message = evt.detail.message;
- debug('Got iframe message: ' + message);
- if (/^OK /.exec(message)) {
- ok(true, message.replace(/^OK /, ""));
- } else if (/^KO /.exec(message)) {
- ok(false, message.replace(/^KO /, ""));
- } else if (/^INFO /.exec(message)) {
- info(message.replace(/^INFO /, ""));
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ""));
- gScript.sendAsyncMessage(command.name, command.data);
- } else if (/^DONE$/.exec(message)) {
- receiverIframe.removeEventListener("mozbrowsershowmodalprompt",
- receiverListener);
- }
- }, false);
-
- var promise = new Promise(function(aResolve, aReject) {
- document.body.appendChild(receiverIframe);
- aResolve(receiverIframe);
- });
-
- var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
- .getService(SpecialPowers.Ci.nsIObserverService);
- obs.notifyObservers(promise, 'setup-request-promise', null);
- });
-
- gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
- debug('Got message: promise-setup-ready');
- gScript.removeMessageListener('promise-setup-ready', promiseSetupReadyHandler);
- gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
- });
-
- return Promise.resolve();
-}
-
-function testCreateRequest() {
- return new Promise(function(aResolve, aReject) {
- info('Sender: --- testCreateRequest ---');
- request = new PresentationRequest("file_presentation_1ua_receiver.html");
- request.getAvailability().then((aAvailability) => {
- is(aAvailability.value, false, "Sender: should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, "Sender: Device should be available.");
- aResolve();
- }
-
- gScript.sendAsyncMessage('trigger-device-add');
- }).catch((aError) => {
- ok(false, "Sender: Error occurred when getting availability: " + aError);
- teardown();
- aReject();
- });
- });
-}
-
-function testStartConnection() {
- return new Promise(function(aResolve, aReject) {
- request.start().then((aConnection) => {
- connection = aConnection;
- ok(connection, "Sender: Connection should be available.");
- ok(connection.id, "Sender: Connection ID should be set.");
- is(connection.state, "connecting", "The initial state should be connecting.");
- is(connection.url, receiverUrl, "request URL should be expanded to absolute URL");
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, "connected", "Connection should be connected.");
- presentationId = connection.id;
- aResolve();
- };
- }).catch((aError) => {
- ok(false, "Sender: Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- });
-
- let request2 = new PresentationRequest("/");
- request2.start().then(() => {
- ok(false, "Sender: session start should fail while there is an unsettled promise.");
- }).catch((aError) => {
- is(aError.name, "OperationError", "Expect to get OperationError.");
- });
- });
-}
-
-function testSendMessage() {
- return new Promise(function(aResolve, aReject) {
- info('Sender: --- testSendMessage ---');
- gScript.addMessageListener('trigger-message-from-sender', function triggerMessageFromSenderHandler() {
- debug('Got message: trigger-message-from-sender');
- gScript.removeMessageListener('trigger-message-from-sender', triggerMessageFromSenderHandler);
- info('Send message to receiver');
- connection.send('msg-sender-to-receiver');
- });
-
- gScript.addMessageListener('message-from-sender-received', function messageFromSenderReceivedHandler() {
- debug('Got message: message-from-sender-received');
- gScript.removeMessageListener('message-from-sender-received', messageFromSenderReceivedHandler);
- aResolve();
- });
- });
-}
-
-function testIncomingMessage() {
- return new Promise(function(aResolve, aReject) {
- info('Sender: --- testIncomingMessage ---');
- connection.addEventListener('message', function messageHandler(evt) {
- connection.removeEventListener('message', messageHandler);
- let msg = evt.data;
- is(msg, "msg-receiver-to-sender", "Sender: Sender should receive message from Receiver");
- postMessageToIframe('message-from-receiver-received');
- aResolve();
- });
- postMessageToIframe('trigger-message-from-receiver');
- });
-}
-
-function testSendBlobMessage() {
- return new Promise(function(aResolve, aReject) {
- info('Sender: --- testSendBlobMessage ---');
- connection.addEventListener('message', function messageHandler(evt) {
- connection.removeEventListener('message', messageHandler);
- let msg = evt.data;
- is(msg, "testIncomingBlobMessage", "Sender: Sender should receive message from Receiver");
- let blob = new Blob(["Hello World"], {type : 'text/plain'});
- connection.send(blob);
- aResolve();
- });
- });
-}
-
-function testSendArrayBuffer() {
- return new Promise(function(aResolve, aReject) {
- info('Sender: --- testSendArrayBuffer ---');
- connection.addEventListener('message', function messageHandler(evt) {
- connection.removeEventListener('message', messageHandler);
- let msg = evt.data;
- is(msg, "testIncomingArrayBuffer", "Sender: Sender should receive message from Receiver");
- connection.send(DATA_ARRAY_BUFFER);
- aResolve();
- });
- });
-}
-
-function testSendArrayBufferView() {
- return new Promise(function(aResolve, aReject) {
- info('Sender: --- testSendArrayBufferView ---');
- connection.addEventListener('message', function messageHandler(evt) {
- connection.removeEventListener('message', messageHandler);
- let msg = evt.data;
- is(msg, "testIncomingArrayBufferView", "Sender: Sender should receive message from Receiver");
- connection.send(TYPED_DATA_ARRAY);
- aResolve();
- });
- });
-}
-
-function testCloseConnection() {
- info('Sender: --- testCloseConnection ---');
- // Test terminate immediate after close.
- function controlChannelEstablishedHandler()
- {
- gScript.removeMessageListener('control-channel-established',
- controlChannelEstablishedHandler);
- ok(false, "terminate after close should do nothing");
- }
- gScript.addMessageListener('ready-to-close', function onReadyToClose() {
- gScript.removeMessageListener('ready-to-close', onReadyToClose);
- connection.close();
-
- gScript.addMessageListener('control-channel-established', controlChannelEstablishedHandler);
- connection.terminate();
- });
-
- return Promise.all([
- new Promise(function(aResolve, aReject) {
- connection.onclose = function() {
- connection.onclose = null;
- is(connection.state, 'closed', 'Sender: Connection should be closed.');
- gScript.removeMessageListener('control-channel-established',
- controlChannelEstablishedHandler);
- aResolve();
- };
- }),
- new Promise(function(aResolve, aReject) {
- let timeout = setTimeout(function() {
- gScript.removeMessageListener('device-disconnected',
- deviceDisconnectedHandler);
- ok(true, "terminate after close should not trigger device.disconnect");
- aResolve();
- }, 3000);
-
- function deviceDisconnectedHandler() {
- gScript.removeMessageListener('device-disconnected',
- deviceDisconnectedHandler);
- ok(false, "terminate after close should not trigger device.disconnect");
- clearTimeout(timeout);
- aResolve();
- }
-
- gScript.addMessageListener('device-disconnected', deviceDisconnectedHandler);
- }),
- new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('receiver-closed', function onReceiverClosed() {
- gScript.removeMessageListener('receiver-closed', onReceiverClosed);
- gScript.removeMessageListener('control-channel-established',
- controlChannelEstablishedHandler);
- aResolve();
- });
- }),
- ]);
-}
-
-function testTerminateAfterClose() {
- info('Sender: --- testTerminateAfterClose ---');
- return Promise.race([
- new Promise(function(aResolve, aReject) {
- connection.onterminate = function() {
- connection.onterminate = null;
- ok(false, 'terminate after close should do nothing');
- aResolve();
- };
- connection.terminate();
- }),
- new Promise(function(aResolve, aReject) {
- setTimeout(function() {
- is(connection.state, 'closed', 'Sender: Connection should be closed.');
- aResolve();
- }, 3000);
- }),
- ]);
-}
-
-function testReconnect() {
- return new Promise(function(aResolve, aReject) {
- info('Sender: --- testReconnect ---');
- gScript.addMessageListener('control-channel-established', function controlChannelEstablished() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablished);
- gScript.sendAsyncMessage("trigger-control-channel-open");
- });
-
- gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) {
- debug('Got message: start-reconnect');
- gScript.removeMessageListener('start-reconnect', startReconnectHandler);
- is(url, receiverUrl, "URLs should be the same.")
- gScript.sendAsyncMessage('trigger-reconnected-acked', url);
- });
-
- gScript.addMessageListener('ready-to-reconnect', function onReadyToReconnect() {
- gScript.removeMessageListener('ready-to-reconnect', onReadyToReconnect);
- request.reconnect(presentationId).then((aConnection) => {
- connection = aConnection;
- ok(connection, "Sender: Connection should be available.");
- is(connection.id, presentationId, "The presentationId should be the same.");
- is(connection.state, "connecting", "The initial state should be connecting.");
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, "connected", "Connection should be connected.");
- aResolve();
- };
- }).catch((aError) => {
- ok(false, "Sender: Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- });
- });
-
- postMessageToIframe('prepare-for-reconnect');
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- debug('Got message: teardown-complete');
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- setup().then(testCreateRequest)
- .then(testStartConnection)
- .then(testSendMessage)
- .then(testIncomingMessage)
- .then(testSendBlobMessage)
- .then(testCloseConnection)
- .then(testReconnect)
- .then(testSendArrayBuffer)
- .then(testSendArrayBufferView)
- .then(testCloseConnection)
- .then(testTerminateAfterClose)
- .then(teardown);
-}
-
-SimpleTest.waitForExplicitFinish();
-SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event');
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
- {type: "browser", allow: true, context: document},
-], () => {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- /* Mocked TCP session transport builder in the test */
- ["dom.presentation.session_transport.data_channel.enable", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.receiver.enabled", true],
- ["dom.presentation.test.enabled", true],
- ["dom.presentation.test.stage", 0],
- ["dom.mozBrowserFramesEnabled", true],
- ["network.disable.ipc.security", true],
- ["media.navigator.permission.disabled", true]]},
- runTests);
-});
diff --git a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_inproc.html b/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_inproc.html
deleted file mode 100644
index 520b1a98c..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_inproc.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
- <head>
- <meta charset="utf-8">
- <title>Test for B2G Presentation API when sender and receiver at the same side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- </head>
- <body>
- <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1234492">
- Test for B2G Presentation API when sender and receiver at the same side</a>
- <script type="application/javascript;version=1.8" src="test_presentation_1ua_sender_and_receiver.js">
- </script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_oop.html b/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_oop.html
deleted file mode 100644
index e744e6802..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_oop.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
- <head>
- <meta charset="utf-8">
- <title>Test for B2G Presentation API when sender and receiver at the same side (OOP ver.)</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- </head>
- <body>
- <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1234492">
- Test for B2G Presentation API when sender and receiver at the same side (OOP ver.)</a>
- <script type="application/javascript;version=1.8" src="test_presentation_1ua_sender_and_receiver.js">
- </script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_availability.html b/dom/presentation/tests/mochitest/test_presentation_availability.html
deleted file mode 100644
index 89f1ad1b7..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_availability.html
+++ /dev/null
@@ -1,236 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for PresentationAvailability</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1228508">Test PresentationAvailability</a>
-<script type="application/javascript;version=1.8">
-
-"use strict";
-
-var testDevice = {
- id: 'id',
- name: 'name',
- type: 'type',
-};
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationDeviceInfoChromeScript.js'));
-var request;
-var availability;
-
-function testSetup() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('setup-complete', function() {
- aResolve();
- });
- gScript.sendAsyncMessage('setup');
- });
-}
-
-function testInitialUnavailable() {
- request = new PresentationRequest("https://example.com");
-
- return request.getAvailability().then(function(aAvailability) {
- is(aAvailability.value, false, "Should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, "Device should be available.");
- }
- availability = aAvailability;
- gScript.sendAsyncMessage('trigger-device-add', testDevice);
- }).catch(function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- teardown();
- });
-}
-
-function testInitialAvailable() {
- let anotherRequest = new PresentationRequest("https://example.net");
- return anotherRequest.getAvailability().then(function(aAvailability) {
- is(aAvailability.value, true, "Should have available device initially");
- isnot(aAvailability, availability, "Should get different availability object for different request URL");
- }).catch(function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- teardown();
- });
-}
-
-function testSameObject() {
- let sameUrlRequest = new PresentationRequest("https://example.com");
- return sameUrlRequest.getAvailability().then(function(aAvailability) {
- is(aAvailability, availability, "Should get same availability object for same request URL");
- }).catch(function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- teardown();
- });
-}
-
-function testOnChangeEvent() {
- return new Promise(function(aResolve, aReject) {
- availability.onchange = function() {
- availability.onchange = null;
- is(availability.value, false, "Should have no available device after device removed");
- aResolve();
- }
- gScript.sendAsyncMessage('trigger-device-remove');
- });
-}
-
-function testConsecutiveGetAvailability() {
- let request = new PresentationRequest("https://example.org");
- let firstAvailabilityResolved = false;
- return Promise.all([
- request.getAvailability().then(function() {
- firstAvailabilityResolved = true;
- }),
- request.getAvailability().then(function() {
- ok(firstAvailabilityResolved, "getAvailability() should be resolved in sequence");
- })
- ]).catch(function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- teardown();
- });
-}
-
-function testUnsupportedDeviceAvailability() {
- return Promise.race([
- new Promise(function(aResolve, aReject) {
- let request = new PresentationRequest("https://test.com");
- request.getAvailability().then(function(aAvailability) {
- availability = aAvailability;
- aAvailability.onchange = function() {
- availability.onchange = null;
- ok(false, "Should not get onchange event.");
- teardown();
- }
- });
- gScript.sendAsyncMessage('trigger-add-unsupport-url-device');
- }),
- new Promise(function(aResolve, aReject) {
- setTimeout(function() {
- ok(true, "Should not get onchange event.");
- availability.onchange = null;
- gScript.sendAsyncMessage('trigger-remove-unsupported-device');
- aResolve();
- }, 3000);
- }),
- ]);
-}
-
-function testMultipleAvailabilityURLs() {
- let request1 = new PresentationRequest(["https://example.com",
- "https://example1.com"]);
- let request2 = new PresentationRequest(["https://example1.com",
- "https://example2.com"]);
- return Promise.all([
- request1.getAvailability().then(function(aAvailability) {
- return new Promise(function(aResolve) {
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(true, "Should get onchange event.");
- aResolve();
- };
- });
- }),
- request2.getAvailability().then(function(aAvailability) {
- return new Promise(function(aResolve) {
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(true, "Should get onchange event.");
- aResolve();
- };
- });
- }),
- new Promise(function(aResolve) {
- gScript.sendAsyncMessage('trigger-add-multiple-devices');
- aResolve();
- }),
- ]).then(new Promise(function(aResolve) {
- gScript.sendAsyncMessage('trigger-remove-multiple-devices');
- aResolve();
- }));
-}
-
-function testPartialSupportedDeviceAvailability() {
- let request1 = new PresentationRequest(["https://supportedUrl.com"]);
- let request2 = new PresentationRequest(["http://notSupportedUrl.com"]);
-
- return Promise.all([
- request1.getAvailability().then(function(aAvailability) {
- return new Promise(function(aResolve) {
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(true, "Should get onchange event.");
- aResolve();
- };
- });
- }),
- Promise.race([
- request2.getAvailability().then(function(aAvailability) {
- return new Promise(function(aResolve) {
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(false, "Should get onchange event.");
- aResolve();
- };
- });
- }),
- new Promise(function(aResolve) {
- setTimeout(function() {
- ok(true, "Should not get onchange event.");
- availability.onchange = null;
- aResolve();
- }, 3000);
- }),
- ]),
- new Promise(function(aResolve) {
- gScript.sendAsyncMessage('trigger-add-https-devices');
- aResolve();
- }),
- ]).then(new Promise(function(aResolve) {
- gScript.sendAsyncMessage('trigger-remove-https-devices');
- aResolve();
- }));
-}
-
-function teardown() {
- request = null;
- availability = null;
- gScript.sendAsyncMessage('teardown');
- gScript.destroy();
- SimpleTest.finish();
-}
-
-function runTests() {
- ok(navigator.presentation, "navigator.presentation should be available.");
- testSetup().then(testInitialUnavailable)
- .then(testInitialAvailable)
- .then(testSameObject)
- .then(testOnChangeEvent)
- .then(testConsecutiveGetAvailability)
- .then(testMultipleAvailabilityURLs)
- .then(testUnsupportedDeviceAvailability)
- .then(testPartialSupportedDeviceAvailability)
- .then(teardown);
-}
-
-SimpleTest.waitForExplicitFinish();
-SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event');
-SpecialPowers.pushPermissions([
- {type: "presentation-device-manage", allow: false, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ "set": [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", false]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_datachannel_sessiontransport.html b/dom/presentation/tests/mochitest/test_presentation_datachannel_sessiontransport.html
deleted file mode 100644
index 89a51afb7..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_datachannel_sessiontransport.html
+++ /dev/null
@@ -1,245 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for data channel as session transport in Presentation API</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>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1148307">Test for data channel as session transport in Presentation API</a>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
-"use strict";
-
-SimpleTest.waitForExplicitFinish();
-
-const loadingTimeoutPref = "presentation.receiver.loading.timeout";
-
-var clientBuilder;
-var serverBuilder;
-var clientTransport;
-var serverTransport;
-
-const clientMessage = "Client Message";
-const serverMessage = "Server Message";
-
-const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-const { Services } = Cu.import("resource://gre/modules/Services.jsm");
-
-var isClientReady = false;
-var isServerReady = false;
-var isClientClosed = false;
-var isServerClosed = false;
-
-var gResolve;
-var gReject;
-
-const clientCallback = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
- notifyTransportReady: function () {
- info("Client transport ready.");
-
- isClientReady = true;
- if (isClientReady && isServerReady) {
- gResolve();
- }
- },
- notifyTransportClosed: function (aReason) {
- info("Client transport is closed.");
-
- isClientClosed = true;
- if (isClientClosed && isServerClosed) {
- gResolve();
- }
- },
- notifyData: function(aData) {
- is(aData, serverMessage, "Client transport receives data.");
- gResolve();
- },
-};
-
-const serverCallback = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
- notifyTransportReady: function () {
- info("Server transport ready.");
-
- isServerReady = true;
- if (isClientReady && isServerReady) {
- gResolve();
- }
- },
- notifyTransportClosed: function (aReason) {
- info("Server transport is closed.");
-
- isServerClosed = true;
- if (isClientClosed && isServerClosed) {
- gResolve();
- }
- },
- notifyData: function(aData) {
- is(aData, clientMessage, "Server transport receives data.");
- gResolve()
- },
-};
-
-const clientListener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
- onSessionTransport: function(aTransport) {
- info("Client Transport is built.");
- clientTransport = aTransport;
- clientTransport.callback = clientCallback;
- },
- onError: function(aError) {
- ok(false, "client's builder reports error " + aError);
- },
- sendOffer: function(aOffer) {
- setTimeout(()=>this._remoteBuilder.onOffer(aOffer), 0);
- },
- sendAnswer: function(aAnswer) {
- setTimeout(()=>this._remoteBuilder.onAnswer(aAnswer), 0);
- },
- sendIceCandidate: function(aCandidate) {
- setTimeout(()=>this._remoteBuilder.onIceCandidate(aCandidate), 0);
- },
- disconnect: function(aReason) {
- setTimeout(()=>this._localBuilder.notifyDisconnected(aReason), 0);
- setTimeout(()=>this._remoteBuilder.notifyDisconnected(aReason), 0);
- },
- set remoteBuilder(aRemoteBuilder) {
- this._remoteBuilder = aRemoteBuilder;
- },
- set localBuilder(aLocalBuilder) {
- this._localBuilder = aLocalBuilder;
- },
-}
-
-const serverListener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
- onSessionTransport: function(aTransport) {
- info("Server Transport is built.");
- serverTransport = aTransport;
- serverTransport.callback = serverCallback;
- serverTransport.enableDataNotification();
- },
- onError: function(aError) {
- ok(false, "server's builder reports error " + aError);
- },
- sendOffer: function(aOffer) {
- setTimeout(()=>this._remoteBuilder.onOffer(aOffer), 0);
- },
- sendAnswer: function(aAnswer) {
- setTimeout(()=>this._remoteBuilder.onAnswer(aAnswer), 0);
- },
- sendIceCandidate: function(aCandidate) {
- setTimeout(()=>this._remoteBuilder.onIceCandidate(aCandidate), 0);
- },
- disconnect: function(aReason) {
- setTimeout(()=>this._localBuilder.notifyDisconnected(aReason), 0);
- setTimeout(()=>this._remoteBuilder.notifyDisconnected(aReason), 0);
- },
- set remoteBuilder(aRemoteBuilder) {
- this._remoteBuilder = aRemoteBuilder;
- },
- set localBuilder(aLocalBuilder) {
- this._localBuilder = aLocalBuilder;
- },
-}
-
-function testBuilder() {
- return new Promise(function(aResolve, aReject) {
- gResolve = aResolve;
- gReject = aReject;
-
- clientBuilder = Cc["@mozilla.org/presentation/datachanneltransportbuilder;1"]
- .createInstance(Ci.nsIPresentationDataChannelSessionTransportBuilder);
- serverBuilder = Cc["@mozilla.org/presentation/datachanneltransportbuilder;1"]
- .createInstance(Ci.nsIPresentationDataChannelSessionTransportBuilder);
-
- clientListener.localBuilder = clientBuilder;
- clientListener.remoteBuilder = serverBuilder;
- serverListener.localBuilder = serverBuilder;
- serverListener.remoteBuilder = clientBuilder;
-
- clientBuilder
- .buildDataChannelTransport(Ci.nsIPresentationService.ROLE_CONTROLLER,
- window,
- clientListener);
-
- serverBuilder
- .buildDataChannelTransport(Ci.nsIPresentationService.ROLE_RECEIVER,
- window,
- serverListener);
- });
-}
-
-function testClientSendMessage() {
- return new Promise(function(aResolve, aReject) {
- info("client sends message");
- gResolve = aResolve;
- gReject = aReject;
-
- clientTransport.send(clientMessage);
- });
-}
-
-function testServerSendMessage() {
- return new Promise(function(aResolve, aReject) {
- info("server sends message");
- gResolve = aResolve;
- gReject = aReject;
-
- serverTransport.send(serverMessage);
- setTimeout(()=>clientTransport.enableDataNotification(), 0);
- });
-}
-
-function testCloseSessionTransport() {
- return new Promise(function(aResolve, aReject) {
- info("close session transport");
- gResolve = aResolve;
- gReject = aReject;
-
- serverTransport.close(Cr.NS_OK);
- });
-}
-
-function finish() {
- info("test finished, teardown");
- Services.prefs.clearUserPref(loadingTimeoutPref);
-
- SimpleTest.finish();
-}
-
-function error(aError) {
- ok(false, "report Error " + aError.name + ":" + aError.message);
- gReject();
-}
-
-function runTests() {
- Services.prefs.setIntPref(loadingTimeoutPref, 30000);
-
- testBuilder()
- .then(testClientSendMessage)
- .then(testServerSendMessage)
- .then(testCloseSessionTransport)
- .then(finish)
- .catch(error);
-
-}
-
-window.addEventListener("load", function() {
- runTests();
-});
-
-</script>
-</pre>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_dc_receiver.html b/dom/presentation/tests/mochitest/test_presentation_dc_receiver.html
deleted file mode 100644
index a42489bdb..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_dc_receiver.html
+++ /dev/null
@@ -1,141 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for B2G PresentationConnection API at receiver side</title>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1148307">Test for B2G PresentationConnection API at receiver side</a>
-<p id="display"></p>
-<div id="content" style="display: none"></div>
-<pre id="test"></pre>
-<script type="application/javascript">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver.html');
-
-var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
- .getService(SpecialPowers.Ci.nsIObserverService);
-
-function setup() {
- return new Promise(function(aResolve, aReject) {
- gScript.sendAsyncMessage('trigger-device-add');
-
- var iframe = document.createElement('iframe');
- iframe.setAttribute('src', receiverUrl);
- iframe.setAttribute("mozbrowser", "true");
- iframe.setAttribute("mozpresentation", receiverUrl);
-
- // This event is triggered when the iframe calls "alert".
- iframe.addEventListener("mozbrowsershowmodalprompt", function receiverListener(evt) {
- var message = evt.detail.message;
- if (/^OK /.exec(message)) {
- ok(true, message.replace(/^OK /, ""));
- } else if (/^KO /.exec(message)) {
- ok(false, message.replace(/^KO /, ""));
- } else if (/^INFO /.exec(message)) {
- info(message.replace(/^INFO /, ""));
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ""));
- gScript.sendAsyncMessage(command.name, command.data);
- } else if (/^DONE$/.exec(message)) {
- iframe.removeEventListener("mozbrowsershowmodalprompt",
- receiverListener);
- teardown();
- }
- }, false);
-
- var promise = new Promise(function(aResolve, aReject) {
- document.body.appendChild(iframe);
-
- aResolve(iframe);
- });
- obs.notifyObservers(promise, 'setup-request-promise', null);
-
- gScript.addMessageListener('offer-received', function offerReceivedHandler() {
- gScript.removeMessageListener('offer-received', offerReceivedHandler);
- info("An offer is received.");
- });
-
- gScript.addMessageListener('answer-sent', function answerSentHandler(aIsValid) {
- gScript.removeMessageListener('answer-sent', answerSentHandler);
- ok(aIsValid, "A valid answer is sent.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed normally.");
- });
-
- gScript.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
- gScript.removeMessageListener('check-navigator', checknavigatorHandler);
- ok(aSuccess, "buildDataChannel get correct window object");
- });
-
- gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
- gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
- info("Data notification is enabled for data transport channel.");
- });
-
- gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- is(aReason, SpecialPowers.Cr.NS_OK, "The data transport should be closed normally.");
- });
-
- aResolve();
- });
-}
-
-function testIncomingSessionRequest() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
- gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
- info("Trying to launch receiver page.");
-
- ok(navigator.presentation, "navigator.presentation should be available in in-process pages.");
- is(navigator.presentation.receiver, null, "Non-receiving in-process pages shouldn't get a presentation receiver instance.");
- aResolve();
- });
-
- gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- setup().
- then(testIncomingSessionRequest);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
- {type: "browser", allow: true, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", false],
- ["dom.presentation.receiver.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", true],
- ["dom.mozBrowserFramesEnabled", true],
- ["network.disable.ipc.security", true]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_dc_receiver_oop.html b/dom/presentation/tests/mochitest/test_presentation_dc_receiver_oop.html
deleted file mode 100644
index b289b0be6..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_dc_receiver_oop.html
+++ /dev/null
@@ -1,213 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for B2G PresentationConnection API at receiver side (OOP)</title>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="PresentationSessionFrameScript.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1148307">Test B2G PresentationConnection API at receiver side (OOP)</a>
-<p id="display"></p>
-<div id="content" style="display: none"></div>
-<pre id="test"></pre>
-<script type="application/javascript">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver.html');
-var nonReceiverUrl = SimpleTest.getTestFileURL('file_presentation_non_receiver.html');
-
-var isReceiverFinished = false;
-var isNonReceiverFinished = false;
-
-var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
- .getService(SpecialPowers.Ci.nsIObserverService);
-var receiverIframe;
-
-function setup() {
- return new Promise(function(aResolve, aReject) {
- gScript.sendAsyncMessage('trigger-device-add');
-
- // Create a receiver OOP iframe.
- receiverIframe = document.createElement('iframe');
- receiverIframe.setAttribute('remote', 'true');
- receiverIframe.setAttribute('mozbrowser', 'true');
- receiverIframe.setAttribute('mozpresentation', receiverUrl);
- receiverIframe.setAttribute('src', receiverUrl);
-
- // This event is triggered when the iframe calls "alert".
- receiverIframe.addEventListener('mozbrowsershowmodalprompt', function receiverListener(aEvent) {
- var message = aEvent.detail.message;
- if (/^OK /.exec(message)) {
- ok(true, "Message from iframe: " + message);
- } else if (/^KO /.exec(message)) {
- ok(false, "Message from iframe: " + message);
- } else if (/^INFO /.exec(message)) {
- info("Message from iframe: " + message);
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ''));
- if (command.name == "trigger-incoming-message") {
- var mm = SpecialPowers.getBrowserFrameMessageManager(receiverIframe);
- mm.sendAsyncMessage('trigger-incoming-message', {"data": command.data});
- } else {
- gScript.sendAsyncMessage(command.name, command.data);
- }
- } else if (/^DONE$/.exec(message)) {
- ok(true, "Messaging from iframe complete.");
- receiverIframe.removeEventListener('mozbrowsershowmodalprompt', receiverListener);
-
- isReceiverFinished = true;
-
- if (isNonReceiverFinished) {
- teardown();
- }
- }
- }, false);
-
- var promise = new Promise(function(aResolve, aReject) {
- document.body.appendChild(receiverIframe);
- receiverIframe.addEventListener("mozbrowserloadstart", function onLoadEnd() {
- receiverIframe.removeEventListener("mozbrowserloadstart", onLoadEnd);
- var mm = SpecialPowers.getBrowserFrameMessageManager(receiverIframe);
- mm.loadFrameScript("data:,(" + loadPrivilegedScriptTest.toString() + ")();", false);
- });
-
- aResolve(receiverIframe);
- });
- obs.notifyObservers(promise, 'setup-request-promise', null);
-
- // Create a non-receiver OOP iframe.
- var nonReceiverIframe = document.createElement('iframe');
- nonReceiverIframe.setAttribute('remote', 'true');
- nonReceiverIframe.setAttribute('mozbrowser', 'true');
- nonReceiverIframe.setAttribute('src', nonReceiverUrl);
-
- // This event is triggered when the iframe calls "alert".
- nonReceiverIframe.addEventListener('mozbrowsershowmodalprompt', function nonReceiverListener(aEvent) {
- var message = aEvent.detail.message;
- if (/^OK /.exec(message)) {
- ok(true, "Message from iframe: " + message);
- } else if (/^KO /.exec(message)) {
- ok(false, "Message from iframe: " + message);
- } else if (/^INFO /.exec(message)) {
- info("Message from iframe: " + message);
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ''));
- gScript.sendAsyncMessage(command.name, command.data);
- } else if (/^DONE$/.exec(message)) {
- ok(true, "Messaging from iframe complete.");
- nonReceiverIframe.removeEventListener('mozbrowsershowmodalprompt', nonReceiverListener);
-
- isNonReceiverFinished = true;
-
- if (isReceiverFinished) {
- teardown();
- }
- }
- }, false);
-
- document.body.appendChild(nonReceiverIframe);
-
- gScript.addMessageListener('offer-received', function offerReceivedHandler() {
- gScript.removeMessageListener('offer-received', offerReceivedHandler);
- info("An offer is received.");
- });
-
- gScript.addMessageListener('answer-sent', function answerSentHandler(aIsValid) {
- gScript.removeMessageListener('answer-sent', answerSentHandler);
- ok(aIsValid, "A valid answer is sent.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed normally.");
- });
-
- var mm = SpecialPowers.getBrowserFrameMessageManager(receiverIframe);
- mm.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
- mm.removeMessageListener('check-navigator', checknavigatorHandler);
- ok(aSuccess.data.data, "buildDataChannel get correct window object");
- });
-
- mm.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
- mm.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
- info("Data notification is enabled for data transport channel.");
- });
-
- mm.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- mm.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- is(aReason.data.data, SpecialPowers.Cr.NS_OK, "The data transport should be closed normally.");
- });
-
- aResolve();
- });
-}
-
-function testIncomingSessionRequest() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
- gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
- info("Trying to launch receiver page.");
-
- aResolve();
- });
-
- gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
- });
-}
-
-var mmTeardownComplete = false;
-var gScriptTeardownComplete = false;
-function teardown() {
- var mm = SpecialPowers.getBrowserFrameMessageManager(receiverIframe);
- mm.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- mm.removeMessageListener('teardown-complete', teardownCompleteHandler);
- mmTeardownComplete = true;
- if (gScriptTeardownComplete) {
- SimpleTest.finish();
- }
- });
-
- mm.sendAsyncMessage('teardown');
-
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- gScriptTeardownComplete = true;
- if (mmTeardownComplete) {
- SimpleTest.finish();
- }
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- setup().
- then(testIncomingSessionRequest);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
- {type: 'browser', allow: true, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", false],
- ["dom.presentation.receiver.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", true],
- ["dom.mozBrowserFramesEnabled", true],
- ["network.disable.ipc.security", true],
- ["dom.ipc.browser_frames.oop_by_default", true],
- ["presentation.receiver.loading.timeout", 5000000]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_dc_sender.html b/dom/presentation/tests/mochitest/test_presentation_dc_sender.html
deleted file mode 100644
index 97e252e84..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_dc_sender.html
+++ /dev/null
@@ -1,291 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for B2G Presentation API at sender side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="PresentationSessionFrameScript.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1148307">Test for B2G Presentation API at sender side</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var frameScript = SpecialPowers.isMainProcess() ? gScript : contentScript;
-var request;
-var connection;
-
-function testSetup() {
- return new Promise(function(aResolve, aReject) {
- request = new PresentationRequest("http://example.com/");
-
- request.getAvailability().then(
- function(aAvailability) {
- is(aAvailability.value, false, "Sender: should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, "Device should be available.");
- aResolve();
- }
-
- gScript.sendAsyncMessage('trigger-device-add');
- },
- function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testStartConnection() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- });
-
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
- info("A control channel is established.");
- gScript.sendAsyncMessage('trigger-control-channel-open');
- });
-
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
- gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
- info("The control channel is opened.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- info("The control channel is closed. " + aReason);
- });
-
- frameScript.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
- frameScript.removeMessageListener('check-navigator', checknavigatorHandler);
- ok(aSuccess, "buildDataChannel get correct window object");
- });
-
- gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- ok(aIsValid, "A valid offer is sent out.");
- gScript.sendAsyncMessage('trigger-incoming-answer');
- });
-
- gScript.addMessageListener('answer-received', function answerReceivedHandler() {
- gScript.removeMessageListener('answer-received', answerReceivedHandler);
- info("An answer is received.");
- });
-
- frameScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
- frameScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
- info("Data transport channel is initialized.");
- });
-
- frameScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
- frameScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
- info("Data notification is enabled for data transport channel.");
- });
-
- var connectionFromEvent;
- request.onconnectionavailable = function(aEvent) {
- request.onconnectionavailable = null;
- connectionFromEvent = aEvent.connection;
- ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
-
- if (connection) {
- is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
- }
- };
-
- request.start().then(
- function(aConnection) {
- connection = aConnection;
- ok(connection, "Connection should be available.");
- ok(connection.id, "Connection ID should be set.");
- is(connection.state, "connecting", "The initial state should be connecting.");
-
- if (connectionFromEvent) {
- is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
- }
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, "connected", "Connection should be connected.");
- aResolve();
- };
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testSend() {
- return new Promise(function(aResolve, aReject) {
- const outgoingMessage = "test outgoing message";
-
- frameScript.addMessageListener('message-sent', function messageSentHandler(aMessage) {
- frameScript.removeMessageListener('message-sent', messageSentHandler);
- is(aMessage, outgoingMessage, "The message is sent out.");
- aResolve();
- });
-
- connection.send(outgoingMessage);
- });
-}
-
-function testIncomingMessage() {
- return new Promise(function(aResolve, aReject) {
- const incomingMessage = "test incoming message";
-
- connection.addEventListener('message', function messageHandler(aEvent) {
- connection.removeEventListener('message', messageHandler);
- is(aEvent.data, incomingMessage, "An incoming message should be received.");
- aResolve();
- });
-
- frameScript.sendAsyncMessage('trigger-incoming-message', incomingMessage);
- });
-}
-
-function testCloseConnection() {
- return new Promise(function(aResolve, aReject) {
- frameScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- frameScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- info("The data transport is closed. " + aReason);
- });
-
- connection.onclose = function() {
- connection.onclose = null;
- is(connection.state, "closed", "Connection should be closed.");
- aResolve();
- };
-
- connection.close();
- });
-}
-
-function testReconnect() {
- return new Promise(function(aResolve, aReject) {
- info('--- testReconnect ---');
- gScript.addMessageListener('control-channel-established', function controlChannelEstablished() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablished);
- gScript.sendAsyncMessage("trigger-control-channel-open");
- });
-
- gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) {
- gScript.removeMessageListener('start-reconnect', startReconnectHandler);
- is(url, "http://example.com/", "URLs should be the same.")
- gScript.sendAsyncMessage('trigger-reconnected-acked', url);
- });
-
- gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- ok(aIsValid, "A valid offer is sent out.");
- gScript.sendAsyncMessage('trigger-incoming-answer');
- });
-
- gScript.addMessageListener('answer-received', function answerReceivedHandler() {
- gScript.removeMessageListener('answer-received', answerReceivedHandler);
- info("An answer is received.");
- });
-
- frameScript.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
- frameScript.removeMessageListener('check-navigator', checknavigatorHandler);
- ok(aSuccess, "buildDataChannel get correct window object");
- });
-
- request.reconnect(connection.id).then(
- function(aConnection) {
- ok(aConnection, "Connection should be available.");
- ok(aConnection.id, "Connection ID should be set.");
- is(aConnection.state, "connecting", "The initial state should be connecting.");
- is(aConnection, connection, "The reconnected connection should be the same.");
-
- aConnection.onconnect = function() {
- aConnection.onconnect = null;
- is(aConnection.state, "connected", "Connection should be connected.");
- aResolve();
- };
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- info('teardown-complete');
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function testConstructRequestError() {
- return Promise.all([
- // XXX: Bug 1305204 - uncomment when bug 1275746 is fixed again.
- // new Promise(function(aResolve, aReject) {
- // try {
- // request = new PresentationRequest("\\\\\\");
- // }
- // catch(e) {
- // is(e.name, "SyntaxError", "Expect to get SyntaxError.");
- // aResolve();
- // }
- // }),
- new Promise(function(aResolve, aReject) {
- try {
- request = new PresentationRequest([]);
- }
- catch(e) {
- is(e.name, "NotSupportedError", "Expect to get NotSupportedError.");
- aResolve();
- }
- }),
- ]);
-}
-
-function runTests() {
- ok(window.PresentationRequest, "PresentationRequest should be available.");
-
- testSetup().
- then(testStartConnection).
- then(testSend).
- then(testIncomingMessage).
- then(testCloseConnection).
- then(testReconnect).
- then(testCloseConnection).
- then(testConstructRequestError).
- then(teardown);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", true]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_device_info.html b/dom/presentation/tests/mochitest/test_presentation_device_info.html
deleted file mode 100644
index 77253e41d..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_device_info.html
+++ /dev/null
@@ -1,144 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for B2G Presentation Device Info API</title>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1080474">Test for B2G Presentation Device Info API</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-SimpleTest.waitForExplicitFinish();
-
-var testDevice = {
- id: 'id',
- name: 'name',
- type: 'type',
-};
-
-var gUrl = SimpleTest.getTestFileURL('PresentationDeviceInfoChromeScript.js');
-var gScript = SpecialPowers.loadChromeScript(gUrl);
-
-function testSetup() {
- return new Promise(function(resolve, reject) {
- gScript.addMessageListener('setup-complete', function() {
- resolve();
- });
- gScript.sendAsyncMessage('setup');
- });
-}
-
-function testForceDiscovery() {
- info('test force discovery');
- return new Promise(function(resolve, reject) {
- gScript.addMessageListener('force-discovery', function() {
- ok(true, 'nsIPresentationDeviceProvider.forceDiscovery is invoked');
- resolve();
- });
- navigator.mozPresentationDeviceInfo.forceDiscovery();
- });
-}
-
-function testDeviceAdd() {
- info('test device add');
- return new Promise(function(resolve, reject) {
- navigator.mozPresentationDeviceInfo.addEventListener('devicechange', function deviceChangeHandler(e) {
- navigator.mozPresentationDeviceInfo.removeEventListener('devicechange', deviceChangeHandler);
- let detail = e.detail;
- is(detail.type, 'add', 'expected update type');
- is(detail.deviceInfo.id, testDevice.id, 'expected device id');
- is(detail.deviceInfo.name, testDevice.name, 'expected device name');
- is(detail.deviceInfo.type, testDevice.type, 'expected device type');
-
- navigator.mozPresentationDeviceInfo.getAll()
- .then(function(devices) {
- is(devices.length, 1, 'expected 1 available device');
- is(devices[0].id, testDevice.id, 'expected device id');
- is(devices[0].name, testDevice.name, 'expected device name');
- is(devices[0].type, testDevice.type, 'expected device type');
- resolve();
- });
- });
- gScript.sendAsyncMessage('trigger-device-add', testDevice);
- });
-}
-
-function testDeviceUpdate() {
- info('test device update');
- return new Promise(function(resolve, reject) {
- testDevice.name = 'name-update';
-
- navigator.mozPresentationDeviceInfo.addEventListener('devicechange', function deviceChangeHandler(e) {
- navigator.mozPresentationDeviceInfo.removeEventListener('devicechange', deviceChangeHandler);
- let detail = e.detail;
- is(detail.type, 'update', 'expected update type');
- is(detail.deviceInfo.id, testDevice.id, 'expected device id');
- is(detail.deviceInfo.name, testDevice.name, 'expected device name');
- is(detail.deviceInfo.type, testDevice.type, 'expected device type');
-
- navigator.mozPresentationDeviceInfo.getAll()
- .then(function(devices) {
- is(devices.length, 1, 'expected 1 available device');
- is(devices[0].id, testDevice.id, 'expected device id');
- is(devices[0].name, testDevice.name, 'expected device name');
- is(devices[0].type, testDevice.type, 'expected device type');
- resolve();
- });
- });
- gScript.sendAsyncMessage('trigger-device-update', testDevice);
- });
-}
-
-function testDeviceRemove() {
- info('test device remove');
- return new Promise(function(resolve, reject) {
- navigator.mozPresentationDeviceInfo.addEventListener('devicechange', function deviceChangeHandler(e) {
- navigator.mozPresentationDeviceInfo.removeEventListener('devicechange', deviceChangeHandler);
- let detail = e.detail;
- is(detail.type, 'remove', 'expected update type');
- is(detail.deviceInfo.id, testDevice.id, 'expected device id');
- is(detail.deviceInfo.name, testDevice.name, 'expected device name');
- is(detail.deviceInfo.type, testDevice.type, 'expected device type');
-
- navigator.mozPresentationDeviceInfo.getAll()
- .then(function(devices) {
- is(devices.length, 0, 'expected 0 available device');
- resolve();
- });
- });
- gScript.sendAsyncMessage('trigger-device-remove');
- });
-}
-
-function runTests() {
- testSetup()
- .then(testForceDiscovery)
- .then(testDeviceAdd)
- .then(testDeviceUpdate)
- .then(testDeviceRemove)
- .then(function() {
- info('test finished, teardown');
- gScript.sendAsyncMessage('teardown', '');
- gScript.destroy();
- SimpleTest.finish();
- });
-}
-
-window.addEventListener('load', function() {
- SpecialPowers.pushPrefEnv({
- 'set': [
- ['dom.presentation.enabled', true],
- ]
- }, runTests);
-});
-
-</script>
-</pre>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_device_info_permission.html b/dom/presentation/tests/mochitest/test_presentation_device_info_permission.html
deleted file mode 100644
index c7f7ac96d..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_device_info_permission.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for B2G Presentation Device Info API Permission</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1080474">Test for B2G Presentation Device Info API Permission</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-SimpleTest.waitForExplicitFinish();
-
-function runTests() {
- is(navigator.mozPresentationDeviceInfo, undefined, 'navigator.mozPresentationDeviceInfo is undefined');
- SimpleTest.finish();
-}
-
-window.addEventListener('load', function() {
- SpecialPowers.pushPrefEnv({
- 'set': [
- ['dom.presentation.enabled', true],
- ]
- }, runTests);
-});
-
-</script>
-</pre>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_mixed_security_contexts.html b/dom/presentation/tests/mochitest/test_presentation_mixed_security_contexts.html
deleted file mode 100644
index 31918a2c4..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_mixed_security_contexts.html
+++ /dev/null
@@ -1,81 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test default request for B2G Presentation API at sender side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268758">Test allow-presentation sandboxing flag</a>
-<iframe id="iframe" src="https://example.com/tests/dom/presentation/tests/mochitest/file_presentation_mixed_security_contexts.html"></iframe>
-<script type="application/javascript;version=1.8">
-
-"use strict";
-
-var iframe = document.getElementById("iframe");
-var readyToStart = false;
-var testSetuped = false;
-
-function setup() {
- SpecialPowers.addPermission("presentation",
- true, { url: "https://example.com/tests/dom/presentation/tests/mochitest/file_presentation_mixed_security_contexts.html",
- originAttributes: {
- appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
- inIsolatedMozBrowser: false }});
-
- return new Promise(function(aResolve, aReject) {
- addEventListener("message", function listener(event) {
- var message = event.data;
- if (/^OK /.exec(message)) {
- ok(true, message.replace(/^OK /, ""));
- } else if (/^KO /.exec(message)) {
- ok(false, message.replace(/^KO /, ""));
- } else if (/^INFO /.exec(message)) {
- info(message.replace(/^INFO /, ""));
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ""));
- if (command === "ready-to-start") {
- readyToStart = true;
- startTest();
- }
- } else if (/^DONE$/.exec(message)) {
- window.removeEventListener('message', listener);
- SimpleTest.finish();
- }
- }, false);
-
- testSetuped = true;
- aResolve();
- });
-}
-
-iframe.onload = startTest();
-
-function startTest() {
- if (!(testSetuped && readyToStart)) {
- return;
- }
- iframe.contentWindow.postMessage("start", "*");
-}
-
-function runTests() {
- ok(navigator.presentation, "navigator.presentation should be available.");
- setup().then(startTest);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: "presentation-device-manage", allow: false, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ "set": [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", false]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation.js b/dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation.js
deleted file mode 100644
index 0647bff3a..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation.js
+++ /dev/null
@@ -1,77 +0,0 @@
-"use strict";
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL("PresentationSessionChromeScript.js"));
-var receiverUrl = SimpleTest.getTestFileURL("file_presentation_receiver_auxiliary_navigation.html");
-
-var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
- .getService(SpecialPowers.Ci.nsIObserverService);
-
-function setup() {
- return new Promise(function(aResolve, aReject) {
- gScript.sendAsyncMessage("trigger-device-add");
-
- var iframe = document.createElement("iframe");
- iframe.setAttribute("mozbrowser", "true");
- iframe.setAttribute("mozpresentation", receiverUrl);
- var oop = location.pathname.indexOf('_inproc') == -1;
- iframe.setAttribute("remote", oop);
- iframe.setAttribute("src", receiverUrl);
-
- // This event is triggered when the iframe calls "postMessage".
- iframe.addEventListener("mozbrowsershowmodalprompt", function listener(aEvent) {
- var message = aEvent.detail.message;
- if (/^OK /.exec(message)) {
- ok(true, "Message from iframe: " + message);
- } else if (/^KO /.exec(message)) {
- ok(false, "Message from iframe: " + message);
- } else if (/^INFO /.exec(message)) {
- info("Message from iframe: " + message);
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ""));
- gScript.sendAsyncMessage(command.name, command.data);
- } else if (/^DONE$/.exec(message)) {
- ok(true, "Messaging from iframe complete.");
- iframe.removeEventListener("mozbrowsershowmodalprompt", listener);
-
- teardown();
- }
- }, false);
-
- var promise = new Promise(function(aResolve, aReject) {
- document.body.appendChild(iframe);
-
- aResolve(iframe);
- });
- obs.notifyObservers(promise, "setup-request-promise", null);
-
- aResolve();
- });
-}
-
-function teardown() {
- gScript.addMessageListener("teardown-complete", function teardownCompleteHandler() {
- gScript.removeMessageListener("teardown-complete", teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage("teardown");
-}
-
-function runTests() {
- setup().then();
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: "presentation-device-manage", allow: false, context: document},
- {type: "browser", allow: true, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ "set": [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.receiver.enabled", true],
- ["dom.mozBrowserFramesEnabled", true],
- ["network.disable.ipc.security", true],
- ["dom.presentation.session_transport.data_channel.enable", false]]},
- runTests);
-});
diff --git a/dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation_inproc.html b/dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation_inproc.html
deleted file mode 100644
index f873fa3da..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation_inproc.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
- <head>
- <meta charset="utf-8">
- <title>Test for B2G Presentation API when sender and receiver at the same side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- </head>
- <body>
- <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268810">
- Test for receiver page with sandboxed auxiliary navigation browsing context flag.</a>
- <script type="application/javascript;version=1.8" src="test_presentation_receiver_auxiliary_navigation.js">
- </script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation_oop.html b/dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation_oop.html
deleted file mode 100644
index f873fa3da..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation_oop.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
- <head>
- <meta charset="utf-8">
- <title>Test for B2G Presentation API when sender and receiver at the same side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- </head>
- <body>
- <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268810">
- Test for receiver page with sandboxed auxiliary navigation browsing context flag.</a>
- <script type="application/javascript;version=1.8" src="test_presentation_receiver_auxiliary_navigation.js">
- </script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_reconnect.html b/dom/presentation/tests/mochitest/test_presentation_reconnect.html
deleted file mode 100644
index 079b7f5c5..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_reconnect.html
+++ /dev/null
@@ -1,379 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for B2G Presentation API at sender side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <script type="application/javascript" src="PresentationSessionFrameScript.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1197690">Test for Presentation API at sender side</a>
-<iframe id="iframe" src="file_presentation_reconnect.html"></iframe>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-var iframe = document.getElementById("iframe");
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var frameScript = SpecialPowers.isMainProcess() ? gScript : contentScript;
-var request;
-var connection;
-var commandHandler = {};
-
-function testSetup() {
- return new Promise(function(aResolve, aReject) {
- addEventListener("message", function listener(event) {
- var message = event.data;
- if (/^OK /.exec(message)) {
- ok(true, message.replace(/^OK /, ""));
- } else if (/^KO /.exec(message)) {
- ok(false, message.replace(/^KO /, ""));
- } else if (/^INFO /.exec(message)) {
- info(message.replace(/^INFO /, ""));
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ""));
- if (command.name in commandHandler) {
- commandHandler[command.name](command);
- }
- } else if (/^DONE$/.exec(message)) {
- window.removeEventListener('message', listener);
- SimpleTest.finish();
- }
- }, false);
-
- request = new PresentationRequest("http://example.com/");
-
- request.getAvailability().then(
- function(aAvailability) {
- is(aAvailability.value, false, "Sender: should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, "Device should be available.");
- aResolve();
- }
-
- gScript.sendAsyncMessage('trigger-device-add');
- },
- function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testStartConnection() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- });
-
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- info("A control channel is established.");
- gScript.sendAsyncMessage('trigger-control-channel-open');
- });
-
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
- info("The control channel is opened.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- info("The control channel is closed. " + aReason);
- });
-
- frameScript.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
- ok(aSuccess, "buildDataChannel get correct window object");
- });
-
- gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
- ok(aIsValid, "A valid offer is sent out.");
- gScript.sendAsyncMessage('trigger-incoming-answer');
- });
-
- gScript.addMessageListener('answer-received', function answerReceivedHandler() {
- info("An answer is received.");
- });
-
- frameScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
- info("Data transport channel is initialized.");
- });
-
- frameScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
- info("Data notification is enabled for data transport channel.");
- });
-
- var connectionFromEvent;
- request.onconnectionavailable = function(aEvent) {
- request.onconnectionavailable = null;
- connectionFromEvent = aEvent.connection;
- ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
-
- if (connection) {
- is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
- }
- };
-
- request.start().then(
- function(aConnection) {
- connection = aConnection;
- ok(connection, "Connection should be available.");
- ok(connection.id, "Connection ID should be set.");
- is(connection.state, "connecting", "The initial state should be connecting.");
-
- if (connectionFromEvent) {
- is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
- }
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, "connected", "Connection should be connected.");
- aResolve();
- };
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testCloseConnection() {
- return new Promise(function(aResolve, aReject) {
- frameScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- frameScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- info("The data transport is closed. " + aReason);
- });
-
- connection.onclose = function() {
- connection.onclose = null;
- is(connection.state, "closed", "Connection should be closed.");
- aResolve();
- };
-
- connection.close();
- });
-}
-
-function testReconnectAConnectedConnection() {
- return new Promise(function(aResolve, aReject) {
- info('--- testReconnectAConnectedConnection ---');
- ok(connection.state, "connected", "Make sure the state is connected.");
-
- request.reconnect(connection.id).then(
- function(aConnection) {
- ok(aConnection, "Connection should be available.");
- is(aConnection.id, connection.id, "Connection ID should be the same.");
- is(aConnection.state, "connected", "The state should be connected.");
- is(aConnection, connection, "The connection should be the same.");
-
- aResolve();
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testReconnectInvalidID() {
- return new Promise(function(aResolve, aReject) {
- info('--- testReconnectInvalidID ---');
-
- request.reconnect("dummyID").then(
- function(aConnection) {
- ok(false, "Unexpected success.");
- teardown();
- aReject();
- },
- function(aError) {
- is(aError.name, "NotFoundError", "Should get NotFoundError.");
- aResolve();
- }
- );
- });
-}
-
-function testReconnectInvalidURL() {
- return new Promise(function(aResolve, aReject) {
- info('--- testReconnectInvalidURL ---');
-
- var request1 = new PresentationRequest("http://invalidURL");
- request1.reconnect(connection.id).then(
- function(aConnection) {
- ok(false, "Unexpected success.");
- teardown();
- aReject();
- },
- function(aError) {
- is(aError.name, "NotFoundError", "Should get NotFoundError.");
- aResolve();
- }
- );
- });
-}
-
-function testReconnectIframeConnectedConnection() {
- info('--- testReconnectIframeConnectedConnection ---');
- gScript.sendAsyncMessage('save-control-channel-listener');
- return Promise.all([
- new Promise(function(aResolve, aReject) {
- commandHandler["connection-connected"] = function(command) {
- gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) {
- gScript.removeMessageListener('start-reconnect', startReconnectHandler);
- gScript.sendAsyncMessage('trigger-reconnected-acked', url);
- });
-
- var request1 = new PresentationRequest("http://example1.com");
- request1.reconnect(command.id).then(
- function(aConnection) {
- is(aConnection.state, "connecting", "The state should be connecting.");
- aConnection.onclose = function() {
- delete commandHandler["connection-connected"];
- gScript.sendAsyncMessage('restore-control-channel-listener');
- aResolve();
- };
- aConnection.close();
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- };
- iframe.contentWindow.postMessage("startConnection", "*");
- }),
- new Promise(function(aResolve, aReject) {
- commandHandler["notify-connection-closed"] = function(command) {
- delete commandHandler["notify-connection-closed"];
- aResolve();
- };
- }),
- ]);
-}
-
-function testReconnectIframeClosedConnection() {
- return new Promise(function(aResolve, aReject) {
- info('--- testReconnectIframeClosedConnection ---');
- gScript.sendAsyncMessage('save-control-channel-listener');
- commandHandler["connection-closed"] = function(command) {
- gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) {
- gScript.removeMessageListener('start-reconnect', startReconnectHandler);
- gScript.sendAsyncMessage('trigger-reconnected-acked', url);
- });
-
- var request1 = new PresentationRequest("http://example1.com");
- request1.reconnect(command.id).then(
- function(aConnection) {
- aConnection.onconnect = function() {
- aConnection.onconnect = null;
- is(aConnection.state, "connected", "The connection should be connected.");
- aConnection.onclose = function() {
- aConnection.onclose = null;
- ok(true, "The connection is closed.");
- delete commandHandler["connection-closed"];
- aResolve();
- };
- aConnection.close();
- gScript.sendAsyncMessage('restore-control-channel-listener');
- };
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- };
- iframe.contentWindow.postMessage("closeConnection", "*");
- });
-}
-
-function testReconnect() {
- return new Promise(function(aResolve, aReject) {
- info('--- testReconnect ---');
- gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) {
- gScript.removeMessageListener('start-reconnect', startReconnectHandler);
- is(url, "http://example.com/", "URLs should be the same.");
- gScript.sendAsyncMessage('trigger-reconnected-acked', url);
- });
-
- request.reconnect(connection.id).then(
- function(aConnection) {
- ok(aConnection, "Connection should be available.");
- ok(aConnection.id, "Connection ID should be set.");
- is(aConnection.state, "connecting", "The initial state should be connecting.");
- is(aConnection, connection, "The reconnected connection should be the same.");
-
- aConnection.onconnect = function() {
- aConnection.onconnect = null;
- is(aConnection.state, "connected", "Connection should be connected.");
-
- const incomingMessage = "test incoming message";
- aConnection.addEventListener('message', function messageHandler(aEvent) {
- aConnection.removeEventListener('message', messageHandler);
- is(aEvent.data, incomingMessage, "An incoming message should be received.");
- aResolve();
- });
-
- frameScript.sendAsyncMessage('trigger-incoming-message', incomingMessage);
- };
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- info('teardown-complete');
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- ok(window.PresentationRequest, "PresentationRequest should be available.");
-
- testSetup().
- then(testStartConnection).
- then(testReconnectInvalidID).
- then(testReconnectInvalidURL).
- then(testReconnectAConnectedConnection).
- then(testReconnectIframeConnectedConnection).
- then(testReconnectIframeClosedConnection).
- then(testCloseConnection).
- then(testReconnect).
- then(testCloseConnection).
- then(teardown);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.receiver.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", true]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_sandboxed_presentation.html b/dom/presentation/tests/mochitest/test_presentation_sandboxed_presentation.html
deleted file mode 100644
index dc17209c5..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_sandboxed_presentation.html
+++ /dev/null
@@ -1,75 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test default request for B2G Presentation API at sender side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268758">Test allow-presentation sandboxing flag</a>
-<iframe sandbox="allow-popups allow-scripts allow-same-origin" id="iframe" src="file_presentation_sandboxed_presentation.html"></iframe>
-<script type="application/javascript;version=1.8">
-
-"use strict";
-
-var iframe = document.getElementById("iframe");
-var readyToStart = false;
-var testSetuped = false;
-function setup() {
- return new Promise(function(aResolve, aReject) {
- addEventListener("message", function listener(event) {
- var message = event.data;
- if (/^OK /.exec(message)) {
- ok(true, message.replace(/^OK /, ""));
- } else if (/^KO /.exec(message)) {
- ok(false, message.replace(/^KO /, ""));
- } else if (/^INFO /.exec(message)) {
- info(message.replace(/^INFO /, ""));
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ""));
- if (command === "ready-to-start") {
- readyToStart = true;
- startTest();
- }
- } else if (/^DONE$/.exec(message)) {
- window.removeEventListener('message', listener);
- SimpleTest.finish();
- }
- }, false);
-
- testSetuped = true;
- aResolve();
- });
-}
-
-iframe.onload = startTest();
-
-function startTest() {
- if (!(testSetuped && readyToStart)) {
- return;
- }
- iframe.contentWindow.postMessage("start", "*");
-}
-
-function runTests() {
- ok(navigator.presentation, "navigator.presentation should be available.");
- setup().then(startTest);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: "presentation-device-manage", allow: false, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ "set": [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.receiver.enabled", false],
- ["dom.presentation.session_transport.data_channel.enable", false]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_sender_on_terminate_request.html b/dom/presentation/tests/mochitest/test_presentation_sender_on_terminate_request.html
deleted file mode 100644
index d0c8af0ad..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_sender_on_terminate_request.html
+++ /dev/null
@@ -1,187 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test onTerminateRequest at sender side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1276378">Test onTerminateRequest at sender side</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var request;
-var connection;
-
-function testSetup() {
- return new Promise(function(aResolve, aReject) {
- request = new PresentationRequest("http://example.com");
-
- request.getAvailability().then(
- function(aAvailability) {
- is(aAvailability.value, false, "Sender: should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, "Device should be available.");
- aResolve();
- }
-
- gScript.sendAsyncMessage('trigger-device-add');
- },
- function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testStartConnection() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- });
-
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
- info("A control channel is established.");
- gScript.sendAsyncMessage('trigger-control-channel-open');
- });
-
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
- gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
- info("The control channel is opened.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- info("The control channel is closed. " + aReason);
- });
-
- gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- ok(aIsValid, "A valid offer is sent out.");
- gScript.sendAsyncMessage('trigger-incoming-transport');
- });
-
- gScript.addMessageListener('answer-received', function answerReceivedHandler() {
- gScript.removeMessageListener('answer-received', answerReceivedHandler);
- info("An answer is received.");
- });
-
- gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
- gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
- info("Data transport channel is initialized.");
- gScript.sendAsyncMessage('trigger-incoming-answer');
- });
-
- gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
- gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
- info("Data notification is enabled for data transport channel.");
- });
-
- var connectionFromEvent;
- request.onconnectionavailable = function(aEvent) {
- request.onconnectionavailable = null;
- connectionFromEvent = aEvent.connection;
- ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
-
- if (connection) {
- is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
- }
- };
-
- request.start().then(
- function(aConnection) {
- connection = aConnection;
- ok(connection, "Connection should be available.");
- ok(connection.id, "Connection ID should be set.");
- is(connection.state, "connecting", "The initial state should be connecting.");
-
- if (connectionFromEvent) {
- is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
- }
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, "connected", "Connection should be connected.");
- aResolve();
- };
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testOnTerminateRequest() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
- gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
- info("The control channel is opened.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- info("The control channel is closed. " + aReason);
- });
-
- gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- info("The data transport is closed. " + aReason);
- });
-
- connection.onterminate = function() {
- connection.onterminate = null;
- is(connection.state, "terminated", "Connection should be closed.");
- aResolve();
- };
-
- gScript.sendAsyncMessage('trigger-incoming-terminate-request');
- gScript.sendAsyncMessage('trigger-control-channel-open');
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- ok(window.PresentationRequest, "PresentationRequest should be available.");
-
- testSetup().
- then(testStartConnection).
- then(testOnTerminateRequest).
- then(teardown);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.receiver.enabled", false],
- ["dom.presentation.session_transport.data_channel.enable", false]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_sender_startWithDevice.html b/dom/presentation/tests/mochitest/test_presentation_sender_startWithDevice.html
deleted file mode 100644
index 27b17bb32..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_sender_startWithDevice.html
+++ /dev/null
@@ -1,173 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test startWithDevice for B2G Presentation API at sender side</title>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1239242">Test startWithDevice for B2G Presentation API at sender side</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var request;
-var connection;
-
-function testSetup() {
- return new Promise(function(aResolve, aReject) {
- request = new PresentationRequest("https://example.com");
-
- request.getAvailability().then(
- function(aAvailability) {
- is(aAvailability.value, false, "Sender: should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, "Device should be available.");
- aResolve();
- }
-
- gScript.sendAsyncMessage('trigger-device-add');
- },
- function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testStartConnectionWithDevice() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- ok(false, "Device prompt should not be triggered.");
- teardown();
- aReject();
- });
-
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
- info("A control channel is established.");
- gScript.sendAsyncMessage('trigger-control-channel-open');
- });
-
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
- gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
- info("The control channel is opened.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- info("The control channel is closed. " + aReason);
- });
-
- gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- ok(aIsValid, "A valid offer is sent out.");
- gScript.sendAsyncMessage('trigger-incoming-transport');
- });
-
- gScript.addMessageListener('answer-received', function answerReceivedHandler() {
- gScript.removeMessageListener('answer-received', answerReceivedHandler);
- info("An answer is received.");
- });
-
- gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
- gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
- info("Data transport channel is initialized.");
- gScript.sendAsyncMessage('trigger-incoming-answer');
- });
-
- gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
- gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
- info("Data notification is enabled for data transport channel.");
- });
-
- var connectionFromEvent;
- request.onconnectionavailable = function(aEvent) {
- request.onconnectionavailable = null;
- connectionFromEvent = aEvent.connection;
- ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
-
- if (connection) {
- is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
- }
- };
-
- request.startWithDevice('id').then(
- function(aConnection) {
- connection = aConnection;
- ok(connection, "Connection should be available.");
- ok(connection.id, "Connection ID should be set.");
- is(connection.state, "connecting", "The initial state should be connecting.");
-
- if (connectionFromEvent) {
- is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
- }
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, "connected", "Connection should be connected.");
- aResolve();
- };
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testStartConnectionWithDeviceNotFoundError() {
- return new Promise(function(aResolve, aReject) {
- request.startWithDevice('').then(
- function(aConnection) {
- ok(false, "Should not establish connection to an unknown device");
- teardown();
- aReject();
- },
- function(aError) {
- is(aError.name, 'NotFoundError', "Expect NotFoundError occurred when establishing a connection");
- aResolve();
- }
- );
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- ok(window.PresentationRequest, "PresentationRequest should be available.");
-
- testSetup().
- then(testStartConnectionWithDevice).
- then(testStartConnectionWithDeviceNotFoundError).
- then(teardown);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", false],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.test.enabled", true],
- ["dom.presentation.test.stage", 0]]},
- runTests);
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver.html b/dom/presentation/tests/mochitest/test_presentation_tcp_receiver.html
deleted file mode 100644
index f26184f0b..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver.html
+++ /dev/null
@@ -1,137 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for B2G PresentationConnection API at receiver side</title>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for B2G PresentationConnection API at receiver side</a>
-<p id="display"></p>
-<div id="content" style="display: none"></div>
-<pre id="test"></pre>
-<script type="application/javascript">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver.html');
-
-var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
- .getService(SpecialPowers.Ci.nsIObserverService);
-
-function setup() {
- return new Promise(function(aResolve, aReject) {
- gScript.sendAsyncMessage('trigger-device-add');
-
- var iframe = document.createElement('iframe');
- iframe.setAttribute('mozbrowser', 'true');
- iframe.setAttribute('mozpresentation', receiverUrl);
- iframe.setAttribute('src', receiverUrl);
-
- // This event is triggered when the iframe calls "postMessage".
- iframe.addEventListener('mozbrowsershowmodalprompt', function listener(aEvent) {
- var message = aEvent.detail.message;
- if (/^OK /.exec(message)) {
- ok(true, "Message from iframe: " + message);
- } else if (/^KO /.exec(message)) {
- ok(false, "Message from iframe: " + message);
- } else if (/^INFO /.exec(message)) {
- info("Message from iframe: " + message);
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ''));
- gScript.sendAsyncMessage(command.name, command.data);
- } else if (/^DONE$/.exec(message)) {
- ok(true, "Messaging from iframe complete.");
- iframe.removeEventListener('mozbrowsershowmodalprompt', listener);
-
- teardown();
- }
- }, false);
-
- var promise = new Promise(function(aResolve, aReject) {
- document.body.appendChild(iframe);
-
- aResolve(iframe);
- });
- obs.notifyObservers(promise, 'setup-request-promise', null);
-
- gScript.addMessageListener('offer-received', function offerReceivedHandler() {
- gScript.removeMessageListener('offer-received', offerReceivedHandler);
- info("An offer is received.");
- });
-
- gScript.addMessageListener('answer-sent', function answerSentHandler(aIsValid) {
- gScript.removeMessageListener('answer-sent', answerSentHandler);
- ok(aIsValid, "A valid answer is sent.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed normally.");
- });
-
- gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
- gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
- info("Data notification is enabled for data transport channel.");
- });
-
- gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- is(aReason, SpecialPowers.Cr.NS_OK, "The data transport should be closed normally.");
- });
-
- aResolve();
- });
-}
-
-function testIncomingSessionRequest() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
- gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
- info("Trying to launch receiver page.");
-
- ok(navigator.presentation, "navigator.presentation should be available in in-process pages.");
- is(navigator.presentation.receiver, null, "Non-receiving in-process pages shouldn't get a presentation receiver instance.");
- aResolve();
- });
-
- gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- setup().
- then(testIncomingSessionRequest);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
- {type: 'browser', allow: true, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", false],
- ["dom.presentation.receiver.enabled", true],
- ["dom.mozBrowserFramesEnabled", true],
- ["network.disable.ipc.security", true],
- ["dom.presentation.session_transport.data_channel.enable", false]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_error.html b/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_error.html
deleted file mode 100644
index 0935aaaf9..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_error.html
+++ /dev/null
@@ -1,110 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for connection establishing errors of B2G Presentation API at receiver side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for connection establishing errors of B2G Presentation API at receiver side</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver_establish_connection_error.html');
-
-var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
- .getService(SpecialPowers.Ci.nsIObserverService);
-
-function setup() {
- return new Promise(function(aResolve, aReject) {
- gScript.sendAsyncMessage('trigger-device-add');
-
- var iframe = document.createElement('iframe');
- iframe.setAttribute('src', receiverUrl);
- iframe.setAttribute("mozbrowser", "true");
- iframe.setAttribute("mozpresentation", receiverUrl);
-
- // This event is triggered when the iframe calls "alert".
- iframe.addEventListener("mozbrowsershowmodalprompt", function receiverListener(evt) {
- var message = evt.detail.message;
- if (/^OK /.exec(message)) {
- ok(true, message.replace(/^OK /, ""));
- } else if (/^KO /.exec(message)) {
- ok(false, message.replace(/^KO /, ""));
- } else if (/^INFO /.exec(message)) {
- info(message.replace(/^INFO /, ""));
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ""));
- gScript.sendAsyncMessage(command.name, command.data);
- } else if (/^DONE$/.exec(message)) {
- iframe.removeEventListener("mozbrowsershowmodalprompt",
- receiverListener);
- teardown();
- }
- }, false);
-
- var promise = new Promise(function(aResolve, aReject) {
- document.body.appendChild(iframe);
-
- aResolve(iframe);
- });
- obs.notifyObservers(promise, 'setup-request-promise', null);
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- is(aReason, 0x80004004 /* NS_ERROR_ABORT */, "The control channel is closed abnormally.");
- });
-
- aResolve();
- });
-}
-
-function testIncomingSessionRequest() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
- gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
- info("Trying to launch receiver page.");
-
- aResolve();
- });
-
- gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- setup().
- then(testIncomingSessionRequest);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
- {type: "browser", allow: true, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.receiver.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", false],
- ["dom.mozBrowserFramesEnabled", true],
- ["network.disable.ipc.security", true]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_timeout.html b/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_timeout.html
deleted file mode 100644
index 1dc002644..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_timeout.html
+++ /dev/null
@@ -1,81 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for connection establishing timeout of B2G Presentation API at receiver side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for connection establishing timeout of B2G Presentation API at receiver side</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-
-var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
- .getService(SpecialPowers.Ci.nsIObserverService);
-
-function setup() {
- return new Promise(function(aResolve, aReject) {
- gScript.sendAsyncMessage('trigger-device-add');
-
- var promise = new Promise(function(aResolve, aReject) {
- // In order to trigger timeout, do not resolve the promise.
- });
- obs.notifyObservers(promise, 'setup-request-promise', null);
-
- aResolve();
- });
-}
-
-function testIncomingSessionRequestReceiverLaunchTimeout() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
- gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
- info("Trying to launch receiver page.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- is(aReason, 0x80530017 /* NS_ERROR_DOM_TIMEOUT_ERR */, "The control channel is closed due to timeout.");
- aResolve();
- });
-
- gScript.sendAsyncMessage('trigger-incoming-session-request', 'http://example.com');
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- setup().
- then(testIncomingSessionRequestReceiverLaunchTimeout).
- then(teardown);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.receiver.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", false],
- ["presentation.receiver.loading.timeout", 10]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type.js b/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type.js
deleted file mode 100644
index d73f84cf8..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type.js
+++ /dev/null
@@ -1,88 +0,0 @@
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var receiverUrl = SimpleTest.getTestFileURL('file_presentation_unknown_content_type.test');
-
-var obs = SpecialPowers.Cc['@mozilla.org/observer-service;1']
- .getService(SpecialPowers.Ci.nsIObserverService);
-
-var receiverIframe;
-
-function setup() {
- return new Promise(function(aResolve, aReject) {
- gScript.sendAsyncMessage('trigger-device-add');
-
- receiverIframe = document.createElement('iframe');
- receiverIframe.setAttribute('mozbrowser', 'true');
- receiverIframe.setAttribute('mozpresentation', receiverUrl);
- receiverIframe.setAttribute('src', receiverUrl);
- var oop = location.pathname.indexOf('_inproc') == -1;
- receiverIframe.setAttribute("remote", oop);
-
- var promise = new Promise(function(aResolve, aReject) {
- document.body.appendChild(receiverIframe);
-
- aResolve(receiverIframe);
- });
- obs.notifyObservers(promise, 'setup-request-promise', null);
-
- aResolve();
- });
-}
-
-function testIncomingSessionRequestReceiverLaunchUnknownContentType() {
- let promise = Promise.all([
- new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
- gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
- info('Trying to launch receiver page.');
-
- receiverIframe.addEventListener('mozbrowserclose', function() {
- ok(true, 'observe receiver window closed');
- aResolve();
- });
- });
- }),
- new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- is(aReason, 0x80530020 /* NS_ERROR_DOM_OPERATION_ERR */, 'The control channel is closed due to load failure.');
- aResolve();
- });
- })
- ]);
-
- gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
- return promise;
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- setup().
- then(testIncomingSessionRequestReceiverLaunchUnknownContentType).
- then(teardown);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
- {type: 'browser', allow: true, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ 'set': [['dom.presentation.enabled', true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.receiver.enabled", true],
- ['dom.presentation.session_transport.data_channel.enable', false],
- ['dom.mozBrowserFramesEnabled', true],
- ["network.disable.ipc.security", true],
- ['dom.ipc.tabs.disabled', false]]},
- runTests);
-});
diff --git a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type_inproc.html b/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type_inproc.html
deleted file mode 100644
index 8ade1d72d..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type_inproc.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for unknown content type of B2G Presentation API at receiver side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1287717">Test for unknown content type of B2G Presentation API at receiver side</a>
- <script type="application/javascript;version=1.8" src="test_presentation_tcp_receiver_establish_connection_unknown_content_type.js">
- </script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type_oop.html b/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type_oop.html
deleted file mode 100644
index b2d2d3c6e..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type_oop.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for unknown content type of B2G Presentation API at receiver side (OOP)</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1287717">Test for unknown content type of B2G Presentation API at receiver side (OOP)</a>
- <script type="application/javascript;version=1.8" src="test_presentation_tcp_receiver_establish_connection_unknown_content_type.js">
- </script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_oop.html b/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_oop.html
deleted file mode 100644
index bfbc7947a..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_oop.html
+++ /dev/null
@@ -1,178 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for B2G PresentationConnection API at receiver side (OOP)</title>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test B2G PresentationConnection API at receiver side (OOP)</a>
-<p id="display"></p>
-<div id="content" style="display: none"></div>
-<pre id="test"></pre>
-<script type="application/javascript">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver.html');
-var nonReceiverUrl = SimpleTest.getTestFileURL('file_presentation_non_receiver.html');
-
-var isReceiverFinished = false;
-var isNonReceiverFinished = false;
-
-var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
- .getService(SpecialPowers.Ci.nsIObserverService);
-
-function setup() {
- return new Promise(function(aResolve, aReject) {
- gScript.sendAsyncMessage('trigger-device-add');
-
- // Create a receiver OOP iframe.
- var receiverIframe = document.createElement('iframe');
- receiverIframe.setAttribute('remote', 'true');
- receiverIframe.setAttribute('mozbrowser', 'true');
- receiverIframe.setAttribute('mozpresentation', receiverUrl);
- receiverIframe.setAttribute('src', receiverUrl);
-
- // This event is triggered when the iframe calls "alert".
- receiverIframe.addEventListener('mozbrowsershowmodalprompt', function receiverListener(aEvent) {
- var message = aEvent.detail.message;
- if (/^OK /.exec(message)) {
- ok(true, "Message from iframe: " + message);
- } else if (/^KO /.exec(message)) {
- ok(false, "Message from iframe: " + message);
- } else if (/^INFO /.exec(message)) {
- info("Message from iframe: " + message);
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ''));
- gScript.sendAsyncMessage(command.name, command.data);
- } else if (/^DONE$/.exec(message)) {
- ok(true, "Messaging from iframe complete.");
- receiverIframe.removeEventListener('mozbrowsershowmodalprompt', receiverListener);
-
- isReceiverFinished = true;
-
- if (isNonReceiverFinished) {
- teardown();
- }
- }
- }, false);
-
- var promise = new Promise(function(aResolve, aReject) {
- document.body.appendChild(receiverIframe);
-
- aResolve(receiverIframe);
- });
- obs.notifyObservers(promise, 'setup-request-promise', null);
-
- // Create a non-receiver OOP iframe.
- var nonReceiverIframe = document.createElement('iframe');
- nonReceiverIframe.setAttribute('remote', 'true');
- nonReceiverIframe.setAttribute('mozbrowser', 'true');
- nonReceiverIframe.setAttribute('src', nonReceiverUrl);
-
- // This event is triggered when the iframe calls "alert".
- nonReceiverIframe.addEventListener('mozbrowsershowmodalprompt', function nonReceiverListener(aEvent) {
- var message = aEvent.detail.message;
- if (/^OK /.exec(message)) {
- ok(true, "Message from iframe: " + message);
- } else if (/^KO /.exec(message)) {
- ok(false, "Message from iframe: " + message);
- } else if (/^INFO /.exec(message)) {
- info("Message from iframe: " + message);
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ''));
- gScript.sendAsyncMessage(command.name, command.data);
- } else if (/^DONE$/.exec(message)) {
- ok(true, "Messaging from iframe complete.");
- nonReceiverIframe.removeEventListener('mozbrowsershowmodalprompt', nonReceiverListener);
-
- isNonReceiverFinished = true;
-
- if (isReceiverFinished) {
- teardown();
- }
- }
- }, false);
-
- document.body.appendChild(nonReceiverIframe);
-
- gScript.addMessageListener('offer-received', function offerReceivedHandler() {
- gScript.removeMessageListener('offer-received', offerReceivedHandler);
- info("An offer is received.");
- });
-
- gScript.addMessageListener('answer-sent', function answerSentHandler(aIsValid) {
- gScript.removeMessageListener('answer-sent', answerSentHandler);
- ok(aIsValid, "A valid answer is sent.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed normally.");
- });
-
- gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
- gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
- info("Data notification is enabled for data transport channel.");
- });
-
- gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- is(aReason, SpecialPowers.Cr.NS_OK, "The data transport should be closed normally.");
- });
-
- aResolve();
- });
-}
-
-function testIncomingSessionRequest() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
- gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
- info("Trying to launch receiver page.");
-
- aResolve();
- });
-
- gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- setup().
- then(testIncomingSessionRequest);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
- {type: 'browser', allow: true, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", false],
- ["dom.presentation.receiver.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", false],
- ["dom.mozBrowserFramesEnabled", true],
- ["network.disable.ipc.security", true],
- ["dom.ipc.browser_frames.oop_by_default", true]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_tcp_sender.html b/dom/presentation/tests/mochitest/test_presentation_tcp_sender.html
deleted file mode 100644
index 8df34c884..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_sender.html
+++ /dev/null
@@ -1,260 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for B2G Presentation API at sender side</title>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for B2G Presentation API at sender side</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var request;
-var connection;
-
-function testSetup() {
- return new Promise(function(aResolve, aReject) {
- request = new PresentationRequest("https://example.com");
-
- request.getAvailability().then(
- function(aAvailability) {
- is(aAvailability.value, false, "Sender: should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, "Device should be available.");
- aResolve();
- }
- gScript.sendAsyncMessage('trigger-device-add');
- },
- function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- teardown();
- aReject();
- }
- );
-
- });
-}
-
-function testStartConnection() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- });
-
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
- info("A control channel is established.");
- gScript.sendAsyncMessage('trigger-control-channel-open');
- });
-
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
- gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
- info("The control channel is opened.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- info("The control channel is closed. " + aReason);
- });
-
- gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- ok(aIsValid, "A valid offer is sent out.");
- gScript.sendAsyncMessage('trigger-incoming-transport');
- });
-
- gScript.addMessageListener('answer-received', function answerReceivedHandler() {
- gScript.removeMessageListener('answer-received', answerReceivedHandler);
- info("An answer is received.");
- });
-
- gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
- gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
- info("Data transport channel is initialized.");
- gScript.sendAsyncMessage('trigger-incoming-answer');
- });
-
- gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
- gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
- info("Data notification is enabled for data transport channel.");
- });
-
- var connectionFromEvent;
- request.onconnectionavailable = function(aEvent) {
- request.onconnectionavailable = null;
- connectionFromEvent = aEvent.connection;
- ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
-
- if (connection) {
- is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
- }
- };
-
- request.start().then(
- function(aConnection) {
- connection = aConnection;
- ok(connection, "Connection should be available.");
- ok(connection.id, "Connection ID should be set.");
- is(connection.state, "connecting", "The initial state should be connecting.");
-
- if (connectionFromEvent) {
- is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
- }
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, "connected", "Connection should be connected.");
- aResolve();
- };
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testSend() {
- return new Promise(function(aResolve, aReject) {
- const outgoingMessage = "test outgoing message";
-
- gScript.addMessageListener('message-sent', function messageSentHandler(aMessage) {
- gScript.removeMessageListener('message-sent', messageSentHandler);
- is(aMessage, outgoingMessage, "The message is sent out.");
- aResolve();
- });
-
- connection.send(outgoingMessage);
- });
-}
-
-function testIncomingMessage() {
- return new Promise(function(aResolve, aReject) {
- const incomingMessage = "test incoming message";
-
- connection.addEventListener('message', function messageHandler(aEvent) {
- connection.removeEventListener('message', messageHandler);
- is(aEvent.data, incomingMessage, "An incoming message should be received.");
- aResolve();
- });
-
- gScript.sendAsyncMessage('trigger-incoming-message', incomingMessage);
- });
-}
-
-function testCloseConnection() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- info("The data transport is closed. " + aReason);
- });
-
- connection.onclose = function() {
- connection.onclose = null;
- is(connection.state, "closed", "Connection should be closed.");
- aResolve();
- };
-
- connection.close();
- });
-}
-
-function testReconnect() {
- return new Promise(function(aResolve, aReject) {
- info('--- testReconnect ---');
- gScript.addMessageListener('control-channel-established', function controlChannelEstablished() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablished);
- gScript.sendAsyncMessage("trigger-control-channel-open");
- });
-
- gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) {
- gScript.removeMessageListener('start-reconnect', startReconnectHandler);
- is(url, "https://example.com/", "URLs should be the same.")
- gScript.sendAsyncMessage('trigger-reconnected-acked', url);
- });
-
- gScript.addMessageListener('offer-sent', function offerSentHandler() {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- gScript.sendAsyncMessage('trigger-incoming-transport');
- });
-
- gScript.addMessageListener('answer-received', function answerReceivedHandler() {
- gScript.removeMessageListener('answer-received', answerReceivedHandler);
- info("An answer is received.");
- });
-
- gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
- gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
- info("Data transport channel is initialized.");
- gScript.sendAsyncMessage('trigger-incoming-answer');
- });
-
- gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
- gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
- info("Data notification is enabled for data transport channel.");
- });
-
- request.reconnect(connection.id).then(
- function(aConnection) {
- ok(aConnection, "Connection should be available.");
- ok(aConnection.id, "Connection ID should be set.");
- is(aConnection.state, "connecting", "The initial state should be connecting.");
- is(aConnection, connection, "The reconnected connection should be the same.");
-
- aConnection.onconnect = function() {
- aConnection.onconnect = null;
- is(aConnection.state, "connected", "Connection should be connected.");
- aResolve();
- };
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- ok(window.PresentationRequest, "PresentationRequest should be available.");
-
- testSetup().
- then(testStartConnection).
- then(testSend).
- then(testIncomingMessage).
- then(testCloseConnection).
- then(testReconnect).
- then(testCloseConnection).
- then(teardown);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", false]]},
- runTests);
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_tcp_sender_default_request.html b/dom/presentation/tests/mochitest/test_presentation_tcp_sender_default_request.html
deleted file mode 100644
index 60247ec98..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_sender_default_request.html
+++ /dev/null
@@ -1,151 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test default request for B2G Presentation API at sender side</title>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test default request for B2G Presentation API at sender side</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var connection;
-
-function testSetup() {
- return new Promise(function(aResolve, aReject) {
- navigator.presentation.defaultRequest = new PresentationRequest("https://example.com");
-
- navigator.presentation.defaultRequest.getAvailability().then(
- function(aAvailability) {
- is(aAvailability.value, false, "Sender: should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, "Device should be available.");
- aResolve();
- }
-
- gScript.sendAsyncMessage('trigger-device-add');
- },
- function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testStartConnection() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- });
-
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
- info("A control channel is established.");
- gScript.sendAsyncMessage('trigger-control-channel-open');
- });
-
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
- gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
- info("The control channel is opened.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- info("The control channel is closed. " + aReason);
- });
-
- gScript.addMessageListener('offer-sent', function offerSentHandler() {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- info("An offer is sent out.");
- gScript.sendAsyncMessage('trigger-incoming-transport');
- });
-
- gScript.addMessageListener('answer-received', function answerReceivedHandler() {
- gScript.removeMessageListener('answer-received', answerReceivedHandler);
- info("An answer is received.");
- });
-
- gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
- gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
- info("Data transport channel is initialized.");
- gScript.sendAsyncMessage('trigger-incoming-answer');
- });
-
- is(navigator.presentation.receiver, undefined, "Sender shouldn't get a presentation receiver instance.");
-
- navigator.presentation.defaultRequest.onconnectionavailable = function(aEvent) {
- navigator.presentation.defaultRequest.onconnectionavailable = null;
- connection = aEvent.connection;
- ok(connection, "|connectionavailable| event is fired with a connection.");
- ok(connection.id, "Connection ID should be set.");
- is(connection.state, "connecting", "The initial state should be connecting.");
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, "connected", "Connection should be connected.");
- aResolve();
- };
- };
-
- // Simulate the UA triggers |start()| of the default request.
- navigator.presentation.defaultRequest.start();
- });
-}
-
-function testCloseConnection() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- info("The data transport is closed. " + aReason);
- });
-
- connection.onclose = function() {
- connection.onclose = null;
- is(connection.state, "closed", "Connection should be closed.");
- aResolve();
- };
-
- connection.close();
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- ok(window.PresentationRequest, "PresentationRequest should be available.");
- ok(navigator.presentation, "navigator.presentation should be available.");
-
- testSetup().
- then(testStartConnection).
- then(testCloseConnection).
- then(teardown);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.receiver.enabled", false],
- ["dom.presentation.session_transport.data_channel.enable", false]]},
- runTests);
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_tcp_sender_disconnect.html b/dom/presentation/tests/mochitest/test_presentation_tcp_sender_disconnect.html
deleted file mode 100644
index a95da104f..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_sender_disconnect.html
+++ /dev/null
@@ -1,160 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for disconnection of B2G Presentation API at sender side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for disconnection of B2G Presentation API at sender side</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var request;
-var connection;
-
-function testSetup() {
- return new Promise(function(aResolve, aReject) {
- request = new PresentationRequest("http://example.com");
-
- request.getAvailability().then(
- function(aAvailability) {
- is(aAvailability.value, false, "Sender: should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, "Device should be available.");
- aResolve();
- }
-
- gScript.sendAsyncMessage('trigger-device-add');
- },
- function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testStartConnection() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- });
-
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
- info("A control channel is established.");
- gScript.sendAsyncMessage('trigger-control-channel-open');
- });
-
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
- gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
- info("The control channel is opened.");
- });
-
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- info("The control channel is closed. " + aReason);
- });
-
- gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- ok(aIsValid, "A valid offer is sent out.");
- gScript.sendAsyncMessage('trigger-incoming-answer');
- });
-
- gScript.addMessageListener('answer-received', function answerReceivedHandler() {
- gScript.removeMessageListener('answer-received', answerReceivedHandler);
- info("An answer is received.");
- gScript.sendAsyncMessage('trigger-incoming-transport');
- });
-
- gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
- gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
- info("Data transport channel is initialized.");
- });
-
- gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
- gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
- info("Data notification is enabled for data transport channel.");
- });
-
- request.start().then(
- function(aConnection) {
- connection = aConnection;
- ok(connection, "Connection should be available.");
- ok(connection.id, "Connection ID should be set.");
- is(connection.state, "connecting", "The initial state should be connecting.");
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, "connected", "Connection should be connected.");
- aResolve();
- };
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testDisconnection() {
- return new Promise(function(aResolve, aReject) {
- gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- info("The data transport is closed. " + aReason);
- });
-
- connection.onclose = function() {
- connection.onclose = null;
- is(connection.state, "closed", "Connection should be closed.");
- aResolve();
- };
-
- gScript.sendAsyncMessage('trigger-data-transport-close', SpecialPowers.Cr.NS_ERROR_FAILURE);
- });
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- ok(window.PresentationRequest, "PresentationRequest should be available.");
-
- testSetup().
- then(testStartConnection).
- then(testDisconnection).
- then(teardown);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", false]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html b/dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html
deleted file mode 100644
index 557ae71a6..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html
+++ /dev/null
@@ -1,514 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
-<head>
- <meta charset="utf-8">
- <title>Test for connection establishing errors of B2G Presentation API at sender side</title>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for connection establishing errors of B2G Presentation API at sender side</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
-var request;
-
-function setup() {
- return new Promise(function(aResolve, aReject) {
- request = new PresentationRequest("http://example.com");
-
- request.getAvailability().then(
- function(aAvailability) {
- is(aAvailability.value, false, "Sender: should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, "Device should be available.");
- aResolve();
- }
-
- gScript.sendAsyncMessage('trigger-device-add');
- },
- function(aError) {
- ok(false, "Error occurred when getting availability: " + aError);
- teardown();
- aReject();
- }
- );
- });
-}
-
-function testStartConnectionCancelPrompt() {
- info('--- testStartConnectionCancelPrompt ---');
- return Promise.all([
- new Promise((resolve) => {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-cancel', SpecialPowers.Cr.NS_ERROR_DOM_NOT_ALLOWED_ERR);
- resolve();
- });
- }),
- request.start().then(
- function(aConnection) {
- ok(false, "|start| shouldn't succeed in this case.");
- },
- function(aError) {
- is(aError.name, "NotAllowedError", "NotAllowedError is expected when the prompt is canceled.");
- }
- ),
- ]);
-}
-
-function testStartConnectionNoDevice() {
- info('--- testStartConnectionNoDevice ---');
- return Promise.all([
- new Promise((resolve) => {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-cancel', SpecialPowers.Cr.NS_ERROR_DOM_NOT_FOUND_ERR);
- resolve();
- });
- }),
- request.start().then(
- function(aConnection) {
- ok(false, "|start| shouldn't succeed in this case.");
- },
- function(aError) {
- is(aError.name, "NotFoundError", "NotFoundError is expected when no available device.");
- }
- ),
- ]);
-}
-
-function testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportInit() {
- info('--- testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportInit ---');
- return Promise.all([
-
- new Promise((resolve) => {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
- info("A control channel is established.");
- gScript.sendAsyncMessage('trigger-control-channel-open');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
- gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
- info("The control channel is opened.");
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- info("The control channel is closed. " + aReason);
- is(aReason, SpecialPowers.Cr.NS_ERROR_FAILURE, "The control channel is closed with NS_ERROR_FAILURE");
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- ok(aIsValid, "A valid offer is sent out.");
- gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_ERROR_FAILURE);
- resolve();
- });
- }),
-
- request.start().then(
- function(aConnection) {
- is(aConnection.state, "connecting", "The initial state should be connecting.");
- return new Promise((resolve) => {
- aConnection.onclose = function() {
- aConnection.onclose = null;
- is(aConnection.state, "closed", "Connection should be closed.");
- resolve();
- };
- });
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- }
- ),
-
- ]);
-}
-
-function testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportInit() {
- info('--- testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportInit ---');
- return Promise.all([
-
- new Promise((resolve) => {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
- info("A control channel is established.");
- gScript.sendAsyncMessage('trigger-control-channel-open');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
- gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
- info("The control channel is opened.");
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- info("The control channel is closed. " + aReason);
- is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed with NS_OK");
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- ok(aIsValid, "A valid offer is sent out.");
- gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_OK);
- resolve();
- });
- }),
-
- request.start().then(
- function(aConnection) {
- is(aConnection.state, "connecting", "The initial state should be connecting.");
- return new Promise((resolve) => {
- aConnection.onclose = function() {
- aConnection.onclose = null;
- is(aConnection.state, "closed", "Connection should be closed.");
- resolve();
- };
- });
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- }
- ),
-
- ]);
-}
-
-function testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportReady() {
- info('--- testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportReady ---');
- return Promise.all([
-
- new Promise((resolve) => {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
- info("A control channel is established.");
- gScript.sendAsyncMessage('trigger-control-channel-open');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
- gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
- info("The control channel is opened.");
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- is(aReason, SpecialPowers.Cr.NS_ERROR_ABORT, "The control channel is closed with NS_ERROR_ABORT");
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- ok(aIsValid, "A valid offer is sent out.");
- gScript.sendAsyncMessage('trigger-incoming-transport');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
- gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
- info("Data transport channel is initialized.");
- gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_ERROR_ABORT);
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- info("The data transport is closed. " + aReason);
- resolve();
- });
- }),
-
- request.start().then(
- function(aConnection) {
- is(aConnection.state, "connecting", "The initial state should be connecting.");
- return new Promise((resolve) => {
- aConnection.onclose = function() {
- aConnection.onclose = null;
- is(aConnection.state, "closed", "Connection should be closed.");
- resolve();
- };
- });
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- }
- ),
-
- ]);
-}
-
-function testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportReady() {
- info('--- testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportReady -- ');
- return Promise.all([
-
- new Promise((resolve) => {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
- info("A control channel is established.");
- gScript.sendAsyncMessage('trigger-control-channel-open');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
- gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
- info("The control channel is opened.");
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- info("The control channel is closed. " + aReason);
- is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed with NS_OK");
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- ok(aIsValid, "A valid offer is sent out.");
- gScript.sendAsyncMessage('trigger-incoming-transport');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
- gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
- info("Data transport channel is initialized.");
- gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_OK);
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- info("The data transport is closed. " + aReason);
- resolve();
- });
- }),
-
- request.start().then(
- function(aConnection) {
- is(aConnection.state, "connecting", "The initial state should be connecting.");
- return new Promise((resolve) => {
- aConnection.onclose = function() {
- aConnection.onclose = null;
- is(aConnection.state, "closed", "Connection should be closed.");
- resolve();
- };
- });
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- }
- ),
-
- ]);
-}
-
-function testStartConnectionUnexpectedDataTransportClose() {
- info('--- testStartConnectionUnexpectedDataTransportClose ---');
- return Promise.all([
-
- new Promise((resolve) => {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- info("Device prompt is triggered.");
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
- info("A control channel is established.");
- gScript.sendAsyncMessage('trigger-control-channel-open');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
- gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
- info("The control channel is opened.");
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
- gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
- info("The control channel is closed. " + aReason);
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
- gScript.removeMessageListener('offer-sent', offerSentHandler);
- ok(aIsValid, "A valid offer is sent out.");
- info("recv offer-sent.");
- gScript.sendAsyncMessage('trigger-incoming-transport');
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
- gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
- info("Data transport channel is initialized.");
- gScript.sendAsyncMessage('trigger-data-transport-close', SpecialPowers.Cr.NS_ERROR_UNEXPECTED);
- resolve();
- });
- }),
-
- new Promise((resolve) => {
- gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
- gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
- info("The data transport is closed. " + aReason);
- resolve();
- });
- }),
-
- request.start().then(
- function(aConnection) {
- is(aConnection.state, "connecting", "The initial state should be connecting.");
- return new Promise((resolve) => {
- aConnection.onclose = function() {
- aConnection.onclose = null;
- is(aConnection.state, "closed", "Connection should be closed.");
- resolve();
- };
- });
- },
- function(aError) {
- ok(false, "Error occurred when establishing a connection: " + aError);
- teardown();
- }
- ),
-
- ]);
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
-
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- ok(window.PresentationRequest, "PresentationRequest should be available.");
-
- setup().
- then(testStartConnectionCancelPrompt).
- then(testStartConnectionNoDevice).
- then(testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportInit).
- then(testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportInit).
- then(testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportReady).
- then(testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportReady).
- then(testStartConnectionUnexpectedDataTransportClose).
- then(teardown);
-}
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
-], function() {
- SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.session_transport.data_channel.enable", false]]},
- runTests);
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_terminate.js b/dom/presentation/tests/mochitest/test_presentation_terminate.js
deleted file mode 100644
index 8ebfd9d64..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_terminate.js
+++ /dev/null
@@ -1,243 +0,0 @@
-'use strict';
-
-SimpleTest.waitForExplicitFinish();
-SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event');
-
-function debug(str) {
- // info(str);
-}
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript1UA.js'));
-var receiverUrl = SimpleTest.getTestFileURL('file_presentation_terminate.html');
-var request;
-var connection;
-var receiverIframe;
-
-function setup() {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- debug('Got message: device-prompt');
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- });
-
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established',
- controlChannelEstablishedHandler);
- gScript.sendAsyncMessage('trigger-control-channel-open');
- });
-
- gScript.addMessageListener('sender-launch', function senderLaunchHandler(url) {
- debug('Got message: sender-launch');
- gScript.removeMessageListener('sender-launch', senderLaunchHandler);
- is(url, receiverUrl, 'Receiver: should receive the same url');
- receiverIframe = document.createElement('iframe');
- receiverIframe.setAttribute('mozbrowser', 'true');
- receiverIframe.setAttribute('mozpresentation', receiverUrl);
- var oop = location.pathname.indexOf('_inproc') == -1;
- receiverIframe.setAttribute('remote', oop);
-
- receiverIframe.setAttribute('src', receiverUrl);
- receiverIframe.addEventListener('mozbrowserloadend', function mozbrowserloadendHander() {
- receiverIframe.removeEventListener('mozbrowserloadend', mozbrowserloadendHander);
- info('Receiver loaded.');
- });
-
- // This event is triggered when the iframe calls 'alert'.
- receiverIframe.addEventListener('mozbrowsershowmodalprompt', function receiverListener(evt) {
- var message = evt.detail.message;
- if (/^OK /.exec(message)) {
- ok(true, message.replace(/^OK /, ''));
- } else if (/^KO /.exec(message)) {
- ok(false, message.replace(/^KO /, ''));
- } else if (/^INFO /.exec(message)) {
- info(message.replace(/^INFO /, ''));
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ''));
- gScript.sendAsyncMessage(command.name, command.data);
- } else if (/^DONE$/.exec(message)) {
- ok(true, 'Messaging from iframe complete.');
- receiverIframe.removeEventListener('mozbrowsershowmodalprompt',
- receiverListener);
- }
- }, false);
-
- var promise = new Promise(function(aResolve, aReject) {
- document.body.appendChild(receiverIframe);
- aResolve(receiverIframe);
- });
-
- var obs = SpecialPowers.Cc['@mozilla.org/observer-service;1']
- .getService(SpecialPowers.Ci.nsIObserverService);
- obs.notifyObservers(promise, 'setup-request-promise', null);
- });
-
- gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
- debug('Got message: promise-setup-ready');
- gScript.removeMessageListener('promise-setup-ready',
- promiseSetupReadyHandler);
- gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
- });
-
- return Promise.resolve();
-}
-
-function testCreateRequest() {
- return new Promise(function(aResolve, aReject) {
- info('Sender: --- testCreateRequest ---');
- request = new PresentationRequest(receiverUrl);
- request.getAvailability().then((aAvailability) => {
- is(aAvailability.value, false, "Sender: should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, 'Sender: Device should be available.');
- aResolve();
- }
-
- gScript.sendAsyncMessage('trigger-device-add');
- }).catch((aError) => {
- ok(false, 'Sender: Error occurred when getting availability: ' + aError);
- teardown();
- aReject();
- });
- });
-}
-
-function testStartConnection() {
- return new Promise(function(aResolve, aReject) {
- request.start().then((aConnection) => {
- connection = aConnection;
- ok(connection, 'Sender: Connection should be available.');
- ok(connection.id, 'Sender: Connection ID should be set.');
- is(connection.state, 'connecting', 'Sender: The initial state should be connecting.');
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, 'connected', 'Connection should be connected.');
- aResolve();
- };
-
- info('Sender: test terminate at connecting state');
- connection.onterminate = function() {
- connection.onterminate = null;
- ok(false, 'Should not be able to terminate at connecting state');
- aReject();
- }
- connection.terminate();
- }).catch((aError) => {
- ok(false, 'Sender: Error occurred when establishing a connection: ' + aError);
- teardown();
- aReject();
- });
- });
-}
-
-function testConnectionTerminate() {
- return new Promise(function(aResolve, aReject) {
- info('Sender: --- testConnectionTerminate---');
- connection.onterminate = function() {
- connection.onterminate = null;
- is(connection.state, 'terminated', 'Sender: Connection should be terminated.');
- };
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established',
- controlChannelEstablishedHandler);
- gScript.sendAsyncMessage('trigger-control-channel-open');
- });
- gScript.addMessageListener('sender-terminate', function senderTerminateHandler() {
- gScript.removeMessageListener('sender-terminate',
- senderTerminateHandler);
-
- Promise.all([
- new Promise((resolve) => {
- gScript.addMessageListener('device-disconnected', function deviceDisconnectedHandler() {
- gScript.removeMessageListener('device-disconnected', deviceDisconnectedHandler);
- ok(true, 'observe device disconnect');
- resolve();
- });
- }),
- new Promise((resolve) => {
- receiverIframe.addEventListener('mozbrowserclose', function() {
- ok(true, 'observe receiver page closing');
- resolve();
- });
- }),
- ]).then(aResolve);
-
- gScript.sendAsyncMessage('trigger-on-terminate-request');
- });
- gScript.addMessageListener('ready-to-terminate', function onReadyToTerminate() {
- gScript.removeMessageListener('ready-to-terminate', onReadyToTerminate);
- connection.terminate();
-
- // test unexpected close right after terminate
- connection.onclose = function() {
- ok(false, 'close after terminate should do nothing');
- };
- connection.close();
- });
- });
-}
-
-function testSendAfterTerminate() {
- return new Promise(function(aResolve, aReject) {
- try {
- connection.send('something');
- ok(false, 'PresentationConnection.send should be failed');
- } catch (e) {
- is(e.name, 'InvalidStateError', 'Must throw InvalidStateError');
- }
- aResolve();
- });
-}
-
-function testCloseAfterTerminate() {
- return Promise.race([
- new Promise(function(aResolve, aReject) {
- connection.onclose = function() {
- connection.onclose = null;
- ok(false, 'close at terminated state should do nothing');
- aResolve();
- };
- connection.close();
- }),
- new Promise(function(aResolve, aReject) {
- setTimeout(function() {
- is(connection.state, 'terminated', 'Sender: Connection should be terminated.');
- aResolve();
- }, 3000);
- }),
- ]);
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- debug('Got message: teardown-complete');
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- setup().then(testCreateRequest)
- .then(testStartConnection)
- .then(testConnectionTerminate)
- .then(testSendAfterTerminate)
- .then(testCloseAfterTerminate)
- .then(teardown);
-}
-
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
- {type: 'browser', allow: true, context: document},
-], () => {
- SpecialPowers.pushPrefEnv({ 'set': [['dom.presentation.enabled', true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.receiver.enabled", true],
- ['dom.presentation.test.enabled', true],
- ['dom.mozBrowserFramesEnabled', true],
- ["network.disable.ipc.security", true],
- ['dom.ipc.tabs.disabled', false],
- ['dom.presentation.test.stage', 0]]},
- runTests);
-});
diff --git a/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error.js b/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error.js
deleted file mode 100644
index a1d477aab..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error.js
+++ /dev/null
@@ -1,197 +0,0 @@
-'use strict';
-
-SimpleTest.waitForExplicitFinish();
-SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event');
-
-function debug(str) {
- // info(str);
-}
-
-var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript1UA.js'));
-var receiverUrl = SimpleTest.getTestFileURL('file_presentation_terminate_establish_connection_error.html');
-var request;
-var connection;
-var receiverIframe;
-
-function postMessageToIframe(aType) {
- receiverIframe.src = receiverUrl + "#" +
- encodeURIComponent(JSON.stringify({ type: aType }));
-}
-
-function setup() {
- gScript.addMessageListener('device-prompt', function devicePromptHandler() {
- debug('Got message: device-prompt');
- gScript.removeMessageListener('device-prompt', devicePromptHandler);
- gScript.sendAsyncMessage('trigger-device-prompt-select');
- });
-
- gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
- gScript.removeMessageListener('control-channel-established',
- controlChannelEstablishedHandler);
- gScript.sendAsyncMessage('trigger-control-channel-open');
- });
-
- gScript.addMessageListener('sender-launch', function senderLaunchHandler(url) {
- debug('Got message: sender-launch');
- gScript.removeMessageListener('sender-launch', senderLaunchHandler);
- is(url, receiverUrl, 'Receiver: should receive the same url');
- receiverIframe = document.createElement('iframe');
- receiverIframe.setAttribute('mozbrowser', 'true');
- receiverIframe.setAttribute('mozpresentation', receiverUrl);
- var oop = location.pathname.indexOf('_inproc') == -1;
- receiverIframe.setAttribute('remote', oop);
-
- receiverIframe.setAttribute('src', receiverUrl);
- receiverIframe.addEventListener('mozbrowserloadend', function mozbrowserloadendHander() {
- receiverIframe.removeEventListener('mozbrowserloadend', mozbrowserloadendHander);
- info('Receiver loaded.');
- });
-
- // This event is triggered when the iframe calls 'alert'.
- receiverIframe.addEventListener('mozbrowsershowmodalprompt', function receiverListener(evt) {
- var message = evt.detail.message;
- if (/^OK /.exec(message)) {
- ok(true, message.replace(/^OK /, ''));
- } else if (/^KO /.exec(message)) {
- ok(false, message.replace(/^KO /, ''));
- } else if (/^INFO /.exec(message)) {
- info(message.replace(/^INFO /, ''));
- } else if (/^COMMAND /.exec(message)) {
- var command = JSON.parse(message.replace(/^COMMAND /, ''));
- gScript.sendAsyncMessage(command.name, command.data);
- } else if (/^DONE$/.exec(message)) {
- ok(true, 'Messaging from iframe complete.');
- receiverIframe.removeEventListener('mozbrowsershowmodalprompt',
- receiverListener);
- }
- }, false);
-
- var promise = new Promise(function(aResolve, aReject) {
- document.body.appendChild(receiverIframe);
- aResolve(receiverIframe);
- });
-
- var obs = SpecialPowers.Cc['@mozilla.org/observer-service;1']
- .getService(SpecialPowers.Ci.nsIObserverService);
- obs.notifyObservers(promise, 'setup-request-promise', null);
- });
-
- gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
- debug('Got message: promise-setup-ready');
- gScript.removeMessageListener('promise-setup-ready',
- promiseSetupReadyHandler);
- gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
- });
-
- return Promise.resolve();
-}
-
-function testCreateRequest() {
- return new Promise(function(aResolve, aReject) {
- info('Sender: --- testCreateRequest ---');
- request = new PresentationRequest(receiverUrl);
- request.getAvailability().then((aAvailability) => {
- is(aAvailability.value, false, "Sender: should have no available device after setup");
- aAvailability.onchange = function() {
- aAvailability.onchange = null;
- ok(aAvailability.value, 'Sender: Device should be available.');
- aResolve();
- }
-
- gScript.sendAsyncMessage('trigger-device-add');
- }).catch((aError) => {
- ok(false, 'Sender: Error occurred when getting availability: ' + aError);
- teardown();
- aReject();
- });
- });
-}
-
-function testStartConnection() {
- return new Promise(function(aResolve, aReject) {
- request.start().then((aConnection) => {
- connection = aConnection;
- ok(connection, 'Sender: Connection should be available.');
- ok(connection.id, 'Sender: Connection ID should be set.');
- is(connection.state, 'connecting', 'Sender: The initial state should be connecting.');
- connection.onconnect = function() {
- connection.onconnect = null;
- is(connection.state, 'connected', 'Connection should be connected.');
- aResolve();
- };
- }).catch((aError) => {
- ok(false, 'Sender: Error occurred when establishing a connection: ' + aError);
- teardown();
- aReject();
- });
- });
-}
-
-function testConnectionTerminate() {
- info('Sender: --- testConnectionTerminate---');
- let promise = Promise.all([
- new Promise(function(aResolve, aReject) {
- connection.onclose = function() {
- connection.onclose = null;
- is(connection.state, 'closed', 'Sender: Connection should be closed.');
- aResolve();
- };
- }),
- new Promise(function(aResolve, aReject) {
- function deviceDisconnectedHandler() {
- gScript.removeMessageListener('device-disconnected', deviceDisconnectedHandler);
- ok(true, 'should not receive device disconnect');
- aResolve();
- }
-
- gScript.addMessageListener('device-disconnected', deviceDisconnectedHandler);
- }),
- new Promise(function(aResolve, aReject) {
- receiverIframe.addEventListener('mozbrowserclose', function() {
- ok(true, 'observe receiver page closing');
- aResolve();
- });
- })
- ]);
-
- gScript.addMessageListener('prepare-for-terminate', function prepareForTerminateHandler() {
- debug('Got message: prepare-for-terminate');
- gScript.removeMessageListener('prepare-for-terminate', prepareForTerminateHandler);
- gScript.sendAsyncMessage('trigger-control-channel-error');
- postMessageToIframe('ready-to-terminate');
- });
-
- return promise;
-}
-
-function teardown() {
- gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
- debug('Got message: teardown-complete');
- gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
- gScript.destroy();
- SimpleTest.finish();
- });
- gScript.sendAsyncMessage('teardown');
-}
-
-function runTests() {
- setup().then(testCreateRequest)
- .then(testStartConnection)
- .then(testConnectionTerminate)
- .then(teardown);
-}
-
-SpecialPowers.pushPermissions([
- {type: 'presentation-device-manage', allow: false, context: document},
- {type: 'browser', allow: true, context: document},
-], () => {
- SpecialPowers.pushPrefEnv({ 'set': [['dom.presentation.enabled', true],
- ["dom.presentation.controller.enabled", true],
- ["dom.presentation.receiver.enabled", true],
- ['dom.presentation.test.enabled', true],
- ['dom.mozBrowserFramesEnabled', true],
- ["network.disable.ipc.security", true],
- ['dom.ipc.tabs.disabled', false],
- ['dom.presentation.test.stage', 0]]},
- runTests);
-});
diff --git a/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error_inproc.html b/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error_inproc.html
deleted file mode 100644
index ccf0767f1..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error_inproc.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
- <head>
- <meta charset='utf-8'>
- <title>Test for control channel establish error during PresentationConnection.terminate()</title>
- <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
- <script type='application/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
- </head>
- <body>
- <a target='_blank' href='https://bugzilla.mozilla.org/show_bug.cgi?id=1289292'>
- Test for constrol channel establish error during PresentationConnection.terminate()</a>
- <script type='application/javascript;version=1.8' src='test_presentation_terminate_establish_connection_error.js'>
- </script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error_oop.html b/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error_oop.html
deleted file mode 100644
index ccf0767f1..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error_oop.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
- <head>
- <meta charset='utf-8'>
- <title>Test for control channel establish error during PresentationConnection.terminate()</title>
- <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
- <script type='application/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
- </head>
- <body>
- <a target='_blank' href='https://bugzilla.mozilla.org/show_bug.cgi?id=1289292'>
- Test for constrol channel establish error during PresentationConnection.terminate()</a>
- <script type='application/javascript;version=1.8' src='test_presentation_terminate_establish_connection_error.js'>
- </script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_terminate_inproc.html b/dom/presentation/tests/mochitest/test_presentation_terminate_inproc.html
deleted file mode 100644
index 33bbcda57..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_terminate_inproc.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
- <head>
- <meta charset='utf-8'>
- <title>Test for PresentationConnection.terminate()</title>
- <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
- <script type='application/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
- </head>
- <body>
- <a target='_blank' href='https://bugzilla.mozilla.org/show_bug.cgi?id=1276378'>
- Test for PresentationConnection.terminate()</a>
- <script type='application/javascript;version=1.8' src='test_presentation_terminate.js'>
- </script>
- </body>
-</html>
diff --git a/dom/presentation/tests/mochitest/test_presentation_terminate_oop.html b/dom/presentation/tests/mochitest/test_presentation_terminate_oop.html
deleted file mode 100644
index 33bbcda57..000000000
--- a/dom/presentation/tests/mochitest/test_presentation_terminate_oop.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE HTML>
-<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
-<html>
- <!-- Any copyright is dedicated to the Public Domain.
- - http://creativecommons.org/publicdomain/zero/1.0/ -->
- <head>
- <meta charset='utf-8'>
- <title>Test for PresentationConnection.terminate()</title>
- <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
- <script type='application/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
- </head>
- <body>
- <a target='_blank' href='https://bugzilla.mozilla.org/show_bug.cgi?id=1276378'>
- Test for PresentationConnection.terminate()</a>
- <script type='application/javascript;version=1.8' src='test_presentation_terminate.js'>
- </script>
- </body>
-</html>
diff --git a/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js b/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js
deleted file mode 100644
index 137a5609a..000000000
--- a/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js
+++ /dev/null
@@ -1,1318 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-/* global Services, do_register_cleanup, do_test_pending */
-
-"use strict";
-
-const { classes: Cc, interfaces: Ci, manager: Cm, results: Cr, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/Promise.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-const INFO_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-info;1";
-const PROVIDER_CONTRACT_ID = "@mozilla.org/presentation-device/multicastdns-provider;1";
-const SD_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-sd;1";
-const UUID_CONTRACT_ID = "@mozilla.org/uuid-generator;1";
-const SERVER_CONTRACT_ID = "@mozilla.org/presentation/control-service;1";
-
-const PREF_DISCOVERY = "dom.presentation.discovery.enabled";
-const PREF_DISCOVERABLE = "dom.presentation.discoverable";
-const PREF_DEVICENAME= "dom.presentation.device.name";
-
-const LATEST_VERSION = 1;
-const SERVICE_TYPE = "_presentation-ctrl._tcp";
-const versionAttr = Cc["@mozilla.org/hash-property-bag;1"]
- .createInstance(Ci.nsIWritablePropertyBag2);
-versionAttr.setPropertyAsUint32("version", LATEST_VERSION);
-
-var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
-
-function sleep(aMs) {
- let deferred = Promise.defer();
-
- let timer = Cc["@mozilla.org/timer;1"]
- .createInstance(Ci.nsITimer);
-
- timer.initWithCallback({
- notify: function () {
- deferred.resolve();
- },
- }, aMs, timer.TYPE_ONE_SHOT);
-
- return deferred.promise;
-}
-
-function MockFactory(aClass) {
- this._cls = aClass;
-}
-MockFactory.prototype = {
- createInstance: function(aOuter, aIID) {
- if (aOuter) {
- throw Cr.NS_ERROR_NO_AGGREGATION;
- }
- switch(typeof(this._cls)) {
- case "function":
- return new this._cls().QueryInterface(aIID);
- case "object":
- return this._cls.QueryInterface(aIID);
- default:
- return null;
- }
- },
- lockFactory: function(aLock) {
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
-};
-
-function ContractHook(aContractID, aClass) {
- this._contractID = aContractID;
- this.classID = Cc[UUID_CONTRACT_ID].getService(Ci.nsIUUIDGenerator).generateUUID();
- this._newFactory = new MockFactory(aClass);
-
- if (!this.hookedMap.has(this._contractID)) {
- this.hookedMap.set(this._contractID, []);
- }
-
- this.init();
-}
-
-ContractHook.prototype = {
- hookedMap: new Map(), // remember only the most original factory.
-
- init: function() {
- this.reset();
-
- let oldContract = this.unregister();
- this.hookedMap.get(this._contractID).push(oldContract);
- registrar.registerFactory(this.classID,
- "",
- this._contractID,
- this._newFactory);
-
- do_register_cleanup(() => { this.cleanup.apply(this); });
- },
-
- reset: function() {},
-
- cleanup: function() {
- this.reset();
-
- this.unregister();
- let prevContract = this.hookedMap.get(this._contractID).pop();
-
- if (prevContract.factory) {
- registrar.registerFactory(prevContract.classID,
- "",
- this._contractID,
- prevContract.factory);
- }
- },
-
- unregister: function() {
- var classID, factory;
-
- try {
- classID = registrar.contractIDToCID(this._contractID);
- factory = Cm.getClassObject(Cc[this._contractID], Ci.nsIFactory);
- } catch (ex) {
- classID = "";
- factory = null;
- }
-
- if (factory) {
- registrar.unregisterFactory(classID, factory);
- }
-
- return { classID: classID, factory: factory };
- }
-};
-
-function MockDNSServiceInfo() {}
-MockDNSServiceInfo.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceInfo]),
-
- set host(aHost) {
- this._host = aHost;
- },
-
- get host() {
- return this._host;
- },
-
- set address(aAddress) {
- this._address = aAddress;
- },
-
- get address() {
- return this._address;
- },
-
- set port(aPort) {
- this._port = aPort;
- },
-
- get port() {
- return this._port;
- },
-
- set serviceName(aServiceName) {
- this._serviceName = aServiceName;
- },
-
- get serviceName() {
- return this._serviceName;
- },
-
- set serviceType(aServiceType) {
- this._serviceType = aServiceType;
- },
-
- get serviceType() {
- return this._serviceType;
- },
-
- set domainName(aDomainName) {
- this._domainName = aDomainName;
- },
-
- get domainName() {
- return this._domainName;
- },
-
- set attributes(aAttributes) {
- this._attributes = aAttributes;
- },
-
- get attributes() {
- return this._attributes;
- }
-};
-
-function TestPresentationDeviceListener() {
- this.devices = {};
-}
-TestPresentationDeviceListener.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
- Ci.nsISupportsWeakReference]),
-
- addDevice: function(device) { this.devices[device.id] = device; },
- removeDevice: function(device) { delete this.devices[device.id]; },
- updateDevice: function(device) { this.devices[device.id] = device; },
- onSessionRequest: function(device, url, presentationId, controlChannel) {},
-
- count: function() {
- var size = 0, key;
- for (key in this.devices) {
- if (this.devices.hasOwnProperty(key)) {
- ++size;
- }
- }
- return size;
- }
-};
-
-function createDevice(host, port, serviceName, serviceType, domainName, attributes) {
- let device = new MockDNSServiceInfo();
- device.host = host || "";
- device.port = port || 0;
- device.address = host || "";
- device.serviceName = serviceName || "";
- device.serviceType = serviceType || "";
- device.domainName = domainName || "";
- device.attributes = attributes || versionAttr;
- return device;
-}
-
-function registerService() {
- Services.prefs.setBoolPref(PREF_DISCOVERABLE, true);
-
- let deferred = Promise.defer();
-
- let mockObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {},
- registerService: function(serviceInfo, listener) {
- deferred.resolve();
- this.serviceRegistered++;
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {
- this.serviceUnregistered++;
- }.bind(this)
- };
- },
- resolveService: function(serviceInfo, listener) {},
- serviceRegistered: 0,
- serviceUnregistered: 0
- };
- let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
-
- Assert.equal(mockObj.serviceRegistered, 0);
- Assert.equal(mockObj.serviceUnregistered, 0);
-
- // Register
- provider.listener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
- Ci.nsISupportsWeakReference]),
- addDevice: function(device) {},
- removeDevice: function(device) {},
- updateDevice: function(device) {},
- };
-
- deferred.promise.then(function() {
- Assert.equal(mockObj.serviceRegistered, 1);
- Assert.equal(mockObj.serviceUnregistered, 0);
-
- // Unregister
- provider.listener = null;
- Assert.equal(mockObj.serviceRegistered, 1);
- Assert.equal(mockObj.serviceUnregistered, 1);
-
- run_next_test();
- });
-}
-
-function noRegisterService() {
- Services.prefs.setBoolPref(PREF_DISCOVERABLE, false);
-
- let deferred = Promise.defer();
-
- let mockObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {},
- registerService: function(serviceInfo, listener) {
- deferred.resolve();
- Assert.ok(false, "should not register service if not discoverable");
- },
- resolveService: function(serviceInfo, listener) {},
- };
-
- let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
-
- // Try register
- provider.listener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
- Ci.nsISupportsWeakReference]),
- addDevice: function(device) {},
- removeDevice: function(device) {},
- updateDevice: function(device) {},
- };
-
- let race = Promise.race([
- deferred.promise,
- sleep(1000),
- ]);
-
- race.then(() => {
- provider.listener = null;
-
- run_next_test();
- });
-}
-
-function registerServiceDynamically() {
- Services.prefs.setBoolPref(PREF_DISCOVERABLE, false);
-
- let deferred = Promise.defer();
-
- let mockObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {},
- registerService: function(serviceInfo, listener) {
- deferred.resolve();
- this.serviceRegistered++;
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {
- this.serviceUnregistered++;
- }.bind(this)
- };
- },
- resolveService: function(serviceInfo, listener) {},
- serviceRegistered: 0,
- serviceUnregistered: 0
- };
- let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
-
- Assert.equal(mockObj.serviceRegistered, 0);
- Assert.equal(mockObj.serviceRegistered, 0);
-
- // Try Register
- provider.listener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
- Ci.nsISupportsWeakReference]),
- addDevice: function(device) {},
- removeDevice: function(device) {},
- updateDevice: function(device) {},
- };
-
- Assert.equal(mockObj.serviceRegistered, 0);
- Assert.equal(mockObj.serviceUnregistered, 0);
-
- // Enable registration
- Services.prefs.setBoolPref(PREF_DISCOVERABLE, true);
-
- deferred.promise.then(function() {
- Assert.equal(mockObj.serviceRegistered, 1);
- Assert.equal(mockObj.serviceUnregistered, 0);
-
- // Disable registration
- Services.prefs.setBoolPref(PREF_DISCOVERABLE, false);
- Assert.equal(mockObj.serviceRegistered, 1);
- Assert.equal(mockObj.serviceUnregistered, 1);
-
- // Try unregister
- provider.listener = null;
- Assert.equal(mockObj.serviceRegistered, 1);
- Assert.equal(mockObj.serviceUnregistered, 1);
-
- run_next_test();
- });
-}
-
-function addDevice() {
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
-
- let mockDevice = createDevice("device.local",
- 12345,
- "service.name",
- SERVICE_TYPE);
- let mockObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {
- listener.onDiscoveryStarted(serviceType);
- listener.onServiceFound(createDevice("",
- 0,
- mockDevice.serviceName,
- mockDevice.serviceType));
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {}
- };
- },
- registerService: function(serviceInfo, listener) {},
- resolveService: function(serviceInfo, listener) {
- Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
- Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
- listener.onServiceResolved(createDevice(mockDevice.host,
- mockDevice.port,
- mockDevice.serviceName,
- mockDevice.serviceType));
- }
- };
-
- let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
- let listener = new TestPresentationDeviceListener();
- Assert.equal(listener.count(), 0);
-
- // Start discovery
- provider.listener = listener;
- Assert.equal(listener.count(), 1);
-
- // Force discovery again
- provider.forceDiscovery();
- Assert.equal(listener.count(), 1);
-
- provider.listener = null;
- Assert.equal(listener.count(), 1);
-
- run_next_test();
-}
-
-function filterDevice() {
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
-
- let mockDevice = createDevice("device.local",
- 12345,
- "service.name",
- SERVICE_TYPE);
- let mockObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {
- listener.onDiscoveryStarted(serviceType);
- listener.onServiceFound(createDevice("",
- 0,
- mockDevice.serviceName,
- mockDevice.serviceType));
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {}
- };
- },
- registerService: function(serviceInfo, listener) {},
- resolveService: function(serviceInfo, listener) {
- Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
- Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
- listener.onServiceResolved(createDevice(mockDevice.host,
- mockDevice.port,
- mockDevice.serviceName,
- mockDevice.serviceType));
- }
- };
-
- let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
- let listener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
- Ci.nsISupportsWeakReference]),
- addDevice: function(device) {
- let tests = [
- { requestedUrl: "app://fling-player.gaiamobile.org/index.html", supported: true },
- { requestedUrl: "app://notification-receiver.gaiamobile.org/index.html", supported: true },
- { requestedUrl: "http://example.com", supported: true },
- { requestedUrl: "https://example.com", supported: true },
- { requestedUrl: "ftp://example.com", supported: false },
- { requestedUrl: "app://unknown-app-id", supported: false },
- { requestedUrl: "unknowSchem://example.com", supported: false },
- ];
-
- for (let test of tests) {
- Assert.equal(device.isRequestedUrlSupported(test.requestedUrl), test.supported);
- }
-
- provider.listener = null;
- run_next_test();
- },
- updateDevice: function() {},
- removeDevice: function() {},
- onSessionRequest: function() {},
- };
-
- provider.listener = listener;
-}
-
-function handleSessionRequest() {
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
- Services.prefs.setBoolPref(PREF_DISCOVERABLE, false);
-
- const testUrl = "http://example.com";
- const testPresentationId = "test-presentation-id";
- const testDeviceName = "test-device-name";
-
- Services.prefs.setCharPref(PREF_DEVICENAME, testDeviceName);
-
- let mockDevice = createDevice("device.local",
- 12345,
- "service.name",
- SERVICE_TYPE);
- let mockSDObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {
- listener.onDiscoveryStarted(serviceType);
- listener.onServiceFound(createDevice("",
- 0,
- mockDevice.serviceName,
- mockDevice.serviceType));
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {}
- };
- },
- registerService: function(serviceInfo, listener) {},
- resolveService: function(serviceInfo, listener) {
- listener.onServiceResolved(createDevice(mockDevice.host,
- mockDevice.port,
- mockDevice.serviceName,
- mockDevice.serviceType));
- }
- };
-
- let mockServerObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
- connect: function(deviceInfo) {
- this.request = {
- deviceInfo: deviceInfo,
- };
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
- };
- },
- id: "",
- version: LATEST_VERSION,
- isCompatibleServer: function(version) {
- return this.version === version;
- }
- };
-
- let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
- let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
- let listener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
- Ci.nsISupportsWeakReference]),
- addDevice: function(device) {
- this.device = device;
- },
- };
-
- provider.listener = listener;
-
- let controlChannel = listener.device.establishControlChannel();
-
- Assert.equal(mockServerObj.request.deviceInfo.id, mockDevice.host);
- Assert.equal(mockServerObj.request.deviceInfo.address, mockDevice.host);
- Assert.equal(mockServerObj.request.deviceInfo.port, mockDevice.port);
- Assert.equal(mockServerObj.id, testDeviceName);
-
- provider.listener = null;
-
- run_next_test();
-}
-
-function handleOnSessionRequest() {
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
- Services.prefs.setBoolPref(PREF_DISCOVERABLE, true);
-
- let mockDevice = createDevice("device.local",
- 12345,
- "service.name",
- SERVICE_TYPE);
- let mockSDObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {
- listener.onDiscoveryStarted(serviceType);
- listener.onServiceFound(createDevice("",
- 0,
- mockDevice.serviceName,
- mockDevice.serviceType));
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {}
- };
- },
- registerService: function(serviceInfo, listener) {},
- resolveService: function(serviceInfo, listener) {
- listener.onServiceResolved(createDevice(mockDevice.host,
- mockDevice.port,
- mockDevice.serviceName,
- mockDevice.serviceType));
- }
- };
-
- let mockServerObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
- startServer: function() {},
- sessionRequest: function() {},
- close: function() {},
- id: '',
- version: LATEST_VERSION,
- port: 0,
- listener: null,
- };
-
- let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
- let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
- let listener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
- Ci.nsISupportsWeakReference]),
- addDevice: function(device) {},
- removeDevice: function(device) {},
- updateDevice: function(device) {},
- onSessionRequest: function(device, url, presentationId, controlChannel) {
- Assert.ok(true, "receive onSessionRequest event");
- this.request = {
- deviceId: device.id,
- url: url,
- presentationId: presentationId,
- };
- }
- };
-
- provider.listener = listener;
-
- const deviceInfo = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
- id: mockDevice.host,
- address: mockDevice.host,
- port: 54321,
- };
-
- const testUrl = "http://example.com";
- const testPresentationId = "test-presentation-id";
- const testControlChannel = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
- };
- provider.QueryInterface(Ci.nsIPresentationControlServerListener)
- .onSessionRequest(deviceInfo, testUrl, testPresentationId, testControlChannel);
-
- Assert.equal(listener.request.deviceId, deviceInfo.id);
- Assert.equal(listener.request.url, testUrl);
- Assert.equal(listener.request.presentationId, testPresentationId);
-
- provider.listener = null;
-
- run_next_test();
-}
-
-function handleOnSessionRequestFromUnknownDevice() {
- Services.prefs.setBoolPref(PREF_DISCOVERY, false);
- Services.prefs.setBoolPref(PREF_DISCOVERABLE, true);
-
- let mockSDObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {},
- registerService: function(serviceInfo, listener) {},
- resolveService: function(serviceInfo, listener) {}
- };
-
- let mockServerObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
- startServer: function() {},
- sessionRequest: function() {},
- close: function() {},
- id: '',
- version: LATEST_VERSION,
- port: 0,
- listener: null,
- };
-
- let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
- let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
- let listener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
- Ci.nsISupportsWeakReference]),
- addDevice: function(device) {
- Assert.ok(false, "shouldn't create any new device");
- },
- removeDevice: function(device) {
- Assert.ok(false, "shouldn't remote any device");
- },
- updateDevice: function(device) {
- Assert.ok(false, "shouldn't update any device");
- },
- onSessionRequest: function(device, url, presentationId, controlChannel) {
- Assert.ok(true, "receive onSessionRequest event");
- this.request = {
- deviceId: device.id,
- url: url,
- presentationId: presentationId,
- };
- }
- };
-
- provider.listener = listener;
-
- const deviceInfo = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
- id: "unknown-device.local",
- address: "unknown-device.local",
- port: 12345,
- };
-
- const testUrl = "http://example.com";
- const testPresentationId = "test-presentation-id";
- const testControlChannel = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
- };
- provider.QueryInterface(Ci.nsIPresentationControlServerListener)
- .onSessionRequest(deviceInfo, testUrl, testPresentationId, testControlChannel);
-
- Assert.equal(listener.request.deviceId, deviceInfo.id);
- Assert.equal(listener.request.url, testUrl);
- Assert.equal(listener.request.presentationId, testPresentationId);
-
- provider.listener = null;
-
- run_next_test();
-}
-
-function noAddDevice() {
- Services.prefs.setBoolPref(PREF_DISCOVERY, false);
-
- let mockDevice = createDevice("device.local", 12345, "service.name", SERVICE_TYPE);
- let mockObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {
- Assert.ok(false, "shouldn't perform any device discovery");
- },
- registerService: function(serviceInfo, listener) {},
- resolveService: function(serviceInfo, listener) {
- }
- };
- let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
-
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
- let listener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
- Ci.nsISupportsWeakReference]),
- addDevice: function(device) {},
- removeDevice: function(device) {},
- updateDevice: function(device) {},
- };
- provider.listener = listener;
- provider.forceDiscovery();
- provider.listener = null;
-
- run_next_test();
-}
-
-function ignoreIncompatibleDevice() {
- Services.prefs.setBoolPref(PREF_DISCOVERY, false);
- Services.prefs.setBoolPref(PREF_DISCOVERABLE, true);
-
- let mockDevice = createDevice("device.local",
- 12345,
- "service.name",
- SERVICE_TYPE);
-
- let deferred = Promise.defer();
-
- let mockSDObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {
- listener.onDiscoveryStarted(serviceType);
- listener.onServiceFound(createDevice("",
- 0,
- mockDevice.serviceName,
- mockDevice.serviceType));
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {}
- };
- },
- registerService: function(serviceInfo, listener) {
- deferred.resolve();
- listener.onServiceRegistered(createDevice("",
- 54321,
- mockDevice.serviceName,
- mockDevice.serviceType));
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {}
- };
- },
- resolveService: function(serviceInfo, listener) {
- Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
- Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
- listener.onServiceResolved(createDevice(mockDevice.host,
- mockDevice.port,
- mockDevice.serviceName,
- mockDevice.serviceType));
- }
- };
-
- let mockServerObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
- startServer: function() {
- Services.tm.currentThread.dispatch(() => {
- this.listener.onServerReady(this.port, this.certFingerprint);
- }, Ci.nsIThread.DISPATCH_NORMAL);
- },
- sessionRequest: function() {},
- close: function() {},
- id: '',
- version: LATEST_VERSION,
- isCompatibleServer: function(version) {
- return false;
- },
- port: 54321,
- certFingerprint: 'mock-cert-fingerprint',
- listener: null,
- };
-
- let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
- let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
- let listener = new TestPresentationDeviceListener();
-
- // Register service
- provider.listener = listener;
-
- deferred.promise.then(function() {
- Assert.equal(mockServerObj.id, mockDevice.host);
-
- // Start discovery
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
- Assert.equal(listener.count(), 0);
-
- provider.listener = null;
-
- run_next_test();
- });
-}
-
-function ignoreSelfDevice() {
- Services.prefs.setBoolPref(PREF_DISCOVERY, false);
- Services.prefs.setBoolPref(PREF_DISCOVERABLE, true);
-
- let mockDevice = createDevice("device.local",
- 12345,
- "service.name",
- SERVICE_TYPE);
-
- let deferred = Promise.defer();
- let mockSDObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {
- listener.onDiscoveryStarted(serviceType);
- listener.onServiceFound(createDevice("",
- 0,
- mockDevice.serviceName,
- mockDevice.serviceType));
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {}
- };
- },
- registerService: function(serviceInfo, listener) {
- deferred.resolve();
- listener.onServiceRegistered(createDevice("",
- 0,
- mockDevice.serviceName,
- mockDevice.serviceType));
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {}
- };
- },
- resolveService: function(serviceInfo, listener) {
- Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
- Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
- listener.onServiceResolved(createDevice(mockDevice.host,
- mockDevice.port,
- mockDevice.serviceName,
- mockDevice.serviceType));
- }
- };
-
- let mockServerObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
- startServer: function() {
- Services.tm.currentThread.dispatch(() => {
- this.listener.onServerReady(this.port, this.certFingerprint);
- }, Ci.nsIThread.DISPATCH_NORMAL);
- },
- sessionRequest: function() {},
- close: function() {},
- id: '',
- version: LATEST_VERSION,
- isCompatibleServer: function(version) {
- return this.version === version;
- },
- port: 54321,
- certFingerprint: 'mock-cert-fingerprint',
- listener: null,
- };
-
- let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
- let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
- let listener = new TestPresentationDeviceListener();
-
- // Register service
- provider.listener = listener;
- deferred.promise.then(() => {
- Assert.equal(mockServerObj.id, mockDevice.host);
-
- // Start discovery
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
- Assert.equal(listener.count(), 0);
-
- provider.listener = null;
-
- run_next_test();
- });
-}
-
-function addDeviceDynamically() {
- Services.prefs.setBoolPref(PREF_DISCOVERY, false);
-
- let mockDevice = createDevice("device.local",
- 12345,
- "service.name",
- SERVICE_TYPE);
- let mockObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {
- listener.onDiscoveryStarted(serviceType);
- listener.onServiceFound(createDevice("",
- 0,
- mockDevice.serviceName,
- mockDevice.serviceType));
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {}
- };
- },
- registerService: function(serviceInfo, listener) {},
- resolveService: function(serviceInfo, listener) {
- Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
- Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
- listener.onServiceResolved(createDevice(mockDevice.host,
- mockDevice.port,
- mockDevice.serviceName,
- mockDevice.serviceType));
- }
- };
-
- let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
- let listener = new TestPresentationDeviceListener();
- provider.listener = listener;
- Assert.equal(listener.count(), 0);
-
- // Enable discovery
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
- Assert.equal(listener.count(), 1);
-
- // Try discovery again
- provider.forceDiscovery();
- Assert.equal(listener.count(), 1);
-
- // Try discovery once more
- Services.prefs.setBoolPref(PREF_DISCOVERY, false);
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
- provider.forceDiscovery();
- Assert.equal(listener.count(), 1);
-
- provider.listener = null;
-
- run_next_test();
-}
-
-function updateDevice() {
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
-
- let mockDevice1 = createDevice("A.local", 12345, "N1", SERVICE_TYPE);
- let mockDevice2 = createDevice("A.local", 23456, "N2", SERVICE_TYPE);
-
- let mockObj = {
- discovered: false,
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {
- listener.onDiscoveryStarted(serviceType);
-
- if (!this.discovered) {
- listener.onServiceFound(mockDevice1);
- } else {
- listener.onServiceFound(mockDevice2);
- }
- this.discovered = true;
-
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {
- listener.onDiscoveryStopped(serviceType);
- }
- };
- },
- registerService: function(serviceInfo, listener) {},
- resolveService: function(serviceInfo, listener) {
- Assert.equal(serviceInfo.serviceType, SERVICE_TYPE);
- if (serviceInfo.serviceName == "N1") {
- listener.onServiceResolved(mockDevice1);
- } else if (serviceInfo.serviceName == "N2") {
- listener.onServiceResolved(mockDevice2);
- } else {
- Assert.ok(false);
- }
- }
- };
-
- let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
- let listener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
- Ci.nsISupportsWeakReference]),
-
- addDevice: function(device) {
- Assert.ok(!this.isDeviceAdded);
- Assert.equal(device.id, mockDevice1.host);
- Assert.equal(device.name, mockDevice1.serviceName);
- this.isDeviceAdded = true;
- },
- removeDevice: function(device) { Assert.ok(false); },
- updateDevice: function(device) {
- Assert.ok(!this.isDeviceUpdated);
- Assert.equal(device.id, mockDevice2.host);
- Assert.equal(device.name, mockDevice2.serviceName);
- this.isDeviceUpdated = true;
- },
-
- isDeviceAdded: false,
- isDeviceUpdated: false
- };
- Assert.equal(listener.isDeviceAdded, false);
- Assert.equal(listener.isDeviceUpdated, false);
-
- // Start discovery
- provider.listener = listener; // discover: N1
-
- Assert.equal(listener.isDeviceAdded, true);
- Assert.equal(listener.isDeviceUpdated, false);
-
- // temporarily disable to stop discovery and re-enable
- Services.prefs.setBoolPref(PREF_DISCOVERY, false);
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
-
- provider.forceDiscovery(); // discover: N2
-
- Assert.equal(listener.isDeviceAdded, true);
- Assert.equal(listener.isDeviceUpdated, true);
-
- provider.listener = null;
-
- run_next_test();
-}
-
-function diffDiscovery() {
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
-
- let mockDevice1 = createDevice("A.local", 12345, "N1", SERVICE_TYPE);
- let mockDevice2 = createDevice("B.local", 23456, "N2", SERVICE_TYPE);
- let mockDevice3 = createDevice("C.local", 45678, "N3", SERVICE_TYPE);
-
- let mockObj = {
- discovered: false,
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {
- listener.onDiscoveryStarted(serviceType);
-
- if (!this.discovered) {
- listener.onServiceFound(mockDevice1);
- listener.onServiceFound(mockDevice2);
- } else {
- listener.onServiceFound(mockDevice1);
- listener.onServiceFound(mockDevice3);
- }
- this.discovered = true;
-
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {
- listener.onDiscoveryStopped(serviceType);
- }
- };
- },
- registerService: function(serviceInfo, listener) {},
- resolveService: function(serviceInfo, listener) {
- Assert.equal(serviceInfo.serviceType, SERVICE_TYPE);
- if (serviceInfo.serviceName == "N1") {
- listener.onServiceResolved(mockDevice1);
- } else if (serviceInfo.serviceName == "N2") {
- listener.onServiceResolved(mockDevice2);
- } else if (serviceInfo.serviceName == "N3") {
- listener.onServiceResolved(mockDevice3);
- } else {
- Assert.ok(false);
- }
- }
- };
-
- let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
- let listener = new TestPresentationDeviceListener();
- Assert.equal(listener.count(), 0);
-
- // Start discovery
- provider.listener = listener; // discover: N1, N2
- Assert.equal(listener.count(), 2);
- Assert.equal(listener.devices['A.local'].name, mockDevice1.serviceName);
- Assert.equal(listener.devices['B.local'].name, mockDevice2.serviceName);
- Assert.ok(!listener.devices['C.local']);
-
- // temporarily disable to stop discovery and re-enable
- Services.prefs.setBoolPref(PREF_DISCOVERY, false);
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
-
- provider.forceDiscovery(); // discover: N1, N3, going to remove: N2
- Assert.equal(listener.count(), 3);
- Assert.equal(listener.devices['A.local'].name, mockDevice1.serviceName);
- Assert.equal(listener.devices['B.local'].name, mockDevice2.serviceName);
- Assert.equal(listener.devices['C.local'].name, mockDevice3.serviceName);
-
- // temporarily disable to stop discovery and re-enable
- Services.prefs.setBoolPref(PREF_DISCOVERY, false);
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
-
- provider.forceDiscovery(); // discover: N1, N3, remove: N2
- Assert.equal(listener.count(), 2);
- Assert.equal(listener.devices['A.local'].name, mockDevice1.serviceName);
- Assert.ok(!listener.devices['B.local']);
- Assert.equal(listener.devices['C.local'].name, mockDevice3.serviceName);
-
- provider.listener = null;
-
- run_next_test();
-}
-
-function serverClosed() {
- Services.prefs.setBoolPref(PREF_DISCOVERABLE, true);
- Services.prefs.setBoolPref(PREF_DISCOVERY, true);
-
- let mockDevice = createDevice("device.local",
- 12345,
- "service.name",
- SERVICE_TYPE);
-
- let mockObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {
- listener.onDiscoveryStarted(serviceType);
- listener.onServiceFound(createDevice("",
- 0,
- mockDevice.serviceName,
- mockDevice.serviceType));
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {}
- };
- },
- registerService: function(serviceInfo, listener) {
- this.serviceRegistered++;
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- cancel: function() {
- this.serviceUnregistered++;
- }.bind(this)
- };
- },
- resolveService: function(serviceInfo, listener) {
- Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
- Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
- listener.onServiceResolved(createDevice(mockDevice.host,
- mockDevice.port,
- mockDevice.serviceName,
- mockDevice.serviceType));
- },
- serviceRegistered: 0,
- serviceUnregistered: 0
- };
- let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
-
- Assert.equal(mockObj.serviceRegistered, 0);
- Assert.equal(mockObj.serviceUnregistered, 0);
-
- // Register
- let listener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
- Ci.nsISupportsWeakReference]),
- addDevice: function(device) { this.devices.push(device); },
- removeDevice: function(device) {},
- updateDevice: function(device) {},
- devices: []
- };
- Assert.equal(listener.devices.length, 0);
-
- provider.listener = listener;
- Assert.equal(mockObj.serviceRegistered, 1);
- Assert.equal(mockObj.serviceUnregistered, 0);
- Assert.equal(listener.devices.length, 1);
-
- let serverListener = provider.QueryInterface(Ci.nsIPresentationControlServerListener);
- let randomPort = 9527;
- serverListener.onServerReady(randomPort, '');
-
- Assert.equal(mockObj.serviceRegistered, 2);
- Assert.equal(mockObj.serviceUnregistered, 1);
- Assert.equal(listener.devices.length, 1);
-
- // Unregister
- provider.listener = null;
- Assert.equal(mockObj.serviceRegistered, 2);
- Assert.equal(mockObj.serviceUnregistered, 2);
- Assert.equal(listener.devices.length, 1);
-
- run_next_test();
-}
-
-function serverRetry() {
- Services.prefs.setBoolPref(PREF_DISCOVERY, false);
- Services.prefs.setBoolPref(PREF_DISCOVERABLE, true);
-
- let isRetrying = false;
-
- let mockSDObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
- startDiscovery: function(serviceType, listener) {},
- registerService: function(serviceInfo, listener) {
- Assert.ok(isRetrying, "register service after retrying startServer");
- provider.listener = null;
- run_next_test();
- },
- resolveService: function(serviceInfo, listener) {}
- };
-
- let mockServerObj = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
- startServer: function(encrypted, port) {
- if (!isRetrying) {
- isRetrying = true;
- Services.tm.currentThread.dispatch(() => {
- this.listener.onServerStopped(Cr.NS_ERROR_FAILURE);
- }, Ci.nsIThread.DISPATCH_NORMAL);
- } else {
- this.port = 54321;
- Services.tm.currentThread.dispatch(() => {
- this.listener.onServerReady(this.port, this.certFingerprint);
- }, Ci.nsIThread.DISPATCH_NORMAL);
- }
- },
- sessionRequest: function() {},
- close: function() {},
- id: '',
- version: LATEST_VERSION,
- port: 0,
- certFingerprint: 'mock-cert-fingerprint',
- listener: null,
- };
-
- let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
- let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
- let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
- let listener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
- Ci.nsISupportsWeakReference]),
- addDevice: function(device) {},
- removeDevice: function(device) {},
- updateDevice: function(device) {},
- onSessionRequest: function(device, url, presentationId, controlChannel) {}
- };
-
- provider.listener = listener;
-}
-
-function run_test() {
- // Need profile dir to store the key / cert
- do_get_profile();
- // Ensure PSM is initialized
- Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
-
- let infoHook = new ContractHook(INFO_CONTRACT_ID, MockDNSServiceInfo);
-
- do_register_cleanup(() => {
- Services.prefs.clearUserPref(PREF_DISCOVERY);
- Services.prefs.clearUserPref(PREF_DISCOVERABLE);
- });
-
- add_test(registerService);
- add_test(noRegisterService);
- add_test(registerServiceDynamically);
- add_test(addDevice);
- add_test(filterDevice);
- add_test(handleSessionRequest);
- add_test(handleOnSessionRequest);
- add_test(handleOnSessionRequestFromUnknownDevice);
- add_test(noAddDevice);
- add_test(ignoreIncompatibleDevice);
- add_test(ignoreSelfDevice);
- add_test(addDeviceDynamically);
- add_test(updateDevice);
- add_test(diffDiscovery);
- add_test(serverClosed);
- add_test(serverRetry);
-
- run_next_test();
-}
diff --git a/dom/presentation/tests/xpcshell/test_presentation_device_manager.js b/dom/presentation/tests/xpcshell/test_presentation_device_manager.js
deleted file mode 100644
index 68f07df65..000000000
--- a/dom/presentation/tests/xpcshell/test_presentation_device_manager.js
+++ /dev/null
@@ -1,244 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-'use strict';
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
-
-const manager = Cc['@mozilla.org/presentation-device/manager;1']
- .getService(Ci.nsIPresentationDeviceManager);
-
-function TestPresentationDevice() {}
-
-
-function TestPresentationControlChannel() {}
-
-TestPresentationControlChannel.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
- sendOffer: function(offer) {},
- sendAnswer: function(answer) {},
- disconnect: function() {},
- launch: function() {},
- terminate: function() {},
- reconnect: function() {},
- set listener(listener) {},
- get listener() {},
-};
-
-var testProvider = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceProvider]),
-
- forceDiscovery: function() {
- },
- set listener(listener) {
- },
- get listener() {
- },
-};
-
-const forbiddenRequestedUrl = 'http://example.com';
-var testDevice = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
- id: 'id',
- name: 'name',
- type: 'type',
- establishControlChannel: function(url, presentationId) {
- return null;
- },
- disconnect: function() {},
- isRequestedUrlSupported: function(requestedUrl) {
- return forbiddenRequestedUrl !== requestedUrl;
- },
-};
-
-function addProvider() {
- Object.defineProperty(testProvider, 'listener', {
- configurable: true,
- set: function(listener) {
- Assert.strictEqual(listener, manager, 'listener setter is invoked by PresentationDeviceManager');
- delete testProvider.listener;
- run_next_test();
- },
- });
- manager.addDeviceProvider(testProvider);
-}
-
-function forceDiscovery() {
- testProvider.forceDiscovery = function() {
- testProvider.forceDiscovery = function() {};
- Assert.ok(true, 'forceDiscovery is invoked by PresentationDeviceManager');
- run_next_test();
- };
- manager.forceDiscovery();
-}
-
-function addDevice() {
- Services.obs.addObserver(function observer(subject, topic, data) {
- Services.obs.removeObserver(observer, topic);
-
- let updatedDevice = subject.QueryInterface(Ci.nsIPresentationDevice);
- Assert.equal(updatedDevice.id, testDevice.id, 'expected device id');
- Assert.equal(updatedDevice.name, testDevice.name, 'expected device name');
- Assert.equal(updatedDevice.type, testDevice.type, 'expected device type');
- Assert.equal(data, 'add', 'expected update type');
-
- Assert.ok(manager.deviceAvailable, 'device is available');
-
- let devices = manager.getAvailableDevices();
- Assert.equal(devices.length, 1, 'expect 1 available device');
-
- let device = devices.queryElementAt(0, Ci.nsIPresentationDevice);
- Assert.equal(device.id, testDevice.id, 'expected device id');
- Assert.equal(device.name, testDevice.name, 'expected device name');
- Assert.equal(device.type, testDevice.type, 'expected device type');
-
- run_next_test();
- }, 'presentation-device-change', false);
- manager.QueryInterface(Ci.nsIPresentationDeviceListener).addDevice(testDevice);
-}
-
-function updateDevice() {
- Services.obs.addObserver(function observer(subject, topic, data) {
- Services.obs.removeObserver(observer, topic);
-
- let updatedDevice = subject.QueryInterface(Ci.nsIPresentationDevice);
- Assert.equal(updatedDevice.id, testDevice.id, 'expected device id');
- Assert.equal(updatedDevice.name, testDevice.name, 'expected device name');
- Assert.equal(updatedDevice.type, testDevice.type, 'expected device type');
- Assert.equal(data, 'update', 'expected update type');
-
- Assert.ok(manager.deviceAvailable, 'device is available');
-
- let devices = manager.getAvailableDevices();
- Assert.equal(devices.length, 1, 'expect 1 available device');
-
- let device = devices.queryElementAt(0, Ci.nsIPresentationDevice);
- Assert.equal(device.id, testDevice.id, 'expected device id');
- Assert.equal(device.name, testDevice.name, 'expected name after device update');
- Assert.equal(device.type, testDevice.type, 'expected device type');
-
- run_next_test();
- }, 'presentation-device-change', false);
- testDevice.name = 'updated-name';
- manager.QueryInterface(Ci.nsIPresentationDeviceListener).updateDevice(testDevice);
-}
-
-function filterDevice() {
- let presentationUrls = Cc['@mozilla.org/array;1'].createInstance(Ci.nsIMutableArray);
- let url = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
- url.data = forbiddenRequestedUrl;
- presentationUrls.appendElement(url, false);
- let devices = manager.getAvailableDevices(presentationUrls);
- Assert.equal(devices.length, 0, 'expect 0 available device for example.com');
- run_next_test();
-}
-
-function sessionRequest() {
- let testUrl = 'http://www.example.org/';
- let testPresentationId = 'test-presentation-id';
- let testControlChannel = new TestPresentationControlChannel();
- Services.obs.addObserver(function observer(subject, topic, data) {
- Services.obs.removeObserver(observer, topic);
-
- let request = subject.QueryInterface(Ci.nsIPresentationSessionRequest);
-
- Assert.equal(request.device.id, testDevice.id, 'expected device');
- Assert.equal(request.url, testUrl, 'expected requesting URL');
- Assert.equal(request.presentationId, testPresentationId, 'expected presentation Id');
-
- run_next_test();
- }, 'presentation-session-request', false);
- manager.QueryInterface(Ci.nsIPresentationDeviceListener)
- .onSessionRequest(testDevice, testUrl, testPresentationId, testControlChannel);
-}
-
-function terminateRequest() {
- let testUrl = 'http://www.example.org/';
- let testPresentationId = 'test-presentation-id';
- let testControlChannel = new TestPresentationControlChannel();
- let testIsFromReceiver = true;
- Services.obs.addObserver(function observer(subject, topic, data) {
- Services.obs.removeObserver(observer, topic);
-
- let request = subject.QueryInterface(Ci.nsIPresentationTerminateRequest);
-
- Assert.equal(request.device.id, testDevice.id, 'expected device');
- Assert.equal(request.presentationId, testPresentationId, 'expected presentation Id');
- Assert.equal(request.isFromReceiver, testIsFromReceiver, 'expected isFromReceiver');
-
- run_next_test();
- }, 'presentation-terminate-request', false);
- manager.QueryInterface(Ci.nsIPresentationDeviceListener)
- .onTerminateRequest(testDevice, testPresentationId,
- testControlChannel, testIsFromReceiver);
-}
-
-function reconnectRequest() {
- let testUrl = 'http://www.example.org/';
- let testPresentationId = 'test-presentation-id';
- let testControlChannel = new TestPresentationControlChannel();
- Services.obs.addObserver(function observer(subject, topic, data) {
- Services.obs.removeObserver(observer, topic);
-
- let request = subject.QueryInterface(Ci.nsIPresentationSessionRequest);
-
- Assert.equal(request.device.id, testDevice.id, 'expected device');
- Assert.equal(request.url, testUrl, 'expected requesting URL');
- Assert.equal(request.presentationId, testPresentationId, 'expected presentation Id');
-
- run_next_test();
- }, 'presentation-reconnect-request', false);
- manager.QueryInterface(Ci.nsIPresentationDeviceListener)
- .onReconnectRequest(testDevice, testUrl, testPresentationId, testControlChannel);
-}
-
-function removeDevice() {
- Services.obs.addObserver(function observer(subject, topic, data) {
- Services.obs.removeObserver(observer, topic);
-
- let updatedDevice = subject.QueryInterface(Ci.nsIPresentationDevice);
- Assert.equal(updatedDevice.id, testDevice.id, 'expected device id');
- Assert.equal(updatedDevice.name, testDevice.name, 'expected device name');
- Assert.equal(updatedDevice.type, testDevice.type, 'expected device type');
- Assert.equal(data, 'remove', 'expected update type');
-
- Assert.ok(!manager.deviceAvailable, 'device is not available');
-
- let devices = manager.getAvailableDevices();
- Assert.equal(devices.length, 0, 'expect 0 available device');
-
- run_next_test();
- }, 'presentation-device-change', false);
- manager.QueryInterface(Ci.nsIPresentationDeviceListener).removeDevice(testDevice);
-}
-
-function removeProvider() {
- Object.defineProperty(testProvider, 'listener', {
- configurable: true,
- set: function(listener) {
- Assert.strictEqual(listener, null, 'unsetListener is invoked by PresentationDeviceManager');
- delete testProvider.listener;
- run_next_test();
- },
- });
- manager.removeDeviceProvider(testProvider);
-}
-
-add_test(addProvider);
-add_test(forceDiscovery);
-add_test(addDevice);
-add_test(updateDevice);
-add_test(filterDevice);
-add_test(sessionRequest);
-add_test(terminateRequest);
-add_test(reconnectRequest);
-add_test(removeDevice);
-add_test(removeProvider);
-
-function run_test() {
- run_next_test();
-}
diff --git a/dom/presentation/tests/xpcshell/test_presentation_session_transport.js b/dom/presentation/tests/xpcshell/test_presentation_session_transport.js
deleted file mode 100644
index 8e207bc22..000000000
--- a/dom/presentation/tests/xpcshell/test_presentation_session_transport.js
+++ /dev/null
@@ -1,198 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-'use strict';
-
-const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr, Constructor: CC } = Components;
-const ServerSocket = CC("@mozilla.org/network/server-socket;1",
- "nsIServerSocket",
- "init");
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
-
-var testServer = null;
-var clientTransport = null;
-var serverTransport = null;
-
-var clientBuilder = null;
-var serverBuilder = null;
-
-const clientMessage = "Client Message";
-const serverMessage = "Server Message";
-
-const address = Cc["@mozilla.org/supports-cstring;1"]
- .createInstance(Ci.nsISupportsCString);
-address.data = "127.0.0.1";
-const addresses = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
-addresses.appendElement(address, false);
-
-const serverChannelDescription = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
- type: 1,
- tcpAddress: addresses,
-};
-
-var isClientReady = false;
-var isServerReady = false;
-var isClientClosed = false;
-var isServerClosed = false;
-
-const clientCallback = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
- notifyTransportReady: function () {
- Assert.ok(true, "Client transport ready.");
-
- isClientReady = true;
- if (isClientReady && isServerReady) {
- run_next_test();
- }
- },
- notifyTransportClosed: function (aReason) {
- Assert.ok(true, "Client transport is closed.");
-
- isClientClosed = true;
- if (isClientClosed && isServerClosed) {
- run_next_test();
- }
- },
- notifyData: function(aData) {
- Assert.equal(aData, serverMessage, "Client transport receives data.");
- run_next_test();
- },
-};
-
-const serverCallback = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
- notifyTransportReady: function () {
- Assert.ok(true, "Server transport ready.");
-
- isServerReady = true;
- if (isClientReady && isServerReady) {
- run_next_test();
- }
- },
- notifyTransportClosed: function (aReason) {
- Assert.ok(true, "Server transport is closed.");
-
- isServerClosed = true;
- if (isClientClosed && isServerClosed) {
- run_next_test();
- }
- },
- notifyData: function(aData) {
- Assert.equal(aData, clientMessage, "Server transport receives data.");
- run_next_test();
- },
-};
-
-const clientListener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
- onSessionTransport(aTransport) {
- Assert.ok(true, "Client Transport is built.");
- clientTransport = aTransport;
- clientTransport.callback = clientCallback;
-
- if (serverTransport) {
- run_next_test();
- }
- }
-}
-
-const serverListener = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
- onSessionTransport(aTransport) {
- Assert.ok(true, "Server Transport is built.");
- serverTransport = aTransport;
- serverTransport.callback = serverCallback;
- serverTransport.enableDataNotification();
-
- if (clientTransport) {
- run_next_test();
- }
- }
-}
-
-function TestServer() {
- this.serverSocket = ServerSocket(-1, true, -1);
- this.serverSocket.asyncListen(this)
-}
-
-TestServer.prototype = {
- onSocketAccepted: function(aSocket, aTransport) {
- print("Test server gets a client connection.");
- serverBuilder = Cc["@mozilla.org/presentation/presentationtcpsessiontransport;1"]
- .createInstance(Ci.nsIPresentationTCPSessionTransportBuilder);
- serverBuilder.buildTCPSenderTransport(aTransport, serverListener);
- },
- onStopListening: function(aSocket) {
- print("Test server stops listening.");
- },
- close: function() {
- if (this.serverSocket) {
- this.serverSocket.close();
- this.serverSocket = null;
- }
- }
-};
-
-// Set up the transport connection and ensure |notifyTransportReady| triggered
-// at both sides.
-function setup() {
- clientBuilder = Cc["@mozilla.org/presentation/presentationtcpsessiontransport;1"]
- .createInstance(Ci.nsIPresentationTCPSessionTransportBuilder);
- clientBuilder.buildTCPReceiverTransport(serverChannelDescription, clientListener);
-}
-
-// Test |selfAddress| attribute of |nsIPresentationSessionTransport|.
-function selfAddress() {
- var serverSelfAddress = serverTransport.selfAddress;
- Assert.equal(serverSelfAddress.address, address.data, "The self address of server transport should be set.");
- Assert.equal(serverSelfAddress.port, testServer.serverSocket.port, "The port of server transport should be set.");
-
- var clientSelfAddress = clientTransport.selfAddress;
- Assert.ok(clientSelfAddress.address, "The self address of client transport should be set.");
- Assert.ok(clientSelfAddress.port, "The port of client transport should be set.");
-
- run_next_test();
-}
-
-// Test the client sends a message and then a corresponding notification gets
-// triggered at the server side.
-function clientSendMessage() {
- clientTransport.send(clientMessage);
-}
-
-// Test the server sends a message an then a corresponding notification gets
-// triggered at the client side.
-function serverSendMessage() {
- serverTransport.send(serverMessage);
- // The client enables data notification even after the incoming message has
- // been sent, and should still be able to consume it.
- clientTransport.enableDataNotification();
-}
-
-function transportClose() {
- clientTransport.close(Cr.NS_OK);
-}
-
-function shutdown() {
- testServer.close();
- run_next_test();
-}
-
-add_test(setup);
-add_test(selfAddress);
-add_test(clientSendMessage);
-add_test(serverSendMessage);
-add_test(transportClose);
-add_test(shutdown);
-
-function run_test() {
- testServer = new TestServer();
- // Get the port of the test server.
- serverChannelDescription.tcpPort = testServer.serverSocket.port;
-
- run_next_test();
-}
diff --git a/dom/presentation/tests/xpcshell/test_presentation_state_machine.js b/dom/presentation/tests/xpcshell/test_presentation_state_machine.js
deleted file mode 100644
index fcaf34da6..000000000
--- a/dom/presentation/tests/xpcshell/test_presentation_state_machine.js
+++ /dev/null
@@ -1,236 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-/* jshint esnext:true, globalstrict:true, moz:true, undef:true, unused:true */
-/* globals Components,Assert,run_next_test,add_test,do_execute_soon */
-
-'use strict';
-
-const { utils: Cu, results: Cr } = Components;
-
-/* globals ControllerStateMachine */
-Cu.import('resource://gre/modules/presentation/ControllerStateMachine.jsm');
-/* globals ReceiverStateMachine */
-Cu.import('resource://gre/modules/presentation/ReceiverStateMachine.jsm');
-/* globals State */
-Cu.import('resource://gre/modules/presentation/StateMachineHelper.jsm');
-
-const testControllerId = 'test-controller-id';
-const testPresentationId = 'test-presentation-id';
-const testUrl = 'http://example.org';
-
-let mockControllerChannel = {};
-let mockReceiverChannel = {};
-
-let controllerState = new ControllerStateMachine(mockControllerChannel, testControllerId);
-let receiverState = new ReceiverStateMachine(mockReceiverChannel);
-
-mockControllerChannel.sendCommand = function(command) {
- do_execute_soon(function() {
- receiverState.onCommand(command);
- });
-};
-
-mockReceiverChannel.sendCommand = function(command) {
- do_execute_soon(function() {
- controllerState.onCommand(command);
- });
-};
-
-function connect() {
- Assert.equal(controllerState.state, State.INIT, 'controller in init state');
- Assert.equal(receiverState.state, State.INIT, 'receiver in init state');
- // step 1: underlying connection is ready
- controllerState.onChannelReady();
- Assert.equal(controllerState.state, State.CONNECTING, 'controller in connecting state');
- receiverState.onChannelReady();
- Assert.equal(receiverState.state, State.CONNECTING, 'receiver in connecting state');
-
- // step 2: receiver reply to connect command
- mockReceiverChannel.notifyDeviceConnected = function(deviceId) {
- Assert.equal(deviceId, testControllerId, 'receiver connect to mock controller');
- Assert.equal(receiverState.state, State.CONNECTED, 'receiver in connected state');
-
- // step 3: controller receive connect-ack command
- mockControllerChannel.notifyDeviceConnected = function() {
- Assert.equal(controllerState.state, State.CONNECTED, 'controller in connected state');
- run_next_test();
- };
- };
-}
-
-function launch() {
- Assert.equal(controllerState.state, State.CONNECTED, 'controller in connected state');
- Assert.equal(receiverState.state, State.CONNECTED, 'receiver in connected state');
-
- controllerState.launch(testPresentationId, testUrl);
- mockReceiverChannel.notifyLaunch = function(presentationId, url) {
- Assert.equal(receiverState.state, State.CONNECTED, 'receiver in connected state');
- Assert.equal(presentationId, testPresentationId, 'expected presentationId received');
- Assert.equal(url, testUrl, 'expected url received');
-
- mockControllerChannel.notifyLaunch = function(presentationId) {
- Assert.equal(controllerState.state, State.CONNECTED, 'controller in connected state');
- Assert.equal(presentationId, testPresentationId, 'expected presentationId received from ack');
-
- run_next_test();
- };
- };
-}
-
-function terminateByController() {
- Assert.equal(controllerState.state, State.CONNECTED, 'controller in connected state');
- Assert.equal(receiverState.state, State.CONNECTED, 'receiver in connected state');
-
- controllerState.terminate(testPresentationId);
- mockReceiverChannel.notifyTerminate = function(presentationId) {
- Assert.equal(receiverState.state, State.CONNECTED, 'receiver in connected state');
- Assert.equal(presentationId, testPresentationId, 'expected presentationId received');
-
- mockControllerChannel.notifyTerminate = function(presentationId) {
- Assert.equal(controllerState.state, State.CONNECTED, 'controller in connected state');
- Assert.equal(presentationId, testPresentationId, 'expected presentationId received from ack');
-
- run_next_test();
- };
-
- receiverState.terminateAck(presentationId);
- };
-}
-
-function terminateByReceiver() {
- Assert.equal(controllerState.state, State.CONNECTED, 'controller in connected state');
- Assert.equal(receiverState.state, State.CONNECTED, 'receiver in connected state');
-
- receiverState.terminate(testPresentationId);
- mockControllerChannel.notifyTerminate = function(presentationId) {
- Assert.equal(controllerState.state, State.CONNECTED, 'controller in connected state');
- Assert.equal(presentationId, testPresentationId, 'expected presentationId received');
-
- mockReceiverChannel.notifyTerminate = function(presentationId) {
- Assert.equal(receiverState.state, State.CONNECTED, 'receiver in connected state');
- Assert.equal(presentationId, testPresentationId, 'expected presentationId received from ack');
- run_next_test();
- };
-
- controllerState.terminateAck(presentationId);
- };
-}
-
-function exchangeSDP() {
- Assert.equal(controllerState.state, State.CONNECTED, 'controller in connected state');
- Assert.equal(receiverState.state, State.CONNECTED, 'receiver in connected state');
-
- const testOffer = 'test-offer';
- const testAnswer = 'test-answer';
- const testIceCandidate = 'test-ice-candidate';
- controllerState.sendOffer(testOffer);
- mockReceiverChannel.notifyOffer = function(offer) {
- Assert.equal(offer, testOffer, 'expected offer received');
-
- receiverState.sendAnswer(testAnswer);
- mockControllerChannel.notifyAnswer = function(answer) {
- Assert.equal(answer, testAnswer, 'expected answer received');
-
- controllerState.updateIceCandidate(testIceCandidate);
- mockReceiverChannel.notifyIceCandidate = function(candidate) {
- Assert.equal(candidate, testIceCandidate, 'expected ice candidate received in receiver');
-
- receiverState.updateIceCandidate(testIceCandidate);
- mockControllerChannel.notifyIceCandidate = function(candidate) {
- Assert.equal(candidate, testIceCandidate, 'expected ice candidate received in controller');
-
- run_next_test();
- };
- };
- };
- };
-}
-
-function disconnect() {
- // step 1: controller send disconnect command
- controllerState.onChannelClosed(Cr.NS_OK, false);
- Assert.equal(controllerState.state, State.CLOSING, 'controller in closing state');
-
- mockReceiverChannel.notifyDisconnected = function(reason) {
- Assert.equal(reason, Cr.NS_OK, 'receive close reason');
- Assert.equal(receiverState.state, State.CLOSED, 'receiver in closed state');
-
- receiverState.onChannelClosed(Cr.NS_OK, true);
- Assert.equal(receiverState.state, State.CLOSED, 'receiver in closed state');
-
- mockControllerChannel.notifyDisconnected = function(reason) {
- Assert.equal(reason, Cr.NS_OK, 'receive close reason');
- Assert.equal(controllerState.state, State.CLOSED, 'controller in closed state');
-
- run_next_test();
- };
- controllerState.onChannelClosed(Cr.NS_OK, true);
- };
-}
-
-function receiverDisconnect() {
- // initial state: controller and receiver are connected
- controllerState.state = State.CONNECTED;
- receiverState.state = State.CONNECTED;
-
- // step 1: controller send disconnect command
- receiverState.onChannelClosed(Cr.NS_OK, false);
- Assert.equal(receiverState.state, State.CLOSING, 'receiver in closing state');
-
- mockControllerChannel.notifyDisconnected = function(reason) {
- Assert.equal(reason, Cr.NS_OK, 'receive close reason');
- Assert.equal(controllerState.state, State.CLOSED, 'controller in closed state');
-
- controllerState.onChannelClosed(Cr.NS_OK, true);
- Assert.equal(controllerState.state, State.CLOSED, 'controller in closed state');
-
- mockReceiverChannel.notifyDisconnected = function(reason) {
- Assert.equal(reason, Cr.NS_OK, 'receive close reason');
- Assert.equal(receiverState.state, State.CLOSED, 'receiver in closed state');
-
- run_next_test();
- };
- receiverState.onChannelClosed(Cr.NS_OK, true);
- };
-}
-
-function abnormalDisconnect() {
- // initial state: controller and receiver are connected
- controllerState.state = State.CONNECTED;
- receiverState.state = State.CONNECTED;
-
- const testErrorReason = Cr.NS_ERROR_FAILURE;
- // step 1: controller send disconnect command
- controllerState.onChannelClosed(testErrorReason, false);
- Assert.equal(controllerState.state, State.CLOSING, 'controller in closing state');
-
- mockReceiverChannel.notifyDisconnected = function(reason) {
- Assert.equal(reason, testErrorReason, 'receive abnormal close reason');
- Assert.equal(receiverState.state, State.CLOSED, 'receiver in closed state');
-
- receiverState.onChannelClosed(Cr.NS_OK, true);
- Assert.equal(receiverState.state, State.CLOSED, 'receiver in closed state');
-
- mockControllerChannel.notifyDisconnected = function(reason) {
- Assert.equal(reason, testErrorReason, 'receive abnormal close reason');
- Assert.equal(controllerState.state, State.CLOSED, 'controller in closed state');
-
- run_next_test();
- };
- controllerState.onChannelClosed(Cr.NS_OK, true);
- };
-}
-
-add_test(connect);
-add_test(launch);
-add_test(terminateByController);
-add_test(terminateByReceiver);
-add_test(exchangeSDP);
-add_test(disconnect);
-add_test(receiverDisconnect);
-add_test(abnormalDisconnect);
-
-function run_test() { // jshint ignore:line
- run_next_test();
-}
diff --git a/dom/presentation/tests/xpcshell/test_tcp_control_channel.js b/dom/presentation/tests/xpcshell/test_tcp_control_channel.js
deleted file mode 100644
index 5f3df584d..000000000
--- a/dom/presentation/tests/xpcshell/test_tcp_control_channel.js
+++ /dev/null
@@ -1,398 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-'use strict';
-
-const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
-
-var pcs;
-
-// Call |run_next_test| if all functions in |names| are called
-function makeJointSuccess(names) {
- let funcs = {}, successCount = 0;
- names.forEach(function(name) {
- funcs[name] = function() {
- do_print('got expected: ' + name);
- if (++successCount === names.length)
- run_next_test();
- };
- });
- return funcs;
-}
-
-function TestDescription(aType, aTcpAddress, aTcpPort) {
- this.type = aType;
- this.tcpAddress = Cc["@mozilla.org/array;1"]
- .createInstance(Ci.nsIMutableArray);
- for (let address of aTcpAddress) {
- let wrapper = Cc["@mozilla.org/supports-cstring;1"]
- .createInstance(Ci.nsISupportsCString);
- wrapper.data = address;
- this.tcpAddress.appendElement(wrapper, false);
- }
- this.tcpPort = aTcpPort;
-}
-
-TestDescription.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
-}
-
-const CONTROLLER_CONTROL_CHANNEL_PORT = 36777;
-const PRESENTER_CONTROL_CHANNEL_PORT = 36888;
-
-var CLOSE_CONTROL_CHANNEL_REASON = Cr.NS_OK;
-var candidate;
-
-// presenter's presentation channel description
-const OFFER_ADDRESS = '192.168.123.123';
-const OFFER_PORT = 123;
-
-// controller's presentation channel description
-const ANSWER_ADDRESS = '192.168.321.321';
-const ANSWER_PORT = 321;
-
-function loopOfferAnser() {
- pcs = Cc["@mozilla.org/presentation/control-service;1"]
- .createInstance(Ci.nsIPresentationControlService);
- pcs.id = 'controllerID';
- pcs.listener = {
- onServerReady: function() {
- testPresentationServer();
- }
- };
-
- // First run with TLS enabled.
- pcs.startServer(true, PRESENTER_CONTROL_CHANNEL_PORT);
-}
-
-
-function testPresentationServer() {
- let yayFuncs = makeJointSuccess(['controllerControlChannelClose',
- 'presenterControlChannelClose',
- 'controllerControlChannelReconnect',
- 'presenterControlChannelReconnect']);
- let presenterControlChannel;
-
- pcs.listener = {
-
- onSessionRequest: function(deviceInfo, url, presentationId, controlChannel) {
- presenterControlChannel = controlChannel;
- Assert.equal(deviceInfo.id, pcs.id, 'expected device id');
- Assert.equal(deviceInfo.address, '127.0.0.1', 'expected device address');
- Assert.equal(url, 'http://example.com', 'expected url');
- Assert.equal(presentationId, 'testPresentationId', 'expected presentation id');
-
- presenterControlChannel.listener = {
- status: 'created',
- onOffer: function(aOffer) {
- Assert.equal(this.status, 'opened', '1. presenterControlChannel: get offer, send answer');
- this.status = 'onOffer';
-
- let offer = aOffer.QueryInterface(Ci.nsIPresentationChannelDescription);
- Assert.strictEqual(offer.tcpAddress.queryElementAt(0,Ci.nsISupportsCString).data,
- OFFER_ADDRESS,
- 'expected offer address array');
- Assert.equal(offer.tcpPort, OFFER_PORT, 'expected offer port');
- try {
- let tcpType = Ci.nsIPresentationChannelDescription.TYPE_TCP;
- let answer = new TestDescription(tcpType, [ANSWER_ADDRESS], ANSWER_PORT);
- presenterControlChannel.sendAnswer(answer);
- } catch (e) {
- Assert.ok(false, 'sending answer fails' + e);
- }
- },
- onAnswer: function(aAnswer) {
- Assert.ok(false, 'get answer');
- },
- onIceCandidate: function(aCandidate) {
- Assert.ok(true, '3. presenterControlChannel: get ice candidate, close channel');
- let recvCandidate = JSON.parse(aCandidate);
- for (let key in recvCandidate) {
- if (typeof(recvCandidate[key]) !== "function") {
- Assert.equal(recvCandidate[key], candidate[key], "key " + key + " should match.");
- }
- }
- presenterControlChannel.disconnect(CLOSE_CONTROL_CHANNEL_REASON);
- },
- notifyConnected: function() {
- Assert.equal(this.status, 'created', '0. presenterControlChannel: opened');
- this.status = 'opened';
- },
- notifyDisconnected: function(aReason) {
- Assert.equal(this.status, 'onOffer', '4. presenterControlChannel: closed');
- Assert.equal(aReason, CLOSE_CONTROL_CHANNEL_REASON, 'presenterControlChannel notify closed');
- this.status = 'closed';
- yayFuncs.controllerControlChannelClose();
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
- };
- },
- onReconnectRequest: function(deviceInfo, url, presentationId, controlChannel) {
- Assert.equal(url, 'http://example.com', 'expected url');
- Assert.equal(presentationId, 'testPresentationId', 'expected presentation id');
- yayFuncs.presenterControlChannelReconnect();
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlServerListener]),
- };
-
- let presenterDeviceInfo = {
- id: 'presentatorID',
- address: '127.0.0.1',
- port: PRESENTER_CONTROL_CHANNEL_PORT,
- certFingerprint: pcs.certFingerprint,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
- };
-
- let controllerControlChannel = pcs.connect(presenterDeviceInfo);
-
- controllerControlChannel.listener = {
- status: 'created',
- onOffer: function(offer) {
- Assert.ok(false, 'get offer');
- },
- onAnswer: function(aAnswer) {
- Assert.equal(this.status, 'opened', '2. controllerControlChannel: get answer, send ICE candidate');
-
- let answer = aAnswer.QueryInterface(Ci.nsIPresentationChannelDescription);
- Assert.strictEqual(answer.tcpAddress.queryElementAt(0,Ci.nsISupportsCString).data,
- ANSWER_ADDRESS,
- 'expected answer address array');
- Assert.equal(answer.tcpPort, ANSWER_PORT, 'expected answer port');
- candidate = {
- candidate: "1 1 UDP 1 127.0.0.1 34567 type host",
- sdpMid: "helloworld",
- sdpMLineIndex: 1
- };
- controllerControlChannel.sendIceCandidate(JSON.stringify(candidate));
- },
- onIceCandidate: function(aCandidate) {
- Assert.ok(false, 'get ICE candidate');
- },
- notifyConnected: function() {
- Assert.equal(this.status, 'created', '0. controllerControlChannel: opened, send offer');
- controllerControlChannel.launch('testPresentationId', 'http://example.com');
- this.status = 'opened';
- try {
- let tcpType = Ci.nsIPresentationChannelDescription.TYPE_TCP;
- let offer = new TestDescription(tcpType, [OFFER_ADDRESS], OFFER_PORT)
- controllerControlChannel.sendOffer(offer);
- } catch (e) {
- Assert.ok(false, 'sending offer fails:' + e);
- }
- },
- notifyDisconnected: function(aReason) {
- this.status = 'closed';
- Assert.equal(aReason, CLOSE_CONTROL_CHANNEL_REASON, '4. controllerControlChannel notify closed');
- yayFuncs.presenterControlChannelClose();
-
- let reconnectControllerControlChannel = pcs.connect(presenterDeviceInfo);
- reconnectControllerControlChannel.listener = {
- notifyConnected: function() {
- reconnectControllerControlChannel.reconnect('testPresentationId', 'http://example.com');
- },
- notifyReconnected: function() {
- yayFuncs.controllerControlChannelReconnect();
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
- };
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
- };
-}
-
-function terminateRequest() {
- let yayFuncs = makeJointSuccess(['controllerControlChannelConnected',
- 'controllerControlChannelDisconnected',
- 'presenterControlChannelDisconnected',
- 'terminatedByController',
- 'terminatedByReceiver']);
- let controllerControlChannel;
- let terminatePhase = 'controller';
-
- pcs.listener = {
- onTerminateRequest: function(deviceInfo, presentationId, controlChannel, isFromReceiver) {
- Assert.equal(deviceInfo.address, '127.0.0.1', 'expected device address');
- Assert.equal(presentationId, 'testPresentationId', 'expected presentation id');
- controlChannel.terminate(presentationId); // Reply terminate ack.
-
- if (terminatePhase === 'controller') {
- controllerControlChannel = controlChannel;
- Assert.equal(deviceInfo.id, pcs.id, 'expected controller device id');
- Assert.equal(isFromReceiver, false, 'expected request from controller');
- yayFuncs.terminatedByController();
-
- controllerControlChannel.listener = {
- notifyConnected: function() {
- Assert.ok(true, 'control channel notify connected');
- yayFuncs.controllerControlChannelConnected();
-
- terminatePhase = 'receiver';
- controllerControlChannel.terminate('testPresentationId');
- },
- notifyDisconnected: function(aReason) {
- Assert.equal(aReason, CLOSE_CONTROL_CHANNEL_REASON, 'controllerControlChannel notify disconncted');
- yayFuncs.controllerControlChannelDisconnected();
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
- };
- } else {
- Assert.equal(deviceInfo.id, presenterDeviceInfo.id, 'expected presenter device id');
- Assert.equal(isFromReceiver, true, 'expected request from receiver');
- yayFuncs.terminatedByReceiver();
- presenterControlChannel.disconnect(CLOSE_CONTROL_CHANNEL_REASON);
- }
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServerListener]),
- };
-
- let presenterDeviceInfo = {
- id: 'presentatorID',
- address: '127.0.0.1',
- port: PRESENTER_CONTROL_CHANNEL_PORT,
- certFingerprint: pcs.certFingerprint,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
- };
-
- let presenterControlChannel = pcs.connect(presenterDeviceInfo);
-
- presenterControlChannel.listener = {
- notifyConnected: function() {
- presenterControlChannel.terminate('testPresentationId');
- },
- notifyDisconnected: function(aReason) {
- Assert.equal(aReason, CLOSE_CONTROL_CHANNEL_REASON, '4. presenterControlChannel notify disconnected');
- yayFuncs.presenterControlChannelDisconnected();
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
- };
-}
-
-function terminateRequestAbnormal() {
- let yayFuncs = makeJointSuccess(['controllerControlChannelConnected',
- 'controllerControlChannelDisconnected',
- 'presenterControlChannelDisconnected']);
- let controllerControlChannel;
-
- pcs.listener = {
- onTerminateRequest: function(deviceInfo, presentationId, controlChannel, isFromReceiver) {
- Assert.equal(deviceInfo.id, pcs.id, 'expected controller device id');
- Assert.equal(deviceInfo.address, '127.0.0.1', 'expected device address');
- Assert.equal(presentationId, 'testPresentationId', 'expected presentation id');
- Assert.equal(isFromReceiver, false, 'expected request from controller');
- controlChannel.terminate('unmatched-presentationId'); // Reply abnormal terminate ack.
-
- controllerControlChannel = controlChannel;
-
- controllerControlChannel.listener = {
- notifyConnected: function() {
- Assert.ok(true, 'control channel notify connected');
- yayFuncs.controllerControlChannelConnected();
- },
- notifyDisconnected: function(aReason) {
- Assert.equal(aReason, Cr.NS_ERROR_FAILURE, 'controllerControlChannel notify disconncted with error');
- yayFuncs.controllerControlChannelDisconnected();
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
- };
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServerListener]),
- };
-
- let presenterDeviceInfo = {
- id: 'presentatorID',
- address: '127.0.0.1',
- port: PRESENTER_CONTROL_CHANNEL_PORT,
- certFingerprint: pcs.certFingerprint,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
- };
-
- let presenterControlChannel = pcs.connect(presenterDeviceInfo);
-
- presenterControlChannel.listener = {
- notifyConnected: function() {
- presenterControlChannel.terminate('testPresentationId');
- },
- notifyDisconnected: function(aReason) {
- Assert.equal(aReason, Cr.NS_ERROR_FAILURE, '4. presenterControlChannel notify disconnected with error');
- yayFuncs.presenterControlChannelDisconnected();
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
- };
-}
-
-function setOffline() {
- pcs.listener = {
- onServerReady: function(aPort, aCertFingerprint) {
- Assert.notEqual(aPort, 0, 'TCPPresentationServer port changed and the port should be valid');
- pcs.close();
- run_next_test();
- },
- };
-
- // Let the server socket restart automatically.
- Services.io.offline = true;
- Services.io.offline = false;
-}
-
-function oneMoreLoop() {
- try {
- pcs.listener = {
- onServerReady: function() {
- testPresentationServer();
- }
- };
-
- // Second run with TLS disabled.
- pcs.startServer(false, PRESENTER_CONTROL_CHANNEL_PORT);
- } catch (e) {
- Assert.ok(false, 'TCP presentation init fail:' + e);
- run_next_test();
- }
-}
-
-
-function shutdown()
-{
- pcs.listener = {
- onServerReady: function(aPort, aCertFingerprint) {
- Assert.ok(false, 'TCPPresentationServer port changed');
- },
- };
- pcs.close();
- Assert.equal(pcs.port, 0, "TCPPresentationServer closed");
- run_next_test();
-}
-
-// Test manually close control channel with NS_ERROR_FAILURE
-function changeCloseReason() {
- CLOSE_CONTROL_CHANNEL_REASON = Cr.NS_ERROR_FAILURE;
- run_next_test();
-}
-
-add_test(loopOfferAnser);
-add_test(terminateRequest);
-add_test(terminateRequestAbnormal);
-add_test(setOffline);
-add_test(changeCloseReason);
-add_test(oneMoreLoop);
-add_test(shutdown);
-
-function run_test() {
- // Need profile dir to store the key / cert
- do_get_profile();
- // Ensure PSM is initialized
- Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
-
- Services.prefs.setBoolPref("dom.presentation.tcp_server.debug", true);
-
- do_register_cleanup(() => {
- Services.prefs.clearUserPref("dom.presentation.tcp_server.debug");
- });
-
- run_next_test();
-}
diff --git a/dom/presentation/tests/xpcshell/xpcshell.ini b/dom/presentation/tests/xpcshell/xpcshell.ini
deleted file mode 100644
index 8a9c305a0..000000000
--- a/dom/presentation/tests/xpcshell/xpcshell.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[DEFAULT]
-head =
-tail =
-
-[test_multicast_dns_device_provider.js]
-[test_presentation_device_manager.js]
-[test_presentation_session_transport.js]
-[test_tcp_control_channel.js]
-[test_presentation_state_machine.js]
diff --git a/dom/push/PushRecord.jsm b/dom/push/PushRecord.jsm
index 08a7678e0..58f808e6c 100644
--- a/dom/push/PushRecord.jsm
+++ b/dom/push/PushRecord.jsm
@@ -9,7 +9,6 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
-Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@@ -145,13 +144,14 @@ PushRecord.prototype = {
return Date.now();
}
- if (AppConstants.MOZ_ANDROID_HISTORY) {
- let result = yield Messaging.sendRequestForResult({
- type: "History:GetPrePathLastVisitedTimeMilliseconds",
- prePath: this.uri.prePath,
- });
- return result == 0 ? -Infinity : result;
- }
+#ifdef MOZ_ANDROID_HISTORY
+ let result = yield Messaging.sendRequestForResult({
+ type: "History:GetPrePathLastVisitedTimeMilliseconds",
+ prePath: this.uri.prePath,
+ });
+
+ return result == 0 ? -Infinity : result;
+#endif
// Places History transition types that can fire a
// `pushsubscriptionchange` event when the user visits a site with expired push
diff --git a/dom/push/PushService.jsm b/dom/push/PushService.jsm
index 373807024..07cf70d21 100644
--- a/dom/push/PushService.jsm
+++ b/dom/push/PushService.jsm
@@ -10,7 +10,6 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
-Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
@@ -24,14 +23,14 @@ const {
const {PushDB} = Cu.import("resource://gre/modules/PushDB.jsm");
const CONNECTION_PROTOCOLS = (function() {
- if ('android' != AppConstants.MOZ_WIDGET_TOOLKIT) {
+#ifdef MOZ_WIDGET_ANDROID
+ const {PushServiceAndroidGCM} = Cu.import("resource://gre/modules/PushServiceAndroidGCM.jsm");
+ return [PushServiceAndroidGCM];
+#else
const {PushServiceWebSocket} = Cu.import("resource://gre/modules/PushServiceWebSocket.jsm");
const {PushServiceHttp2} = Cu.import("resource://gre/modules/PushServiceHttp2.jsm");
return [PushServiceWebSocket, PushServiceHttp2];
- } else {
- const {PushServiceAndroidGCM} = Cu.import("resource://gre/modules/PushServiceAndroidGCM.jsm");
- return [PushServiceAndroidGCM];
- }
+#endif
})();
XPCOMUtils.defineLazyServiceGetter(this, "gPushNotifier",
diff --git a/dom/push/PushServiceWebSocket.jsm b/dom/push/PushServiceWebSocket.jsm
index 46b12b8f0..54348e71c 100644
--- a/dom/push/PushServiceWebSocket.jsm
+++ b/dom/push/PushServiceWebSocket.jsm
@@ -10,7 +10,6 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
-Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Services.jsm");
diff --git a/dom/push/moz.build b/dom/push/moz.build
index 7eee8896f..d138b270c 100644
--- a/dom/push/moz.build
+++ b/dom/push/moz.build
@@ -12,12 +12,15 @@ EXTRA_COMPONENTS += [
EXTRA_JS_MODULES += [
'PushCrypto.jsm',
'PushDB.jsm',
- 'PushRecord.jsm',
- 'PushService.jsm',
'PushServiceHttp2.jsm',
'PushServiceWebSocket.jsm',
]
+EXTRA_PP_JS_MODULES += [
+ 'PushRecord.jsm',
+ 'PushService.jsm',
+]
+
MOCHITEST_MANIFESTS += [
'test/mochitest.ini',
]
diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp
index d07ad7945..6d4f297d6 100644
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -555,7 +555,21 @@ permitsPort(const nsAString& aEnforcementScheme,
int32_t resourcePort;
nsresult rv = aResourceURI->GetPort(&resourcePort);
- NS_ENSURE_SUCCESS(rv, false);
+ if (NS_FAILED(rv) && aEnforcementPort.IsEmpty()) {
+ // If we cannot get a Port (e.g. because of an Custom Protocol handler)
+ // we need to check if a default port is associated with the Scheme
+ if (aEnforcementScheme.IsEmpty()) {
+ return false;
+ }
+ int defaultPortforScheme =
+ NS_GetDefaultPort(NS_ConvertUTF16toUTF8(aEnforcementScheme).get());
+
+ // If there is no default port associated with the Scheme (
+ // defaultPortforScheme == -1) or it is an externally handled protocol (
+ // defaultPortforScheme == 0 ) and the csp does not enforce a port - we can
+ // allow not having a port
+ return (defaultPortforScheme == -1 || defaultPortforScheme == 0);
+ }
// Avoid unnecessary string creation/manipulation and don't block the
// load if the resource to be loaded uses the default port for that
diff --git a/dom/system/OSFileConstants.cpp b/dom/system/OSFileConstants.cpp
index 86377e75a..ec84d784b 100644
--- a/dom/system/OSFileConstants.cpp
+++ b/dom/system/OSFileConstants.cpp
@@ -1048,22 +1048,11 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
}
#endif // defined(XP_MACOSX)
- // sqlite3 is linked from different places depending on the platform
+ // sqlite3 is always a shared lib
nsAutoString libsqlite3;
-#if defined(ANDROID)
- // On Android, we use the system's libsqlite3
- libsqlite3.AppendLiteral(DLL_PREFIX);
- libsqlite3.AppendLiteral("sqlite3");
- libsqlite3.AppendLiteral(DLL_SUFFIX);
-#elif defined(XP_WIN)
- // On Windows, for some reason, this is part of nss3.dll
libsqlite3.AppendLiteral(DLL_PREFIX);
- libsqlite3.AppendLiteral("nss3");
+ libsqlite3.AppendLiteral("mozsqlite3");
libsqlite3.AppendLiteral(DLL_SUFFIX);
-#else
- // On other platforms, we link sqlite3 into libxul
- libsqlite3 = libxul;
-#endif // defined(ANDROID) || defined(XP_WIN)
if (!SetStringProperty(cx, objPath, "libsqlite3", libsqlite3)) {
return false;
diff --git a/dom/webidl/FlyWebDiscoveryManager.webidl b/dom/webidl/FlyWebDiscoveryManager.webidl
deleted file mode 100644
index 963cebf20..000000000
--- a/dom/webidl/FlyWebDiscoveryManager.webidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- 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/.
- */
-
-dictionary FlyWebDiscoveredService {
- DOMString serviceId = "";
- DOMString displayName = "";
- DOMString transport = "";
- DOMString serviceType = "";
- DOMString cert = "";
- DOMString path = "";
-};
-
-dictionary FlyWebPairedService {
- FlyWebDiscoveredService discoveredService;
- DOMString hostname = "";
- DOMString uiUrl = "";
-};
-
-callback interface FlyWebPairingCallback {
- void pairingSucceeded(optional FlyWebPairedService service);
- void pairingFailed(DOMString error);
-};
-
-callback interface FlyWebDiscoveryCallback {
- void onDiscoveredServicesChanged(sequence<FlyWebDiscoveredService> serviceList);
-};
-
-[ChromeOnly, ChromeConstructor, Exposed=(Window,System)]
-interface FlyWebDiscoveryManager {
- sequence<FlyWebDiscoveredService> listServices();
-
- unsigned long startDiscovery(FlyWebDiscoveryCallback aCallback);
- void stopDiscovery(unsigned long aId);
-
- void pairWithService(DOMString serviceId, FlyWebPairingCallback callback);
-};
diff --git a/dom/webidl/FlyWebFetchEvent.webidl b/dom/webidl/FlyWebFetchEvent.webidl
deleted file mode 100644
index 4bee424e5..000000000
--- a/dom/webidl/FlyWebFetchEvent.webidl
+++ /dev/null
@@ -1,13 +0,0 @@
-/* -*- 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/.
- */
-
-[Pref="dom.flyweb.enabled"]
-interface FlyWebFetchEvent : Event {
- [SameObject] readonly attribute Request request;
-
- [Throws]
- void respondWith(Promise<Response> r);
-};
diff --git a/dom/webidl/FlyWebPublish.webidl b/dom/webidl/FlyWebPublish.webidl
deleted file mode 100644
index 0c8714a2a..000000000
--- a/dom/webidl/FlyWebPublish.webidl
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- 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/.
- */
-
-[Pref="dom.flyweb.enabled"]
-interface FlyWebPublishedServer : EventTarget {
- readonly attribute DOMString name;
- readonly attribute DOMString? uiUrl;
-
- void close();
-
- attribute EventHandler onclose;
- attribute EventHandler onfetch;
- attribute EventHandler onwebsocket;
-};
-
-dictionary FlyWebPublishOptions {
- DOMString? uiUrl = null; // URL to user interface. Can be different server. Makes
- // endpoint show up in browser's "local services" UI.
- // If relative, resolves against the root of the server.
-};
diff --git a/dom/webidl/FlyWebWebSocketEvent.webidl b/dom/webidl/FlyWebWebSocketEvent.webidl
deleted file mode 100644
index 9a47c6dec..000000000
--- a/dom/webidl/FlyWebWebSocketEvent.webidl
+++ /dev/null
@@ -1,16 +0,0 @@
-/* -*- 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/.
- */
-
-[Pref="dom.flyweb.enabled"]
-interface FlyWebWebSocketEvent : Event {
- [SameObject] readonly attribute Request request;
-
- [Throws]
- WebSocket accept(optional DOMString protocol);
-
- [Throws]
- void respondWith(Promise<Response> r);
-};
diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl
index c353e8be7..4536d7d25 100644
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -132,12 +132,6 @@ partial interface Navigator {
Promise<BatteryManager> getBattery();
};
-partial interface Navigator {
- [NewObject, Pref="dom.flyweb.enabled"]
- Promise<FlyWebPublishedServer> publishServer(DOMString name,
- optional FlyWebPublishOptions options);
-};
-
// http://www.w3.org/TR/vibration/#vibration-interface
partial interface Navigator {
// We don't support sequences in unions yet
@@ -331,11 +325,6 @@ partial interface Navigator {
};
partial interface Navigator {
- [Throws, Pref="dom.presentation.enabled", SameObject]
- readonly attribute Presentation? presentation;
-};
-
-partial interface Navigator {
[NewObject, Func="mozilla::dom::TCPSocket::ShouldTCPSocketExist"]
readonly attribute LegacyMozTCPSocket mozTCPSocket;
};
diff --git a/dom/webidl/Performance.webidl b/dom/webidl/Performance.webidl
index 0bd2677df..e811e1cee 100644
--- a/dom/webidl/Performance.webidl
+++ b/dom/webidl/Performance.webidl
@@ -55,12 +55,14 @@ partial interface Performance {
attribute EventHandler onresourcetimingbufferfull;
};
+#ifdef MOZ_DEVTOOLS_SERVER
// GC microbenchmarks, pref-guarded, not for general use (bug 1125412)
[Exposed=Window]
partial interface Performance {
[Pref="dom.enable_memory_stats"]
readonly attribute object mozMemory;
};
+#endif
// http://www.w3.org/TR/user-timing/
[Exposed=(Window,Worker)]
diff --git a/dom/webidl/Presentation.webidl b/dom/webidl/Presentation.webidl
deleted file mode 100644
index d5b331616..000000000
--- a/dom/webidl/Presentation.webidl
+++ /dev/null
@@ -1,30 +0,0 @@
-/* -*- 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://w3c.github.io/presentation-api/#interface-presentation
- */
-
-[Pref="dom.presentation.enabled"]
-interface Presentation {
- /*
- * This should be used by the UA as the default presentation request for the
- * controller. When the UA wishes to initiate a PresentationConnection on the
- * controller's behalf, it MUST start a presentation connection using the default
- * presentation request (as if the controller had called |defaultRequest.start()|).
- *
- * Only used by controlling browsing context (senders).
- */
- [Pref="dom.presentation.controller.enabled"]
- attribute PresentationRequest? defaultRequest;
-
- /*
- * This should be available on the receiving browsing context in order to
- * access the controlling browsing context and communicate with them.
- */
- [SameObject,
- Pref="dom.presentation.receiver.enabled"]
- readonly attribute PresentationReceiver? receiver;
-};
diff --git a/dom/webidl/PresentationAvailability.webidl b/dom/webidl/PresentationAvailability.webidl
deleted file mode 100644
index f72b88565..000000000
--- a/dom/webidl/PresentationAvailability.webidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- 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://w3c.github.io/presentation-api/#interface-presentationavailability
- */
-
-[Pref="dom.presentation.controller.enabled"]
-interface PresentationAvailability : EventTarget {
- /*
- * If there is at least one device discovered by UA, the value is |true|.
- * Otherwise, its value should be |false|.
- */
- readonly attribute boolean value;
-
- /*
- * It is called when device availability changes.
- */
- attribute EventHandler onchange;
-};
diff --git a/dom/webidl/PresentationConnection.webidl b/dom/webidl/PresentationConnection.webidl
deleted file mode 100644
index 9676d2069..000000000
--- a/dom/webidl/PresentationConnection.webidl
+++ /dev/null
@@ -1,96 +0,0 @@
-/* -*- 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://w3c.github.io/presentation-api/#interface-presentationconnection
- */
-
-enum PresentationConnectionState
-{
- // The initial state when a PresentationConnection is ceated.
- "connecting",
-
- // Existing presentation, and the communication channel is active.
- "connected",
-
- // Existing presentation, but the communication channel is inactive.
- "closed",
-
- // The presentation is nonexistent anymore. It could be terminated manually,
- // or either controlling or receiving browsing context is no longer available.
- "terminated"
-};
-
-enum PresentationConnectionBinaryType
-{
- "blob",
- "arraybuffer"
-};
-
-[Pref="dom.presentation.enabled"]
-interface PresentationConnection : EventTarget {
- /*
- * Unique id for all existing connections.
- */
- [Constant]
- readonly attribute DOMString id;
-
- /*
- * Specifies the connection's presentation URL.
- */
- readonly attribute DOMString url;
-
- /*
- * @value "connected", "closed", or "terminated".
- */
- readonly attribute PresentationConnectionState state;
-
- attribute EventHandler onconnect;
- attribute EventHandler onclose;
- attribute EventHandler onterminate;
- attribute PresentationConnectionBinaryType binaryType;
-
- /*
- * After a communication channel has been established between the controlling
- * and receiving context, this function is called to send message out, and the
- * event handler "onmessage" will be invoked at the remote side.
- *
- * This function only works when the state is "connected".
- */
- [Throws]
- void send(DOMString data);
-
- [Throws]
- void send(Blob data);
-
- [Throws]
- void send(ArrayBuffer data);
-
- [Throws]
- void send(ArrayBufferView data);
-
- /*
- * It is triggered when receiving messages.
- */
- attribute EventHandler onmessage;
-
- /*
- * Both the controlling and receiving browsing context can close the
- * connection. Then the connection state should turn into "closed".
- *
- * This function only works when the state is "connected" or "connecting".
- */
- [Throws]
- void close();
-
- /*
- * Both the controlling and receiving browsing context can terminate the
- * connection. Then the connection state should turn into "terminated".
- *
- * This function only works when the state is not "connected".
- */
- [Throws]
- void terminate();
-};
diff --git a/dom/webidl/PresentationConnectionAvailableEvent.webidl b/dom/webidl/PresentationConnectionAvailableEvent.webidl
deleted file mode 100644
index 9efecb7d6..000000000
--- a/dom/webidl/PresentationConnectionAvailableEvent.webidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- 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://w3c.github.io/presentation-api/#interface-presentationconnectionavailableevent
- */
-
-[Constructor(DOMString type,
- PresentationConnectionAvailableEventInit eventInitDict),
- Pref="dom.presentation.enabled"]
-interface PresentationConnectionAvailableEvent : Event
-{
- [SameObject]
- readonly attribute PresentationConnection connection;
-};
-
-dictionary PresentationConnectionAvailableEventInit : EventInit
-{
- required PresentationConnection connection;
-};
diff --git a/dom/webidl/PresentationConnectionCloseEvent.webidl b/dom/webidl/PresentationConnectionCloseEvent.webidl
deleted file mode 100644
index da6c25545..000000000
--- a/dom/webidl/PresentationConnectionCloseEvent.webidl
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- 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://w3c.github.io/presentation-api/#interface-presentationconnectioncloseevent
- */
-
-enum PresentationConnectionClosedReason
-{
- // The communication encountered an unrecoverable error.
- "error",
-
- // |PresentationConnection.close()| is called by controlling browsing context
- // or the receiving browsing context.
- "closed",
-
- // The connection is closed because the destination browsing context
- // that owned the connection navigated or was discarded.
- "wentaway"
-};
-
-[Constructor(DOMString type,
- PresentationConnectionCloseEventInit eventInitDict),
- Pref="dom.presentation.enabled"]
-interface PresentationConnectionCloseEvent : Event
-{
- readonly attribute PresentationConnectionClosedReason reason;
-
- // The message is a human readable description of
- // how the communication channel encountered an error.
- // It is empty when the closed reason is closed or wentaway.
- readonly attribute DOMString message;
-};
-
-dictionary PresentationConnectionCloseEventInit : EventInit
-{
- required PresentationConnectionClosedReason reason;
- DOMString message = "";
-};
diff --git a/dom/webidl/PresentationConnectionList.webidl b/dom/webidl/PresentationConnectionList.webidl
deleted file mode 100644
index 2c90ce9de..000000000
--- a/dom/webidl/PresentationConnectionList.webidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/* -*- 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://w3c.github.io/presentation-api/#interface-presentationconnectionlist
- */
-
-[Pref="dom.presentation.receiver.enabled"]
-interface PresentationConnectionList : EventTarget {
- /*
- * Return the non-terminated set of presentation connections in the
- * set of presentation controllers.
- * TODO: Use FrozenArray once available. (Bug 1236777)
- * readonly attribute FrozenArray<PresentationConnection> connections;
- */
- [Frozen, Cached, Pure]
- readonly attribute sequence<PresentationConnection> connections;
-
- /*
- * It is called when an incoming connection is connected.
- */
- attribute EventHandler onconnectionavailable;
-};
diff --git a/dom/webidl/PresentationDeviceInfoManager.webidl b/dom/webidl/PresentationDeviceInfoManager.webidl
deleted file mode 100644
index 6ccace324..000000000
--- a/dom/webidl/PresentationDeviceInfoManager.webidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- 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/.
- */
-
-dictionary PresentationDeviceInfo {
- DOMString id;
- DOMString name;
- DOMString type;
-};
-
-[NavigatorProperty="mozPresentationDeviceInfo",
- JSImplementation="@mozilla.org/presentation-device/deviceInfo;1",
- Pref="dom.presentation.enabled",
- ChromeOnly]
-interface PresentationDeviceInfoManager : EventTarget {
- // notify if any device updated.
- attribute EventHandler ondevicechange;
-
- // retrieve all available device infos
- Promise<sequence<PresentationDeviceInfo>> getAll();
-
- // Force all registered device provider to update device information.
- void forceDiscovery();
-};
diff --git a/dom/webidl/PresentationReceiver.webidl b/dom/webidl/PresentationReceiver.webidl
deleted file mode 100644
index 4acb37cf3..000000000
--- a/dom/webidl/PresentationReceiver.webidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* -*- 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://w3c.github.io/presentation-api/#interface-presentationreceiver
- */
-
-[Pref="dom.presentation.receiver.enabled"]
-interface PresentationReceiver {
- /*
- * Get a list which contains all connected presentation connections
- * in a receiving browsing context.
- */
- [SameObject, Throws]
- readonly attribute Promise<PresentationConnectionList> connectionList;
-};
diff --git a/dom/webidl/PresentationRequest.webidl b/dom/webidl/PresentationRequest.webidl
deleted file mode 100644
index c0c5fb8a6..000000000
--- a/dom/webidl/PresentationRequest.webidl
+++ /dev/null
@@ -1,86 +0,0 @@
-/* -*- 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://w3c.github.io/presentation-api/#interface-presentationrequest
- */
-
-[Constructor(DOMString url),
- Constructor(sequence<DOMString> urls),
- Pref="dom.presentation.controller.enabled"]
-interface PresentationRequest : EventTarget {
- /*
- * A requesting page use start() to start a new connection, and it will be
- * returned with the promise. UA may show a prompt box with a list of
- * available devices and ask the user to grant permission, choose a device, or
- * cancel the operation.
- *
- * The promise is resolved when the presenting page is successfully loaded and
- * the communication channel is established, i.e., the connection state is
- * "connected".
- *
- * The promise may be rejected duo to one of the following reasons:
- * - "OperationError": Unexpected error occurs.
- * - "NotFoundError": No available device.
- * - "AbortError": User dismiss/cancel the device prompt box.
- * - "NetworkError": Failed to establish the control channel or data channel.
- * - "TimeoutError": Presenting page takes too long to load.
- * - "SecurityError": This operation is insecure.
- */
- [Throws]
- Promise<PresentationConnection> start();
-
- /*
- * A requesting page can use reconnect(presentationId) to reopen a
- * non-terminated presentation connection.
- *
- * The promise is resolved when a new presentation connection is created.
- * The connection state is "connecting".
- *
- * The promise may be rejected duo to one of the following reasons:
- * - "OperationError": Unexpected error occurs.
- * - "NotFoundError": Can not find a presentation connection with the presentationId.
- * - "SecurityError": This operation is insecure.
- */
- [Throws]
- Promise<PresentationConnection> reconnect(DOMString presentationId);
-
- /*
- * UA triggers device discovery mechanism periodically and monitor device
- * availability.
- *
- * The promise may be rejected duo to one of the following reasons:
- * - "NotSupportedError": Unable to continuously monitor the availability.
- * - "SecurityError": This operation is insecure.
- */
- [Throws]
- Promise<PresentationAvailability> getAvailability();
-
- /*
- * It is called when a connection associated with a PresentationRequest is created.
- * The event is fired for all connections that are created for the controller.
- */
- attribute EventHandler onconnectionavailable;
-
- /*
- * A chrome page, or page which has presentation-device-manage permissiongs,
- * uses startWithDevice() to start a new connection with specified device,
- * and it will be returned with the promise. UA may show a prompt box with a
- * list of available devices and ask the user to grant permission, choose a
- * device, or cancel the operation.
- *
- * The promise is resolved when the presenting page is successfully loaded and
- * the communication channel is established, i.e., the connection state is
- * "connected".
- *
- * The promise may be rejected duo to one of the following reasons:
- * - "OperationError": Unexpected error occurs.
- * - "NotFoundError": No available device.
- * - "NetworkError": Failed to establish the control channel or data channel.
- * - "TimeoutError": Presenting page takes too long to load.
- */
- [ChromeOnly, Throws]
- Promise<PresentationConnection> startWithDevice(DOMString deviceId);
-};
diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build
index 4e3b8f655..156da302d 100644
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -12,6 +12,7 @@ PREPROCESSED_WEBIDL_FILES = [
'HTMLMediaElement.webidl',
'Navigator.webidl',
'Node.webidl',
+ 'Performance.webidl',
'Window.webidl',
]
@@ -151,10 +152,6 @@ WEBIDL_FILES = [
'FileSystemDirectoryReader.webidl',
'FileSystemEntry.webidl',
'FileSystemFileEntry.webidl',
- 'FlyWebDiscoveryManager.webidl',
- 'FlyWebFetchEvent.webidl',
- 'FlyWebPublish.webidl',
- 'FlyWebWebSocketEvent.webidl',
'FocusEvent.webidl',
'FontFace.webidl',
'FontFaceSet.webidl',
@@ -285,15 +282,7 @@ WEBIDL_FILES = [
'MediaDeviceInfo.webidl',
'MediaDevices.webidl',
'MediaElementAudioSourceNode.webidl',
- 'MediaEncryptedEvent.webidl',
'MediaError.webidl',
- 'MediaKeyError.webidl',
- 'MediaKeyMessageEvent.webidl',
- 'MediaKeys.webidl',
- 'MediaKeySession.webidl',
- 'MediaKeysRequestStatus.webidl',
- 'MediaKeyStatusMap.webidl',
- 'MediaKeySystemAccess.webidl',
'MediaList.webidl',
'MediaQueryList.webidl',
'MediaRecorder.webidl',
@@ -341,7 +330,6 @@ WEBIDL_FILES = [
'PaintRequestList.webidl',
'PannerNode.webidl',
'ParentNode.webidl',
- 'Performance.webidl',
'PerformanceEntry.webidl',
'PerformanceMark.webidl',
'PerformanceMeasure.webidl',
@@ -361,13 +349,6 @@ WEBIDL_FILES = [
'PopupBoxObject.webidl',
'Position.webidl',
'PositionError.webidl',
- 'Presentation.webidl',
- 'PresentationAvailability.webidl',
- 'PresentationConnection.webidl',
- 'PresentationConnectionList.webidl',
- 'PresentationDeviceInfoManager.webidl',
- 'PresentationReceiver.webidl',
- 'PresentationRequest.webidl',
'ProcessingInstruction.webidl',
'ProfileTimelineMarker.webidl',
'Promise.webidl',
@@ -565,7 +546,6 @@ WEBIDL_FILES = [
'WebKitCSSMatrix.webidl',
'WebSocket.webidl',
'WheelEvent.webidl',
- 'WidevineCDMManifest.webidl',
'WifiOptions.webidl',
'WindowOrWorkerGlobalScope.webidl',
'WindowRoot.webidl',
@@ -592,6 +572,19 @@ WEBIDL_FILES = [
'XULElement.webidl',
]
+if CONFIG['MOZ_EME']:
+ WEBIDL_FILES += [
+ 'MediaEncryptedEvent.webidl',
+ 'MediaKeyError.webidl',
+ 'MediaKeyMessageEvent.webidl',
+ 'MediaKeys.webidl',
+ 'MediaKeySession.webidl',
+ 'MediaKeysRequestStatus.webidl',
+ 'MediaKeyStatusMap.webidl',
+ 'MediaKeySystemAccess.webidl',
+ 'WidevineCDMManifest.webidl',
+ ]
+
if CONFIG['MOZ_AUDIO_CHANNEL_MANAGER']:
WEBIDL_FILES += [
'AudioChannelManager.webidl',
@@ -702,8 +695,6 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'PluginCrashedEvent.webidl',
'PopStateEvent.webidl',
'PopupBlockedEvent.webidl',
- 'PresentationConnectionAvailableEvent.webidl',
- 'PresentationConnectionCloseEvent.webidl',
'ProgressEvent.webidl',
'RecordErrorEvent.webidl',
'ScrollViewChangeEvent.webidl',