toolkit/modules/RemoteWebProgress.jsm

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:5b92bfc4c0ce
1 // -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // This Source Code Form is subject to the terms of the Mozilla Public
3 // License, v. 2.0. If a copy of the MPL was not distributed with this
4 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
6 this.EXPORTED_SYMBOLS = ["RemoteWebProgressManager"];
7
8 const Ci = Components.interfaces;
9 const Cc = Components.classes;
10 const Cu = Components.utils;
11
12 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
13
14 function newURI(spec)
15 {
16 return Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService)
17 .newURI(spec, null, null);
18 }
19
20 function RemoteWebProgressRequest(spec)
21 {
22 this.uri = newURI(spec);
23 }
24
25 RemoteWebProgressRequest.prototype = {
26 QueryInterface : XPCOMUtils.generateQI([Ci.nsIChannel]),
27
28 get URI() { return this.uri.clone(); }
29 };
30
31 function RemoteWebProgress(aManager, aIsTopLevel) {
32 this._manager = aManager;
33
34 this._isLoadingDocument = false;
35 this._DOMWindow = null;
36 this._isTopLevel = aIsTopLevel;
37 this._loadType = 0;
38 }
39
40 RemoteWebProgress.prototype = {
41 NOTIFY_STATE_REQUEST: 0x00000001,
42 NOTIFY_STATE_DOCUMENT: 0x00000002,
43 NOTIFY_STATE_NETWORK: 0x00000004,
44 NOTIFY_STATE_WINDOW: 0x00000008,
45 NOTIFY_STATE_ALL: 0x0000000f,
46 NOTIFY_PROGRESS: 0x00000010,
47 NOTIFY_STATUS: 0x00000020,
48 NOTIFY_SECURITY: 0x00000040,
49 NOTIFY_LOCATION: 0x00000080,
50 NOTIFY_REFRESH: 0x00000100,
51 NOTIFY_ALL: 0x000001ff,
52
53 get isLoadingDocument() { return this._isLoadingDocument },
54 get DOMWindow() { return this._DOMWindow; },
55 get DOMWindowID() { return 0; },
56 get isTopLevel() { return this._isTopLevel },
57 get loadType() { return this._loadType; },
58
59 addProgressListener: function (aListener) {
60 this._manager.addProgressListener(aListener);
61 },
62
63 removeProgressListener: function (aListener) {
64 this._manager.removeProgressListener(aListener);
65 }
66 };
67
68 function RemoteWebProgressManager (aBrowser) {
69 this._browser = aBrowser;
70 this._topLevelWebProgress = new RemoteWebProgress(this, true);
71 this._progressListeners = [];
72
73 this._browser.messageManager.addMessageListener("Content:StateChange", this);
74 this._browser.messageManager.addMessageListener("Content:LocationChange", this);
75 this._browser.messageManager.addMessageListener("Content:SecurityChange", this);
76 this._browser.messageManager.addMessageListener("Content:StatusChange", this);
77 }
78
79 RemoteWebProgressManager.prototype = {
80 get topLevelWebProgress() {
81 return this._topLevelWebProgress;
82 },
83
84 addProgressListener: function (aListener) {
85 let listener = aListener.QueryInterface(Ci.nsIWebProgressListener);
86 this._progressListeners.push(listener);
87 },
88
89 removeProgressListener: function (aListener) {
90 this._progressListeners =
91 this._progressListeners.filter(l => l != aListener);
92 },
93
94 _fixSSLStatusAndState: function (aStatus, aState) {
95 let deserialized = null;
96 if (aStatus) {
97 let helper = Cc["@mozilla.org/network/serialization-helper;1"]
98 .getService(Components.interfaces.nsISerializationHelper);
99
100 deserialized = helper.deserializeObject(aStatus)
101 deserialized.QueryInterface(Ci.nsISSLStatus);
102 }
103
104 // We must check the Extended Validation (EV) state here, on the chrome
105 // process, because NSS is needed for that determination.
106 if (deserialized && deserialized.isExtendedValidation)
107 aState |= Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL;
108
109 return [deserialized, aState];
110 },
111
112 setCurrentURI: function (aURI) {
113 // This function is simpler than nsDocShell::SetCurrentURI since
114 // it doesn't have to deal with child docshells.
115 let webNavigation = this._browser.webNavigation;
116 webNavigation._currentURI = aURI;
117
118 let webProgress = this.topLevelWebProgress;
119 for (let p of this._progressListeners) {
120 p.onLocationChange(webProgress, null, aURI);
121 }
122 },
123
124 _callProgressListeners: function(methodName, ...args) {
125 for (let p of this._progressListeners) {
126 if (p[methodName]) {
127 try {
128 p[methodName].apply(p, args);
129 } catch (ex) {
130 Cu.reportError("RemoteWebProgress failed to call " + methodName + ": " + ex + "\n");
131 }
132 }
133 }
134 },
135
136 receiveMessage: function (aMessage) {
137 let json = aMessage.json;
138 let objects = aMessage.objects;
139
140 // The top-level WebProgress is always the same, but because we don't
141 // really have a concept of subframes/content we always creat a new object
142 // for those.
143 let webProgress = json.isTopLevel ? this._topLevelWebProgress
144 : new RemoteWebProgress(this, false);
145
146 // The WebProgressRequest object however is always dynamic.
147 let request = json.requestURI ? new RemoteWebProgressRequest(json.requestURI)
148 : null;
149
150 // Update the actual WebProgress fields.
151 webProgress._isLoadingDocument = json.isLoadingDocument;
152 webProgress._DOMWindow = objects.DOMWindow;
153 webProgress._loadType = json.loadType;
154
155 if (json.isTopLevel) {
156 this._browser._contentWindow = objects.contentWindow;
157 this._browser._documentContentType = json.documentContentType;
158 }
159
160 switch (aMessage.name) {
161 case "Content:StateChange":
162 this._callProgressListeners("onStateChange", webProgress, request, json.stateFlags, json.status);
163 break;
164
165 case "Content:LocationChange":
166 let location = newURI(json.location);
167 let flags = json.flags;
168
169 if (json.isTopLevel) {
170 this._browser.webNavigation._currentURI = location;
171 this._browser.webNavigation.canGoBack = json.canGoBack;
172 this._browser.webNavigation.canGoForward = json.canGoForward;
173 this._browser._characterSet = json.charset;
174 this._browser._documentURI = newURI(json.documentURI);
175 this._browser._imageDocument = null;
176 }
177
178 this._callProgressListeners("onLocationChange", webProgress, request, location, flags);
179 break;
180
181 case "Content:SecurityChange":
182 let [status, state] = this._fixSSLStatusAndState(json.status, json.state);
183
184 if (json.isTopLevel) {
185 // Invoking this getter triggers the generation of the underlying object,
186 // which we need to access with ._securityUI, because .securityUI returns
187 // a wrapper that makes _update inaccessible.
188 void this._browser.securityUI;
189 this._browser._securityUI._update(status, state);
190 }
191
192 this._callProgressListeners("onSecurityChange", webProgress, request, state);
193 break;
194
195 case "Content:StatusChange":
196 this._callProgressListeners("onStatusChange", webProgress, request, json.status, json.message);
197 break;
198 }
199 }
200 };

mercurial