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