|
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 |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 let Ci = Components.interfaces; |
|
6 let Cu = Components.utils; |
|
7 |
|
8 Cu.import('resource://gre/modules/XPCOMUtils.jsm'); |
|
9 Cu.import('resource://gre/modules/Services.jsm'); |
|
10 Cu.import('resource://gre/modules/DOMRequestHelper.jsm'); |
|
11 |
|
12 XPCOMUtils.defineLazyModuleGetter(this, 'GlobalSimulatorScreen', |
|
13 'resource://gre/modules/GlobalSimulatorScreen.jsm'); |
|
14 |
|
15 let DEBUG_PREFIX = 'SimulatorScreen.js - '; |
|
16 function debug() { |
|
17 //dump(DEBUG_PREFIX + Array.slice(arguments) + '\n'); |
|
18 } |
|
19 |
|
20 function fireOrientationEvent(window) { |
|
21 let e = new window.Event('mozorientationchange'); |
|
22 window.screen.dispatchEvent(e); |
|
23 } |
|
24 |
|
25 function hookScreen(window) { |
|
26 let nodePrincipal = window.document.nodePrincipal; |
|
27 let origin = nodePrincipal.origin; |
|
28 if (nodePrincipal.appStatus == nodePrincipal.APP_STATUS_NOT_INSTALLED) { |
|
29 Cu.reportError('deny mozLockOrientation:' + origin + 'is not installed'); |
|
30 return; |
|
31 } |
|
32 |
|
33 let screen = window.wrappedJSObject.screen; |
|
34 |
|
35 screen.mozLockOrientation = function (orientation) { |
|
36 debug('mozLockOrientation:', orientation, 'from', origin); |
|
37 |
|
38 // Normalize and do some checks against orientation input |
|
39 if (typeof(orientation) == 'string') { |
|
40 orientation = [orientation]; |
|
41 } |
|
42 |
|
43 function isInvalidOrientationString(str) { |
|
44 return typeof(str) != 'string' || |
|
45 !str.match(/^default$|^(portrait|landscape)(-(primary|secondary))?$/); |
|
46 } |
|
47 if (!Array.isArray(orientation) || |
|
48 orientation.some(isInvalidOrientationString)) { |
|
49 Cu.reportError('Invalid orientation "' + orientation + '"'); |
|
50 return false; |
|
51 } |
|
52 |
|
53 GlobalSimulatorScreen.lock(orientation); |
|
54 |
|
55 return true; |
|
56 }; |
|
57 |
|
58 screen.mozUnlockOrientation = function() { |
|
59 debug('mozOrientationUnlock from', origin); |
|
60 GlobalSimulatorScreen.unlock(); |
|
61 return true; |
|
62 }; |
|
63 |
|
64 Object.defineProperty(screen, 'width', { |
|
65 get: function () GlobalSimulatorScreen.width |
|
66 }); |
|
67 Object.defineProperty(screen, 'height', { |
|
68 get: function () GlobalSimulatorScreen.height |
|
69 }); |
|
70 Object.defineProperty(screen, 'mozOrientation', { |
|
71 get: function () GlobalSimulatorScreen.mozOrientation |
|
72 }); |
|
73 } |
|
74 |
|
75 function SimulatorScreen() {} |
|
76 SimulatorScreen.prototype = { |
|
77 classID: Components.ID('{c83c02c0-5d43-4e3e-987f-9173b313e880}'), |
|
78 QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, |
|
79 Ci.nsISupportsWeakReference]), |
|
80 _windows: new Map(), |
|
81 |
|
82 observe: function (subject, topic, data) { |
|
83 let windows = this._windows; |
|
84 switch (topic) { |
|
85 case 'profile-after-change': |
|
86 Services.obs.addObserver(this, 'document-element-inserted', false); |
|
87 Services.obs.addObserver(this, 'simulator-orientation-change', false); |
|
88 Services.obs.addObserver(this, 'inner-window-destroyed', false); |
|
89 break; |
|
90 |
|
91 case 'document-element-inserted': |
|
92 let window = subject.defaultView; |
|
93 if (!window) { |
|
94 return; |
|
95 } |
|
96 |
|
97 hookScreen(window); |
|
98 |
|
99 var id = window.QueryInterface(Ci.nsIInterfaceRequestor) |
|
100 .getInterface(Ci.nsIDOMWindowUtils) |
|
101 .currentInnerWindowID; |
|
102 windows.set(id, window); |
|
103 break; |
|
104 |
|
105 case 'inner-window-destroyed': |
|
106 var id = subject.QueryInterface(Ci.nsISupportsPRUint64).data; |
|
107 windows.delete(id); |
|
108 break; |
|
109 |
|
110 case 'simulator-orientation-change': |
|
111 windows.forEach(fireOrientationEvent); |
|
112 break; |
|
113 } |
|
114 } |
|
115 }; |
|
116 |
|
117 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SimulatorScreen]); |