1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 sw=2 et tw=78: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code, released
17 : * March 31, 1998.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Netscape Communications Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 1998
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Johnny Stenback <jst@netscape.com>
26 : * Christopher A. Aillon <christopher@aillon.com>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either of the GNU General Public License Version 2 or later (the "GPL"),
30 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : /* A namespace class for static layout utilities. */
43 :
44 : #include "mozilla/Util.h"
45 :
46 : #include "jsapi.h"
47 : #include "jsdbgapi.h"
48 : #include "jstypedarray.h"
49 :
50 : #include "nsJSUtils.h"
51 : #include "nsCOMPtr.h"
52 : #include "nsAString.h"
53 : #include "nsPrintfCString.h"
54 : #include "nsUnicharUtils.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 "nsIXPConnect.h"
62 : #include "nsIContent.h"
63 : #include "mozilla/dom/Element.h"
64 : #include "nsIDocument.h"
65 : #include "nsINodeInfo.h"
66 : #include "nsReadableUtils.h"
67 : #include "nsIDOMDocument.h"
68 : #include "nsIDOMNodeList.h"
69 : #include "nsIDOMNode.h"
70 : #include "nsIIOService.h"
71 : #include "nsNetCID.h"
72 : #include "nsNetUtil.h"
73 : #include "nsIScriptSecurityManager.h"
74 : #include "nsDOMError.h"
75 : #include "nsPIDOMWindow.h"
76 : #include "nsIJSContextStack.h"
77 : #include "nsIDocShell.h"
78 : #include "nsIDocShellTreeItem.h"
79 : #include "nsParserCIID.h"
80 : #include "nsIParser.h"
81 : #include "nsIFragmentContentSink.h"
82 : #include "nsIContentSink.h"
83 : #include "nsIHTMLContentSink.h"
84 : #include "nsIXMLContentSink.h"
85 : #include "nsHTMLParts.h"
86 : #include "nsIParserService.h"
87 : #include "nsIServiceManager.h"
88 : #include "nsIAttribute.h"
89 : #include "nsContentList.h"
90 : #include "nsIHTMLDocument.h"
91 : #include "nsIDOMHTMLDocument.h"
92 : #include "nsIDOMHTMLCollection.h"
93 : #include "nsIDOMHTMLFormElement.h"
94 : #include "nsIDOMHTMLElement.h"
95 : #include "nsIForm.h"
96 : #include "nsIFormControl.h"
97 : #include "nsGkAtoms.h"
98 : #include "nsISupportsPrimitives.h"
99 : #include "imgIDecoderObserver.h"
100 : #include "imgIRequest.h"
101 : #include "imgIContainer.h"
102 : #include "imgILoader.h"
103 : #include "nsDocShellCID.h"
104 : #include "nsIImageLoadingContent.h"
105 : #include "nsIInterfaceRequestor.h"
106 : #include "nsIInterfaceRequestorUtils.h"
107 : #include "nsILoadGroup.h"
108 : #include "nsIObserver.h"
109 : #include "nsIObserverService.h"
110 : #include "nsContentPolicyUtils.h"
111 : #include "nsNodeInfoManager.h"
112 : #include "nsIXBLService.h"
113 : #include "nsCRT.h"
114 : #include "nsIDOMEvent.h"
115 : #include "nsIDOMEventTarget.h"
116 : #include "nsIPrivateDOMEvent.h"
117 : #ifdef MOZ_XTF
118 : #include "nsIXTFService.h"
119 : static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
120 : #endif
121 : #include "nsIMIMEService.h"
122 : #include "nsLWBrkCIID.h"
123 : #include "nsILineBreaker.h"
124 : #include "nsIWordBreaker.h"
125 : #include "nsUnicodeProperties.h"
126 : #include "harfbuzz/hb-common.h"
127 : #include "jsdbgapi.h"
128 : #include "nsIJSRuntimeService.h"
129 : #include "nsIDOMDocumentXBL.h"
130 : #include "nsBindingManager.h"
131 : #include "nsIURI.h"
132 : #include "nsIURL.h"
133 : #include "nsXBLBinding.h"
134 : #include "nsXBLPrototypeBinding.h"
135 : #include "nsEscape.h"
136 : #include "nsICharsetConverterManager.h"
137 : #include "nsEventListenerManager.h"
138 : #include "nsAttrName.h"
139 : #include "nsIDOMUserDataHandler.h"
140 : #include "nsContentCreatorFunctions.h"
141 : #include "nsGUIEvent.h"
142 : #include "nsMutationEvent.h"
143 : #include "nsIMEStateManager.h"
144 : #include "nsContentErrors.h"
145 : #include "nsUnicharUtilCIID.h"
146 : #include "nsCompressedCharMap.h"
147 : #include "nsINativeKeyBindings.h"
148 : #include "nsIDOMNSEvent.h"
149 : #include "nsIPrivateDOMEvent.h"
150 : #include "nsXULPopupManager.h"
151 : #include "nsIPermissionManager.h"
152 : #include "nsIContentPrefService.h"
153 : #include "nsIScriptObjectPrincipal.h"
154 : #include "nsIRunnable.h"
155 : #include "nsDOMJSUtils.h"
156 : #include "nsGenericHTMLElement.h"
157 : #include "nsAttrValue.h"
158 : #include "nsReferencedElement.h"
159 : #include "nsIDragService.h"
160 : #include "nsIChannelEventSink.h"
161 : #include "nsIAsyncVerifyRedirectCallback.h"
162 : #include "nsIInterfaceRequestor.h"
163 : #include "nsIOfflineCacheUpdate.h"
164 : #include "nsCPrefetchService.h"
165 : #include "nsIChromeRegistry.h"
166 : #include "nsEventDispatcher.h"
167 : #include "nsIMIMEHeaderParam.h"
168 : #include "nsIDOMXULCommandEvent.h"
169 : #include "nsIDOMDragEvent.h"
170 : #include "nsDOMDataTransfer.h"
171 : #include "nsHtml5Module.h"
172 : #include "nsPresContext.h"
173 : #include "nsLayoutStatics.h"
174 : #include "nsLayoutUtils.h"
175 : #include "nsFrameManager.h"
176 : #include "BasicLayers.h"
177 : #include "nsFocusManager.h"
178 : #include "nsTextEditorState.h"
179 : #include "nsIPluginHost.h"
180 : #include "nsICategoryManager.h"
181 : #include "nsIViewManager.h"
182 : #include "nsEventStateManager.h"
183 : #include "nsIDOMHTMLInputElement.h"
184 : #include "nsParserConstants.h"
185 :
186 : #ifdef IBMBIDI
187 : #include "nsIBidiKeyboard.h"
188 : #endif
189 : #include "nsCycleCollectionParticipant.h"
190 :
191 : // for ReportToConsole
192 : #include "nsIStringBundle.h"
193 : #include "nsIScriptError.h"
194 : #include "nsIConsoleService.h"
195 :
196 : #include "mozAutoDocUpdate.h"
197 : #include "imgICache.h"
198 : #include "xpcprivate.h" // nsXPConnect
199 : #include "nsScriptSecurityManager.h"
200 : #include "nsIChannelPolicy.h"
201 : #include "nsChannelPolicy.h"
202 : #include "nsIContentSecurityPolicy.h"
203 : #include "nsContentDLF.h"
204 : #ifdef MOZ_MEDIA
205 : #include "nsHTMLMediaElement.h"
206 : #endif
207 : #include "nsDOMTouchEvent.h"
208 : #include "nsIScriptElement.h"
209 : #include "nsIContentViewer.h"
210 : #include "nsIObjectLoadingContent.h"
211 : #include "nsCCUncollectableMarker.h"
212 : #include "mozilla/Base64.h"
213 : #include "mozilla/Preferences.h"
214 :
215 : #include "nsWrapperCacheInlines.h"
216 : #include "nsIDOMDocumentType.h"
217 : #include "nsIDOMWindowUtils.h"
218 : #include "nsCharSeparatedTokenizer.h"
219 : #include "nsUnicharUtils.h"
220 :
221 : using namespace mozilla::dom;
222 : using namespace mozilla::layers;
223 : using namespace mozilla::widget;
224 : using namespace mozilla;
225 :
226 : const char kLoadAsData[] = "loadAsData";
227 :
228 : /**
229 : * Default values for the ViewportInfo structure.
230 : */
231 : static const float kViewportMinScale = 0.0;
232 : static const float kViewportMaxScale = 10.0;
233 : static const PRUint32 kViewportMinWidth = 200;
234 : static const PRUint32 kViewportMaxWidth = 10000;
235 : static const PRUint32 kViewportMinHeight = 223;
236 : static const PRUint32 kViewportMaxHeight = 10000;
237 : static const PRInt32 kViewportDefaultScreenWidth = 980;
238 :
239 : static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
240 : static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
241 : static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
242 :
243 : nsIDOMScriptObjectFactory *nsContentUtils::sDOMScriptObjectFactory = nsnull;
244 : nsIXPConnect *nsContentUtils::sXPConnect;
245 : nsIScriptSecurityManager *nsContentUtils::sSecurityManager;
246 : nsIThreadJSContextStack *nsContentUtils::sThreadJSContextStack;
247 : nsIParserService *nsContentUtils::sParserService = nsnull;
248 : nsINameSpaceManager *nsContentUtils::sNameSpaceManager;
249 : nsIIOService *nsContentUtils::sIOService;
250 : #ifdef MOZ_XTF
251 : nsIXTFService *nsContentUtils::sXTFService = nsnull;
252 : #endif
253 : imgILoader *nsContentUtils::sImgLoader;
254 : imgICache *nsContentUtils::sImgCache;
255 : nsIConsoleService *nsContentUtils::sConsoleService;
256 : nsDataHashtable<nsISupportsHashKey, EventNameMapping>* nsContentUtils::sAtomEventTable = nsnull;
257 : nsDataHashtable<nsStringHashKey, EventNameMapping>* nsContentUtils::sStringEventTable = nsnull;
258 : nsCOMArray<nsIAtom>* nsContentUtils::sUserDefinedEvents = nsnull;
259 : nsIStringBundleService *nsContentUtils::sStringBundleService;
260 : nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT];
261 : nsIContentPolicy *nsContentUtils::sContentPolicyService;
262 : bool nsContentUtils::sTriedToGetContentPolicy = false;
263 : nsILineBreaker *nsContentUtils::sLineBreaker;
264 : nsIWordBreaker *nsContentUtils::sWordBreaker;
265 : nsIScriptRuntime *nsContentUtils::sScriptRuntimes[NS_STID_ARRAY_UBOUND];
266 : PRInt32 nsContentUtils::sScriptRootCount[NS_STID_ARRAY_UBOUND];
267 : PRUint32 nsContentUtils::sJSGCThingRootCount;
268 : #ifdef IBMBIDI
269 : nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nsnull;
270 : #endif
271 : PRUint32 nsContentUtils::sScriptBlockerCount = 0;
272 : #ifdef DEBUG
273 : PRUint32 nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
274 : #endif
275 : nsTArray< nsCOMPtr<nsIRunnable> >* nsContentUtils::sBlockedScriptRunners = nsnull;
276 : PRUint32 nsContentUtils::sRunnersCountAtFirstBlocker = 0;
277 : nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nsnull;
278 :
279 : bool nsContentUtils::sIsHandlingKeyBoardEvent = false;
280 : bool nsContentUtils::sAllowXULXBL_for_file = false;
281 :
282 : nsString* nsContentUtils::sShiftText = nsnull;
283 : nsString* nsContentUtils::sControlText = nsnull;
284 : nsString* nsContentUtils::sMetaText = nsnull;
285 : nsString* nsContentUtils::sAltText = nsnull;
286 : nsString* nsContentUtils::sModifierSeparator = nsnull;
287 :
288 : bool nsContentUtils::sInitialized = false;
289 : bool nsContentUtils::sIsFullScreenApiEnabled = false;
290 : bool nsContentUtils::sTrustedFullScreenOnly = true;
291 : bool nsContentUtils::sFullScreenKeyInputRestricted = true;
292 :
293 : PRUint32 nsContentUtils::sHandlingInputTimeout = 1000;
294 :
295 : nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nsnull;
296 : nsIParser* nsContentUtils::sXMLFragmentParser = nsnull;
297 : nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nsnull;
298 : bool nsContentUtils::sFragmentParsingActive = false;
299 :
300 : static PLDHashTable sEventListenerManagersHash;
301 :
302 : class EventListenerManagerMapEntry : public PLDHashEntryHdr
303 : {
304 : public:
305 2 : EventListenerManagerMapEntry(const void *aKey)
306 2 : : mKey(aKey)
307 : {
308 2 : }
309 :
310 0 : ~EventListenerManagerMapEntry()
311 0 : {
312 0 : NS_ASSERTION(!mListenerManager, "caller must release and disconnect ELM");
313 0 : }
314 :
315 : private:
316 : const void *mKey; // must be first, to look like PLDHashEntryStub
317 :
318 : public:
319 : nsRefPtr<nsEventListenerManager> mListenerManager;
320 : };
321 :
322 : static bool
323 2 : EventListenerManagerHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
324 : const void *key)
325 : {
326 : // Initialize the entry with placement new
327 2 : new (entry) EventListenerManagerMapEntry(key);
328 2 : return true;
329 : }
330 :
331 : static void
332 0 : EventListenerManagerHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
333 : {
334 : EventListenerManagerMapEntry *lm =
335 0 : static_cast<EventListenerManagerMapEntry *>(entry);
336 :
337 : // Let the EventListenerManagerMapEntry clean itself up...
338 0 : lm->~EventListenerManagerMapEntry();
339 0 : }
340 :
341 : class nsSameOriginChecker : public nsIChannelEventSink,
342 : public nsIInterfaceRequestor
343 0 : {
344 : NS_DECL_ISUPPORTS
345 : NS_DECL_NSICHANNELEVENTSINK
346 : NS_DECL_NSIINTERFACEREQUESTOR
347 : };
348 :
349 : /* static */
350 : TimeDuration
351 0 : nsContentUtils::HandlingUserInputTimeout()
352 : {
353 0 : return TimeDuration::FromMilliseconds(sHandlingInputTimeout);
354 : }
355 :
356 : // static
357 : nsresult
358 1404 : nsContentUtils::Init()
359 : {
360 1404 : if (sInitialized) {
361 0 : NS_WARNING("Init() called twice");
362 :
363 0 : return NS_OK;
364 : }
365 :
366 1404 : nsresult rv = NS_GetNameSpaceManager(&sNameSpaceManager);
367 1404 : NS_ENSURE_SUCCESS(rv, rv);
368 :
369 1404 : nsXPConnect* xpconnect = nsXPConnect::GetXPConnect();
370 1404 : NS_ENSURE_TRUE(xpconnect, NS_ERROR_FAILURE);
371 :
372 1404 : sXPConnect = xpconnect;
373 1404 : sThreadJSContextStack = xpconnect;
374 :
375 1404 : sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager();
376 1404 : if(!sSecurityManager)
377 0 : return NS_ERROR_FAILURE;
378 1404 : NS_ADDREF(sSecurityManager);
379 :
380 1404 : rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
381 1404 : if (NS_FAILED(rv)) {
382 : // This makes life easier, but we can live without it.
383 :
384 0 : sIOService = nsnull;
385 : }
386 :
387 1404 : rv = CallGetService(NS_LBRK_CONTRACTID, &sLineBreaker);
388 1404 : NS_ENSURE_SUCCESS(rv, rv);
389 :
390 1404 : rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker);
391 1404 : NS_ENSURE_SUCCESS(rv, rv);
392 :
393 1404 : if (!InitializeEventTable())
394 0 : return NS_ERROR_FAILURE;
395 :
396 1404 : if (!sEventListenerManagersHash.ops) {
397 : static PLDHashTableOps hash_table_ops =
398 : {
399 : PL_DHashAllocTable,
400 : PL_DHashFreeTable,
401 : PL_DHashVoidPtrKeyStub,
402 : PL_DHashMatchEntryStub,
403 : PL_DHashMoveEntryStub,
404 : EventListenerManagerHashClearEntry,
405 : PL_DHashFinalizeStub,
406 : EventListenerManagerHashInitEntry
407 : };
408 :
409 1404 : if (!PL_DHashTableInit(&sEventListenerManagersHash, &hash_table_ops,
410 1404 : nsnull, sizeof(EventListenerManagerMapEntry), 16)) {
411 0 : sEventListenerManagersHash.ops = nsnull;
412 :
413 0 : return NS_ERROR_OUT_OF_MEMORY;
414 : }
415 : }
416 :
417 1404 : sBlockedScriptRunners = new nsTArray< nsCOMPtr<nsIRunnable> >;
418 :
419 : Preferences::AddBoolVarCache(&sAllowXULXBL_for_file,
420 1404 : "dom.allow_XUL_XBL_for_file");
421 :
422 : Preferences::AddBoolVarCache(&sIsFullScreenApiEnabled,
423 1404 : "full-screen-api.enabled");
424 :
425 : Preferences::AddBoolVarCache(&sTrustedFullScreenOnly,
426 1404 : "full-screen-api.allow-trusted-requests-only");
427 :
428 : Preferences::AddBoolVarCache(&sFullScreenKeyInputRestricted,
429 1404 : "full-screen-api.key-input-restricted");
430 :
431 : Preferences::AddUintVarCache(&sHandlingInputTimeout,
432 : "dom.event.handling-user-input-time-limit",
433 1404 : 1000);
434 :
435 1404 : nsGenericElement::InitCCCallbacks();
436 :
437 1404 : sInitialized = true;
438 :
439 1404 : return NS_OK;
440 : }
441 :
442 : void
443 0 : nsContentUtils::GetShiftText(nsAString& text)
444 : {
445 0 : if (!sShiftText)
446 0 : InitializeModifierStrings();
447 0 : text.Assign(*sShiftText);
448 0 : }
449 :
450 : void
451 0 : nsContentUtils::GetControlText(nsAString& text)
452 : {
453 0 : if (!sControlText)
454 0 : InitializeModifierStrings();
455 0 : text.Assign(*sControlText);
456 0 : }
457 :
458 : void
459 0 : nsContentUtils::GetMetaText(nsAString& text)
460 : {
461 0 : if (!sMetaText)
462 0 : InitializeModifierStrings();
463 0 : text.Assign(*sMetaText);
464 0 : }
465 :
466 : void
467 0 : nsContentUtils::GetAltText(nsAString& text)
468 : {
469 0 : if (!sAltText)
470 0 : InitializeModifierStrings();
471 0 : text.Assign(*sAltText);
472 0 : }
473 :
474 : void
475 0 : nsContentUtils::GetModifierSeparatorText(nsAString& text)
476 : {
477 0 : if (!sModifierSeparator)
478 0 : InitializeModifierStrings();
479 0 : text.Assign(*sModifierSeparator);
480 0 : }
481 :
482 : void
483 0 : nsContentUtils::InitializeModifierStrings()
484 : {
485 : //load the display strings for the keyboard accelerators
486 : nsCOMPtr<nsIStringBundleService> bundleService =
487 0 : mozilla::services::GetStringBundleService();
488 0 : nsCOMPtr<nsIStringBundle> bundle;
489 0 : nsresult rv = NS_OK;
490 0 : if (bundleService) {
491 0 : rv = bundleService->CreateBundle( "chrome://global-platform/locale/platformKeys.properties",
492 0 : getter_AddRefs(bundle));
493 : }
494 :
495 0 : NS_ASSERTION(NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/platformKeys.properties could not be loaded");
496 0 : nsXPIDLString shiftModifier;
497 0 : nsXPIDLString metaModifier;
498 0 : nsXPIDLString altModifier;
499 0 : nsXPIDLString controlModifier;
500 0 : nsXPIDLString modifierSeparator;
501 0 : if (bundle) {
502 : //macs use symbols for each modifier key, so fetch each from the bundle, which also covers i18n
503 0 : bundle->GetStringFromName(NS_LITERAL_STRING("VK_SHIFT").get(), getter_Copies(shiftModifier));
504 0 : bundle->GetStringFromName(NS_LITERAL_STRING("VK_META").get(), getter_Copies(metaModifier));
505 0 : bundle->GetStringFromName(NS_LITERAL_STRING("VK_ALT").get(), getter_Copies(altModifier));
506 0 : bundle->GetStringFromName(NS_LITERAL_STRING("VK_CONTROL").get(), getter_Copies(controlModifier));
507 0 : bundle->GetStringFromName(NS_LITERAL_STRING("MODIFIER_SEPARATOR").get(), getter_Copies(modifierSeparator));
508 : }
509 : //if any of these don't exist, we get an empty string
510 0 : sShiftText = new nsString(shiftModifier);
511 0 : sMetaText = new nsString(metaModifier);
512 0 : sAltText = new nsString(altModifier);
513 0 : sControlText = new nsString(controlModifier);
514 0 : sModifierSeparator = new nsString(modifierSeparator);
515 0 : }
516 :
517 : bool nsContentUtils::sImgLoaderInitialized;
518 :
519 : void
520 1 : nsContentUtils::InitImgLoader()
521 : {
522 1 : sImgLoaderInitialized = true;
523 :
524 : // Ignore failure and just don't load images
525 1 : nsresult rv = CallGetService("@mozilla.org/image/loader;1", &sImgLoader);
526 1 : if (NS_FAILED(rv)) {
527 : // no image loading for us. Oh, well.
528 0 : sImgLoader = nsnull;
529 0 : sImgCache = nsnull;
530 : } else {
531 1 : if (NS_FAILED(CallGetService("@mozilla.org/image/cache;1", &sImgCache )))
532 0 : sImgCache = nsnull;
533 : }
534 1 : }
535 :
536 : bool
537 1404 : nsContentUtils::InitializeEventTable() {
538 1404 : NS_ASSERTION(!sAtomEventTable, "EventTable already initialized!");
539 1404 : NS_ASSERTION(!sStringEventTable, "EventTable already initialized!");
540 :
541 : static const EventNameMapping eventArray[] = {
542 : #define EVENT(name_, _id, _type, _struct) \
543 : { nsGkAtoms::on##name_, _id, _type, _struct },
544 : #define WINDOW_ONLY_EVENT EVENT
545 : #define NON_IDL_EVENT EVENT
546 : #include "nsEventNameList.h"
547 : #undef WINDOW_ONLY_EVENT
548 : #undef EVENT
549 : { nsnull }
550 1404 : };
551 :
552 1404 : sAtomEventTable = new nsDataHashtable<nsISupportsHashKey, EventNameMapping>;
553 1404 : sStringEventTable = new nsDataHashtable<nsStringHashKey, EventNameMapping>;
554 1404 : sUserDefinedEvents = new nsCOMArray<nsIAtom>(64);
555 :
556 4212 : if (!sAtomEventTable || !sStringEventTable || !sUserDefinedEvents ||
557 1404 : !sAtomEventTable->Init(int(ArrayLength(eventArray) / 0.75) + 1) ||
558 1404 : !sStringEventTable->Init(int(ArrayLength(eventArray) / 0.75) + 1)) {
559 0 : delete sAtomEventTable;
560 0 : sAtomEventTable = nsnull;
561 0 : delete sStringEventTable;
562 0 : sStringEventTable = nsnull;
563 0 : delete sUserDefinedEvents;
564 0 : sUserDefinedEvents = nsnull;
565 0 : return false;
566 : }
567 :
568 : // Subtract one from the length because of the trailing null
569 196560 : for (PRUint32 i = 0; i < ArrayLength(eventArray) - 1; ++i) {
570 780624 : if (!sAtomEventTable->Put(eventArray[i].mAtom, eventArray[i]) ||
571 390312 : !sStringEventTable->Put(Substring(nsDependentAtomString(eventArray[i].mAtom), 2),
572 780624 : eventArray[i])) {
573 0 : delete sAtomEventTable;
574 0 : sAtomEventTable = nsnull;
575 0 : delete sStringEventTable;
576 0 : sStringEventTable = nsnull;
577 0 : return false;
578 : }
579 : }
580 :
581 1404 : return true;
582 : }
583 :
584 : void
585 0 : nsContentUtils::InitializeTouchEventTable()
586 : {
587 : static bool sEventTableInitialized = false;
588 0 : if (!sEventTableInitialized && sAtomEventTable && sStringEventTable) {
589 0 : sEventTableInitialized = true;
590 : static const EventNameMapping touchEventArray[] = {
591 : #define EVENT(name_, _id, _type, _struct)
592 : #define TOUCH_EVENT(name_, _id, _type, _struct) \
593 : { nsGkAtoms::on##name_, _id, _type, _struct },
594 : #include "nsEventNameList.h"
595 : #undef TOUCH_EVENT
596 : #undef EVENT
597 : { nsnull }
598 0 : };
599 : // Subtract one from the length because of the trailing null
600 0 : for (PRUint32 i = 0; i < ArrayLength(touchEventArray) - 1; ++i) {
601 0 : if (!sAtomEventTable->Put(touchEventArray[i].mAtom, touchEventArray[i]) ||
602 0 : !sStringEventTable->Put(Substring(nsDependentAtomString(touchEventArray[i].mAtom), 2),
603 0 : touchEventArray[i])) {
604 0 : delete sAtomEventTable;
605 0 : sAtomEventTable = nsnull;
606 0 : delete sStringEventTable;
607 0 : sStringEventTable = nsnull;
608 0 : return;
609 : }
610 : }
611 : }
612 : }
613 :
614 : static bool
615 0 : Is8bit(const nsAString& aString)
616 : {
617 : static const PRUnichar EIGHT_BIT = PRUnichar(~0x00FF);
618 :
619 0 : nsAString::const_iterator done_reading;
620 0 : aString.EndReading(done_reading);
621 :
622 : // for each chunk of |aString|...
623 0 : PRUint32 fragmentLength = 0;
624 0 : nsAString::const_iterator iter;
625 0 : for (aString.BeginReading(iter); iter != done_reading;
626 0 : iter.advance(PRInt32(fragmentLength))) {
627 0 : fragmentLength = PRUint32(iter.size_forward());
628 0 : const PRUnichar* c = iter.get();
629 0 : const PRUnichar* fragmentEnd = c + fragmentLength;
630 :
631 : // for each character in this chunk...
632 0 : while (c < fragmentEnd) {
633 0 : if (*c++ & EIGHT_BIT) {
634 0 : return false;
635 : }
636 : }
637 : }
638 :
639 0 : return true;
640 : }
641 :
642 : nsresult
643 0 : nsContentUtils::Btoa(const nsAString& aBinaryData,
644 : nsAString& aAsciiBase64String)
645 : {
646 0 : if (!Is8bit(aBinaryData)) {
647 0 : aAsciiBase64String.Truncate();
648 0 : return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
649 : }
650 :
651 0 : return Base64Encode(aBinaryData, aAsciiBase64String);
652 : }
653 :
654 : nsresult
655 0 : nsContentUtils::Atob(const nsAString& aAsciiBase64String,
656 : nsAString& aBinaryData)
657 : {
658 0 : if (!Is8bit(aAsciiBase64String)) {
659 0 : aBinaryData.Truncate();
660 0 : return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
661 : }
662 :
663 0 : nsresult rv = Base64Decode(aAsciiBase64String, aBinaryData);
664 0 : if (NS_FAILED(rv) && rv == NS_ERROR_INVALID_ARG) {
665 0 : return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
666 : }
667 0 : return rv;
668 : }
669 :
670 : bool
671 0 : nsContentUtils::IsAutocompleteEnabled(nsIDOMHTMLInputElement* aInput)
672 : {
673 0 : NS_PRECONDITION(aInput, "aInput should not be null!");
674 :
675 0 : nsAutoString autocomplete;
676 0 : aInput->GetAutocomplete(autocomplete);
677 :
678 0 : if (autocomplete.IsEmpty()) {
679 0 : nsCOMPtr<nsIDOMHTMLFormElement> form;
680 0 : aInput->GetForm(getter_AddRefs(form));
681 0 : if (!form) {
682 0 : return true;
683 : }
684 :
685 0 : form->GetAutocomplete(autocomplete);
686 : }
687 :
688 0 : return autocomplete.EqualsLiteral("on");
689 : }
690 :
691 : bool
692 0 : nsContentUtils::URIIsChromeOrInPref(nsIURI *aURI, const char *aPref)
693 : {
694 0 : if (!aURI) {
695 0 : return false;
696 : }
697 :
698 0 : nsCAutoString scheme;
699 0 : aURI->GetScheme(scheme);
700 0 : if (scheme.EqualsLiteral("chrome")) {
701 0 : return true;
702 : }
703 :
704 0 : nsCAutoString prePathUTF8;
705 0 : aURI->GetPrePath(prePathUTF8);
706 0 : NS_ConvertUTF8toUTF16 prePath(prePathUTF8);
707 :
708 0 : const nsAdoptingString& whitelist = Preferences::GetString(aPref);
709 :
710 : // This tokenizer also strips off whitespace around tokens, as desired.
711 : nsCharSeparatedTokenizer tokenizer(whitelist, ',',
712 0 : nsCharSeparatedTokenizerTemplate<>::SEPARATOR_OPTIONAL);
713 :
714 0 : while (tokenizer.hasMoreTokens()) {
715 0 : const nsSubstring& whitelistItem = tokenizer.nextToken();
716 :
717 0 : if (whitelistItem.Equals(prePath, nsCaseInsensitiveStringComparator())) {
718 0 : return true;
719 : }
720 : }
721 :
722 0 : return false;
723 : }
724 :
725 : #define SKIP_WHITESPACE(iter, end_iter, end_res) \
726 : while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \
727 : ++(iter); \
728 : } \
729 : if ((iter) == (end_iter)) { \
730 : return (end_res); \
731 : }
732 :
733 : #define SKIP_ATTR_NAME(iter, end_iter) \
734 : while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \
735 : *(iter) != '=') { \
736 : ++(iter); \
737 : }
738 :
739 : bool
740 112 : nsContentUtils::GetPseudoAttributeValue(const nsString& aSource, nsIAtom *aName,
741 : nsAString& aValue)
742 : {
743 112 : aValue.Truncate();
744 :
745 112 : const PRUnichar *start = aSource.get();
746 112 : const PRUnichar *end = start + aSource.Length();
747 : const PRUnichar *iter;
748 :
749 286 : while (start != end) {
750 154 : SKIP_WHITESPACE(start, end, false)
751 154 : iter = start;
752 154 : SKIP_ATTR_NAME(iter, end)
753 :
754 154 : if (start == iter) {
755 0 : return false;
756 : }
757 :
758 : // Remember the attr name.
759 308 : const nsDependentSubstring & attrName = Substring(start, iter);
760 :
761 : // Now check whether this is a valid name="value" pair.
762 154 : start = iter;
763 154 : SKIP_WHITESPACE(start, end, false)
764 130 : if (*start != '=') {
765 : // No '=', so this is not a name="value" pair. We don't know
766 : // what it is, and we have no way to handle it.
767 6 : return false;
768 : }
769 :
770 : // Have to skip the value.
771 124 : ++start;
772 124 : SKIP_WHITESPACE(start, end, false)
773 124 : PRUnichar q = *start;
774 124 : if (q != kQuote && q != kApostrophe) {
775 : // Not a valid quoted value, so bail.
776 0 : return false;
777 : }
778 :
779 124 : ++start; // Point to the first char of the value.
780 124 : iter = start;
781 :
782 2666 : while (iter != end && *iter != q) {
783 2418 : ++iter;
784 : }
785 :
786 124 : if (iter == end) {
787 : // Oops, unterminated quoted string.
788 0 : return false;
789 : }
790 :
791 : // At this point attrName holds the name of the "attribute" and
792 : // the value is between start and iter.
793 :
794 124 : if (aName->Equals(attrName)) {
795 62 : nsIParserService* parserService = nsContentUtils::GetParserService();
796 62 : NS_ENSURE_TRUE(parserService, false);
797 :
798 : // We'll accumulate as many characters as possible (until we hit either
799 : // the end of the string or the beginning of an entity). Chunks will be
800 : // delimited by start and chunkEnd.
801 62 : const PRUnichar *chunkEnd = start;
802 620 : while (chunkEnd != iter) {
803 496 : if (*chunkEnd == kLessThan) {
804 0 : aValue.Truncate();
805 :
806 0 : return false;
807 : }
808 :
809 496 : if (*chunkEnd == kAmpersand) {
810 0 : aValue.Append(start, chunkEnd - start);
811 :
812 : // Point to first character after the ampersand.
813 0 : ++chunkEnd;
814 :
815 : const PRUnichar *afterEntity;
816 : PRUnichar result[2];
817 : PRUint32 count =
818 0 : parserService->DecodeEntity(chunkEnd, iter, &afterEntity, result);
819 0 : if (count == 0) {
820 0 : aValue.Truncate();
821 :
822 0 : return false;
823 : }
824 :
825 0 : aValue.Append(result, count);
826 :
827 : // Advance to after the entity and begin a new chunk.
828 0 : start = chunkEnd = afterEntity;
829 : }
830 : else {
831 496 : ++chunkEnd;
832 : }
833 : }
834 :
835 : // Append remainder.
836 62 : aValue.Append(start, iter - start);
837 :
838 62 : return true;
839 : }
840 :
841 : // Resume scanning after the end of the attribute value (past the quote
842 : // char).
843 216 : start = iter + 1;
844 : }
845 :
846 20 : return false;
847 : }
848 :
849 : bool
850 0 : nsContentUtils::IsJavaScriptLanguage(const nsString& aName, PRUint32 *aFlags)
851 : {
852 0 : JSVersion version = JSVERSION_UNKNOWN;
853 :
854 0 : if (aName.LowerCaseEqualsLiteral("javascript") ||
855 0 : aName.LowerCaseEqualsLiteral("livescript") ||
856 0 : aName.LowerCaseEqualsLiteral("mocha")) {
857 0 : version = JSVERSION_DEFAULT;
858 0 : } else if (aName.LowerCaseEqualsLiteral("javascript1.0")) {
859 0 : version = JSVERSION_1_0;
860 0 : } else if (aName.LowerCaseEqualsLiteral("javascript1.1")) {
861 0 : version = JSVERSION_1_1;
862 0 : } else if (aName.LowerCaseEqualsLiteral("javascript1.2")) {
863 0 : version = JSVERSION_1_2;
864 0 : } else if (aName.LowerCaseEqualsLiteral("javascript1.3")) {
865 0 : version = JSVERSION_1_3;
866 0 : } else if (aName.LowerCaseEqualsLiteral("javascript1.4")) {
867 0 : version = JSVERSION_1_4;
868 0 : } else if (aName.LowerCaseEqualsLiteral("javascript1.5")) {
869 0 : version = JSVERSION_1_5;
870 0 : } else if (aName.LowerCaseEqualsLiteral("javascript1.6")) {
871 0 : version = JSVERSION_1_6;
872 0 : } else if (aName.LowerCaseEqualsLiteral("javascript1.7")) {
873 0 : version = JSVERSION_1_7;
874 0 : } else if (aName.LowerCaseEqualsLiteral("javascript1.8")) {
875 0 : version = JSVERSION_1_8;
876 : }
877 :
878 0 : if (version == JSVERSION_UNKNOWN) {
879 0 : return false;
880 : }
881 0 : *aFlags = version;
882 0 : return true;
883 : }
884 :
885 : void
886 0 : nsContentUtils::SplitMimeType(const nsAString& aValue, nsString& aType,
887 : nsString& aParams)
888 : {
889 0 : aType.Truncate();
890 0 : aParams.Truncate();
891 0 : PRInt32 semiIndex = aValue.FindChar(PRUnichar(';'));
892 0 : if (-1 != semiIndex) {
893 0 : aType = Substring(aValue, 0, semiIndex);
894 : aParams = Substring(aValue, semiIndex + 1,
895 0 : aValue.Length() - (semiIndex + 1));
896 0 : aParams.StripWhitespace();
897 : }
898 : else {
899 0 : aType = aValue;
900 : }
901 0 : aType.StripWhitespace();
902 0 : }
903 :
904 : /**
905 : * Access a cached parser service. Don't addref. We need only one
906 : * reference to it and this class has that one.
907 : */
908 : /* static */
909 : nsIParserService*
910 2966 : nsContentUtils::GetParserService()
911 : {
912 : // XXX: This isn't accessed from several threads, is it?
913 2966 : if (!sParserService) {
914 : // Lock, recheck sCachedParserService and aquire if this should be
915 : // safe for multiple threads.
916 36 : nsresult rv = CallGetService(kParserServiceCID, &sParserService);
917 36 : if (NS_FAILED(rv)) {
918 0 : sParserService = nsnull;
919 : }
920 : }
921 :
922 2966 : return sParserService;
923 : }
924 :
925 : #ifdef MOZ_XTF
926 : nsIXTFService*
927 19537 : nsContentUtils::GetXTFService()
928 : {
929 19537 : if (!sXTFService) {
930 236 : nsresult rv = CallGetService(kXTFServiceCID, &sXTFService);
931 236 : if (NS_FAILED(rv)) {
932 0 : sXTFService = nsnull;
933 : }
934 : }
935 :
936 19537 : return sXTFService;
937 : }
938 : #endif
939 :
940 : #ifdef IBMBIDI
941 : nsIBidiKeyboard*
942 0 : nsContentUtils::GetBidiKeyboard()
943 : {
944 0 : if (!sBidiKeyboard) {
945 0 : nsresult rv = CallGetService("@mozilla.org/widget/bidikeyboard;1", &sBidiKeyboard);
946 0 : if (NS_FAILED(rv)) {
947 0 : sBidiKeyboard = nsnull;
948 : }
949 : }
950 0 : return sBidiKeyboard;
951 : }
952 : #endif
953 :
954 : template <class OutputIterator>
955 : struct NormalizeNewlinesCharTraits {
956 : public:
957 : typedef typename OutputIterator::value_type value_type;
958 :
959 : public:
960 0 : NormalizeNewlinesCharTraits(OutputIterator& aIterator) : mIterator(aIterator) { }
961 0 : void writechar(typename OutputIterator::value_type aChar) {
962 0 : *mIterator++ = aChar;
963 0 : }
964 :
965 : private:
966 : OutputIterator mIterator;
967 : };
968 :
969 : #ifdef HAVE_CPP_PARTIAL_SPECIALIZATION
970 :
971 : template <class CharT>
972 : struct NormalizeNewlinesCharTraits<CharT*> {
973 : public:
974 : typedef CharT value_type;
975 :
976 : public:
977 0 : NormalizeNewlinesCharTraits(CharT* aCharPtr) : mCharPtr(aCharPtr) { }
978 0 : void writechar(CharT aChar) {
979 0 : *mCharPtr++ = aChar;
980 0 : }
981 :
982 : private:
983 : CharT* mCharPtr;
984 : };
985 :
986 : #else
987 :
988 : template <>
989 : struct NormalizeNewlinesCharTraits<char*> {
990 : public:
991 : typedef char value_type;
992 :
993 : public:
994 : NormalizeNewlinesCharTraits(char* aCharPtr) : mCharPtr(aCharPtr) { }
995 : void writechar(char aChar) {
996 : *mCharPtr++ = aChar;
997 : }
998 :
999 : private:
1000 : char* mCharPtr;
1001 : };
1002 :
1003 : template <>
1004 : struct NormalizeNewlinesCharTraits<PRUnichar*> {
1005 : public:
1006 : typedef PRUnichar value_type;
1007 :
1008 : public:
1009 : NormalizeNewlinesCharTraits(PRUnichar* aCharPtr) : mCharPtr(aCharPtr) { }
1010 : void writechar(PRUnichar aChar) {
1011 : *mCharPtr++ = aChar;
1012 : }
1013 :
1014 : private:
1015 : PRUnichar* mCharPtr;
1016 : };
1017 :
1018 : #endif
1019 :
1020 : template <class OutputIterator>
1021 : class CopyNormalizeNewlines
1022 : {
1023 : public:
1024 : typedef typename OutputIterator::value_type value_type;
1025 :
1026 : public:
1027 0 : CopyNormalizeNewlines(OutputIterator* aDestination,
1028 : bool aLastCharCR=false) :
1029 : mLastCharCR(aLastCharCR),
1030 : mDestination(aDestination),
1031 0 : mWritten(0)
1032 0 : { }
1033 :
1034 0 : PRUint32 GetCharsWritten() {
1035 0 : return mWritten;
1036 : }
1037 :
1038 0 : bool IsLastCharCR() {
1039 0 : return mLastCharCR;
1040 : }
1041 :
1042 0 : void write(const typename OutputIterator::value_type* aSource, PRUint32 aSourceLength) {
1043 :
1044 0 : const typename OutputIterator::value_type* done_writing = aSource + aSourceLength;
1045 :
1046 : // If the last source buffer ended with a CR...
1047 0 : if (mLastCharCR) {
1048 : // ..and if the next one is a LF, then skip it since
1049 : // we've already written out a newline
1050 0 : if (aSourceLength && (*aSource == value_type('\n'))) {
1051 0 : ++aSource;
1052 : }
1053 0 : mLastCharCR = false;
1054 : }
1055 :
1056 0 : PRUint32 num_written = 0;
1057 0 : while ( aSource < done_writing ) {
1058 0 : if (*aSource == value_type('\r')) {
1059 0 : mDestination->writechar('\n');
1060 0 : ++aSource;
1061 : // If we've reached the end of the buffer, record
1062 : // that we wrote out a CR
1063 0 : if (aSource == done_writing) {
1064 0 : mLastCharCR = true;
1065 : }
1066 : // If the next character is a LF, skip it
1067 0 : else if (*aSource == value_type('\n')) {
1068 0 : ++aSource;
1069 : }
1070 : }
1071 : else {
1072 0 : mDestination->writechar(*aSource++);
1073 : }
1074 0 : ++num_written;
1075 : }
1076 :
1077 0 : mWritten += num_written;
1078 0 : }
1079 :
1080 : private:
1081 : bool mLastCharCR;
1082 : OutputIterator* mDestination;
1083 : PRUint32 mWritten;
1084 : };
1085 :
1086 : // static
1087 : PRUint32
1088 0 : nsContentUtils::CopyNewlineNormalizedUnicodeTo(const nsAString& aSource,
1089 : PRUint32 aSrcOffset,
1090 : PRUnichar* aDest,
1091 : PRUint32 aLength,
1092 : bool& aLastCharCR)
1093 : {
1094 : typedef NormalizeNewlinesCharTraits<PRUnichar*> sink_traits;
1095 :
1096 0 : sink_traits dest_traits(aDest);
1097 0 : CopyNormalizeNewlines<sink_traits> normalizer(&dest_traits,aLastCharCR);
1098 0 : nsReadingIterator<PRUnichar> fromBegin, fromEnd;
1099 0 : copy_string(aSource.BeginReading(fromBegin).advance( PRInt32(aSrcOffset) ),
1100 0 : aSource.BeginReading(fromEnd).advance( PRInt32(aSrcOffset+aLength) ),
1101 0 : normalizer);
1102 0 : aLastCharCR = normalizer.IsLastCharCR();
1103 0 : return normalizer.GetCharsWritten();
1104 : }
1105 :
1106 : // static
1107 : PRUint32
1108 0 : nsContentUtils::CopyNewlineNormalizedUnicodeTo(nsReadingIterator<PRUnichar>& aSrcStart, const nsReadingIterator<PRUnichar>& aSrcEnd, nsAString& aDest)
1109 : {
1110 : typedef nsWritingIterator<PRUnichar> WritingIterator;
1111 : typedef NormalizeNewlinesCharTraits<WritingIterator> sink_traits;
1112 :
1113 0 : WritingIterator iter;
1114 0 : aDest.BeginWriting(iter);
1115 0 : sink_traits dest_traits(iter);
1116 0 : CopyNormalizeNewlines<sink_traits> normalizer(&dest_traits);
1117 0 : copy_string(aSrcStart, aSrcEnd, normalizer);
1118 0 : return normalizer.GetCharsWritten();
1119 : }
1120 :
1121 : /**
1122 : * This is used to determine whether a character is in one of the punctuation
1123 : * mark classes which CSS says should be part of the first-letter.
1124 : * See http://www.w3.org/TR/CSS2/selector.html#first-letter and
1125 : * http://www.w3.org/TR/selectors/#first-letter
1126 : */
1127 :
1128 : // static
1129 : bool
1130 0 : nsContentUtils::IsFirstLetterPunctuation(PRUint32 aChar)
1131 : {
1132 0 : PRUint8 cat = mozilla::unicode::GetGeneralCategory(aChar);
1133 :
1134 : return (cat == HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION || // Ps
1135 : cat == HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION || // Pe
1136 : cat == HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION || // Pi
1137 : cat == HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION || // Pf
1138 0 : cat == HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION); // Po
1139 : }
1140 :
1141 : // static
1142 : bool
1143 0 : nsContentUtils::IsFirstLetterPunctuationAt(const nsTextFragment* aFrag, PRUint32 aOffset)
1144 : {
1145 0 : PRUnichar h = aFrag->CharAt(aOffset);
1146 0 : if (!IS_SURROGATE(h)) {
1147 0 : return IsFirstLetterPunctuation(h);
1148 : }
1149 0 : if (NS_IS_HIGH_SURROGATE(h) && aOffset + 1 < aFrag->GetLength()) {
1150 0 : PRUnichar l = aFrag->CharAt(aOffset + 1);
1151 0 : if (NS_IS_LOW_SURROGATE(l)) {
1152 0 : return IsFirstLetterPunctuation(SURROGATE_TO_UCS4(h, l));
1153 : }
1154 : }
1155 0 : return false;
1156 : }
1157 :
1158 : // static
1159 0 : bool nsContentUtils::IsAlphanumeric(PRUint32 aChar)
1160 : {
1161 0 : nsIUGenCategory::nsUGenCategory cat = mozilla::unicode::GetGenCategory(aChar);
1162 :
1163 0 : return (cat == nsIUGenCategory::kLetter || cat == nsIUGenCategory::kNumber);
1164 : }
1165 :
1166 : // static
1167 0 : bool nsContentUtils::IsAlphanumericAt(const nsTextFragment* aFrag, PRUint32 aOffset)
1168 : {
1169 0 : PRUnichar h = aFrag->CharAt(aOffset);
1170 0 : if (!IS_SURROGATE(h)) {
1171 0 : return IsAlphanumeric(h);
1172 : }
1173 0 : if (NS_IS_HIGH_SURROGATE(h) && aOffset + 1 < aFrag->GetLength()) {
1174 0 : PRUnichar l = aFrag->CharAt(aOffset + 1);
1175 0 : if (NS_IS_LOW_SURROGATE(l)) {
1176 0 : return IsAlphanumeric(SURROGATE_TO_UCS4(h, l));
1177 : }
1178 : }
1179 0 : return false;
1180 : }
1181 :
1182 : /* static */
1183 : bool
1184 0 : nsContentUtils::IsHTMLWhitespace(PRUnichar aChar)
1185 : {
1186 : return aChar == PRUnichar(0x0009) ||
1187 : aChar == PRUnichar(0x000A) ||
1188 : aChar == PRUnichar(0x000C) ||
1189 : aChar == PRUnichar(0x000D) ||
1190 0 : aChar == PRUnichar(0x0020);
1191 : }
1192 :
1193 : /* static */
1194 : bool
1195 1059 : nsContentUtils::IsHTMLBlock(nsIAtom* aLocalName)
1196 : {
1197 : return
1198 : (aLocalName == nsGkAtoms::address) ||
1199 : (aLocalName == nsGkAtoms::article) ||
1200 : (aLocalName == nsGkAtoms::aside) ||
1201 : (aLocalName == nsGkAtoms::blockquote) ||
1202 : (aLocalName == nsGkAtoms::center) ||
1203 : (aLocalName == nsGkAtoms::dir) ||
1204 : (aLocalName == nsGkAtoms::div) ||
1205 : (aLocalName == nsGkAtoms::dl) || // XXX why not dt and dd?
1206 : (aLocalName == nsGkAtoms::fieldset) ||
1207 : (aLocalName == nsGkAtoms::figure) || // XXX shouldn't figcaption be on this list
1208 : (aLocalName == nsGkAtoms::footer) ||
1209 : (aLocalName == nsGkAtoms::form) ||
1210 : (aLocalName == nsGkAtoms::h1) ||
1211 : (aLocalName == nsGkAtoms::h2) ||
1212 : (aLocalName == nsGkAtoms::h3) ||
1213 : (aLocalName == nsGkAtoms::h4) ||
1214 : (aLocalName == nsGkAtoms::h5) ||
1215 : (aLocalName == nsGkAtoms::h6) ||
1216 : (aLocalName == nsGkAtoms::header) ||
1217 : (aLocalName == nsGkAtoms::hgroup) ||
1218 : (aLocalName == nsGkAtoms::hr) ||
1219 : (aLocalName == nsGkAtoms::li) ||
1220 : (aLocalName == nsGkAtoms::listing) ||
1221 : (aLocalName == nsGkAtoms::menu) ||
1222 : (aLocalName == nsGkAtoms::multicol) || // XXX get rid of this one?
1223 : (aLocalName == nsGkAtoms::nav) ||
1224 : (aLocalName == nsGkAtoms::ol) ||
1225 : (aLocalName == nsGkAtoms::p) ||
1226 : (aLocalName == nsGkAtoms::pre) ||
1227 : (aLocalName == nsGkAtoms::section) ||
1228 : (aLocalName == nsGkAtoms::table) ||
1229 : (aLocalName == nsGkAtoms::ul) ||
1230 1059 : (aLocalName == nsGkAtoms::xmp);
1231 : }
1232 :
1233 : /* static */
1234 : bool
1235 1560 : nsContentUtils::IsHTMLVoid(nsIAtom* aLocalName)
1236 : {
1237 : return
1238 : (aLocalName == nsGkAtoms::area) ||
1239 : (aLocalName == nsGkAtoms::base) ||
1240 : (aLocalName == nsGkAtoms::basefont) ||
1241 : (aLocalName == nsGkAtoms::bgsound) ||
1242 : (aLocalName == nsGkAtoms::br) ||
1243 : (aLocalName == nsGkAtoms::col) ||
1244 : (aLocalName == nsGkAtoms::command) ||
1245 : (aLocalName == nsGkAtoms::embed) ||
1246 : (aLocalName == nsGkAtoms::frame) ||
1247 : (aLocalName == nsGkAtoms::hr) ||
1248 : (aLocalName == nsGkAtoms::img) ||
1249 : (aLocalName == nsGkAtoms::input) ||
1250 : (aLocalName == nsGkAtoms::keygen) ||
1251 : (aLocalName == nsGkAtoms::link) ||
1252 : (aLocalName == nsGkAtoms::meta) ||
1253 : (aLocalName == nsGkAtoms::param) ||
1254 : (aLocalName == nsGkAtoms::source) ||
1255 : (aLocalName == nsGkAtoms::track) ||
1256 1560 : (aLocalName == nsGkAtoms::wbr);
1257 : }
1258 :
1259 : /* static */
1260 : bool
1261 0 : nsContentUtils::ParseIntMarginValue(const nsAString& aString, nsIntMargin& result)
1262 : {
1263 0 : nsAutoString marginStr(aString);
1264 0 : marginStr.CompressWhitespace(true, true);
1265 0 : if (marginStr.IsEmpty()) {
1266 0 : return false;
1267 : }
1268 :
1269 0 : PRInt32 start = 0, end = 0;
1270 0 : for (int count = 0; count < 4; count++) {
1271 0 : if ((PRUint32)end >= marginStr.Length())
1272 0 : return false;
1273 :
1274 : // top, right, bottom, left
1275 0 : if (count < 3)
1276 0 : end = Substring(marginStr, start).FindChar(',');
1277 : else
1278 0 : end = Substring(marginStr, start).Length();
1279 :
1280 0 : if (end <= 0)
1281 0 : return false;
1282 :
1283 : PRInt32 ec, val =
1284 0 : nsString(Substring(marginStr, start, end)).ToInteger(&ec);
1285 0 : if (NS_FAILED(ec))
1286 0 : return false;
1287 :
1288 0 : switch(count) {
1289 : case 0:
1290 0 : result.top = val;
1291 0 : break;
1292 : case 1:
1293 0 : result.right = val;
1294 0 : break;
1295 : case 2:
1296 0 : result.bottom = val;
1297 0 : break;
1298 : case 3:
1299 0 : result.left = val;
1300 0 : break;
1301 : }
1302 0 : start += end + 1;
1303 : }
1304 0 : return true;
1305 : }
1306 :
1307 : /* static */
1308 : void
1309 0 : nsContentUtils::GetOfflineAppManifest(nsIDocument *aDocument, nsIURI **aURI)
1310 : {
1311 0 : Element* docElement = aDocument->GetRootElement();
1312 0 : if (!docElement) {
1313 0 : return;
1314 : }
1315 :
1316 0 : nsAutoString manifestSpec;
1317 0 : docElement->GetAttr(kNameSpaceID_None, nsGkAtoms::manifest, manifestSpec);
1318 :
1319 : // Manifest URIs can't have fragment identifiers.
1320 0 : if (manifestSpec.IsEmpty() ||
1321 0 : manifestSpec.FindChar('#') != kNotFound) {
1322 : return;
1323 : }
1324 :
1325 : nsContentUtils::NewURIWithDocumentCharset(aURI, manifestSpec,
1326 : aDocument,
1327 0 : aDocument->GetDocBaseURI());
1328 : }
1329 :
1330 : /* static */
1331 : bool
1332 0 : nsContentUtils::OfflineAppAllowed(nsIURI *aURI)
1333 : {
1334 : nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
1335 0 : do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
1336 0 : if (!updateService) {
1337 0 : return false;
1338 : }
1339 :
1340 : bool allowed;
1341 : nsresult rv =
1342 0 : updateService->OfflineAppAllowedForURI(aURI,
1343 : Preferences::GetRootBranch(),
1344 0 : &allowed);
1345 0 : return NS_SUCCEEDED(rv) && allowed;
1346 : }
1347 :
1348 : /* static */
1349 : bool
1350 0 : nsContentUtils::OfflineAppAllowed(nsIPrincipal *aPrincipal)
1351 : {
1352 : nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
1353 0 : do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
1354 0 : if (!updateService) {
1355 0 : return false;
1356 : }
1357 :
1358 : bool allowed;
1359 0 : nsresult rv = updateService->OfflineAppAllowed(aPrincipal,
1360 : Preferences::GetRootBranch(),
1361 0 : &allowed);
1362 0 : return NS_SUCCEEDED(rv) && allowed;
1363 : }
1364 :
1365 : // static
1366 : void
1367 1403 : nsContentUtils::Shutdown()
1368 : {
1369 1403 : sInitialized = false;
1370 :
1371 1403 : NS_IF_RELEASE(sContentPolicyService);
1372 1403 : sTriedToGetContentPolicy = false;
1373 : PRUint32 i;
1374 16836 : for (i = 0; i < PropertiesFile_COUNT; ++i)
1375 15433 : NS_IF_RELEASE(sStringBundles[i]);
1376 :
1377 1403 : NS_IF_RELEASE(sStringBundleService);
1378 1403 : NS_IF_RELEASE(sConsoleService);
1379 1403 : NS_IF_RELEASE(sDOMScriptObjectFactory);
1380 1403 : sXPConnect = nsnull;
1381 1403 : sThreadJSContextStack = nsnull;
1382 1403 : NS_IF_RELEASE(sSecurityManager);
1383 1403 : NS_IF_RELEASE(sNameSpaceManager);
1384 1403 : NS_IF_RELEASE(sParserService);
1385 1403 : NS_IF_RELEASE(sIOService);
1386 1403 : NS_IF_RELEASE(sLineBreaker);
1387 1403 : NS_IF_RELEASE(sWordBreaker);
1388 : #ifdef MOZ_XTF
1389 1403 : NS_IF_RELEASE(sXTFService);
1390 : #endif
1391 1403 : NS_IF_RELEASE(sImgLoader);
1392 1403 : NS_IF_RELEASE(sImgCache);
1393 : #ifdef IBMBIDI
1394 1403 : NS_IF_RELEASE(sBidiKeyboard);
1395 : #endif
1396 :
1397 1403 : delete sAtomEventTable;
1398 1403 : sAtomEventTable = nsnull;
1399 1403 : delete sStringEventTable;
1400 1403 : sStringEventTable = nsnull;
1401 1403 : delete sUserDefinedEvents;
1402 1403 : sUserDefinedEvents = nsnull;
1403 :
1404 1403 : if (sEventListenerManagersHash.ops) {
1405 1403 : NS_ASSERTION(sEventListenerManagersHash.entryCount == 0,
1406 : "Event listener manager hash not empty at shutdown!");
1407 :
1408 : // See comment above.
1409 :
1410 : // However, we have to handle this table differently. If it still
1411 : // has entries, we want to leak it too, so that we can keep it alive
1412 : // in case any elements are destroyed. Because if they are, we need
1413 : // their event listener managers to be destroyed too, or otherwise
1414 : // it could leave dangling references in DOMClassInfo's preserved
1415 : // wrapper table.
1416 :
1417 1403 : if (sEventListenerManagersHash.entryCount == 0) {
1418 1403 : PL_DHashTableFinish(&sEventListenerManagersHash);
1419 1403 : sEventListenerManagersHash.ops = nsnull;
1420 : }
1421 : }
1422 :
1423 1403 : NS_ASSERTION(!sBlockedScriptRunners ||
1424 : sBlockedScriptRunners->Length() == 0,
1425 : "How'd this happen?");
1426 1403 : delete sBlockedScriptRunners;
1427 1403 : sBlockedScriptRunners = nsnull;
1428 :
1429 1403 : delete sShiftText;
1430 1403 : sShiftText = nsnull;
1431 1403 : delete sControlText;
1432 1403 : sControlText = nsnull;
1433 1403 : delete sMetaText;
1434 1403 : sMetaText = nsnull;
1435 1403 : delete sAltText;
1436 1403 : sAltText = nsnull;
1437 1403 : delete sModifierSeparator;
1438 1403 : sModifierSeparator = nsnull;
1439 :
1440 1403 : NS_IF_RELEASE(sSameOriginChecker);
1441 :
1442 1403 : nsTextEditorState::ShutDown();
1443 1403 : }
1444 :
1445 : // static
1446 : bool
1447 0 : nsContentUtils::CallerHasUniversalXPConnect()
1448 : {
1449 : bool hasCap;
1450 0 : if (NS_FAILED(sSecurityManager->IsCapabilityEnabled("UniversalXPConnect",
1451 : &hasCap)))
1452 0 : return false;
1453 0 : return hasCap;
1454 : }
1455 :
1456 : /**
1457 : * Checks whether two nodes come from the same origin. aTrustedNode is
1458 : * considered 'safe' in that a user can operate on it and that it isn't
1459 : * a js-object that implements nsIDOMNode.
1460 : * Never call this function with the first node provided by script, it
1461 : * must always be known to be a 'real' node!
1462 : */
1463 : // static
1464 : nsresult
1465 176 : nsContentUtils::CheckSameOrigin(nsINode *aTrustedNode,
1466 : nsIDOMNode *aUnTrustedNode)
1467 : {
1468 176 : NS_PRECONDITION(aTrustedNode, "There must be a trusted node");
1469 :
1470 176 : bool isSystem = false;
1471 176 : nsresult rv = sSecurityManager->SubjectPrincipalIsSystem(&isSystem);
1472 176 : NS_ENSURE_SUCCESS(rv, rv);
1473 :
1474 176 : if (isSystem) {
1475 : // we're running as system, grant access to the node.
1476 :
1477 176 : return NS_OK;
1478 : }
1479 :
1480 : /*
1481 : * Get hold of each node's principal
1482 : */
1483 0 : nsCOMPtr<nsINode> unTrustedNode = do_QueryInterface(aUnTrustedNode);
1484 :
1485 : // Make sure these are both real nodes
1486 0 : NS_ENSURE_TRUE(aTrustedNode && unTrustedNode, NS_ERROR_UNEXPECTED);
1487 :
1488 0 : nsIPrincipal* trustedPrincipal = aTrustedNode->NodePrincipal();
1489 0 : nsIPrincipal* unTrustedPrincipal = unTrustedNode->NodePrincipal();
1490 :
1491 0 : if (trustedPrincipal == unTrustedPrincipal) {
1492 0 : return NS_OK;
1493 : }
1494 :
1495 : bool equal;
1496 : // XXXbz should we actually have a Subsumes() check here instead? Or perhaps
1497 : // a separate method for that, with callers using one or the other?
1498 0 : if (NS_FAILED(trustedPrincipal->Equals(unTrustedPrincipal, &equal)) ||
1499 0 : !equal) {
1500 0 : return NS_ERROR_DOM_PROP_ACCESS_DENIED;
1501 : }
1502 :
1503 0 : return NS_OK;
1504 : }
1505 :
1506 : // static
1507 : bool
1508 326 : nsContentUtils::CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
1509 : nsIPrincipal* aPrincipal)
1510 : {
1511 : bool subsumes;
1512 326 : nsresult rv = aSubjectPrincipal->Subsumes(aPrincipal, &subsumes);
1513 326 : NS_ENSURE_SUCCESS(rv, false);
1514 :
1515 326 : if (subsumes) {
1516 326 : return true;
1517 : }
1518 :
1519 : // The subject doesn't subsume aPrincipal. Allow access only if the subject
1520 : // has UniversalXPConnect.
1521 0 : return CallerHasUniversalXPConnect();
1522 : }
1523 :
1524 : // static
1525 : bool
1526 327 : nsContentUtils::CanCallerAccess(nsIDOMNode *aNode)
1527 : {
1528 : // XXXbz why not check the IsCapabilityEnabled thing up front, and not bother
1529 : // with the system principal games? But really, there should be a simpler
1530 : // API here, dammit.
1531 654 : nsCOMPtr<nsIPrincipal> subjectPrincipal;
1532 327 : nsresult rv = sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
1533 327 : NS_ENSURE_SUCCESS(rv, false);
1534 :
1535 327 : if (!subjectPrincipal) {
1536 : // we're running as system, grant access to the node.
1537 :
1538 0 : return true;
1539 : }
1540 :
1541 654 : nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
1542 327 : NS_ENSURE_TRUE(node, false);
1543 :
1544 326 : return CanCallerAccess(subjectPrincipal, node->NodePrincipal());
1545 : }
1546 :
1547 : // static
1548 : bool
1549 0 : nsContentUtils::CanCallerAccess(nsPIDOMWindow* aWindow)
1550 : {
1551 : // XXXbz why not check the IsCapabilityEnabled thing up front, and not bother
1552 : // with the system principal games? But really, there should be a simpler
1553 : // API here, dammit.
1554 0 : nsCOMPtr<nsIPrincipal> subjectPrincipal;
1555 0 : nsresult rv = sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
1556 0 : NS_ENSURE_SUCCESS(rv, false);
1557 :
1558 0 : if (!subjectPrincipal) {
1559 : // we're running as system, grant access to the node.
1560 :
1561 0 : return true;
1562 : }
1563 :
1564 : nsCOMPtr<nsIScriptObjectPrincipal> scriptObject =
1565 0 : do_QueryInterface(aWindow->IsOuterWindow() ?
1566 0 : aWindow->GetCurrentInnerWindow() : aWindow);
1567 0 : NS_ENSURE_TRUE(scriptObject, false);
1568 :
1569 0 : return CanCallerAccess(subjectPrincipal, scriptObject->GetPrincipal());
1570 : }
1571 :
1572 : //static
1573 : bool
1574 0 : nsContentUtils::InProlog(nsINode *aNode)
1575 : {
1576 0 : NS_PRECONDITION(aNode, "missing node to nsContentUtils::InProlog");
1577 :
1578 0 : nsINode* parent = aNode->GetNodeParent();
1579 0 : if (!parent || !parent->IsNodeOfType(nsINode::eDOCUMENT)) {
1580 0 : return false;
1581 : }
1582 :
1583 0 : nsIDocument* doc = static_cast<nsIDocument*>(parent);
1584 0 : nsIContent* root = doc->GetRootElement();
1585 :
1586 0 : return !root || doc->IndexOf(aNode) < doc->IndexOf(root);
1587 : }
1588 :
1589 : JSContext *
1590 0 : nsContentUtils::GetContextFromDocument(nsIDocument *aDocument)
1591 : {
1592 0 : nsIScriptGlobalObject *sgo = aDocument->GetScopeObject();
1593 0 : if (!sgo) {
1594 : // No script global, no context.
1595 0 : return nsnull;
1596 : }
1597 :
1598 0 : nsIScriptContext *scx = sgo->GetContext();
1599 0 : if (!scx) {
1600 : // No context left in the scope...
1601 0 : return nsnull;
1602 : }
1603 :
1604 0 : return scx->GetNativeContext();
1605 : }
1606 :
1607 : // static
1608 : nsresult
1609 0 : nsContentUtils::GetContextAndScope(nsIDocument *aOldDocument,
1610 : nsIDocument *aNewDocument, JSContext **aCx,
1611 : JSObject **aNewScope)
1612 : {
1613 0 : *aCx = nsnull;
1614 0 : *aNewScope = nsnull;
1615 :
1616 0 : JSObject *newScope = aNewDocument->GetWrapper();
1617 : JSObject *global;
1618 0 : if (!newScope) {
1619 0 : nsIScriptGlobalObject *newSGO = aNewDocument->GetScopeObject();
1620 0 : if (!newSGO || !(global = newSGO->GetGlobalJSObject())) {
1621 0 : return NS_OK;
1622 : }
1623 : }
1624 :
1625 0 : NS_ENSURE_TRUE(sXPConnect, NS_ERROR_NOT_INITIALIZED);
1626 :
1627 0 : JSContext *cx = aOldDocument ? GetContextFromDocument(aOldDocument) : nsnull;
1628 0 : if (!cx) {
1629 0 : cx = GetContextFromDocument(aNewDocument);
1630 :
1631 0 : if (!cx) {
1632 : // No context reachable from the old or new document, use the
1633 : // calling context, or the safe context if no caller can be
1634 : // found.
1635 :
1636 0 : sThreadJSContextStack->Peek(&cx);
1637 :
1638 0 : if (!cx) {
1639 0 : sThreadJSContextStack->GetSafeJSContext(&cx);
1640 :
1641 0 : if (!cx) {
1642 : // No safe context reachable, bail.
1643 0 : NS_WARNING("No context reachable in GetContextAndScopes()!");
1644 :
1645 0 : return NS_ERROR_NOT_AVAILABLE;
1646 : }
1647 : }
1648 : }
1649 : }
1650 :
1651 0 : if (!newScope && cx) {
1652 : jsval v;
1653 0 : nsresult rv = WrapNative(cx, global, aNewDocument, aNewDocument, &v);
1654 0 : NS_ENSURE_SUCCESS(rv, rv);
1655 :
1656 0 : newScope = JSVAL_TO_OBJECT(v);
1657 : }
1658 :
1659 0 : *aCx = cx;
1660 0 : *aNewScope = newScope;
1661 :
1662 0 : return NS_OK;
1663 : }
1664 :
1665 : nsresult
1666 0 : nsContentUtils::ReparentContentWrappersInScope(JSContext *cx,
1667 : nsIScriptGlobalObject *aOldScope,
1668 : nsIScriptGlobalObject *aNewScope)
1669 : {
1670 0 : JSObject *oldScopeObj = aOldScope->GetGlobalJSObject();
1671 0 : JSObject *newScopeObj = aNewScope->GetGlobalJSObject();
1672 :
1673 0 : if (!newScopeObj || !oldScopeObj) {
1674 : // We can't really do anything without the JSObjects.
1675 :
1676 0 : return NS_ERROR_NOT_AVAILABLE;
1677 : }
1678 :
1679 0 : return sXPConnect->MoveWrappers(cx, oldScopeObj, newScopeObj);
1680 : }
1681 :
1682 : nsPIDOMWindow *
1683 0 : nsContentUtils::GetWindowFromCaller()
1684 : {
1685 0 : JSContext *cx = nsnull;
1686 0 : sThreadJSContextStack->Peek(&cx);
1687 :
1688 0 : if (cx) {
1689 : nsCOMPtr<nsPIDOMWindow> win =
1690 0 : do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
1691 0 : return win;
1692 : }
1693 :
1694 0 : return nsnull;
1695 : }
1696 :
1697 : nsIDOMDocument *
1698 0 : nsContentUtils::GetDocumentFromCaller()
1699 : {
1700 0 : JSContext *cx = nsnull;
1701 0 : JSObject *obj = nsnull;
1702 0 : sXPConnect->GetCaller(&cx, &obj);
1703 0 : NS_ASSERTION(cx && obj, "Caller ensures something is running");
1704 :
1705 0 : JSAutoEnterCompartment ac;
1706 0 : if (!ac.enter(cx, obj)) {
1707 0 : return nsnull;
1708 : }
1709 :
1710 : nsCOMPtr<nsPIDOMWindow> win =
1711 0 : do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(cx, obj));
1712 0 : if (!win) {
1713 0 : return nsnull;
1714 : }
1715 :
1716 0 : return win->GetExtantDocument();
1717 : }
1718 :
1719 : nsIDOMDocument *
1720 0 : nsContentUtils::GetDocumentFromContext()
1721 : {
1722 0 : JSContext *cx = nsnull;
1723 0 : sThreadJSContextStack->Peek(&cx);
1724 :
1725 0 : if (cx) {
1726 0 : nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(cx);
1727 :
1728 0 : if (sgo) {
1729 0 : nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(sgo);
1730 0 : if (pwin) {
1731 0 : return pwin->GetExtantDocument();
1732 : }
1733 : }
1734 : }
1735 :
1736 0 : return nsnull;
1737 : }
1738 :
1739 : bool
1740 309 : nsContentUtils::IsCallerChrome()
1741 : {
1742 309 : bool is_caller_chrome = false;
1743 309 : nsresult rv = sSecurityManager->SubjectPrincipalIsSystem(&is_caller_chrome);
1744 309 : if (NS_FAILED(rv)) {
1745 0 : return false;
1746 : }
1747 :
1748 309 : return is_caller_chrome;
1749 : }
1750 :
1751 : bool
1752 0 : nsContentUtils::IsCallerTrustedForRead()
1753 : {
1754 0 : return CallerHasUniversalXPConnect();
1755 : }
1756 :
1757 : bool
1758 0 : nsContentUtils::IsCallerTrustedForWrite()
1759 : {
1760 0 : return CallerHasUniversalXPConnect();
1761 : }
1762 :
1763 : bool
1764 0 : nsContentUtils::IsImageSrcSetDisabled()
1765 : {
1766 0 : return Preferences::GetBool("dom.disable_image_src_set") &&
1767 0 : !IsCallerChrome();
1768 : }
1769 :
1770 : // static
1771 : nsINode*
1772 0 : nsContentUtils::GetCrossDocParentNode(nsINode* aChild)
1773 : {
1774 0 : NS_PRECONDITION(aChild, "The child is null!");
1775 :
1776 0 : nsINode* parent = aChild->GetNodeParent();
1777 0 : if (parent || !aChild->IsNodeOfType(nsINode::eDOCUMENT))
1778 0 : return parent;
1779 :
1780 0 : nsIDocument* doc = static_cast<nsIDocument*>(aChild);
1781 0 : nsIDocument* parentDoc = doc->GetParentDocument();
1782 0 : return parentDoc ? parentDoc->FindContentForSubDocument(doc) : nsnull;
1783 : }
1784 :
1785 : // static
1786 : bool
1787 691 : nsContentUtils::ContentIsDescendantOf(const nsINode* aPossibleDescendant,
1788 : const nsINode* aPossibleAncestor)
1789 : {
1790 691 : NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
1791 691 : NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
1792 :
1793 912 : do {
1794 1174 : if (aPossibleDescendant == aPossibleAncestor)
1795 262 : return true;
1796 912 : aPossibleDescendant = aPossibleDescendant->GetNodeParent();
1797 : } while (aPossibleDescendant);
1798 :
1799 429 : return false;
1800 : }
1801 :
1802 : // static
1803 : bool
1804 0 : nsContentUtils::ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
1805 : nsINode* aPossibleAncestor)
1806 : {
1807 0 : NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
1808 0 : NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
1809 :
1810 0 : do {
1811 0 : if (aPossibleDescendant == aPossibleAncestor)
1812 0 : return true;
1813 0 : aPossibleDescendant = GetCrossDocParentNode(aPossibleDescendant);
1814 : } while (aPossibleDescendant);
1815 :
1816 0 : return false;
1817 : }
1818 :
1819 :
1820 : // static
1821 : nsresult
1822 0 : nsContentUtils::GetAncestors(nsINode* aNode,
1823 : nsTArray<nsINode*>& aArray)
1824 : {
1825 0 : while (aNode) {
1826 0 : aArray.AppendElement(aNode);
1827 0 : aNode = aNode->GetNodeParent();
1828 : }
1829 0 : return NS_OK;
1830 : }
1831 :
1832 : // static
1833 : nsresult
1834 6 : nsContentUtils::GetAncestorsAndOffsets(nsIDOMNode* aNode,
1835 : PRInt32 aOffset,
1836 : nsTArray<nsIContent*>* aAncestorNodes,
1837 : nsTArray<PRInt32>* aAncestorOffsets)
1838 : {
1839 6 : NS_ENSURE_ARG_POINTER(aNode);
1840 :
1841 12 : nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
1842 :
1843 6 : if (!content) {
1844 0 : return NS_ERROR_FAILURE;
1845 : }
1846 :
1847 6 : if (!aAncestorNodes->IsEmpty()) {
1848 0 : NS_WARNING("aAncestorNodes is not empty");
1849 0 : aAncestorNodes->Clear();
1850 : }
1851 :
1852 6 : if (!aAncestorOffsets->IsEmpty()) {
1853 0 : NS_WARNING("aAncestorOffsets is not empty");
1854 0 : aAncestorOffsets->Clear();
1855 : }
1856 :
1857 : // insert the node itself
1858 6 : aAncestorNodes->AppendElement(content.get());
1859 6 : aAncestorOffsets->AppendElement(aOffset);
1860 :
1861 : // insert all the ancestors
1862 6 : nsIContent* child = content;
1863 6 : nsIContent* parent = child->GetParent();
1864 14 : while (parent) {
1865 2 : aAncestorNodes->AppendElement(parent);
1866 2 : aAncestorOffsets->AppendElement(parent->IndexOf(child));
1867 2 : child = parent;
1868 2 : parent = parent->GetParent();
1869 : }
1870 :
1871 6 : return NS_OK;
1872 : }
1873 :
1874 : // static
1875 : nsresult
1876 4 : nsContentUtils::GetCommonAncestor(nsIDOMNode *aNode,
1877 : nsIDOMNode *aOther,
1878 : nsIDOMNode** aCommonAncestor)
1879 : {
1880 4 : *aCommonAncestor = nsnull;
1881 :
1882 8 : nsCOMPtr<nsINode> node1 = do_QueryInterface(aNode);
1883 8 : nsCOMPtr<nsINode> node2 = do_QueryInterface(aOther);
1884 :
1885 4 : NS_ENSURE_TRUE(node1 && node2, NS_ERROR_UNEXPECTED);
1886 :
1887 4 : nsINode* common = GetCommonAncestor(node1, node2);
1888 4 : NS_ENSURE_TRUE(common, NS_ERROR_NOT_AVAILABLE);
1889 :
1890 4 : return CallQueryInterface(common, aCommonAncestor);
1891 : }
1892 :
1893 : // static
1894 : nsINode*
1895 105 : nsContentUtils::GetCommonAncestor(nsINode* aNode1,
1896 : nsINode* aNode2)
1897 : {
1898 105 : if (aNode1 == aNode2) {
1899 38 : return aNode1;
1900 : }
1901 :
1902 : // Build the chain of parents
1903 134 : nsAutoTArray<nsINode*, 30> parents1, parents2;
1904 135 : do {
1905 135 : parents1.AppendElement(aNode1);
1906 135 : aNode1 = aNode1->GetNodeParent();
1907 : } while (aNode1);
1908 118 : do {
1909 118 : parents2.AppendElement(aNode2);
1910 118 : aNode2 = aNode2->GetNodeParent();
1911 : } while (aNode2);
1912 :
1913 : // Find where the parent chain differs
1914 67 : PRUint32 pos1 = parents1.Length();
1915 67 : PRUint32 pos2 = parents2.Length();
1916 67 : nsINode* parent = nsnull;
1917 : PRUint32 len;
1918 133 : for (len = NS_MIN(pos1, pos2); len > 0; --len) {
1919 101 : nsINode* child1 = parents1.ElementAt(--pos1);
1920 101 : nsINode* child2 = parents2.ElementAt(--pos2);
1921 101 : if (child1 != child2) {
1922 35 : break;
1923 : }
1924 66 : parent = child1;
1925 : }
1926 :
1927 67 : return parent;
1928 : }
1929 :
1930 : /* static */
1931 : PRInt32
1932 161 : nsContentUtils::ComparePoints(nsINode* aParent1, PRInt32 aOffset1,
1933 : nsINode* aParent2, PRInt32 aOffset2,
1934 : bool* aDisconnected)
1935 : {
1936 161 : if (aParent1 == aParent2) {
1937 : return aOffset1 < aOffset2 ? -1 :
1938 : aOffset1 > aOffset2 ? 1 :
1939 125 : 0;
1940 : }
1941 :
1942 72 : nsAutoTArray<nsINode*, 32> parents1, parents2;
1943 36 : nsINode* node1 = aParent1;
1944 36 : nsINode* node2 = aParent2;
1945 72 : do {
1946 72 : parents1.AppendElement(node1);
1947 72 : node1 = node1->GetNodeParent();
1948 : } while (node1);
1949 55 : do {
1950 55 : parents2.AppendElement(node2);
1951 55 : node2 = node2->GetNodeParent();
1952 : } while (node2);
1953 :
1954 36 : PRUint32 pos1 = parents1.Length() - 1;
1955 36 : PRUint32 pos2 = parents2.Length() - 1;
1956 :
1957 36 : bool disconnected = parents1.ElementAt(pos1) != parents2.ElementAt(pos2);
1958 36 : if (aDisconnected) {
1959 32 : *aDisconnected = disconnected;
1960 : }
1961 36 : if (disconnected) {
1962 0 : NS_ASSERTION(aDisconnected, "unexpected disconnected nodes");
1963 0 : return 1;
1964 : }
1965 :
1966 : // Find where the parent chains differ
1967 36 : nsINode* parent = parents1.ElementAt(pos1);
1968 : PRUint32 len;
1969 36 : for (len = NS_MIN(pos1, pos2); len > 0; --len) {
1970 19 : nsINode* child1 = parents1.ElementAt(--pos1);
1971 19 : nsINode* child2 = parents2.ElementAt(--pos2);
1972 19 : if (child1 != child2) {
1973 19 : return parent->IndexOf(child1) < parent->IndexOf(child2) ? -1 : 1;
1974 : }
1975 0 : parent = child1;
1976 : }
1977 :
1978 :
1979 : // The parent chains never differed, so one of the nodes is an ancestor of
1980 : // the other
1981 :
1982 17 : NS_ASSERTION(!pos1 || !pos2,
1983 : "should have run out of parent chain for one of the nodes");
1984 :
1985 17 : if (!pos1) {
1986 0 : nsINode* child2 = parents2.ElementAt(--pos2);
1987 0 : return aOffset1 <= parent->IndexOf(child2) ? -1 : 1;
1988 : }
1989 :
1990 17 : nsINode* child1 = parents1.ElementAt(--pos1);
1991 17 : return parent->IndexOf(child1) < aOffset2 ? -1 : 1;
1992 : }
1993 :
1994 : /* static */
1995 : PRInt32
1996 0 : nsContentUtils::ComparePoints(nsIDOMNode* aParent1, PRInt32 aOffset1,
1997 : nsIDOMNode* aParent2, PRInt32 aOffset2,
1998 : bool* aDisconnected)
1999 : {
2000 0 : nsCOMPtr<nsINode> parent1 = do_QueryInterface(aParent1);
2001 0 : nsCOMPtr<nsINode> parent2 = do_QueryInterface(aParent2);
2002 0 : NS_ENSURE_TRUE(parent1 && parent2, -1);
2003 0 : return ComparePoints(parent1, aOffset1, parent2, aOffset2);
2004 : }
2005 :
2006 : inline bool
2007 0 : IsCharInSet(const char* aSet,
2008 : const PRUnichar aChar)
2009 : {
2010 : PRUnichar ch;
2011 0 : while ((ch = *aSet)) {
2012 0 : if (aChar == PRUnichar(ch)) {
2013 0 : return true;
2014 : }
2015 0 : ++aSet;
2016 : }
2017 0 : return false;
2018 : }
2019 :
2020 : /**
2021 : * This method strips leading/trailing chars, in given set, from string.
2022 : */
2023 :
2024 : // static
2025 : const nsDependentSubstring
2026 0 : nsContentUtils::TrimCharsInSet(const char* aSet,
2027 : const nsAString& aValue)
2028 : {
2029 0 : nsAString::const_iterator valueCurrent, valueEnd;
2030 :
2031 0 : aValue.BeginReading(valueCurrent);
2032 0 : aValue.EndReading(valueEnd);
2033 :
2034 : // Skip characters in the beginning
2035 0 : while (valueCurrent != valueEnd) {
2036 0 : if (!IsCharInSet(aSet, *valueCurrent)) {
2037 0 : break;
2038 : }
2039 0 : ++valueCurrent;
2040 : }
2041 :
2042 0 : if (valueCurrent != valueEnd) {
2043 0 : for (;;) {
2044 0 : --valueEnd;
2045 0 : if (!IsCharInSet(aSet, *valueEnd)) {
2046 : break;
2047 : }
2048 : }
2049 0 : ++valueEnd; // Step beyond the last character we want in the value.
2050 : }
2051 :
2052 : // valueEnd should point to the char after the last to copy
2053 0 : return Substring(valueCurrent, valueEnd);
2054 : }
2055 :
2056 : /**
2057 : * This method strips leading and trailing whitespace from a string.
2058 : */
2059 :
2060 : // static
2061 : template<bool IsWhitespace(PRUnichar)>
2062 : const nsDependentSubstring
2063 0 : nsContentUtils::TrimWhitespace(const nsAString& aStr, bool aTrimTrailing)
2064 : {
2065 0 : nsAString::const_iterator start, end;
2066 :
2067 0 : aStr.BeginReading(start);
2068 0 : aStr.EndReading(end);
2069 :
2070 : // Skip whitespace characters in the beginning
2071 0 : while (start != end && IsWhitespace(*start)) {
2072 0 : ++start;
2073 : }
2074 :
2075 0 : if (aTrimTrailing) {
2076 : // Skip whitespace characters in the end.
2077 0 : while (end != start) {
2078 0 : --end;
2079 :
2080 0 : if (!IsWhitespace(*end)) {
2081 : // Step back to the last non-whitespace character.
2082 0 : ++end;
2083 :
2084 0 : break;
2085 : }
2086 : }
2087 : }
2088 :
2089 : // Return a substring for the string w/o leading and/or trailing
2090 : // whitespace
2091 :
2092 0 : return Substring(start, end);
2093 : }
2094 :
2095 : // Declaring the templates we are going to use avoid linking issues without
2096 : // inlining the method. Considering there is not so much spaces checking
2097 : // methods we can consider this to be better than inlining.
2098 : template
2099 : const nsDependentSubstring
2100 : nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(const nsAString&, bool);
2101 : template
2102 : const nsDependentSubstring
2103 : nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(const nsAString&, bool);
2104 :
2105 0 : static inline void KeyAppendSep(nsACString& aKey)
2106 : {
2107 0 : if (!aKey.IsEmpty()) {
2108 0 : aKey.Append('>');
2109 : }
2110 0 : }
2111 :
2112 0 : static inline void KeyAppendString(const nsAString& aString, nsACString& aKey)
2113 : {
2114 0 : KeyAppendSep(aKey);
2115 :
2116 : // Could escape separator here if collisions happen. > is not a legal char
2117 : // for a name or type attribute, so we should be safe avoiding that extra work.
2118 :
2119 0 : AppendUTF16toUTF8(aString, aKey);
2120 0 : }
2121 :
2122 0 : static inline void KeyAppendString(const nsACString& aString, nsACString& aKey)
2123 : {
2124 0 : KeyAppendSep(aKey);
2125 :
2126 : // Could escape separator here if collisions happen. > is not a legal char
2127 : // for a name or type attribute, so we should be safe avoiding that extra work.
2128 :
2129 0 : aKey.Append(aString);
2130 0 : }
2131 :
2132 0 : static inline void KeyAppendInt(PRInt32 aInt, nsACString& aKey)
2133 : {
2134 0 : KeyAppendSep(aKey);
2135 :
2136 0 : aKey.Append(nsPrintfCString("%d", aInt));
2137 0 : }
2138 :
2139 : static inline void KeyAppendAtom(nsIAtom* aAtom, nsACString& aKey)
2140 : {
2141 : NS_PRECONDITION(aAtom, "KeyAppendAtom: aAtom can not be null!\n");
2142 :
2143 : KeyAppendString(nsAtomCString(aAtom), aKey);
2144 : }
2145 :
2146 0 : static inline bool IsAutocompleteOff(const nsIContent* aElement)
2147 : {
2148 : return aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::autocomplete,
2149 0 : NS_LITERAL_STRING("off"), eIgnoreCase);
2150 : }
2151 :
2152 : /*static*/ nsresult
2153 0 : nsContentUtils::GenerateStateKey(nsIContent* aContent,
2154 : const nsIDocument* aDocument,
2155 : nsIStatefulFrame::SpecialStateID aID,
2156 : nsACString& aKey)
2157 : {
2158 0 : aKey.Truncate();
2159 :
2160 0 : PRUint32 partID = aDocument ? aDocument->GetPartID() : 0;
2161 :
2162 : // SpecialStateID case - e.g. scrollbars around the content window
2163 : // The key in this case is a special state id
2164 0 : if (nsIStatefulFrame::eNoID != aID) {
2165 0 : KeyAppendInt(partID, aKey); // first append a partID
2166 0 : KeyAppendInt(aID, aKey);
2167 0 : return NS_OK;
2168 : }
2169 :
2170 : // We must have content if we're not using a special state id
2171 0 : NS_ENSURE_TRUE(aContent, NS_ERROR_FAILURE);
2172 :
2173 : // Don't capture state for anonymous content
2174 0 : if (aContent->IsInAnonymousSubtree()) {
2175 0 : return NS_OK;
2176 : }
2177 :
2178 0 : if (IsAutocompleteOff(aContent)) {
2179 0 : return NS_OK;
2180 : }
2181 :
2182 0 : nsCOMPtr<nsIHTMLDocument> htmlDocument(do_QueryInterface(aContent->GetCurrentDoc()));
2183 :
2184 0 : KeyAppendInt(partID, aKey); // first append a partID
2185 : // Make sure we can't possibly collide with an nsIStatefulFrame
2186 : // special id of some sort
2187 0 : KeyAppendInt(nsIStatefulFrame::eNoID, aKey);
2188 0 : bool generatedUniqueKey = false;
2189 :
2190 0 : if (htmlDocument) {
2191 : // Flush our content model so it'll be up to date
2192 : // If this becomes unnecessary and the following line is removed,
2193 : // please also remove the corresponding flush operation from
2194 : // nsHtml5TreeBuilderCppSupplement.h. (Look for "See bug 497861." there.)
2195 0 : aContent->GetCurrentDoc()->FlushPendingNotifications(Flush_Content);
2196 :
2197 0 : nsContentList *htmlForms = htmlDocument->GetForms();
2198 0 : nsContentList *htmlFormControls = htmlDocument->GetFormControls();
2199 :
2200 0 : NS_ENSURE_TRUE(htmlForms && htmlFormControls, NS_ERROR_OUT_OF_MEMORY);
2201 :
2202 : // If we have a form control and can calculate form information, use that
2203 : // as the key - it is more reliable than just recording position in the
2204 : // DOM.
2205 : // XXXbz Is it, really? We have bugs on this, I think...
2206 : // Important to have a unique key, and tag/type/name may not be.
2207 : //
2208 : // If the control has a form, the format of the key is:
2209 : // f>type>IndOfFormInDoc>IndOfControlInForm>FormName>name
2210 : // else:
2211 : // d>type>IndOfControlInDoc>name
2212 : //
2213 : // XXX We don't need to use index if name is there
2214 : // XXXbz We don't? Why not? I don't follow.
2215 : //
2216 0 : nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent));
2217 0 : if (control && htmlFormControls && htmlForms) {
2218 :
2219 : // Append the control type
2220 0 : KeyAppendInt(control->GetType(), aKey);
2221 :
2222 : // If in a form, add form name / index of form / index in form
2223 0 : PRInt32 index = -1;
2224 0 : Element *formElement = control->GetFormElement();
2225 0 : if (formElement) {
2226 0 : if (IsAutocompleteOff(formElement)) {
2227 0 : aKey.Truncate();
2228 0 : return NS_OK;
2229 : }
2230 :
2231 0 : KeyAppendString(NS_LITERAL_CSTRING("f"), aKey);
2232 :
2233 : // Append the index of the form in the document
2234 0 : index = htmlForms->IndexOf(formElement, false);
2235 0 : if (index <= -1) {
2236 : //
2237 : // XXX HACK this uses some state that was dumped into the document
2238 : // specifically to fix bug 138892. What we are trying to do is *guess*
2239 : // which form this control's state is found in, with the highly likely
2240 : // guess that the highest form parsed so far is the one.
2241 : // This code should not be on trunk, only branch.
2242 : //
2243 0 : index = htmlDocument->GetNumFormsSynchronous() - 1;
2244 : }
2245 0 : if (index > -1) {
2246 0 : KeyAppendInt(index, aKey);
2247 :
2248 : // Append the index of the control in the form
2249 0 : nsCOMPtr<nsIForm> form(do_QueryInterface(formElement));
2250 0 : index = form->IndexOfControl(control);
2251 :
2252 0 : if (index > -1) {
2253 0 : KeyAppendInt(index, aKey);
2254 0 : generatedUniqueKey = true;
2255 : }
2256 : }
2257 :
2258 : // Append the form name
2259 0 : nsAutoString formName;
2260 0 : formElement->GetAttr(kNameSpaceID_None, nsGkAtoms::name, formName);
2261 0 : KeyAppendString(formName, aKey);
2262 :
2263 : } else {
2264 :
2265 0 : KeyAppendString(NS_LITERAL_CSTRING("d"), aKey);
2266 :
2267 : // If not in a form, add index of control in document
2268 : // Less desirable than indexing by form info.
2269 :
2270 : // Hash by index of control in doc (we are not in a form)
2271 : // These are important as they are unique, and type/name may not be.
2272 :
2273 : // We have to flush sink notifications at this point to make
2274 : // sure that htmlFormControls is up to date.
2275 0 : index = htmlFormControls->IndexOf(aContent, true);
2276 0 : if (index > -1) {
2277 0 : KeyAppendInt(index, aKey);
2278 0 : generatedUniqueKey = true;
2279 : }
2280 : }
2281 :
2282 : // Append the control name
2283 0 : nsAutoString name;
2284 0 : aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
2285 0 : KeyAppendString(name, aKey);
2286 : }
2287 : }
2288 :
2289 0 : if (!generatedUniqueKey) {
2290 : // Either we didn't have a form control or we aren't in an HTML document so
2291 : // we can't figure out form info. Append the tag name if it's an element
2292 : // to avoid restoring state for one type of element on another type.
2293 0 : if (aContent->IsElement()) {
2294 0 : KeyAppendString(nsDependentAtomString(aContent->Tag()), aKey);
2295 : }
2296 : else {
2297 : // Append a character that is not "d" or "f" to disambiguate from
2298 : // the case when we were a form control in an HTML document.
2299 0 : KeyAppendString(NS_LITERAL_CSTRING("o"), aKey);
2300 : }
2301 :
2302 : // Now start at aContent and append the indices of it and all its ancestors
2303 : // in their containers. That should at least pin down its position in the
2304 : // DOM...
2305 0 : nsINode* parent = aContent->GetNodeParent();
2306 0 : nsINode* content = aContent;
2307 0 : while (parent) {
2308 0 : KeyAppendInt(parent->IndexOf(content), aKey);
2309 0 : content = parent;
2310 0 : parent = content->GetNodeParent();
2311 : }
2312 : }
2313 :
2314 0 : return NS_OK;
2315 : }
2316 :
2317 : // static
2318 : nsresult
2319 0 : nsContentUtils::NewURIWithDocumentCharset(nsIURI** aResult,
2320 : const nsAString& aSpec,
2321 : nsIDocument* aDocument,
2322 : nsIURI* aBaseURI)
2323 : {
2324 : return NS_NewURI(aResult, aSpec,
2325 0 : aDocument ? aDocument->GetDocumentCharacterSet().get() : nsnull,
2326 0 : aBaseURI, sIOService);
2327 : }
2328 :
2329 : // static
2330 : bool
2331 0 : nsContentUtils::BelongsInForm(nsIContent *aForm,
2332 : nsIContent *aContent)
2333 : {
2334 0 : NS_PRECONDITION(aForm, "Must have a form");
2335 0 : NS_PRECONDITION(aContent, "Must have a content node");
2336 :
2337 0 : if (aForm == aContent) {
2338 : // A form does not belong inside itself, so we return false here
2339 :
2340 0 : return false;
2341 : }
2342 :
2343 0 : nsIContent* content = aContent->GetParent();
2344 :
2345 0 : while (content) {
2346 0 : if (content == aForm) {
2347 : // aContent is contained within the form so we return true.
2348 :
2349 0 : return true;
2350 : }
2351 :
2352 0 : if (content->Tag() == nsGkAtoms::form &&
2353 0 : content->IsHTML()) {
2354 : // The child is contained within a form, but not the right form
2355 : // so we ignore it.
2356 :
2357 0 : return false;
2358 : }
2359 :
2360 0 : content = content->GetParent();
2361 : }
2362 :
2363 0 : if (aForm->GetChildCount() > 0) {
2364 : // The form is a container but aContent wasn't inside the form,
2365 : // return false
2366 :
2367 0 : return false;
2368 : }
2369 :
2370 : // The form is a leaf and aContent wasn't inside any other form so
2371 : // we check whether the content comes after the form. If it does,
2372 : // return true. If it does not, then it couldn't have been inside
2373 : // the form in the HTML.
2374 0 : if (PositionIsBefore(aForm, aContent)) {
2375 : // We could be in this form!
2376 : // In the future, we may want to get document.forms, look at the
2377 : // form after aForm, and if aContent is after that form after
2378 : // aForm return false here....
2379 0 : return true;
2380 : }
2381 :
2382 0 : return false;
2383 : }
2384 :
2385 : // static
2386 : nsresult
2387 1867 : nsContentUtils::CheckQName(const nsAString& aQualifiedName,
2388 : bool aNamespaceAware)
2389 : {
2390 1867 : nsIParserService *parserService = GetParserService();
2391 1867 : NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
2392 :
2393 : const PRUnichar *colon;
2394 1867 : return parserService->CheckQName(PromiseFlatString(aQualifiedName),
2395 1867 : aNamespaceAware, &colon);
2396 : }
2397 :
2398 : //static
2399 : nsresult
2400 0 : nsContentUtils::SplitQName(const nsIContent* aNamespaceResolver,
2401 : const nsAFlatString& aQName,
2402 : PRInt32 *aNamespace, nsIAtom **aLocalName)
2403 : {
2404 0 : nsIParserService* parserService = GetParserService();
2405 0 : NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
2406 :
2407 : const PRUnichar* colon;
2408 0 : nsresult rv = parserService->CheckQName(aQName, true, &colon);
2409 0 : NS_ENSURE_SUCCESS(rv, rv);
2410 :
2411 0 : if (colon) {
2412 : const PRUnichar* end;
2413 0 : aQName.EndReading(end);
2414 0 : nsAutoString nameSpace;
2415 : rv = aNamespaceResolver->LookupNamespaceURIInternal(Substring(aQName.get(),
2416 0 : colon),
2417 0 : nameSpace);
2418 0 : NS_ENSURE_SUCCESS(rv, rv);
2419 :
2420 0 : *aNamespace = NameSpaceManager()->GetNameSpaceID(nameSpace);
2421 0 : if (*aNamespace == kNameSpaceID_Unknown)
2422 0 : return NS_ERROR_FAILURE;
2423 :
2424 0 : *aLocalName = NS_NewAtom(Substring(colon + 1, end));
2425 : }
2426 : else {
2427 0 : *aNamespace = kNameSpaceID_None;
2428 0 : *aLocalName = NS_NewAtom(aQName);
2429 : }
2430 0 : NS_ENSURE_TRUE(aLocalName, NS_ERROR_OUT_OF_MEMORY);
2431 0 : return NS_OK;
2432 : }
2433 :
2434 : // static
2435 : nsresult
2436 193 : nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI,
2437 : const nsAString& aQualifiedName,
2438 : nsNodeInfoManager* aNodeInfoManager,
2439 : PRUint16 aNodeType,
2440 : nsINodeInfo** aNodeInfo)
2441 : {
2442 193 : nsIParserService* parserService = GetParserService();
2443 193 : NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
2444 :
2445 386 : const nsAFlatString& qName = PromiseFlatString(aQualifiedName);
2446 : const PRUnichar* colon;
2447 193 : nsresult rv = parserService->CheckQName(qName, true, &colon);
2448 193 : NS_ENSURE_SUCCESS(rv, rv);
2449 :
2450 : PRInt32 nsID;
2451 193 : sNameSpaceManager->RegisterNameSpace(aNamespaceURI, nsID);
2452 193 : if (colon) {
2453 : const PRUnichar* end;
2454 15 : qName.EndReading(end);
2455 :
2456 30 : nsCOMPtr<nsIAtom> prefix = do_GetAtom(Substring(qName.get(), colon));
2457 :
2458 15 : rv = aNodeInfoManager->GetNodeInfo(Substring(colon + 1, end), prefix,
2459 15 : nsID, aNodeType, aNodeInfo);
2460 : }
2461 : else {
2462 : rv = aNodeInfoManager->GetNodeInfo(aQualifiedName, nsnull, nsID,
2463 178 : aNodeType, aNodeInfo);
2464 : }
2465 193 : NS_ENSURE_SUCCESS(rv, rv);
2466 :
2467 : return nsContentUtils::IsValidNodeName((*aNodeInfo)->NameAtom(),
2468 : (*aNodeInfo)->GetPrefixAtom(),
2469 193 : (*aNodeInfo)->NamespaceID()) ?
2470 193 : NS_OK : NS_ERROR_DOM_NAMESPACE_ERR;
2471 : }
2472 :
2473 : // static
2474 : void
2475 82909 : nsContentUtils::SplitExpatName(const PRUnichar *aExpatName, nsIAtom **aPrefix,
2476 : nsIAtom **aLocalName, PRInt32* aNameSpaceID)
2477 : {
2478 : /**
2479 : * Expat can send the following:
2480 : * localName
2481 : * namespaceURI<separator>localName
2482 : * namespaceURI<separator>localName<separator>prefix
2483 : *
2484 : * and we use 0xFFFF for the <separator>.
2485 : *
2486 : */
2487 :
2488 82909 : const PRUnichar *uriEnd = nsnull;
2489 82909 : const PRUnichar *nameEnd = nsnull;
2490 : const PRUnichar *pos;
2491 3240318 : for (pos = aExpatName; *pos; ++pos) {
2492 3157409 : if (*pos == 0xFFFF) {
2493 93772 : if (uriEnd) {
2494 34501 : nameEnd = pos;
2495 : }
2496 : else {
2497 59271 : uriEnd = pos;
2498 : }
2499 : }
2500 : }
2501 :
2502 : const PRUnichar *nameStart;
2503 82909 : if (uriEnd) {
2504 59271 : if (sNameSpaceManager) {
2505 : sNameSpaceManager->RegisterNameSpace(nsDependentSubstring(aExpatName,
2506 59271 : uriEnd),
2507 59271 : *aNameSpaceID);
2508 : }
2509 : else {
2510 0 : *aNameSpaceID = kNameSpaceID_Unknown;
2511 : }
2512 :
2513 59271 : nameStart = (uriEnd + 1);
2514 59271 : if (nameEnd) {
2515 34501 : const PRUnichar *prefixStart = nameEnd + 1;
2516 34501 : *aPrefix = NS_NewAtom(Substring(prefixStart, pos));
2517 : }
2518 : else {
2519 24770 : nameEnd = pos;
2520 24770 : *aPrefix = nsnull;
2521 : }
2522 : }
2523 : else {
2524 23638 : *aNameSpaceID = kNameSpaceID_None;
2525 23638 : nameStart = aExpatName;
2526 23638 : nameEnd = pos;
2527 23638 : *aPrefix = nsnull;
2528 : }
2529 82909 : *aLocalName = NS_NewAtom(Substring(nameStart, nameEnd));
2530 82909 : }
2531 :
2532 : // static
2533 : nsPresContext*
2534 0 : nsContentUtils::GetContextForContent(const nsIContent* aContent)
2535 : {
2536 0 : nsIDocument* doc = aContent->GetCurrentDoc();
2537 0 : if (doc) {
2538 0 : nsIPresShell *presShell = doc->GetShell();
2539 0 : if (presShell) {
2540 0 : return presShell->GetPresContext();
2541 : }
2542 : }
2543 0 : return nsnull;
2544 : }
2545 :
2546 : // static
2547 : bool
2548 0 : nsContentUtils::CanLoadImage(nsIURI* aURI, nsISupports* aContext,
2549 : nsIDocument* aLoadingDocument,
2550 : nsIPrincipal* aLoadingPrincipal,
2551 : PRInt16* aImageBlockingStatus)
2552 : {
2553 0 : NS_PRECONDITION(aURI, "Must have a URI");
2554 0 : NS_PRECONDITION(aLoadingDocument, "Must have a document");
2555 0 : NS_PRECONDITION(aLoadingPrincipal, "Must have a loading principal");
2556 :
2557 : nsresult rv;
2558 :
2559 0 : PRUint32 appType = nsIDocShell::APP_TYPE_UNKNOWN;
2560 :
2561 : {
2562 0 : nsCOMPtr<nsISupports> container = aLoadingDocument->GetContainer();
2563 : nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
2564 0 : do_QueryInterface(container);
2565 :
2566 0 : if (docShellTreeItem) {
2567 0 : nsCOMPtr<nsIDocShellTreeItem> root;
2568 0 : docShellTreeItem->GetRootTreeItem(getter_AddRefs(root));
2569 :
2570 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root));
2571 :
2572 0 : if (!docShell || NS_FAILED(docShell->GetAppType(&appType))) {
2573 0 : appType = nsIDocShell::APP_TYPE_UNKNOWN;
2574 : }
2575 : }
2576 : }
2577 :
2578 0 : if (appType != nsIDocShell::APP_TYPE_EDITOR) {
2579 : // Editor apps get special treatment here, editors can load images
2580 : // from anywhere. This allows editor to insert images from file://
2581 : // into documents that are being edited.
2582 : rv = sSecurityManager->
2583 : CheckLoadURIWithPrincipal(aLoadingPrincipal, aURI,
2584 0 : nsIScriptSecurityManager::ALLOW_CHROME);
2585 0 : if (NS_FAILED(rv)) {
2586 0 : if (aImageBlockingStatus) {
2587 : // Reject the request itself, not all requests to the relevant
2588 : // server...
2589 0 : *aImageBlockingStatus = nsIContentPolicy::REJECT_REQUEST;
2590 : }
2591 0 : return false;
2592 : }
2593 : }
2594 :
2595 0 : PRInt16 decision = nsIContentPolicy::ACCEPT;
2596 :
2597 : rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_IMAGE,
2598 : aURI,
2599 : aLoadingPrincipal,
2600 : aContext,
2601 0 : EmptyCString(), //mime guess
2602 : nsnull, //extra
2603 : &decision,
2604 : GetContentPolicy(),
2605 0 : sSecurityManager);
2606 :
2607 0 : if (aImageBlockingStatus) {
2608 : *aImageBlockingStatus =
2609 0 : NS_FAILED(rv) ? nsIContentPolicy::REJECT_REQUEST : decision;
2610 : }
2611 0 : return NS_FAILED(rv) ? false : NS_CP_ACCEPTED(decision);
2612 : }
2613 :
2614 : // static
2615 : bool
2616 0 : nsContentUtils::IsImageInCache(nsIURI* aURI)
2617 : {
2618 0 : if (!sImgLoaderInitialized)
2619 0 : InitImgLoader();
2620 :
2621 0 : if (!sImgCache) return false;
2622 :
2623 : // If something unexpected happened we return false, otherwise if props
2624 : // is set, the image is cached and we return true
2625 0 : nsCOMPtr<nsIProperties> props;
2626 0 : nsresult rv = sImgCache->FindEntryProperties(aURI, getter_AddRefs(props));
2627 0 : return (NS_SUCCEEDED(rv) && props);
2628 : }
2629 :
2630 : // static
2631 : nsresult
2632 0 : nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
2633 : nsIPrincipal* aLoadingPrincipal, nsIURI* aReferrer,
2634 : imgIDecoderObserver* aObserver, PRInt32 aLoadFlags,
2635 : imgIRequest** aRequest)
2636 : {
2637 0 : NS_PRECONDITION(aURI, "Must have a URI");
2638 0 : NS_PRECONDITION(aLoadingDocument, "Must have a document");
2639 0 : NS_PRECONDITION(aLoadingPrincipal, "Must have a principal");
2640 0 : NS_PRECONDITION(aRequest, "Null out param");
2641 :
2642 0 : imgILoader* imgLoader = GetImgLoader();
2643 0 : if (!imgLoader) {
2644 : // nothing we can do here
2645 0 : return NS_OK;
2646 : }
2647 :
2648 0 : nsCOMPtr<nsILoadGroup> loadGroup = aLoadingDocument->GetDocumentLoadGroup();
2649 0 : NS_ASSERTION(loadGroup, "Could not get loadgroup; onload may fire too early");
2650 :
2651 0 : nsIURI *documentURI = aLoadingDocument->GetDocumentURI();
2652 :
2653 : // check for a Content Security Policy to pass down to the channel that
2654 : // will get created to load the image
2655 0 : nsCOMPtr<nsIChannelPolicy> channelPolicy;
2656 0 : nsCOMPtr<nsIContentSecurityPolicy> csp;
2657 0 : if (aLoadingPrincipal) {
2658 0 : nsresult rv = aLoadingPrincipal->GetCsp(getter_AddRefs(csp));
2659 0 : NS_ENSURE_SUCCESS(rv, rv);
2660 0 : if (csp) {
2661 0 : channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
2662 0 : channelPolicy->SetContentSecurityPolicy(csp);
2663 0 : channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE);
2664 : }
2665 : }
2666 :
2667 : // Make the URI immutable so people won't change it under us
2668 0 : NS_TryToSetImmutable(aURI);
2669 :
2670 : // XXXbz using "documentURI" for the initialDocumentURI is not quite
2671 : // right, but the best we can do here...
2672 : return imgLoader->LoadImage(aURI, /* uri to load */
2673 : documentURI, /* initialDocumentURI */
2674 : aReferrer, /* referrer */
2675 : aLoadingPrincipal, /* loading principal */
2676 : loadGroup, /* loadgroup */
2677 : aObserver, /* imgIDecoderObserver */
2678 : aLoadingDocument, /* uniquification key */
2679 : aLoadFlags, /* load flags */
2680 : nsnull, /* cache key */
2681 : nsnull, /* existing request*/
2682 : channelPolicy, /* CSP info */
2683 0 : aRequest);
2684 : }
2685 :
2686 : // static
2687 : already_AddRefed<imgIContainer>
2688 0 : nsContentUtils::GetImageFromContent(nsIImageLoadingContent* aContent,
2689 : imgIRequest **aRequest)
2690 : {
2691 0 : if (aRequest) {
2692 0 : *aRequest = nsnull;
2693 : }
2694 :
2695 0 : NS_ENSURE_TRUE(aContent, nsnull);
2696 :
2697 0 : nsCOMPtr<imgIRequest> imgRequest;
2698 : aContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
2699 0 : getter_AddRefs(imgRequest));
2700 0 : if (!imgRequest) {
2701 0 : return nsnull;
2702 : }
2703 :
2704 0 : nsCOMPtr<imgIContainer> imgContainer;
2705 0 : imgRequest->GetImage(getter_AddRefs(imgContainer));
2706 :
2707 0 : if (!imgContainer) {
2708 0 : return nsnull;
2709 : }
2710 :
2711 0 : if (aRequest) {
2712 0 : imgRequest.swap(*aRequest);
2713 : }
2714 :
2715 0 : return imgContainer.forget();
2716 : }
2717 :
2718 : //static
2719 : already_AddRefed<imgIRequest>
2720 0 : nsContentUtils::GetStaticRequest(imgIRequest* aRequest)
2721 : {
2722 0 : NS_ENSURE_TRUE(aRequest, nsnull);
2723 0 : nsCOMPtr<imgIRequest> retval;
2724 0 : aRequest->GetStaticRequest(getter_AddRefs(retval));
2725 0 : return retval.forget();
2726 : }
2727 :
2728 : // static
2729 : bool
2730 0 : nsContentUtils::ContentIsDraggable(nsIContent* aContent)
2731 : {
2732 0 : nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(aContent);
2733 0 : if (htmlElement) {
2734 0 : bool draggable = false;
2735 0 : htmlElement->GetDraggable(&draggable);
2736 0 : if (draggable)
2737 0 : return true;
2738 :
2739 0 : if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
2740 0 : nsGkAtoms::_false, eIgnoreCase))
2741 0 : return false;
2742 : }
2743 :
2744 : // special handling for content area image and link dragging
2745 0 : return IsDraggableImage(aContent) || IsDraggableLink(aContent);
2746 : }
2747 :
2748 : // static
2749 : bool
2750 0 : nsContentUtils::IsDraggableImage(nsIContent* aContent)
2751 : {
2752 0 : NS_PRECONDITION(aContent, "Must have content node to test");
2753 :
2754 0 : nsCOMPtr<nsIImageLoadingContent> imageContent(do_QueryInterface(aContent));
2755 0 : if (!imageContent) {
2756 0 : return false;
2757 : }
2758 :
2759 0 : nsCOMPtr<imgIRequest> imgRequest;
2760 0 : imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
2761 0 : getter_AddRefs(imgRequest));
2762 :
2763 : // XXXbz It may be draggable even if the request resulted in an error. Why?
2764 : // Not sure; that's what the old nsContentAreaDragDrop/nsFrame code did.
2765 0 : return imgRequest != nsnull;
2766 : }
2767 :
2768 : // static
2769 : bool
2770 0 : nsContentUtils::IsDraggableLink(const nsIContent* aContent) {
2771 0 : nsCOMPtr<nsIURI> absURI;
2772 0 : return aContent->IsLink(getter_AddRefs(absURI));
2773 : }
2774 :
2775 : bool
2776 0 : nsContentUtils::IsSitePermAllow(nsIURI* aURI, const char* aType)
2777 : {
2778 : nsCOMPtr<nsIPermissionManager> permMgr =
2779 0 : do_GetService("@mozilla.org/permissionmanager;1");
2780 0 : NS_ENSURE_TRUE(permMgr, false);
2781 :
2782 : PRUint32 perm;
2783 0 : nsresult rv = permMgr->TestPermission(aURI, aType, &perm);
2784 0 : NS_ENSURE_SUCCESS(rv, false);
2785 :
2786 0 : return perm == nsIPermissionManager::ALLOW_ACTION;
2787 : }
2788 :
2789 : static const char *gEventNames[] = {"event"};
2790 : static const char *gSVGEventNames[] = {"evt"};
2791 : // for b/w compat, the first name to onerror is still 'event', even though it
2792 : // is actually the error message. (pre this code, the other 2 were not avail.)
2793 : // XXXmarkh - a quick lxr shows no affected code - should we correct this?
2794 : static const char *gOnErrorNames[] = {"event", "source", "lineno"};
2795 :
2796 : // static
2797 : void
2798 0 : nsContentUtils::GetEventArgNames(PRInt32 aNameSpaceID,
2799 : nsIAtom *aEventName,
2800 : PRUint32 *aArgCount,
2801 : const char*** aArgArray)
2802 : {
2803 : #define SET_EVENT_ARG_NAMES(names) \
2804 : *aArgCount = sizeof(names)/sizeof(names[0]); \
2805 : *aArgArray = names;
2806 :
2807 : // nsJSEventListener is what does the arg magic for onerror, and it does
2808 : // not seem to take the namespace into account. So we let onerror in all
2809 : // namespaces get the 3 arg names.
2810 0 : if (aEventName == nsGkAtoms::onerror) {
2811 0 : SET_EVENT_ARG_NAMES(gOnErrorNames);
2812 0 : } else if (aNameSpaceID == kNameSpaceID_SVG) {
2813 0 : SET_EVENT_ARG_NAMES(gSVGEventNames);
2814 : } else {
2815 0 : SET_EVENT_ARG_NAMES(gEventNames);
2816 : }
2817 0 : }
2818 :
2819 16904 : nsCxPusher::nsCxPusher()
2820 : : mScriptIsRunning(false),
2821 16904 : mPushedSomething(false)
2822 : {
2823 16904 : }
2824 :
2825 33808 : nsCxPusher::~nsCxPusher()
2826 : {
2827 16904 : Pop();
2828 16904 : }
2829 :
2830 : static bool
2831 261 : IsContextOnStack(nsIJSContextStack *aStack, JSContext *aContext)
2832 : {
2833 261 : JSContext *ctx = nsnull;
2834 261 : aStack->Peek(&ctx);
2835 261 : if (!ctx)
2836 0 : return false;
2837 261 : if (ctx == aContext)
2838 261 : return true;
2839 :
2840 : nsCOMPtr<nsIJSContextStackIterator>
2841 0 : iterator(do_CreateInstance("@mozilla.org/js/xpc/ContextStackIterator;1"));
2842 0 : NS_ENSURE_TRUE(iterator, false);
2843 :
2844 0 : nsresult rv = iterator->Reset(aStack);
2845 0 : NS_ENSURE_SUCCESS(rv, false);
2846 :
2847 : bool done;
2848 0 : while (NS_SUCCEEDED(iterator->Done(&done)) && !done) {
2849 0 : rv = iterator->Prev(&ctx);
2850 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "Broken iterator implementation");
2851 :
2852 0 : if (!ctx) {
2853 0 : continue;
2854 : }
2855 :
2856 0 : if (nsJSUtils::GetDynamicScriptContext(ctx) && ctx == aContext)
2857 0 : return true;
2858 : }
2859 :
2860 0 : return false;
2861 : }
2862 :
2863 : bool
2864 3972 : nsCxPusher::Push(nsIDOMEventTarget *aCurrentTarget)
2865 : {
2866 3972 : if (mPushedSomething) {
2867 0 : NS_ERROR("Whaaa! No double pushing with nsCxPusher::Push()!");
2868 :
2869 0 : return false;
2870 : }
2871 :
2872 3972 : NS_ENSURE_TRUE(aCurrentTarget, false);
2873 : nsresult rv;
2874 : nsIScriptContext* scx =
2875 3972 : aCurrentTarget->GetContextForEventHandlers(&rv);
2876 3972 : NS_ENSURE_SUCCESS(rv, false);
2877 :
2878 3972 : if (!scx) {
2879 : // The target may have a special JS context for event handlers.
2880 3972 : JSContext* cx = aCurrentTarget->GetJSContextForEventHandlers();
2881 3972 : if (cx) {
2882 0 : DoPush(cx);
2883 : }
2884 :
2885 : // Nothing to do here, I guess. Have to return true so that event firing
2886 : // will still work correctly even if there is no associated JSContext
2887 3972 : return true;
2888 : }
2889 :
2890 0 : JSContext* cx = nsnull;
2891 :
2892 0 : if (scx) {
2893 0 : cx = scx->GetNativeContext();
2894 : // Bad, no JSContext from script context!
2895 0 : NS_ENSURE_TRUE(cx, false);
2896 : }
2897 :
2898 : // If there's no native context in the script context it must be
2899 : // in the process or being torn down. We don't want to notify the
2900 : // script context about scripts having been evaluated in such a
2901 : // case, calling with a null cx is fine in that case.
2902 0 : return Push(cx);
2903 : }
2904 :
2905 : bool
2906 3972 : nsCxPusher::RePush(nsIDOMEventTarget *aCurrentTarget)
2907 : {
2908 3972 : if (!mPushedSomething) {
2909 3972 : return Push(aCurrentTarget);
2910 : }
2911 :
2912 0 : if (aCurrentTarget) {
2913 : nsresult rv;
2914 : nsIScriptContext* scx =
2915 0 : aCurrentTarget->GetContextForEventHandlers(&rv);
2916 0 : if (NS_FAILED(rv)) {
2917 0 : Pop();
2918 0 : return false;
2919 : }
2920 :
2921 : // If we have the same script context and native context is still
2922 : // alive, no need to Pop/Push.
2923 0 : if (scx && scx == mScx &&
2924 0 : scx->GetNativeContext()) {
2925 0 : return true;
2926 : }
2927 : }
2928 :
2929 0 : Pop();
2930 0 : return Push(aCurrentTarget);
2931 : }
2932 :
2933 : bool
2934 261 : nsCxPusher::Push(JSContext *cx, bool aRequiresScriptContext)
2935 : {
2936 261 : if (mPushedSomething) {
2937 0 : NS_ERROR("Whaaa! No double pushing with nsCxPusher::Push()!");
2938 :
2939 0 : return false;
2940 : }
2941 :
2942 261 : if (!cx) {
2943 0 : return false;
2944 : }
2945 :
2946 : // Hold a strong ref to the nsIScriptContext, just in case
2947 : // XXXbz do we really need to? If we don't get one of these in Pop(), is
2948 : // that really a problem? Or do we need to do this to effectively root |cx|?
2949 261 : mScx = GetScriptContextFromJSContext(cx);
2950 261 : if (!mScx && aRequiresScriptContext) {
2951 : // Should probably return false. See bug 416916.
2952 0 : return true;
2953 : }
2954 :
2955 261 : return DoPush(cx);
2956 : }
2957 :
2958 : bool
2959 261 : nsCxPusher::DoPush(JSContext* cx)
2960 : {
2961 261 : nsIThreadJSContextStack* stack = nsContentUtils::ThreadJSContextStack();
2962 261 : if (!stack) {
2963 0 : return true;
2964 : }
2965 :
2966 261 : if (cx && IsContextOnStack(stack, cx)) {
2967 : // If the context is on the stack, that means that a script
2968 : // is running at the moment in the context.
2969 261 : mScriptIsRunning = true;
2970 : }
2971 :
2972 261 : if (NS_FAILED(stack->Push(cx))) {
2973 0 : mScriptIsRunning = false;
2974 0 : mScx = nsnull;
2975 0 : return false;
2976 : }
2977 :
2978 261 : mPushedSomething = true;
2979 : #ifdef DEBUG
2980 261 : mPushedContext = cx;
2981 : #endif
2982 261 : return true;
2983 : }
2984 :
2985 : bool
2986 0 : nsCxPusher::PushNull()
2987 : {
2988 0 : return DoPush(nsnull);
2989 : }
2990 :
2991 : void
2992 33379 : nsCxPusher::Pop()
2993 : {
2994 33379 : nsIThreadJSContextStack* stack = nsContentUtils::ThreadJSContextStack();
2995 33379 : if (!mPushedSomething || !stack) {
2996 33118 : mScx = nsnull;
2997 33118 : mPushedSomething = false;
2998 :
2999 33118 : NS_ASSERTION(!mScriptIsRunning, "Huh, this can't be happening, "
3000 : "mScriptIsRunning can't be set here!");
3001 :
3002 33118 : return;
3003 : }
3004 :
3005 : JSContext *unused;
3006 261 : stack->Pop(&unused);
3007 :
3008 261 : NS_ASSERTION(unused == mPushedContext, "Unexpected context popped");
3009 :
3010 261 : if (!mScriptIsRunning && mScx) {
3011 : // No JS is running in the context, but executing the event handler might have
3012 : // caused some JS to run. Tell the script context that it's done.
3013 :
3014 0 : mScx->ScriptEvaluated(true);
3015 : }
3016 :
3017 261 : mScx = nsnull;
3018 261 : mScriptIsRunning = false;
3019 261 : mPushedSomething = false;
3020 : }
3021 :
3022 : static const char gPropertiesFiles[nsContentUtils::PropertiesFile_COUNT][56] = {
3023 : // Must line up with the enum values in |PropertiesFile| enum.
3024 : "chrome://global/locale/css.properties",
3025 : "chrome://global/locale/xbl.properties",
3026 : "chrome://global/locale/xul.properties",
3027 : "chrome://global/locale/layout_errors.properties",
3028 : "chrome://global/locale/layout/HtmlForm.properties",
3029 : "chrome://global/locale/printing.properties",
3030 : "chrome://global/locale/dom/dom.properties",
3031 : "chrome://global/locale/layout/htmlparser.properties",
3032 : "chrome://global/locale/svg/svg.properties",
3033 : "chrome://branding/locale/brand.properties",
3034 : "chrome://global/locale/commonDialogs.properties"
3035 : };
3036 :
3037 : /* static */ nsresult
3038 28 : nsContentUtils::EnsureStringBundle(PropertiesFile aFile)
3039 : {
3040 28 : if (!sStringBundles[aFile]) {
3041 4 : if (!sStringBundleService) {
3042 : nsresult rv =
3043 4 : CallGetService(NS_STRINGBUNDLE_CONTRACTID, &sStringBundleService);
3044 4 : NS_ENSURE_SUCCESS(rv, rv);
3045 : }
3046 : nsIStringBundle *bundle;
3047 : nsresult rv =
3048 4 : sStringBundleService->CreateBundle(gPropertiesFiles[aFile], &bundle);
3049 4 : NS_ENSURE_SUCCESS(rv, rv);
3050 4 : sStringBundles[aFile] = bundle; // transfer ownership
3051 : }
3052 28 : return NS_OK;
3053 : }
3054 :
3055 : /* static */
3056 28 : nsresult nsContentUtils::GetLocalizedString(PropertiesFile aFile,
3057 : const char* aKey,
3058 : nsXPIDLString& aResult)
3059 : {
3060 28 : nsresult rv = EnsureStringBundle(aFile);
3061 28 : NS_ENSURE_SUCCESS(rv, rv);
3062 28 : nsIStringBundle *bundle = sStringBundles[aFile];
3063 :
3064 28 : return bundle->GetStringFromName(NS_ConvertASCIItoUTF16(aKey).get(),
3065 56 : getter_Copies(aResult));
3066 : }
3067 :
3068 : /* static */
3069 0 : nsresult nsContentUtils::FormatLocalizedString(PropertiesFile aFile,
3070 : const char* aKey,
3071 : const PRUnichar **aParams,
3072 : PRUint32 aParamsLength,
3073 : nsXPIDLString& aResult)
3074 : {
3075 0 : nsresult rv = EnsureStringBundle(aFile);
3076 0 : NS_ENSURE_SUCCESS(rv, rv);
3077 0 : nsIStringBundle *bundle = sStringBundles[aFile];
3078 :
3079 0 : return bundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aKey).get(),
3080 : aParams, aParamsLength,
3081 0 : getter_Copies(aResult));
3082 : }
3083 :
3084 : /* static */ nsresult
3085 28 : nsContentUtils::ReportToConsole(PRUint32 aErrorFlags,
3086 : const char *aCategory,
3087 : nsIDocument* aDocument,
3088 : PropertiesFile aFile,
3089 : const char *aMessageName,
3090 : const PRUnichar **aParams,
3091 : PRUint32 aParamsLength,
3092 : nsIURI* aURI,
3093 : const nsAFlatString& aSourceLine,
3094 : PRUint32 aLineNumber,
3095 : PRUint32 aColumnNumber)
3096 : {
3097 28 : NS_ASSERTION((aParams && aParamsLength) || (!aParams && !aParamsLength),
3098 : "Supply either both parameters and their number or no"
3099 : "parameters and 0.");
3100 :
3101 28 : PRUint64 innerWindowID = 0;
3102 28 : if (aDocument) {
3103 5 : if (!aURI) {
3104 5 : aURI = aDocument->GetDocumentURI();
3105 : }
3106 5 : innerWindowID = aDocument->InnerWindowID();
3107 : }
3108 :
3109 : nsresult rv;
3110 28 : if (!sConsoleService) { // only need to bother null-checking here
3111 4 : rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService);
3112 4 : NS_ENSURE_SUCCESS(rv, rv);
3113 : }
3114 :
3115 56 : nsXPIDLString errorText;
3116 28 : if (aParams) {
3117 : rv = FormatLocalizedString(aFile, aMessageName, aParams, aParamsLength,
3118 0 : errorText);
3119 : }
3120 : else {
3121 28 : rv = GetLocalizedString(aFile, aMessageName, errorText);
3122 : }
3123 28 : NS_ENSURE_SUCCESS(rv, rv);
3124 :
3125 56 : nsCAutoString spec;
3126 28 : if (aURI)
3127 5 : aURI->GetSpec(spec);
3128 :
3129 : nsCOMPtr<nsIScriptError> errorObject =
3130 56 : do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
3131 28 : NS_ENSURE_SUCCESS(rv, rv);
3132 :
3133 28 : rv = errorObject->InitWithWindowID(errorText.get(),
3134 28 : NS_ConvertUTF8toUTF16(spec).get(), // file name
3135 : aSourceLine.get(),
3136 : aLineNumber, aColumnNumber,
3137 : aErrorFlags, aCategory,
3138 28 : innerWindowID);
3139 28 : NS_ENSURE_SUCCESS(rv, rv);
3140 :
3141 28 : return sConsoleService->LogMessage(errorObject);
3142 : }
3143 :
3144 : bool
3145 2 : nsContentUtils::IsChromeDoc(nsIDocument *aDocument)
3146 : {
3147 2 : if (!aDocument) {
3148 0 : return false;
3149 : }
3150 :
3151 4 : nsCOMPtr<nsIPrincipal> systemPrincipal;
3152 2 : sSecurityManager->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
3153 :
3154 2 : return aDocument->NodePrincipal() == systemPrincipal;
3155 : }
3156 :
3157 : bool
3158 0 : nsContentUtils::IsChildOfSameType(nsIDocument* aDoc)
3159 : {
3160 0 : nsCOMPtr<nsISupports> container = aDoc->GetContainer();
3161 0 : nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(container));
3162 0 : nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
3163 0 : if (docShellAsItem) {
3164 0 : docShellAsItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
3165 : }
3166 0 : return sameTypeParent != nsnull;
3167 : }
3168 :
3169 : bool
3170 0 : nsContentUtils::GetWrapperSafeScriptFilename(nsIDocument *aDocument,
3171 : nsIURI *aURI,
3172 : nsACString& aScriptURI)
3173 : {
3174 0 : bool scriptFileNameModified = false;
3175 0 : aURI->GetSpec(aScriptURI);
3176 :
3177 0 : if (IsChromeDoc(aDocument)) {
3178 : nsCOMPtr<nsIChromeRegistry> chromeReg =
3179 0 : mozilla::services::GetChromeRegistryService();
3180 :
3181 0 : if (!chromeReg) {
3182 : // If we're running w/o a chrome registry we won't modify any
3183 : // script file names.
3184 :
3185 0 : return scriptFileNameModified;
3186 : }
3187 :
3188 : bool docWrappersEnabled =
3189 0 : chromeReg->WrappersEnabled(aDocument->GetDocumentURI());
3190 :
3191 0 : bool uriWrappersEnabled = chromeReg->WrappersEnabled(aURI);
3192 :
3193 0 : nsIURI *docURI = aDocument->GetDocumentURI();
3194 :
3195 0 : if (docURI && docWrappersEnabled && !uriWrappersEnabled) {
3196 : // aURI is a script from a URL that doesn't get wrapper
3197 : // automation. aDocument is a chrome document that does get
3198 : // wrapper automation. Prepend the chrome document's URI
3199 : // followed by the string " -> " to the URI of the script we're
3200 : // loading here so that script in that URI gets the same wrapper
3201 : // automation that the chrome document expects.
3202 0 : nsCAutoString spec;
3203 0 : docURI->GetSpec(spec);
3204 0 : spec.AppendASCII(" -> ");
3205 0 : spec.Append(aScriptURI);
3206 :
3207 0 : aScriptURI = spec;
3208 :
3209 0 : scriptFileNameModified = true;
3210 : }
3211 : }
3212 :
3213 0 : return scriptFileNameModified;
3214 : }
3215 :
3216 : // static
3217 : bool
3218 0 : nsContentUtils::IsInChromeDocshell(nsIDocument *aDocument)
3219 : {
3220 0 : if (!aDocument) {
3221 0 : return false;
3222 : }
3223 :
3224 0 : if (aDocument->GetDisplayDocument()) {
3225 0 : return IsInChromeDocshell(aDocument->GetDisplayDocument());
3226 : }
3227 :
3228 0 : nsCOMPtr<nsISupports> docContainer = aDocument->GetContainer();
3229 0 : nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryInterface(docContainer));
3230 0 : PRInt32 itemType = nsIDocShellTreeItem::typeContent;
3231 0 : if (docShell) {
3232 0 : docShell->GetItemType(&itemType);
3233 : }
3234 :
3235 0 : return itemType == nsIDocShellTreeItem::typeChrome;
3236 : }
3237 :
3238 : // static
3239 : nsIContentPolicy*
3240 598 : nsContentUtils::GetContentPolicy()
3241 : {
3242 598 : if (!sTriedToGetContentPolicy) {
3243 110 : CallGetService(NS_CONTENTPOLICY_CONTRACTID, &sContentPolicyService);
3244 : // It's OK to not have a content policy service
3245 110 : sTriedToGetContentPolicy = true;
3246 : }
3247 :
3248 598 : return sContentPolicyService;
3249 : }
3250 :
3251 : // static
3252 : bool
3253 72 : nsContentUtils::IsEventAttributeName(nsIAtom* aName, PRInt32 aType)
3254 : {
3255 72 : const PRUnichar* name = aName->GetUTF16String();
3256 72 : if (name[0] != 'o' || name[1] != 'n')
3257 72 : return false;
3258 :
3259 : EventNameMapping mapping;
3260 0 : return (sAtomEventTable->Get(aName, &mapping) && mapping.mType & aType);
3261 : }
3262 :
3263 : // static
3264 : PRUint32
3265 4613 : nsContentUtils::GetEventId(nsIAtom* aName)
3266 : {
3267 : EventNameMapping mapping;
3268 4613 : if (sAtomEventTable->Get(aName, &mapping))
3269 2906 : return mapping.mId;
3270 :
3271 1707 : return NS_USER_DEFINED_EVENT;
3272 : }
3273 :
3274 : // static
3275 : PRUint32
3276 0 : nsContentUtils::GetEventCategory(const nsAString& aName)
3277 : {
3278 : EventNameMapping mapping;
3279 0 : if (sStringEventTable->Get(aName, &mapping))
3280 0 : return mapping.mStructType;
3281 :
3282 0 : return NS_EVENT;
3283 : }
3284 :
3285 : nsIAtom*
3286 16367 : nsContentUtils::GetEventIdAndAtom(const nsAString& aName,
3287 : PRUint32 aEventStruct,
3288 : PRUint32* aEventID)
3289 : {
3290 : EventNameMapping mapping;
3291 16367 : if (sStringEventTable->Get(aName, &mapping)) {
3292 : *aEventID =
3293 15351 : mapping.mStructType == aEventStruct ? mapping.mId : NS_USER_DEFINED_EVENT;
3294 15351 : return mapping.mAtom;
3295 : }
3296 :
3297 : // If we have cached lots of user defined event names, clear some of them.
3298 1016 : if (sUserDefinedEvents->Count() > 127) {
3299 0 : while (sUserDefinedEvents->Count() > 64) {
3300 0 : nsIAtom* first = sUserDefinedEvents->ObjectAt(0);
3301 0 : sStringEventTable->Remove(Substring(nsDependentAtomString(first), 2));
3302 0 : sUserDefinedEvents->RemoveObjectAt(0);
3303 : }
3304 : }
3305 :
3306 1016 : *aEventID = NS_USER_DEFINED_EVENT;
3307 2032 : nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aName);
3308 1016 : sUserDefinedEvents->AppendObject(atom);
3309 1016 : mapping.mAtom = atom;
3310 1016 : mapping.mId = NS_USER_DEFINED_EVENT;
3311 1016 : mapping.mType = EventNameType_None;
3312 1016 : mapping.mStructType = NS_EVENT_NULL;
3313 1016 : sStringEventTable->Put(aName, mapping);
3314 1016 : return mapping.mAtom;
3315 : }
3316 :
3317 : static
3318 6401 : nsresult GetEventAndTarget(nsIDocument* aDoc, nsISupports* aTarget,
3319 : const nsAString& aEventName,
3320 : bool aCanBubble, bool aCancelable,
3321 : bool aTrusted, nsIDOMEvent** aEvent,
3322 : nsIDOMEventTarget** aTargetOut)
3323 : {
3324 12802 : nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
3325 12802 : nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(aTarget));
3326 6401 : NS_ENSURE_TRUE(domDoc && target, NS_ERROR_INVALID_ARG);
3327 :
3328 12802 : nsCOMPtr<nsIDOMEvent> event;
3329 : nsresult rv =
3330 6401 : domDoc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
3331 6401 : NS_ENSURE_SUCCESS(rv, rv);
3332 :
3333 12802 : nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
3334 6401 : NS_ENSURE_TRUE(privateEvent, NS_ERROR_FAILURE);
3335 :
3336 6401 : rv = event->InitEvent(aEventName, aCanBubble, aCancelable);
3337 6401 : NS_ENSURE_SUCCESS(rv, rv);
3338 :
3339 6401 : rv = privateEvent->SetTrusted(aTrusted);
3340 6401 : NS_ENSURE_SUCCESS(rv, rv);
3341 :
3342 6401 : rv = privateEvent->SetTarget(target);
3343 6401 : NS_ENSURE_SUCCESS(rv, rv);
3344 :
3345 6401 : event.forget(aEvent);
3346 6401 : target.forget(aTargetOut);
3347 6401 : return NS_OK;
3348 : }
3349 :
3350 : // static
3351 : nsresult
3352 5363 : nsContentUtils::DispatchTrustedEvent(nsIDocument* aDoc, nsISupports* aTarget,
3353 : const nsAString& aEventName,
3354 : bool aCanBubble, bool aCancelable,
3355 : bool *aDefaultAction)
3356 : {
3357 : return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
3358 5363 : true, aDefaultAction);
3359 : }
3360 :
3361 : // static
3362 : nsresult
3363 0 : nsContentUtils::DispatchUntrustedEvent(nsIDocument* aDoc, nsISupports* aTarget,
3364 : const nsAString& aEventName,
3365 : bool aCanBubble, bool aCancelable,
3366 : bool *aDefaultAction)
3367 : {
3368 : return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
3369 0 : false, aDefaultAction);
3370 : }
3371 :
3372 : // static
3373 : nsresult
3374 5363 : nsContentUtils::DispatchEvent(nsIDocument* aDoc, nsISupports* aTarget,
3375 : const nsAString& aEventName,
3376 : bool aCanBubble, bool aCancelable,
3377 : bool aTrusted, bool *aDefaultAction)
3378 : {
3379 10726 : nsCOMPtr<nsIDOMEvent> event;
3380 10726 : nsCOMPtr<nsIDOMEventTarget> target;
3381 : nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble,
3382 5363 : aCancelable, aTrusted, getter_AddRefs(event),
3383 10726 : getter_AddRefs(target));
3384 5363 : NS_ENSURE_SUCCESS(rv, rv);
3385 :
3386 : bool dummy;
3387 5363 : return target->DispatchEvent(event, aDefaultAction ? aDefaultAction : &dummy);
3388 : }
3389 :
3390 : nsresult
3391 1038 : nsContentUtils::DispatchChromeEvent(nsIDocument *aDoc,
3392 : nsISupports *aTarget,
3393 : const nsAString& aEventName,
3394 : bool aCanBubble, bool aCancelable,
3395 : bool *aDefaultAction)
3396 : {
3397 :
3398 2076 : nsCOMPtr<nsIDOMEvent> event;
3399 2076 : nsCOMPtr<nsIDOMEventTarget> target;
3400 : nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble,
3401 1038 : aCancelable, true, getter_AddRefs(event),
3402 2076 : getter_AddRefs(target));
3403 1038 : NS_ENSURE_SUCCESS(rv, rv);
3404 :
3405 1038 : NS_ASSERTION(aDoc, "GetEventAndTarget lied?");
3406 1038 : if (!aDoc->GetWindow())
3407 1038 : return NS_ERROR_INVALID_ARG;
3408 :
3409 0 : nsIDOMEventTarget* piTarget = aDoc->GetWindow()->GetChromeEventHandler();
3410 0 : if (!piTarget)
3411 0 : return NS_ERROR_INVALID_ARG;
3412 :
3413 0 : nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(piTarget);
3414 0 : if (flo) {
3415 0 : nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
3416 0 : if (fl) {
3417 0 : nsIDOMEventTarget* t = fl->GetTabChildGlobalAsEventTarget();
3418 0 : piTarget = t ? t : piTarget;
3419 : }
3420 : }
3421 :
3422 0 : nsEventStatus status = nsEventStatus_eIgnore;
3423 0 : rv = piTarget->DispatchDOMEvent(nsnull, event, nsnull, &status);
3424 0 : if (aDefaultAction) {
3425 0 : *aDefaultAction = (status != nsEventStatus_eConsumeNoDefault);
3426 : }
3427 0 : return rv;
3428 : }
3429 :
3430 : /* static */
3431 : Element*
3432 0 : nsContentUtils::MatchElementId(nsIContent *aContent, const nsIAtom* aId)
3433 : {
3434 0 : for (nsIContent* cur = aContent;
3435 : cur;
3436 0 : cur = cur->GetNextNode(aContent)) {
3437 0 : if (aId == cur->GetID()) {
3438 0 : return cur->AsElement();
3439 : }
3440 : }
3441 :
3442 0 : return nsnull;
3443 : }
3444 :
3445 : /* static */
3446 : Element *
3447 0 : nsContentUtils::MatchElementId(nsIContent *aContent, const nsAString& aId)
3448 : {
3449 0 : NS_PRECONDITION(!aId.IsEmpty(), "Will match random elements");
3450 :
3451 : // ID attrs are generally stored as atoms, so just atomize this up front
3452 0 : nsCOMPtr<nsIAtom> id(do_GetAtom(aId));
3453 0 : if (!id) {
3454 : // OOM, so just bail
3455 0 : return nsnull;
3456 : }
3457 :
3458 0 : return MatchElementId(aContent, id);
3459 : }
3460 :
3461 : // Convert the string from the given charset to Unicode.
3462 : /* static */
3463 : nsresult
3464 0 : nsContentUtils::ConvertStringFromCharset(const nsACString& aCharset,
3465 : const nsACString& aInput,
3466 : nsAString& aOutput)
3467 : {
3468 0 : if (aCharset.IsEmpty()) {
3469 : // Treat the string as UTF8
3470 0 : CopyUTF8toUTF16(aInput, aOutput);
3471 0 : return NS_OK;
3472 : }
3473 :
3474 : nsresult rv;
3475 : nsCOMPtr<nsICharsetConverterManager> ccm =
3476 0 : do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
3477 0 : if (NS_FAILED(rv))
3478 0 : return rv;
3479 :
3480 0 : nsCOMPtr<nsIUnicodeDecoder> decoder;
3481 0 : rv = ccm->GetUnicodeDecoder(PromiseFlatCString(aCharset).get(),
3482 0 : getter_AddRefs(decoder));
3483 0 : if (NS_FAILED(rv))
3484 0 : return rv;
3485 :
3486 0 : nsPromiseFlatCString flatInput(aInput);
3487 0 : PRInt32 srcLen = flatInput.Length();
3488 : PRInt32 dstLen;
3489 0 : rv = decoder->GetMaxLength(flatInput.get(), srcLen, &dstLen);
3490 0 : if (NS_FAILED(rv))
3491 0 : return rv;
3492 :
3493 : PRUnichar *ustr = (PRUnichar *)nsMemory::Alloc((dstLen + 1) *
3494 0 : sizeof(PRUnichar));
3495 0 : if (!ustr)
3496 0 : return NS_ERROR_OUT_OF_MEMORY;
3497 :
3498 0 : rv = decoder->Convert(flatInput.get(), &srcLen, ustr, &dstLen);
3499 0 : if (NS_SUCCEEDED(rv)) {
3500 0 : ustr[dstLen] = 0;
3501 0 : aOutput.Assign(ustr, dstLen);
3502 : }
3503 :
3504 0 : nsMemory::Free(ustr);
3505 0 : return rv;
3506 : }
3507 :
3508 : /* static */
3509 : bool
3510 286 : nsContentUtils::CheckForBOM(const unsigned char* aBuffer, PRUint32 aLength,
3511 : nsACString& aCharset, bool *bigEndian)
3512 : {
3513 286 : bool found = true;
3514 286 : aCharset.Truncate();
3515 571 : if (aLength >= 3 &&
3516 285 : aBuffer[0] == 0xEF &&
3517 0 : aBuffer[1] == 0xBB &&
3518 0 : aBuffer[2] == 0xBF) {
3519 0 : aCharset = "UTF-8";
3520 : }
3521 572 : else if (aLength >= 2 &&
3522 286 : aBuffer[0] == 0xFE && aBuffer[1] == 0xFF) {
3523 0 : aCharset = "UTF-16";
3524 0 : if (bigEndian)
3525 0 : *bigEndian = true;
3526 : }
3527 572 : else if (aLength >= 2 &&
3528 286 : aBuffer[0] == 0xFF && aBuffer[1] == 0xFE) {
3529 0 : aCharset = "UTF-16";
3530 0 : if (bigEndian)
3531 0 : *bigEndian = false;
3532 : } else {
3533 286 : found = false;
3534 : }
3535 :
3536 286 : return found;
3537 : }
3538 :
3539 : /* static */
3540 : void
3541 0 : nsContentUtils::RegisterShutdownObserver(nsIObserver* aObserver)
3542 : {
3543 : nsCOMPtr<nsIObserverService> observerService =
3544 0 : mozilla::services::GetObserverService();
3545 0 : if (observerService) {
3546 0 : observerService->AddObserver(aObserver,
3547 : NS_XPCOM_SHUTDOWN_OBSERVER_ID,
3548 0 : false);
3549 : }
3550 0 : }
3551 :
3552 : /* static */
3553 : void
3554 0 : nsContentUtils::UnregisterShutdownObserver(nsIObserver* aObserver)
3555 : {
3556 : nsCOMPtr<nsIObserverService> observerService =
3557 0 : mozilla::services::GetObserverService();
3558 0 : if (observerService) {
3559 0 : observerService->RemoveObserver(aObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
3560 : }
3561 0 : }
3562 :
3563 : /* static */
3564 : bool
3565 3 : nsContentUtils::HasNonEmptyAttr(const nsIContent* aContent, PRInt32 aNameSpaceID,
3566 : nsIAtom* aName)
3567 : {
3568 : static nsIContent::AttrValuesArray strings[] = {&nsGkAtoms::_empty, nsnull};
3569 3 : return aContent->FindAttrValueIn(aNameSpaceID, aName, strings, eCaseMatters)
3570 3 : == nsIContent::ATTR_VALUE_NO_MATCH;
3571 : }
3572 :
3573 : /* static */
3574 : bool
3575 3616 : nsContentUtils::HasMutationListeners(nsINode* aNode,
3576 : PRUint32 aType,
3577 : nsINode* aTargetForSubtreeModified)
3578 : {
3579 3616 : nsIDocument* doc = aNode->OwnerDoc();
3580 :
3581 : // global object will be null for documents that don't have windows.
3582 3616 : nsPIDOMWindow* window = doc->GetInnerWindow();
3583 : // This relies on nsEventListenerManager::AddEventListener, which sets
3584 : // all mutation bits when there is a listener for DOMSubtreeModified event.
3585 3616 : if (window && !window->HasMutationListeners(aType)) {
3586 0 : return false;
3587 : }
3588 :
3589 7232 : if (aNode->IsNodeOfType(nsINode::eCONTENT) &&
3590 3616 : static_cast<nsIContent*>(aNode)->IsInNativeAnonymousSubtree()) {
3591 0 : return false;
3592 : }
3593 :
3594 3616 : doc->MayDispatchMutationEvent(aTargetForSubtreeModified);
3595 :
3596 : // If we have a window, we can check it for mutation listeners now.
3597 3616 : if (aNode->IsInDoc()) {
3598 3158 : nsCOMPtr<nsIDOMEventTarget> piTarget(do_QueryInterface(window));
3599 1579 : if (piTarget) {
3600 0 : nsEventListenerManager* manager = piTarget->GetListenerManager(false);
3601 0 : if (manager && manager->HasMutationListeners()) {
3602 0 : return true;
3603 : }
3604 : }
3605 : }
3606 :
3607 : // If we have a window, we know a mutation listener is registered, but it
3608 : // might not be in our chain. If we don't have a window, we might have a
3609 : // mutation listener. Check quickly to see.
3610 13414 : while (aNode) {
3611 6184 : nsEventListenerManager* manager = aNode->GetListenerManager(false);
3612 6184 : if (manager && manager->HasMutationListeners()) {
3613 2 : return true;
3614 : }
3615 :
3616 6182 : if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
3617 4605 : nsIContent* content = static_cast<nsIContent*>(aNode);
3618 : nsIContent* insertionParent =
3619 4605 : doc->BindingManager()->GetInsertionParent(content);
3620 4605 : if (insertionParent) {
3621 0 : aNode = insertionParent;
3622 0 : continue;
3623 : }
3624 : }
3625 6182 : aNode = aNode->GetNodeParent();
3626 : }
3627 :
3628 3614 : return false;
3629 : }
3630 :
3631 : /* static */
3632 : bool
3633 15 : nsContentUtils::HasMutationListeners(nsIDocument* aDocument,
3634 : PRUint32 aType)
3635 : {
3636 : nsPIDOMWindow* window = aDocument ?
3637 15 : aDocument->GetInnerWindow() : nsnull;
3638 :
3639 : // This relies on nsEventListenerManager::AddEventListener, which sets
3640 : // all mutation bits when there is a listener for DOMSubtreeModified event.
3641 15 : return !window || window->HasMutationListeners(aType);
3642 : }
3643 :
3644 : void
3645 239 : nsContentUtils::MaybeFireNodeRemoved(nsINode* aChild, nsINode* aParent,
3646 : nsIDocument* aOwnerDoc)
3647 : {
3648 239 : NS_PRECONDITION(aChild, "Missing child");
3649 239 : NS_PRECONDITION(aChild->GetNodeParent() == aParent, "Wrong parent");
3650 239 : NS_PRECONDITION(aChild->OwnerDoc() == aOwnerDoc, "Wrong owner-doc");
3651 :
3652 : // This checks that IsSafeToRunScript is true since we don't want to fire
3653 : // events when that is false. We can't rely on nsEventDispatcher to assert
3654 : // this in this situation since most of the time there are no mutation
3655 : // event listeners, in which case we won't even attempt to dispatch events.
3656 : // However this also allows for two exceptions. First off, we don't assert
3657 : // if the mutation happens to native anonymous content since we never fire
3658 : // mutation events on such content anyway.
3659 : // Second, we don't assert if sDOMNodeRemovedSuppressCount is true since
3660 : // that is a know case when we'd normally fire a mutation event, but can't
3661 : // make that safe and so we suppress it at this time. Ideally this should
3662 : // go away eventually.
3663 239 : NS_ASSERTION(aChild->IsNodeOfType(nsINode::eCONTENT) &&
3664 : static_cast<nsIContent*>(aChild)->
3665 : IsInNativeAnonymousSubtree() ||
3666 : IsSafeToRunScript() ||
3667 : sDOMNodeRemovedSuppressCount,
3668 : "Want to fire DOMNodeRemoved event, but it's not safe");
3669 :
3670 : // Having an explicit check here since it's an easy mistake to fall into,
3671 : // and there might be existing code with problems. We'd rather be safe
3672 : // than fire DOMNodeRemoved in all corner cases. We also rely on it for
3673 : // nsAutoScriptBlockerSuppressNodeRemoved.
3674 239 : if (!IsSafeToRunScript()) {
3675 0 : return;
3676 : }
3677 :
3678 239 : if (HasMutationListeners(aChild,
3679 : NS_EVENT_BITS_MUTATION_NODEREMOVED, aParent)) {
3680 0 : nsMutationEvent mutation(true, NS_MUTATION_NODEREMOVED);
3681 0 : mutation.mRelatedNode = do_QueryInterface(aParent);
3682 :
3683 0 : mozAutoSubtreeModified subtree(aOwnerDoc, aParent);
3684 0 : nsEventDispatcher::Dispatch(aChild, nsnull, &mutation);
3685 : }
3686 : }
3687 :
3688 : PLDHashOperator
3689 0 : ListenerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aEntry,
3690 : PRUint32 aNumber, void* aArg)
3691 : {
3692 : EventListenerManagerMapEntry* entry =
3693 0 : static_cast<EventListenerManagerMapEntry*>(aEntry);
3694 0 : if (entry) {
3695 0 : nsINode* n = static_cast<nsINode*>(entry->mListenerManager->GetTarget());
3696 0 : if (n && n->IsInDoc() &&
3697 0 : nsCCUncollectableMarker::InGeneration(n->OwnerDoc()->GetMarkedCCGeneration())) {
3698 0 : entry->mListenerManager->UnmarkGrayJSListeners();
3699 : }
3700 : }
3701 0 : return PL_DHASH_NEXT;
3702 : }
3703 :
3704 : void
3705 0 : nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(PRUint32 aGeneration)
3706 : {
3707 0 : if (sEventListenerManagersHash.ops) {
3708 : PL_DHashTableEnumerate(&sEventListenerManagersHash, ListenerEnumerator,
3709 0 : &aGeneration);
3710 : }
3711 0 : }
3712 :
3713 : /* static */
3714 : void
3715 3 : nsContentUtils::TraverseListenerManager(nsINode *aNode,
3716 : nsCycleCollectionTraversalCallback &cb)
3717 : {
3718 3 : if (!sEventListenerManagersHash.ops) {
3719 : // We're already shut down, just return.
3720 0 : return;
3721 : }
3722 :
3723 : EventListenerManagerMapEntry *entry =
3724 : static_cast<EventListenerManagerMapEntry *>
3725 : (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
3726 3 : PL_DHASH_LOOKUP));
3727 3 : if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
3728 3 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(entry->mListenerManager,
3729 : nsEventListenerManager,
3730 : "[via hash] mListenerManager")
3731 : }
3732 : }
3733 :
3734 : nsEventListenerManager*
3735 27262 : nsContentUtils::GetListenerManager(nsINode *aNode,
3736 : bool aCreateIfNotFound)
3737 : {
3738 27262 : if (!aCreateIfNotFound && !aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) {
3739 27254 : return nsnull;
3740 : }
3741 :
3742 8 : if (!sEventListenerManagersHash.ops) {
3743 : // We're already shut down, don't bother creating an event listener
3744 : // manager.
3745 :
3746 0 : return nsnull;
3747 : }
3748 :
3749 8 : if (!aCreateIfNotFound) {
3750 : EventListenerManagerMapEntry *entry =
3751 : static_cast<EventListenerManagerMapEntry *>
3752 : (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
3753 6 : PL_DHASH_LOOKUP));
3754 6 : if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
3755 6 : return entry->mListenerManager;
3756 : }
3757 0 : return nsnull;
3758 : }
3759 :
3760 : EventListenerManagerMapEntry *entry =
3761 : static_cast<EventListenerManagerMapEntry *>
3762 : (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
3763 2 : PL_DHASH_ADD));
3764 :
3765 2 : if (!entry) {
3766 0 : return nsnull;
3767 : }
3768 :
3769 2 : if (!entry->mListenerManager) {
3770 2 : entry->mListenerManager = new nsEventListenerManager(aNode);
3771 :
3772 2 : aNode->SetFlags(NODE_HAS_LISTENERMANAGER);
3773 : }
3774 :
3775 2 : return entry->mListenerManager;
3776 : }
3777 :
3778 : /* static */
3779 : void
3780 0 : nsContentUtils::RemoveListenerManager(nsINode *aNode)
3781 : {
3782 0 : if (sEventListenerManagersHash.ops) {
3783 : EventListenerManagerMapEntry *entry =
3784 : static_cast<EventListenerManagerMapEntry *>
3785 : (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
3786 0 : PL_DHASH_LOOKUP));
3787 0 : if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
3788 0 : nsRefPtr<nsEventListenerManager> listenerManager;
3789 0 : listenerManager.swap(entry->mListenerManager);
3790 : // Remove the entry and *then* do operations that could cause further
3791 : // modification of sEventListenerManagersHash. See bug 334177.
3792 0 : PL_DHashTableRawRemove(&sEventListenerManagersHash, entry);
3793 0 : if (listenerManager) {
3794 0 : listenerManager->Disconnect();
3795 : }
3796 : }
3797 : }
3798 0 : }
3799 :
3800 : /* static */
3801 : bool
3802 193 : nsContentUtils::IsValidNodeName(nsIAtom *aLocalName, nsIAtom *aPrefix,
3803 : PRInt32 aNamespaceID)
3804 : {
3805 193 : if (aNamespaceID == kNameSpaceID_Unknown) {
3806 0 : return false;
3807 : }
3808 :
3809 193 : if (!aPrefix) {
3810 : // If the prefix is null, then either the QName must be xmlns or the
3811 : // namespace must not be XMLNS.
3812 : return (aLocalName == nsGkAtoms::xmlns) ==
3813 178 : (aNamespaceID == kNameSpaceID_XMLNS);
3814 : }
3815 :
3816 : // If the prefix is non-null then the namespace must not be null.
3817 15 : if (aNamespaceID == kNameSpaceID_None) {
3818 0 : return false;
3819 : }
3820 :
3821 : // If the namespace is the XMLNS namespace then the prefix must be xmlns,
3822 : // but the localname must not be xmlns.
3823 15 : if (aNamespaceID == kNameSpaceID_XMLNS) {
3824 0 : return aPrefix == nsGkAtoms::xmlns && aLocalName != nsGkAtoms::xmlns;
3825 : }
3826 :
3827 : // If the namespace is not the XMLNS namespace then the prefix must not be
3828 : // xmlns.
3829 : // If the namespace is the XML namespace then the prefix can be anything.
3830 : // If the namespace is not the XML namespace then the prefix must not be xml.
3831 : return aPrefix != nsGkAtoms::xmlns &&
3832 15 : (aNamespaceID == kNameSpaceID_XML || aPrefix != nsGkAtoms::xml);
3833 : }
3834 :
3835 : /* static */
3836 : nsresult
3837 0 : nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
3838 : const nsAString& aFragment,
3839 : bool aPreventScriptExecution,
3840 : nsIDOMDocumentFragment** aReturn)
3841 : {
3842 0 : *aReturn = nsnull;
3843 0 : NS_ENSURE_ARG(aContextNode);
3844 :
3845 : // If we don't have a document here, we can't get the right security context
3846 : // for compiling event handlers... so just bail out.
3847 0 : nsCOMPtr<nsIDocument> document = aContextNode->OwnerDoc();
3848 0 : bool isHTML = document->IsHTML();
3849 : #ifdef DEBUG
3850 0 : nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(document);
3851 0 : NS_ASSERTION(!isHTML || htmlDoc, "Should have HTMLDocument here!");
3852 : #endif
3853 :
3854 0 : if (isHTML) {
3855 0 : nsCOMPtr<nsIDOMDocumentFragment> frag;
3856 0 : NS_NewDocumentFragment(getter_AddRefs(frag), document->NodeInfoManager());
3857 :
3858 0 : nsCOMPtr<nsIContent> contextAsContent = do_QueryInterface(aContextNode);
3859 0 : if (contextAsContent && !contextAsContent->IsElement()) {
3860 0 : contextAsContent = contextAsContent->GetParent();
3861 0 : if (contextAsContent && !contextAsContent->IsElement()) {
3862 : // can this even happen?
3863 0 : contextAsContent = nsnull;
3864 : }
3865 : }
3866 :
3867 : nsresult rv;
3868 0 : nsCOMPtr<nsIContent> fragment = do_QueryInterface(frag);
3869 0 : if (contextAsContent && !contextAsContent->IsHTML(nsGkAtoms::html)) {
3870 : rv = ParseFragmentHTML(aFragment,
3871 : fragment,
3872 : contextAsContent->Tag(),
3873 : contextAsContent->GetNameSpaceID(),
3874 0 : (document->GetCompatibilityMode() ==
3875 : eCompatibility_NavQuirks),
3876 0 : aPreventScriptExecution);
3877 : } else {
3878 : rv = ParseFragmentHTML(aFragment,
3879 : fragment,
3880 : nsGkAtoms::body,
3881 : kNameSpaceID_XHTML,
3882 0 : (document->GetCompatibilityMode() ==
3883 : eCompatibility_NavQuirks),
3884 0 : aPreventScriptExecution);
3885 : }
3886 :
3887 0 : frag.forget(aReturn);
3888 0 : return rv;
3889 : }
3890 :
3891 0 : nsAutoTArray<nsString, 32> tagStack;
3892 0 : nsAutoString uriStr, nameStr;
3893 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(aContextNode);
3894 : // just in case we have a text node
3895 0 : if (content && !content->IsElement())
3896 0 : content = content->GetParent();
3897 :
3898 0 : while (content && content->IsElement()) {
3899 0 : nsString& tagName = *tagStack.AppendElement();
3900 0 : NS_ENSURE_TRUE(&tagName, NS_ERROR_OUT_OF_MEMORY);
3901 :
3902 0 : tagName = content->NodeInfo()->QualifiedName();
3903 :
3904 : // see if we need to add xmlns declarations
3905 0 : PRUint32 count = content->GetAttrCount();
3906 0 : bool setDefaultNamespace = false;
3907 0 : if (count > 0) {
3908 : PRUint32 index;
3909 :
3910 0 : for (index = 0; index < count; index++) {
3911 0 : const nsAttrName* name = content->GetAttrNameAt(index);
3912 0 : if (name->NamespaceEquals(kNameSpaceID_XMLNS)) {
3913 0 : content->GetAttr(kNameSpaceID_XMLNS, name->LocalName(), uriStr);
3914 :
3915 : // really want something like nsXMLContentSerializer::SerializeAttr
3916 0 : tagName.Append(NS_LITERAL_STRING(" xmlns")); // space important
3917 0 : if (name->GetPrefix()) {
3918 0 : tagName.Append(PRUnichar(':'));
3919 0 : name->LocalName()->ToString(nameStr);
3920 0 : tagName.Append(nameStr);
3921 : } else {
3922 0 : setDefaultNamespace = true;
3923 : }
3924 0 : tagName.Append(NS_LITERAL_STRING("=\"") + uriStr +
3925 0 : NS_LITERAL_STRING("\""));
3926 : }
3927 : }
3928 : }
3929 :
3930 0 : if (!setDefaultNamespace) {
3931 0 : nsINodeInfo* info = content->NodeInfo();
3932 0 : if (!info->GetPrefixAtom() &&
3933 0 : info->NamespaceID() != kNameSpaceID_None) {
3934 : // We have no namespace prefix, but have a namespace ID. Push
3935 : // default namespace attr in, so that our kids will be in our
3936 : // namespace.
3937 0 : info->GetNamespaceURI(uriStr);
3938 0 : tagName.Append(NS_LITERAL_STRING(" xmlns=\"") + uriStr +
3939 0 : NS_LITERAL_STRING("\""));
3940 : }
3941 : }
3942 :
3943 0 : content = content->GetParent();
3944 : }
3945 :
3946 : return ParseFragmentXML(aFragment,
3947 : document,
3948 : tagStack,
3949 : aPreventScriptExecution,
3950 0 : aReturn);
3951 : }
3952 :
3953 : /* static */
3954 : void
3955 1404 : nsContentUtils::DropFragmentParsers()
3956 : {
3957 1404 : NS_IF_RELEASE(sHTMLFragmentParser);
3958 1404 : NS_IF_RELEASE(sXMLFragmentParser);
3959 1404 : NS_IF_RELEASE(sXMLFragmentSink);
3960 1404 : }
3961 :
3962 : /* static */
3963 : void
3964 1404 : nsContentUtils::XPCOMShutdown()
3965 : {
3966 1404 : nsContentUtils::DropFragmentParsers();
3967 1404 : }
3968 :
3969 : /* static */
3970 : nsresult
3971 0 : nsContentUtils::ParseFragmentHTML(const nsAString& aSourceBuffer,
3972 : nsIContent* aTargetNode,
3973 : nsIAtom* aContextLocalName,
3974 : PRInt32 aContextNamespace,
3975 : bool aQuirks,
3976 : bool aPreventScriptExecution)
3977 : {
3978 0 : if (nsContentUtils::sFragmentParsingActive) {
3979 0 : NS_NOTREACHED("Re-entrant fragment parsing attempted.");
3980 0 : return NS_ERROR_DOM_INVALID_STATE_ERR;
3981 : }
3982 0 : mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
3983 0 : nsContentUtils::sFragmentParsingActive = true;
3984 0 : if (!sHTMLFragmentParser) {
3985 0 : NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
3986 : // Now sHTMLFragmentParser owns the object
3987 : }
3988 : nsresult rv =
3989 : sHTMLFragmentParser->ParseFragment(aSourceBuffer,
3990 : aTargetNode,
3991 : aContextLocalName,
3992 : aContextNamespace,
3993 : aQuirks,
3994 0 : aPreventScriptExecution);
3995 0 : return rv;
3996 : }
3997 :
3998 : /* static */
3999 : nsresult
4000 234 : nsContentUtils::ParseDocumentHTML(const nsAString& aSourceBuffer,
4001 : nsIDocument* aTargetDocument,
4002 : bool aScriptingEnabledForNoscriptParsing)
4003 : {
4004 234 : if (nsContentUtils::sFragmentParsingActive) {
4005 0 : NS_NOTREACHED("Re-entrant fragment parsing attempted.");
4006 0 : return NS_ERROR_DOM_INVALID_STATE_ERR;
4007 : }
4008 468 : mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
4009 234 : nsContentUtils::sFragmentParsingActive = true;
4010 234 : if (!sHTMLFragmentParser) {
4011 12 : NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
4012 : // Now sHTMLFragmentParser owns the object
4013 : }
4014 : nsresult rv =
4015 : sHTMLFragmentParser->ParseDocument(aSourceBuffer,
4016 : aTargetDocument,
4017 234 : aScriptingEnabledForNoscriptParsing);
4018 234 : return rv;
4019 : }
4020 :
4021 : /* static */
4022 : nsresult
4023 1 : nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
4024 : nsIDocument* aDocument,
4025 : nsTArray<nsString>& aTagStack,
4026 : bool aPreventScriptExecution,
4027 : nsIDOMDocumentFragment** aReturn)
4028 : {
4029 1 : if (nsContentUtils::sFragmentParsingActive) {
4030 0 : NS_NOTREACHED("Re-entrant fragment parsing attempted.");
4031 0 : return NS_ERROR_DOM_INVALID_STATE_ERR;
4032 : }
4033 2 : mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
4034 1 : nsContentUtils::sFragmentParsingActive = true;
4035 1 : if (!sXMLFragmentParser) {
4036 2 : nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID);
4037 1 : parser.forget(&sXMLFragmentParser);
4038 : // sXMLFragmentParser now owns the parser
4039 : }
4040 1 : if (!sXMLFragmentSink) {
4041 1 : NS_NewXMLFragmentContentSink(&sXMLFragmentSink);
4042 : // sXMLFragmentSink now owns the sink
4043 : }
4044 2 : nsCOMPtr<nsIContentSink> contentsink = do_QueryInterface(sXMLFragmentSink);
4045 1 : NS_ABORT_IF_FALSE(contentsink, "Sink doesn't QI to nsIContentSink!");
4046 1 : sXMLFragmentParser->SetContentSink(contentsink);
4047 :
4048 1 : sXMLFragmentSink->SetTargetDocument(aDocument);
4049 1 : sXMLFragmentSink->SetPreventScriptExecution(aPreventScriptExecution);
4050 :
4051 : nsresult rv =
4052 : sXMLFragmentParser->ParseFragment(aSourceBuffer,
4053 1 : aTagStack);
4054 1 : if (NS_FAILED(rv)) {
4055 : // Drop the fragment parser and sink that might be in an inconsistent state
4056 0 : NS_IF_RELEASE(sXMLFragmentParser);
4057 0 : NS_IF_RELEASE(sXMLFragmentSink);
4058 0 : return rv;
4059 : }
4060 :
4061 1 : rv = sXMLFragmentSink->FinishFragmentParsing(aReturn);
4062 :
4063 1 : sXMLFragmentParser->Reset();
4064 :
4065 1 : return rv;
4066 : }
4067 :
4068 : /* static */
4069 : nsresult
4070 234 : nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer,
4071 : nsAString& aResultBuffer,
4072 : PRUint32 aFlags,
4073 : PRUint32 aWrapCol)
4074 : {
4075 468 : nsCOMPtr<nsIURI> uri;
4076 234 : NS_NewURI(getter_AddRefs(uri), "about:blank");
4077 : nsCOMPtr<nsIPrincipal> principal =
4078 468 : do_CreateInstance("@mozilla.org/nullprincipal;1");
4079 468 : nsCOMPtr<nsIDOMDocument> domDocument;
4080 234 : nsresult rv = nsContentUtils::CreateDocument(EmptyString(),
4081 234 : EmptyString(),
4082 : nsnull,
4083 : uri,
4084 : uri,
4085 : principal,
4086 : nsnull,
4087 : DocumentFlavorHTML,
4088 702 : getter_AddRefs(domDocument));
4089 234 : NS_ENSURE_SUCCESS(rv, rv);
4090 :
4091 468 : nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
4092 : rv = nsContentUtils::ParseDocumentHTML(aSourceBuffer, document,
4093 234 : !(aFlags & nsIDocumentEncoder::OutputNoScriptContent));
4094 234 : NS_ENSURE_SUCCESS(rv, rv);
4095 :
4096 : nsCOMPtr<nsIDocumentEncoder> encoder = do_CreateInstance(
4097 468 : "@mozilla.org/layout/documentEncoder;1?type=text/plain");
4098 :
4099 234 : rv = encoder->Init(domDocument, NS_LITERAL_STRING("text/plain"), aFlags);
4100 234 : NS_ENSURE_SUCCESS(rv, rv);
4101 :
4102 234 : encoder->SetWrapColumn(aWrapCol);
4103 :
4104 234 : return encoder->EncodeToString(aResultBuffer);
4105 : }
4106 :
4107 : /* static */
4108 : nsresult
4109 1273 : nsContentUtils::CreateDocument(const nsAString& aNamespaceURI,
4110 : const nsAString& aQualifiedName,
4111 : nsIDOMDocumentType* aDoctype,
4112 : nsIURI* aDocumentURI, nsIURI* aBaseURI,
4113 : nsIPrincipal* aPrincipal,
4114 : nsIScriptGlobalObject* aEventObject,
4115 : DocumentFlavor aFlavor,
4116 : nsIDOMDocument** aResult)
4117 : {
4118 : nsresult rv = NS_NewDOMDocument(aResult, aNamespaceURI, aQualifiedName,
4119 : aDoctype, aDocumentURI, aBaseURI, aPrincipal,
4120 1273 : true, aEventObject, aFlavor);
4121 1273 : NS_ENSURE_SUCCESS(rv, rv);
4122 :
4123 2546 : nsCOMPtr<nsIDocument> document = do_QueryInterface(*aResult);
4124 :
4125 : // created documents are immediately "complete" (ready to use)
4126 1273 : document->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
4127 1273 : return NS_OK;
4128 : }
4129 :
4130 : /* static */
4131 : nsresult
4132 1 : nsContentUtils::SetNodeTextContent(nsIContent* aContent,
4133 : const nsAString& aValue,
4134 : bool aTryReuse)
4135 : {
4136 : // Fire DOMNodeRemoved mutation events before we do anything else.
4137 2 : nsCOMPtr<nsIContent> owningContent;
4138 :
4139 : // Batch possible DOMSubtreeModified events.
4140 2 : mozAutoSubtreeModified subtree(nsnull, nsnull);
4141 :
4142 : // Scope firing mutation events so that we don't carry any state that
4143 : // might be stale
4144 : {
4145 : // We're relying on mozAutoSubtreeModified to keep a strong reference if
4146 : // needed.
4147 1 : nsIDocument* doc = aContent->OwnerDoc();
4148 :
4149 : // Optimize the common case of there being no observers
4150 1 : if (HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED)) {
4151 1 : subtree.UpdateTarget(doc, nsnull);
4152 1 : owningContent = aContent;
4153 2 : nsCOMPtr<nsINode> child;
4154 1 : bool skipFirst = aTryReuse;
4155 2 : for (child = aContent->GetFirstChild();
4156 1 : child && child->GetNodeParent() == aContent;
4157 0 : child = child->GetNextSibling()) {
4158 0 : if (skipFirst && child->IsNodeOfType(nsINode::eTEXT)) {
4159 0 : skipFirst = false;
4160 0 : continue;
4161 : }
4162 0 : nsContentUtils::MaybeFireNodeRemoved(child, aContent, doc);
4163 : }
4164 : }
4165 : }
4166 :
4167 : // Might as well stick a batch around this since we're performing several
4168 : // mutations.
4169 : mozAutoDocUpdate updateBatch(aContent->GetCurrentDoc(),
4170 2 : UPDATE_CONTENT_MODEL, true);
4171 :
4172 1 : PRUint32 childCount = aContent->GetChildCount();
4173 :
4174 1 : if (aTryReuse && !aValue.IsEmpty()) {
4175 0 : PRUint32 removeIndex = 0;
4176 :
4177 0 : for (PRUint32 i = 0; i < childCount; ++i) {
4178 0 : nsIContent* child = aContent->GetChildAt(removeIndex);
4179 0 : if (removeIndex == 0 && child && child->IsNodeOfType(nsINode::eTEXT)) {
4180 0 : nsresult rv = child->SetText(aValue, true);
4181 0 : NS_ENSURE_SUCCESS(rv, rv);
4182 :
4183 0 : removeIndex = 1;
4184 : }
4185 : else {
4186 0 : aContent->RemoveChildAt(removeIndex, true);
4187 : }
4188 : }
4189 :
4190 0 : if (removeIndex == 1) {
4191 0 : return NS_OK;
4192 : }
4193 : }
4194 : else {
4195 1 : for (PRUint32 i = 0; i < childCount; ++i) {
4196 0 : aContent->RemoveChildAt(0, true);
4197 : }
4198 : }
4199 :
4200 1 : if (aValue.IsEmpty()) {
4201 0 : return NS_OK;
4202 : }
4203 :
4204 2 : nsCOMPtr<nsIContent> textContent;
4205 1 : nsresult rv = NS_NewTextNode(getter_AddRefs(textContent),
4206 1 : aContent->NodeInfo()->NodeInfoManager());
4207 1 : NS_ENSURE_SUCCESS(rv, rv);
4208 :
4209 1 : textContent->SetText(aValue, true);
4210 :
4211 1 : return aContent->AppendChildTo(textContent, true);
4212 : }
4213 :
4214 3875 : static void AppendNodeTextContentsRecurse(nsINode* aNode, nsAString& aResult)
4215 : {
4216 7737 : for (nsIContent* child = aNode->GetFirstChild();
4217 : child;
4218 3862 : child = child->GetNextSibling()) {
4219 3862 : if (child->IsElement()) {
4220 0 : AppendNodeTextContentsRecurse(child, aResult);
4221 : }
4222 3862 : else if (child->IsNodeOfType(nsINode::eTEXT)) {
4223 3862 : child->AppendTextTo(aResult);
4224 : }
4225 : }
4226 3875 : }
4227 :
4228 : /* static */
4229 : void
4230 3875 : nsContentUtils::AppendNodeTextContent(nsINode* aNode, bool aDeep,
4231 : nsAString& aResult)
4232 : {
4233 3875 : if (aNode->IsNodeOfType(nsINode::eTEXT)) {
4234 0 : static_cast<nsIContent*>(aNode)->AppendTextTo(aResult);
4235 : }
4236 3875 : else if (aDeep) {
4237 3875 : AppendNodeTextContentsRecurse(aNode, aResult);
4238 : }
4239 : else {
4240 0 : for (nsIContent* child = aNode->GetFirstChild();
4241 : child;
4242 0 : child = child->GetNextSibling()) {
4243 0 : if (child->IsNodeOfType(nsINode::eTEXT)) {
4244 0 : child->AppendTextTo(aResult);
4245 : }
4246 : }
4247 : }
4248 3875 : }
4249 :
4250 : bool
4251 0 : nsContentUtils::HasNonEmptyTextContent(nsINode* aNode)
4252 : {
4253 0 : for (nsIContent* child = aNode->GetFirstChild();
4254 : child;
4255 0 : child = child->GetNextSibling()) {
4256 0 : if (child->IsNodeOfType(nsINode::eTEXT) &&
4257 0 : child->TextLength() > 0) {
4258 0 : return true;
4259 : }
4260 : }
4261 :
4262 0 : return false;
4263 : }
4264 :
4265 : /* static */
4266 : bool
4267 52 : nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode,
4268 : const nsIContent* aContent)
4269 : {
4270 52 : NS_PRECONDITION(aNode,
4271 : "Must have a node to work with");
4272 52 : NS_PRECONDITION(aContent,
4273 : "Must have a content to work with");
4274 :
4275 52 : if (!aNode->IsNodeOfType(nsINode::eCONTENT)) {
4276 : /**
4277 : * The root isn't an nsIContent, so it's a document or attribute. The only
4278 : * nodes in the same anonymous subtree as it will have a null
4279 : * bindingParent.
4280 : *
4281 : * XXXbz strictly speaking, that's not true for attribute nodes.
4282 : */
4283 48 : return aContent->GetBindingParent() == nsnull;
4284 : }
4285 :
4286 4 : return static_cast<const nsIContent*>(aNode)->GetBindingParent() ==
4287 4 : aContent->GetBindingParent();
4288 :
4289 : }
4290 :
4291 0 : class AnonymousContentDestroyer : public nsRunnable {
4292 : public:
4293 0 : AnonymousContentDestroyer(nsCOMPtr<nsIContent>* aContent) {
4294 0 : mContent.swap(*aContent);
4295 0 : mParent = mContent->GetParent();
4296 0 : mDoc = mContent->OwnerDoc();
4297 0 : }
4298 0 : NS_IMETHOD Run() {
4299 0 : mContent->UnbindFromTree();
4300 0 : return NS_OK;
4301 : }
4302 : private:
4303 : nsCOMPtr<nsIContent> mContent;
4304 : // Hold strong refs to the parent content and document so that they
4305 : // don't die unexpectedly
4306 : nsCOMPtr<nsIDocument> mDoc;
4307 : nsCOMPtr<nsIContent> mParent;
4308 : };
4309 :
4310 : /* static */
4311 : void
4312 0 : nsContentUtils::DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent)
4313 : {
4314 0 : if (*aContent) {
4315 0 : AddScriptRunner(new AnonymousContentDestroyer(aContent));
4316 : }
4317 0 : }
4318 :
4319 : /* static */
4320 : nsIDOMScriptObjectFactory*
4321 0 : nsContentUtils::GetDOMScriptObjectFactory()
4322 : {
4323 0 : if (!sDOMScriptObjectFactory) {
4324 : static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
4325 : NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
4326 :
4327 0 : CallGetService(kDOMScriptObjectFactoryCID, &sDOMScriptObjectFactory);
4328 : }
4329 :
4330 0 : return sDOMScriptObjectFactory;
4331 : }
4332 :
4333 : /* static */
4334 : nsresult
4335 0 : nsContentUtils::HoldScriptObject(PRUint32 aLangID, void *aObject)
4336 : {
4337 0 : NS_ASSERTION(aObject, "unexpected null object");
4338 0 : NS_ASSERTION(aLangID != nsIProgrammingLanguage::JAVASCRIPT,
4339 : "Should use HoldJSObjects.");
4340 : nsresult rv;
4341 :
4342 0 : PRUint32 langIndex = NS_STID_INDEX(aLangID);
4343 0 : nsIScriptRuntime *runtime = sScriptRuntimes[langIndex];
4344 0 : if (!runtime) {
4345 0 : nsIDOMScriptObjectFactory *factory = GetDOMScriptObjectFactory();
4346 0 : NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
4347 :
4348 0 : rv = factory->GetScriptRuntimeByID(aLangID, &runtime);
4349 0 : NS_ENSURE_SUCCESS(rv, rv);
4350 :
4351 : // This makes sScriptRuntimes hold a strong ref.
4352 0 : sScriptRuntimes[langIndex] = runtime;
4353 : }
4354 :
4355 0 : rv = runtime->HoldScriptObject(aObject);
4356 0 : NS_ENSURE_SUCCESS(rv, rv);
4357 :
4358 0 : ++sScriptRootCount[langIndex];
4359 0 : NS_LOG_ADDREF(sScriptRuntimes[langIndex], sScriptRootCount[langIndex],
4360 0 : "HoldScriptObject", sizeof(void*));
4361 :
4362 0 : return NS_OK;
4363 : }
4364 :
4365 : /* static */
4366 : void
4367 0 : nsContentUtils::DropScriptObject(PRUint32 aLangID, void *aObject,
4368 : void *aClosure)
4369 : {
4370 0 : NS_ASSERTION(aObject, "unexpected null object");
4371 0 : NS_ASSERTION(aLangID != nsIProgrammingLanguage::JAVASCRIPT,
4372 : "Should use DropJSObjects.");
4373 0 : PRUint32 langIndex = NS_STID_INDEX(aLangID);
4374 0 : NS_LOG_RELEASE(sScriptRuntimes[langIndex], sScriptRootCount[langIndex] - 1,
4375 0 : "HoldScriptObject");
4376 0 : sScriptRuntimes[langIndex]->DropScriptObject(aObject);
4377 0 : if (--sScriptRootCount[langIndex] == 0) {
4378 0 : NS_RELEASE(sScriptRuntimes[langIndex]);
4379 : }
4380 0 : }
4381 :
4382 : /* static */
4383 : nsresult
4384 7458 : nsContentUtils::HoldJSObjects(void* aScriptObjectHolder,
4385 : nsScriptObjectTracer* aTracer)
4386 : {
4387 7458 : NS_ENSURE_TRUE(sXPConnect, NS_ERROR_UNEXPECTED);
4388 :
4389 7458 : nsresult rv = sXPConnect->AddJSHolder(aScriptObjectHolder, aTracer);
4390 7458 : NS_ENSURE_SUCCESS(rv, rv);
4391 :
4392 7458 : if (sJSGCThingRootCount++ == 0) {
4393 52 : nsLayoutStatics::AddRef();
4394 : }
4395 7458 : NS_LOG_ADDREF(sXPConnect, sJSGCThingRootCount, "HoldJSObjects",
4396 14916 : sizeof(void*));
4397 :
4398 7458 : return NS_OK;
4399 : }
4400 :
4401 : /* static */
4402 : nsresult
4403 7456 : nsContentUtils::DropJSObjects(void* aScriptObjectHolder)
4404 : {
4405 7456 : NS_LOG_RELEASE(sXPConnect, sJSGCThingRootCount - 1, "HoldJSObjects");
4406 7456 : nsresult rv = sXPConnect->RemoveJSHolder(aScriptObjectHolder);
4407 7456 : if (--sJSGCThingRootCount == 0) {
4408 51 : nsLayoutStatics::Release();
4409 : }
4410 7456 : return rv;
4411 : }
4412 :
4413 : /* static */
4414 : void
4415 0 : nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling)
4416 : {
4417 0 : nsIMEStateManager::OnInstalledMenuKeyboardListener(aInstalling);
4418 0 : }
4419 :
4420 0 : static bool SchemeIs(nsIURI* aURI, const char* aScheme)
4421 : {
4422 0 : nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
4423 0 : NS_ENSURE_TRUE(baseURI, false);
4424 :
4425 0 : bool isScheme = false;
4426 0 : return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme;
4427 : }
4428 :
4429 : /* static */
4430 : nsresult
4431 0 : nsContentUtils::CheckSecurityBeforeLoad(nsIURI* aURIToLoad,
4432 : nsIPrincipal* aLoadingPrincipal,
4433 : PRUint32 aCheckLoadFlags,
4434 : bool aAllowData,
4435 : PRUint32 aContentPolicyType,
4436 : nsISupports* aContext,
4437 : const nsACString& aMimeGuess,
4438 : nsISupports* aExtra)
4439 : {
4440 0 : NS_PRECONDITION(aLoadingPrincipal, "Must have a loading principal here");
4441 :
4442 0 : bool isSystemPrin = false;
4443 0 : if (NS_SUCCEEDED(sSecurityManager->IsSystemPrincipal(aLoadingPrincipal,
4444 : &isSystemPrin)) &&
4445 : isSystemPrin) {
4446 0 : return NS_OK;
4447 : }
4448 :
4449 : // XXXbz do we want to fast-path skin stylesheets loading XBL here somehow?
4450 : // CheckLoadURIWithPrincipal
4451 : nsresult rv = sSecurityManager->
4452 0 : CheckLoadURIWithPrincipal(aLoadingPrincipal, aURIToLoad, aCheckLoadFlags);
4453 0 : NS_ENSURE_SUCCESS(rv, rv);
4454 :
4455 : // Content Policy
4456 0 : PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
4457 : rv = NS_CheckContentLoadPolicy(aContentPolicyType,
4458 : aURIToLoad,
4459 : aLoadingPrincipal,
4460 : aContext,
4461 : aMimeGuess,
4462 : aExtra,
4463 : &shouldLoad,
4464 : GetContentPolicy(),
4465 0 : sSecurityManager);
4466 0 : NS_ENSURE_SUCCESS(rv, rv);
4467 0 : if (NS_CP_REJECTED(shouldLoad)) {
4468 0 : return NS_ERROR_CONTENT_BLOCKED;
4469 : }
4470 :
4471 : // Same Origin
4472 0 : if ((aAllowData && SchemeIs(aURIToLoad, "data")) ||
4473 : ((aCheckLoadFlags & nsIScriptSecurityManager::ALLOW_CHROME) &&
4474 0 : SchemeIs(aURIToLoad, "chrome"))) {
4475 0 : return NS_OK;
4476 : }
4477 :
4478 0 : return aLoadingPrincipal->CheckMayLoad(aURIToLoad, true);
4479 : }
4480 :
4481 : bool
4482 4085 : nsContentUtils::IsSystemPrincipal(nsIPrincipal* aPrincipal)
4483 : {
4484 : bool isSystem;
4485 4085 : nsresult rv = sSecurityManager->IsSystemPrincipal(aPrincipal, &isSystem);
4486 4085 : return NS_SUCCEEDED(rv) && isSystem;
4487 : }
4488 :
4489 : /* static */
4490 : void
4491 0 : nsContentUtils::TriggerLink(nsIContent *aContent, nsPresContext *aPresContext,
4492 : nsIURI *aLinkURI, const nsString &aTargetSpec,
4493 : bool aClick, bool aIsUserTriggered,
4494 : bool aIsTrusted)
4495 : {
4496 0 : NS_ASSERTION(aPresContext, "Need a nsPresContext");
4497 0 : NS_PRECONDITION(aLinkURI, "No link URI");
4498 :
4499 0 : if (aContent->IsEditable()) {
4500 0 : return;
4501 : }
4502 :
4503 0 : nsILinkHandler *handler = aPresContext->GetLinkHandler();
4504 0 : if (!handler) {
4505 0 : return;
4506 : }
4507 :
4508 0 : if (!aClick) {
4509 0 : handler->OnOverLink(aContent, aLinkURI, aTargetSpec.get());
4510 :
4511 0 : return;
4512 : }
4513 :
4514 : // Check that this page is allowed to load this URI.
4515 0 : nsresult proceed = NS_OK;
4516 :
4517 0 : if (sSecurityManager) {
4518 : PRUint32 flag =
4519 : aIsUserTriggered ?
4520 : (PRUint32)nsIScriptSecurityManager::STANDARD :
4521 0 : (PRUint32)nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT;
4522 : proceed =
4523 : sSecurityManager->CheckLoadURIWithPrincipal(aContent->NodePrincipal(),
4524 0 : aLinkURI, flag);
4525 : }
4526 :
4527 : // Only pass off the click event if the script security manager says it's ok.
4528 0 : if (NS_SUCCEEDED(proceed)) {
4529 : handler->OnLinkClick(aContent, aLinkURI, aTargetSpec.get(), nsnull, nsnull,
4530 0 : aIsTrusted);
4531 : }
4532 : }
4533 :
4534 : /* static */
4535 : nsIWidget*
4536 0 : nsContentUtils::GetTopLevelWidget(nsIWidget* aWidget)
4537 : {
4538 0 : if (!aWidget)
4539 0 : return nsnull;
4540 :
4541 0 : return aWidget->GetTopLevelWidget();
4542 : }
4543 :
4544 : /* static */
4545 : const nsDependentString
4546 0 : nsContentUtils::GetLocalizedEllipsis()
4547 : {
4548 : static PRUnichar sBuf[4] = { 0, 0, 0, 0 };
4549 0 : if (!sBuf[0]) {
4550 0 : nsAdoptingString tmp = Preferences::GetLocalizedString("intl.ellipsis");
4551 0 : PRUint32 len = NS_MIN(PRUint32(tmp.Length()),
4552 0 : PRUint32(ArrayLength(sBuf) - 1));
4553 0 : CopyUnicodeTo(tmp, 0, sBuf, len);
4554 0 : if (!sBuf[0])
4555 0 : sBuf[0] = PRUnichar(0x2026);
4556 : }
4557 0 : return nsDependentString(sBuf);
4558 : }
4559 :
4560 : //static
4561 : nsEvent*
4562 0 : nsContentUtils::GetNativeEvent(nsIDOMEvent* aDOMEvent)
4563 : {
4564 0 : nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aDOMEvent));
4565 0 : if (!privateEvent)
4566 0 : return nsnull;
4567 0 : return privateEvent->GetInternalNSEvent();
4568 : }
4569 :
4570 : //static
4571 : bool
4572 0 : nsContentUtils::DOMEventToNativeKeyEvent(nsIDOMKeyEvent* aKeyEvent,
4573 : nsNativeKeyEvent* aNativeEvent,
4574 : bool aGetCharCode)
4575 : {
4576 0 : nsCOMPtr<nsIDOMNSEvent> nsevent = do_QueryInterface(aKeyEvent);
4577 : bool defaultPrevented;
4578 0 : nsevent->GetPreventDefault(&defaultPrevented);
4579 0 : if (defaultPrevented)
4580 0 : return false;
4581 :
4582 0 : bool trusted = false;
4583 0 : nsevent->GetIsTrusted(&trusted);
4584 0 : if (!trusted)
4585 0 : return false;
4586 :
4587 0 : if (aGetCharCode) {
4588 0 : aKeyEvent->GetCharCode(&aNativeEvent->charCode);
4589 : } else {
4590 0 : aNativeEvent->charCode = 0;
4591 : }
4592 0 : aKeyEvent->GetKeyCode(&aNativeEvent->keyCode);
4593 0 : aKeyEvent->GetAltKey(&aNativeEvent->altKey);
4594 0 : aKeyEvent->GetCtrlKey(&aNativeEvent->ctrlKey);
4595 0 : aKeyEvent->GetShiftKey(&aNativeEvent->shiftKey);
4596 0 : aKeyEvent->GetMetaKey(&aNativeEvent->metaKey);
4597 :
4598 0 : aNativeEvent->nativeEvent = GetNativeEvent(aKeyEvent);
4599 :
4600 0 : return true;
4601 : }
4602 :
4603 : static bool
4604 0 : HasASCIIDigit(const nsTArray<nsShortcutCandidate>& aCandidates)
4605 : {
4606 0 : for (PRUint32 i = 0; i < aCandidates.Length(); ++i) {
4607 0 : PRUint32 ch = aCandidates[i].mCharCode;
4608 0 : if (ch >= '0' && ch <= '9')
4609 0 : return true;
4610 : }
4611 0 : return false;
4612 : }
4613 :
4614 : static bool
4615 0 : CharsCaseInsensitiveEqual(PRUint32 aChar1, PRUint32 aChar2)
4616 : {
4617 : return aChar1 == aChar2 ||
4618 : (IS_IN_BMP(aChar1) && IS_IN_BMP(aChar2) &&
4619 0 : ToLowerCase(PRUnichar(aChar1)) == ToLowerCase(PRUnichar(aChar2)));
4620 : }
4621 :
4622 : static bool
4623 0 : IsCaseChangeableChar(PRUint32 aChar)
4624 : {
4625 : return IS_IN_BMP(aChar) &&
4626 0 : ToLowerCase(PRUnichar(aChar)) != ToUpperCase(PRUnichar(aChar));
4627 : }
4628 :
4629 : /* static */
4630 : void
4631 0 : nsContentUtils::GetAccelKeyCandidates(nsIDOMKeyEvent* aDOMKeyEvent,
4632 : nsTArray<nsShortcutCandidate>& aCandidates)
4633 : {
4634 0 : NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
4635 :
4636 0 : nsAutoString eventType;
4637 0 : aDOMKeyEvent->GetType(eventType);
4638 : // Don't process if aDOMKeyEvent is not a keypress event.
4639 0 : if (!eventType.EqualsLiteral("keypress"))
4640 : return;
4641 :
4642 : nsKeyEvent* nativeKeyEvent =
4643 0 : static_cast<nsKeyEvent*>(GetNativeEvent(aDOMKeyEvent));
4644 0 : if (nativeKeyEvent) {
4645 0 : NS_ASSERTION(nativeKeyEvent->eventStructType == NS_KEY_EVENT,
4646 : "wrong type of native event");
4647 : // nsShortcutCandidate::mCharCode is a candidate charCode.
4648 : // nsShoftcutCandidate::mIgnoreShift means the mCharCode should be tried to
4649 : // execute a command with/without shift key state. If this is TRUE, the
4650 : // shifted key state should be ignored. Otherwise, don't ignore the state.
4651 : // the priority of the charCodes are (shift key is not pressed):
4652 : // 0: charCode/false,
4653 : // 1: unshiftedCharCodes[0]/false, 2: unshiftedCharCodes[1]/false...
4654 : // the priority of the charCodes are (shift key is pressed):
4655 : // 0: charCode/false,
4656 : // 1: shiftedCharCodes[0]/false, 2: shiftedCharCodes[0]/true,
4657 : // 3: shiftedCharCodes[1]/false, 4: shiftedCharCodes[1]/true...
4658 0 : if (nativeKeyEvent->charCode) {
4659 0 : nsShortcutCandidate key(nativeKeyEvent->charCode, false);
4660 0 : aCandidates.AppendElement(key);
4661 : }
4662 :
4663 0 : PRUint32 len = nativeKeyEvent->alternativeCharCodes.Length();
4664 0 : if (!nativeKeyEvent->isShift) {
4665 0 : for (PRUint32 i = 0; i < len; ++i) {
4666 : PRUint32 ch =
4667 0 : nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode;
4668 0 : if (!ch || ch == nativeKeyEvent->charCode)
4669 0 : continue;
4670 :
4671 0 : nsShortcutCandidate key(ch, false);
4672 0 : aCandidates.AppendElement(key);
4673 : }
4674 : // If unshiftedCharCodes doesn't have numeric but shiftedCharCode has it,
4675 : // this keyboard layout is AZERTY or similar layout, probably.
4676 : // In this case, Accel+[0-9] should be accessible without shift key.
4677 : // However, the priority should be lowest.
4678 0 : if (!HasASCIIDigit(aCandidates)) {
4679 0 : for (PRUint32 i = 0; i < len; ++i) {
4680 : PRUint32 ch =
4681 0 : nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode;
4682 0 : if (ch >= '0' && ch <= '9') {
4683 0 : nsShortcutCandidate key(ch, false);
4684 0 : aCandidates.AppendElement(key);
4685 0 : break;
4686 : }
4687 : }
4688 : }
4689 : } else {
4690 0 : for (PRUint32 i = 0; i < len; ++i) {
4691 0 : PRUint32 ch = nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode;
4692 0 : if (!ch)
4693 0 : continue;
4694 :
4695 0 : if (ch != nativeKeyEvent->charCode) {
4696 0 : nsShortcutCandidate key(ch, false);
4697 0 : aCandidates.AppendElement(key);
4698 : }
4699 :
4700 : // If the char is an alphabet, the shift key state should not be
4701 : // ignored. E.g., Ctrl+Shift+C should not execute Ctrl+C.
4702 :
4703 : // And checking the charCode is same as unshiftedCharCode too.
4704 : // E.g., for Ctrl+Shift+(Plus of Numpad) should not run Ctrl+Plus.
4705 : PRUint32 unshiftCh =
4706 0 : nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode;
4707 0 : if (CharsCaseInsensitiveEqual(ch, unshiftCh))
4708 0 : continue;
4709 :
4710 : // On the Hebrew keyboard layout on Windows, the unshifted char is a
4711 : // localized character but the shifted char is a Latin alphabet,
4712 : // then, we should not execute without the shift state. See bug 433192.
4713 0 : if (IsCaseChangeableChar(ch))
4714 0 : continue;
4715 :
4716 : // Setting the alternative charCode candidates for retry without shift
4717 : // key state only when the shift key is pressed.
4718 0 : nsShortcutCandidate key(ch, true);
4719 0 : aCandidates.AppendElement(key);
4720 : }
4721 : }
4722 : } else {
4723 : PRUint32 charCode;
4724 0 : aDOMKeyEvent->GetCharCode(&charCode);
4725 0 : if (charCode) {
4726 0 : nsShortcutCandidate key(charCode, false);
4727 0 : aCandidates.AppendElement(key);
4728 : }
4729 : }
4730 : }
4731 :
4732 : /* static */
4733 : void
4734 0 : nsContentUtils::GetAccessKeyCandidates(nsKeyEvent* aNativeKeyEvent,
4735 : nsTArray<PRUint32>& aCandidates)
4736 : {
4737 0 : NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
4738 :
4739 : // return the lower cased charCode candidates for access keys.
4740 : // the priority of the charCodes are:
4741 : // 0: charCode, 1: unshiftedCharCodes[0], 2: shiftedCharCodes[0]
4742 : // 3: unshiftedCharCodes[1], 4: shiftedCharCodes[1],...
4743 0 : if (aNativeKeyEvent->charCode) {
4744 0 : PRUint32 ch = aNativeKeyEvent->charCode;
4745 0 : if (IS_IN_BMP(ch))
4746 0 : ch = ToLowerCase(PRUnichar(ch));
4747 0 : aCandidates.AppendElement(ch);
4748 : }
4749 0 : for (PRUint32 i = 0;
4750 0 : i < aNativeKeyEvent->alternativeCharCodes.Length(); ++i) {
4751 : PRUint32 ch[2] =
4752 0 : { aNativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode,
4753 0 : aNativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode };
4754 0 : for (PRUint32 j = 0; j < 2; ++j) {
4755 0 : if (!ch[j])
4756 0 : continue;
4757 0 : if (IS_IN_BMP(ch[j]))
4758 0 : ch[j] = ToLowerCase(PRUnichar(ch[j]));
4759 : // Don't append the charCode that was already appended.
4760 0 : if (aCandidates.IndexOf(ch[j]) == aCandidates.NoIndex)
4761 0 : aCandidates.AppendElement(ch[j]);
4762 : }
4763 : }
4764 : return;
4765 : }
4766 :
4767 : /* static */
4768 : void
4769 285283 : nsContentUtils::AddScriptBlocker()
4770 : {
4771 285283 : if (!sScriptBlockerCount) {
4772 259228 : NS_ASSERTION(sRunnersCountAtFirstBlocker == 0,
4773 : "Should not already have a count");
4774 259228 : sRunnersCountAtFirstBlocker = sBlockedScriptRunners->Length();
4775 : }
4776 285283 : ++sScriptBlockerCount;
4777 285283 : }
4778 :
4779 : /* static */
4780 : void
4781 285283 : nsContentUtils::RemoveScriptBlocker()
4782 : {
4783 285283 : NS_ASSERTION(sScriptBlockerCount != 0, "Negative script blockers");
4784 285283 : --sScriptBlockerCount;
4785 285283 : if (sScriptBlockerCount) {
4786 26055 : return;
4787 : }
4788 :
4789 259228 : PRUint32 firstBlocker = sRunnersCountAtFirstBlocker;
4790 259228 : PRUint32 lastBlocker = sBlockedScriptRunners->Length();
4791 259228 : PRUint32 originalFirstBlocker = firstBlocker;
4792 259228 : PRUint32 blockersCount = lastBlocker - firstBlocker;
4793 259228 : sRunnersCountAtFirstBlocker = 0;
4794 259228 : NS_ASSERTION(firstBlocker <= lastBlocker,
4795 : "bad sRunnersCountAtFirstBlocker");
4796 :
4797 518824 : while (firstBlocker < lastBlocker) {
4798 736 : nsCOMPtr<nsIRunnable> runnable = (*sBlockedScriptRunners)[firstBlocker];
4799 368 : ++firstBlocker;
4800 :
4801 368 : runnable->Run();
4802 368 : NS_ASSERTION(sRunnersCountAtFirstBlocker == 0,
4803 : "Bad count");
4804 368 : NS_ASSERTION(!sScriptBlockerCount, "This is really bad");
4805 : }
4806 259228 : sBlockedScriptRunners->RemoveElementsAt(originalFirstBlocker, blockersCount);
4807 : }
4808 :
4809 : /* static */
4810 : bool
4811 4733 : nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable)
4812 : {
4813 4733 : if (!aRunnable) {
4814 0 : return false;
4815 : }
4816 :
4817 4733 : if (sScriptBlockerCount) {
4818 368 : return sBlockedScriptRunners->AppendElement(aRunnable) != nsnull;
4819 : }
4820 :
4821 8730 : nsCOMPtr<nsIRunnable> run = aRunnable;
4822 4365 : run->Run();
4823 :
4824 4365 : return true;
4825 : }
4826 :
4827 : /*
4828 : * Helper function for nsContentUtils::ProcessViewportInfo.
4829 : *
4830 : * Handles a single key=value pair. If it corresponds to a valid viewport
4831 : * attribute, add it to the document header data. No validation is done on the
4832 : * value itself (this is done at display time).
4833 : */
4834 0 : static void ProcessViewportToken(nsIDocument *aDocument,
4835 : const nsAString &token) {
4836 :
4837 : /* Iterators. */
4838 0 : nsAString::const_iterator tip, tail, end;
4839 0 : token.BeginReading(tip);
4840 0 : tail = tip;
4841 0 : token.EndReading(end);
4842 :
4843 : /* Move tip to the '='. */
4844 0 : while ((tip != end) && (*tip != '='))
4845 0 : ++tip;
4846 :
4847 : /* If we didn't find an '=', punt. */
4848 0 : if (tip == end)
4849 0 : return;
4850 :
4851 : /* Extract the key and value. */
4852 : const nsAString &key =
4853 0 : nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(Substring(tail, tip),
4854 0 : true);
4855 : const nsAString &value =
4856 0 : nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(Substring(++tip, end),
4857 0 : true);
4858 :
4859 : /* Check for known keys. If we find a match, insert the appropriate
4860 : * information into the document header. */
4861 0 : nsCOMPtr<nsIAtom> key_atom = do_GetAtom(key);
4862 0 : if (key_atom == nsGkAtoms::height)
4863 0 : aDocument->SetHeaderData(nsGkAtoms::viewport_height, value);
4864 0 : else if (key_atom == nsGkAtoms::width)
4865 0 : aDocument->SetHeaderData(nsGkAtoms::viewport_width, value);
4866 0 : else if (key_atom == nsGkAtoms::initial_scale)
4867 0 : aDocument->SetHeaderData(nsGkAtoms::viewport_initial_scale, value);
4868 0 : else if (key_atom == nsGkAtoms::minimum_scale)
4869 0 : aDocument->SetHeaderData(nsGkAtoms::viewport_minimum_scale, value);
4870 0 : else if (key_atom == nsGkAtoms::maximum_scale)
4871 0 : aDocument->SetHeaderData(nsGkAtoms::viewport_maximum_scale, value);
4872 0 : else if (key_atom == nsGkAtoms::user_scalable)
4873 0 : aDocument->SetHeaderData(nsGkAtoms::viewport_user_scalable, value);
4874 : }
4875 :
4876 : #define IS_SEPARATOR(c) ((c == '=') || (c == ',') || (c == ';') || \
4877 : (c == '\t') || (c == '\n') || (c == '\r'))
4878 :
4879 : /* static */
4880 : ViewportInfo
4881 0 : nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
4882 : {
4883 : ViewportInfo ret;
4884 0 : ret.defaultZoom = 1.0;
4885 0 : ret.autoSize = true;
4886 0 : ret.allowZoom = true;
4887 0 : ret.autoScale = true;
4888 :
4889 : // If the docType specifies that we are on a site optimized for mobile,
4890 : // then we want to return specially crafted defaults for the viewport info.
4891 : nsCOMPtr<nsIDOMDocument>
4892 0 : domDoc(do_QueryInterface(aDocument));
4893 :
4894 0 : nsCOMPtr<nsIDOMDocumentType> docType;
4895 0 : nsresult rv = domDoc->GetDoctype(getter_AddRefs(docType));
4896 0 : if (NS_SUCCEEDED(rv) && docType) {
4897 0 : nsAutoString docId;
4898 0 : rv = docType->GetPublicId(docId);
4899 0 : if (NS_SUCCEEDED(rv)) {
4900 0 : if ((docId.Find("WAP") != -1) ||
4901 0 : (docId.Find("Mobile") != -1) ||
4902 0 : (docId.Find("WML") != -1))
4903 : {
4904 : return ret;
4905 : }
4906 : }
4907 : }
4908 :
4909 0 : if (aDocument->IsXUL()) {
4910 0 : ret.autoScale = false;
4911 : return ret;
4912 : }
4913 :
4914 0 : nsIDOMWindow* window = aDocument->GetWindow();
4915 0 : nsCOMPtr<nsIDOMWindowUtils> windowUtils(do_GetInterface(window));
4916 :
4917 0 : if (!windowUtils) {
4918 : return ret;
4919 : }
4920 :
4921 0 : nsAutoString handheldFriendly;
4922 0 : aDocument->GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
4923 :
4924 0 : if (handheldFriendly.EqualsLiteral("true")) {
4925 : return ret;
4926 : }
4927 :
4928 : PRInt32 errorCode;
4929 :
4930 0 : nsAutoString minScaleStr;
4931 0 : aDocument->GetHeaderData(nsGkAtoms::minimum_scale, minScaleStr);
4932 :
4933 0 : float scaleMinFloat = minScaleStr.ToFloat(&errorCode);
4934 :
4935 0 : if (errorCode) {
4936 0 : scaleMinFloat = kViewportMinScale;
4937 : }
4938 :
4939 0 : scaleMinFloat = NS_MIN(scaleMinFloat, kViewportMaxScale);
4940 0 : scaleMinFloat = NS_MAX(scaleMinFloat, kViewportMinScale);
4941 :
4942 0 : nsAutoString maxScaleStr;
4943 0 : aDocument->GetHeaderData(nsGkAtoms::maximum_scale, maxScaleStr);
4944 :
4945 : // We define a special error code variable for the scale and max scale,
4946 : // because they are used later (see the width calculations).
4947 : PRInt32 scaleMaxErrorCode;
4948 0 : float scaleMaxFloat = maxScaleStr.ToFloat(&scaleMaxErrorCode);
4949 :
4950 0 : if (scaleMaxErrorCode) {
4951 0 : scaleMaxFloat = kViewportMaxScale;
4952 : }
4953 :
4954 0 : scaleMaxFloat = NS_MIN(scaleMaxFloat, kViewportMaxScale);
4955 0 : scaleMaxFloat = NS_MAX(scaleMaxFloat, kViewportMinScale);
4956 :
4957 0 : nsAutoString scaleStr;
4958 0 : aDocument->GetHeaderData(nsGkAtoms::viewport_initial_scale, scaleStr);
4959 :
4960 : PRInt32 scaleErrorCode;
4961 0 : float scaleFloat = scaleStr.ToFloat(&scaleErrorCode);
4962 0 : scaleFloat = NS_MIN(scaleFloat, scaleMaxFloat);
4963 0 : scaleFloat = NS_MAX(scaleFloat, scaleMinFloat);
4964 :
4965 0 : nsAutoString widthStr, heightStr;
4966 :
4967 0 : aDocument->GetHeaderData(nsGkAtoms::viewport_height, heightStr);
4968 0 : aDocument->GetHeaderData(nsGkAtoms::viewport_width, widthStr);
4969 :
4970 0 : bool autoSize = false;
4971 :
4972 0 : if (widthStr.EqualsLiteral("device-width")) {
4973 0 : autoSize = true;
4974 : }
4975 :
4976 0 : if (widthStr.IsEmpty() &&
4977 0 : (heightStr.EqualsLiteral("device-height") ||
4978 : scaleFloat == 1.0))
4979 : {
4980 0 : autoSize = true;
4981 : }
4982 :
4983 : // XXXjwir3:
4984 : // See bug 706918, comment 23 for more information on this particular section
4985 : // of the code. We're using "screen size" in place of the size of the content
4986 : // area, because on mobile, these are close or equal. This will work for our
4987 : // purposes (bug 706198), but it will need to be changed in the future to be
4988 : // more correct when we bring the rest of the viewport code into platform.
4989 : // We actually want the size of the content area, in the event that we don't
4990 : // have any metadata about the width and/or height. On mobile, the screen size
4991 : // and the size of the content area are very close, or the same value.
4992 : // In XUL fennec, the content area is the size of the <browser> widget, but
4993 : // in native fennec, the content area is the size of the Gecko LayerView
4994 : // object.
4995 :
4996 : // TODO:
4997 : // Once bug 716575 has been resolved, this code should be changed so that it
4998 : // does the right thing on all platforms.
4999 : nsresult result;
5000 : PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
5001 : nsCOMPtr<nsIScreenManager> screenMgr =
5002 0 : do_GetService("@mozilla.org/gfx/screenmanager;1", &result);
5003 :
5004 0 : nsCOMPtr<nsIScreen> screen;
5005 0 : screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
5006 0 : screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
5007 :
5008 0 : PRUint32 width = widthStr.ToInteger(&errorCode);
5009 0 : if (errorCode) {
5010 0 : if (autoSize) {
5011 0 : width = screenWidth;
5012 : } else {
5013 0 : width = Preferences::GetInt("browser.viewport.desktopWidth", 0);
5014 : }
5015 : }
5016 :
5017 0 : width = NS_MIN(width, kViewportMaxWidth);
5018 0 : width = NS_MAX(width, kViewportMinWidth);
5019 :
5020 : // Also recalculate the default zoom, if it wasn't specified in the metadata,
5021 : // and the width is specified.
5022 0 : if (scaleStr.IsEmpty() && !widthStr.IsEmpty()) {
5023 0 : scaleFloat = NS_MAX(scaleFloat, (float)(screenWidth/width));
5024 : }
5025 :
5026 0 : PRUint32 height = heightStr.ToInteger(&errorCode);
5027 :
5028 0 : if (errorCode) {
5029 0 : height = width * ((float)screenHeight / screenWidth);
5030 : }
5031 :
5032 : // If height was provided by the user, but width wasn't, then we should
5033 : // calculate the width.
5034 0 : if (widthStr.IsEmpty() && !heightStr.IsEmpty()) {
5035 0 : width = (PRUint32) ((height * screenWidth) / screenHeight);
5036 : }
5037 :
5038 0 : height = NS_MIN(height, kViewportMaxHeight);
5039 0 : height = NS_MAX(height, kViewportMinHeight);
5040 :
5041 : // We need to perform a conversion, but only if the initial or maximum
5042 : // scale were set explicitly by the user.
5043 0 : if (!scaleStr.IsEmpty() && !scaleErrorCode) {
5044 0 : width = NS_MAX(width, (PRUint32)(screenWidth / scaleFloat));
5045 0 : height = NS_MAX(height, (PRUint32)(screenHeight / scaleFloat));
5046 0 : } else if (!maxScaleStr.IsEmpty() && !scaleMaxErrorCode) {
5047 0 : width = NS_MAX(width, (PRUint32)(screenWidth / scaleMaxFloat));
5048 0 : height = NS_MAX(height, (PRUint32)(screenHeight / scaleMaxFloat));
5049 : }
5050 :
5051 0 : bool allowZoom = true;
5052 0 : nsAutoString userScalable;
5053 0 : aDocument->GetHeaderData(nsGkAtoms::viewport_user_scalable, userScalable);
5054 :
5055 0 : if ((userScalable.EqualsLiteral("0")) ||
5056 0 : (userScalable.EqualsLiteral("no")) ||
5057 0 : (userScalable.EqualsLiteral("false"))) {
5058 0 : allowZoom = false;
5059 : }
5060 :
5061 0 : ret.allowZoom = allowZoom;
5062 0 : ret.width = width;
5063 0 : ret.height = height;
5064 0 : ret.defaultZoom = scaleFloat;
5065 0 : ret.minZoom = scaleMinFloat;
5066 0 : ret.maxZoom = scaleMaxFloat;
5067 0 : ret.autoSize = autoSize;
5068 : return ret;
5069 : }
5070 :
5071 : /* static */
5072 : nsresult
5073 0 : nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument,
5074 : const nsAString &viewportInfo) {
5075 :
5076 : /* We never fail. */
5077 0 : nsresult rv = NS_OK;
5078 :
5079 : /* Iterators. */
5080 0 : nsAString::const_iterator tip, tail, end;
5081 0 : viewportInfo.BeginReading(tip);
5082 0 : tail = tip;
5083 0 : viewportInfo.EndReading(end);
5084 :
5085 : /* Read the tip to the first non-separator character. */
5086 0 : while ((tip != end) && (IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip)))
5087 0 : ++tip;
5088 :
5089 : /* Read through and find tokens separated by separators. */
5090 0 : while (tip != end) {
5091 :
5092 : /* Synchronize tip and tail. */
5093 0 : tail = tip;
5094 :
5095 : /* Advance tip past non-separator characters. */
5096 0 : while ((tip != end) && !IS_SEPARATOR(*tip))
5097 0 : ++tip;
5098 :
5099 : /* Allow white spaces that surround the '=' character */
5100 0 : if ((tip != end) && (*tip == '=')) {
5101 0 : ++tip;
5102 :
5103 0 : while ((tip != end) && nsCRT::IsAsciiSpace(*tip))
5104 0 : ++tip;
5105 :
5106 0 : while ((tip != end) && !(IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip)))
5107 0 : ++tip;
5108 : }
5109 :
5110 : /* Our token consists of the characters between tail and tip. */
5111 0 : ProcessViewportToken(aDocument, Substring(tail, tip));
5112 :
5113 : /* Skip separators. */
5114 0 : while ((tip != end) && (IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip)))
5115 0 : ++tip;
5116 : }
5117 :
5118 0 : return rv;
5119 :
5120 : }
5121 :
5122 : #undef IS_SEPARATOR
5123 :
5124 : /* static */
5125 : void
5126 0 : nsContentUtils::HidePopupsInDocument(nsIDocument* aDocument)
5127 : {
5128 : #ifdef MOZ_XUL
5129 0 : nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
5130 0 : if (pm && aDocument) {
5131 0 : nsCOMPtr<nsISupports> container = aDocument->GetContainer();
5132 0 : nsCOMPtr<nsIDocShellTreeItem> docShellToHide = do_QueryInterface(container);
5133 0 : if (docShellToHide)
5134 0 : pm->HidePopupsInDocShell(docShellToHide);
5135 : }
5136 : #endif
5137 0 : }
5138 :
5139 : /* static */
5140 : already_AddRefed<nsIDragSession>
5141 0 : nsContentUtils::GetDragSession()
5142 : {
5143 0 : nsIDragSession* dragSession = nsnull;
5144 : nsCOMPtr<nsIDragService> dragService =
5145 0 : do_GetService("@mozilla.org/widget/dragservice;1");
5146 0 : if (dragService)
5147 0 : dragService->GetCurrentSession(&dragSession);
5148 0 : return dragSession;
5149 : }
5150 :
5151 : /* static */
5152 : nsresult
5153 0 : nsContentUtils::SetDataTransferInEvent(nsDragEvent* aDragEvent)
5154 : {
5155 0 : if (aDragEvent->dataTransfer || !NS_IS_TRUSTED_EVENT(aDragEvent))
5156 0 : return NS_OK;
5157 :
5158 : // For draggesture and dragstart events, the data transfer object is
5159 : // created before the event fires, so it should already be set. For other
5160 : // drag events, get the object from the drag session.
5161 0 : NS_ASSERTION(aDragEvent->message != NS_DRAGDROP_GESTURE &&
5162 : aDragEvent->message != NS_DRAGDROP_START,
5163 : "draggesture event created without a dataTransfer");
5164 :
5165 0 : nsCOMPtr<nsIDragSession> dragSession = GetDragSession();
5166 0 : NS_ENSURE_TRUE(dragSession, NS_OK); // no drag in progress
5167 :
5168 0 : nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
5169 0 : dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
5170 0 : if (!initialDataTransfer) {
5171 : // A dataTransfer won't exist when a drag was started by some other
5172 : // means, for instance calling the drag service directly, or a drag
5173 : // from another application. In either case, a new dataTransfer should
5174 : // be created that reflects the data.
5175 : initialDataTransfer =
5176 0 : new nsDOMDataTransfer(aDragEvent->message);
5177 0 : NS_ENSURE_TRUE(initialDataTransfer, NS_ERROR_OUT_OF_MEMORY);
5178 :
5179 : // now set it in the drag session so we don't need to create it again
5180 0 : dragSession->SetDataTransfer(initialDataTransfer);
5181 : }
5182 :
5183 : // each event should use a clone of the original dataTransfer.
5184 0 : initialDataTransfer->Clone(aDragEvent->message, aDragEvent->userCancelled,
5185 0 : getter_AddRefs(aDragEvent->dataTransfer));
5186 0 : NS_ENSURE_TRUE(aDragEvent->dataTransfer, NS_ERROR_OUT_OF_MEMORY);
5187 :
5188 : // for the dragenter and dragover events, initialize the drop effect
5189 : // from the drop action, which platform specific widget code sets before
5190 : // the event is fired based on the keyboard state.
5191 0 : if (aDragEvent->message == NS_DRAGDROP_ENTER ||
5192 : aDragEvent->message == NS_DRAGDROP_OVER) {
5193 : PRUint32 action, effectAllowed;
5194 0 : dragSession->GetDragAction(&action);
5195 0 : aDragEvent->dataTransfer->GetEffectAllowedInt(&effectAllowed);
5196 0 : aDragEvent->dataTransfer->SetDropEffectInt(FilterDropEffect(action, effectAllowed));
5197 : }
5198 0 : else if (aDragEvent->message == NS_DRAGDROP_DROP ||
5199 : aDragEvent->message == NS_DRAGDROP_DRAGDROP ||
5200 : aDragEvent->message == NS_DRAGDROP_END) {
5201 : // For the drop and dragend events, set the drop effect based on the
5202 : // last value that the dropEffect had. This will have been set in
5203 : // nsEventStateManager::PostHandleEvent for the last dragenter or
5204 : // dragover event.
5205 : PRUint32 dropEffect;
5206 0 : initialDataTransfer->GetDropEffectInt(&dropEffect);
5207 0 : aDragEvent->dataTransfer->SetDropEffectInt(dropEffect);
5208 : }
5209 :
5210 0 : return NS_OK;
5211 : }
5212 :
5213 : /* static */
5214 : PRUint32
5215 0 : nsContentUtils::FilterDropEffect(PRUint32 aAction, PRUint32 aEffectAllowed)
5216 : {
5217 : // It is possible for the drag action to include more than one action, but
5218 : // the widget code which sets the action from the keyboard state should only
5219 : // be including one. If multiple actions were set, we just consider them in
5220 : // the following order:
5221 : // copy, link, move
5222 0 : if (aAction & nsIDragService::DRAGDROP_ACTION_COPY)
5223 0 : aAction = nsIDragService::DRAGDROP_ACTION_COPY;
5224 0 : else if (aAction & nsIDragService::DRAGDROP_ACTION_LINK)
5225 0 : aAction = nsIDragService::DRAGDROP_ACTION_LINK;
5226 0 : else if (aAction & nsIDragService::DRAGDROP_ACTION_MOVE)
5227 0 : aAction = nsIDragService::DRAGDROP_ACTION_MOVE;
5228 :
5229 : // Filter the action based on the effectAllowed. If the effectAllowed
5230 : // doesn't include the action, then that action cannot be done, so adjust
5231 : // the action to something that is allowed. For a copy, adjust to move or
5232 : // link. For a move, adjust to copy or link. For a link, adjust to move or
5233 : // link. Otherwise, use none.
5234 0 : if (aAction & aEffectAllowed ||
5235 : aEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
5236 0 : return aAction;
5237 0 : if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_MOVE)
5238 0 : return nsIDragService::DRAGDROP_ACTION_MOVE;
5239 0 : if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_COPY)
5240 0 : return nsIDragService::DRAGDROP_ACTION_COPY;
5241 0 : if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_LINK)
5242 0 : return nsIDragService::DRAGDROP_ACTION_LINK;
5243 0 : return nsIDragService::DRAGDROP_ACTION_NONE;
5244 : }
5245 :
5246 : /* static */
5247 : bool
5248 2 : nsContentUtils::URIIsLocalFile(nsIURI *aURI)
5249 : {
5250 : bool isFile;
5251 4 : nsCOMPtr<nsINetUtil> util = do_QueryInterface(sIOService);
5252 :
5253 : // Important: we do NOT test the entire URI chain here!
5254 4 : return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
5255 : nsIProtocolHandler::URI_IS_LOCAL_FILE,
5256 : &isFile)) &&
5257 4 : isFile;
5258 : }
5259 :
5260 : nsresult
5261 0 : nsContentUtils::SplitURIAtHash(nsIURI *aURI,
5262 : nsACString &aBeforeHash,
5263 : nsACString &aAfterHash)
5264 : {
5265 : // See bug 225910 for why we can't do this using nsIURL.
5266 :
5267 0 : aBeforeHash.Truncate();
5268 0 : aAfterHash.Truncate();
5269 :
5270 0 : NS_ENSURE_ARG_POINTER(aURI);
5271 :
5272 0 : nsCAutoString spec;
5273 0 : nsresult rv = aURI->GetSpec(spec);
5274 0 : NS_ENSURE_SUCCESS(rv, rv);
5275 :
5276 0 : PRInt32 index = spec.FindChar('#');
5277 0 : if (index == -1) {
5278 0 : index = spec.Length();
5279 : }
5280 :
5281 0 : aBeforeHash.Assign(Substring(spec, 0, index));
5282 0 : aAfterHash.Assign(Substring(spec, index));
5283 0 : return NS_OK;
5284 : }
5285 :
5286 : /* static */
5287 : nsIScriptContext*
5288 2 : nsContentUtils::GetContextForEventHandlers(nsINode* aNode,
5289 : nsresult* aRv)
5290 : {
5291 2 : *aRv = NS_OK;
5292 2 : bool hasHadScriptObject = true;
5293 : nsIScriptGlobalObject* sgo =
5294 2 : aNode->OwnerDoc()->GetScriptHandlingObject(hasHadScriptObject);
5295 : // It is bad if the document doesn't have event handling context,
5296 : // but it used to have one.
5297 2 : if (!sgo && hasHadScriptObject) {
5298 0 : *aRv = NS_ERROR_UNEXPECTED;
5299 0 : return nsnull;
5300 : }
5301 :
5302 2 : if (sgo) {
5303 0 : nsIScriptContext* scx = sgo->GetContext();
5304 : // Bad, no context from script global object!
5305 0 : if (!scx) {
5306 0 : *aRv = NS_ERROR_UNEXPECTED;
5307 0 : return nsnull;
5308 : }
5309 0 : return scx;
5310 : }
5311 :
5312 2 : return nsnull;
5313 : }
5314 :
5315 : /* static */
5316 : JSContext *
5317 70 : nsContentUtils::GetCurrentJSContext()
5318 : {
5319 70 : JSContext *cx = nsnull;
5320 :
5321 70 : sThreadJSContextStack->Peek(&cx);
5322 :
5323 70 : return cx;
5324 : }
5325 :
5326 : /* static */
5327 : nsresult
5328 0 : nsContentUtils::ASCIIToLower(nsAString& aStr)
5329 : {
5330 0 : PRUnichar* iter = aStr.BeginWriting();
5331 0 : PRUnichar* end = aStr.EndWriting();
5332 0 : if (NS_UNLIKELY(!iter || !end)) {
5333 0 : return NS_ERROR_OUT_OF_MEMORY;
5334 : }
5335 0 : while (iter != end) {
5336 0 : PRUnichar c = *iter;
5337 0 : if (c >= 'A' && c <= 'Z') {
5338 0 : *iter = c + ('a' - 'A');
5339 : }
5340 0 : ++iter;
5341 : }
5342 0 : return NS_OK;
5343 : }
5344 :
5345 : /* static */
5346 : nsresult
5347 3338 : nsContentUtils::ASCIIToLower(const nsAString& aSource, nsAString& aDest)
5348 : {
5349 3338 : PRUint32 len = aSource.Length();
5350 3338 : aDest.SetLength(len);
5351 3338 : if (aDest.Length() == len) {
5352 3338 : PRUnichar* dest = aDest.BeginWriting();
5353 3338 : if (NS_UNLIKELY(!dest)) {
5354 0 : return NS_ERROR_OUT_OF_MEMORY;
5355 : }
5356 3338 : const PRUnichar* iter = aSource.BeginReading();
5357 3338 : const PRUnichar* end = aSource.EndReading();
5358 36730 : while (iter != end) {
5359 30054 : PRUnichar c = *iter;
5360 : *dest = (c >= 'A' && c <= 'Z') ?
5361 30054 : c + ('a' - 'A') : c;
5362 30054 : ++iter;
5363 30054 : ++dest;
5364 : }
5365 3338 : return NS_OK;
5366 : }
5367 0 : return NS_ERROR_OUT_OF_MEMORY;
5368 : }
5369 :
5370 : /* static */
5371 : nsresult
5372 0 : nsContentUtils::ASCIIToUpper(nsAString& aStr)
5373 : {
5374 0 : PRUnichar* iter = aStr.BeginWriting();
5375 0 : PRUnichar* end = aStr.EndWriting();
5376 0 : if (NS_UNLIKELY(!iter || !end)) {
5377 0 : return NS_ERROR_OUT_OF_MEMORY;
5378 : }
5379 0 : while (iter != end) {
5380 0 : PRUnichar c = *iter;
5381 0 : if (c >= 'a' && c <= 'z') {
5382 0 : *iter = c + ('A' - 'a');
5383 : }
5384 0 : ++iter;
5385 : }
5386 0 : return NS_OK;
5387 : }
5388 :
5389 : /* static */
5390 : nsresult
5391 775 : nsContentUtils::ASCIIToUpper(const nsAString& aSource, nsAString& aDest)
5392 : {
5393 775 : PRUint32 len = aSource.Length();
5394 775 : aDest.SetLength(len);
5395 775 : if (aDest.Length() == len) {
5396 775 : PRUnichar* dest = aDest.BeginWriting();
5397 775 : if (NS_UNLIKELY(!dest)) {
5398 0 : return NS_ERROR_OUT_OF_MEMORY;
5399 : }
5400 775 : const PRUnichar* iter = aSource.BeginReading();
5401 775 : const PRUnichar* end = aSource.EndReading();
5402 4490 : while (iter != end) {
5403 2940 : PRUnichar c = *iter;
5404 : *dest = (c >= 'a' && c <= 'z') ?
5405 2940 : c + ('A' - 'a') : c;
5406 2940 : ++iter;
5407 2940 : ++dest;
5408 : }
5409 775 : return NS_OK;
5410 : }
5411 0 : return NS_ERROR_OUT_OF_MEMORY;
5412 : }
5413 :
5414 : /* static */
5415 : bool
5416 0 : nsContentUtils::EqualsIgnoreASCIICase(const nsAString& aStr1,
5417 : const nsAString& aStr2)
5418 : {
5419 0 : PRUint32 len = aStr1.Length();
5420 0 : if (len != aStr2.Length()) {
5421 0 : return false;
5422 : }
5423 :
5424 0 : const PRUnichar* str1 = aStr1.BeginReading();
5425 0 : const PRUnichar* str2 = aStr2.BeginReading();
5426 0 : const PRUnichar* end = str1 + len;
5427 :
5428 0 : while (str1 < end) {
5429 0 : PRUnichar c1 = *str1++;
5430 0 : PRUnichar c2 = *str2++;
5431 :
5432 : // First check if any bits other than the 0x0020 differs
5433 0 : if ((c1 ^ c2) & 0xffdf) {
5434 0 : return false;
5435 : }
5436 :
5437 : // We know they can only differ in the 0x0020 bit.
5438 : // Likely the two chars are the same, so check that first
5439 0 : if (c1 != c2) {
5440 : // They do differ, but since it's only in the 0x0020 bit, check if it's
5441 : // the same ascii char, but just differing in case
5442 0 : PRUnichar c1Upper = c1 & 0xffdf;
5443 0 : if (!('A' <= c1Upper && c1Upper <= 'Z')) {
5444 0 : return false;
5445 : }
5446 : }
5447 : }
5448 :
5449 0 : return true;
5450 : }
5451 :
5452 : /* static */
5453 : bool
5454 0 : nsContentUtils::EqualsLiteralIgnoreASCIICase(const nsAString& aStr1,
5455 : const char* aStr2,
5456 : const PRUint32 len)
5457 : {
5458 0 : if (aStr1.Length() != len) {
5459 0 : return false;
5460 : }
5461 :
5462 0 : const PRUnichar* str1 = aStr1.BeginReading();
5463 0 : const char* str2 = aStr2;
5464 0 : const PRUnichar* end = str1 + len;
5465 :
5466 0 : while (str1 < end) {
5467 0 : PRUnichar c1 = *str1++;
5468 0 : PRUnichar c2 = *str2++;
5469 :
5470 : // First check if any bits other than the 0x0020 differs
5471 0 : if ((c1 ^ c2) & 0xffdf) {
5472 0 : return false;
5473 : }
5474 :
5475 : // We know they can only differ in the 0x0020 bit.
5476 : // Likely the two chars are the same, so check that first
5477 0 : if (c1 != c2) {
5478 : // They do differ, but since it's only in the 0x0020 bit, check if it's
5479 : // the same ascii char, but just differing in case
5480 0 : PRUnichar c1Upper = c1 & 0xffdf;
5481 0 : if (!('A' <= c1Upper && c1Upper <= 'Z')) {
5482 0 : return false;
5483 : }
5484 : }
5485 : }
5486 :
5487 0 : return true;
5488 : }
5489 :
5490 : /* static */
5491 : nsIInterfaceRequestor*
5492 0 : nsContentUtils::GetSameOriginChecker()
5493 : {
5494 0 : if (!sSameOriginChecker) {
5495 0 : sSameOriginChecker = new nsSameOriginChecker();
5496 0 : NS_IF_ADDREF(sSameOriginChecker);
5497 : }
5498 0 : return sSameOriginChecker;
5499 : }
5500 :
5501 : /* static */
5502 : nsresult
5503 0 : nsContentUtils::CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel)
5504 : {
5505 0 : if (!nsContentUtils::GetSecurityManager())
5506 0 : return NS_ERROR_NOT_AVAILABLE;
5507 :
5508 0 : nsCOMPtr<nsIPrincipal> oldPrincipal;
5509 0 : nsContentUtils::GetSecurityManager()->
5510 0 : GetChannelPrincipal(aOldChannel, getter_AddRefs(oldPrincipal));
5511 :
5512 0 : nsCOMPtr<nsIURI> newURI;
5513 0 : aNewChannel->GetURI(getter_AddRefs(newURI));
5514 0 : nsCOMPtr<nsIURI> newOriginalURI;
5515 0 : aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
5516 :
5517 0 : NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
5518 :
5519 0 : nsresult rv = oldPrincipal->CheckMayLoad(newURI, false);
5520 0 : if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
5521 0 : rv = oldPrincipal->CheckMayLoad(newOriginalURI, false);
5522 : }
5523 :
5524 0 : return rv;
5525 : }
5526 :
5527 0 : NS_IMPL_ISUPPORTS2(nsSameOriginChecker,
5528 : nsIChannelEventSink,
5529 : nsIInterfaceRequestor)
5530 :
5531 : NS_IMETHODIMP
5532 0 : nsSameOriginChecker::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
5533 : nsIChannel *aNewChannel,
5534 : PRUint32 aFlags,
5535 : nsIAsyncVerifyRedirectCallback *cb)
5536 : {
5537 0 : NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
5538 :
5539 0 : nsresult rv = nsContentUtils::CheckSameOrigin(aOldChannel, aNewChannel);
5540 0 : if (NS_SUCCEEDED(rv)) {
5541 0 : cb->OnRedirectVerifyCallback(NS_OK);
5542 : }
5543 :
5544 0 : return rv;
5545 : }
5546 :
5547 : NS_IMETHODIMP
5548 0 : nsSameOriginChecker::GetInterface(const nsIID & aIID, void **aResult)
5549 : {
5550 0 : return QueryInterface(aIID, aResult);
5551 : }
5552 :
5553 : /* static */
5554 : nsresult
5555 0 : nsContentUtils::GetASCIIOrigin(nsIPrincipal* aPrincipal, nsCString& aOrigin)
5556 : {
5557 0 : NS_PRECONDITION(aPrincipal, "missing principal");
5558 :
5559 0 : aOrigin.Truncate();
5560 :
5561 0 : nsCOMPtr<nsIURI> uri;
5562 0 : nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
5563 0 : NS_ENSURE_SUCCESS(rv, rv);
5564 :
5565 0 : if (uri) {
5566 0 : return GetASCIIOrigin(uri, aOrigin);
5567 : }
5568 :
5569 0 : aOrigin.AssignLiteral("null");
5570 :
5571 0 : return NS_OK;
5572 : }
5573 :
5574 : /* static */
5575 : nsresult
5576 96 : nsContentUtils::GetASCIIOrigin(nsIURI* aURI, nsCString& aOrigin)
5577 : {
5578 96 : NS_PRECONDITION(aURI, "missing uri");
5579 :
5580 96 : aOrigin.Truncate();
5581 :
5582 192 : nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
5583 96 : NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
5584 :
5585 192 : nsCString host;
5586 96 : nsresult rv = uri->GetAsciiHost(host);
5587 :
5588 96 : if (NS_SUCCEEDED(rv) && !host.IsEmpty()) {
5589 192 : nsCString scheme;
5590 96 : rv = uri->GetScheme(scheme);
5591 96 : NS_ENSURE_SUCCESS(rv, rv);
5592 :
5593 96 : PRInt32 port = -1;
5594 96 : uri->GetPort(&port);
5595 96 : if (port != -1 && port == NS_GetDefaultPort(scheme.get()))
5596 0 : port = -1;
5597 :
5598 192 : nsCString hostPort;
5599 96 : rv = NS_GenerateHostPort(host, port, hostPort);
5600 96 : NS_ENSURE_SUCCESS(rv, rv);
5601 :
5602 192 : aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort;
5603 : }
5604 : else {
5605 0 : aOrigin.AssignLiteral("null");
5606 : }
5607 :
5608 96 : return NS_OK;
5609 : }
5610 :
5611 : /* static */
5612 : nsresult
5613 0 : nsContentUtils::GetUTFOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin)
5614 : {
5615 0 : NS_PRECONDITION(aPrincipal, "missing principal");
5616 :
5617 0 : aOrigin.Truncate();
5618 :
5619 0 : nsCOMPtr<nsIURI> uri;
5620 0 : nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
5621 0 : NS_ENSURE_SUCCESS(rv, rv);
5622 :
5623 0 : if (uri) {
5624 0 : return GetUTFOrigin(uri, aOrigin);
5625 : }
5626 :
5627 0 : aOrigin.AssignLiteral("null");
5628 :
5629 0 : return NS_OK;
5630 : }
5631 :
5632 : /* static */
5633 : nsresult
5634 0 : nsContentUtils::GetUTFOrigin(nsIURI* aURI, nsString& aOrigin)
5635 : {
5636 0 : NS_PRECONDITION(aURI, "missing uri");
5637 :
5638 0 : aOrigin.Truncate();
5639 :
5640 0 : nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
5641 0 : NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
5642 :
5643 0 : nsCString host;
5644 0 : nsresult rv = uri->GetHost(host);
5645 :
5646 0 : if (NS_SUCCEEDED(rv) && !host.IsEmpty()) {
5647 0 : nsCString scheme;
5648 0 : rv = uri->GetScheme(scheme);
5649 0 : NS_ENSURE_SUCCESS(rv, rv);
5650 :
5651 0 : PRInt32 port = -1;
5652 0 : uri->GetPort(&port);
5653 0 : if (port != -1 && port == NS_GetDefaultPort(scheme.get()))
5654 0 : port = -1;
5655 :
5656 0 : nsCString hostPort;
5657 0 : rv = NS_GenerateHostPort(host, port, hostPort);
5658 0 : NS_ENSURE_SUCCESS(rv, rv);
5659 :
5660 : aOrigin = NS_ConvertUTF8toUTF16(
5661 0 : scheme + NS_LITERAL_CSTRING("://") + hostPort);
5662 : }
5663 : else {
5664 0 : aOrigin.AssignLiteral("null");
5665 : }
5666 :
5667 0 : return NS_OK;
5668 : }
5669 :
5670 : /* static */
5671 : already_AddRefed<nsIDocument>
5672 6160 : nsContentUtils::GetDocumentFromScriptContext(nsIScriptContext *aScriptContext)
5673 : {
5674 6160 : if (!aScriptContext)
5675 6160 : return nsnull;
5676 :
5677 : nsCOMPtr<nsIDOMWindow> window =
5678 0 : do_QueryInterface(aScriptContext->GetGlobalObject());
5679 0 : nsIDocument *doc = nsnull;
5680 0 : if (window) {
5681 0 : nsCOMPtr<nsIDOMDocument> domdoc;
5682 0 : window->GetDocument(getter_AddRefs(domdoc));
5683 0 : if (domdoc) {
5684 0 : CallQueryInterface(domdoc, &doc);
5685 : }
5686 : }
5687 0 : return doc;
5688 : }
5689 :
5690 : /* static */
5691 : bool
5692 0 : nsContentUtils::CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel)
5693 : {
5694 0 : nsCOMPtr<nsIURI> channelURI;
5695 0 : nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
5696 0 : NS_ENSURE_SUCCESS(rv, false);
5697 :
5698 0 : return NS_SUCCEEDED(aPrincipal->CheckMayLoad(channelURI, false));
5699 : }
5700 :
5701 0 : nsContentTypeParser::nsContentTypeParser(const nsAString& aString)
5702 0 : : mString(aString), mService(nsnull)
5703 : {
5704 0 : CallGetService("@mozilla.org/network/mime-hdrparam;1", &mService);
5705 0 : }
5706 :
5707 0 : nsContentTypeParser::~nsContentTypeParser()
5708 : {
5709 0 : NS_IF_RELEASE(mService);
5710 0 : }
5711 :
5712 : nsresult
5713 0 : nsContentTypeParser::GetParameter(const char* aParameterName, nsAString& aResult)
5714 : {
5715 0 : NS_ENSURE_TRUE(mService, NS_ERROR_FAILURE);
5716 : return mService->GetParameter(mString, aParameterName,
5717 0 : EmptyCString(), false, nsnull,
5718 0 : aResult);
5719 : }
5720 :
5721 : /* static */
5722 :
5723 : // If you change this code, change also AllowedToAct() in
5724 : // XPCSystemOnlyWrapper.cpp!
5725 : bool
5726 0 : nsContentUtils::CanAccessNativeAnon()
5727 : {
5728 0 : JSContext* cx = nsnull;
5729 0 : sThreadJSContextStack->Peek(&cx);
5730 0 : if (!cx) {
5731 0 : return true;
5732 : }
5733 : JSStackFrame* fp;
5734 : nsIPrincipal* principal =
5735 0 : sSecurityManager->GetCxSubjectPrincipalAndFrame(cx, &fp);
5736 0 : NS_ENSURE_TRUE(principal, false);
5737 :
5738 0 : if (!fp) {
5739 0 : if (!JS_FrameIterator(cx, &fp)) {
5740 : // No code at all is running. So we must be arriving here as the result
5741 : // of C++ code asking us to do something. Allow access.
5742 0 : return true;
5743 : }
5744 :
5745 : // Some code is running, we can't make the assumption, as above, but we
5746 : // can't use a native frame, so clear fp.
5747 0 : fp = nsnull;
5748 0 : } else if (!JS_IsScriptFrame(cx, fp)) {
5749 0 : fp = nsnull;
5750 : }
5751 :
5752 : bool privileged;
5753 0 : if (NS_SUCCEEDED(sSecurityManager->IsSystemPrincipal(principal, &privileged)) &&
5754 : privileged) {
5755 : // Chrome things are allowed to touch us.
5756 0 : return true;
5757 : }
5758 :
5759 : // XXX HACK EWW! Allow chrome://global/ access to these things, even
5760 : // if they've been cloned into less privileged contexts.
5761 : static const char prefix[] = "chrome://global/";
5762 : const char *filename;
5763 0 : if (fp && JS_IsScriptFrame(cx, fp) &&
5764 0 : (filename = JS_GetScriptFilename(cx, JS_GetFrameScript(cx, fp))) &&
5765 0 : !strncmp(filename, prefix, ArrayLength(prefix) - 1)) {
5766 0 : return true;
5767 : }
5768 :
5769 : // Before we throw, check for UniversalXPConnect.
5770 0 : nsresult rv = sSecurityManager->IsCapabilityEnabled("UniversalXPConnect", &privileged);
5771 0 : if (NS_SUCCEEDED(rv) && privileged) {
5772 0 : return true;
5773 : }
5774 :
5775 0 : return false;
5776 : }
5777 :
5778 : /* static */ nsresult
5779 0 : nsContentUtils::DispatchXULCommand(nsIContent* aTarget,
5780 : bool aTrusted,
5781 : nsIDOMEvent* aSourceEvent,
5782 : nsIPresShell* aShell,
5783 : bool aCtrl,
5784 : bool aAlt,
5785 : bool aShift,
5786 : bool aMeta)
5787 : {
5788 0 : NS_ENSURE_STATE(aTarget);
5789 0 : nsIDocument* doc = aTarget->OwnerDoc();
5790 0 : nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
5791 0 : NS_ENSURE_STATE(domDoc);
5792 0 : nsCOMPtr<nsIDOMEvent> event;
5793 0 : domDoc->CreateEvent(NS_LITERAL_STRING("xulcommandevent"),
5794 0 : getter_AddRefs(event));
5795 0 : nsCOMPtr<nsIDOMXULCommandEvent> xulCommand = do_QueryInterface(event);
5796 0 : nsCOMPtr<nsIPrivateDOMEvent> pEvent = do_QueryInterface(xulCommand);
5797 0 : NS_ENSURE_STATE(pEvent);
5798 0 : nsresult rv = xulCommand->InitCommandEvent(NS_LITERAL_STRING("command"),
5799 0 : true, true, doc->GetWindow(),
5800 : 0, aCtrl, aAlt, aShift, aMeta,
5801 0 : aSourceEvent);
5802 0 : NS_ENSURE_SUCCESS(rv, rv);
5803 :
5804 0 : if (aShell) {
5805 0 : nsEventStatus status = nsEventStatus_eIgnore;
5806 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip = aShell;
5807 0 : return aShell->HandleDOMEventWithTarget(aTarget, event, &status);
5808 : }
5809 :
5810 0 : nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(aTarget);
5811 0 : NS_ENSURE_STATE(target);
5812 : bool dummy;
5813 0 : return target->DispatchEvent(event, &dummy);
5814 : }
5815 :
5816 : // static
5817 : nsresult
5818 1933 : nsContentUtils::WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
5819 : nsWrapperCache *cache, const nsIID* aIID, jsval *vp,
5820 : nsIXPConnectJSObjectHolder **aHolder,
5821 : bool aAllowWrapping)
5822 : {
5823 1933 : if (!native) {
5824 0 : NS_ASSERTION(!aHolder || !*aHolder, "*aHolder should be null!");
5825 :
5826 0 : *vp = JSVAL_NULL;
5827 :
5828 0 : return NS_OK;
5829 : }
5830 :
5831 1933 : JSObject *wrapper = xpc_FastGetCachedWrapper(cache, scope, vp);
5832 1933 : if (wrapper) {
5833 0 : return NS_OK;
5834 : }
5835 :
5836 1933 : NS_ENSURE_TRUE(sXPConnect && sThreadJSContextStack, NS_ERROR_UNEXPECTED);
5837 :
5838 : // Keep sXPConnect and sThreadJSContextStack alive. If we're on the main
5839 : // thread then this can be done simply and cheaply by adding a reference to
5840 : // nsLayoutStatics. If we're not on the main thread then we need to add a
5841 : // more expensive reference sXPConnect directly. We have to use manual
5842 : // AddRef and Release calls so don't early-exit from this function after we've
5843 : // added the reference!
5844 1933 : bool isMainThread = NS_IsMainThread();
5845 :
5846 1933 : if (isMainThread) {
5847 1933 : nsLayoutStatics::AddRef();
5848 : }
5849 : else {
5850 0 : sXPConnect->AddRef();
5851 : }
5852 :
5853 : JSContext *topJSContext;
5854 1933 : nsresult rv = sThreadJSContextStack->Peek(&topJSContext);
5855 1933 : if (NS_SUCCEEDED(rv)) {
5856 1933 : bool push = topJSContext != cx;
5857 1933 : if (push) {
5858 1861 : rv = sThreadJSContextStack->Push(cx);
5859 : }
5860 1933 : if (NS_SUCCEEDED(rv)) {
5861 : rv = sXPConnect->WrapNativeToJSVal(cx, scope, native, cache, aIID,
5862 1933 : aAllowWrapping, vp, aHolder);
5863 1933 : if (push) {
5864 1861 : sThreadJSContextStack->Pop(nsnull);
5865 : }
5866 : }
5867 : }
5868 :
5869 1933 : if (isMainThread) {
5870 1933 : nsLayoutStatics::Release();
5871 : }
5872 : else {
5873 0 : sXPConnect->Release();
5874 : }
5875 :
5876 1933 : return rv;
5877 : }
5878 :
5879 : nsresult
5880 0 : nsContentUtils::CreateArrayBuffer(JSContext *aCx, const nsACString& aData,
5881 : JSObject** aResult)
5882 : {
5883 0 : if (!aCx) {
5884 0 : return NS_ERROR_FAILURE;
5885 : }
5886 :
5887 0 : PRInt32 dataLen = aData.Length();
5888 0 : *aResult = js_CreateArrayBuffer(aCx, dataLen);
5889 0 : if (!*aResult) {
5890 0 : return NS_ERROR_FAILURE;
5891 : }
5892 :
5893 0 : if (dataLen > 0) {
5894 0 : JSObject *abuf = js::ArrayBuffer::getArrayBuffer(*aResult);
5895 0 : NS_ASSERTION(abuf, "What happened?");
5896 0 : memcpy(JS_GetArrayBufferData(abuf), aData.BeginReading(), dataLen);
5897 : }
5898 :
5899 0 : return NS_OK;
5900 : }
5901 :
5902 : void
5903 0 : nsContentUtils::StripNullChars(const nsAString& aInStr, nsAString& aOutStr)
5904 : {
5905 : // In common cases where we don't have nulls in the
5906 : // string we can simple simply bypass the checking code.
5907 0 : PRInt32 firstNullPos = aInStr.FindChar('\0');
5908 0 : if (firstNullPos == kNotFound) {
5909 0 : aOutStr.Assign(aInStr);
5910 0 : return;
5911 : }
5912 :
5913 0 : aOutStr.SetCapacity(aInStr.Length() - 1);
5914 0 : nsAString::const_iterator start, end;
5915 0 : aInStr.BeginReading(start);
5916 0 : aInStr.EndReading(end);
5917 0 : while (start != end) {
5918 0 : if (*start != '\0')
5919 0 : aOutStr.Append(*start);
5920 0 : ++start;
5921 : }
5922 : }
5923 :
5924 0 : struct ClassMatchingInfo {
5925 : nsAttrValue::AtomArray mClasses;
5926 : nsCaseTreatment mCaseTreatment;
5927 : };
5928 :
5929 : static bool
5930 0 : MatchClassNames(nsIContent* aContent, PRInt32 aNamespaceID, nsIAtom* aAtom,
5931 : void* aData)
5932 : {
5933 : // We can't match if there are no class names
5934 0 : const nsAttrValue* classAttr = aContent->GetClasses();
5935 0 : if (!classAttr) {
5936 0 : return false;
5937 : }
5938 :
5939 : // need to match *all* of the classes
5940 0 : ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData);
5941 0 : PRUint32 length = info->mClasses.Length();
5942 0 : if (!length) {
5943 : // If we actually had no classes, don't match.
5944 0 : return false;
5945 : }
5946 : PRUint32 i;
5947 0 : for (i = 0; i < length; ++i) {
5948 0 : if (!classAttr->Contains(info->mClasses[i],
5949 0 : info->mCaseTreatment)) {
5950 0 : return false;
5951 : }
5952 : }
5953 :
5954 0 : return true;
5955 : }
5956 :
5957 : static void
5958 0 : DestroyClassNameArray(void* aData)
5959 : {
5960 0 : ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData);
5961 0 : delete info;
5962 0 : }
5963 :
5964 : static void*
5965 0 : AllocClassMatchingInfo(nsINode* aRootNode,
5966 : const nsString* aClasses)
5967 : {
5968 0 : nsAttrValue attrValue;
5969 0 : attrValue.ParseAtomArray(*aClasses);
5970 : // nsAttrValue::Equals is sensitive to order, so we'll send an array
5971 0 : ClassMatchingInfo* info = new ClassMatchingInfo;
5972 0 : NS_ENSURE_TRUE(info, nsnull);
5973 :
5974 0 : if (attrValue.Type() == nsAttrValue::eAtomArray) {
5975 0 : info->mClasses.SwapElements(*(attrValue.GetAtomArrayValue()));
5976 0 : } else if (attrValue.Type() == nsAttrValue::eAtom) {
5977 0 : info->mClasses.AppendElement(attrValue.GetAtomValue());
5978 : }
5979 :
5980 : info->mCaseTreatment =
5981 0 : aRootNode->OwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks ?
5982 0 : eIgnoreCase : eCaseMatters;
5983 0 : return info;
5984 : }
5985 :
5986 : // static
5987 :
5988 : nsresult
5989 0 : nsContentUtils::GetElementsByClassName(nsINode* aRootNode,
5990 : const nsAString& aClasses,
5991 : nsIDOMNodeList** aReturn)
5992 : {
5993 0 : NS_PRECONDITION(aRootNode, "Must have root node");
5994 :
5995 : nsContentList* elements =
5996 : NS_GetFuncStringContentList(aRootNode, MatchClassNames,
5997 : DestroyClassNameArray,
5998 : AllocClassMatchingInfo,
5999 0 : aClasses).get();
6000 0 : NS_ENSURE_TRUE(elements, NS_ERROR_OUT_OF_MEMORY);
6001 :
6002 : // Transfer ownership
6003 0 : *aReturn = elements;
6004 :
6005 0 : return NS_OK;
6006 : }
6007 :
6008 : #ifdef DEBUG
6009 : class DebugWrapperTraversalCallback : public nsCycleCollectionTraversalCallback
6010 : {
6011 : public:
6012 5 : DebugWrapperTraversalCallback(void* aWrapper) : mFound(false),
6013 5 : mWrapper(aWrapper)
6014 : {
6015 5 : mFlags = WANT_ALL_TRACES;
6016 5 : }
6017 :
6018 5 : NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refCount,
6019 : size_t objSz,
6020 : const char *objName)
6021 : {
6022 5 : }
6023 0 : NS_IMETHOD_(void) DescribeGCedNode(bool isMarked,
6024 : size_t objSz,
6025 : const char *objName)
6026 : {
6027 0 : }
6028 0 : NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root)
6029 : {
6030 0 : }
6031 0 : NS_IMETHOD_(void) NoteRoot(PRUint32 langID, void* root,
6032 : nsCycleCollectionParticipant* helper)
6033 : {
6034 0 : }
6035 12 : NS_IMETHOD_(void) NoteScriptChild(PRUint32 langID, void* child)
6036 : {
6037 12 : if (langID == nsIProgrammingLanguage::JAVASCRIPT &&
6038 : child == mWrapper) {
6039 10 : mFound = true;
6040 : }
6041 12 : }
6042 34 : NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child)
6043 : {
6044 34 : }
6045 4 : NS_IMETHOD_(void) NoteNativeChild(void* child,
6046 : nsCycleCollectionParticipant* helper)
6047 : {
6048 4 : }
6049 :
6050 0 : NS_IMETHOD_(void) NoteNextEdgeName(const char* name)
6051 : {
6052 0 : }
6053 :
6054 0 : NS_IMETHOD_(void) NoteWeakMapping(void* map, void* key, void* val)
6055 : {
6056 0 : }
6057 :
6058 : bool mFound;
6059 :
6060 : private:
6061 : void* mWrapper;
6062 : };
6063 :
6064 : static void
6065 6 : DebugWrapperTraceCallback(PRUint32 langID, void *p, const char *name,
6066 : void *closure)
6067 : {
6068 : DebugWrapperTraversalCallback* callback =
6069 6 : static_cast<DebugWrapperTraversalCallback*>(closure);
6070 6 : callback->NoteScriptChild(langID, p);
6071 6 : }
6072 :
6073 : // static
6074 : void
6075 5 : nsContentUtils::CheckCCWrapperTraversal(nsISupports* aScriptObjectHolder,
6076 : nsWrapperCache* aCache)
6077 : {
6078 5 : JSObject* wrapper = aCache->GetWrapper();
6079 5 : if (!wrapper) {
6080 0 : return;
6081 : }
6082 :
6083 : nsXPCOMCycleCollectionParticipant* participant;
6084 5 : CallQueryInterface(aScriptObjectHolder, &participant);
6085 :
6086 5 : DebugWrapperTraversalCallback callback(wrapper);
6087 :
6088 5 : participant->Traverse(aScriptObjectHolder, callback);
6089 5 : NS_ASSERTION(callback.mFound,
6090 : "Cycle collection participant didn't traverse to preserved "
6091 : "wrapper! This will probably crash.");
6092 :
6093 5 : callback.mFound = false;
6094 5 : participant->Trace(aScriptObjectHolder, DebugWrapperTraceCallback, &callback);
6095 5 : NS_ASSERTION(callback.mFound,
6096 : "Cycle collection participant didn't trace preserved wrapper! "
6097 : "This will probably crash.");
6098 : }
6099 : #endif
6100 :
6101 : // static
6102 : bool
6103 0 : nsContentUtils::IsFocusedContent(const nsIContent* aContent)
6104 : {
6105 0 : nsFocusManager* fm = nsFocusManager::GetFocusManager();
6106 :
6107 0 : return fm && fm->GetFocusedContent() == aContent;
6108 : }
6109 :
6110 : bool
6111 0 : nsContentUtils::IsSubDocumentTabbable(nsIContent* aContent)
6112 : {
6113 0 : nsIDocument* doc = aContent->GetCurrentDoc();
6114 0 : if (!doc) {
6115 0 : return false;
6116 : }
6117 :
6118 : // XXXbz should this use OwnerDoc() for GetSubDocumentFor?
6119 : // sXBL/XBL2 issue!
6120 0 : nsIDocument* subDoc = doc->GetSubDocumentFor(aContent);
6121 0 : if (!subDoc) {
6122 0 : return false;
6123 : }
6124 :
6125 0 : nsCOMPtr<nsISupports> container = subDoc->GetContainer();
6126 0 : nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
6127 0 : if (!docShell) {
6128 0 : return false;
6129 : }
6130 :
6131 0 : nsCOMPtr<nsIContentViewer> contentViewer;
6132 0 : docShell->GetContentViewer(getter_AddRefs(contentViewer));
6133 0 : if (!contentViewer) {
6134 0 : return false;
6135 : }
6136 :
6137 0 : nsCOMPtr<nsIContentViewer> zombieViewer;
6138 0 : contentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
6139 :
6140 : // If there are 2 viewers for the current docshell, that
6141 : // means the current document is a zombie document.
6142 : // Only navigate into the subdocument if it's not a zombie.
6143 0 : return !zombieViewer;
6144 : }
6145 :
6146 : void
6147 0 : nsContentUtils::FlushLayoutForTree(nsIDOMWindow* aWindow)
6148 : {
6149 0 : nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
6150 0 : if (!piWin)
6151 : return;
6152 :
6153 : // Note that because FlushPendingNotifications flushes parents, this
6154 : // is O(N^2) in docshell tree depth. However, the docshell tree is
6155 : // usually pretty shallow.
6156 :
6157 0 : nsCOMPtr<nsIDOMDocument> domDoc;
6158 0 : aWindow->GetDocument(getter_AddRefs(domDoc));
6159 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
6160 0 : if (doc) {
6161 0 : doc->FlushPendingNotifications(Flush_Layout);
6162 : }
6163 :
6164 : nsCOMPtr<nsIDocShellTreeNode> node =
6165 0 : do_QueryInterface(piWin->GetDocShell());
6166 0 : if (node) {
6167 0 : PRInt32 i = 0, i_end;
6168 0 : node->GetChildCount(&i_end);
6169 0 : for (; i < i_end; ++i) {
6170 0 : nsCOMPtr<nsIDocShellTreeItem> item;
6171 0 : node->GetChildAt(i, getter_AddRefs(item));
6172 0 : nsCOMPtr<nsIDOMWindow> win = do_GetInterface(item);
6173 0 : if (win) {
6174 0 : FlushLayoutForTree(win);
6175 : }
6176 : }
6177 : }
6178 : }
6179 :
6180 0 : void nsContentUtils::RemoveNewlines(nsString &aString)
6181 : {
6182 : // strip CR/LF and null
6183 : static const char badChars[] = {'\r', '\n', 0};
6184 0 : aString.StripChars(badChars);
6185 0 : }
6186 :
6187 : void
6188 1 : nsContentUtils::PlatformToDOMLineBreaks(nsString &aString)
6189 : {
6190 1 : if (aString.FindChar(PRUnichar('\r')) != -1) {
6191 : // Windows linebreaks: Map CRLF to LF:
6192 0 : aString.ReplaceSubstring(NS_LITERAL_STRING("\r\n").get(),
6193 0 : NS_LITERAL_STRING("\n").get());
6194 :
6195 : // Mac linebreaks: Map any remaining CR to LF:
6196 0 : aString.ReplaceSubstring(NS_LITERAL_STRING("\r").get(),
6197 0 : NS_LITERAL_STRING("\n").get());
6198 : }
6199 1 : }
6200 :
6201 : nsIWidget *
6202 0 : nsContentUtils::WidgetForDocument(nsIDocument *aDoc)
6203 : {
6204 0 : nsIDocument* doc = aDoc;
6205 0 : nsIDocument* displayDoc = doc->GetDisplayDocument();
6206 0 : if (displayDoc) {
6207 0 : doc = displayDoc;
6208 : }
6209 :
6210 0 : nsIPresShell* shell = doc->GetShell();
6211 0 : nsCOMPtr<nsISupports> container = doc->GetContainer();
6212 0 : nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = do_QueryInterface(container);
6213 0 : while (!shell && docShellTreeItem) {
6214 : // We may be in a display:none subdocument, or we may not have a presshell
6215 : // created yet.
6216 : // Walk the docshell tree to find the nearest container that has a presshell,
6217 : // and find the root widget from that.
6218 0 : nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(docShellTreeItem);
6219 0 : nsCOMPtr<nsIPresShell> presShell;
6220 0 : docShell->GetPresShell(getter_AddRefs(presShell));
6221 0 : if (presShell) {
6222 0 : shell = presShell;
6223 : } else {
6224 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
6225 0 : docShellTreeItem->GetParent(getter_AddRefs(parent));
6226 0 : docShellTreeItem = parent;
6227 : }
6228 : }
6229 :
6230 0 : if (shell) {
6231 0 : nsIViewManager* VM = shell->GetViewManager();
6232 0 : if (VM) {
6233 0 : nsIView* rootView = VM->GetRootView();
6234 0 : if (rootView) {
6235 0 : nsIView* displayRoot = nsIViewManager::GetDisplayRootFor(rootView);
6236 0 : if (displayRoot) {
6237 0 : return displayRoot->GetNearestWidget(nsnull);
6238 : }
6239 : }
6240 : }
6241 : }
6242 :
6243 0 : return nsnull;
6244 : }
6245 :
6246 : static already_AddRefed<LayerManager>
6247 0 : LayerManagerForDocumentInternal(nsIDocument *aDoc, bool aRequirePersistent,
6248 : bool* aAllowRetaining)
6249 : {
6250 0 : nsIWidget *widget = nsContentUtils::WidgetForDocument(aDoc);
6251 0 : if (widget) {
6252 : nsRefPtr<LayerManager> manager =
6253 : widget->GetLayerManager(aRequirePersistent ? nsIWidget::LAYER_MANAGER_PERSISTENT :
6254 : nsIWidget::LAYER_MANAGER_CURRENT,
6255 0 : aAllowRetaining);
6256 0 : return manager.forget();
6257 : }
6258 :
6259 0 : return nsnull;
6260 : }
6261 :
6262 : already_AddRefed<LayerManager>
6263 0 : nsContentUtils::LayerManagerForDocument(nsIDocument *aDoc, bool *aAllowRetaining)
6264 : {
6265 0 : return LayerManagerForDocumentInternal(aDoc, false, aAllowRetaining);
6266 : }
6267 :
6268 : already_AddRefed<LayerManager>
6269 0 : nsContentUtils::PersistentLayerManagerForDocument(nsIDocument *aDoc, bool *aAllowRetaining)
6270 : {
6271 0 : return LayerManagerForDocumentInternal(aDoc, true, aAllowRetaining);
6272 : }
6273 :
6274 : bool
6275 0 : nsContentUtils::AllowXULXBLForPrincipal(nsIPrincipal* aPrincipal)
6276 : {
6277 0 : if (IsSystemPrincipal(aPrincipal)) {
6278 0 : return true;
6279 : }
6280 :
6281 0 : nsCOMPtr<nsIURI> princURI;
6282 0 : aPrincipal->GetURI(getter_AddRefs(princURI));
6283 :
6284 : return princURI &&
6285 0 : ((sAllowXULXBL_for_file && SchemeIs(princURI, "file")) ||
6286 0 : IsSitePermAllow(princURI, "allowXULXBL"));
6287 : }
6288 :
6289 : already_AddRefed<nsIDocumentLoaderFactory>
6290 0 : nsContentUtils::FindInternalContentViewer(const char* aType,
6291 : ContentViewerType* aLoaderType)
6292 : {
6293 0 : if (aLoaderType) {
6294 0 : *aLoaderType = TYPE_UNSUPPORTED;
6295 : }
6296 :
6297 : // one helper factory, please
6298 0 : nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
6299 0 : if (!catMan)
6300 0 : return NULL;
6301 :
6302 0 : nsCOMPtr<nsIDocumentLoaderFactory> docFactory;
6303 :
6304 0 : nsXPIDLCString contractID;
6305 0 : nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", aType, getter_Copies(contractID));
6306 0 : if (NS_SUCCEEDED(rv)) {
6307 0 : docFactory = do_GetService(contractID);
6308 0 : if (docFactory && aLoaderType) {
6309 0 : if (contractID.EqualsLiteral(CONTENT_DLF_CONTRACTID))
6310 0 : *aLoaderType = TYPE_CONTENT;
6311 0 : else if (contractID.EqualsLiteral(PLUGIN_DLF_CONTRACTID))
6312 0 : *aLoaderType = TYPE_PLUGIN;
6313 : else
6314 0 : *aLoaderType = TYPE_UNKNOWN;
6315 : }
6316 0 : return docFactory.forget();
6317 : }
6318 :
6319 : #ifdef MOZ_MEDIA
6320 : #ifdef MOZ_OGG
6321 0 : if (nsHTMLMediaElement::IsOggEnabled()) {
6322 0 : for (unsigned int i = 0; i < ArrayLength(nsHTMLMediaElement::gOggTypes); ++i) {
6323 0 : const char* type = nsHTMLMediaElement::gOggTypes[i];
6324 0 : if (!strcmp(aType, type)) {
6325 0 : docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
6326 0 : if (docFactory && aLoaderType) {
6327 0 : *aLoaderType = TYPE_CONTENT;
6328 : }
6329 0 : return docFactory.forget();
6330 : }
6331 : }
6332 : }
6333 : #endif
6334 :
6335 : #ifdef MOZ_WEBM
6336 0 : if (nsHTMLMediaElement::IsWebMEnabled()) {
6337 0 : for (unsigned int i = 0; i < ArrayLength(nsHTMLMediaElement::gWebMTypes); ++i) {
6338 0 : const char* type = nsHTMLMediaElement::gWebMTypes[i];
6339 0 : if (!strcmp(aType, type)) {
6340 0 : docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
6341 0 : if (docFactory && aLoaderType) {
6342 0 : *aLoaderType = TYPE_CONTENT;
6343 : }
6344 0 : return docFactory.forget();
6345 : }
6346 : }
6347 : }
6348 : #endif
6349 : #endif // MOZ_MEDIA
6350 :
6351 0 : return NULL;
6352 : }
6353 :
6354 : // static
6355 : bool
6356 0 : nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
6357 : nsIDocument* aDocument)
6358 : {
6359 0 : NS_ASSERTION(aDocument, "aDocument should be a valid pointer (not null)");
6360 0 : NS_ENSURE_TRUE(aDocument->GetScriptGlobalObject(), true);
6361 :
6362 0 : JSContext* ctx = (JSContext*) aDocument->GetScriptGlobalObject()->
6363 0 : GetContext()->GetNativeContext();
6364 0 : NS_ENSURE_TRUE(ctx, true);
6365 :
6366 0 : JSAutoRequest ar(ctx);
6367 :
6368 : // The pattern has to match the entire value.
6369 0 : aPattern.Insert(NS_LITERAL_STRING("^(?:"), 0);
6370 0 : aPattern.Append(NS_LITERAL_STRING(")$"));
6371 :
6372 : JSObject* re = JS_NewUCRegExpObjectNoStatics(ctx, reinterpret_cast<jschar*>
6373 0 : (aPattern.BeginWriting()),
6374 0 : aPattern.Length(), 0);
6375 0 : NS_ENSURE_TRUE(re, true);
6376 :
6377 0 : jsval rval = JSVAL_NULL;
6378 0 : size_t idx = 0;
6379 : JSBool res;
6380 :
6381 : res = JS_ExecuteRegExpNoStatics(ctx, re, reinterpret_cast<jschar*>
6382 0 : (aValue.BeginWriting()),
6383 0 : aValue.Length(), &idx, JS_TRUE, &rval);
6384 :
6385 0 : return res == JS_FALSE || rval != JSVAL_NULL;
6386 : }
6387 :
6388 : // static
6389 : nsresult
6390 4 : nsContentUtils::URIInheritsSecurityContext(nsIURI *aURI, bool *aResult)
6391 : {
6392 : // Note: about:blank URIs do NOT inherit the security context from the
6393 : // current document, which is what this function tests for...
6394 : return NS_URIChainHasFlags(aURI,
6395 : nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
6396 4 : aResult);
6397 : }
6398 :
6399 : // static
6400 : bool
6401 4 : nsContentUtils::SetUpChannelOwner(nsIPrincipal* aLoadingPrincipal,
6402 : nsIChannel* aChannel,
6403 : nsIURI* aURI,
6404 : bool aSetUpForAboutBlank)
6405 : {
6406 : //
6407 : // Set the owner of the channel, but only for channels that can't
6408 : // provide their own security context.
6409 : //
6410 : // XXX: It seems wrong that the owner is ignored - even if one is
6411 : // supplied) unless the URI is javascript or data or about:blank.
6412 : // XXX: If this is ever changed, check all callers for what owners
6413 : // they're passing in. In particular, see the code and
6414 : // comments in nsDocShell::LoadURI where we fall back on
6415 : // inheriting the owner if called from chrome. That would be
6416 : // very wrong if this code changed anything but channels that
6417 : // can't provide their own security context!
6418 : //
6419 : // (Currently chrome URIs set the owner when they are created!
6420 : // So setting a NULL owner would be bad!)
6421 : //
6422 : bool inherit;
6423 : // We expect URIInheritsSecurityContext to return success for an
6424 : // about:blank URI, so don't call NS_IsAboutBlank() if this call fails.
6425 : // This condition needs to match the one in nsDocShell::InternalLoad where
6426 : // we're checking for things that will use the owner.
6427 4 : if (NS_SUCCEEDED(URIInheritsSecurityContext(aURI, &inherit)) &&
6428 0 : (inherit || (aSetUpForAboutBlank && NS_IsAboutBlank(aURI)))) {
6429 2 : aChannel->SetOwner(aLoadingPrincipal);
6430 2 : return true;
6431 : }
6432 :
6433 : //
6434 : // file: uri special-casing
6435 : //
6436 : // If this is a file: load opened from another file: then it may need
6437 : // to inherit the owner from the referrer so they can script each other.
6438 : // If we don't set the owner explicitly then each file: gets an owner
6439 : // based on its own codebase later.
6440 : //
6441 2 : if (URIIsLocalFile(aURI) && aLoadingPrincipal &&
6442 0 : NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, false)) &&
6443 : // One more check here. CheckMayLoad will always return true for the
6444 : // system principal, but we do NOT want to inherit in that case.
6445 0 : !IsSystemPrincipal(aLoadingPrincipal)) {
6446 0 : aChannel->SetOwner(aLoadingPrincipal);
6447 0 : return true;
6448 : }
6449 :
6450 2 : return false;
6451 : }
6452 :
6453 : bool
6454 0 : nsContentUtils::IsFullScreenApiEnabled()
6455 : {
6456 0 : return sIsFullScreenApiEnabled;
6457 : }
6458 :
6459 0 : bool nsContentUtils::IsRequestFullScreenAllowed()
6460 : {
6461 0 : return !sTrustedFullScreenOnly ||
6462 0 : nsEventStateManager::IsHandlingUserInput() ||
6463 0 : IsCallerChrome();
6464 : }
6465 :
6466 : bool
6467 0 : nsContentUtils::IsFullScreenKeyInputRestricted()
6468 : {
6469 0 : return sFullScreenKeyInputRestricted;
6470 : }
6471 :
6472 : static void
6473 0 : CheckForWindowedPlugins(nsIContent* aContent, void* aResult)
6474 : {
6475 0 : if (!aContent->IsInDoc()) {
6476 0 : return;
6477 : }
6478 0 : nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent));
6479 0 : if (!olc) {
6480 : return;
6481 : }
6482 0 : nsRefPtr<nsNPAPIPluginInstance> plugin;
6483 0 : olc->GetPluginInstance(getter_AddRefs(plugin));
6484 0 : if (!plugin) {
6485 : return;
6486 : }
6487 0 : bool isWindowless = false;
6488 0 : nsresult res = plugin->IsWindowless(&isWindowless);
6489 0 : if (NS_SUCCEEDED(res) && !isWindowless) {
6490 0 : *static_cast<bool*>(aResult) = true;
6491 : }
6492 : }
6493 :
6494 : static bool
6495 0 : DocTreeContainsWindowedPlugins(nsIDocument* aDoc, void* aResult)
6496 : {
6497 0 : if (!nsContentUtils::IsChromeDoc(aDoc)) {
6498 0 : aDoc->EnumerateFreezableElements(CheckForWindowedPlugins, aResult);
6499 : }
6500 0 : if (*static_cast<bool*>(aResult)) {
6501 : // Return false to stop iteration, we found a windowed plugin.
6502 0 : return false;
6503 : }
6504 0 : aDoc->EnumerateSubDocuments(DocTreeContainsWindowedPlugins, aResult);
6505 : // Return false to stop iteration if we found a windowed plugin in
6506 : // the sub documents.
6507 0 : return !*static_cast<bool*>(aResult);
6508 : }
6509 :
6510 : /* static */
6511 : bool
6512 0 : nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc)
6513 : {
6514 : #ifdef XP_MACOSX
6515 : // We control dispatch to all mac plugins.
6516 : return false;
6517 : #endif
6518 0 : bool result = false;
6519 :
6520 : // Find the top of the document's branch, the child of the chrome document.
6521 0 : nsIDocument* doc = aDoc;
6522 0 : nsIDocument* parent = nsnull;
6523 0 : while (doc && (parent = doc->GetParentDocument()) && !IsChromeDoc(parent)) {
6524 0 : doc = parent;
6525 : }
6526 :
6527 0 : DocTreeContainsWindowedPlugins(doc, &result);
6528 0 : return result;
6529 : }
6530 :
6531 : /* static */
6532 : bool
6533 0 : nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent)
6534 : {
6535 : #ifdef XP_MACOSX
6536 : // We control dispatch to all mac plugins.
6537 : return false;
6538 : #endif
6539 0 : bool result = false;
6540 0 : CheckForWindowedPlugins(aContent, &result);
6541 0 : return result;
6542 : }
6543 :
6544 : /* static */
6545 : nsIDocument*
6546 0 : nsContentUtils::GetRootDocument(nsIDocument* aDoc)
6547 : {
6548 0 : if (!aDoc) {
6549 0 : return nsnull;
6550 : }
6551 0 : nsIDocument* doc = aDoc;
6552 0 : while (doc->GetParentDocument()) {
6553 0 : doc = doc->GetParentDocument();
6554 : }
6555 0 : return doc;
6556 : }
6557 :
6558 : // static
6559 : void
6560 236785 : nsContentUtils::ReleaseWrapper(nsISupports* aScriptObjectHolder,
6561 : nsWrapperCache* aCache)
6562 : {
6563 236785 : if (aCache->PreservingWrapper()) {
6564 3 : DropJSObjects(aScriptObjectHolder);
6565 3 : aCache->SetPreservingWrapper(false);
6566 : }
6567 :
6568 236785 : aCache->ClearWrapperIfProxy();
6569 236785 : }
6570 :
6571 : // static
6572 : void
6573 146657 : nsContentUtils::TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback,
6574 : void *aClosure)
6575 : {
6576 146657 : if (aCache->PreservingWrapper()) {
6577 42 : JSObject *wrapper = aCache->GetWrapperPreserveColor();
6578 42 : if (wrapper) {
6579 : aCallback(nsIProgrammingLanguage::JAVASCRIPT, wrapper,
6580 42 : "Preserved wrapper", aClosure);
6581 : }
6582 : }
6583 : else {
6584 146615 : JSObject *expando = aCache->GetExpandoObjectPreserveColor();
6585 146615 : if (expando) {
6586 : aCallback(nsIProgrammingLanguage::JAVASCRIPT, expando, "Expando object",
6587 0 : aClosure);
6588 : }
6589 : }
6590 146657 : }
|