|
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/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 const {utils: Cu, interfaces: Ci} = Components; |
|
8 |
|
9 Cu.import("resource://gre/modules/Services.jsm"); |
|
10 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
11 |
|
12 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; |
|
13 const BROWSER_FRAMES_ENABLED_PREF = "dom.mozBrowserFramesEnabled"; |
|
14 |
|
15 XPCOMUtils.defineLazyModuleGetter(this, "BrowserElementParentBuilder", |
|
16 "resource://gre/modules/BrowserElementParent.jsm", |
|
17 "BrowserElementParentBuilder"); |
|
18 |
|
19 function debug(msg) { |
|
20 //dump("BrowserElementParent.js - " + msg + "\n"); |
|
21 } |
|
22 |
|
23 /** |
|
24 * BrowserElementParent implements one half of <iframe mozbrowser>. (The other |
|
25 * half is, unsurprisingly, BrowserElementChild.) |
|
26 * |
|
27 * BrowserElementParentFactory detects when we create a windows or docshell |
|
28 * contained inside a <iframe mozbrowser> and creates a BrowserElementParent |
|
29 * object for that window. |
|
30 * |
|
31 * It creates a BrowserElementParent that injects script to listen for |
|
32 * certain event. |
|
33 */ |
|
34 |
|
35 function BrowserElementParentFactory() { |
|
36 this._initialized = false; |
|
37 } |
|
38 |
|
39 BrowserElementParentFactory.prototype = { |
|
40 classID: Components.ID("{ddeafdac-cb39-47c4-9cb8-c9027ee36d26}"), |
|
41 QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, |
|
42 Ci.nsISupportsWeakReference]), |
|
43 |
|
44 /** |
|
45 * Called on app startup, and also when the browser frames enabled pref is |
|
46 * changed. |
|
47 */ |
|
48 _init: function() { |
|
49 if (this._initialized) { |
|
50 return; |
|
51 } |
|
52 |
|
53 // If the pref is disabled, do nothing except wait for the pref to change. |
|
54 // (This is important for tests, if nothing else.) |
|
55 if (!this._browserFramesPrefEnabled()) { |
|
56 Services.prefs.addObserver(BROWSER_FRAMES_ENABLED_PREF, this, /* ownsWeak = */ true); |
|
57 return; |
|
58 } |
|
59 |
|
60 debug("_init"); |
|
61 this._initialized = true; |
|
62 |
|
63 // Maps frame elements to BrowserElementParent objects. We never look up |
|
64 // anything in this map; the purpose is to keep the BrowserElementParent |
|
65 // alive for as long as its frame element lives. |
|
66 this._bepMap = new WeakMap(); |
|
67 |
|
68 Services.obs.addObserver(this, 'remote-browser-pending', /* ownsWeak = */ true); |
|
69 Services.obs.addObserver(this, 'inprocess-browser-shown', /* ownsWeak = */ true); |
|
70 }, |
|
71 |
|
72 _browserFramesPrefEnabled: function() { |
|
73 try { |
|
74 return Services.prefs.getBoolPref(BROWSER_FRAMES_ENABLED_PREF); |
|
75 } |
|
76 catch(e) { |
|
77 return false; |
|
78 } |
|
79 }, |
|
80 |
|
81 _observeInProcessBrowserFrameShown: function(frameLoader) { |
|
82 // Ignore notifications that aren't from a BrowserOrApp |
|
83 if (!frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerIsBrowserOrAppFrame) { |
|
84 return; |
|
85 } |
|
86 debug("In-process browser frame shown " + frameLoader); |
|
87 this._createBrowserElementParent(frameLoader, |
|
88 /* hasRemoteFrame = */ false, |
|
89 /* pending frame */ false); |
|
90 }, |
|
91 |
|
92 _observeRemoteBrowserFramePending: function(frameLoader) { |
|
93 // Ignore notifications that aren't from a BrowserOrApp |
|
94 if (!frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerIsBrowserOrAppFrame) { |
|
95 return; |
|
96 } |
|
97 debug("Remote browser frame shown " + frameLoader); |
|
98 this._createBrowserElementParent(frameLoader, |
|
99 /* hasRemoteFrame = */ true, |
|
100 /* pending frame */ true); |
|
101 }, |
|
102 |
|
103 _createBrowserElementParent: function(frameLoader, hasRemoteFrame, isPendingFrame) { |
|
104 let frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement; |
|
105 this._bepMap.set(frameElement, BrowserElementParentBuilder.create( |
|
106 frameLoader, hasRemoteFrame, isPendingFrame)); |
|
107 }, |
|
108 |
|
109 observe: function(subject, topic, data) { |
|
110 switch(topic) { |
|
111 case 'app-startup': |
|
112 this._init(); |
|
113 break; |
|
114 case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID: |
|
115 if (data == BROWSER_FRAMES_ENABLED_PREF) { |
|
116 this._init(); |
|
117 } |
|
118 break; |
|
119 case 'remote-browser-pending': |
|
120 this._observeRemoteBrowserFramePending(subject); |
|
121 break; |
|
122 case 'inprocess-browser-shown': |
|
123 this._observeInProcessBrowserFrameShown(subject); |
|
124 break; |
|
125 } |
|
126 }, |
|
127 }; |
|
128 |
|
129 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementParentFactory]); |