Bug 570258: Some more atom usage cleanup. r=jst
[mozilla-central.git] / content / base / src / nsContentUtils.cpp
blob3bfa903c57b698830fa0c2d41393153ed568c496
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=2 sw=2 et tw=78:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
25 * Contributor(s):
26 * Johnny Stenback <jst@netscape.com>
27 * Christopher A. Aillon <christopher@aillon.com>
29 * Alternatively, the contents of this file may be used under the terms of
30 * either of the GNU General Public License Version 2 or later (the "GPL"),
31 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 * in which case the provisions of the GPL or the LGPL are applicable instead
33 * of those above. If you wish to allow use of your version of this file only
34 * under the terms of either the GPL or the LGPL, and not to allow others to
35 * use your version of this file under the terms of the MPL, indicate your
36 * decision by deleting the provisions above and replace them with the notice
37 * and other provisions required by the GPL or the LGPL. If you do not delete
38 * the provisions above, a recipient may use your version of this file under
39 * the terms of any one of the MPL, the GPL or the LGPL.
41 * ***** END LICENSE BLOCK ***** */
43 /* A namespace class for static layout utilities. */
45 #include "jscntxt.h"
47 #include "nsJSUtils.h"
48 #include "nsCOMPtr.h"
49 #include "nsAString.h"
50 #include "nsPrintfCString.h"
51 #include "nsUnicharUtils.h"
52 #include "nsIPrefService.h"
53 #include "nsIPrefBranch2.h"
54 #include "nsIPrefLocalizedString.h"
55 #include "nsServiceManagerUtils.h"
56 #include "nsIScriptGlobalObject.h"
57 #include "nsIScriptContext.h"
58 #include "nsIDOMScriptObjectFactory.h"
59 #include "nsDOMCID.h"
60 #include "nsContentUtils.h"
61 #include "nsIContentUtils.h"
62 #include "nsIXPConnect.h"
63 #include "nsIContent.h"
64 #include "mozilla/dom/Element.h"
65 #include "nsIDocument.h"
66 #include "nsINodeInfo.h"
67 #include "nsReadableUtils.h"
68 #include "nsIDOMDocument.h"
69 #include "nsIDOMNodeList.h"
70 #include "nsIDOMNode.h"
71 #include "nsIDOM3Node.h"
72 #include "nsIIOService.h"
73 #include "nsNetCID.h"
74 #include "nsNetUtil.h"
75 #include "nsIScriptSecurityManager.h"
76 #include "nsDOMError.h"
77 #include "nsPIDOMWindow.h"
78 #include "nsIJSContextStack.h"
79 #include "nsIDocShell.h"
80 #include "nsIDocShellTreeItem.h"
81 #include "nsParserCIID.h"
82 #include "nsIParser.h"
83 #include "nsIFragmentContentSink.h"
84 #include "nsIContentSink.h"
85 #include "nsIHTMLContentSink.h"
86 #include "nsIXMLContentSink.h"
87 #include "nsHTMLParts.h"
88 #include "nsIParserService.h"
89 #include "nsIServiceManager.h"
90 #include "nsIAttribute.h"
91 #include "nsContentList.h"
92 #include "nsIHTMLDocument.h"
93 #include "nsIDOMHTMLDocument.h"
94 #include "nsIDOMHTMLCollection.h"
95 #include "nsIDOMHTMLFormElement.h"
96 #include "nsIDOMNSHTMLElement.h"
97 #include "nsIForm.h"
98 #include "nsIFormControl.h"
99 #include "nsGkAtoms.h"
100 #include "nsISupportsPrimitives.h"
101 #include "imgIDecoderObserver.h"
102 #include "imgIRequest.h"
103 #include "imgIContainer.h"
104 #include "imgILoader.h"
105 #include "mozilla/IHistory.h"
106 #include "nsDocShellCID.h"
107 #include "nsIImageLoadingContent.h"
108 #include "nsIInterfaceRequestor.h"
109 #include "nsIInterfaceRequestorUtils.h"
110 #include "nsILoadGroup.h"
111 #include "nsIObserver.h"
112 #include "nsIObserverService.h"
113 #include "nsContentPolicyUtils.h"
114 #include "nsNodeInfoManager.h"
115 #include "nsIXBLService.h"
116 #include "nsCRT.h"
117 #include "nsIDOMEvent.h"
118 #include "nsIDOMEventTarget.h"
119 #include "nsIPrivateDOMEvent.h"
120 #include "nsIDOMDocumentEvent.h"
121 #ifdef MOZ_XTF
122 #include "nsIXTFService.h"
123 static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
124 #endif
125 #include "nsIMIMEService.h"
126 #include "nsLWBrkCIID.h"
127 #include "nsILineBreaker.h"
128 #include "nsIWordBreaker.h"
129 #include "jsdbgapi.h"
130 #include "nsIJSRuntimeService.h"
131 #include "nsIDOMDocumentXBL.h"
132 #include "nsBindingManager.h"
133 #include "nsIURI.h"
134 #include "nsIURL.h"
135 #include "nsXBLBinding.h"
136 #include "nsXBLPrototypeBinding.h"
137 #include "nsEscape.h"
138 #include "nsICharsetConverterManager.h"
139 #include "nsIEventListenerManager.h"
140 #include "nsAttrName.h"
141 #include "nsIDOMUserDataHandler.h"
142 #include "nsContentCreatorFunctions.h"
143 #include "nsTPtrArray.h"
144 #include "nsGUIEvent.h"
145 #include "nsMutationEvent.h"
146 #include "nsIMEStateManager.h"
147 #include "nsContentErrors.h"
148 #include "nsUnicharUtilCIID.h"
149 #include "nsICaseConversion.h"
150 #include "nsCompressedCharMap.h"
151 #include "nsINativeKeyBindings.h"
152 #include "nsIDOMNSUIEvent.h"
153 #include "nsIDOMNSEvent.h"
154 #include "nsIPrivateDOMEvent.h"
155 #include "nsXULPopupManager.h"
156 #include "nsIPermissionManager.h"
157 #include "nsIScriptObjectPrincipal.h"
158 #include "nsIRunnable.h"
159 #include "nsDOMJSUtils.h"
160 #include "nsGenericHTMLElement.h"
161 #include "nsAttrValue.h"
162 #include "nsReferencedElement.h"
163 #include "nsIUGenCategory.h"
164 #include "nsIDragService.h"
165 #include "nsIChannelEventSink.h"
166 #include "nsIInterfaceRequestor.h"
167 #include "nsIOfflineCacheUpdate.h"
168 #include "nsCPrefetchService.h"
169 #include "nsIChromeRegistry.h"
170 #include "nsIMIMEHeaderParam.h"
171 #include "nsIDOMXULCommandEvent.h"
172 #include "nsIDOMAbstractView.h"
173 #include "nsIDOMDragEvent.h"
174 #include "nsDOMDataTransfer.h"
175 #include "nsHtml5Module.h"
176 #include "nsPresContext.h"
177 #include "nsLayoutStatics.h"
178 #include "nsLayoutUtils.h"
179 #include "nsFrameManager.h"
180 #include "BasicLayers.h"
181 #include "nsFocusManager.h"
182 #include "nsTextEditorState.h"
184 #ifdef IBMBIDI
185 #include "nsIBidiKeyboard.h"
186 #endif
187 #include "nsCycleCollectionParticipant.h"
189 // for ReportToConsole
190 #include "nsIStringBundle.h"
191 #include "nsIScriptError.h"
192 #include "nsIConsoleService.h"
194 #include "mozAutoDocUpdate.h"
195 #include "imgICache.h"
196 #include "jsinterp.h"
197 #include "jsarray.h"
198 #include "jsdate.h"
199 #include "jsregexp.h"
200 #include "jstypedarray.h"
201 #include "xpcprivate.h"
202 #include "nsScriptSecurityManager.h"
203 #include "nsIChannelPolicy.h"
204 #include "nsChannelPolicy.h"
205 #include "nsIContentSecurityPolicy.h"
207 using namespace mozilla::dom;
209 const char kLoadAsData[] = "loadAsData";
211 static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
212 static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
213 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
215 nsIDOMScriptObjectFactory *nsContentUtils::sDOMScriptObjectFactory = nsnull;
216 nsIXPConnect *nsContentUtils::sXPConnect;
217 nsIScriptSecurityManager *nsContentUtils::sSecurityManager;
218 nsIThreadJSContextStack *nsContentUtils::sThreadJSContextStack;
219 nsIParserService *nsContentUtils::sParserService = nsnull;
220 nsINameSpaceManager *nsContentUtils::sNameSpaceManager;
221 nsIIOService *nsContentUtils::sIOService;
222 #ifdef MOZ_XTF
223 nsIXTFService *nsContentUtils::sXTFService = nsnull;
224 #endif
225 nsIPrefBranch2 *nsContentUtils::sPrefBranch = nsnull;
226 imgILoader *nsContentUtils::sImgLoader;
227 imgICache *nsContentUtils::sImgCache;
228 mozilla::IHistory *nsContentUtils::sHistory;
229 nsIConsoleService *nsContentUtils::sConsoleService;
230 nsDataHashtable<nsISupportsHashKey, EventNameMapping>* nsContentUtils::sEventTable = nsnull;
231 nsIStringBundleService *nsContentUtils::sStringBundleService;
232 nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT];
233 nsIContentPolicy *nsContentUtils::sContentPolicyService;
234 PRBool nsContentUtils::sTriedToGetContentPolicy = PR_FALSE;
235 nsILineBreaker *nsContentUtils::sLineBreaker;
236 nsIWordBreaker *nsContentUtils::sWordBreaker;
237 nsICaseConversion *nsContentUtils::sCaseConv;
238 nsIUGenCategory *nsContentUtils::sGenCat;
239 nsTArray<nsISupports**> *nsContentUtils::sPtrsToPtrsToRelease;
240 nsIScriptRuntime *nsContentUtils::sScriptRuntimes[NS_STID_ARRAY_UBOUND];
241 PRInt32 nsContentUtils::sScriptRootCount[NS_STID_ARRAY_UBOUND];
242 PRUint32 nsContentUtils::sJSGCThingRootCount;
243 #ifdef IBMBIDI
244 nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nsnull;
245 #endif
246 PRUint32 nsContentUtils::sScriptBlockerCount = 0;
247 PRUint32 nsContentUtils::sRemovableScriptBlockerCount = 0;
248 nsCOMArray<nsIRunnable>* nsContentUtils::sBlockedScriptRunners = nsnull;
249 PRUint32 nsContentUtils::sRunnersCountAtFirstBlocker = 0;
250 PRUint32 nsContentUtils::sScriptBlockerCountWhereRunnersPrevented = 0;
251 nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nsnull;
253 nsIJSRuntimeService *nsAutoGCRoot::sJSRuntimeService;
254 JSRuntime *nsAutoGCRoot::sJSScriptRuntime;
256 PRBool nsContentUtils::sIsHandlingKeyBoardEvent = PR_FALSE;
258 PRBool nsContentUtils::sInitialized = PR_FALSE;
260 nsCOMArray<nsPrefOldCallback> *nsContentUtils::sPrefCallbackList = nsnull;
262 static PLDHashTable sEventListenerManagersHash;
264 class EventListenerManagerMapEntry : public PLDHashEntryHdr
266 public:
267 EventListenerManagerMapEntry(const void *aKey)
268 : mKey(aKey)
272 ~EventListenerManagerMapEntry()
274 NS_ASSERTION(!mListenerManager, "caller must release and disconnect ELM");
277 private:
278 const void *mKey; // must be first, to look like PLDHashEntryStub
280 public:
281 nsCOMPtr<nsIEventListenerManager> mListenerManager;
284 static PRBool
285 EventListenerManagerHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
286 const void *key)
288 // Initialize the entry with placement new
289 new (entry) EventListenerManagerMapEntry(key);
290 return PR_TRUE;
293 static void
294 EventListenerManagerHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
296 EventListenerManagerMapEntry *lm =
297 static_cast<EventListenerManagerMapEntry *>(entry);
299 // Let the EventListenerManagerMapEntry clean itself up...
300 lm->~EventListenerManagerMapEntry();
303 class nsSameOriginChecker : public nsIChannelEventSink,
304 public nsIInterfaceRequestor
306 NS_DECL_ISUPPORTS
307 NS_DECL_NSICHANNELEVENTSINK
308 NS_DECL_NSIINTERFACEREQUESTOR
311 // For nsContentUtils::RegisterPrefCallback/UnregisterPrefCallback
312 class nsPrefOldCallback : public nsIObserver
314 public:
315 NS_DECL_ISUPPORTS
316 NS_DECL_NSIOBSERVER
318 public:
319 nsPrefOldCallback(const char *aPref, PrefChangedFunc aCallback, void *aClosure) : mPref(aPref), mCallback(aCallback), mClosure(aClosure) {
322 PRBool IsEqual(const char *aPref, PrefChangedFunc aCallback, void *aClosure) {
323 return aCallback == mCallback &&
324 aClosure == mClosure &&
325 mPref.Equals(aPref);
328 public:
329 nsCString mPref;
330 PrefChangedFunc mCallback;
331 void *mClosure;
334 NS_IMPL_ISUPPORTS1(nsPrefOldCallback, nsIObserver)
336 NS_IMETHODIMP
337 nsPrefOldCallback::Observe(nsISupports *aSubject,
338 const char *aTopic,
339 const PRUnichar *aData)
341 NS_ASSERTION(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),
342 "invalid topic");
343 mCallback(NS_LossyConvertUTF16toASCII(aData).get(), mClosure);
345 return NS_OK;
348 struct PrefCacheData {
349 void* cacheLocation;
350 union {
351 PRBool defaultValueBool;
352 PRInt32 defaultValueInt;
356 nsTArray<nsAutoPtr<PrefCacheData> >* sPrefCacheData = nsnull;
358 // static
359 nsresult
360 nsContentUtils::Init()
362 if (sInitialized) {
363 NS_WARNING("Init() called twice");
365 return NS_OK;
368 sPrefCacheData = new nsTArray<nsAutoPtr<PrefCacheData> >();
370 // It's ok to not have a pref service.
371 CallGetService(NS_PREFSERVICE_CONTRACTID, &sPrefBranch);
373 nsresult rv = NS_GetNameSpaceManager(&sNameSpaceManager);
374 NS_ENSURE_SUCCESS(rv, rv);
376 nsXPConnect* xpconnect = nsXPConnect::GetXPConnect();
377 NS_ENSURE_TRUE(xpconnect, NS_ERROR_FAILURE);
379 sXPConnect = xpconnect;
380 sThreadJSContextStack = xpconnect;
382 sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager();
383 if(!sSecurityManager)
384 return NS_ERROR_FAILURE;
385 NS_ADDREF(sSecurityManager);
387 rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
388 if (NS_FAILED(rv)) {
389 // This makes life easier, but we can live without it.
391 sIOService = nsnull;
394 rv = CallGetService(NS_LBRK_CONTRACTID, &sLineBreaker);
395 NS_ENSURE_SUCCESS(rv, rv);
397 rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker);
398 NS_ENSURE_SUCCESS(rv, rv);
400 rv = CallGetService(NS_UNICHARUTIL_CONTRACTID, &sCaseConv);
401 NS_ENSURE_SUCCESS(rv, rv);
403 rv = CallGetService(NS_UNICHARCATEGORY_CONTRACTID, &sGenCat);
404 NS_ENSURE_SUCCESS(rv, rv);
406 // Ignore failure and just don't load images
407 rv = CallGetService("@mozilla.org/image/loader;1", &sImgLoader);
408 if (NS_FAILED(rv)) {
409 // no image loading for us. Oh, well.
410 sImgLoader = nsnull;
411 sImgCache = nsnull;
412 } else {
413 if (NS_FAILED(CallGetService("@mozilla.org/image/cache;1", &sImgCache )))
414 sImgCache = nsnull;
417 rv = CallGetService(NS_IHISTORY_CONTRACTID, &sHistory);
418 if (NS_FAILED(rv)) {
419 NS_RUNTIMEABORT("Cannot get the history service");
420 return rv;
423 sPtrsToPtrsToRelease = new nsTArray<nsISupports**>();
424 if (!sPtrsToPtrsToRelease) {
425 return NS_ERROR_OUT_OF_MEMORY;
428 if (!InitializeEventTable())
429 return NS_ERROR_FAILURE;
431 if (!sEventListenerManagersHash.ops) {
432 static PLDHashTableOps hash_table_ops =
434 PL_DHashAllocTable,
435 PL_DHashFreeTable,
436 PL_DHashVoidPtrKeyStub,
437 PL_DHashMatchEntryStub,
438 PL_DHashMoveEntryStub,
439 EventListenerManagerHashClearEntry,
440 PL_DHashFinalizeStub,
441 EventListenerManagerHashInitEntry
444 if (!PL_DHashTableInit(&sEventListenerManagersHash, &hash_table_ops,
445 nsnull, sizeof(EventListenerManagerMapEntry), 16)) {
446 sEventListenerManagersHash.ops = nsnull;
448 return NS_ERROR_OUT_OF_MEMORY;
452 sBlockedScriptRunners = new nsCOMArray<nsIRunnable>;
453 NS_ENSURE_TRUE(sBlockedScriptRunners, NS_ERROR_OUT_OF_MEMORY);
455 sInitialized = PR_TRUE;
457 return NS_OK;
460 PRBool
461 nsContentUtils::InitializeEventTable() {
462 NS_ASSERTION(!sEventTable, "EventTable already initialized!");
464 struct EventItem
466 nsIAtom** mAtom;
467 EventNameMapping mValue;
470 static const EventItem eventArray[] = {
471 { &nsGkAtoms::onmousedown, { NS_MOUSE_BUTTON_DOWN, EventNameType_All }},
472 { &nsGkAtoms::onmouseup, { NS_MOUSE_BUTTON_UP, EventNameType_All }},
473 { &nsGkAtoms::onclick, { NS_MOUSE_CLICK, EventNameType_All }},
474 { &nsGkAtoms::ondblclick, { NS_MOUSE_DOUBLECLICK, EventNameType_HTMLXUL }},
475 { &nsGkAtoms::onmouseover, { NS_MOUSE_ENTER_SYNTH, EventNameType_All }},
476 { &nsGkAtoms::onmouseout, { NS_MOUSE_EXIT_SYNTH, EventNameType_All }},
477 { &nsGkAtoms::onmousemove, { NS_MOUSE_MOVE, EventNameType_All }},
478 { &nsGkAtoms::oncontextmenu, { NS_CONTEXTMENU, EventNameType_HTMLXUL }},
479 { &nsGkAtoms::onkeydown, { NS_KEY_DOWN, EventNameType_HTMLXUL }},
480 { &nsGkAtoms::onkeyup, { NS_KEY_UP, EventNameType_HTMLXUL }},
481 { &nsGkAtoms::onkeypress, { NS_KEY_PRESS, EventNameType_HTMLXUL }},
482 { &nsGkAtoms::onfocus, { NS_FOCUS_CONTENT, EventNameType_HTMLXUL }},
483 { &nsGkAtoms::onblur, { NS_BLUR_CONTENT, EventNameType_HTMLXUL }},
484 { &nsGkAtoms::onoffline, { NS_OFFLINE, EventNameType_HTMLXUL }},
485 { &nsGkAtoms::ononline, { NS_ONLINE, EventNameType_HTMLXUL }},
486 { &nsGkAtoms::onsubmit, { NS_FORM_SUBMIT, EventNameType_HTMLXUL }},
487 { &nsGkAtoms::onreset, { NS_FORM_RESET, EventNameType_HTMLXUL }},
488 { &nsGkAtoms::onchange, { NS_FORM_CHANGE, EventNameType_HTMLXUL }},
489 { &nsGkAtoms::onselect, { NS_FORM_SELECTED, EventNameType_HTMLXUL }},
490 { &nsGkAtoms::onload, { NS_LOAD, EventNameType_All }},
491 { &nsGkAtoms::onpopstate, { NS_POPSTATE, EventNameType_HTMLXUL }},
492 { &nsGkAtoms::onunload, { NS_PAGE_UNLOAD,
493 (EventNameType_HTMLXUL | EventNameType_SVGSVG) }},
494 { &nsGkAtoms::onhashchange, { NS_HASHCHANGE, EventNameType_HTMLXUL }},
495 { &nsGkAtoms::onbeforeunload, { NS_BEFORE_PAGE_UNLOAD, EventNameType_HTMLXUL }},
496 { &nsGkAtoms::onabort, { NS_IMAGE_ABORT,
497 (EventNameType_HTMLXUL | EventNameType_SVGSVG) }},
498 { &nsGkAtoms::onerror, { NS_LOAD_ERROR,
499 (EventNameType_HTMLXUL | EventNameType_SVGSVG) }},
500 { &nsGkAtoms::onDOMAttrModified, { NS_MUTATION_ATTRMODIFIED, EventNameType_HTMLXUL }},
501 { &nsGkAtoms::onDOMCharacterDataModified, { NS_MUTATION_CHARACTERDATAMODIFIED, EventNameType_HTMLXUL }},
502 { &nsGkAtoms::onDOMNodeInserted, { NS_MUTATION_NODEINSERTED, EventNameType_HTMLXUL }},
503 { &nsGkAtoms::onDOMNodeRemoved, { NS_MUTATION_NODEREMOVED, EventNameType_HTMLXUL }},
504 { &nsGkAtoms::onDOMNodeInsertedIntoDocument, { NS_MUTATION_NODEINSERTEDINTODOCUMENT, EventNameType_HTMLXUL }},
505 { &nsGkAtoms::onDOMNodeRemovedFromDocument, { NS_MUTATION_NODEREMOVEDFROMDOCUMENT, EventNameType_HTMLXUL }},
506 { &nsGkAtoms::onDOMSubtreeModified, { NS_MUTATION_SUBTREEMODIFIED, EventNameType_HTMLXUL }},
507 { &nsGkAtoms::onDOMActivate, { NS_UI_ACTIVATE, EventNameType_HTMLXUL }},
508 { &nsGkAtoms::onDOMFocusIn, { NS_UI_FOCUSIN, EventNameType_HTMLXUL }},
509 { &nsGkAtoms::onDOMFocusOut, { NS_UI_FOCUSOUT, EventNameType_HTMLXUL }},
510 { &nsGkAtoms::onDOMMouseScroll, { NS_MOUSE_SCROLL, EventNameType_HTMLXUL }},
511 { &nsGkAtoms::onMozMousePixelScroll, { NS_MOUSE_PIXEL_SCROLL, EventNameType_HTMLXUL }},
512 { &nsGkAtoms::oninput, { NS_FORM_INPUT, EventNameType_HTMLXUL }},
513 { &nsGkAtoms::onpageshow, { NS_PAGE_SHOW, EventNameType_HTML }},
514 { &nsGkAtoms::onpagehide, { NS_PAGE_HIDE, EventNameType_HTML }},
515 { &nsGkAtoms::onresize, { NS_RESIZE_EVENT,
516 (EventNameType_HTMLXUL | EventNameType_SVGSVG) }},
517 { &nsGkAtoms::onscroll, { NS_SCROLL_EVENT,
518 (EventNameType_HTMLXUL | EventNameType_SVGSVG) }},
519 { &nsGkAtoms::oncopy, { NS_COPY, EventNameType_HTMLXUL }},
520 { &nsGkAtoms::oncut, { NS_CUT, EventNameType_HTMLXUL }},
521 { &nsGkAtoms::onpaste, { NS_PASTE, EventNameType_HTMLXUL }},
522 // XUL specific events
523 { &nsGkAtoms::ontext, { NS_TEXT_TEXT, EventNameType_XUL }},
524 { &nsGkAtoms::oncompositionstart, { NS_COMPOSITION_START, EventNameType_XUL }},
525 { &nsGkAtoms::oncompositionend, { NS_COMPOSITION_END, EventNameType_XUL }},
526 { &nsGkAtoms::onclose, { NS_XUL_CLOSE, EventNameType_XUL }},
527 { &nsGkAtoms::onpopupshowing, { NS_XUL_POPUP_SHOWING, EventNameType_XUL }},
528 { &nsGkAtoms::onpopupshown, { NS_XUL_POPUP_SHOWN, EventNameType_XUL }},
529 { &nsGkAtoms::onpopuphiding, { NS_XUL_POPUP_HIDING, EventNameType_XUL }},
530 { &nsGkAtoms::onpopuphidden, { NS_XUL_POPUP_HIDDEN, EventNameType_XUL }},
531 { &nsGkAtoms::oncommand, { NS_XUL_COMMAND, EventNameType_XUL }},
532 { &nsGkAtoms::onbroadcast, { NS_XUL_BROADCAST, EventNameType_XUL }},
533 { &nsGkAtoms::oncommandupdate, { NS_XUL_COMMAND_UPDATE, EventNameType_XUL }},
534 { &nsGkAtoms::ondragenter, { NS_DRAGDROP_ENTER, EventNameType_HTMLXUL }},
535 { &nsGkAtoms::ondragover, { NS_DRAGDROP_OVER_SYNTH, EventNameType_HTMLXUL }},
536 { &nsGkAtoms::ondragexit, { NS_DRAGDROP_EXIT_SYNTH, EventNameType_XUL }},
537 { &nsGkAtoms::ondragdrop, { NS_DRAGDROP_DRAGDROP, EventNameType_XUL }},
538 { &nsGkAtoms::ondraggesture, { NS_DRAGDROP_GESTURE, EventNameType_XUL }},
539 { &nsGkAtoms::ondrag, { NS_DRAGDROP_DRAG, EventNameType_HTMLXUL }},
540 { &nsGkAtoms::ondragend, { NS_DRAGDROP_END, EventNameType_HTMLXUL }},
541 { &nsGkAtoms::ondragstart, { NS_DRAGDROP_START, EventNameType_HTMLXUL }},
542 { &nsGkAtoms::ondragleave, { NS_DRAGDROP_LEAVE_SYNTH, EventNameType_HTMLXUL }},
543 { &nsGkAtoms::ondrop, { NS_DRAGDROP_DROP, EventNameType_HTMLXUL }},
544 { &nsGkAtoms::onoverflow, { NS_SCROLLPORT_OVERFLOW, EventNameType_XUL }},
545 { &nsGkAtoms::onunderflow, { NS_SCROLLPORT_UNDERFLOW, EventNameType_XUL }},
546 #ifdef MOZ_SVG
547 { &nsGkAtoms::onSVGLoad, { NS_SVG_LOAD, EventNameType_None }},
548 { &nsGkAtoms::onSVGUnload, { NS_SVG_UNLOAD, EventNameType_None }},
549 { &nsGkAtoms::onSVGAbort, { NS_SVG_ABORT, EventNameType_None }},
550 { &nsGkAtoms::onSVGError, { NS_SVG_ERROR, EventNameType_None }},
551 { &nsGkAtoms::onSVGResize, { NS_SVG_RESIZE, EventNameType_None }},
552 { &nsGkAtoms::onSVGScroll, { NS_SVG_SCROLL, EventNameType_None }},
553 { &nsGkAtoms::onSVGZoom, { NS_SVG_ZOOM, EventNameType_None }},
554 { &nsGkAtoms::onzoom, { NS_SVG_ZOOM, EventNameType_SVGSVG }},
555 #endif // MOZ_SVG
556 #ifdef MOZ_MEDIA
557 { &nsGkAtoms::onloadstart, { NS_LOADSTART, EventNameType_HTML }},
558 { &nsGkAtoms::onprogress, { NS_PROGRESS, EventNameType_HTML }},
559 { &nsGkAtoms::onsuspend, { NS_SUSPEND, EventNameType_HTML }},
560 { &nsGkAtoms::onemptied, { NS_EMPTIED, EventNameType_HTML }},
561 { &nsGkAtoms::onstalled, { NS_STALLED, EventNameType_HTML }},
562 { &nsGkAtoms::onplay, { NS_PLAY, EventNameType_HTML }},
563 { &nsGkAtoms::onpause, { NS_PAUSE, EventNameType_HTML }},
564 { &nsGkAtoms::onloadedmetadata, { NS_LOADEDMETADATA, EventNameType_HTML }},
565 { &nsGkAtoms::onloadeddata, { NS_LOADEDDATA, EventNameType_HTML }},
566 { &nsGkAtoms::onwaiting, { NS_WAITING, EventNameType_HTML }},
567 { &nsGkAtoms::onplaying, { NS_PLAYING, EventNameType_HTML }},
568 { &nsGkAtoms::oncanplay, { NS_CANPLAY, EventNameType_HTML }},
569 { &nsGkAtoms::oncanplaythrough, { NS_CANPLAYTHROUGH, EventNameType_HTML }},
570 { &nsGkAtoms::onseeking, { NS_SEEKING, EventNameType_HTML }},
571 { &nsGkAtoms::onseeked, { NS_SEEKED, EventNameType_HTML }},
572 { &nsGkAtoms::ontimeupdate, { NS_TIMEUPDATE, EventNameType_HTML }},
573 { &nsGkAtoms::onended, { NS_ENDED, EventNameType_HTML }},
574 { &nsGkAtoms::onratechange, { NS_RATECHANGE, EventNameType_HTML }},
575 { &nsGkAtoms::ondurationchange, { NS_DURATIONCHANGE, EventNameType_HTML }},
576 { &nsGkAtoms::onvolumechange, { NS_VOLUMECHANGE, EventNameType_HTML }},
577 #endif //MOZ_MEDIA
578 { &nsGkAtoms::onMozAfterPaint, { NS_AFTERPAINT, EventNameType_None }},
579 { &nsGkAtoms::onMozScrolledAreaChanged, { NS_SCROLLEDAREACHANGED, EventNameType_None }},
581 // Simple gesture events
582 { &nsGkAtoms::onMozSwipeGesture, { NS_SIMPLE_GESTURE_SWIPE, EventNameType_None } },
583 { &nsGkAtoms::onMozMagnifyGestureStart, { NS_SIMPLE_GESTURE_MAGNIFY_START, EventNameType_None } },
584 { &nsGkAtoms::onMozMagnifyGestureUpdate, { NS_SIMPLE_GESTURE_MAGNIFY_UPDATE, EventNameType_None } },
585 { &nsGkAtoms::onMozMagnifyGesture, { NS_SIMPLE_GESTURE_MAGNIFY, EventNameType_None } },
586 { &nsGkAtoms::onMozRotateGestureStart, { NS_SIMPLE_GESTURE_ROTATE_START, EventNameType_None } },
587 { &nsGkAtoms::onMozRotateGestureUpdate, { NS_SIMPLE_GESTURE_ROTATE_UPDATE, EventNameType_None } },
588 { &nsGkAtoms::onMozRotateGesture, { NS_SIMPLE_GESTURE_ROTATE, EventNameType_None } },
589 { &nsGkAtoms::onMozTapGesture, { NS_SIMPLE_GESTURE_TAP, EventNameType_None } },
590 { &nsGkAtoms::onMozPressTapGesture, { NS_SIMPLE_GESTURE_PRESSTAP, EventNameType_None } },
592 { &nsGkAtoms::ontransitionend, { NS_TRANSITION_END, EventNameType_None }},
595 sEventTable = new nsDataHashtable<nsISupportsHashKey, EventNameMapping>;
596 if (!sEventTable ||
597 !sEventTable->Init(int(NS_ARRAY_LENGTH(eventArray) / 0.75) + 1)) {
598 delete sEventTable;
599 sEventTable = nsnull;
600 return PR_FALSE;
603 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(eventArray); ++i) {
604 if (!sEventTable->Put(*(eventArray[i].mAtom), eventArray[i].mValue)) {
605 delete sEventTable;
606 sEventTable = nsnull;
607 return PR_FALSE;
611 return PR_TRUE;
615 * Access a cached parser service. Don't addref. We need only one
616 * reference to it and this class has that one.
618 /* static */
619 nsIParserService*
620 nsContentUtils::GetParserService()
622 // XXX: This isn't accessed from several threads, is it?
623 if (!sParserService) {
624 // Lock, recheck sCachedParserService and aquire if this should be
625 // safe for multiple threads.
626 nsresult rv = CallGetService(kParserServiceCID, &sParserService);
627 if (NS_FAILED(rv)) {
628 sParserService = nsnull;
632 return sParserService;
635 #ifdef MOZ_XTF
636 nsIXTFService*
637 nsContentUtils::GetXTFService()
639 if (!sXTFService) {
640 nsresult rv = CallGetService(kXTFServiceCID, &sXTFService);
641 if (NS_FAILED(rv)) {
642 sXTFService = nsnull;
646 return sXTFService;
648 #endif
650 #ifdef IBMBIDI
651 nsIBidiKeyboard*
652 nsContentUtils::GetBidiKeyboard()
654 if (!sBidiKeyboard) {
655 nsresult rv = CallGetService("@mozilla.org/widget/bidikeyboard;1", &sBidiKeyboard);
656 if (NS_FAILED(rv)) {
657 sBidiKeyboard = nsnull;
660 return sBidiKeyboard;
662 #endif
664 template <class OutputIterator>
665 struct NormalizeNewlinesCharTraits {
666 public:
667 typedef typename OutputIterator::value_type value_type;
669 public:
670 NormalizeNewlinesCharTraits(OutputIterator& aIterator) : mIterator(aIterator) { }
671 void writechar(typename OutputIterator::value_type aChar) {
672 *mIterator++ = aChar;
675 private:
676 OutputIterator mIterator;
679 #ifdef HAVE_CPP_PARTIAL_SPECIALIZATION
681 template <class CharT>
682 struct NormalizeNewlinesCharTraits<CharT*> {
683 public:
684 typedef CharT value_type;
686 public:
687 NormalizeNewlinesCharTraits(CharT* aCharPtr) : mCharPtr(aCharPtr) { }
688 void writechar(CharT aChar) {
689 *mCharPtr++ = aChar;
692 private:
693 CharT* mCharPtr;
696 #else
698 NS_SPECIALIZE_TEMPLATE
699 struct NormalizeNewlinesCharTraits<char*> {
700 public:
701 typedef char value_type;
703 public:
704 NormalizeNewlinesCharTraits(char* aCharPtr) : mCharPtr(aCharPtr) { }
705 void writechar(char aChar) {
706 *mCharPtr++ = aChar;
709 private:
710 char* mCharPtr;
713 NS_SPECIALIZE_TEMPLATE
714 struct NormalizeNewlinesCharTraits<PRUnichar*> {
715 public:
716 typedef PRUnichar value_type;
718 public:
719 NormalizeNewlinesCharTraits(PRUnichar* aCharPtr) : mCharPtr(aCharPtr) { }
720 void writechar(PRUnichar aChar) {
721 *mCharPtr++ = aChar;
724 private:
725 PRUnichar* mCharPtr;
728 #endif
730 template <class OutputIterator>
731 class CopyNormalizeNewlines
733 public:
734 typedef typename OutputIterator::value_type value_type;
736 public:
737 CopyNormalizeNewlines(OutputIterator* aDestination,
738 PRBool aLastCharCR=PR_FALSE) :
739 mLastCharCR(aLastCharCR),
740 mDestination(aDestination),
741 mWritten(0)
744 PRUint32 GetCharsWritten() {
745 return mWritten;
748 PRBool IsLastCharCR() {
749 return mLastCharCR;
752 void write(const typename OutputIterator::value_type* aSource, PRUint32 aSourceLength) {
754 const typename OutputIterator::value_type* done_writing = aSource + aSourceLength;
756 // If the last source buffer ended with a CR...
757 if (mLastCharCR) {
758 // ..and if the next one is a LF, then skip it since
759 // we've already written out a newline
760 if (aSourceLength && (*aSource == value_type('\n'))) {
761 ++aSource;
763 mLastCharCR = PR_FALSE;
766 PRUint32 num_written = 0;
767 while ( aSource < done_writing ) {
768 if (*aSource == value_type('\r')) {
769 mDestination->writechar('\n');
770 ++aSource;
771 // If we've reached the end of the buffer, record
772 // that we wrote out a CR
773 if (aSource == done_writing) {
774 mLastCharCR = PR_TRUE;
776 // If the next character is a LF, skip it
777 else if (*aSource == value_type('\n')) {
778 ++aSource;
781 else {
782 mDestination->writechar(*aSource++);
784 ++num_written;
787 mWritten += num_written;
790 private:
791 PRBool mLastCharCR;
792 OutputIterator* mDestination;
793 PRUint32 mWritten;
796 // static
797 PRUint32
798 nsContentUtils::CopyNewlineNormalizedUnicodeTo(const nsAString& aSource,
799 PRUint32 aSrcOffset,
800 PRUnichar* aDest,
801 PRUint32 aLength,
802 PRBool& aLastCharCR)
804 typedef NormalizeNewlinesCharTraits<PRUnichar*> sink_traits;
806 sink_traits dest_traits(aDest);
807 CopyNormalizeNewlines<sink_traits> normalizer(&dest_traits,aLastCharCR);
808 nsReadingIterator<PRUnichar> fromBegin, fromEnd;
809 copy_string(aSource.BeginReading(fromBegin).advance( PRInt32(aSrcOffset) ),
810 aSource.BeginReading(fromEnd).advance( PRInt32(aSrcOffset+aLength) ),
811 normalizer);
812 aLastCharCR = normalizer.IsLastCharCR();
813 return normalizer.GetCharsWritten();
816 // static
817 PRUint32
818 nsContentUtils::CopyNewlineNormalizedUnicodeTo(nsReadingIterator<PRUnichar>& aSrcStart, const nsReadingIterator<PRUnichar>& aSrcEnd, nsAString& aDest)
820 typedef nsWritingIterator<PRUnichar> WritingIterator;
821 typedef NormalizeNewlinesCharTraits<WritingIterator> sink_traits;
823 WritingIterator iter;
824 aDest.BeginWriting(iter);
825 sink_traits dest_traits(iter);
826 CopyNormalizeNewlines<sink_traits> normalizer(&dest_traits);
827 copy_string(aSrcStart, aSrcEnd, normalizer);
828 return normalizer.GetCharsWritten();
831 // Replaced by precompiled CCMap (see bug 180266). To update the list
832 // of characters, see one of files included below. As for the way
833 // the original list of characters was obtained by Frank Tang, see bug 54467.
834 // Updated to fix the regression (bug 263411). The list contains
835 // characters of the following Unicode character classes : Ps, Pi, Po, Pf, Pe.
836 // (ref.: http://www.w3.org/TR/2004/CR-CSS21-20040225/selector.html#first-letter)
837 #include "punct_marks.x-ccmap"
838 DEFINE_X_CCMAP(gPuncCharsCCMapExt, const);
840 // static
841 PRBool
842 nsContentUtils::IsPunctuationMark(PRUint32 aChar)
844 return CCMAP_HAS_CHAR_EXT(gPuncCharsCCMapExt, aChar);
847 // static
848 PRBool
849 nsContentUtils::IsPunctuationMarkAt(const nsTextFragment* aFrag, PRUint32 aOffset)
851 PRUnichar h = aFrag->CharAt(aOffset);
852 if (!IS_SURROGATE(h)) {
853 return IsPunctuationMark(h);
855 if (NS_IS_HIGH_SURROGATE(h) && aOffset + 1 < aFrag->GetLength()) {
856 PRUnichar l = aFrag->CharAt(aOffset + 1);
857 if (NS_IS_LOW_SURROGATE(l)) {
858 return IsPunctuationMark(SURROGATE_TO_UCS4(h, l));
861 return PR_FALSE;
864 // static
865 PRBool nsContentUtils::IsAlphanumeric(PRUint32 aChar)
867 nsIUGenCategory::nsUGenCategory cat = sGenCat->Get(aChar);
869 return (cat == nsIUGenCategory::kLetter || cat == nsIUGenCategory::kNumber);
872 // static
873 PRBool nsContentUtils::IsAlphanumericAt(const nsTextFragment* aFrag, PRUint32 aOffset)
875 PRUnichar h = aFrag->CharAt(aOffset);
876 if (!IS_SURROGATE(h)) {
877 return IsAlphanumeric(h);
879 if (NS_IS_HIGH_SURROGATE(h) && aOffset + 1 < aFrag->GetLength()) {
880 PRUnichar l = aFrag->CharAt(aOffset + 1);
881 if (NS_IS_LOW_SURROGATE(l)) {
882 return IsAlphanumeric(SURROGATE_TO_UCS4(h, l));
885 return PR_FALSE;
888 /* static */
889 PRBool
890 nsContentUtils::IsHTMLWhitespace(PRUnichar aChar)
892 return aChar == PRUnichar(0x0009) ||
893 aChar == PRUnichar(0x000A) ||
894 aChar == PRUnichar(0x000C) ||
895 aChar == PRUnichar(0x000D) ||
896 aChar == PRUnichar(0x0020);
900 /* static */
901 void
902 nsContentUtils::GetOfflineAppManifest(nsIDocument *aDocument, nsIURI **aURI)
904 Element* docElement = aDocument->GetRootElement();
905 if (!docElement) {
906 return;
909 nsAutoString manifestSpec;
910 docElement->GetAttr(kNameSpaceID_None, nsGkAtoms::manifest, manifestSpec);
912 // Manifest URIs can't have fragment identifiers.
913 if (manifestSpec.IsEmpty() ||
914 manifestSpec.FindChar('#') != kNotFound) {
915 return;
918 nsContentUtils::NewURIWithDocumentCharset(aURI, manifestSpec,
919 aDocument,
920 aDocument->GetDocBaseURI());
923 /* static */
924 PRBool
925 nsContentUtils::OfflineAppAllowed(nsIURI *aURI)
927 nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
928 do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
929 if (!updateService) {
930 return PR_FALSE;
933 PRBool allowed;
934 nsresult rv = updateService->OfflineAppAllowedForURI(aURI,
935 sPrefBranch,
936 &allowed);
937 return NS_SUCCEEDED(rv) && allowed;
940 /* static */
941 PRBool
942 nsContentUtils::OfflineAppAllowed(nsIPrincipal *aPrincipal)
944 nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
945 do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
946 if (!updateService) {
947 return PR_FALSE;
950 PRBool allowed;
951 nsresult rv = updateService->OfflineAppAllowed(aPrincipal,
952 sPrefBranch,
953 &allowed);
954 return NS_SUCCEEDED(rv) && allowed;
957 // static
958 void
959 nsContentUtils::Shutdown()
961 sInitialized = PR_FALSE;
963 NS_HTMLParanoidFragmentSinkShutdown();
964 NS_XHTMLParanoidFragmentSinkShutdown();
966 NS_IF_RELEASE(sContentPolicyService);
967 sTriedToGetContentPolicy = PR_FALSE;
968 PRUint32 i;
969 for (i = 0; i < PropertiesFile_COUNT; ++i)
970 NS_IF_RELEASE(sStringBundles[i]);
972 // Clean up c-style's observer
973 if (sPrefCallbackList) {
974 while (sPrefCallbackList->Count() > 0) {
975 nsRefPtr<nsPrefOldCallback> callback = (*sPrefCallbackList)[0];
976 NS_ABORT_IF_FALSE(callback, "Invalid c-style callback is appended");
977 if (sPrefBranch)
978 sPrefBranch->RemoveObserver(callback->mPref.get(), callback);
979 sPrefCallbackList->RemoveObject(callback);
981 delete sPrefCallbackList;
982 sPrefCallbackList = nsnull;
985 delete sPrefCacheData;
986 sPrefCacheData = nsnull;
988 NS_IF_RELEASE(sStringBundleService);
989 NS_IF_RELEASE(sConsoleService);
990 NS_IF_RELEASE(sDOMScriptObjectFactory);
991 sXPConnect = nsnull;
992 sThreadJSContextStack = nsnull;
993 NS_IF_RELEASE(sSecurityManager);
994 NS_IF_RELEASE(sNameSpaceManager);
995 NS_IF_RELEASE(sParserService);
996 NS_IF_RELEASE(sIOService);
997 NS_IF_RELEASE(sLineBreaker);
998 NS_IF_RELEASE(sWordBreaker);
999 NS_IF_RELEASE(sCaseConv);
1000 NS_IF_RELEASE(sGenCat);
1001 #ifdef MOZ_XTF
1002 NS_IF_RELEASE(sXTFService);
1003 #endif
1004 NS_IF_RELEASE(sImgLoader);
1005 NS_IF_RELEASE(sImgCache);
1006 NS_IF_RELEASE(sHistory);
1007 NS_IF_RELEASE(sPrefBranch);
1008 #ifdef IBMBIDI
1009 NS_IF_RELEASE(sBidiKeyboard);
1010 #endif
1012 delete sEventTable;
1013 sEventTable = nsnull;
1015 if (sPtrsToPtrsToRelease) {
1016 for (i = 0; i < sPtrsToPtrsToRelease->Length(); ++i) {
1017 nsISupports** ptrToPtr = sPtrsToPtrsToRelease->ElementAt(i);
1018 NS_RELEASE(*ptrToPtr);
1020 delete sPtrsToPtrsToRelease;
1021 sPtrsToPtrsToRelease = nsnull;
1024 if (sEventListenerManagersHash.ops) {
1025 NS_ASSERTION(sEventListenerManagersHash.entryCount == 0,
1026 "Event listener manager hash not empty at shutdown!");
1028 // See comment above.
1030 // However, we have to handle this table differently. If it still
1031 // has entries, we want to leak it too, so that we can keep it alive
1032 // in case any elements are destroyed. Because if they are, we need
1033 // their event listener managers to be destroyed too, or otherwise
1034 // it could leave dangling references in DOMClassInfo's preserved
1035 // wrapper table.
1037 if (sEventListenerManagersHash.entryCount == 0) {
1038 PL_DHashTableFinish(&sEventListenerManagersHash);
1039 sEventListenerManagersHash.ops = nsnull;
1043 NS_ASSERTION(!sBlockedScriptRunners ||
1044 sBlockedScriptRunners->Count() == 0,
1045 "How'd this happen?");
1046 delete sBlockedScriptRunners;
1047 sBlockedScriptRunners = nsnull;
1049 NS_IF_RELEASE(sSameOriginChecker);
1051 nsAutoGCRoot::Shutdown();
1053 nsTextEditorState::ShutDown();
1056 // static
1057 PRBool
1058 nsContentUtils::IsCallerTrustedForCapability(const char* aCapability)
1060 // The secman really should handle UniversalXPConnect case, since that
1061 // should include UniversalBrowserRead... doesn't right now, though.
1062 PRBool hasCap;
1063 if (NS_FAILED(sSecurityManager->IsCapabilityEnabled(aCapability, &hasCap)))
1064 return PR_FALSE;
1065 if (hasCap)
1066 return PR_TRUE;
1068 if (NS_FAILED(sSecurityManager->IsCapabilityEnabled("UniversalXPConnect",
1069 &hasCap)))
1070 return PR_FALSE;
1071 return hasCap;
1075 * Checks whether two nodes come from the same origin. aTrustedNode is
1076 * considered 'safe' in that a user can operate on it and that it isn't
1077 * a js-object that implements nsIDOMNode.
1078 * Never call this function with the first node provided by script, it
1079 * must always be known to be a 'real' node!
1081 // static
1082 nsresult
1083 nsContentUtils::CheckSameOrigin(nsINode *aTrustedNode,
1084 nsIDOMNode *aUnTrustedNode)
1086 NS_PRECONDITION(aTrustedNode, "There must be a trusted node");
1088 PRBool isSystem = PR_FALSE;
1089 sSecurityManager->SubjectPrincipalIsSystem(&isSystem);
1090 if (isSystem) {
1091 // we're running as system, grant access to the node.
1093 return NS_OK;
1097 * Get hold of each node's principal
1099 nsCOMPtr<nsINode> unTrustedNode = do_QueryInterface(aUnTrustedNode);
1101 // Make sure these are both real nodes
1102 NS_ENSURE_TRUE(aTrustedNode && unTrustedNode, NS_ERROR_UNEXPECTED);
1104 nsIPrincipal* trustedPrincipal = aTrustedNode->NodePrincipal();
1105 nsIPrincipal* unTrustedPrincipal = unTrustedNode->NodePrincipal();
1107 if (trustedPrincipal == unTrustedPrincipal) {
1108 return NS_OK;
1111 PRBool equal;
1112 // XXXbz should we actually have a Subsumes() check here instead? Or perhaps
1113 // a separate method for that, with callers using one or the other?
1114 if (NS_FAILED(trustedPrincipal->Equals(unTrustedPrincipal, &equal)) ||
1115 !equal) {
1116 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
1119 return NS_OK;
1122 // static
1123 PRBool
1124 nsContentUtils::CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
1125 nsIPrincipal* aPrincipal)
1127 PRBool subsumes;
1128 nsresult rv = aSubjectPrincipal->Subsumes(aPrincipal, &subsumes);
1129 NS_ENSURE_SUCCESS(rv, PR_FALSE);
1131 if (subsumes) {
1132 return PR_TRUE;
1135 // The subject doesn't subsume aPrincipal. Allow access only if the subject
1136 // has either "UniversalXPConnect" (if aPrincipal is system principal) or
1137 // "UniversalBrowserRead" (in all other cases).
1138 PRBool isSystem;
1139 rv = sSecurityManager->IsSystemPrincipal(aPrincipal, &isSystem);
1140 isSystem = NS_FAILED(rv) || isSystem;
1141 const char* capability =
1142 NS_FAILED(rv) || isSystem ? "UniversalXPConnect" : "UniversalBrowserRead";
1144 return IsCallerTrustedForCapability(capability);
1147 // static
1148 PRBool
1149 nsContentUtils::CanCallerAccess(nsIDOMNode *aNode)
1151 // XXXbz why not check the IsCapabilityEnabled thing up front, and not bother
1152 // with the system principal games? But really, there should be a simpler
1153 // API here, dammit.
1154 nsCOMPtr<nsIPrincipal> subjectPrincipal;
1155 sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
1157 if (!subjectPrincipal) {
1158 // we're running as system, grant access to the node.
1160 return PR_TRUE;
1163 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
1164 NS_ENSURE_TRUE(node, PR_FALSE);
1166 return CanCallerAccess(subjectPrincipal, node->NodePrincipal());
1169 // static
1170 PRBool
1171 nsContentUtils::CanCallerAccess(nsPIDOMWindow* aWindow)
1173 // XXXbz why not check the IsCapabilityEnabled thing up front, and not bother
1174 // with the system principal games? But really, there should be a simpler
1175 // API here, dammit.
1176 nsCOMPtr<nsIPrincipal> subjectPrincipal;
1177 sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
1179 if (!subjectPrincipal) {
1180 // we're running as system, grant access to the node.
1182 return PR_TRUE;
1185 nsCOMPtr<nsIScriptObjectPrincipal> scriptObject =
1186 do_QueryInterface(aWindow->IsOuterWindow() ?
1187 aWindow->GetCurrentInnerWindow() : aWindow);
1188 NS_ENSURE_TRUE(scriptObject, PR_FALSE);
1190 return CanCallerAccess(subjectPrincipal, scriptObject->GetPrincipal());
1193 //static
1194 PRBool
1195 nsContentUtils::InProlog(nsINode *aNode)
1197 NS_PRECONDITION(aNode, "missing node to nsContentUtils::InProlog");
1199 nsINode* parent = aNode->GetNodeParent();
1200 if (!parent || !parent->IsNodeOfType(nsINode::eDOCUMENT)) {
1201 return PR_FALSE;
1204 nsIDocument* doc = static_cast<nsIDocument*>(parent);
1205 nsIContent* root = doc->GetRootElement();
1207 return !root || doc->IndexOf(aNode) < doc->IndexOf(root);
1210 static JSContext *
1211 GetContextFromDocument(nsIDocument *aDocument, JSObject** aGlobalObject)
1213 nsIScriptGlobalObject *sgo = aDocument->GetScopeObject();
1214 if (!sgo) {
1215 // No script global, no context.
1217 *aGlobalObject = nsnull;
1219 return nsnull;
1222 *aGlobalObject = sgo->GetGlobalJSObject();
1224 nsIScriptContext *scx = sgo->GetContext();
1225 if (!scx) {
1226 // No context left in the old scope...
1228 return nsnull;
1231 return (JSContext *)scx->GetNativeContext();
1234 // static
1235 nsresult
1236 nsContentUtils::GetContextAndScopes(nsIDocument *aOldDocument,
1237 nsIDocument *aNewDocument, JSContext **aCx,
1238 JSObject **aOldScope, JSObject **aNewScope)
1240 *aCx = nsnull;
1241 *aOldScope = nsnull;
1242 *aNewScope = nsnull;
1244 JSObject *newScope = nsnull;
1245 nsIScriptGlobalObject *newSGO = aNewDocument->GetScopeObject();
1246 if (!newSGO || !(newScope = newSGO->GetGlobalJSObject())) {
1247 return NS_OK;
1250 NS_ENSURE_TRUE(sXPConnect, NS_ERROR_NOT_INITIALIZED);
1252 // Make sure to get our hands on the right scope object, since
1253 // GetWrappedNativeOfNativeObject doesn't call PreCreate and hence won't get
1254 // the right scope if we pass in something bogus. The right scope lives on
1255 // the script global of the old document.
1256 // XXXbz note that if GetWrappedNativeOfNativeObject did call PreCreate it
1257 // would get the wrong scope (that of the _new_ document), so we should be
1258 // glad it doesn't!
1259 JSObject *oldScope = nsnull;
1260 JSContext *cx = GetContextFromDocument(aOldDocument, &oldScope);
1262 if (!oldScope) {
1263 return NS_OK;
1266 if (!cx) {
1267 JSObject *dummy;
1268 cx = GetContextFromDocument(aNewDocument, &dummy);
1270 if (!cx) {
1271 // No context reachable from the old or new document, use the
1272 // calling context, or the safe context if no caller can be
1273 // found.
1275 sThreadJSContextStack->Peek(&cx);
1277 if (!cx) {
1278 sThreadJSContextStack->GetSafeJSContext(&cx);
1280 if (!cx) {
1281 // No safe context reachable, bail.
1282 NS_WARNING("No context reachable in GetContextAndScopes()!");
1284 return NS_ERROR_NOT_AVAILABLE;
1290 *aCx = cx;
1291 *aOldScope = oldScope;
1292 *aNewScope = newScope;
1294 return NS_OK;
1297 nsresult
1298 nsContentUtils::ReparentContentWrappersInScope(nsIScriptGlobalObject *aOldScope,
1299 nsIScriptGlobalObject *aNewScope)
1301 JSContext *cx = nsnull;
1303 // Try really hard to find a context to work on.
1304 nsIScriptContext *context = aOldScope->GetContext();
1305 if (context) {
1306 cx = static_cast<JSContext *>(context->GetNativeContext());
1309 if (!cx) {
1310 context = aNewScope->GetContext();
1311 if (context) {
1312 cx = static_cast<JSContext *>(context->GetNativeContext());
1315 if (!cx) {
1316 sThreadJSContextStack->Peek(&cx);
1318 if (!cx) {
1319 sThreadJSContextStack->GetSafeJSContext(&cx);
1321 if (!cx) {
1322 // Wow, this is really bad!
1323 NS_WARNING("No context reachable in ReparentContentWrappers()!");
1325 return NS_ERROR_NOT_AVAILABLE;
1331 // Now that we have a context, let's get the global objects from the two
1332 // scopes and ask XPConnect to do the rest of the work.
1334 JSObject *oldScopeObj = aOldScope->GetGlobalJSObject();
1335 JSObject *newScopeObj = aNewScope->GetGlobalJSObject();
1337 if (!newScopeObj || !oldScopeObj) {
1338 // We can't really do anything without the JSObjects.
1340 return NS_ERROR_NOT_AVAILABLE;
1343 return sXPConnect->MoveWrappers(cx, oldScopeObj, newScopeObj);
1346 nsIDocShell *
1347 nsContentUtils::GetDocShellFromCaller()
1349 JSContext *cx = nsnull;
1350 sThreadJSContextStack->Peek(&cx);
1352 if (cx) {
1353 nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(cx);
1354 nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(sgo));
1356 if (win) {
1357 return win->GetDocShell();
1361 return nsnull;
1364 nsIDOMDocument *
1365 nsContentUtils::GetDocumentFromCaller()
1367 JSContext *cx = nsnull;
1368 sThreadJSContextStack->Peek(&cx);
1370 nsIDOMDocument *doc = nsnull;
1372 if (cx) {
1373 JSObject *callee = nsnull;
1374 JSStackFrame *fp = nsnull;
1375 while (!callee && (fp = ::JS_FrameIterator(cx, &fp))) {
1376 callee = ::JS_GetFrameCalleeObject(cx, fp);
1379 nsCOMPtr<nsPIDOMWindow> win =
1380 do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(cx, callee));
1381 if (win) {
1382 doc = win->GetExtantDocument();
1386 return doc;
1389 nsIDOMDocument *
1390 nsContentUtils::GetDocumentFromContext()
1392 JSContext *cx = nsnull;
1393 sThreadJSContextStack->Peek(&cx);
1395 if (cx) {
1396 nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(cx);
1398 if (sgo) {
1399 nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(sgo);
1400 if (pwin) {
1401 return pwin->GetExtantDocument();
1406 return nsnull;
1409 PRBool
1410 nsContentUtils::IsCallerChrome()
1412 PRBool is_caller_chrome = PR_FALSE;
1413 nsresult rv = sSecurityManager->SubjectPrincipalIsSystem(&is_caller_chrome);
1414 if (NS_FAILED(rv)) {
1415 return PR_FALSE;
1418 return is_caller_chrome;
1421 PRBool
1422 nsContentUtils::IsCallerTrustedForRead()
1424 return IsCallerTrustedForCapability("UniversalBrowserRead");
1427 PRBool
1428 nsContentUtils::IsCallerTrustedForWrite()
1430 return IsCallerTrustedForCapability("UniversalBrowserWrite");
1433 // static
1434 PRBool
1435 nsContentUtils::ContentIsDescendantOf(const nsINode* aPossibleDescendant,
1436 const nsINode* aPossibleAncestor)
1438 NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
1439 NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
1441 do {
1442 if (aPossibleDescendant == aPossibleAncestor)
1443 return PR_TRUE;
1444 aPossibleDescendant = aPossibleDescendant->GetNodeParent();
1445 } while (aPossibleDescendant);
1447 return PR_FALSE;
1450 // static
1451 PRBool
1452 nsContentUtils::ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
1453 nsINode* aPossibleAncestor)
1455 NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
1456 NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
1458 do {
1459 if (aPossibleDescendant == aPossibleAncestor)
1460 return PR_TRUE;
1461 nsINode* parent = aPossibleDescendant->GetNodeParent();
1462 if (!parent && aPossibleDescendant->IsNodeOfType(nsINode::eDOCUMENT)) {
1463 nsIDocument* doc = static_cast<nsIDocument*>(aPossibleDescendant);
1464 nsIDocument* parentDoc = doc->GetParentDocument();
1465 aPossibleDescendant = parentDoc ?
1466 parentDoc->FindContentForSubDocument(doc) : nsnull;
1468 else {
1469 aPossibleDescendant = parent;
1471 } while (aPossibleDescendant);
1473 return PR_FALSE;
1477 // static
1478 nsresult
1479 nsContentUtils::GetAncestors(nsINode* aNode,
1480 nsTArray<nsINode*>& aArray)
1482 while (aNode) {
1483 aArray.AppendElement(aNode);
1484 aNode = aNode->GetNodeParent();
1486 return NS_OK;
1489 // static
1490 nsresult
1491 nsContentUtils::GetAncestorsAndOffsets(nsIDOMNode* aNode,
1492 PRInt32 aOffset,
1493 nsTArray<nsIContent*>* aAncestorNodes,
1494 nsTArray<PRInt32>* aAncestorOffsets)
1496 NS_ENSURE_ARG_POINTER(aNode);
1498 nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
1500 if (!content) {
1501 return NS_ERROR_FAILURE;
1504 if (!aAncestorNodes->IsEmpty()) {
1505 NS_WARNING("aAncestorNodes is not empty");
1506 aAncestorNodes->Clear();
1509 if (!aAncestorOffsets->IsEmpty()) {
1510 NS_WARNING("aAncestorOffsets is not empty");
1511 aAncestorOffsets->Clear();
1514 // insert the node itself
1515 aAncestorNodes->AppendElement(content.get());
1516 aAncestorOffsets->AppendElement(aOffset);
1518 // insert all the ancestors
1519 nsIContent* child = content;
1520 nsIContent* parent = child->GetParent();
1521 while (parent) {
1522 aAncestorNodes->AppendElement(parent);
1523 aAncestorOffsets->AppendElement(parent->IndexOf(child));
1524 child = parent;
1525 parent = parent->GetParent();
1528 return NS_OK;
1531 // static
1532 nsresult
1533 nsContentUtils::GetCommonAncestor(nsIDOMNode *aNode,
1534 nsIDOMNode *aOther,
1535 nsIDOMNode** aCommonAncestor)
1537 *aCommonAncestor = nsnull;
1539 nsCOMPtr<nsINode> node1 = do_QueryInterface(aNode);
1540 nsCOMPtr<nsINode> node2 = do_QueryInterface(aOther);
1542 NS_ENSURE_TRUE(node1 && node2, NS_ERROR_UNEXPECTED);
1544 nsINode* common = GetCommonAncestor(node1, node2);
1545 NS_ENSURE_TRUE(common, NS_ERROR_NOT_AVAILABLE);
1547 return CallQueryInterface(common, aCommonAncestor);
1550 // static
1551 nsINode*
1552 nsContentUtils::GetCommonAncestor(nsINode* aNode1,
1553 nsINode* aNode2)
1555 if (aNode1 == aNode2) {
1556 return aNode1;
1559 // Build the chain of parents
1560 nsAutoTPtrArray<nsINode, 30> parents1, parents2;
1561 do {
1562 parents1.AppendElement(aNode1);
1563 aNode1 = aNode1->GetNodeParent();
1564 } while (aNode1);
1565 do {
1566 parents2.AppendElement(aNode2);
1567 aNode2 = aNode2->GetNodeParent();
1568 } while (aNode2);
1570 // Find where the parent chain differs
1571 PRUint32 pos1 = parents1.Length();
1572 PRUint32 pos2 = parents2.Length();
1573 nsINode* parent = nsnull;
1574 PRUint32 len;
1575 for (len = NS_MIN(pos1, pos2); len > 0; --len) {
1576 nsINode* child1 = parents1.ElementAt(--pos1);
1577 nsINode* child2 = parents2.ElementAt(--pos2);
1578 if (child1 != child2) {
1579 break;
1581 parent = child1;
1584 return parent;
1587 /* static */
1588 PRInt32
1589 nsContentUtils::ComparePoints(nsINode* aParent1, PRInt32 aOffset1,
1590 nsINode* aParent2, PRInt32 aOffset2,
1591 PRBool* aDisconnected)
1593 if (aParent1 == aParent2) {
1594 return aOffset1 < aOffset2 ? -1 :
1595 aOffset1 > aOffset2 ? 1 :
1599 nsAutoTArray<nsINode*, 32> parents1, parents2;
1600 nsINode* node1 = aParent1;
1601 nsINode* node2 = aParent2;
1602 do {
1603 parents1.AppendElement(node1);
1604 node1 = node1->GetNodeParent();
1605 } while (node1);
1606 do {
1607 parents2.AppendElement(node2);
1608 node2 = node2->GetNodeParent();
1609 } while (node2);
1611 PRUint32 pos1 = parents1.Length() - 1;
1612 PRUint32 pos2 = parents2.Length() - 1;
1614 PRBool disconnected = parents1.ElementAt(pos1) != parents2.ElementAt(pos2);
1615 if (aDisconnected) {
1616 *aDisconnected = disconnected;
1618 if (disconnected) {
1619 NS_ASSERTION(aDisconnected, "unexpected disconnected nodes");
1620 return 1;
1623 // Find where the parent chains differ
1624 nsINode* parent = parents1.ElementAt(pos1);
1625 PRUint32 len;
1626 for (len = NS_MIN(pos1, pos2); len > 0; --len) {
1627 nsINode* child1 = parents1.ElementAt(--pos1);
1628 nsINode* child2 = parents2.ElementAt(--pos2);
1629 if (child1 != child2) {
1630 return parent->IndexOf(child1) < parent->IndexOf(child2) ? -1 : 1;
1632 parent = child1;
1636 // The parent chains never differed, so one of the nodes is an ancestor of
1637 // the other
1639 NS_ASSERTION(!pos1 || !pos2,
1640 "should have run out of parent chain for one of the nodes");
1642 if (!pos1) {
1643 nsINode* child2 = parents2.ElementAt(--pos2);
1644 return aOffset1 <= parent->IndexOf(child2) ? -1 : 1;
1647 nsINode* child1 = parents1.ElementAt(--pos1);
1648 return parent->IndexOf(child1) < aOffset2 ? -1 : 1;
1651 nsIContent*
1652 nsContentUtils::FindFirstChildWithResolvedTag(nsIContent* aParent,
1653 PRInt32 aNamespace,
1654 nsIAtom* aTag)
1656 nsIDocument* doc;
1657 if (!aParent || !(doc = aParent->GetOwnerDoc())) {
1658 return nsnull;
1661 nsBindingManager* bindingManager = doc->BindingManager();
1663 PRInt32 namespaceID;
1664 PRUint32 count = aParent->GetChildCount();
1666 PRUint32 i;
1668 for (i = 0; i < count; i++) {
1669 nsIContent *child = aParent->GetChildAt(i);
1670 nsIAtom* tag = bindingManager->ResolveTag(child, &namespaceID);
1671 if (tag == aTag && namespaceID == aNamespace) {
1672 return child;
1676 // now look for children in XBL
1677 nsCOMPtr<nsIDOMNodeList> children;
1678 bindingManager->GetXBLChildNodesFor(aParent, getter_AddRefs(children));
1679 if (!children) {
1680 return nsnull;
1683 PRUint32 length;
1684 children->GetLength(&length);
1685 for (i = 0; i < length; i++) {
1686 nsCOMPtr<nsIDOMNode> childNode;
1687 children->Item(i, getter_AddRefs(childNode));
1688 nsCOMPtr<nsIContent> childContent = do_QueryInterface(childNode);
1689 nsIAtom* tag = bindingManager->ResolveTag(childContent, &namespaceID);
1690 if (tag == aTag && namespaceID == aNamespace) {
1691 return childContent;
1695 return nsnull;
1698 inline PRBool
1699 IsCharInSet(const char* aSet,
1700 const PRUnichar aChar)
1702 PRUnichar ch;
1703 while ((ch = *aSet)) {
1704 if (aChar == PRUnichar(ch)) {
1705 return PR_TRUE;
1707 ++aSet;
1709 return PR_FALSE;
1713 * This method strips leading/trailing chars, in given set, from string.
1716 // static
1717 const nsDependentSubstring
1718 nsContentUtils::TrimCharsInSet(const char* aSet,
1719 const nsAString& aValue)
1721 nsAString::const_iterator valueCurrent, valueEnd;
1723 aValue.BeginReading(valueCurrent);
1724 aValue.EndReading(valueEnd);
1726 // Skip characters in the beginning
1727 while (valueCurrent != valueEnd) {
1728 if (!IsCharInSet(aSet, *valueCurrent)) {
1729 break;
1731 ++valueCurrent;
1734 if (valueCurrent != valueEnd) {
1735 for (;;) {
1736 --valueEnd;
1737 if (!IsCharInSet(aSet, *valueEnd)) {
1738 break;
1741 ++valueEnd; // Step beyond the last character we want in the value.
1744 // valueEnd should point to the char after the last to copy
1745 return Substring(valueCurrent, valueEnd);
1749 * This method strips leading and trailing whitespace from a string.
1752 // static
1753 const nsDependentSubstring
1754 nsContentUtils::TrimWhitespace(const nsAString& aStr, PRBool aTrimTrailing)
1756 nsAString::const_iterator start, end;
1758 aStr.BeginReading(start);
1759 aStr.EndReading(end);
1761 // Skip whitespace characters in the beginning
1762 while (start != end && nsCRT::IsAsciiSpace(*start)) {
1763 ++start;
1766 if (aTrimTrailing) {
1767 // Skip whitespace characters in the end.
1768 while (end != start) {
1769 --end;
1771 if (!nsCRT::IsAsciiSpace(*end)) {
1772 // Step back to the last non-whitespace character.
1773 ++end;
1775 break;
1780 // Return a substring for the string w/o leading and/or trailing
1781 // whitespace
1783 return Substring(start, end);
1786 static inline void KeyAppendSep(nsACString& aKey)
1788 if (!aKey.IsEmpty()) {
1789 aKey.Append('>');
1793 static inline void KeyAppendString(const nsAString& aString, nsACString& aKey)
1795 KeyAppendSep(aKey);
1797 // Could escape separator here if collisions happen. > is not a legal char
1798 // for a name or type attribute, so we should be safe avoiding that extra work.
1800 AppendUTF16toUTF8(aString, aKey);
1803 static inline void KeyAppendString(const nsACString& aString, nsACString& aKey)
1805 KeyAppendSep(aKey);
1807 // Could escape separator here if collisions happen. > is not a legal char
1808 // for a name or type attribute, so we should be safe avoiding that extra work.
1810 aKey.Append(aString);
1813 static inline void KeyAppendInt(PRInt32 aInt, nsACString& aKey)
1815 KeyAppendSep(aKey);
1817 aKey.Append(nsPrintfCString("%d", aInt));
1820 static inline void KeyAppendAtom(nsIAtom* aAtom, nsACString& aKey)
1822 NS_PRECONDITION(aAtom, "KeyAppendAtom: aAtom can not be null!\n");
1824 KeyAppendString(nsAtomCString(aAtom), aKey);
1827 static inline PRBool IsAutocompleteOff(nsIDOMElement* aElement)
1829 nsAutoString autocomplete;
1830 aElement->GetAttribute(NS_LITERAL_STRING("autocomplete"), autocomplete);
1831 return autocomplete.LowerCaseEqualsLiteral("off");
1834 /*static*/ nsresult
1835 nsContentUtils::GenerateStateKey(nsIContent* aContent,
1836 nsIDocument* aDocument,
1837 nsIStatefulFrame::SpecialStateID aID,
1838 nsACString& aKey)
1840 aKey.Truncate();
1842 PRUint32 partID = aDocument ? aDocument->GetPartID() : 0;
1844 // SpecialStateID case - e.g. scrollbars around the content window
1845 // The key in this case is a special state id
1846 if (nsIStatefulFrame::eNoID != aID) {
1847 KeyAppendInt(partID, aKey); // first append a partID
1848 KeyAppendInt(aID, aKey);
1849 return NS_OK;
1852 // We must have content if we're not using a special state id
1853 NS_ENSURE_TRUE(aContent, NS_ERROR_FAILURE);
1855 // Don't capture state for anonymous content
1856 if (aContent->IsInAnonymousSubtree()) {
1857 return NS_OK;
1860 nsCOMPtr<nsIDOMElement> element(do_QueryInterface(aContent));
1861 if (element && IsAutocompleteOff(element)) {
1862 return NS_OK;
1865 nsCOMPtr<nsIHTMLDocument> htmlDocument(do_QueryInterface(aContent->GetCurrentDoc()));
1867 KeyAppendInt(partID, aKey); // first append a partID
1868 // Make sure we can't possibly collide with an nsIStatefulFrame
1869 // special id of some sort
1870 KeyAppendInt(nsIStatefulFrame::eNoID, aKey);
1871 PRBool generatedUniqueKey = PR_FALSE;
1873 if (htmlDocument) {
1874 // Flush our content model so it'll be up to date
1875 // If this becomes unnecessary and the following line is removed,
1876 // please also remove the corresponding flush operation from
1877 // nsHtml5TreeBuilderCppSupplement.h. (Look for "See bug 497861." there.)
1878 aContent->GetCurrentDoc()->FlushPendingNotifications(Flush_Content);
1880 nsContentList *htmlForms = htmlDocument->GetForms();
1881 nsContentList *htmlFormControls = htmlDocument->GetFormControls();
1883 NS_ENSURE_TRUE(htmlForms && htmlFormControls, NS_ERROR_OUT_OF_MEMORY);
1885 // If we have a form control and can calculate form information, use that
1886 // as the key - it is more reliable than just recording position in the
1887 // DOM.
1888 // XXXbz Is it, really? We have bugs on this, I think...
1889 // Important to have a unique key, and tag/type/name may not be.
1891 // If the control has a form, the format of the key is:
1892 // f>type>IndOfFormInDoc>IndOfControlInForm>FormName>name
1893 // else:
1894 // d>type>IndOfControlInDoc>name
1896 // XXX We don't need to use index if name is there
1897 // XXXbz We don't? Why not? I don't follow.
1899 nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent));
1900 if (control && htmlFormControls && htmlForms) {
1902 // Append the control type
1903 KeyAppendInt(control->GetType(), aKey);
1905 // If in a form, add form name / index of form / index in form
1906 PRInt32 index = -1;
1907 nsCOMPtr<nsIDOMHTMLFormElement> formElement;
1908 control->GetForm(getter_AddRefs(formElement));
1909 if (formElement) {
1911 if (IsAutocompleteOff(formElement)) {
1912 aKey.Truncate();
1913 return NS_OK;
1916 KeyAppendString(NS_LITERAL_CSTRING("f"), aKey);
1918 // Append the index of the form in the document
1919 nsCOMPtr<nsIContent> formContent(do_QueryInterface(formElement));
1920 index = htmlForms->IndexOf(formContent, PR_FALSE);
1921 if (index <= -1) {
1923 // XXX HACK this uses some state that was dumped into the document
1924 // specifically to fix bug 138892. What we are trying to do is *guess*
1925 // which form this control's state is found in, with the highly likely
1926 // guess that the highest form parsed so far is the one.
1927 // This code should not be on trunk, only branch.
1929 index = htmlDocument->GetNumFormsSynchronous() - 1;
1931 if (index > -1) {
1932 KeyAppendInt(index, aKey);
1934 // Append the index of the control in the form
1935 nsCOMPtr<nsIForm> form(do_QueryInterface(formElement));
1936 index = form->IndexOfControl(control);
1938 if (index > -1) {
1939 KeyAppendInt(index, aKey);
1940 generatedUniqueKey = PR_TRUE;
1944 // Append the form name
1945 nsAutoString formName;
1946 formElement->GetName(formName);
1947 KeyAppendString(formName, aKey);
1949 } else {
1951 KeyAppendString(NS_LITERAL_CSTRING("d"), aKey);
1953 // If not in a form, add index of control in document
1954 // Less desirable than indexing by form info.
1956 // Hash by index of control in doc (we are not in a form)
1957 // These are important as they are unique, and type/name may not be.
1959 // We have to flush sink notifications at this point to make
1960 // sure that htmlFormControls is up to date.
1961 index = htmlFormControls->IndexOf(aContent, PR_TRUE);
1962 if (index > -1) {
1963 KeyAppendInt(index, aKey);
1964 generatedUniqueKey = PR_TRUE;
1968 // Append the control name
1969 nsAutoString name;
1970 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
1971 KeyAppendString(name, aKey);
1975 if (!generatedUniqueKey) {
1976 // Either we didn't have a form control or we aren't in an HTML document so
1977 // we can't figure out form info. First append a character that is not "d"
1978 // or "f" to disambiguate from the case when we were a form control in an
1979 // HTML document.
1980 KeyAppendString(NS_LITERAL_CSTRING("o"), aKey);
1982 // Now start at aContent and append the indices of it and all its ancestors
1983 // in their containers. That should at least pin down its position in the
1984 // DOM...
1985 nsINode* parent = aContent->GetNodeParent();
1986 nsINode* content = aContent;
1987 while (parent) {
1988 KeyAppendInt(parent->IndexOf(content), aKey);
1989 content = parent;
1990 parent = content->GetNodeParent();
1994 return NS_OK;
1997 // static
1998 nsresult
1999 nsContentUtils::NewURIWithDocumentCharset(nsIURI** aResult,
2000 const nsAString& aSpec,
2001 nsIDocument* aDocument,
2002 nsIURI* aBaseURI)
2004 return NS_NewURI(aResult, aSpec,
2005 aDocument ? aDocument->GetDocumentCharacterSet().get() : nsnull,
2006 aBaseURI, sIOService);
2009 // static
2010 PRBool
2011 nsContentUtils::BelongsInForm(nsIDOMHTMLFormElement *aForm,
2012 nsIContent *aContent)
2014 NS_PRECONDITION(aForm, "Must have a form");
2015 NS_PRECONDITION(aContent, "Must have a content node");
2017 nsCOMPtr<nsIContent> form(do_QueryInterface(aForm));
2019 if (!form) {
2020 NS_ERROR("This should not happen, form is not an nsIContent!");
2022 return PR_TRUE;
2025 if (form == aContent) {
2026 // A form does not belong inside itself, so we return false here
2028 return PR_FALSE;
2031 nsIContent* content = aContent->GetParent();
2033 while (content) {
2034 if (content == form) {
2035 // aContent is contained within the form so we return true.
2037 return PR_TRUE;
2040 if (content->Tag() == nsGkAtoms::form &&
2041 content->IsHTML()) {
2042 // The child is contained within a form, but not the right form
2043 // so we ignore it.
2045 return PR_FALSE;
2048 content = content->GetParent();
2051 if (form->GetChildCount() > 0) {
2052 // The form is a container but aContent wasn't inside the form,
2053 // return false
2055 return PR_FALSE;
2058 // The form is a leaf and aContent wasn't inside any other form so
2059 // we check whether the content comes after the form. If it does,
2060 // return true. If it does not, then it couldn't have been inside
2061 // the form in the HTML.
2062 if (PositionIsBefore(form, aContent)) {
2063 // We could be in this form!
2064 // In the future, we may want to get document.forms, look at the
2065 // form after aForm, and if aContent is after that form after
2066 // aForm return false here....
2067 return PR_TRUE;
2070 return PR_FALSE;
2073 // static
2074 nsresult
2075 nsContentUtils::CheckQName(const nsAString& aQualifiedName,
2076 PRBool aNamespaceAware)
2078 nsIParserService *parserService = GetParserService();
2079 NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
2081 const PRUnichar *colon;
2082 return parserService->CheckQName(PromiseFlatString(aQualifiedName),
2083 aNamespaceAware, &colon);
2086 //static
2087 nsresult
2088 nsContentUtils::SplitQName(nsIContent* aNamespaceResolver,
2089 const nsAFlatString& aQName,
2090 PRInt32 *aNamespace, nsIAtom **aLocalName)
2092 nsIParserService* parserService = GetParserService();
2093 NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
2095 const PRUnichar* colon;
2096 nsresult rv = parserService->CheckQName(aQName, PR_TRUE, &colon);
2097 NS_ENSURE_SUCCESS(rv, rv);
2099 if (colon) {
2100 const PRUnichar* end;
2101 aQName.EndReading(end);
2102 nsAutoString nameSpace;
2103 rv = aNamespaceResolver->LookupNamespaceURI(Substring(aQName.get(), colon),
2104 nameSpace);
2105 NS_ENSURE_SUCCESS(rv, rv);
2107 *aNamespace = NameSpaceManager()->GetNameSpaceID(nameSpace);
2108 if (*aNamespace == kNameSpaceID_Unknown)
2109 return NS_ERROR_FAILURE;
2111 *aLocalName = NS_NewAtom(Substring(colon + 1, end));
2113 else {
2114 *aNamespace = kNameSpaceID_None;
2115 *aLocalName = NS_NewAtom(aQName);
2117 NS_ENSURE_TRUE(aLocalName, NS_ERROR_OUT_OF_MEMORY);
2118 return NS_OK;
2121 // static
2122 nsresult
2123 nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI,
2124 const nsAString& aQualifiedName,
2125 nsNodeInfoManager* aNodeInfoManager,
2126 nsINodeInfo** aNodeInfo)
2128 nsIParserService* parserService = GetParserService();
2129 NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
2131 const nsAFlatString& qName = PromiseFlatString(aQualifiedName);
2132 const PRUnichar* colon;
2133 nsresult rv = parserService->CheckQName(qName, PR_TRUE, &colon);
2134 NS_ENSURE_SUCCESS(rv, rv);
2136 PRInt32 nsID;
2137 sNameSpaceManager->RegisterNameSpace(aNamespaceURI, nsID);
2138 if (colon) {
2139 const PRUnichar* end;
2140 qName.EndReading(end);
2142 nsCOMPtr<nsIAtom> prefix = do_GetAtom(Substring(qName.get(), colon));
2144 rv = aNodeInfoManager->GetNodeInfo(Substring(colon + 1, end), prefix,
2145 nsID, aNodeInfo);
2147 else {
2148 rv = aNodeInfoManager->GetNodeInfo(aQualifiedName, nsnull, nsID,
2149 aNodeInfo);
2151 NS_ENSURE_SUCCESS(rv, rv);
2153 return nsContentUtils::IsValidNodeName((*aNodeInfo)->NameAtom(),
2154 (*aNodeInfo)->GetPrefixAtom(),
2155 (*aNodeInfo)->NamespaceID()) ?
2156 NS_OK : NS_ERROR_DOM_NAMESPACE_ERR;
2159 // static
2160 void
2161 nsContentUtils::SplitExpatName(const PRUnichar *aExpatName, nsIAtom **aPrefix,
2162 nsIAtom **aLocalName, PRInt32* aNameSpaceID)
2165 * Expat can send the following:
2166 * localName
2167 * namespaceURI<separator>localName
2168 * namespaceURI<separator>localName<separator>prefix
2170 * and we use 0xFFFF for the <separator>.
2174 const PRUnichar *uriEnd = nsnull;
2175 const PRUnichar *nameEnd = nsnull;
2176 const PRUnichar *pos;
2177 for (pos = aExpatName; *pos; ++pos) {
2178 if (*pos == 0xFFFF) {
2179 if (uriEnd) {
2180 nameEnd = pos;
2182 else {
2183 uriEnd = pos;
2188 const PRUnichar *nameStart;
2189 if (uriEnd) {
2190 if (sNameSpaceManager) {
2191 sNameSpaceManager->RegisterNameSpace(nsDependentSubstring(aExpatName,
2192 uriEnd),
2193 *aNameSpaceID);
2195 else {
2196 *aNameSpaceID = kNameSpaceID_Unknown;
2199 nameStart = (uriEnd + 1);
2200 if (nameEnd) {
2201 const PRUnichar *prefixStart = nameEnd + 1;
2202 *aPrefix = NS_NewAtom(Substring(prefixStart, pos));
2204 else {
2205 nameEnd = pos;
2206 *aPrefix = nsnull;
2209 else {
2210 *aNameSpaceID = kNameSpaceID_None;
2211 nameStart = aExpatName;
2212 nameEnd = pos;
2213 *aPrefix = nsnull;
2215 *aLocalName = NS_NewAtom(Substring(nameStart, nameEnd));
2218 // static
2219 nsPresContext*
2220 nsContentUtils::GetContextForContent(nsIContent* aContent)
2222 nsIDocument* doc = aContent->GetCurrentDoc();
2223 if (doc) {
2224 nsIPresShell *presShell = doc->GetPrimaryShell();
2225 if (presShell) {
2226 return presShell->GetPresContext();
2229 return nsnull;
2232 // static
2233 PRBool
2234 nsContentUtils::CanLoadImage(nsIURI* aURI, nsISupports* aContext,
2235 nsIDocument* aLoadingDocument,
2236 nsIPrincipal* aLoadingPrincipal,
2237 PRInt16* aImageBlockingStatus)
2239 NS_PRECONDITION(aURI, "Must have a URI");
2240 NS_PRECONDITION(aLoadingDocument, "Must have a document");
2241 NS_PRECONDITION(aLoadingPrincipal, "Must have a loading principal");
2243 nsresult rv;
2245 PRUint32 appType = nsIDocShell::APP_TYPE_UNKNOWN;
2248 nsCOMPtr<nsISupports> container = aLoadingDocument->GetContainer();
2249 nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
2250 do_QueryInterface(container);
2252 if (docShellTreeItem) {
2253 nsCOMPtr<nsIDocShellTreeItem> root;
2254 docShellTreeItem->GetRootTreeItem(getter_AddRefs(root));
2256 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root));
2258 if (!docShell || NS_FAILED(docShell->GetAppType(&appType))) {
2259 appType = nsIDocShell::APP_TYPE_UNKNOWN;
2264 if (appType != nsIDocShell::APP_TYPE_EDITOR) {
2265 // Editor apps get special treatment here, editors can load images
2266 // from anywhere. This allows editor to insert images from file://
2267 // into documents that are being edited.
2268 rv = sSecurityManager->
2269 CheckLoadURIWithPrincipal(aLoadingPrincipal, aURI,
2270 nsIScriptSecurityManager::ALLOW_CHROME);
2271 if (NS_FAILED(rv)) {
2272 if (aImageBlockingStatus) {
2273 // Reject the request itself, not all requests to the relevant
2274 // server...
2275 *aImageBlockingStatus = nsIContentPolicy::REJECT_REQUEST;
2277 return PR_FALSE;
2281 PRInt16 decision = nsIContentPolicy::ACCEPT;
2283 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_IMAGE,
2284 aURI,
2285 aLoadingPrincipal,
2286 aContext,
2287 EmptyCString(), //mime guess
2288 nsnull, //extra
2289 &decision,
2290 GetContentPolicy(),
2291 sSecurityManager);
2293 if (aImageBlockingStatus) {
2294 *aImageBlockingStatus =
2295 NS_FAILED(rv) ? nsIContentPolicy::REJECT_REQUEST : decision;
2297 return NS_FAILED(rv) ? PR_FALSE : NS_CP_ACCEPTED(decision);
2300 // static
2301 PRBool
2302 nsContentUtils::IsImageInCache(nsIURI* aURI)
2304 if (!sImgCache) return PR_FALSE;
2306 // If something unexpected happened we return false, otherwise if props
2307 // is set, the image is cached and we return true
2308 nsCOMPtr<nsIProperties> props;
2309 nsresult rv = sImgCache->FindEntryProperties(aURI, getter_AddRefs(props));
2310 return (NS_SUCCEEDED(rv) && props);
2313 // static
2314 nsresult
2315 nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
2316 nsIPrincipal* aLoadingPrincipal, nsIURI* aReferrer,
2317 imgIDecoderObserver* aObserver, PRInt32 aLoadFlags,
2318 imgIRequest** aRequest)
2320 NS_PRECONDITION(aURI, "Must have a URI");
2321 NS_PRECONDITION(aLoadingDocument, "Must have a document");
2322 NS_PRECONDITION(aLoadingPrincipal, "Must have a principal");
2323 NS_PRECONDITION(aRequest, "Null out param");
2325 if (!sImgLoader) {
2326 // nothing we can do here
2327 return NS_OK;
2330 nsCOMPtr<nsILoadGroup> loadGroup = aLoadingDocument->GetDocumentLoadGroup();
2331 NS_ASSERTION(loadGroup, "Could not get loadgroup; onload may fire too early");
2333 nsIURI *documentURI = aLoadingDocument->GetDocumentURI();
2335 // check for a Content Security Policy to pass down to the channel that
2336 // will get created to load the image
2337 nsCOMPtr<nsIChannelPolicy> channelPolicy;
2338 nsCOMPtr<nsIContentSecurityPolicy> csp;
2339 if (aLoadingPrincipal) {
2340 nsresult rv = aLoadingPrincipal->GetCsp(getter_AddRefs(csp));
2341 NS_ENSURE_SUCCESS(rv, rv);
2342 if (csp) {
2343 channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
2344 channelPolicy->SetContentSecurityPolicy(csp);
2345 channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE);
2349 // Make the URI immutable so people won't change it under us
2350 NS_TryToSetImmutable(aURI);
2352 // XXXbz using "documentURI" for the initialDocumentURI is not quite
2353 // right, but the best we can do here...
2354 return sImgLoader->LoadImage(aURI, /* uri to load */
2355 documentURI, /* initialDocumentURI */
2356 aReferrer, /* referrer */
2357 loadGroup, /* loadgroup */
2358 aObserver, /* imgIDecoderObserver */
2359 aLoadingDocument, /* uniquification key */
2360 aLoadFlags, /* load flags */
2361 nsnull, /* cache key */
2362 nsnull, /* existing request*/
2363 channelPolicy, /* CSP info */
2364 aRequest);
2367 // static
2368 already_AddRefed<imgIContainer>
2369 nsContentUtils::GetImageFromContent(nsIImageLoadingContent* aContent,
2370 imgIRequest **aRequest)
2372 if (aRequest) {
2373 *aRequest = nsnull;
2376 NS_ENSURE_TRUE(aContent, nsnull);
2378 nsCOMPtr<imgIRequest> imgRequest;
2379 aContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
2380 getter_AddRefs(imgRequest));
2381 if (!imgRequest) {
2382 return nsnull;
2385 nsCOMPtr<imgIContainer> imgContainer;
2386 imgRequest->GetImage(getter_AddRefs(imgContainer));
2388 if (!imgContainer) {
2389 return nsnull;
2392 if (aRequest) {
2393 imgRequest.swap(*aRequest);
2396 return imgContainer.forget();
2399 //static
2400 already_AddRefed<imgIRequest>
2401 nsContentUtils::GetStaticRequest(imgIRequest* aRequest)
2403 NS_ENSURE_TRUE(aRequest, nsnull);
2404 nsCOMPtr<imgIRequest> retval;
2405 aRequest->GetStaticRequest(getter_AddRefs(retval));
2406 return retval.forget();
2409 // static
2410 PRBool
2411 nsContentUtils::ContentIsDraggable(nsIContent* aContent)
2413 nsCOMPtr<nsIDOMNSHTMLElement> htmlElement = do_QueryInterface(aContent);
2414 if (htmlElement) {
2415 PRBool draggable = PR_FALSE;
2416 htmlElement->GetDraggable(&draggable);
2417 if (draggable)
2418 return PR_TRUE;
2420 if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
2421 nsGkAtoms::_false, eIgnoreCase))
2422 return PR_FALSE;
2425 // special handling for content area image and link dragging
2426 return IsDraggableImage(aContent) || IsDraggableLink(aContent);
2429 // static
2430 PRBool
2431 nsContentUtils::IsDraggableImage(nsIContent* aContent)
2433 NS_PRECONDITION(aContent, "Must have content node to test");
2435 nsCOMPtr<nsIImageLoadingContent> imageContent(do_QueryInterface(aContent));
2436 if (!imageContent) {
2437 return PR_FALSE;
2440 nsCOMPtr<imgIRequest> imgRequest;
2441 imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
2442 getter_AddRefs(imgRequest));
2444 // XXXbz It may be draggable even if the request resulted in an error. Why?
2445 // Not sure; that's what the old nsContentAreaDragDrop/nsFrame code did.
2446 return imgRequest != nsnull;
2449 // static
2450 PRBool
2451 nsContentUtils::IsDraggableLink(nsIContent* aContent) {
2452 nsCOMPtr<nsIURI> absURI;
2453 return aContent->IsLink(getter_AddRefs(absURI));
2456 // static
2457 nsAdoptingCString
2458 nsContentUtils::GetCharPref(const char *aPref)
2460 nsAdoptingCString result;
2462 if (sPrefBranch) {
2463 sPrefBranch->GetCharPref(aPref, getter_Copies(result));
2466 return result;
2469 // static
2470 PRPackedBool
2471 nsContentUtils::GetBoolPref(const char *aPref, PRBool aDefault)
2473 PRBool result;
2475 if (!sPrefBranch ||
2476 NS_FAILED(sPrefBranch->GetBoolPref(aPref, &result))) {
2477 result = aDefault;
2480 return (PRPackedBool)result;
2483 // static
2484 PRInt32
2485 nsContentUtils::GetIntPref(const char *aPref, PRInt32 aDefault)
2487 PRInt32 result;
2489 if (!sPrefBranch ||
2490 NS_FAILED(sPrefBranch->GetIntPref(aPref, &result))) {
2491 result = aDefault;
2494 return result;
2497 // static
2498 nsAdoptingString
2499 nsContentUtils::GetLocalizedStringPref(const char *aPref)
2501 nsAdoptingString result;
2503 if (sPrefBranch) {
2504 nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
2505 sPrefBranch->GetComplexValue(aPref, NS_GET_IID(nsIPrefLocalizedString),
2506 getter_AddRefs(prefLocalString));
2507 if (prefLocalString) {
2508 prefLocalString->GetData(getter_Copies(result));
2512 return result;
2515 // static
2516 nsAdoptingString
2517 nsContentUtils::GetStringPref(const char *aPref)
2519 nsAdoptingString result;
2521 if (sPrefBranch) {
2522 nsCOMPtr<nsISupportsString> theString;
2523 sPrefBranch->GetComplexValue(aPref, NS_GET_IID(nsISupportsString),
2524 getter_AddRefs(theString));
2525 if (theString) {
2526 theString->ToString(getter_Copies(result));
2530 return result;
2533 // RegisterPrefCallback/UnregisterPrefCallback are backward compatiblity for
2534 // c-style observer.
2536 // static
2537 void
2538 nsContentUtils::RegisterPrefCallback(const char *aPref,
2539 PrefChangedFunc aCallback,
2540 void * aClosure)
2542 if (sPrefBranch) {
2543 if (!sPrefCallbackList) {
2544 sPrefCallbackList = new nsCOMArray<nsPrefOldCallback> ();
2545 if (!sPrefCallbackList)
2546 return;
2549 nsPrefOldCallback *callback = new nsPrefOldCallback(aPref, aCallback, aClosure);
2550 if (callback) {
2551 if (NS_SUCCEEDED(sPrefBranch->AddObserver(aPref, callback, PR_FALSE))) {
2552 sPrefCallbackList->AppendObject(callback);
2553 return;
2555 // error to get/add nsIPrefBranch2. Destroy callback information
2556 delete callback;
2561 // static
2562 void
2563 nsContentUtils::UnregisterPrefCallback(const char *aPref,
2564 PrefChangedFunc aCallback,
2565 void * aClosure)
2567 if (sPrefBranch) {
2568 if (!sPrefCallbackList)
2569 return;
2571 int i;
2572 for (i = 0; i < sPrefCallbackList->Count(); i++) {
2573 nsRefPtr<nsPrefOldCallback> callback = (*sPrefCallbackList)[i];
2574 if (callback && callback->IsEqual(aPref, aCallback, aClosure)) {
2575 sPrefBranch->RemoveObserver(aPref, callback);
2576 sPrefCallbackList->RemoveObject(callback);
2577 return;
2583 static int
2584 BoolVarChanged(const char *aPref, void *aClosure)
2586 PrefCacheData* cache = static_cast<PrefCacheData*>(aClosure);
2587 *((PRBool*)cache->cacheLocation) =
2588 nsContentUtils::GetBoolPref(aPref, cache->defaultValueBool);
2590 return 0;
2593 void
2594 nsContentUtils::AddBoolPrefVarCache(const char *aPref,
2595 PRBool* aCache,
2596 PRBool aDefault)
2598 *aCache = GetBoolPref(aPref, aDefault);
2599 PrefCacheData* data = new PrefCacheData;
2600 data->cacheLocation = aCache;
2601 data->defaultValueBool = aDefault;
2602 sPrefCacheData->AppendElement(data);
2603 RegisterPrefCallback(aPref, BoolVarChanged, data);
2606 static int
2607 IntVarChanged(const char *aPref, void *aClosure)
2609 PrefCacheData* cache = static_cast<PrefCacheData*>(aClosure);
2610 *((PRInt32*)cache->cacheLocation) =
2611 nsContentUtils::GetIntPref(aPref, cache->defaultValueInt);
2613 return 0;
2616 void
2617 nsContentUtils::AddIntPrefVarCache(const char *aPref,
2618 PRInt32* aCache,
2619 PRInt32 aDefault)
2621 *aCache = GetIntPref(aPref, aDefault);
2622 PrefCacheData* data = new PrefCacheData;
2623 data->cacheLocation = aCache;
2624 data->defaultValueInt = aDefault;
2625 sPrefCacheData->AppendElement(data);
2626 RegisterPrefCallback(aPref, IntVarChanged, data);
2629 static const char *gEventNames[] = {"event"};
2630 static const char *gSVGEventNames[] = {"evt"};
2631 // for b/w compat, the first name to onerror is still 'event', even though it
2632 // is actually the error message. (pre this code, the other 2 were not avail.)
2633 // XXXmarkh - a quick lxr shows no affected code - should we correct this?
2634 static const char *gOnErrorNames[] = {"event", "source", "lineno"};
2636 // static
2637 void
2638 nsContentUtils::GetEventArgNames(PRInt32 aNameSpaceID,
2639 nsIAtom *aEventName,
2640 PRUint32 *aArgCount,
2641 const char*** aArgArray)
2643 #define SET_EVENT_ARG_NAMES(names) \
2644 *aArgCount = sizeof(names)/sizeof(names[0]); \
2645 *aArgArray = names;
2647 // nsJSEventListener is what does the arg magic for onerror, and it does
2648 // not seem to take the namespace into account. So we let onerror in all
2649 // namespaces get the 3 arg names.
2650 if (aEventName == nsGkAtoms::onerror) {
2651 SET_EVENT_ARG_NAMES(gOnErrorNames);
2652 } else if (aNameSpaceID == kNameSpaceID_SVG) {
2653 SET_EVENT_ARG_NAMES(gSVGEventNames);
2654 } else {
2655 SET_EVENT_ARG_NAMES(gEventNames);
2659 nsCxPusher::nsCxPusher()
2660 : mScriptIsRunning(PR_FALSE),
2661 mPushedSomething(PR_FALSE)
2665 nsCxPusher::~nsCxPusher()
2667 Pop();
2670 static PRBool
2671 IsContextOnStack(nsIJSContextStack *aStack, JSContext *aContext)
2673 JSContext *ctx = nsnull;
2674 aStack->Peek(&ctx);
2675 if (!ctx)
2676 return PR_FALSE;
2677 if (ctx == aContext)
2678 return PR_TRUE;
2680 nsCOMPtr<nsIJSContextStackIterator>
2681 iterator(do_CreateInstance("@mozilla.org/js/xpc/ContextStackIterator;1"));
2682 NS_ENSURE_TRUE(iterator, PR_FALSE);
2684 nsresult rv = iterator->Reset(aStack);
2685 NS_ENSURE_SUCCESS(rv, PR_FALSE);
2687 PRBool done;
2688 while (NS_SUCCEEDED(iterator->Done(&done)) && !done) {
2689 rv = iterator->Prev(&ctx);
2690 NS_ASSERTION(NS_SUCCEEDED(rv), "Broken iterator implementation");
2692 if (!ctx) {
2693 continue;
2696 if (nsJSUtils::GetDynamicScriptContext(ctx) && ctx == aContext)
2697 return PR_TRUE;
2700 return PR_FALSE;
2703 PRBool
2704 nsCxPusher::Push(nsPIDOMEventTarget *aCurrentTarget)
2706 if (mPushedSomething) {
2707 NS_ERROR("Whaaa! No double pushing with nsCxPusher::Push()!");
2709 return PR_FALSE;
2712 NS_ENSURE_TRUE(aCurrentTarget, PR_FALSE);
2713 nsresult rv;
2714 nsIScriptContext* scx =
2715 aCurrentTarget->GetContextForEventHandlers(&rv);
2716 NS_ENSURE_SUCCESS(rv, PR_FALSE);
2718 if (!scx) {
2719 // The target may have a special JS context for event handlers.
2720 JSContext* cx = aCurrentTarget->GetJSContextForEventHandlers();
2721 if (cx) {
2722 DoPush(cx);
2725 // Nothing to do here, I guess. Have to return true so that event firing
2726 // will still work correctly even if there is no associated JSContext
2727 return PR_TRUE;
2730 JSContext* cx = nsnull;
2732 if (scx) {
2733 cx = static_cast<JSContext*>(scx->GetNativeContext());
2734 // Bad, no JSContext from script context!
2735 NS_ENSURE_TRUE(cx, PR_FALSE);
2738 // If there's no native context in the script context it must be
2739 // in the process or being torn down. We don't want to notify the
2740 // script context about scripts having been evaluated in such a
2741 // case, calling with a null cx is fine in that case.
2742 return Push(cx);
2745 PRBool
2746 nsCxPusher::RePush(nsPIDOMEventTarget *aCurrentTarget)
2748 if (!mPushedSomething) {
2749 return Push(aCurrentTarget);
2752 if (aCurrentTarget) {
2753 nsresult rv;
2754 nsIScriptContext* scx =
2755 aCurrentTarget->GetContextForEventHandlers(&rv);
2756 if (NS_FAILED(rv)) {
2757 Pop();
2758 return PR_FALSE;
2761 // If we have the same script context and native context is still
2762 // alive, no need to Pop/Push.
2763 if (scx && scx == mScx &&
2764 scx->GetNativeContext()) {
2765 return PR_TRUE;
2769 Pop();
2770 return Push(aCurrentTarget);
2773 PRBool
2774 nsCxPusher::Push(JSContext *cx, PRBool aRequiresScriptContext)
2776 if (mPushedSomething) {
2777 NS_ERROR("Whaaa! No double pushing with nsCxPusher::Push()!");
2779 return PR_FALSE;
2782 if (!cx) {
2783 return PR_FALSE;
2786 // Hold a strong ref to the nsIScriptContext, just in case
2787 // XXXbz do we really need to? If we don't get one of these in Pop(), is
2788 // that really a problem? Or do we need to do this to effectively root |cx|?
2789 mScx = GetScriptContextFromJSContext(cx);
2790 if (!mScx && aRequiresScriptContext) {
2791 // Should probably return PR_FALSE. See bug 416916.
2792 return PR_TRUE;
2795 return DoPush(cx);
2798 PRBool
2799 nsCxPusher::DoPush(JSContext* cx)
2801 nsIThreadJSContextStack* stack = nsContentUtils::ThreadJSContextStack();
2802 if (!stack) {
2803 return PR_TRUE;
2806 if (cx && IsContextOnStack(stack, cx)) {
2807 // If the context is on the stack, that means that a script
2808 // is running at the moment in the context.
2809 mScriptIsRunning = PR_TRUE;
2812 if (NS_FAILED(stack->Push(cx))) {
2813 mScriptIsRunning = PR_FALSE;
2814 mScx = nsnull;
2815 return PR_FALSE;
2818 mPushedSomething = PR_TRUE;
2819 #ifdef DEBUG
2820 mPushedContext = cx;
2821 #endif
2822 return PR_TRUE;
2825 PRBool
2826 nsCxPusher::PushNull()
2828 return DoPush(nsnull);
2831 void
2832 nsCxPusher::Pop()
2834 nsIThreadJSContextStack* stack = nsContentUtils::ThreadJSContextStack();
2835 if (!mPushedSomething || !stack) {
2836 mScx = nsnull;
2837 mPushedSomething = PR_FALSE;
2839 NS_ASSERTION(!mScriptIsRunning, "Huh, this can't be happening, "
2840 "mScriptIsRunning can't be set here!");
2842 return;
2845 JSContext *unused;
2846 stack->Pop(&unused);
2848 NS_ASSERTION(unused == mPushedContext, "Unexpected context popped");
2850 if (!mScriptIsRunning && mScx) {
2851 // No JS is running in the context, but executing the event handler might have
2852 // caused some JS to run. Tell the script context that it's done.
2854 mScx->ScriptEvaluated(PR_TRUE);
2857 mScx = nsnull;
2858 mScriptIsRunning = PR_FALSE;
2859 mPushedSomething = PR_FALSE;
2862 static const char gPropertiesFiles[nsContentUtils::PropertiesFile_COUNT][56] = {
2863 // Must line up with the enum values in |PropertiesFile| enum.
2864 "chrome://global/locale/css.properties",
2865 "chrome://global/locale/xbl.properties",
2866 "chrome://global/locale/xul.properties",
2867 "chrome://global/locale/layout_errors.properties",
2868 "chrome://global/locale/layout/HtmlForm.properties",
2869 "chrome://global/locale/printing.properties",
2870 "chrome://global/locale/dom/dom.properties",
2871 #ifdef MOZ_SVG
2872 "chrome://global/locale/svg/svg.properties",
2873 #endif
2874 "chrome://branding/locale/brand.properties",
2875 "chrome://global/locale/commonDialogs.properties"
2878 /* static */ nsresult
2879 nsContentUtils::EnsureStringBundle(PropertiesFile aFile)
2881 if (!sStringBundles[aFile]) {
2882 if (!sStringBundleService) {
2883 nsresult rv =
2884 CallGetService(NS_STRINGBUNDLE_CONTRACTID, &sStringBundleService);
2885 NS_ENSURE_SUCCESS(rv, rv);
2887 nsIStringBundle *bundle;
2888 nsresult rv =
2889 sStringBundleService->CreateBundle(gPropertiesFiles[aFile], &bundle);
2890 NS_ENSURE_SUCCESS(rv, rv);
2891 sStringBundles[aFile] = bundle; // transfer ownership
2893 return NS_OK;
2896 /* static */
2897 nsresult nsContentUtils::GetLocalizedString(PropertiesFile aFile,
2898 const char* aKey,
2899 nsXPIDLString& aResult)
2901 nsresult rv = EnsureStringBundle(aFile);
2902 NS_ENSURE_SUCCESS(rv, rv);
2903 nsIStringBundle *bundle = sStringBundles[aFile];
2905 return bundle->GetStringFromName(NS_ConvertASCIItoUTF16(aKey).get(),
2906 getter_Copies(aResult));
2909 /* static */
2910 nsresult nsContentUtils::FormatLocalizedString(PropertiesFile aFile,
2911 const char* aKey,
2912 const PRUnichar **aParams,
2913 PRUint32 aParamsLength,
2914 nsXPIDLString& aResult)
2916 nsresult rv = EnsureStringBundle(aFile);
2917 NS_ENSURE_SUCCESS(rv, rv);
2918 nsIStringBundle *bundle = sStringBundles[aFile];
2920 return bundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aKey).get(),
2921 aParams, aParamsLength,
2922 getter_Copies(aResult));
2925 /* static */ nsresult
2926 nsContentUtils::ReportToConsole(PropertiesFile aFile,
2927 const char *aMessageName,
2928 const PRUnichar **aParams,
2929 PRUint32 aParamsLength,
2930 nsIURI* aURI,
2931 const nsAFlatString& aSourceLine,
2932 PRUint32 aLineNumber,
2933 PRUint32 aColumnNumber,
2934 PRUint32 aErrorFlags,
2935 const char *aCategory)
2937 NS_ASSERTION((aParams && aParamsLength) || (!aParams && !aParamsLength),
2938 "Supply either both parameters and their number or no"
2939 "parameters and 0.");
2941 nsresult rv;
2942 if (!sConsoleService) { // only need to bother null-checking here
2943 rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService);
2944 NS_ENSURE_SUCCESS(rv, rv);
2947 nsXPIDLString errorText;
2948 if (aParams) {
2949 rv = FormatLocalizedString(aFile, aMessageName, aParams, aParamsLength,
2950 errorText);
2952 else {
2953 rv = GetLocalizedString(aFile, aMessageName, errorText);
2955 NS_ENSURE_SUCCESS(rv, rv);
2957 nsCAutoString spec;
2958 if (aURI)
2959 aURI->GetSpec(spec);
2961 nsCOMPtr<nsIScriptError> errorObject =
2962 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
2963 NS_ENSURE_SUCCESS(rv, rv);
2964 rv = errorObject->Init(errorText.get(),
2965 NS_ConvertUTF8toUTF16(spec).get(), // file name
2966 aSourceLine.get(),
2967 aLineNumber, aColumnNumber,
2968 aErrorFlags, aCategory);
2969 NS_ENSURE_SUCCESS(rv, rv);
2971 return sConsoleService->LogMessage(errorObject);
2974 PRBool
2975 nsContentUtils::IsChromeDoc(nsIDocument *aDocument)
2977 if (!aDocument) {
2978 return PR_FALSE;
2981 nsCOMPtr<nsIPrincipal> systemPrincipal;
2982 sSecurityManager->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
2984 return aDocument->NodePrincipal() == systemPrincipal;
2987 PRBool
2988 nsContentUtils::IsChildOfSameType(nsIDocument* aDoc)
2990 nsCOMPtr<nsISupports> container = aDoc->GetContainer();
2991 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(container));
2992 nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
2993 if (docShellAsItem) {
2994 docShellAsItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
2996 return sameTypeParent != nsnull;
2999 PRBool
3000 nsContentUtils::GetWrapperSafeScriptFilename(nsIDocument *aDocument,
3001 nsIURI *aURI,
3002 nsACString& aScriptURI)
3004 PRBool scriptFileNameModified = PR_FALSE;
3005 aURI->GetSpec(aScriptURI);
3007 if (IsChromeDoc(aDocument)) {
3008 nsCOMPtr<nsIChromeRegistry> chromeReg =
3009 mozilla::services::GetChromeRegistryService();
3011 if (!chromeReg) {
3012 // If we're running w/o a chrome registry we won't modify any
3013 // script file names.
3015 return scriptFileNameModified;
3018 PRBool docWrappersEnabled =
3019 chromeReg->WrappersEnabled(aDocument->GetDocumentURI());
3021 PRBool uriWrappersEnabled = chromeReg->WrappersEnabled(aURI);
3023 nsIURI *docURI = aDocument->GetDocumentURI();
3025 if (docURI && docWrappersEnabled && !uriWrappersEnabled) {
3026 // aURI is a script from a URL that doesn't get wrapper
3027 // automation. aDocument is a chrome document that does get
3028 // wrapper automation. Prepend the chrome document's URI
3029 // followed by the string " -> " to the URI of the script we're
3030 // loading here so that script in that URI gets the same wrapper
3031 // automation that the chrome document expects.
3032 nsCAutoString spec;
3033 docURI->GetSpec(spec);
3034 spec.AppendASCII(" -> ");
3035 spec.Append(aScriptURI);
3037 aScriptURI = spec;
3039 scriptFileNameModified = PR_TRUE;
3043 return scriptFileNameModified;
3046 // static
3047 PRBool
3048 nsContentUtils::IsInChromeDocshell(nsIDocument *aDocument)
3050 if (!aDocument) {
3051 return PR_FALSE;
3054 if (aDocument->GetDisplayDocument()) {
3055 return IsInChromeDocshell(aDocument->GetDisplayDocument());
3058 nsCOMPtr<nsISupports> docContainer = aDocument->GetContainer();
3059 nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryInterface(docContainer));
3060 PRInt32 itemType = nsIDocShellTreeItem::typeContent;
3061 if (docShell) {
3062 docShell->GetItemType(&itemType);
3065 return itemType == nsIDocShellTreeItem::typeChrome;
3068 // static
3069 nsIContentPolicy*
3070 nsContentUtils::GetContentPolicy()
3072 if (!sTriedToGetContentPolicy) {
3073 CallGetService(NS_CONTENTPOLICY_CONTRACTID, &sContentPolicyService);
3074 // It's OK to not have a content policy service
3075 sTriedToGetContentPolicy = PR_TRUE;
3078 return sContentPolicyService;
3081 // static
3082 nsresult
3083 nsAutoGCRoot::AddJSGCRoot(void* aPtr, const char* aName)
3085 if (!sJSScriptRuntime) {
3086 nsresult rv = CallGetService("@mozilla.org/js/xpc/RuntimeService;1",
3087 &sJSRuntimeService);
3088 NS_ENSURE_TRUE(sJSRuntimeService, rv);
3090 sJSRuntimeService->GetRuntime(&sJSScriptRuntime);
3091 if (!sJSScriptRuntime) {
3092 NS_RELEASE(sJSRuntimeService);
3093 NS_WARNING("Unable to get JS runtime from JS runtime service");
3094 return NS_ERROR_FAILURE;
3098 PRBool ok;
3099 ok = ::JS_AddNamedRootRT(sJSScriptRuntime, aPtr, aName);
3100 if (!ok) {
3101 NS_WARNING("JS_AddNamedRootRT failed");
3102 return NS_ERROR_OUT_OF_MEMORY;
3105 return NS_OK;
3108 /* static */
3109 nsresult
3110 nsAutoGCRoot::RemoveJSGCRoot(void* aPtr)
3112 if (!sJSScriptRuntime) {
3113 NS_NOTREACHED("Trying to remove a JS GC root when none were added");
3114 return NS_ERROR_UNEXPECTED;
3117 ::JS_RemoveRootRT(sJSScriptRuntime, aPtr);
3119 return NS_OK;
3122 // static
3123 PRBool
3124 nsContentUtils::IsEventAttributeName(nsIAtom* aName, PRInt32 aType)
3126 const PRUnichar* name = aName->GetUTF16String();
3127 if (name[0] != 'o' || name[1] != 'n')
3128 return PR_FALSE;
3130 EventNameMapping mapping;
3131 return (sEventTable->Get(aName, &mapping) && mapping.mType & aType);
3134 // static
3135 PRUint32
3136 nsContentUtils::GetEventId(nsIAtom* aName)
3138 EventNameMapping mapping;
3139 if (sEventTable->Get(aName, &mapping))
3140 return mapping.mId;
3142 return NS_USER_DEFINED_EVENT;
3145 static
3146 nsresult GetEventAndTarget(nsIDocument* aDoc, nsISupports* aTarget,
3147 const nsAString& aEventName,
3148 PRBool aCanBubble, PRBool aCancelable,
3149 nsIDOMEvent** aEvent,
3150 nsIDOMEventTarget** aTargetOut)
3152 nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(aDoc));
3153 nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(aTarget));
3154 NS_ENSURE_TRUE(docEvent && target, NS_ERROR_INVALID_ARG);
3156 nsCOMPtr<nsIDOMEvent> event;
3157 nsresult rv =
3158 docEvent->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
3159 NS_ENSURE_SUCCESS(rv, rv);
3161 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
3162 NS_ENSURE_TRUE(privateEvent, NS_ERROR_FAILURE);
3164 rv = event->InitEvent(aEventName, aCanBubble, aCancelable);
3165 NS_ENSURE_SUCCESS(rv, rv);
3167 rv = privateEvent->SetTrusted(PR_TRUE);
3168 NS_ENSURE_SUCCESS(rv, rv);
3170 rv = privateEvent->SetTarget(target);
3171 NS_ENSURE_SUCCESS(rv, rv);
3173 event.forget(aEvent);
3174 target.forget(aTargetOut);
3175 return NS_OK;
3178 // static
3179 nsresult
3180 nsContentUtils::DispatchTrustedEvent(nsIDocument* aDoc, nsISupports* aTarget,
3181 const nsAString& aEventName,
3182 PRBool aCanBubble, PRBool aCancelable,
3183 PRBool *aDefaultAction)
3185 nsCOMPtr<nsIDOMEvent> event;
3186 nsCOMPtr<nsIDOMEventTarget> target;
3187 nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble,
3188 aCancelable, getter_AddRefs(event),
3189 getter_AddRefs(target));
3190 NS_ENSURE_SUCCESS(rv, rv);
3192 PRBool dummy;
3193 return target->DispatchEvent(event, aDefaultAction ? aDefaultAction : &dummy);
3196 nsresult
3197 nsContentUtils::DispatchChromeEvent(nsIDocument *aDoc,
3198 nsISupports *aTarget,
3199 const nsAString& aEventName,
3200 PRBool aCanBubble, PRBool aCancelable,
3201 PRBool *aDefaultAction)
3204 nsCOMPtr<nsIDOMEvent> event;
3205 nsCOMPtr<nsIDOMEventTarget> target;
3206 nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble,
3207 aCancelable, getter_AddRefs(event),
3208 getter_AddRefs(target));
3209 NS_ENSURE_SUCCESS(rv, rv);
3211 NS_ASSERTION(aDoc, "GetEventAndTarget lied?");
3212 if (!aDoc->GetWindow())
3213 return NS_ERROR_INVALID_ARG;
3215 nsPIDOMEventTarget* piTarget = aDoc->GetWindow()->GetChromeEventHandler();
3216 if (!piTarget)
3217 return NS_ERROR_INVALID_ARG;
3219 nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(piTarget);
3220 if (flo) {
3221 nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
3222 if (fl) {
3223 nsPIDOMEventTarget* t = fl->GetTabChildGlobalAsEventTarget();
3224 piTarget = t ? t : piTarget;
3228 nsEventStatus status = nsEventStatus_eIgnore;
3229 rv = piTarget->DispatchDOMEvent(nsnull, event, nsnull, &status);
3230 if (aDefaultAction) {
3231 *aDefaultAction = (status != nsEventStatus_eConsumeNoDefault);
3233 return rv;
3236 /* static */
3237 Element*
3238 nsContentUtils::MatchElementId(nsIContent *aContent, nsIAtom* aId)
3240 for (nsIContent* cur = aContent;
3241 cur;
3242 cur = cur->GetNextNode(aContent)) {
3243 if (aId == cur->GetID()) {
3244 return cur->AsElement();
3248 return nsnull;
3251 /* static */
3252 Element *
3253 nsContentUtils::MatchElementId(nsIContent *aContent, const nsAString& aId)
3255 NS_PRECONDITION(!aId.IsEmpty(), "Will match random elements");
3257 // ID attrs are generally stored as atoms, so just atomize this up front
3258 nsCOMPtr<nsIAtom> id(do_GetAtom(aId));
3259 if (!id) {
3260 // OOM, so just bail
3261 return nsnull;
3264 return MatchElementId(aContent, id);
3267 // Convert the string from the given charset to Unicode.
3268 /* static */
3269 nsresult
3270 nsContentUtils::ConvertStringFromCharset(const nsACString& aCharset,
3271 const nsACString& aInput,
3272 nsAString& aOutput)
3274 if (aCharset.IsEmpty()) {
3275 // Treat the string as UTF8
3276 CopyUTF8toUTF16(aInput, aOutput);
3277 return NS_OK;
3280 nsresult rv;
3281 nsCOMPtr<nsICharsetConverterManager> ccm =
3282 do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
3283 if (NS_FAILED(rv))
3284 return rv;
3286 nsCOMPtr<nsIUnicodeDecoder> decoder;
3287 rv = ccm->GetUnicodeDecoder(PromiseFlatCString(aCharset).get(),
3288 getter_AddRefs(decoder));
3289 if (NS_FAILED(rv))
3290 return rv;
3292 nsPromiseFlatCString flatInput(aInput);
3293 PRInt32 srcLen = flatInput.Length();
3294 PRInt32 dstLen;
3295 rv = decoder->GetMaxLength(flatInput.get(), srcLen, &dstLen);
3296 if (NS_FAILED(rv))
3297 return rv;
3299 PRUnichar *ustr = (PRUnichar *)nsMemory::Alloc((dstLen + 1) *
3300 sizeof(PRUnichar));
3301 if (!ustr)
3302 return NS_ERROR_OUT_OF_MEMORY;
3304 rv = decoder->Convert(flatInput.get(), &srcLen, ustr, &dstLen);
3305 if (NS_SUCCEEDED(rv)) {
3306 ustr[dstLen] = 0;
3307 aOutput.Assign(ustr, dstLen);
3310 nsMemory::Free(ustr);
3311 return rv;
3314 /* static */
3315 PRBool
3316 nsContentUtils::CheckForBOM(const unsigned char* aBuffer, PRUint32 aLength,
3317 nsACString& aCharset, PRBool *bigEndian)
3319 PRBool found = PR_TRUE;
3320 aCharset.Truncate();
3321 if (aLength >= 3 &&
3322 aBuffer[0] == 0xEF &&
3323 aBuffer[1] == 0xBB &&
3324 aBuffer[2] == 0xBF) {
3325 aCharset = "UTF-8";
3327 else if (aLength >= 4 &&
3328 aBuffer[0] == 0x00 &&
3329 aBuffer[1] == 0x00 &&
3330 aBuffer[2] == 0xFE &&
3331 aBuffer[3] == 0xFF) {
3332 aCharset = "UTF-32";
3333 if (bigEndian)
3334 *bigEndian = PR_TRUE;
3336 else if (aLength >= 4 &&
3337 aBuffer[0] == 0xFF &&
3338 aBuffer[1] == 0xFE &&
3339 aBuffer[2] == 0x00 &&
3340 aBuffer[3] == 0x00) {
3341 aCharset = "UTF-32";
3342 if (bigEndian)
3343 *bigEndian = PR_FALSE;
3345 else if (aLength >= 2 &&
3346 aBuffer[0] == 0xFE && aBuffer[1] == 0xFF) {
3347 aCharset = "UTF-16";
3348 if (bigEndian)
3349 *bigEndian = PR_TRUE;
3351 else if (aLength >= 2 &&
3352 aBuffer[0] == 0xFF && aBuffer[1] == 0xFE) {
3353 aCharset = "UTF-16";
3354 if (bigEndian)
3355 *bigEndian = PR_FALSE;
3356 } else {
3357 found = PR_FALSE;
3360 return found;
3363 /* static */
3364 nsIContent*
3365 nsContentUtils::GetReferencedElement(nsIURI* aURI, nsIContent *aFromContent)
3367 nsReferencedElement ref;
3368 ref.Reset(aFromContent, aURI);
3369 return ref.get();
3372 /* static */
3373 void
3374 nsContentUtils::RegisterShutdownObserver(nsIObserver* aObserver)
3376 nsCOMPtr<nsIObserverService> observerService =
3377 mozilla::services::GetObserverService();
3378 if (observerService) {
3379 observerService->AddObserver(aObserver,
3380 NS_XPCOM_SHUTDOWN_OBSERVER_ID,
3381 PR_FALSE);
3385 /* static */
3386 void
3387 nsContentUtils::UnregisterShutdownObserver(nsIObserver* aObserver)
3389 nsCOMPtr<nsIObserverService> observerService =
3390 mozilla::services::GetObserverService();
3391 if (observerService) {
3392 observerService->RemoveObserver(aObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
3396 /* static */
3397 PRBool
3398 nsContentUtils::HasNonEmptyAttr(nsIContent* aContent, PRInt32 aNameSpaceID,
3399 nsIAtom* aName)
3401 static nsIContent::AttrValuesArray strings[] = {&nsGkAtoms::_empty, nsnull};
3402 return aContent->FindAttrValueIn(aNameSpaceID, aName, strings, eCaseMatters)
3403 == nsIContent::ATTR_VALUE_NO_MATCH;
3406 /* static */
3407 PRBool
3408 nsContentUtils::HasMutationListeners(nsINode* aNode,
3409 PRUint32 aType,
3410 nsINode* aTargetForSubtreeModified)
3412 nsIDocument* doc = aNode->GetOwnerDoc();
3413 if (!doc) {
3414 return PR_FALSE;
3417 NS_ASSERTION((aNode->IsNodeOfType(nsINode::eCONTENT) &&
3418 static_cast<nsIContent*>(aNode)->
3419 IsInNativeAnonymousSubtree()) ||
3420 sScriptBlockerCount == sRemovableScriptBlockerCount,
3421 "Want to fire mutation events, but it's not safe");
3423 // global object will be null for documents that don't have windows.
3424 nsPIDOMWindow* window = doc->GetInnerWindow();
3425 // This relies on nsEventListenerManager::AddEventListener, which sets
3426 // all mutation bits when there is a listener for DOMSubtreeModified event.
3427 if (window && !window->HasMutationListeners(aType)) {
3428 return PR_FALSE;
3431 if (aNode->IsNodeOfType(nsINode::eCONTENT) &&
3432 static_cast<nsIContent*>(aNode)->IsInNativeAnonymousSubtree()) {
3433 return PR_FALSE;
3436 doc->MayDispatchMutationEvent(aTargetForSubtreeModified);
3438 // If we have a window, we can check it for mutation listeners now.
3439 if (aNode->IsInDoc()) {
3440 nsCOMPtr<nsPIDOMEventTarget> piTarget(do_QueryInterface(window));
3441 if (piTarget) {
3442 nsIEventListenerManager* manager = piTarget->GetListenerManager(PR_FALSE);
3443 if (manager) {
3444 PRBool hasListeners = PR_FALSE;
3445 manager->HasMutationListeners(&hasListeners);
3446 if (hasListeners) {
3447 return PR_TRUE;
3453 // If we have a window, we know a mutation listener is registered, but it
3454 // might not be in our chain. If we don't have a window, we might have a
3455 // mutation listener. Check quickly to see.
3456 while (aNode) {
3457 nsIEventListenerManager* manager = aNode->GetListenerManager(PR_FALSE);
3458 if (manager) {
3459 PRBool hasListeners = PR_FALSE;
3460 manager->HasMutationListeners(&hasListeners);
3461 if (hasListeners) {
3462 return PR_TRUE;
3466 if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
3467 nsIContent* content = static_cast<nsIContent*>(aNode);
3468 nsIContent* insertionParent =
3469 doc->BindingManager()->GetInsertionParent(content);
3470 if (insertionParent) {
3471 aNode = insertionParent;
3472 continue;
3475 aNode = aNode->GetNodeParent();
3478 return PR_FALSE;
3481 /* static */
3482 void
3483 nsContentUtils::TraverseListenerManager(nsINode *aNode,
3484 nsCycleCollectionTraversalCallback &cb)
3486 if (!sEventListenerManagersHash.ops) {
3487 // We're already shut down, just return.
3488 return;
3491 EventListenerManagerMapEntry *entry =
3492 static_cast<EventListenerManagerMapEntry *>
3493 (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
3494 PL_DHASH_LOOKUP));
3495 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
3496 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via hash] mListenerManager");
3497 cb.NoteXPCOMChild(entry->mListenerManager);
3501 nsIEventListenerManager*
3502 nsContentUtils::GetListenerManager(nsINode *aNode,
3503 PRBool aCreateIfNotFound)
3505 if (!aCreateIfNotFound && !aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) {
3506 return nsnull;
3509 if (!sEventListenerManagersHash.ops) {
3510 // We're already shut down, don't bother creating an event listener
3511 // manager.
3513 return nsnull;
3516 if (!aCreateIfNotFound) {
3517 EventListenerManagerMapEntry *entry =
3518 static_cast<EventListenerManagerMapEntry *>
3519 (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
3520 PL_DHASH_LOOKUP));
3521 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
3522 return entry->mListenerManager;
3524 return nsnull;
3527 EventListenerManagerMapEntry *entry =
3528 static_cast<EventListenerManagerMapEntry *>
3529 (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
3530 PL_DHASH_ADD));
3532 if (!entry) {
3533 return nsnull;
3536 if (!entry->mListenerManager) {
3537 nsresult rv =
3538 NS_NewEventListenerManager(getter_AddRefs(entry->mListenerManager));
3540 if (NS_FAILED(rv)) {
3541 PL_DHashTableRawRemove(&sEventListenerManagersHash, entry);
3543 return nsnull;
3546 entry->mListenerManager->SetListenerTarget(aNode);
3548 aNode->SetFlags(NODE_HAS_LISTENERMANAGER);
3551 return entry->mListenerManager;
3554 /* static */
3555 void
3556 nsContentUtils::RemoveListenerManager(nsINode *aNode)
3558 if (sEventListenerManagersHash.ops) {
3559 EventListenerManagerMapEntry *entry =
3560 static_cast<EventListenerManagerMapEntry *>
3561 (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
3562 PL_DHASH_LOOKUP));
3563 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
3564 nsCOMPtr<nsIEventListenerManager> listenerManager;
3565 listenerManager.swap(entry->mListenerManager);
3566 // Remove the entry and *then* do operations that could cause further
3567 // modification of sEventListenerManagersHash. See bug 334177.
3568 PL_DHashTableRawRemove(&sEventListenerManagersHash, entry);
3569 if (listenerManager) {
3570 listenerManager->Disconnect();
3576 /* static */
3577 PRBool
3578 nsContentUtils::IsValidNodeName(nsIAtom *aLocalName, nsIAtom *aPrefix,
3579 PRInt32 aNamespaceID)
3581 if (aNamespaceID == kNameSpaceID_Unknown) {
3582 return PR_FALSE;
3585 if (!aPrefix) {
3586 // If the prefix is null, then either the QName must be xmlns or the
3587 // namespace must not be XMLNS.
3588 return (aLocalName == nsGkAtoms::xmlns) ==
3589 (aNamespaceID == kNameSpaceID_XMLNS);
3592 // If the prefix is non-null then the namespace must not be null.
3593 if (aNamespaceID == kNameSpaceID_None) {
3594 return PR_FALSE;
3597 // If the namespace is the XMLNS namespace then the prefix must be xmlns,
3598 // but the localname must not be xmlns.
3599 if (aNamespaceID == kNameSpaceID_XMLNS) {
3600 return aPrefix == nsGkAtoms::xmlns && aLocalName != nsGkAtoms::xmlns;
3603 // If the namespace is not the XMLNS namespace then the prefix must not be
3604 // xmlns.
3605 // If the namespace is the XML namespace then the prefix can be anything.
3606 // If the namespace is not the XML namespace then the prefix must not be xml.
3607 return aPrefix != nsGkAtoms::xmlns &&
3608 (aNamespaceID == kNameSpaceID_XML || aPrefix != nsGkAtoms::xml);
3611 /* static */
3612 nsresult
3613 nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
3614 const nsAString& aFragment,
3615 PRBool aWillOwnFragment,
3616 nsIDOMDocumentFragment** aReturn)
3618 *aReturn = nsnull;
3619 NS_ENSURE_ARG(aContextNode);
3621 nsresult rv;
3623 // If we don't have a document here, we can't get the right security context
3624 // for compiling event handlers... so just bail out.
3625 nsCOMPtr<nsIDocument> document = aContextNode->GetOwnerDoc();
3626 NS_ENSURE_TRUE(document, NS_ERROR_NOT_AVAILABLE);
3628 PRBool isHTML = document->IsHTML();
3629 #ifdef DEBUG
3630 nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(document);
3631 NS_ASSERTION(!isHTML || htmlDoc, "Should have HTMLDocument here!");
3632 #endif
3634 if (isHTML && nsHtml5Module::sEnabled) {
3635 // See if the document has a cached fragment parser. nsHTMLDocument is the
3636 // only one that should really have one at the moment.
3637 nsCOMPtr<nsIParser> parser = document->GetFragmentParser();
3638 if (parser) {
3639 // Get the parser ready to use.
3640 parser->Reset();
3642 else {
3643 // Create a new parser for this operation.
3644 parser = nsHtml5Module::NewHtml5Parser();
3645 if (!parser) {
3646 return NS_ERROR_OUT_OF_MEMORY;
3649 nsCOMPtr<nsIDOMDocumentFragment> frag;
3650 rv = NS_NewDocumentFragment(getter_AddRefs(frag), document->NodeInfoManager());
3651 NS_ENSURE_SUCCESS(rv, rv);
3653 nsCOMPtr<nsIContent> contextAsContent = do_QueryInterface(aContextNode);
3654 if (contextAsContent && !contextAsContent->IsElement()) {
3655 contextAsContent = contextAsContent->GetParent();
3656 if (contextAsContent && !contextAsContent->IsElement()) {
3657 // can this even happen?
3658 contextAsContent = nsnull;
3662 if (contextAsContent) {
3663 parser->ParseFragment(aFragment,
3664 frag,
3665 contextAsContent->Tag(),
3666 contextAsContent->GetNameSpaceID(),
3667 (document->GetCompatibilityMode() == eCompatibility_NavQuirks));
3668 } else {
3669 parser->ParseFragment(aFragment,
3670 frag,
3671 nsGkAtoms::body,
3672 kNameSpaceID_XHTML,
3673 (document->GetCompatibilityMode() == eCompatibility_NavQuirks));
3676 frag.swap(*aReturn);
3677 document->SetFragmentParser(parser);
3678 return NS_OK;
3681 nsAutoTArray<nsString, 32> tagStack;
3682 nsAutoString uriStr, nameStr;
3683 nsCOMPtr<nsIContent> content = do_QueryInterface(aContextNode);
3684 // just in case we have a text node
3685 if (content && !content->IsElement())
3686 content = content->GetParent();
3688 while (content && content->IsElement()) {
3689 nsString& tagName = *tagStack.AppendElement();
3690 NS_ENSURE_TRUE(&tagName, NS_ERROR_OUT_OF_MEMORY);
3692 content->NodeInfo()->GetQualifiedName(tagName);
3694 // see if we need to add xmlns declarations
3695 PRUint32 count = content->GetAttrCount();
3696 PRBool setDefaultNamespace = PR_FALSE;
3697 if (count > 0) {
3698 PRUint32 index;
3700 for (index = 0; index < count; index++) {
3701 const nsAttrName* name = content->GetAttrNameAt(index);
3702 if (name->NamespaceEquals(kNameSpaceID_XMLNS)) {
3703 content->GetAttr(kNameSpaceID_XMLNS, name->LocalName(), uriStr);
3705 // really want something like nsXMLContentSerializer::SerializeAttr
3706 tagName.Append(NS_LITERAL_STRING(" xmlns")); // space important
3707 if (name->GetPrefix()) {
3708 tagName.Append(PRUnichar(':'));
3709 name->LocalName()->ToString(nameStr);
3710 tagName.Append(nameStr);
3711 } else {
3712 setDefaultNamespace = PR_TRUE;
3714 tagName.Append(NS_LITERAL_STRING("=\"") + uriStr +
3715 NS_LITERAL_STRING("\""));
3720 if (!setDefaultNamespace) {
3721 nsINodeInfo* info = content->NodeInfo();
3722 if (!info->GetPrefixAtom() &&
3723 info->NamespaceID() != kNameSpaceID_None) {
3724 // We have no namespace prefix, but have a namespace ID. Push
3725 // default namespace attr in, so that our kids will be in our
3726 // namespace.
3727 info->GetNamespaceURI(uriStr);
3728 tagName.Append(NS_LITERAL_STRING(" xmlns=\"") + uriStr +
3729 NS_LITERAL_STRING("\""));
3733 content = content->GetParent();
3736 nsCAutoString contentType;
3737 nsAutoString buf;
3738 document->GetContentType(buf);
3739 LossyCopyUTF16toASCII(buf, contentType);
3741 // See if the document has a cached fragment parser. nsHTMLDocument is the
3742 // only one that should really have one at the moment.
3743 nsCOMPtr<nsIParser> parser = document->GetFragmentParser();
3744 if (parser) {
3745 // Get the parser ready to use.
3746 parser->Reset();
3748 else {
3749 // Create a new parser for this operation.
3750 parser = do_CreateInstance(kCParserCID, &rv);
3751 NS_ENSURE_SUCCESS(rv, rv);
3754 // See if the parser already has a content sink that we can reuse.
3755 nsCOMPtr<nsIFragmentContentSink> sink;
3756 nsCOMPtr<nsIContentSink> contentsink = parser->GetContentSink();
3757 if (contentsink) {
3758 // Make sure it's the correct type.
3759 if (isHTML) {
3760 nsCOMPtr<nsIHTMLContentSink> htmlsink = do_QueryInterface(contentsink);
3761 sink = do_QueryInterface(htmlsink);
3763 else {
3764 nsCOMPtr<nsIXMLContentSink> xmlsink = do_QueryInterface(contentsink);
3765 sink = do_QueryInterface(xmlsink);
3769 if (!sink) {
3770 // Either there was no cached content sink or it was the wrong type. Make a
3771 // new one.
3772 if (isHTML) {
3773 rv = NS_NewHTMLFragmentContentSink(getter_AddRefs(sink));
3774 } else {
3775 rv = NS_NewXMLFragmentContentSink(getter_AddRefs(sink));
3777 NS_ENSURE_SUCCESS(rv, rv);
3779 contentsink = do_QueryInterface(sink);
3780 NS_ASSERTION(contentsink, "Sink doesn't QI to nsIContentSink!");
3782 parser->SetContentSink(contentsink);
3785 sink->SetTargetDocument(document);
3787 nsDTDMode mode = eDTDMode_autodetect;
3788 switch (document->GetCompatibilityMode()) {
3789 case eCompatibility_NavQuirks:
3790 mode = eDTDMode_quirks;
3791 break;
3792 case eCompatibility_AlmostStandards:
3793 mode = eDTDMode_almost_standards;
3794 break;
3795 case eCompatibility_FullStandards:
3796 mode = eDTDMode_full_standards;
3797 break;
3798 default:
3799 NS_NOTREACHED("unknown mode");
3800 break;
3803 rv = parser->ParseFragment(aFragment, nsnull, tagStack,
3804 !isHTML, contentType, mode);
3805 if (NS_SUCCEEDED(rv)) {
3806 rv = sink->GetFragment(aWillOwnFragment, aReturn);
3809 document->SetFragmentParser(parser);
3811 return rv;
3814 /* static */
3815 nsresult
3816 nsContentUtils::CreateDocument(const nsAString& aNamespaceURI,
3817 const nsAString& aQualifiedName,
3818 nsIDOMDocumentType* aDoctype,
3819 nsIURI* aDocumentURI, nsIURI* aBaseURI,
3820 nsIPrincipal* aPrincipal,
3821 nsIScriptGlobalObject* aEventObject,
3822 nsIDOMDocument** aResult)
3824 nsresult rv = NS_NewDOMDocument(aResult, aNamespaceURI, aQualifiedName,
3825 aDoctype, aDocumentURI, aBaseURI, aPrincipal,
3826 PR_TRUE);
3827 NS_ENSURE_SUCCESS(rv, rv);
3829 nsCOMPtr<nsIDocument> document = do_QueryInterface(*aResult);
3830 document->SetScriptHandlingObject(aEventObject);
3832 // created documents are immediately "complete" (ready to use)
3833 document->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
3834 return NS_OK;
3837 /* static */
3838 nsresult
3839 nsContentUtils::SetNodeTextContent(nsIContent* aContent,
3840 const nsAString& aValue,
3841 PRBool aTryReuse)
3843 // Might as well stick a batch around this since we're performing several
3844 // mutations.
3845 mozAutoDocUpdate updateBatch(aContent->GetCurrentDoc(),
3846 UPDATE_CONTENT_MODEL, PR_TRUE);
3848 PRUint32 childCount = aContent->GetChildCount();
3850 if (aTryReuse && !aValue.IsEmpty()) {
3851 PRUint32 removeIndex = 0;
3853 // i is unsigned, so i >= is always true
3854 for (PRUint32 i = 0; i < childCount; ++i) {
3855 nsIContent* child = aContent->GetChildAt(removeIndex);
3856 if (removeIndex == 0 && child && child->IsNodeOfType(nsINode::eTEXT)) {
3857 nsresult rv = child->SetText(aValue, PR_TRUE);
3858 NS_ENSURE_SUCCESS(rv, rv);
3860 removeIndex = 1;
3862 else {
3863 aContent->RemoveChildAt(removeIndex, PR_TRUE);
3867 if (removeIndex == 1) {
3868 return NS_OK;
3871 else {
3872 // i is unsigned, so i >= is always true
3873 for (PRUint32 i = childCount; i-- != 0; ) {
3874 aContent->RemoveChildAt(i, PR_TRUE);
3878 if (aValue.IsEmpty()) {
3879 return NS_OK;
3882 nsCOMPtr<nsIContent> textContent;
3883 nsresult rv = NS_NewTextNode(getter_AddRefs(textContent),
3884 aContent->NodeInfo()->NodeInfoManager());
3885 NS_ENSURE_SUCCESS(rv, rv);
3887 textContent->SetText(aValue, PR_TRUE);
3889 return aContent->AppendChildTo(textContent, PR_TRUE);
3892 static void AppendNodeTextContentsRecurse(nsINode* aNode, nsAString& aResult)
3894 nsIContent* child;
3895 PRUint32 i;
3896 for (i = 0; (child = aNode->GetChildAt(i)); ++i) {
3897 if (child->IsElement()) {
3898 AppendNodeTextContentsRecurse(child, aResult);
3900 else if (child->IsNodeOfType(nsINode::eTEXT)) {
3901 child->AppendTextTo(aResult);
3906 /* static */
3907 void
3908 nsContentUtils::AppendNodeTextContent(nsINode* aNode, PRBool aDeep,
3909 nsAString& aResult)
3911 if (aNode->IsNodeOfType(nsINode::eTEXT)) {
3912 static_cast<nsIContent*>(aNode)->AppendTextTo(aResult);
3914 else if (aDeep) {
3915 AppendNodeTextContentsRecurse(aNode, aResult);
3917 else {
3918 nsIContent* child;
3919 PRUint32 i;
3920 for (i = 0; (child = aNode->GetChildAt(i)); ++i) {
3921 if (child->IsNodeOfType(nsINode::eTEXT)) {
3922 child->AppendTextTo(aResult);
3928 PRBool
3929 nsContentUtils::HasNonEmptyTextContent(nsINode* aNode)
3931 nsIContent* child;
3932 PRUint32 i;
3933 for (i = 0; (child = aNode->GetChildAt(i)); ++i) {
3934 if (child->IsNodeOfType(nsINode::eTEXT) &&
3935 child->TextLength() > 0) {
3936 return PR_TRUE;
3940 return PR_FALSE;
3943 /* static */
3944 PRBool
3945 nsContentUtils::IsInSameAnonymousTree(nsINode* aNode,
3946 nsIContent* aContent)
3948 NS_PRECONDITION(aNode,
3949 "Must have a node to work with");
3950 NS_PRECONDITION(aContent,
3951 "Must have a content to work with");
3953 if (!aNode->IsNodeOfType(nsINode::eCONTENT)) {
3955 * The root isn't an nsIContent, so it's a document or attribute. The only
3956 * nodes in the same anonymous subtree as it will have a null
3957 * bindingParent.
3959 * XXXbz strictly speaking, that's not true for attribute nodes.
3961 return aContent->GetBindingParent() == nsnull;
3964 return static_cast<nsIContent*>(aNode)->GetBindingParent() ==
3965 aContent->GetBindingParent();
3969 class AnonymousContentDestroyer : public nsRunnable {
3970 public:
3971 AnonymousContentDestroyer(nsCOMPtr<nsIContent>* aContent) {
3972 mContent.swap(*aContent);
3973 mParent = mContent->GetParent();
3974 mDoc = mContent->GetOwnerDoc();
3976 NS_IMETHOD Run() {
3977 mContent->UnbindFromTree();
3978 return NS_OK;
3980 private:
3981 nsCOMPtr<nsIContent> mContent;
3982 // Hold strong refs to the parent content and document so that they
3983 // don't die unexpectedly
3984 nsCOMPtr<nsIDocument> mDoc;
3985 nsCOMPtr<nsIContent> mParent;
3988 /* static */
3989 void
3990 nsContentUtils::DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent)
3992 if (*aContent) {
3993 AddScriptRunner(new AnonymousContentDestroyer(aContent));
3997 /* static */
3998 nsIDOMScriptObjectFactory*
3999 nsContentUtils::GetDOMScriptObjectFactory()
4001 if (!sDOMScriptObjectFactory) {
4002 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
4003 NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
4005 CallGetService(kDOMScriptObjectFactoryCID, &sDOMScriptObjectFactory);
4008 return sDOMScriptObjectFactory;
4011 /* static */
4012 nsresult
4013 nsContentUtils::HoldScriptObject(PRUint32 aLangID, void *aObject)
4015 NS_ASSERTION(aObject, "unexpected null object");
4016 NS_ASSERTION(aLangID != nsIProgrammingLanguage::JAVASCRIPT,
4017 "Should use HoldJSObjects.");
4018 nsresult rv;
4020 PRUint32 langIndex = NS_STID_INDEX(aLangID);
4021 nsIScriptRuntime *runtime = sScriptRuntimes[langIndex];
4022 if (!runtime) {
4023 nsIDOMScriptObjectFactory *factory = GetDOMScriptObjectFactory();
4024 NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
4026 rv = factory->GetScriptRuntimeByID(aLangID, &runtime);
4027 NS_ENSURE_SUCCESS(rv, rv);
4029 // This makes sScriptRuntimes hold a strong ref.
4030 sScriptRuntimes[langIndex] = runtime;
4033 rv = runtime->HoldScriptObject(aObject);
4034 NS_ENSURE_SUCCESS(rv, rv);
4036 ++sScriptRootCount[langIndex];
4037 NS_LOG_ADDREF(sScriptRuntimes[langIndex], sScriptRootCount[langIndex],
4038 "HoldScriptObject", sizeof(void*));
4040 return NS_OK;
4043 /* static */
4044 void
4045 nsContentUtils::DropScriptObject(PRUint32 aLangID, void *aObject,
4046 void *aClosure)
4048 NS_ASSERTION(aObject, "unexpected null object");
4049 NS_ASSERTION(aLangID != nsIProgrammingLanguage::JAVASCRIPT,
4050 "Should use DropJSObjects.");
4051 PRUint32 langIndex = NS_STID_INDEX(aLangID);
4052 NS_LOG_RELEASE(sScriptRuntimes[langIndex], sScriptRootCount[langIndex] - 1,
4053 "HoldScriptObject");
4054 sScriptRuntimes[langIndex]->DropScriptObject(aObject);
4055 if (--sScriptRootCount[langIndex] == 0) {
4056 NS_RELEASE(sScriptRuntimes[langIndex]);
4060 /* static */
4061 nsresult
4062 nsContentUtils::HoldJSObjects(void* aScriptObjectHolder,
4063 nsScriptObjectTracer* aTracer)
4065 NS_ENSURE_TRUE(sXPConnect, NS_ERROR_UNEXPECTED);
4067 nsresult rv = sXPConnect->AddJSHolder(aScriptObjectHolder, aTracer);
4068 NS_ENSURE_SUCCESS(rv, rv);
4070 if (sJSGCThingRootCount++ == 0) {
4071 nsLayoutStatics::AddRef();
4073 NS_LOG_ADDREF(sXPConnect, sJSGCThingRootCount, "HoldJSObjects",
4074 sizeof(void*));
4076 return NS_OK;
4079 /* static */
4080 nsresult
4081 nsContentUtils::DropJSObjects(void* aScriptObjectHolder)
4083 NS_LOG_RELEASE(sXPConnect, sJSGCThingRootCount - 1, "HoldJSObjects");
4084 nsresult rv = sXPConnect->RemoveJSHolder(aScriptObjectHolder);
4085 if (--sJSGCThingRootCount == 0) {
4086 nsLayoutStatics::Release();
4088 return rv;
4091 /* static */
4092 PRUint32
4093 nsContentUtils::GetWidgetStatusFromIMEStatus(PRUint32 aState)
4095 switch (aState & nsIContent::IME_STATUS_MASK_ENABLED) {
4096 case nsIContent::IME_STATUS_DISABLE:
4097 return nsIWidget::IME_STATUS_DISABLED;
4098 case nsIContent::IME_STATUS_ENABLE:
4099 return nsIWidget::IME_STATUS_ENABLED;
4100 case nsIContent::IME_STATUS_PASSWORD:
4101 return nsIWidget::IME_STATUS_PASSWORD;
4102 case nsIContent::IME_STATUS_PLUGIN:
4103 return nsIWidget::IME_STATUS_PLUGIN;
4104 default:
4105 NS_ERROR("The given state doesn't have valid enable state");
4106 return nsIWidget::IME_STATUS_ENABLED;
4110 /* static */
4111 void
4112 nsContentUtils::NotifyInstalledMenuKeyboardListener(PRBool aInstalling)
4114 nsIMEStateManager::OnInstalledMenuKeyboardListener(aInstalling);
4117 static PRBool SchemeIs(nsIURI* aURI, const char* aScheme)
4119 nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
4120 NS_ENSURE_TRUE(baseURI, PR_FALSE);
4122 PRBool isScheme = PR_FALSE;
4123 return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme;
4126 /* static */
4127 nsresult
4128 nsContentUtils::CheckSecurityBeforeLoad(nsIURI* aURIToLoad,
4129 nsIPrincipal* aLoadingPrincipal,
4130 PRUint32 aCheckLoadFlags,
4131 PRBool aAllowData,
4132 PRUint32 aContentPolicyType,
4133 nsISupports* aContext,
4134 const nsACString& aMimeGuess,
4135 nsISupports* aExtra)
4137 NS_PRECONDITION(aLoadingPrincipal, "Must have a loading principal here");
4139 PRBool isSystemPrin = PR_FALSE;
4140 if (NS_SUCCEEDED(sSecurityManager->IsSystemPrincipal(aLoadingPrincipal,
4141 &isSystemPrin)) &&
4142 isSystemPrin) {
4143 return NS_OK;
4146 // XXXbz do we want to fast-path skin stylesheets loading XBL here somehow?
4147 // CheckLoadURIWithPrincipal
4148 nsresult rv = sSecurityManager->
4149 CheckLoadURIWithPrincipal(aLoadingPrincipal, aURIToLoad, aCheckLoadFlags);
4150 NS_ENSURE_SUCCESS(rv, rv);
4152 // Content Policy
4153 PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
4154 rv = NS_CheckContentLoadPolicy(aContentPolicyType,
4155 aURIToLoad,
4156 aLoadingPrincipal,
4157 aContext,
4158 aMimeGuess,
4159 aExtra,
4160 &shouldLoad,
4161 GetContentPolicy(),
4162 sSecurityManager);
4163 NS_ENSURE_SUCCESS(rv, rv);
4164 if (NS_CP_REJECTED(shouldLoad)) {
4165 return NS_ERROR_CONTENT_BLOCKED;
4168 // Same Origin
4169 if ((aAllowData && SchemeIs(aURIToLoad, "data")) ||
4170 ((aCheckLoadFlags & nsIScriptSecurityManager::ALLOW_CHROME) &&
4171 SchemeIs(aURIToLoad, "chrome"))) {
4172 return NS_OK;
4175 return aLoadingPrincipal->CheckMayLoad(aURIToLoad, PR_TRUE);
4178 PRBool
4179 nsContentUtils::IsSystemPrincipal(nsIPrincipal* aPrincipal)
4181 PRBool isSystem;
4182 nsresult rv = sSecurityManager->IsSystemPrincipal(aPrincipal, &isSystem);
4183 return NS_SUCCEEDED(rv) && isSystem;
4186 /* static */
4187 void
4188 nsContentUtils::TriggerLink(nsIContent *aContent, nsPresContext *aPresContext,
4189 nsIURI *aLinkURI, const nsString &aTargetSpec,
4190 PRBool aClick, PRBool aIsUserTriggered)
4192 NS_ASSERTION(aPresContext, "Need a nsPresContext");
4193 NS_PRECONDITION(aLinkURI, "No link URI");
4195 if (aContent->IsEditable()) {
4196 return;
4199 nsILinkHandler *handler = aPresContext->GetLinkHandler();
4200 if (!handler) {
4201 return;
4204 if (!aClick) {
4205 handler->OnOverLink(aContent, aLinkURI, aTargetSpec.get());
4207 return;
4210 // Check that this page is allowed to load this URI.
4211 nsresult proceed = NS_OK;
4213 if (sSecurityManager) {
4214 PRUint32 flag =
4215 aIsUserTriggered ?
4216 (PRUint32)nsIScriptSecurityManager::STANDARD :
4217 (PRUint32)nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT;
4218 proceed =
4219 sSecurityManager->CheckLoadURIWithPrincipal(aContent->NodePrincipal(),
4220 aLinkURI, flag);
4223 // Only pass off the click event if the script security manager says it's ok.
4224 if (NS_SUCCEEDED(proceed)) {
4225 handler->OnLinkClick(aContent, aLinkURI, aTargetSpec.get());
4229 /* static */
4230 nsIWidget*
4231 nsContentUtils::GetTopLevelWidget(nsIWidget* aWidget)
4233 if (!aWidget)
4234 return nsnull;
4236 return aWidget->GetTopLevelWidget();
4239 /* static */
4240 const nsDependentString
4241 nsContentUtils::GetLocalizedEllipsis()
4243 static PRUnichar sBuf[4] = { 0, 0, 0, 0 };
4244 if (!sBuf[0]) {
4245 nsAutoString tmp(GetLocalizedStringPref("intl.ellipsis"));
4246 PRUint32 len = NS_MIN(PRUint32(tmp.Length()),
4247 PRUint32(NS_ARRAY_LENGTH(sBuf) - 1));
4248 CopyUnicodeTo(tmp, 0, sBuf, len);
4249 if (!sBuf[0])
4250 sBuf[0] = PRUnichar(0x2026);
4252 return nsDependentString(sBuf);
4255 //static
4256 nsEvent*
4257 nsContentUtils::GetNativeEvent(nsIDOMEvent* aDOMEvent)
4259 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aDOMEvent));
4260 if (!privateEvent)
4261 return nsnull;
4262 return privateEvent->GetInternalNSEvent();
4265 //static
4266 PRBool
4267 nsContentUtils::DOMEventToNativeKeyEvent(nsIDOMKeyEvent* aKeyEvent,
4268 nsNativeKeyEvent* aNativeEvent,
4269 PRBool aGetCharCode)
4271 nsCOMPtr<nsIDOMNSUIEvent> uievent = do_QueryInterface(aKeyEvent);
4272 PRBool defaultPrevented;
4273 uievent->GetPreventDefault(&defaultPrevented);
4274 if (defaultPrevented)
4275 return PR_FALSE;
4277 nsCOMPtr<nsIDOMNSEvent> nsevent = do_QueryInterface(aKeyEvent);
4278 PRBool trusted = PR_FALSE;
4279 nsevent->GetIsTrusted(&trusted);
4280 if (!trusted)
4281 return PR_FALSE;
4283 if (aGetCharCode) {
4284 aKeyEvent->GetCharCode(&aNativeEvent->charCode);
4285 } else {
4286 aNativeEvent->charCode = 0;
4288 aKeyEvent->GetKeyCode(&aNativeEvent->keyCode);
4289 aKeyEvent->GetAltKey(&aNativeEvent->altKey);
4290 aKeyEvent->GetCtrlKey(&aNativeEvent->ctrlKey);
4291 aKeyEvent->GetShiftKey(&aNativeEvent->shiftKey);
4292 aKeyEvent->GetMetaKey(&aNativeEvent->metaKey);
4294 aNativeEvent->nativeEvent = GetNativeEvent(aKeyEvent);
4296 return PR_TRUE;
4299 static PRBool
4300 HasASCIIDigit(const nsTArray<nsShortcutCandidate>& aCandidates)
4302 for (PRUint32 i = 0; i < aCandidates.Length(); ++i) {
4303 PRUint32 ch = aCandidates[i].mCharCode;
4304 if (ch >= '0' && ch <= '9')
4305 return PR_TRUE;
4307 return PR_FALSE;
4310 static PRBool
4311 CharsCaseInsensitiveEqual(PRUint32 aChar1, PRUint32 aChar2)
4313 return aChar1 == aChar2 ||
4314 (IS_IN_BMP(aChar1) && IS_IN_BMP(aChar2) &&
4315 ToLowerCase(PRUnichar(aChar1)) == ToLowerCase(PRUnichar(aChar2)));
4318 static PRBool
4319 IsCaseChangeableChar(PRUint32 aChar)
4321 return IS_IN_BMP(aChar) &&
4322 ToLowerCase(PRUnichar(aChar)) != ToUpperCase(PRUnichar(aChar));
4325 /* static */
4326 void
4327 nsContentUtils::GetAccelKeyCandidates(nsIDOMKeyEvent* aDOMKeyEvent,
4328 nsTArray<nsShortcutCandidate>& aCandidates)
4330 NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
4332 nsAutoString eventType;
4333 aDOMKeyEvent->GetType(eventType);
4334 // Don't process if aDOMKeyEvent is not a keypress event.
4335 if (!eventType.EqualsLiteral("keypress"))
4336 return;
4338 nsKeyEvent* nativeKeyEvent =
4339 static_cast<nsKeyEvent*>(GetNativeEvent(aDOMKeyEvent));
4340 if (nativeKeyEvent) {
4341 NS_ASSERTION(nativeKeyEvent->eventStructType == NS_KEY_EVENT,
4342 "wrong type of native event");
4343 // nsShortcutCandidate::mCharCode is a candidate charCode.
4344 // nsShoftcutCandidate::mIgnoreShift means the mCharCode should be tried to
4345 // execute a command with/without shift key state. If this is TRUE, the
4346 // shifted key state should be ignored. Otherwise, don't ignore the state.
4347 // the priority of the charCodes are (shift key is not pressed):
4348 // 0: charCode/PR_FALSE,
4349 // 1: unshiftedCharCodes[0]/PR_FALSE, 2: unshiftedCharCodes[1]/PR_FALSE...
4350 // the priority of the charCodes are (shift key is pressed):
4351 // 0: charCode/PR_FALSE,
4352 // 1: shiftedCharCodes[0]/PR_FALSE, 2: shiftedCharCodes[0]/PR_TRUE,
4353 // 3: shiftedCharCodes[1]/PR_FALSE, 4: shiftedCharCodes[1]/PR_TRUE...
4354 if (nativeKeyEvent->charCode) {
4355 nsShortcutCandidate key(nativeKeyEvent->charCode, PR_FALSE);
4356 aCandidates.AppendElement(key);
4359 PRUint32 len = nativeKeyEvent->alternativeCharCodes.Length();
4360 if (!nativeKeyEvent->isShift) {
4361 for (PRUint32 i = 0; i < len; ++i) {
4362 PRUint32 ch =
4363 nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode;
4364 if (!ch || ch == nativeKeyEvent->charCode)
4365 continue;
4367 nsShortcutCandidate key(ch, PR_FALSE);
4368 aCandidates.AppendElement(key);
4370 // If unshiftedCharCodes doesn't have numeric but shiftedCharCode has it,
4371 // this keyboard layout is AZERTY or similar layout, probably.
4372 // In this case, Accel+[0-9] should be accessible without shift key.
4373 // However, the priority should be lowest.
4374 if (!HasASCIIDigit(aCandidates)) {
4375 for (PRUint32 i = 0; i < len; ++i) {
4376 PRUint32 ch =
4377 nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode;
4378 if (ch >= '0' && ch <= '9') {
4379 nsShortcutCandidate key(ch, PR_FALSE);
4380 aCandidates.AppendElement(key);
4381 break;
4385 } else {
4386 for (PRUint32 i = 0; i < len; ++i) {
4387 PRUint32 ch = nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode;
4388 if (!ch)
4389 continue;
4391 if (ch != nativeKeyEvent->charCode) {
4392 nsShortcutCandidate key(ch, PR_FALSE);
4393 aCandidates.AppendElement(key);
4396 // If the char is an alphabet, the shift key state should not be
4397 // ignored. E.g., Ctrl+Shift+C should not execute Ctrl+C.
4399 // And checking the charCode is same as unshiftedCharCode too.
4400 // E.g., for Ctrl+Shift+(Plus of Numpad) should not run Ctrl+Plus.
4401 PRUint32 unshiftCh =
4402 nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode;
4403 if (CharsCaseInsensitiveEqual(ch, unshiftCh))
4404 continue;
4406 // On the Hebrew keyboard layout on Windows, the unshifted char is a
4407 // localized character but the shifted char is a Latin alphabet,
4408 // then, we should not execute without the shift state. See bug 433192.
4409 if (IsCaseChangeableChar(ch))
4410 continue;
4412 // Setting the alternative charCode candidates for retry without shift
4413 // key state only when the shift key is pressed.
4414 nsShortcutCandidate key(ch, PR_TRUE);
4415 aCandidates.AppendElement(key);
4418 } else {
4419 PRUint32 charCode;
4420 aDOMKeyEvent->GetCharCode(&charCode);
4421 if (charCode) {
4422 nsShortcutCandidate key(charCode, PR_FALSE);
4423 aCandidates.AppendElement(key);
4428 /* static */
4429 void
4430 nsContentUtils::GetAccessKeyCandidates(nsKeyEvent* aNativeKeyEvent,
4431 nsTArray<PRUint32>& aCandidates)
4433 NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
4435 // return the lower cased charCode candidates for access keys.
4436 // the priority of the charCodes are:
4437 // 0: charCode, 1: unshiftedCharCodes[0], 2: shiftedCharCodes[0]
4438 // 3: unshiftedCharCodes[1], 4: shiftedCharCodes[1],...
4439 if (aNativeKeyEvent->charCode) {
4440 PRUint32 ch = aNativeKeyEvent->charCode;
4441 if (IS_IN_BMP(ch))
4442 ch = ToLowerCase(PRUnichar(ch));
4443 aCandidates.AppendElement(ch);
4445 for (PRUint32 i = 0;
4446 i < aNativeKeyEvent->alternativeCharCodes.Length(); ++i) {
4447 PRUint32 ch[2] =
4448 { aNativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode,
4449 aNativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode };
4450 for (PRUint32 j = 0; j < 2; ++j) {
4451 if (!ch[j])
4452 continue;
4453 if (IS_IN_BMP(ch[j]))
4454 ch[j] = ToLowerCase(PRUnichar(ch[j]));
4455 // Don't append the charCode that was already appended.
4456 if (aCandidates.IndexOf(ch[j]) == aCandidates.NoIndex)
4457 aCandidates.AppendElement(ch[j]);
4460 return;
4463 /* static */
4464 void
4465 nsContentUtils::AddScriptBlocker()
4467 if (!sScriptBlockerCount) {
4468 NS_ASSERTION(sRunnersCountAtFirstBlocker == 0,
4469 "Should not already have a count");
4470 sRunnersCountAtFirstBlocker = sBlockedScriptRunners->Count();
4472 ++sScriptBlockerCount;
4475 /* static */
4476 void
4477 nsContentUtils::AddScriptBlockerAndPreventAddingRunners()
4479 AddScriptBlocker();
4480 if (sScriptBlockerCountWhereRunnersPrevented == 0) {
4481 sScriptBlockerCountWhereRunnersPrevented = sScriptBlockerCount;
4485 /* static */
4486 void
4487 nsContentUtils::RemoveScriptBlocker()
4489 NS_ASSERTION(sScriptBlockerCount != 0, "Negative script blockers");
4490 --sScriptBlockerCount;
4491 if (sScriptBlockerCount < sScriptBlockerCountWhereRunnersPrevented) {
4492 sScriptBlockerCountWhereRunnersPrevented = 0;
4494 if (sScriptBlockerCount) {
4495 return;
4498 PRUint32 firstBlocker = sRunnersCountAtFirstBlocker;
4499 PRUint32 lastBlocker = (PRUint32)sBlockedScriptRunners->Count();
4500 sRunnersCountAtFirstBlocker = 0;
4501 NS_ASSERTION(firstBlocker <= lastBlocker,
4502 "bad sRunnersCountAtFirstBlocker");
4504 while (firstBlocker < lastBlocker) {
4505 nsCOMPtr<nsIRunnable> runnable = (*sBlockedScriptRunners)[firstBlocker];
4506 sBlockedScriptRunners->RemoveObjectAt(firstBlocker);
4507 --lastBlocker;
4509 runnable->Run();
4510 NS_ASSERTION(lastBlocker == (PRUint32)sBlockedScriptRunners->Count() &&
4511 sRunnersCountAtFirstBlocker == 0,
4512 "Bad count");
4513 NS_ASSERTION(!sScriptBlockerCount, "This is really bad");
4517 /* static */
4518 PRBool
4519 nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable)
4521 if (!aRunnable) {
4522 return PR_FALSE;
4525 if (sScriptBlockerCount) {
4526 if (sScriptBlockerCountWhereRunnersPrevented > 0) {
4527 NS_ERROR("Adding a script runner when that is prevented!");
4528 return PR_FALSE;
4530 return sBlockedScriptRunners->AppendObject(aRunnable);
4533 nsCOMPtr<nsIRunnable> run = aRunnable;
4534 run->Run();
4536 return PR_TRUE;
4540 * Helper function for nsContentUtils::ProcessViewportInfo.
4542 * Handles a single key=value pair. If it corresponds to a valid viewport
4543 * attribute, add it to the document header data. No validation is done on the
4544 * value itself (this is done at display time).
4546 static void ProcessViewportToken(nsIDocument *aDocument,
4547 const nsAString &token) {
4549 /* Iterators. */
4550 nsAString::const_iterator tip, tail, end;
4551 token.BeginReading(tip);
4552 tail = tip;
4553 token.EndReading(end);
4555 /* Move tip to the '='. */
4556 while ((tip != end) && (*tip != '='))
4557 ++tip;
4559 /* If we didn't find an '=', punt. */
4560 if (tip == end)
4561 return;
4563 /* Extract the key and value. */
4564 const nsAString &key = Substring(tail, tip);
4565 const nsAString &value = Substring(++tip, end);
4567 /* Check for known keys. If we find a match, insert the appropriate
4568 * information into the document header. */
4569 nsCOMPtr<nsIAtom> key_atom = do_GetAtom(key);
4570 if (key_atom == nsGkAtoms::height)
4571 aDocument->SetHeaderData(nsGkAtoms::viewport_height, value);
4572 else if (key_atom == nsGkAtoms::width)
4573 aDocument->SetHeaderData(nsGkAtoms::viewport_width, value);
4574 else if (key_atom == nsGkAtoms::initial_scale)
4575 aDocument->SetHeaderData(nsGkAtoms::viewport_initial_scale, value);
4576 else if (key_atom == nsGkAtoms::minimum_scale)
4577 aDocument->SetHeaderData(nsGkAtoms::viewport_minimum_scale, value);
4578 else if (key_atom == nsGkAtoms::maximum_scale)
4579 aDocument->SetHeaderData(nsGkAtoms::viewport_maximum_scale, value);
4580 else if (key_atom == nsGkAtoms::user_scalable)
4581 aDocument->SetHeaderData(nsGkAtoms::viewport_user_scalable, value);
4584 #define IS_SEPARATOR(c) ((c == ' ') || (c == ',') || (c == ';'))
4585 /* static */
4586 nsresult
4587 nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument,
4588 const nsAString &viewportInfo) {
4590 /* We never fail. */
4591 nsresult rv = NS_OK;
4593 /* Iterators. */
4594 nsAString::const_iterator tip, tail, end;
4595 viewportInfo.BeginReading(tip);
4596 tail = tip;
4597 viewportInfo.EndReading(end);
4599 /* Read the tip to the first non-separator character. */
4600 while ((tip != end) && IS_SEPARATOR(*tip))
4601 ++tip;
4603 /* Read through and find tokens separated by separators. */
4604 while (tip != end) {
4606 /* Synchronize tip and tail. */
4607 tail = tip;
4609 /* Advance tip past non-separator characters. */
4610 while ((tip != end) && !IS_SEPARATOR(*tip))
4611 ++tip;
4613 /* Our token consists of the characters between tail and tip. */
4614 ProcessViewportToken(aDocument, Substring(tail, tip));
4616 /* Skip separators. */
4617 while ((tip != end) && IS_SEPARATOR(*tip))
4618 ++tip;
4621 return rv;
4625 #undef IS_SEPARATOR
4627 /* static */
4628 void
4629 nsContentUtils::HidePopupsInDocument(nsIDocument* aDocument)
4631 #ifdef MOZ_XUL
4632 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
4633 if (pm && aDocument) {
4634 nsCOMPtr<nsISupports> container = aDocument->GetContainer();
4635 nsCOMPtr<nsIDocShellTreeItem> docShellToHide = do_QueryInterface(container);
4636 if (docShellToHide)
4637 pm->HidePopupsInDocShell(docShellToHide);
4639 #endif
4642 /* static */
4643 already_AddRefed<nsIDragSession>
4644 nsContentUtils::GetDragSession()
4646 nsIDragSession* dragSession = nsnull;
4647 nsCOMPtr<nsIDragService> dragService =
4648 do_GetService("@mozilla.org/widget/dragservice;1");
4649 if (dragService)
4650 dragService->GetCurrentSession(&dragSession);
4651 return dragSession;
4654 /* static */
4655 nsresult
4656 nsContentUtils::SetDataTransferInEvent(nsDragEvent* aDragEvent)
4658 if (aDragEvent->dataTransfer || !NS_IS_TRUSTED_EVENT(aDragEvent))
4659 return NS_OK;
4661 // For draggesture and dragstart events, the data transfer object is
4662 // created before the event fires, so it should already be set. For other
4663 // drag events, get the object from the drag session.
4664 NS_ASSERTION(aDragEvent->message != NS_DRAGDROP_GESTURE &&
4665 aDragEvent->message != NS_DRAGDROP_START,
4666 "draggesture event created without a dataTransfer");
4668 nsCOMPtr<nsIDragSession> dragSession = GetDragSession();
4669 NS_ENSURE_TRUE(dragSession, NS_OK); // no drag in progress
4671 nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
4672 dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
4673 if (!initialDataTransfer) {
4674 // A dataTransfer won't exist when a drag was started by some other
4675 // means, for instance calling the drag service directly, or a drag
4676 // from another application. In either case, a new dataTransfer should
4677 // be created that reflects the data. Pass true to the constructor for
4678 // the aIsExternal argument, so that only system access is allowed.
4679 PRUint32 action = 0;
4680 dragSession->GetDragAction(&action);
4681 initialDataTransfer =
4682 new nsDOMDataTransfer(aDragEvent->message, action);
4683 NS_ENSURE_TRUE(initialDataTransfer, NS_ERROR_OUT_OF_MEMORY);
4685 // now set it in the drag session so we don't need to create it again
4686 dragSession->SetDataTransfer(initialDataTransfer);
4689 // each event should use a clone of the original dataTransfer.
4690 nsCOMPtr<nsIDOMNSDataTransfer> initialDataTransferNS =
4691 do_QueryInterface(initialDataTransfer);
4692 NS_ENSURE_TRUE(initialDataTransferNS, NS_ERROR_FAILURE);
4693 initialDataTransferNS->Clone(aDragEvent->message, aDragEvent->userCancelled,
4694 getter_AddRefs(aDragEvent->dataTransfer));
4695 NS_ENSURE_TRUE(aDragEvent->dataTransfer, NS_ERROR_OUT_OF_MEMORY);
4697 // for the dragenter and dragover events, initialize the drop effect
4698 // from the drop action, which platform specific widget code sets before
4699 // the event is fired based on the keyboard state.
4700 if (aDragEvent->message == NS_DRAGDROP_ENTER ||
4701 aDragEvent->message == NS_DRAGDROP_OVER) {
4702 nsCOMPtr<nsIDOMNSDataTransfer> newDataTransfer =
4703 do_QueryInterface(aDragEvent->dataTransfer);
4704 NS_ENSURE_TRUE(newDataTransfer, NS_ERROR_FAILURE);
4706 PRUint32 action, effectAllowed;
4707 dragSession->GetDragAction(&action);
4708 newDataTransfer->GetEffectAllowedInt(&effectAllowed);
4709 newDataTransfer->SetDropEffectInt(FilterDropEffect(action, effectAllowed));
4711 else if (aDragEvent->message == NS_DRAGDROP_DROP ||
4712 aDragEvent->message == NS_DRAGDROP_DRAGDROP ||
4713 aDragEvent->message == NS_DRAGDROP_END) {
4714 // For the drop and dragend events, set the drop effect based on the
4715 // last value that the dropEffect had. This will have been set in
4716 // nsEventStateManager::PostHandleEvent for the last dragenter or
4717 // dragover event.
4718 nsCOMPtr<nsIDOMNSDataTransfer> newDataTransfer =
4719 do_QueryInterface(aDragEvent->dataTransfer);
4720 NS_ENSURE_TRUE(newDataTransfer, NS_ERROR_FAILURE);
4722 PRUint32 dropEffect;
4723 initialDataTransferNS->GetDropEffectInt(&dropEffect);
4724 newDataTransfer->SetDropEffectInt(dropEffect);
4727 return NS_OK;
4730 /* static */
4731 PRUint32
4732 nsContentUtils::FilterDropEffect(PRUint32 aAction, PRUint32 aEffectAllowed)
4734 // It is possible for the drag action to include more than one action, but
4735 // the widget code which sets the action from the keyboard state should only
4736 // be including one. If multiple actions were set, we just consider them in
4737 // the following order:
4738 // copy, link, move
4739 if (aAction & nsIDragService::DRAGDROP_ACTION_COPY)
4740 aAction = nsIDragService::DRAGDROP_ACTION_COPY;
4741 else if (aAction & nsIDragService::DRAGDROP_ACTION_LINK)
4742 aAction = nsIDragService::DRAGDROP_ACTION_LINK;
4743 else if (aAction & nsIDragService::DRAGDROP_ACTION_MOVE)
4744 aAction = nsIDragService::DRAGDROP_ACTION_MOVE;
4746 // Filter the action based on the effectAllowed. If the effectAllowed
4747 // doesn't include the action, then that action cannot be done, so adjust
4748 // the action to something that is allowed. For a copy, adjust to move or
4749 // link. For a move, adjust to copy or link. For a link, adjust to move or
4750 // link. Otherwise, use none.
4751 if (aAction & aEffectAllowed ||
4752 aEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
4753 return aAction;
4754 if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_MOVE)
4755 return nsIDragService::DRAGDROP_ACTION_MOVE;
4756 if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_COPY)
4757 return nsIDragService::DRAGDROP_ACTION_COPY;
4758 if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_LINK)
4759 return nsIDragService::DRAGDROP_ACTION_LINK;
4760 return nsIDragService::DRAGDROP_ACTION_NONE;
4763 /* static */
4764 PRBool
4765 nsContentUtils::URIIsLocalFile(nsIURI *aURI)
4767 PRBool isFile;
4768 nsCOMPtr<nsINetUtil> util = do_QueryInterface(sIOService);
4770 return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
4771 nsIProtocolHandler::URI_IS_LOCAL_FILE,
4772 &isFile)) &&
4773 isFile;
4776 /* static */
4777 nsIScriptContext*
4778 nsContentUtils::GetContextForEventHandlers(nsINode* aNode,
4779 nsresult* aRv)
4781 *aRv = NS_OK;
4782 nsIDocument* ownerDoc = aNode->GetOwnerDoc();
4783 if (!ownerDoc) {
4784 *aRv = NS_ERROR_UNEXPECTED;
4785 return nsnull;
4788 PRBool hasHadScriptObject = PR_TRUE;
4789 nsIScriptGlobalObject* sgo =
4790 ownerDoc->GetScriptHandlingObject(hasHadScriptObject);
4791 // It is bad if the document doesn't have event handling context,
4792 // but it used to have one.
4793 if (!sgo && hasHadScriptObject) {
4794 *aRv = NS_ERROR_UNEXPECTED;
4795 return nsnull;
4798 if (sgo) {
4799 nsIScriptContext* scx = sgo->GetContext();
4800 // Bad, no context from script global object!
4801 if (!scx) {
4802 *aRv = NS_ERROR_UNEXPECTED;
4803 return nsnull;
4805 return scx;
4808 return nsnull;
4811 /* static */
4812 JSContext *
4813 nsContentUtils::GetCurrentJSContext()
4815 JSContext *cx = nsnull;
4817 sThreadJSContextStack->Peek(&cx);
4819 return cx;
4822 /* static */
4823 void
4824 nsContentUtils::ASCIIToLower(const nsAString& aSource, nsAString& aDest)
4826 PRUint32 len = aSource.Length();
4827 aDest.SetLength(len);
4828 if (aDest.Length() == len) {
4829 PRUnichar* dest = aDest.BeginWriting();
4830 const PRUnichar* iter = aSource.BeginReading();
4831 const PRUnichar* end = aSource.EndReading();
4832 while (iter != end) {
4833 PRUnichar c = *iter;
4834 *dest = (c >= 'A' && c <= 'Z') ?
4835 c + ('a' - 'A') : c;
4836 ++iter;
4837 ++dest;
4842 /* static */
4843 void
4844 nsContentUtils::ASCIIToUpper(nsAString& aStr)
4846 PRUnichar* iter = aStr.BeginWriting();
4847 PRUnichar* end = aStr.EndWriting();
4848 while (iter != end) {
4849 PRUnichar c = *iter;
4850 if (c >= 'a' && c <= 'z') {
4851 *iter = c + ('A' - 'a');
4853 ++iter;
4857 PRBool
4858 nsContentUtils::EqualsIgnoreASCIICase(const nsAString& aStr1,
4859 const nsAString& aStr2)
4861 PRUint32 len = aStr1.Length();
4862 if (len != aStr2.Length()) {
4863 return PR_FALSE;
4866 const PRUnichar* str1 = aStr1.BeginReading();
4867 const PRUnichar* str2 = aStr2.BeginReading();
4868 const PRUnichar* end = str1 + len;
4870 while (str1 < end) {
4871 PRUnichar c1 = *str1++;
4872 PRUnichar c2 = *str2++;
4874 // First check if any bits other than the 0x0020 differs
4875 if ((c1 ^ c2) & 0xffdf) {
4876 return PR_FALSE;
4879 // We know they only differ in the 0x0020 bit.
4880 // Likely the two chars are the same, so check that first
4881 if (c1 != c2) {
4882 // They do differ, but since it's only in the 0x0020 bit, check if it's
4883 // the same ascii char, but just differing in case
4884 PRUnichar c1Upper = c1 & 0xffdf;
4885 if (!('A' <= c1Upper && c1Upper <= 'Z')) {
4886 return PR_FALSE;
4891 return PR_TRUE;
4894 /* static */
4895 void
4896 nsAutoGCRoot::Shutdown()
4898 NS_IF_RELEASE(sJSRuntimeService);
4901 /* static */
4902 nsIInterfaceRequestor*
4903 nsContentUtils::GetSameOriginChecker()
4905 if (!sSameOriginChecker) {
4906 sSameOriginChecker = new nsSameOriginChecker();
4907 NS_IF_ADDREF(sSameOriginChecker);
4909 return sSameOriginChecker;
4913 NS_IMPL_ISUPPORTS2(nsSameOriginChecker,
4914 nsIChannelEventSink,
4915 nsIInterfaceRequestor)
4917 NS_IMETHODIMP
4918 nsSameOriginChecker::OnChannelRedirect(nsIChannel *aOldChannel,
4919 nsIChannel *aNewChannel,
4920 PRUint32 aFlags)
4922 NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
4923 if (!nsContentUtils::GetSecurityManager()) {
4924 return NS_ERROR_NOT_AVAILABLE;
4927 nsCOMPtr<nsIPrincipal> oldPrincipal;
4928 nsContentUtils::GetSecurityManager()->
4929 GetChannelPrincipal(aOldChannel, getter_AddRefs(oldPrincipal));
4931 nsCOMPtr<nsIURI> newURI;
4932 aNewChannel->GetURI(getter_AddRefs(newURI));
4933 nsCOMPtr<nsIURI> newOriginalURI;
4934 aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
4936 NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
4938 nsresult rv = oldPrincipal->CheckMayLoad(newURI, PR_FALSE);
4939 if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
4940 rv = oldPrincipal->CheckMayLoad(newOriginalURI, PR_FALSE);
4942 return rv;
4945 NS_IMETHODIMP
4946 nsSameOriginChecker::GetInterface(const nsIID & aIID, void **aResult)
4948 return QueryInterface(aIID, aResult);
4951 /* static */
4952 nsresult
4953 nsContentUtils::GetASCIIOrigin(nsIPrincipal* aPrincipal, nsCString& aOrigin)
4955 NS_PRECONDITION(aPrincipal, "missing principal");
4957 aOrigin.Truncate();
4959 nsCOMPtr<nsIURI> uri;
4960 nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
4961 NS_ENSURE_SUCCESS(rv, rv);
4963 if (uri) {
4964 return GetASCIIOrigin(uri, aOrigin);
4967 aOrigin.AssignLiteral("null");
4969 return NS_OK;
4972 /* static */
4973 nsresult
4974 nsContentUtils::GetASCIIOrigin(nsIURI* aURI, nsCString& aOrigin)
4976 NS_PRECONDITION(aURI, "missing uri");
4978 aOrigin.Truncate();
4980 nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
4981 NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
4983 nsCString host;
4984 nsresult rv = uri->GetAsciiHost(host);
4986 if (NS_SUCCEEDED(rv) && !host.IsEmpty()) {
4987 nsCString scheme;
4988 rv = uri->GetScheme(scheme);
4989 NS_ENSURE_SUCCESS(rv, rv);
4991 aOrigin = scheme + NS_LITERAL_CSTRING("://") + host;
4993 // If needed, append the port
4994 PRInt32 port;
4995 uri->GetPort(&port);
4996 if (port != -1) {
4997 PRInt32 defaultPort = NS_GetDefaultPort(scheme.get());
4998 if (port != defaultPort) {
4999 aOrigin.Append(':');
5000 aOrigin.AppendInt(port);
5004 else {
5005 aOrigin.AssignLiteral("null");
5008 return NS_OK;
5011 /* static */
5012 nsresult
5013 nsContentUtils::GetUTFOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin)
5015 NS_PRECONDITION(aPrincipal, "missing principal");
5017 aOrigin.Truncate();
5019 nsCOMPtr<nsIURI> uri;
5020 nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
5021 NS_ENSURE_SUCCESS(rv, rv);
5023 if (uri) {
5024 return GetUTFOrigin(uri, aOrigin);
5027 aOrigin.AssignLiteral("null");
5029 return NS_OK;
5032 /* static */
5033 nsresult
5034 nsContentUtils::GetUTFOrigin(nsIURI* aURI, nsString& aOrigin)
5036 NS_PRECONDITION(aURI, "missing uri");
5038 aOrigin.Truncate();
5040 nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
5041 NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
5043 nsCString host;
5044 nsresult rv = uri->GetHost(host);
5046 if (NS_SUCCEEDED(rv) && !host.IsEmpty()) {
5047 nsCString scheme;
5048 rv = uri->GetScheme(scheme);
5049 NS_ENSURE_SUCCESS(rv, rv);
5051 aOrigin = NS_ConvertUTF8toUTF16(scheme + NS_LITERAL_CSTRING("://") + host);
5053 // If needed, append the port
5054 PRInt32 port;
5055 uri->GetPort(&port);
5056 if (port != -1) {
5057 PRInt32 defaultPort = NS_GetDefaultPort(scheme.get());
5058 if (port != defaultPort) {
5059 aOrigin.Append(':');
5060 aOrigin.AppendInt(port);
5064 else {
5065 aOrigin.AssignLiteral("null");
5068 return NS_OK;
5071 /* static */
5072 already_AddRefed<nsIDocument>
5073 nsContentUtils::GetDocumentFromScriptContext(nsIScriptContext *aScriptContext)
5075 if (!aScriptContext)
5076 return nsnull;
5078 nsCOMPtr<nsIDOMWindow> window =
5079 do_QueryInterface(aScriptContext->GetGlobalObject());
5080 nsIDocument *doc = nsnull;
5081 if (window) {
5082 nsCOMPtr<nsIDOMDocument> domdoc;
5083 window->GetDocument(getter_AddRefs(domdoc));
5084 if (domdoc) {
5085 CallQueryInterface(domdoc, &doc);
5088 return doc;
5091 nsContentTypeParser::nsContentTypeParser(const nsAString& aString)
5092 : mString(aString), mService(nsnull)
5094 CallGetService("@mozilla.org/network/mime-hdrparam;1", &mService);
5097 nsContentTypeParser::~nsContentTypeParser()
5099 NS_IF_RELEASE(mService);
5102 nsresult
5103 nsContentTypeParser::GetParameter(const char* aParameterName, nsAString& aResult)
5105 NS_ENSURE_TRUE(mService, NS_ERROR_FAILURE);
5106 return mService->GetParameter(mString, aParameterName,
5107 EmptyCString(), PR_FALSE, nsnull,
5108 aResult);
5111 /* static */
5113 // If you change this code, change also AllowedToAct() in
5114 // XPCSystemOnlyWrapper.cpp!
5115 PRBool
5116 nsContentUtils::CanAccessNativeAnon()
5118 JSContext* cx = nsnull;
5119 sThreadJSContextStack->Peek(&cx);
5120 if (!cx) {
5121 return PR_TRUE;
5123 JSStackFrame* fp;
5124 nsIPrincipal* principal =
5125 sSecurityManager->GetCxSubjectPrincipalAndFrame(cx, &fp);
5126 NS_ENSURE_TRUE(principal, PR_FALSE);
5128 if (!fp) {
5129 if (!JS_FrameIterator(cx, &fp)) {
5130 // No code at all is running. So we must be arriving here as the result
5131 // of C++ code asking us to do something. Allow access.
5132 return PR_TRUE;
5135 // Some code is running, we can't make the assumption, as above, but we
5136 // can't use a native frame, so clear fp.
5137 fp = nsnull;
5138 } else if (!fp->script) {
5139 fp = nsnull;
5142 PRBool privileged;
5143 if (NS_SUCCEEDED(sSecurityManager->IsSystemPrincipal(principal, &privileged)) &&
5144 privileged) {
5145 // Chrome things are allowed to touch us.
5146 return PR_TRUE;
5149 // XXX HACK EWW! Allow chrome://global/ access to these things, even
5150 // if they've been cloned into less privileged contexts.
5151 static const char prefix[] = "chrome://global/";
5152 const char *filename;
5153 if (fp && fp->script &&
5154 (filename = fp->script->filename) &&
5155 !strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
5156 return PR_TRUE;
5159 // Before we throw, check for UniversalXPConnect.
5160 nsresult rv = sSecurityManager->IsCapabilityEnabled("UniversalXPConnect", &privileged);
5161 if (NS_SUCCEEDED(rv) && privileged) {
5162 return PR_TRUE;
5165 return PR_FALSE;
5168 /* static */ nsresult
5169 nsContentUtils::DispatchXULCommand(nsIContent* aTarget,
5170 PRBool aTrusted,
5171 nsIDOMEvent* aSourceEvent,
5172 nsIPresShell* aShell,
5173 PRBool aCtrl,
5174 PRBool aAlt,
5175 PRBool aShift,
5176 PRBool aMeta)
5178 NS_ENSURE_STATE(aTarget);
5179 nsIDocument* doc = aTarget->GetOwnerDoc();
5180 nsCOMPtr<nsIDOMDocumentEvent> docEvent = do_QueryInterface(doc);
5181 NS_ENSURE_STATE(docEvent);
5182 nsCOMPtr<nsIDOMEvent> event;
5183 docEvent->CreateEvent(NS_LITERAL_STRING("xulcommandevent"),
5184 getter_AddRefs(event));
5185 nsCOMPtr<nsIDOMXULCommandEvent> xulCommand = do_QueryInterface(event);
5186 nsCOMPtr<nsIPrivateDOMEvent> pEvent = do_QueryInterface(xulCommand);
5187 NS_ENSURE_STATE(pEvent);
5188 nsCOMPtr<nsIDOMAbstractView> view = do_QueryInterface(doc->GetWindow());
5189 nsresult rv = xulCommand->InitCommandEvent(NS_LITERAL_STRING("command"),
5190 PR_TRUE, PR_TRUE, view,
5191 0, aCtrl, aAlt, aShift, aMeta,
5192 aSourceEvent);
5193 NS_ENSURE_SUCCESS(rv, rv);
5195 if (aShell) {
5196 nsEventStatus status = nsEventStatus_eIgnore;
5197 nsCOMPtr<nsIPresShell> kungFuDeathGrip = aShell;
5198 return aShell->HandleDOMEventWithTarget(aTarget, event, &status);
5201 nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(aTarget);
5202 NS_ENSURE_STATE(target);
5203 PRBool dummy;
5204 return target->DispatchEvent(event, &dummy);
5207 // static
5208 nsresult
5209 nsContentUtils::WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
5210 const nsIID* aIID, jsval *vp,
5211 nsIXPConnectJSObjectHolder **aHolder,
5212 PRBool aAllowWrapping)
5214 if (!native) {
5215 NS_ASSERTION(!aHolder || !*aHolder, "*aHolder should be null!");
5217 *vp = JSVAL_NULL;
5219 return NS_OK;
5222 NS_ENSURE_TRUE(sXPConnect && sThreadJSContextStack, NS_ERROR_UNEXPECTED);
5224 // Keep sXPConnect and sThreadJSContextStack alive. If we're on the main
5225 // thread then this can be done simply and cheaply by adding a reference to
5226 // nsLayoutStatics. If we're not on the main thread then we need to add a
5227 // more expensive reference sXPConnect directly. We have to use manual
5228 // AddRef and Release calls so don't early-exit from this function after we've
5229 // added the reference!
5230 PRBool isMainThread = NS_IsMainThread();
5232 if (isMainThread) {
5233 nsLayoutStatics::AddRef();
5235 else {
5236 sXPConnect->AddRef();
5239 JSContext *topJSContext;
5240 nsresult rv = sThreadJSContextStack->Peek(&topJSContext);
5241 if (NS_SUCCEEDED(rv)) {
5242 PRBool push = topJSContext != cx;
5243 if (push) {
5244 rv = sThreadJSContextStack->Push(cx);
5246 if (NS_SUCCEEDED(rv)) {
5247 rv = sXPConnect->WrapNativeToJSVal(cx, scope, native, aIID,
5248 aAllowWrapping, vp, aHolder);
5249 if (push) {
5250 sThreadJSContextStack->Pop(nsnull);
5255 if (isMainThread) {
5256 nsLayoutStatics::Release();
5258 else {
5259 sXPConnect->Release();
5262 return rv;
5265 void
5266 nsContentUtils::StripNullChars(const nsAString& aInStr, nsAString& aOutStr)
5268 // In common cases where we don't have nulls in the
5269 // string we can simple simply bypass the checking code.
5270 PRInt32 firstNullPos = aInStr.FindChar('\0');
5271 if (firstNullPos == kNotFound) {
5272 aOutStr.Assign(aInStr);
5273 return;
5276 aOutStr.SetCapacity(aInStr.Length() - 1);
5277 nsAString::const_iterator start, end;
5278 aInStr.BeginReading(start);
5279 aInStr.EndReading(end);
5280 while (start != end) {
5281 if (*start != '\0')
5282 aOutStr.Append(*start);
5283 ++start;
5287 namespace {
5289 const unsigned int kCloneStackFrameStackSize = 20;
5291 class CloneStackFrame
5293 friend class CloneStack;
5295 public:
5296 // These three jsvals must all stick together as they're treated as a jsval
5297 // array!
5298 jsval source;
5299 jsval clone;
5300 jsval temp;
5301 js::AutoIdArray ids;
5302 jsuint index;
5304 private:
5305 // Only let CloneStack access these.
5306 CloneStackFrame(JSContext* aCx, jsval aSource, jsval aClone, JSIdArray* aIds)
5307 : source(aSource), clone(aClone), temp(JSVAL_NULL), ids(aCx, aIds), index(0),
5308 prevFrame(nsnull), tvrVals(aCx, 3, &source)
5310 MOZ_COUNT_CTOR(CloneStackFrame);
5313 ~CloneStackFrame()
5315 MOZ_COUNT_DTOR(CloneStackFrame);
5318 CloneStackFrame* prevFrame;
5319 js::AutoArrayRooter tvrVals;
5322 class CloneStack
5324 public:
5325 CloneStack(JSContext* cx)
5326 : mCx(cx), mLastFrame(nsnull) {
5327 mObjectSet.Init();
5330 ~CloneStack() {
5331 while (!IsEmpty()) {
5332 Pop();
5336 PRBool
5337 Push(jsval source, jsval clone, JSIdArray* ids) {
5338 NS_ASSERTION(!JSVAL_IS_PRIMITIVE(source) && !JSVAL_IS_PRIMITIVE(clone),
5339 "Must be an object!");
5340 if (!ids) {
5341 return PR_FALSE;
5344 CloneStackFrame* newFrame;
5345 if (mObjectSet.Count() < kCloneStackFrameStackSize) {
5346 // If the object can fit in our stack space then use that.
5347 CloneStackFrame* buf = reinterpret_cast<CloneStackFrame*>(mStackFrames);
5348 newFrame = new (buf + mObjectSet.Count())
5349 CloneStackFrame(mCx, source, clone, ids);
5351 else {
5352 // Use the heap.
5353 newFrame = new CloneStackFrame(mCx, source, clone, ids);
5356 mObjectSet.PutEntry(JSVAL_TO_OBJECT(source));
5358 newFrame->prevFrame = mLastFrame;
5359 mLastFrame = newFrame;
5361 return PR_TRUE;
5364 CloneStackFrame*
5365 Peek() {
5366 return mLastFrame;
5369 void
5370 Pop() {
5371 if (IsEmpty()) {
5372 NS_ERROR("Empty stack!");
5373 return;
5376 CloneStackFrame* lastFrame = mLastFrame;
5378 mObjectSet.RemoveEntry(JSVAL_TO_OBJECT(lastFrame->source));
5379 mLastFrame = lastFrame->prevFrame;
5381 if (mObjectSet.Count() >= kCloneStackFrameStackSize) {
5382 // Only delete if this was a heap object.
5383 delete lastFrame;
5385 else {
5386 // Otherwise just run the destructor.
5387 lastFrame->~CloneStackFrame();
5391 PRBool
5392 IsEmpty() {
5393 NS_ASSERTION((!mLastFrame && !mObjectSet.Count()) ||
5394 (mLastFrame && mObjectSet.Count()),
5395 "Hashset is out of sync!");
5396 return mObjectSet.Count() == 0;
5399 PRBool
5400 Search(JSObject* obj) {
5401 return !!mObjectSet.GetEntry(obj);
5404 private:
5405 JSContext* mCx;
5406 CloneStackFrame* mLastFrame;
5407 nsTHashtable<nsVoidPtrHashKey> mObjectSet;
5409 // Use a char array instead of CloneStackFrame array to prevent the JSAuto*
5410 // helpers from running until we're ready for them.
5411 char mStackFrames[kCloneStackFrameStackSize * sizeof(CloneStackFrame)];
5414 struct ReparentObjectData {
5415 ReparentObjectData(JSContext* cx, JSObject* obj)
5416 : cx(cx), obj(obj), ids(nsnull), index(0) { }
5418 ~ReparentObjectData() {
5419 if (ids) {
5420 JS_DestroyIdArray(cx, ids);
5424 JSContext* cx;
5425 JSObject* obj;
5426 JSIdArray* ids;
5427 jsint index;
5430 inline nsresult
5431 SetPropertyOnValueOrObject(JSContext* cx,
5432 jsval val,
5433 jsval* rval,
5434 JSObject* obj,
5435 jsid id)
5437 NS_ASSERTION((rval && !obj) || (!rval && obj), "Can only clone to one dest!");
5438 if (rval) {
5439 *rval = val;
5440 return NS_OK;
5442 if (!JS_DefinePropertyById(cx, obj, id, val, nsnull, nsnull,
5443 JSPROP_ENUMERATE)) {
5444 return NS_ERROR_FAILURE;
5446 return NS_OK;
5449 inline JSObject*
5450 CreateEmptyObjectOrArray(JSContext* cx,
5451 JSObject* obj)
5453 if (JS_IsArrayObject(cx, obj)) {
5454 jsuint length;
5455 if (!JS_GetArrayLength(cx, obj, &length)) {
5456 NS_ERROR("Failed to get array length?!");
5457 return nsnull;
5459 return JS_NewArrayObject(cx, length, NULL);
5461 return JS_NewObject(cx, NULL, NULL, NULL);
5464 nsresult
5465 CloneSimpleValues(JSContext* cx,
5466 jsval val,
5467 jsval* rval,
5468 PRBool* wasCloned,
5469 JSObject* robj = nsnull,
5470 jsid rid = INT_TO_JSID(0))
5472 *wasCloned = PR_TRUE;
5474 // No cloning necessary for these non-GC'd jsvals.
5475 if (!JSVAL_IS_GCTHING(val) || JSVAL_IS_NULL(val)) {
5476 return SetPropertyOnValueOrObject(cx, val, rval, robj, rid);
5479 // Clone doubles.
5480 if (JSVAL_IS_DOUBLE(val)) {
5481 jsval newVal;
5482 if (!JS_NewDoubleValue(cx, *JSVAL_TO_DOUBLE(val), &newVal)) {
5483 return NS_ERROR_OUT_OF_MEMORY;
5485 return SetPropertyOnValueOrObject(cx, newVal, rval, robj, rid);
5488 // We'll use immutable strings to prevent copying if we can.
5489 if (JSVAL_IS_STRING(val)) {
5490 if (!JS_MakeStringImmutable(cx, JSVAL_TO_STRING(val))) {
5491 return NS_ERROR_FAILURE;
5493 return SetPropertyOnValueOrObject(cx, val, rval, robj, rid);
5496 NS_ASSERTION(!JSVAL_IS_PRIMITIVE(val), "Not an object!");
5497 JSObject* obj = JSVAL_TO_OBJECT(val);
5499 // Dense arrays of primitives can be cloned quickly.
5500 JSObject* newArray;
5501 if (!js_CloneDensePrimitiveArray(cx, obj, &newArray)) {
5502 return NS_ERROR_FAILURE;
5504 if (newArray) {
5505 return SetPropertyOnValueOrObject(cx, OBJECT_TO_JSVAL(newArray), rval, robj,
5506 rid);
5509 // Date objects.
5510 if (js_DateIsValid(cx, obj)) {
5511 jsdouble msec = js_DateGetMsecSinceEpoch(cx, obj);
5512 JSObject* newDate;
5513 if (!(msec && (newDate = js_NewDateObjectMsec(cx, msec)))) {
5514 return NS_ERROR_OUT_OF_MEMORY;
5516 return SetPropertyOnValueOrObject(cx, OBJECT_TO_JSVAL(newDate), rval, robj,
5517 rid);
5520 // RegExp objects.
5521 if (js_ObjectIsRegExp(obj)) {
5522 JSObject* proto;
5523 if (!js_GetClassPrototype(cx, JS_GetScopeChain(cx), JSProto_RegExp,
5524 &proto)) {
5525 return NS_ERROR_FAILURE;
5527 JSObject* newRegExp = js_CloneRegExpObject(cx, obj, proto);
5528 if (!newRegExp) {
5529 return NS_ERROR_FAILURE;
5531 return SetPropertyOnValueOrObject(cx, OBJECT_TO_JSVAL(newRegExp), rval,
5532 robj, rid);
5535 // Typed array objects.
5536 if (js_IsTypedArray(obj)) {
5537 js::TypedArray* src = js::TypedArray::fromJSObject(obj);
5538 JSObject* newTypedArray = js_CreateTypedArrayWithArray(cx, src->type, obj);
5539 if (!newTypedArray) {
5540 return NS_ERROR_FAILURE;
5542 return SetPropertyOnValueOrObject(cx, OBJECT_TO_JSVAL(newTypedArray), rval,
5543 robj, rid);
5546 // ArrayBuffer objects.
5547 if (js_IsArrayBuffer(obj)) {
5548 js::ArrayBuffer* src = js::ArrayBuffer::fromJSObject(obj);
5549 JSObject* newBuffer = js_CreateArrayBuffer(cx, src->byteLength);
5550 if (!newBuffer) {
5551 return NS_ERROR_FAILURE;
5553 memcpy(js::ArrayBuffer::fromJSObject(newBuffer)->data, src->data,
5554 src->byteLength);
5555 return SetPropertyOnValueOrObject(cx, OBJECT_TO_JSVAL(newBuffer), rval,
5556 robj, rid);
5559 // Do we support File?
5560 // Do we support Blob?
5561 // Do we support FileList?
5563 // Function objects don't get cloned.
5564 if (JS_ObjectIsFunction(cx, obj)) {
5565 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
5568 // Security wrapped objects are not allowed either.
5569 JSClass* clasp = JS_GET_CLASS(cx, obj);
5570 if ((clasp->flags & JSCLASS_IS_EXTENDED) &&
5571 ((JSExtendedClass*)clasp)->wrappedObject) {
5572 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
5575 // See if this JSObject is backed by some C++ object. If it is then we assume
5576 // that it is inappropriate to clone.
5577 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
5578 nsContentUtils::XPConnect()->
5579 GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrapper));
5580 if (wrapper) {
5581 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
5584 *wasCloned = PR_FALSE;
5585 return NS_OK;
5588 } // anonymous namespace
5590 // static
5591 nsresult
5592 nsContentUtils::CreateStructuredClone(JSContext* cx,
5593 jsval val,
5594 jsval* rval)
5596 JSAutoRequest ar(cx);
5598 nsCOMPtr<nsIXPConnect> xpconnect(sXPConnect);
5599 NS_ENSURE_STATE(xpconnect);
5601 PRBool wasCloned;
5602 nsresult rv = CloneSimpleValues(cx, val, rval, &wasCloned);
5603 if (NS_FAILED(rv)) {
5604 return rv;
5607 if (wasCloned) {
5608 return NS_OK;
5611 NS_ASSERTION(JSVAL_IS_OBJECT(val), "Not an object?!");
5612 JSObject* obj = CreateEmptyObjectOrArray(cx, JSVAL_TO_OBJECT(val));
5613 if (!obj) {
5614 return NS_ERROR_OUT_OF_MEMORY;
5617 jsval output = OBJECT_TO_JSVAL(obj);
5618 js::AutoValueRooter tvr(cx, output);
5620 CloneStack stack(cx);
5621 if (!stack.Push(val, OBJECT_TO_JSVAL(obj),
5622 JS_Enumerate(cx, JSVAL_TO_OBJECT(val)))) {
5623 return NS_ERROR_OUT_OF_MEMORY;
5626 while (!stack.IsEmpty()) {
5627 CloneStackFrame* frame = stack.Peek();
5629 NS_ASSERTION(!!frame->ids &&
5630 frame->ids.length() >= frame->index &&
5631 !JSVAL_IS_PRIMITIVE(frame->source) &&
5632 !JSVAL_IS_PRIMITIVE(frame->clone),
5633 "Bad frame state!");
5635 if (frame->index == frame->ids.length()) {
5636 // Done cloning this object, pop the frame.
5637 stack.Pop();
5638 continue;
5641 // Get the current id and increment the index.
5642 jsid id = frame->ids[frame->index++];
5644 if (!JS_GetPropertyById(cx, JSVAL_TO_OBJECT(frame->source), id,
5645 &frame->temp)) {
5646 return NS_ERROR_FAILURE;
5649 if (!JSVAL_IS_PRIMITIVE(frame->temp) &&
5650 stack.Search(JSVAL_TO_OBJECT(frame->temp))) {
5651 // Spec says to throw this particular exception for cyclical references.
5652 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
5655 JSObject* clone = JSVAL_TO_OBJECT(frame->clone);
5657 PRBool wasCloned;
5658 nsresult rv = CloneSimpleValues(cx, frame->temp, nsnull, &wasCloned, clone,
5659 id);
5660 if (NS_FAILED(rv)) {
5661 return rv;
5664 if (!wasCloned) {
5665 NS_ASSERTION(JSVAL_IS_OBJECT(frame->temp), "Not an object?!");
5666 obj = CreateEmptyObjectOrArray(cx, JSVAL_TO_OBJECT(frame->temp));
5667 if (!obj ||
5668 !stack.Push(frame->temp, OBJECT_TO_JSVAL(obj),
5669 JS_Enumerate(cx, JSVAL_TO_OBJECT(frame->temp)))) {
5670 return NS_ERROR_OUT_OF_MEMORY;
5672 // Set the new object as a property of the clone. We'll fill it on the
5673 // next iteration.
5674 if (!JS_DefinePropertyById(cx, clone, id, OBJECT_TO_JSVAL(obj), nsnull,
5675 nsnull, JSPROP_ENUMERATE)) {
5676 return NS_ERROR_FAILURE;
5681 *rval = output;
5682 return NS_OK;
5685 // static
5686 nsresult
5687 nsContentUtils::ReparentClonedObjectToScope(JSContext* cx,
5688 JSObject* obj,
5689 JSObject* scope)
5691 JSAutoRequest ar(cx);
5693 scope = JS_GetGlobalForObject(cx, scope);
5695 nsAutoTArray<ReparentObjectData, 20> objectData;
5696 objectData.AppendElement(ReparentObjectData(cx, obj));
5698 while (!objectData.IsEmpty()) {
5699 ReparentObjectData& data = objectData[objectData.Length() - 1];
5701 if (!data.ids) {
5702 NS_ASSERTION(!data.index, "Shouldn't have index here");
5704 // Typed arrays are special and don't need to be enumerated.
5705 if (js_IsTypedArray(data.obj)) {
5706 if (!js_ReparentTypedArrayToScope(cx, data.obj, scope)) {
5707 return NS_ERROR_FAILURE;
5710 // No need to enumerate anything here.
5711 objectData.RemoveElementAt(objectData.Length() - 1);
5712 continue;
5715 JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(JS_GET_CLASS(cx, data.obj));
5716 if (!key) {
5717 // We should never be reparenting an object that doesn't have a standard
5718 // proto key.
5719 return NS_ERROR_FAILURE;
5722 // Fix the prototype and parent first.
5723 JSObject* proto;
5724 if (!js_GetClassPrototype(cx, scope, key, &proto) ||
5725 !JS_SetPrototype(cx, data.obj, proto) ||
5726 !JS_SetParent(cx, data.obj, scope)) {
5727 return NS_ERROR_FAILURE;
5730 // Primitive arrays don't need to be enumerated either but the proto and
5731 // parent needed to be fixed above. Now we can just move on.
5732 if (js_IsDensePrimitiveArray(data.obj)) {
5733 objectData.RemoveElementAt(objectData.Length() - 1);
5734 continue;
5737 // And now enumerate the object's properties.
5738 if (!(data.ids = JS_Enumerate(cx, data.obj))) {
5739 return NS_ERROR_FAILURE;
5743 // If we've gone through all the object's properties then we're done with
5744 // this frame.
5745 if (data.index == data.ids->length) {
5746 objectData.RemoveElementAt(objectData.Length() - 1);
5747 continue;
5750 // Get the id and increment!
5751 jsid id = data.ids->vector[data.index++];
5753 jsval prop;
5754 if (!JS_GetPropertyById(cx, data.obj, id, &prop)) {
5755 return NS_ERROR_FAILURE;
5758 // Push a new frame if this property is an object.
5759 if (!JSVAL_IS_PRIMITIVE(prop)) {
5760 objectData.AppendElement(ReparentObjectData(cx, JSVAL_TO_OBJECT(prop)));
5764 return NS_OK;
5767 struct ClassMatchingInfo {
5768 nsCOMArray<nsIAtom> mClasses;
5769 nsCaseTreatment mCaseTreatment;
5772 static PRBool
5773 MatchClassNames(nsIContent* aContent, PRInt32 aNamespaceID, nsIAtom* aAtom,
5774 void* aData)
5776 // We can't match if there are no class names
5777 const nsAttrValue* classAttr = aContent->GetClasses();
5778 if (!classAttr) {
5779 return PR_FALSE;
5782 // need to match *all* of the classes
5783 ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData);
5784 PRInt32 length = info->mClasses.Count();
5785 if (!length) {
5786 // If we actually had no classes, don't match.
5787 return PR_FALSE;
5789 PRInt32 i;
5790 for (i = 0; i < length; ++i) {
5791 if (!classAttr->Contains(info->mClasses.ObjectAt(i),
5792 info->mCaseTreatment)) {
5793 return PR_FALSE;
5797 return PR_TRUE;
5800 static void
5801 DestroyClassNameArray(void* aData)
5803 ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData);
5804 delete info;
5807 static void*
5808 AllocClassMatchingInfo(nsINode* aRootNode,
5809 const nsString* aClasses)
5811 nsAttrValue attrValue;
5812 attrValue.ParseAtomArray(*aClasses);
5813 // nsAttrValue::Equals is sensitive to order, so we'll send an array
5814 ClassMatchingInfo* info = new ClassMatchingInfo;
5815 NS_ENSURE_TRUE(info, nsnull);
5817 if (attrValue.Type() == nsAttrValue::eAtomArray) {
5818 info->mClasses.AppendObjects(*(attrValue.GetAtomArrayValue()));
5819 } else if (attrValue.Type() == nsAttrValue::eAtom) {
5820 info->mClasses.AppendObject(attrValue.GetAtomValue());
5823 info->mCaseTreatment =
5824 aRootNode->GetOwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks ?
5825 eIgnoreCase : eCaseMatters;
5826 return info;
5829 // static
5831 nsresult
5832 nsContentUtils::GetElementsByClassName(nsINode* aRootNode,
5833 const nsAString& aClasses,
5834 nsIDOMNodeList** aReturn)
5836 NS_PRECONDITION(aRootNode, "Must have root node");
5838 nsContentList* elements =
5839 NS_GetFuncStringContentList(aRootNode, MatchClassNames,
5840 DestroyClassNameArray,
5841 AllocClassMatchingInfo,
5842 aClasses).get();
5843 NS_ENSURE_TRUE(elements, NS_ERROR_OUT_OF_MEMORY);
5845 // Transfer ownership
5846 *aReturn = elements;
5848 return NS_OK;
5851 #ifdef DEBUG
5852 class DebugWrapperTraversalCallback : public nsCycleCollectionTraversalCallback
5854 public:
5855 DebugWrapperTraversalCallback(void* aWrapper) : mFound(PR_FALSE),
5856 mWrapper(aWrapper)
5858 mFlags = WANT_ALL_TRACES;
5861 NS_IMETHOD_(void) DescribeNode(CCNodeType type,
5862 nsrefcnt refcount,
5863 size_t objsz,
5864 const char* objname)
5867 NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root)
5870 NS_IMETHOD_(void) NoteRoot(PRUint32 langID, void* root,
5871 nsCycleCollectionParticipant* helper)
5874 NS_IMETHOD_(void) NoteScriptChild(PRUint32 langID, void* child)
5876 if (langID == nsIProgrammingLanguage::JAVASCRIPT) {
5877 mFound = child == mWrapper;
5880 NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child)
5883 NS_IMETHOD_(void) NoteNativeChild(void* child,
5884 nsCycleCollectionParticipant* helper)
5888 NS_IMETHOD_(void) NoteNextEdgeName(const char* name)
5892 PRBool mFound;
5894 private:
5895 void* mWrapper;
5898 static void
5899 DebugWrapperTraceCallback(PRUint32 langID, void *p, void *closure)
5901 DebugWrapperTraversalCallback* callback =
5902 static_cast<DebugWrapperTraversalCallback*>(closure);
5903 callback->NoteScriptChild(langID, p);
5906 // static
5907 void
5908 nsContentUtils::CheckCCWrapperTraversal(nsISupports* aScriptObjectHolder,
5909 nsWrapperCache* aCache)
5911 nsXPCOMCycleCollectionParticipant* participant;
5912 CallQueryInterface(aScriptObjectHolder, &participant);
5914 DebugWrapperTraversalCallback callback(aCache->GetWrapper());
5916 participant->Traverse(aScriptObjectHolder, callback);
5917 NS_ASSERTION(callback.mFound,
5918 "Cycle collection participant didn't traverse to preserved "
5919 "wrapper! This will probably crash.");
5921 callback.mFound = PR_FALSE;
5922 participant->Trace(aScriptObjectHolder, DebugWrapperTraceCallback, &callback);
5923 NS_ASSERTION(callback.mFound,
5924 "Cycle collection participant didn't trace preserved wrapper! "
5925 "This will probably crash.");
5927 #endif
5929 mozAutoRemovableBlockerRemover::mozAutoRemovableBlockerRemover(nsIDocument* aDocument MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
5931 MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
5932 mNestingLevel = nsContentUtils::GetRemovableScriptBlockerLevel();
5933 mDocument = aDocument;
5934 nsISupports* sink = aDocument ? aDocument->GetCurrentContentSink() : nsnull;
5935 mObserver = do_QueryInterface(sink);
5936 for (PRUint32 i = 0; i < mNestingLevel; ++i) {
5937 if (mObserver) {
5938 mObserver->EndUpdate(mDocument, UPDATE_CONTENT_MODEL);
5940 nsContentUtils::RemoveRemovableScriptBlocker();
5943 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "killing mutation events");
5946 mozAutoRemovableBlockerRemover::~mozAutoRemovableBlockerRemover()
5948 NS_ASSERTION(nsContentUtils::GetRemovableScriptBlockerLevel() == 0,
5949 "Should have had none");
5950 for (PRUint32 i = 0; i < mNestingLevel; ++i) {
5951 nsContentUtils::AddRemovableScriptBlocker();
5952 if (mObserver) {
5953 mObserver->BeginUpdate(mDocument, UPDATE_CONTENT_MODEL);
5958 // static
5959 PRBool
5960 nsContentUtils::IsFocusedContent(nsIContent* aContent)
5962 nsFocusManager* fm = nsFocusManager::GetFocusManager();
5964 return fm && fm->GetFocusedContent() == aContent;
5967 void nsContentUtils::RemoveNewlines(nsString &aString)
5969 // strip CR/LF and null
5970 static const char badChars[] = {'\r', '\n', 0};
5971 aString.StripChars(badChars);
5974 void
5975 nsContentUtils::PlatformToDOMLineBreaks(nsString &aString)
5977 if (aString.FindChar(PRUnichar('\r')) != -1) {
5978 // Windows linebreaks: Map CRLF to LF:
5979 aString.ReplaceSubstring(NS_LITERAL_STRING("\r\n").get(),
5980 NS_LITERAL_STRING("\n").get());
5982 // Mac linebreaks: Map any remaining CR to LF:
5983 aString.ReplaceSubstring(NS_LITERAL_STRING("\r").get(),
5984 NS_LITERAL_STRING("\n").get());
5988 already_AddRefed<mozilla::layers::LayerManager>
5989 nsContentUtils::LayerManagerForDocument(nsIDocument *aDoc)
5991 nsIDocument* doc = aDoc;
5992 nsIDocument* displayDoc = doc->GetDisplayDocument();
5993 if (displayDoc) {
5994 doc = displayDoc;
5997 nsIPresShell* shell = doc->GetPrimaryShell();
5998 nsCOMPtr<nsISupports> container = doc->GetContainer();
5999 nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = do_QueryInterface(container);
6000 while (!shell && docShellTreeItem) {
6001 // We may be in a display:none subdocument, or we may not have a presshell
6002 // created yet.
6003 // Walk the docshell tree to find the nearest container that has a presshell,
6004 // and find the root widget from that.
6005 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(docShellTreeItem);
6006 nsCOMPtr<nsIPresShell> presShell;
6007 docShell->GetPresShell(getter_AddRefs(presShell));
6008 if (presShell) {
6009 shell = presShell;
6010 } else {
6011 nsCOMPtr<nsIDocShellTreeItem> parent;
6012 docShellTreeItem->GetParent(getter_AddRefs(parent));
6013 docShellTreeItem = parent;
6017 if (shell) {
6018 nsIFrame* rootFrame = shell->FrameManager()->GetRootFrame();
6019 if (rootFrame) {
6020 nsIWidget* widget =
6021 nsLayoutUtils::GetDisplayRootFrame(rootFrame)->GetWindow();
6022 if (widget) {
6023 nsRefPtr<mozilla::layers::LayerManager> manager = widget->GetLayerManager();
6024 return manager.forget();
6029 nsRefPtr<mozilla::layers::LayerManager> manager =
6030 new mozilla::layers::BasicLayerManager(nsnull);
6031 return manager.forget();
6035 NS_IMPL_ISUPPORTS1(nsIContentUtils, nsIContentUtils)
6037 PRBool
6038 nsIContentUtils::IsSafeToRunScript()
6040 return nsContentUtils::IsSafeToRunScript();