Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 'use strict';
7 this.EXPORTED_SYMBOLS = ['Keyboard'];
9 const Cu = Components.utils;
10 const Cc = Components.classes;
11 const Ci = Components.interfaces;
13 Cu.import('resource://gre/modules/Services.jsm');
14 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
16 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
17 "@mozilla.org/parentprocessmessagemanager;1", "nsIMessageBroadcaster");
19 XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
20 "resource://gre/modules/SystemAppProxy.jsm");
22 this.Keyboard = {
23 _formMM: null, // The current web page message manager.
24 _keyboardMM: null, // The keyboard app message manager.
25 _systemMessageName: [
26 'SetValue', 'RemoveFocus', 'SetSelectedOption', 'SetSelectedOptions'
27 ],
29 _messageNames: [
30 'SetSelectionRange', 'ReplaceSurroundingText', 'ShowInputMethodPicker',
31 'SwitchToNextInputMethod', 'HideInputMethod',
32 'GetText', 'SendKey', 'GetContext',
33 'SetComposition', 'EndComposition',
34 'Register', 'Unregister'
35 ],
37 get formMM() {
38 if (this._formMM && !Cu.isDeadWrapper(this._formMM))
39 return this._formMM;
41 return null;
42 },
44 set formMM(mm) {
45 this._formMM = mm;
46 },
48 sendToForm: function(name, data) {
49 try {
50 this.formMM.sendAsyncMessage(name, data);
51 } catch(e) { }
52 },
54 sendToKeyboard: function(name, data) {
55 try {
56 this._keyboardMM.sendAsyncMessage(name, data);
57 } catch(e) { }
58 },
60 init: function keyboardInit() {
61 Services.obs.addObserver(this, 'inprocess-browser-shown', false);
62 Services.obs.addObserver(this, 'remote-browser-shown', false);
63 Services.obs.addObserver(this, 'oop-frameloader-crashed', false);
65 for (let name of this._messageNames) {
66 ppmm.addMessageListener('Keyboard:' + name, this);
67 }
69 for (let name of this._systemMessageName) {
70 ppmm.addMessageListener('System:' + name, this);
71 }
72 },
74 observe: function keyboardObserve(subject, topic, data) {
75 let frameLoader = subject.QueryInterface(Ci.nsIFrameLoader);
76 let mm = frameLoader.messageManager;
78 if (topic == 'oop-frameloader-crashed') {
79 if (this.formMM == mm) {
80 // The application has been closed unexpectingly. Let's tell the
81 // keyboard app that the focus has been lost.
82 this.sendToKeyboard('Keyboard:FocusChange', { 'type': 'blur' });
83 }
84 } else {
85 // Ignore notifications that aren't from a BrowserOrApp
86 if (!frameLoader.ownerIsBrowserOrAppFrame) {
87 return;
88 }
89 this.initFormsFrameScript(mm);
90 }
91 },
93 initFormsFrameScript: function(mm) {
94 mm.addMessageListener('Forms:Input', this);
95 mm.addMessageListener('Forms:SelectionChange', this);
96 mm.addMessageListener('Forms:GetText:Result:OK', this);
97 mm.addMessageListener('Forms:GetText:Result:Error', this);
98 mm.addMessageListener('Forms:SetSelectionRange:Result:OK', this);
99 mm.addMessageListener('Forms:SetSelectionRange:Result:Error', this);
100 mm.addMessageListener('Forms:ReplaceSurroundingText:Result:OK', this);
101 mm.addMessageListener('Forms:ReplaceSurroundingText:Result:Error', this);
102 mm.addMessageListener('Forms:SendKey:Result:OK', this);
103 mm.addMessageListener('Forms:SendKey:Result:Error', this);
104 mm.addMessageListener('Forms:SequenceError', this);
105 mm.addMessageListener('Forms:GetContext:Result:OK', this);
106 mm.addMessageListener('Forms:SetComposition:Result:OK', this);
107 mm.addMessageListener('Forms:EndComposition:Result:OK', this);
108 },
110 receiveMessage: function keyboardReceiveMessage(msg) {
111 // If we get a 'Keyboard:XXX'/'System:XXX' message, check that the sender
112 // has the required permission.
113 let mm;
114 let isKeyboardRegistration = msg.name == "Keyboard:Register" ||
115 msg.name == "Keyboard:Unregister";
116 if (msg.name.indexOf("Keyboard:") === 0 ||
117 msg.name.indexOf("System:") === 0) {
118 if (!this.formMM && !isKeyboardRegistration) {
119 return;
120 }
122 try {
123 mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
124 .frameLoader.messageManager;
125 } catch(e) {
126 mm = msg.target;
127 }
129 // That should never happen.
130 if (!mm) {
131 dump("!! No message manager found for " + msg.name);
132 return;
133 }
135 let testing = false;
136 try {
137 testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
138 } catch (e) {
139 }
141 let perm = (msg.name.indexOf("Keyboard:") === 0) ? "input"
142 : "input-manage";
143 if (!isKeyboardRegistration && !testing &&
144 !mm.assertPermission(perm)) {
145 dump("Keyboard message " + msg.name +
146 " from a content process with no '" + perm + "' privileges.");
147 return;
148 }
149 }
151 switch (msg.name) {
152 case 'Forms:Input':
153 this.handleFocusChange(msg);
154 break;
155 case 'Forms:SelectionChange':
156 case 'Forms:GetText:Result:OK':
157 case 'Forms:GetText:Result:Error':
158 case 'Forms:SetSelectionRange:Result:OK':
159 case 'Forms:ReplaceSurroundingText:Result:OK':
160 case 'Forms:SendKey:Result:OK':
161 case 'Forms:SendKey:Result:Error':
162 case 'Forms:SequenceError':
163 case 'Forms:GetContext:Result:OK':
164 case 'Forms:SetComposition:Result:OK':
165 case 'Forms:EndComposition:Result:OK':
166 case 'Forms:SetSelectionRange:Result:Error':
167 case 'Forms:ReplaceSurroundingText:Result:Error':
168 let name = msg.name.replace(/^Forms/, 'Keyboard');
169 this.forwardEvent(name, msg);
170 break;
172 case 'System:SetValue':
173 this.setValue(msg);
174 break;
175 case 'Keyboard:RemoveFocus':
176 case 'System:RemoveFocus':
177 this.removeFocus();
178 break;
179 case 'System:SetSelectedOption':
180 this.setSelectedOption(msg);
181 break;
182 case 'System:SetSelectedOptions':
183 this.setSelectedOption(msg);
184 break;
185 case 'Keyboard:SetSelectionRange':
186 this.setSelectionRange(msg);
187 break;
188 case 'Keyboard:ReplaceSurroundingText':
189 this.replaceSurroundingText(msg);
190 break;
191 case 'Keyboard:SwitchToNextInputMethod':
192 this.switchToNextInputMethod();
193 break;
194 case 'Keyboard:ShowInputMethodPicker':
195 this.showInputMethodPicker();
196 break;
197 case 'Keyboard:GetText':
198 this.getText(msg);
199 break;
200 case 'Keyboard:SendKey':
201 this.sendKey(msg);
202 break;
203 case 'Keyboard:GetContext':
204 this.getContext(msg);
205 break;
206 case 'Keyboard:SetComposition':
207 this.setComposition(msg);
208 break;
209 case 'Keyboard:EndComposition':
210 this.endComposition(msg);
211 break;
212 case 'Keyboard:Register':
213 this._keyboardMM = mm;
214 break;
215 case 'Keyboard:Unregister':
216 this._keyboardMM = null;
217 break;
218 }
219 },
221 forwardEvent: function keyboardForwardEvent(newEventName, msg) {
222 this.formMM = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
223 .frameLoader.messageManager;
225 this.sendToKeyboard(newEventName, msg.data);
226 },
228 handleFocusChange: function keyboardHandleFocusChange(msg) {
229 this.forwardEvent('Keyboard:FocusChange', msg);
231 // Chrome event, used also to render value selectors; that's why we need
232 // the info about choices / min / max here as well...
233 SystemAppProxy.dispatchEvent({
234 type: 'inputmethod-contextchange',
235 inputType: msg.data.type,
236 value: msg.data.value,
237 choices: JSON.stringify(msg.data.choices),
238 min: msg.data.min,
239 max: msg.data.max
240 });
241 },
243 setSelectedOption: function keyboardSetSelectedOption(msg) {
244 this.sendToForm('Forms:Select:Choice', msg.data);
245 },
247 setSelectedOptions: function keyboardSetSelectedOptions(msg) {
248 this.sendToForm('Forms:Select:Choice', msg.data);
249 },
251 setSelectionRange: function keyboardSetSelectionRange(msg) {
252 this.sendToForm('Forms:SetSelectionRange', msg.data);
253 },
255 setValue: function keyboardSetValue(msg) {
256 this.sendToForm('Forms:Input:Value', msg.data);
257 },
259 removeFocus: function keyboardRemoveFocus() {
260 this.sendToForm('Forms:Select:Blur', {});
261 },
263 replaceSurroundingText: function keyboardReplaceSurroundingText(msg) {
264 this.sendToForm('Forms:ReplaceSurroundingText', msg.data);
265 },
267 showInputMethodPicker: function keyboardShowInputMethodPicker() {
268 SystemAppProxy.dispatchEvent({
269 type: "inputmethod-showall"
270 });
271 },
273 switchToNextInputMethod: function keyboardSwitchToNextInputMethod() {
274 SystemAppProxy.dispatchEvent({
275 type: "inputmethod-next"
276 });
277 },
279 getText: function keyboardGetText(msg) {
280 this.sendToForm('Forms:GetText', msg.data);
281 },
283 sendKey: function keyboardSendKey(msg) {
284 this.sendToForm('Forms:Input:SendKey', msg.data);
285 },
287 getContext: function keyboardGetContext(msg) {
288 if (this._layouts) {
289 this.sendToKeyboard('Keyboard:LayoutsChange', this._layouts);
290 }
292 this.sendToForm('Forms:GetContext', msg.data);
293 },
295 setComposition: function keyboardSetComposition(msg) {
296 this.sendToForm('Forms:SetComposition', msg.data);
297 },
299 endComposition: function keyboardEndComposition(msg) {
300 this.sendToForm('Forms:EndComposition', msg.data);
301 },
303 /**
304 * Get the number of keyboard layouts active from keyboard_manager
305 */
306 _layouts: null,
307 setLayouts: function keyboardSetLayoutCount(layouts) {
308 // The input method plugins may not have loaded yet,
309 // cache the layouts so on init we can respond immediately instead
310 // of going back and forth between keyboard_manager
311 this._layouts = layouts;
313 this.sendToKeyboard('Keyboard:LayoutsChange', layouts);
314 }
315 };
317 this.Keyboard.init();