Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
4 "use strict";
6 const Cc = Components.classes;
7 const Ci = Components.interfaces;
8 const Cr = Components.results;
9 const Cu = Components.utils;
11 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
12 Cu.import("resource://gre/modules/Services.jsm");
14 XPCOMUtils.defineLazyGetter(this, "cpmm", function() {
15 return Cc["@mozilla.org/childprocessmessagemanager;1"]
16 .getService(Ci.nsIMessageSender);
17 });
19 function debug(aMsg) {
20 //dump("--*-- ContentHandler: " + aMsg + "\n");
21 }
23 const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001;
25 let ActivityContentFactory = {
26 createInstance: function createInstance(outer, iid) {
27 if (outer != null) {
28 throw Cr.NS_ERROR_NO_AGGREGATION;
29 }
30 return new ActivityContentHandler().QueryInterface(iid);
31 },
33 QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
34 }
36 function ActivityContentHandler() {
37 }
39 ActivityContentHandler.prototype = {
40 handleContent: function handleContent(aMimetype, aContext, aRequest) {
41 if (!(aRequest instanceof Ci.nsIChannel))
42 throw NS_ERROR_WONT_HANDLE_CONTENT;
44 let detail = {
45 "type": aMimetype,
46 "url": aRequest.URI.spec
47 };
48 cpmm.sendAsyncMessage("content-handler", detail);
50 aRequest.cancel(Cr.NS_BINDING_ABORTED);
51 },
53 QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler])
54 }
56 function ContentHandler() {
57 this.classIdMap = {};
58 }
60 ContentHandler.prototype = {
61 observe: function(aSubject, aTopic, aData) {
62 if (aTopic == "app-startup") {
63 // We only want to register these from content processes.
64 let appInfo = Cc["@mozilla.org/xre/app-info;1"];
65 if (appInfo.getService(Ci.nsIXULRuntime)
66 .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
67 return;
68 }
69 }
71 cpmm.addMessageListener("Activities:RegisterContentTypes", this);
72 cpmm.addMessageListener("Activities:UnregisterContentTypes", this);
73 cpmm.sendAsyncMessage("Activities:GetContentTypes", { });
74 },
76 /**
77 * Do the component registration for a content type.
78 * We only need to register one component per content type, even if several
79 * apps provide it, so we keep track of the number of providers for each
80 * content type.
81 */
82 registerContentHandler: function registerContentHandler(aContentType) {
83 debug("Registering " + aContentType);
85 // We already have a provider for this content type, just increase the
86 // tracking count.
87 if (this.classIdMap[aContentType]) {
88 this.classIdMap[aContentType].count++;
89 return;
90 }
92 let contractID = "@mozilla.org/uriloader/content-handler;1?type=" +
93 aContentType;
94 let uuidGen = Cc["@mozilla.org/uuid-generator;1"]
95 .getService(Ci.nsIUUIDGenerator);
96 let id = Components.ID(uuidGen.generateUUID().toString());
97 this.classIdMap[aContentType] = { count: 1, id: id };
98 let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
99 cr.registerFactory(Components.ID(id), "Activity Content Handler", contractID,
100 ActivityContentFactory);
101 },
103 /**
104 * Do the component unregistration for a content type.
105 */
106 unregisterContentHandler: function registerContentHandler(aContentType) {
107 debug("Unregistering " + aContentType);
109 let record = this.classIdMap[aContentType];
110 if (!record) {
111 return;
112 }
114 // Bail out if we still have providers left for this content type.
115 if (--record.count > 0) {
116 return;
117 }
119 let contractID = "@mozilla.org/uriloader/content-handler;1?type=" +
120 aContentType;
121 let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
122 cr.unregisterFactory(record.id, ActivityContentFactory);
123 delete this.classIdMap[aContentType]
124 },
126 receiveMessage: function(aMessage) {
127 let data = aMessage.data;
129 switch (aMessage.name) {
130 case "Activities:RegisterContentTypes":
131 data.contentTypes.forEach(this.registerContentHandler, this);
132 break;
133 case "Activities:UnregisterContentTypes":
134 data.contentTypes.forEach(this.unregisterContentHandler, this);
135 break;
136 }
137 },
139 classID: Components.ID("{d18d0216-d50c-11e1-ba54-efb18d0ef0ac}"),
140 QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler,
141 Ci.nsIObserver,
142 Ci.nsISupportsWeakReference])
143 };
145 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentHandler]);