1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * vim: set ts=2 sw=2 et tw=78:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is mozilla.org code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Netscape Communications Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 1998
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK *****
39 : *
40 : *
41 : * This Original Code has been modified by IBM Corporation.
42 : * Modifications made by IBM described herein are
43 : * Copyright (c) International Business Machines
44 : * Corporation, 2000
45 : *
46 : * Modifications to Mozilla code or documentation
47 : * identified per MPL Section 3.3
48 : *
49 : * Date Modified by Description of modification
50 : * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
51 : * use in OS2
52 : */
53 :
54 : #include "nsDOMScriptObjectFactory.h"
55 : #include "xpcexception.h"
56 : #include "nsScriptNameSpaceManager.h"
57 : #include "nsIObserverService.h"
58 : #include "nsJSEnvironment.h"
59 : #include "nsJSEventListener.h"
60 : #include "nsGlobalWindow.h"
61 : #include "nsIJSContextStack.h"
62 : #include "nsISupportsPrimitives.h"
63 : #include "nsDOMException.h"
64 : #include "nsCRT.h"
65 : #ifdef MOZ_XUL
66 : #include "nsXULPrototypeCache.h"
67 : #endif
68 : #include "nsThreadUtils.h"
69 :
70 : static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
71 :
72 : nsIExceptionProvider* gExceptionProvider = nsnull;
73 :
74 50 : nsDOMScriptObjectFactory::nsDOMScriptObjectFactory() :
75 50 : mLoadedAllLanguages(false)
76 : {
77 : nsCOMPtr<nsIObserverService> observerService =
78 100 : mozilla::services::GetObserverService();
79 50 : if (observerService) {
80 50 : observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
81 : }
82 :
83 100 : nsCOMPtr<nsIExceptionProvider> provider(new nsDOMExceptionProvider());
84 50 : if (provider) {
85 : nsCOMPtr<nsIExceptionService> xs =
86 100 : do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID);
87 :
88 50 : if (xs) {
89 50 : xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_DOM);
90 50 : xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_SVG);
91 50 : xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_DOM_XPATH);
92 50 : xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_DOM_INDEXEDDB);
93 50 : xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_XPCONNECT);
94 50 : xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_DOM_EVENTS);
95 : }
96 :
97 50 : NS_ASSERTION(!gExceptionProvider, "Registered twice?!");
98 50 : provider.swap(gExceptionProvider);
99 : }
100 :
101 : // And pre-create the javascript language.
102 50 : NS_CreateJSRuntime(getter_AddRefs(mLanguageArray[NS_STID_INDEX(nsIProgrammingLanguage::JAVASCRIPT)]));
103 50 : }
104 :
105 50 : NS_INTERFACE_MAP_BEGIN(nsDOMScriptObjectFactory)
106 50 : NS_INTERFACE_MAP_ENTRY(nsIDOMScriptObjectFactory)
107 0 : NS_INTERFACE_MAP_ENTRY(nsIObserver)
108 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMScriptObjectFactory)
109 0 : NS_INTERFACE_MAP_END
110 :
111 :
112 350 : NS_IMPL_ADDREF(nsDOMScriptObjectFactory)
113 400 : NS_IMPL_RELEASE(nsDOMScriptObjectFactory)
114 :
115 : /**
116 : * Notes about language registration (for language other than js):
117 : * - All language are expected to register (at least) 2 contract IDs
118 : * @mozilla.org/script-language;1?id=%d
119 : * using the language ID as defined in nsIProgrammingLanguage, and
120 : * @mozilla.org/script-language;1?script-type=%s
121 : * using the "mime-type" of the script language
122 : *
123 : * Theoretically, a language could register multiple script-type
124 : * names, although this is discouraged - each language should have one,
125 : * canonical name.
126 : *
127 : * The most common case is that languages are looked up by ID. For this
128 : * reason, we keep an array of languages indexed by this ID - the registry
129 : * is only looked the first request for a language ID.
130 : *
131 : * The registry is looked up and getService called for each query by name.
132 : * (As services are cached by CID, multiple contractIDs will still work
133 : * correctly)
134 : **/
135 :
136 : NS_IMETHODIMP
137 0 : nsDOMScriptObjectFactory::GetScriptRuntime(const nsAString &aLanguageName,
138 : nsIScriptRuntime **aLanguage)
139 : {
140 : // Note that many callers have optimized detection for JS (along with
141 : // supporting various alternate names for JS), so don't call this.
142 : // One exception is for the new "script-type" attribute on a node - and
143 : // there is no need to support backwards compatible names.
144 : // As JS is the default language, this is still rarely called for JS -
145 : // only when a node explicitly sets JS - so that is done last.
146 0 : nsCAutoString contractid(NS_LITERAL_CSTRING(
147 0 : "@mozilla.org/script-language;1?script-type="));
148 : // Arbitrarily use utf8 encoding should the name have extended chars
149 0 : AppendUTF16toUTF8(aLanguageName, contractid);
150 : nsresult rv;
151 : nsCOMPtr<nsIScriptRuntime> lang =
152 0 : do_GetService(contractid.get(), &rv);
153 :
154 0 : if (NS_FAILED(rv)) {
155 0 : if (aLanguageName.Equals(NS_LITERAL_STRING("application/javascript")))
156 0 : return GetScriptRuntimeByID(nsIProgrammingLanguage::JAVASCRIPT, aLanguage);
157 : // Not JS and nothing else we know about.
158 0 : NS_WARNING("No script language registered for this mime-type");
159 0 : return NS_ERROR_FACTORY_NOT_REGISTERED;
160 : }
161 : // And stash it away in our array for fast lookup by ID.
162 0 : PRUint32 lang_ndx = NS_STID_INDEX(lang->GetScriptTypeID());
163 0 : if (mLanguageArray[lang_ndx] == nsnull) {
164 0 : mLanguageArray[lang_ndx] = lang;
165 : } else {
166 : // All languages are services - we should have an identical object!
167 0 : NS_ASSERTION(mLanguageArray[lang_ndx] == lang,
168 : "Got a different language for this ID???");
169 : }
170 0 : *aLanguage = lang;
171 0 : NS_IF_ADDREF(*aLanguage);
172 0 : return NS_OK;
173 : }
174 :
175 : NS_IMETHODIMP
176 0 : nsDOMScriptObjectFactory::GetScriptRuntimeByID(PRUint32 aLanguageID,
177 : nsIScriptRuntime **aLanguage)
178 : {
179 0 : if (!NS_STID_VALID(aLanguageID)) {
180 0 : NS_WARNING("Unknown script language");
181 0 : return NS_ERROR_UNEXPECTED;
182 : }
183 0 : *aLanguage = mLanguageArray[NS_STID_INDEX(aLanguageID)];
184 0 : if (!*aLanguage) {
185 0 : nsCAutoString contractid(NS_LITERAL_CSTRING(
186 0 : "@mozilla.org/script-language;1?id="));
187 : char langIdStr[25]; // space for an int.
188 0 : sprintf(langIdStr, "%d", aLanguageID);
189 0 : contractid += langIdStr;
190 : nsresult rv;
191 0 : nsCOMPtr<nsIScriptRuntime> lang = do_GetService(contractid.get(), &rv);
192 :
193 0 : if (NS_FAILED(rv)) {
194 0 : NS_ERROR("Failed to get the script language");
195 0 : return rv;
196 : }
197 :
198 : // Stash it away in our array for fast lookup by ID.
199 0 : mLanguageArray[NS_STID_INDEX(aLanguageID)] = lang;
200 0 : *aLanguage = lang;
201 : }
202 0 : NS_IF_ADDREF(*aLanguage);
203 0 : return NS_OK;
204 : }
205 :
206 : NS_IMETHODIMP
207 0 : nsDOMScriptObjectFactory::GetIDForScriptType(const nsAString &aLanguageName,
208 : PRUint32 *aScriptTypeID)
209 : {
210 0 : nsCOMPtr<nsIScriptRuntime> languageRuntime;
211 : nsresult rv;
212 0 : rv = GetScriptRuntime(aLanguageName, getter_AddRefs(languageRuntime));
213 0 : if (NS_FAILED(rv))
214 0 : return rv;
215 :
216 0 : *aScriptTypeID = languageRuntime->GetScriptTypeID();
217 0 : return NS_OK;
218 : }
219 :
220 : NS_IMETHODIMP
221 0 : nsDOMScriptObjectFactory::NewScriptGlobalObject(bool aIsChrome,
222 : bool aIsModalContentWindow,
223 : nsIScriptGlobalObject **aGlobal)
224 : {
225 0 : return NS_NewScriptGlobalObject(aIsChrome, aIsModalContentWindow, aGlobal);
226 : }
227 :
228 : NS_IMETHODIMP_(nsISupports *)
229 0 : nsDOMScriptObjectFactory::GetClassInfoInstance(nsDOMClassInfoID aID)
230 : {
231 0 : return NS_GetDOMClassInfoInstance(aID);
232 : }
233 :
234 : NS_IMETHODIMP_(nsISupports *)
235 0 : nsDOMScriptObjectFactory::GetExternalClassInfoInstance(const nsAString& aName)
236 : {
237 0 : nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
238 0 : NS_ENSURE_TRUE(nameSpaceManager, nsnull);
239 :
240 : const nsGlobalNameStruct *globalStruct;
241 0 : nameSpaceManager->LookupName(aName, &globalStruct);
242 0 : if (globalStruct) {
243 0 : if (globalStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator) {
244 : nsresult rv;
245 0 : nsCOMPtr<nsIDOMCIExtension> creator(do_CreateInstance(globalStruct->mCID, &rv));
246 0 : NS_ENSURE_SUCCESS(rv, nsnull);
247 :
248 0 : rv = creator->RegisterDOMCI(NS_ConvertUTF16toUTF8(aName).get(), this);
249 0 : NS_ENSURE_SUCCESS(rv, nsnull);
250 :
251 0 : rv = nameSpaceManager->LookupName(aName, &globalStruct);
252 0 : NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && globalStruct, nsnull);
253 :
254 0 : NS_ASSERTION(globalStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo,
255 : "The classinfo data for this class didn't get registered.");
256 : }
257 0 : if (globalStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
258 0 : return nsDOMClassInfo::GetClassInfoInstance(globalStruct->mData);
259 : }
260 : }
261 0 : return nsnull;
262 : }
263 :
264 : NS_IMETHODIMP
265 50 : nsDOMScriptObjectFactory::Observe(nsISupports *aSubject,
266 : const char *aTopic,
267 : const PRUnichar *someData)
268 : {
269 50 : if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
270 : #ifdef MOZ_XUL
271 : // Flush the XUL cache since it holds JS roots, and we're about to
272 : // start the final GC.
273 50 : nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
274 :
275 50 : if (cache)
276 50 : cache->Flush();
277 : #endif
278 :
279 50 : nsGlobalWindow::ShutDown();
280 50 : nsDOMClassInfo::ShutDown();
281 :
282 50 : if (gExceptionProvider) {
283 : nsCOMPtr<nsIExceptionService> xs =
284 100 : do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID);
285 :
286 50 : if (xs) {
287 50 : xs->UnregisterExceptionProvider(gExceptionProvider,
288 50 : NS_ERROR_MODULE_DOM);
289 50 : xs->UnregisterExceptionProvider(gExceptionProvider,
290 50 : NS_ERROR_MODULE_SVG);
291 50 : xs->UnregisterExceptionProvider(gExceptionProvider,
292 50 : NS_ERROR_MODULE_DOM_XPATH);
293 50 : xs->UnregisterExceptionProvider(gExceptionProvider,
294 50 : NS_ERROR_MODULE_XPCONNECT);
295 50 : xs->UnregisterExceptionProvider(gExceptionProvider,
296 50 : NS_ERROR_MODULE_DOM_EVENTS);
297 : }
298 :
299 50 : NS_RELEASE(gExceptionProvider);
300 : }
301 : }
302 :
303 50 : return NS_OK;
304 : }
305 :
306 : static nsresult
307 10 : CreateXPConnectException(nsresult aResult, nsIException *aDefaultException,
308 : nsIException **_retval)
309 : {
310 : // See whether we already have a useful XPConnect exception. If we
311 : // do, let's not create one with _less_ information!
312 20 : nsCOMPtr<nsIXPCException> exception(do_QueryInterface(aDefaultException));
313 10 : if (!exception) {
314 0 : nsresult rv = NS_OK;
315 0 : exception = do_CreateInstance("@mozilla.org/js/xpc/Exception;1", &rv);
316 0 : NS_ENSURE_SUCCESS(rv, rv);
317 :
318 0 : rv = exception->Initialize(nsnull, aResult, nsnull, nsnull, nsnull,
319 0 : nsnull);
320 0 : NS_ENSURE_SUCCESS(rv, rv);
321 : }
322 :
323 10 : NS_ADDREF(*_retval = exception);
324 10 : return NS_OK;
325 : }
326 :
327 : NS_IMETHODIMP
328 0 : nsDOMScriptObjectFactory::RegisterDOMClassInfo(const char *aName,
329 : nsDOMClassInfoExternalConstructorFnc aConstructorFptr,
330 : const nsIID *aProtoChainInterface,
331 : const nsIID **aInterfaces,
332 : PRUint32 aScriptableFlags,
333 : bool aHasClassInterface,
334 : const nsCID *aConstructorCID)
335 : {
336 0 : nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
337 0 : NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
338 :
339 : return nameSpaceManager->RegisterDOMCIData(aName,
340 : aConstructorFptr,
341 : aProtoChainInterface,
342 : aInterfaces,
343 : aScriptableFlags,
344 : aHasClassInterface,
345 0 : aConstructorCID);
346 : }
347 :
348 : // Factories
349 0 : nsresult NS_GetScriptRuntime(const nsAString &aLanguageName,
350 : nsIScriptRuntime **aLanguage)
351 : {
352 : nsresult rv;
353 0 : *aLanguage = nsnull;
354 : nsCOMPtr<nsIDOMScriptObjectFactory> factory = \
355 0 : do_GetService(kDOMScriptObjectFactoryCID, &rv);
356 0 : if (NS_FAILED(rv))
357 0 : return rv;
358 0 : return factory->GetScriptRuntime(aLanguageName, aLanguage);
359 : }
360 :
361 0 : nsresult NS_GetScriptRuntimeByID(PRUint32 aScriptTypeID,
362 : nsIScriptRuntime **aLanguage)
363 : {
364 : nsresult rv;
365 0 : *aLanguage = nsnull;
366 : nsCOMPtr<nsIDOMScriptObjectFactory> factory = \
367 0 : do_GetService(kDOMScriptObjectFactoryCID, &rv);
368 0 : if (NS_FAILED(rv))
369 0 : return rv;
370 0 : return factory->GetScriptRuntimeByID(aScriptTypeID, aLanguage);
371 : }
372 :
373 1985 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsDOMExceptionProvider, nsIExceptionProvider)
374 :
375 : NS_IMETHODIMP
376 217 : nsDOMExceptionProvider::GetException(nsresult result,
377 : nsIException *aDefaultException,
378 : nsIException **_retval)
379 : {
380 217 : if (!NS_IsMainThread()) {
381 0 : return NS_ERROR_NOT_IMPLEMENTED;
382 : }
383 :
384 217 : switch (NS_ERROR_GET_MODULE(result))
385 : {
386 : case NS_ERROR_MODULE_SVG:
387 0 : return NS_NewSVGException(result, aDefaultException, _retval);
388 : case NS_ERROR_MODULE_DOM_XPATH:
389 0 : return NS_NewXPathException(result, aDefaultException, _retval);
390 : case NS_ERROR_MODULE_XPCONNECT:
391 10 : return CreateXPConnectException(result, aDefaultException, _retval);
392 : case NS_ERROR_MODULE_DOM_FILE:
393 0 : return NS_NewFileException(result, aDefaultException, _retval);
394 : case NS_ERROR_MODULE_DOM_INDEXEDDB:
395 203 : return NS_NewIDBDatabaseException(result, aDefaultException, _retval);
396 : default:
397 4 : return NS_NewDOMException(result, aDefaultException, _retval);
398 : }
399 : NS_NOTREACHED("Not reached");
400 : return NS_ERROR_UNEXPECTED;
401 : }
|