1 : /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
2 : /* vim: set sw=4 ts=8 et tw=80 : */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Content App.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * The Mozilla Foundation.
20 : * Portions created by the Initial Developer are Copyright (C) 2010
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsInProcessTabChildGlobal.h"
40 : #include "nsContentUtils.h"
41 : #include "nsIScriptSecurityManager.h"
42 : #include "nsIInterfaceRequestorUtils.h"
43 : #include "nsEventDispatcher.h"
44 : #include "nsIComponentManager.h"
45 : #include "nsIServiceManager.h"
46 : #include "nsIJSRuntimeService.h"
47 : #include "nsComponentManagerUtils.h"
48 : #include "nsNetUtil.h"
49 : #include "nsScriptLoader.h"
50 : #include "nsIJSContextStack.h"
51 : #include "nsFrameLoader.h"
52 : #include "nsIPrivateDOMEvent.h"
53 : #include "xpcpublic.h"
54 :
55 0 : bool SendSyncMessageToParent(void* aCallbackData,
56 : const nsAString& aMessage,
57 : const nsAString& aJSON,
58 : InfallibleTArray<nsString>* aJSONRetVal)
59 : {
60 : nsInProcessTabChildGlobal* tabChild =
61 0 : static_cast<nsInProcessTabChildGlobal*>(aCallbackData);
62 0 : nsCOMPtr<nsIContent> owner = tabChild->mOwner;
63 0 : nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
64 0 : asyncMessages.SwapElements(tabChild->mASyncMessages);
65 0 : PRUint32 len = asyncMessages.Length();
66 0 : for (PRUint32 i = 0; i < len; ++i) {
67 0 : nsCOMPtr<nsIRunnable> async = asyncMessages[i];
68 0 : async->Run();
69 : }
70 0 : if (tabChild->mChromeMessageManager) {
71 0 : nsRefPtr<nsFrameMessageManager> mm = tabChild->mChromeMessageManager;
72 0 : mm->ReceiveMessage(owner, aMessage, true, aJSON, nsnull, aJSONRetVal);
73 : }
74 0 : return true;
75 : }
76 :
77 : class nsAsyncMessageToParent : public nsRunnable
78 0 : {
79 : public:
80 0 : nsAsyncMessageToParent(nsInProcessTabChildGlobal* aTabChild,
81 : const nsAString& aMessage, const nsAString& aJSON)
82 0 : : mTabChild(aTabChild), mMessage(aMessage), mJSON(aJSON) {}
83 :
84 0 : NS_IMETHOD Run()
85 : {
86 0 : mTabChild->mASyncMessages.RemoveElement(this);
87 0 : if (mTabChild->mChromeMessageManager) {
88 0 : nsRefPtr<nsFrameMessageManager> mm = mTabChild->mChromeMessageManager;
89 0 : mm->ReceiveMessage(mTabChild->mOwner, mMessage, false,
90 0 : mJSON, nsnull, nsnull);
91 : }
92 0 : return NS_OK;
93 : }
94 : nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
95 : nsString mMessage;
96 : nsString mJSON;
97 : };
98 :
99 0 : bool SendAsyncMessageToParent(void* aCallbackData,
100 : const nsAString& aMessage,
101 : const nsAString& aJSON)
102 : {
103 : nsInProcessTabChildGlobal* tabChild =
104 0 : static_cast<nsInProcessTabChildGlobal*>(aCallbackData);
105 : nsCOMPtr<nsIRunnable> ev =
106 0 : new nsAsyncMessageToParent(tabChild, aMessage, aJSON);
107 0 : tabChild->mASyncMessages.AppendElement(ev);
108 0 : NS_DispatchToCurrentThread(ev);
109 0 : return true;
110 : }
111 :
112 0 : nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
113 : nsIContent* aOwner,
114 : nsFrameMessageManager* aChrome)
115 : : mDocShell(aShell), mInitialized(false), mLoadingScript(false),
116 0 : mDelayedDisconnect(false), mOwner(aOwner), mChromeMessageManager(aChrome)
117 : {
118 0 : }
119 :
120 0 : nsInProcessTabChildGlobal::~nsInProcessTabChildGlobal()
121 : {
122 0 : NS_ASSERTION(!mCx, "Couldn't release JSContext?!?");
123 0 : }
124 :
125 : nsresult
126 0 : nsInProcessTabChildGlobal::Init()
127 : {
128 : #ifdef DEBUG
129 : nsresult rv =
130 : #endif
131 0 : InitTabChildGlobal();
132 0 : NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
133 : "Couldn't initialize nsInProcessTabChildGlobal");
134 : mMessageManager = new nsFrameMessageManager(false,
135 : SendSyncMessageToParent,
136 : SendAsyncMessageToParent,
137 : nsnull,
138 : this,
139 : nsnull,
140 0 : mCx);
141 0 : return NS_OK;
142 : }
143 :
144 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsInProcessTabChildGlobal)
145 :
146 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsInProcessTabChildGlobal,
147 : nsDOMEventTargetHelper)
148 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mMessageManager)
149 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGlobal)
150 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
151 :
152 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsInProcessTabChildGlobal,
153 : nsDOMEventTargetHelper)
154 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMessageManager)
155 0 : nsFrameScriptExecutor::Traverse(tmp, cb);
156 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
157 :
158 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsInProcessTabChildGlobal)
159 0 : NS_INTERFACE_MAP_ENTRY(nsIFrameMessageManager)
160 0 : NS_INTERFACE_MAP_ENTRY(nsISyncMessageSender)
161 0 : NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager)
162 0 : NS_INTERFACE_MAP_ENTRY(nsIInProcessContentFrameMessageManager)
163 0 : NS_INTERFACE_MAP_ENTRY(nsIScriptContextPrincipal)
164 0 : NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
165 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ContentFrameMessageManager)
166 0 : NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
167 :
168 0 : NS_IMPL_ADDREF_INHERITED(nsInProcessTabChildGlobal, nsDOMEventTargetHelper)
169 0 : NS_IMPL_RELEASE_INHERITED(nsInProcessTabChildGlobal, nsDOMEventTargetHelper)
170 :
171 : NS_IMETHODIMP
172 0 : nsInProcessTabChildGlobal::GetContent(nsIDOMWindow** aContent)
173 : {
174 0 : *aContent = nsnull;
175 0 : nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mDocShell);
176 0 : window.swap(*aContent);
177 0 : return NS_OK;
178 : }
179 :
180 : NS_IMETHODIMP
181 0 : nsInProcessTabChildGlobal::GetDocShell(nsIDocShell** aDocShell)
182 : {
183 0 : NS_IF_ADDREF(*aDocShell = mDocShell);
184 0 : return NS_OK;
185 : }
186 :
187 : NS_IMETHODIMP
188 0 : nsInProcessTabChildGlobal::Btoa(const nsAString& aBinaryData,
189 : nsAString& aAsciiBase64String)
190 : {
191 0 : return nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
192 : }
193 :
194 : NS_IMETHODIMP
195 0 : nsInProcessTabChildGlobal::Atob(const nsAString& aAsciiString,
196 : nsAString& aBinaryData)
197 : {
198 0 : return nsContentUtils::Atob(aAsciiString, aBinaryData);
199 : }
200 :
201 :
202 : NS_IMETHODIMP
203 0 : nsInProcessTabChildGlobal::PrivateNoteIntentionalCrash()
204 : {
205 0 : return NS_ERROR_NOT_IMPLEMENTED;
206 : }
207 :
208 : void
209 0 : nsInProcessTabChildGlobal::Disconnect()
210 : {
211 : // Let the frame scripts know the child is being closed. We do any other
212 : // cleanup after the event has been fired. See DelayedDisconnect
213 : nsContentUtils::AddScriptRunner(
214 0 : NS_NewRunnableMethod(this, &nsInProcessTabChildGlobal::DelayedDisconnect)
215 0 : );
216 0 : }
217 :
218 : void
219 0 : nsInProcessTabChildGlobal::DelayedDisconnect()
220 : {
221 : // Don't let the event escape
222 0 : mOwner = nsnull;
223 :
224 : // Fire the "unload" event
225 0 : nsCOMPtr<nsIDOMEvent> event;
226 0 : NS_NewDOMEvent(getter_AddRefs(event), nsnull, nsnull);
227 0 : if (event) {
228 0 : event->InitEvent(NS_LITERAL_STRING("unload"), false, false);
229 0 : nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
230 0 : privateEvent->SetTrusted(true);
231 :
232 : bool dummy;
233 0 : nsDOMEventTargetHelper::DispatchEvent(event, &dummy);
234 : }
235 :
236 : // Continue with the Disconnect cleanup
237 0 : nsCOMPtr<nsIDOMWindow> win = do_GetInterface(mDocShell);
238 0 : nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(win);
239 0 : if (pwin) {
240 0 : pwin->SetChromeEventHandler(pwin->GetChromeEventHandler());
241 : }
242 0 : mDocShell = nsnull;
243 0 : mChromeMessageManager = nsnull;
244 0 : if (mMessageManager) {
245 0 : static_cast<nsFrameMessageManager*>(mMessageManager.get())->Disconnect();
246 0 : mMessageManager = nsnull;
247 : }
248 0 : if (mListenerManager) {
249 0 : mListenerManager->Disconnect();
250 : }
251 :
252 0 : if (!mLoadingScript) {
253 : nsContentUtils::ReleaseWrapper(static_cast<nsIDOMEventTarget*>(this),
254 0 : this);
255 0 : if (mCx) {
256 0 : DestroyCx();
257 : }
258 : } else {
259 0 : mDelayedDisconnect = true;
260 : }
261 0 : }
262 :
263 : NS_IMETHODIMP_(nsIContent *)
264 0 : nsInProcessTabChildGlobal::GetOwnerContent()
265 : {
266 0 : return mOwner;
267 : }
268 :
269 : nsresult
270 0 : nsInProcessTabChildGlobal::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
271 : {
272 0 : aVisitor.mCanHandle = true;
273 0 : aVisitor.mParentTarget = mOwner;
274 :
275 : #ifdef DEBUG
276 0 : if (mOwner) {
277 0 : nsCOMPtr<nsIFrameLoaderOwner> owner = do_QueryInterface(mOwner);
278 0 : nsRefPtr<nsFrameLoader> fl = owner->GetFrameLoader();
279 0 : if (fl) {
280 0 : NS_ASSERTION(this == fl->GetTabChildGlobalAsEventTarget(),
281 : "Wrong event target!");
282 0 : NS_ASSERTION(fl->mMessageManager == mChromeMessageManager,
283 : "Wrong message manager!");
284 : }
285 : }
286 : #endif
287 :
288 0 : return NS_OK;
289 : }
290 :
291 : nsresult
292 0 : nsInProcessTabChildGlobal::InitTabChildGlobal()
293 : {
294 :
295 : nsISupports* scopeSupports =
296 0 : NS_ISUPPORTS_CAST(nsIDOMEventTarget*, this);
297 0 : NS_ENSURE_STATE(InitTabChildGlobalInternal(scopeSupports));
298 0 : return NS_OK;
299 : }
300 :
301 : class nsAsyncScriptLoad : public nsRunnable
302 0 : {
303 : public:
304 0 : nsAsyncScriptLoad(nsInProcessTabChildGlobal* aTabChild, const nsAString& aURL)
305 0 : : mTabChild(aTabChild), mURL(aURL) {}
306 :
307 0 : NS_IMETHOD Run()
308 : {
309 0 : mTabChild->LoadFrameScript(mURL);
310 0 : return NS_OK;
311 : }
312 : nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
313 : nsString mURL;
314 : };
315 :
316 : void
317 0 : nsInProcessTabChildGlobal::LoadFrameScript(const nsAString& aURL)
318 : {
319 0 : if (!nsContentUtils::IsSafeToRunScript()) {
320 0 : nsContentUtils::AddScriptRunner(new nsAsyncScriptLoad(this, aURL));
321 0 : return;
322 : }
323 0 : if (!mInitialized) {
324 0 : mInitialized = true;
325 0 : Init();
326 : }
327 0 : bool tmp = mLoadingScript;
328 0 : mLoadingScript = true;
329 0 : LoadFrameScriptInternal(aURL);
330 0 : mLoadingScript = tmp;
331 0 : if (!mLoadingScript && mDelayedDisconnect) {
332 0 : mDelayedDisconnect = false;
333 0 : Disconnect();
334 : }
335 4392 : }
|