1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/nsContentUtils.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,6627 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* A namespace class for static layout utilities. */ 1.11 + 1.12 +#include "nsContentUtils.h" 1.13 + 1.14 +#include <algorithm> 1.15 +#include <math.h> 1.16 + 1.17 +#include "prprf.h" 1.18 +#include "nsCxPusher.h" 1.19 +#include "DecoderTraits.h" 1.20 +#include "harfbuzz/hb.h" 1.21 +#include "imgICache.h" 1.22 +#include "imgIContainer.h" 1.23 +#include "imgINotificationObserver.h" 1.24 +#include "imgLoader.h" 1.25 +#include "imgRequestProxy.h" 1.26 +#include "jsapi.h" 1.27 +#include "jsfriendapi.h" 1.28 +#include "js/OldDebugAPI.h" 1.29 +#include "js/Value.h" 1.30 +#include "Layers.h" 1.31 +#include "MediaDecoder.h" 1.32 +// nsNPAPIPluginInstance must be included before nsIDocument.h, which is included in mozAutoDocUpdate.h. 1.33 +#include "nsNPAPIPluginInstance.h" 1.34 +#include "mozAutoDocUpdate.h" 1.35 +#include "mozilla/ArrayUtils.h" 1.36 +#include "mozilla/Attributes.h" 1.37 +#include "mozilla/AutoRestore.h" 1.38 +#include "mozilla/Base64.h" 1.39 +#include "mozilla/DebugOnly.h" 1.40 +#include "mozilla/dom/DocumentFragment.h" 1.41 +#include "mozilla/dom/Element.h" 1.42 +#include "mozilla/dom/HTMLMediaElement.h" 1.43 +#include "mozilla/dom/HTMLTemplateElement.h" 1.44 +#include "mozilla/dom/HTMLContentElement.h" 1.45 +#include "mozilla/dom/TextDecoder.h" 1.46 +#include "mozilla/dom/TouchEvent.h" 1.47 +#include "mozilla/dom/ShadowRoot.h" 1.48 +#include "mozilla/EventDispatcher.h" 1.49 +#include "mozilla/EventListenerManager.h" 1.50 +#include "mozilla/EventStateManager.h" 1.51 +#include "mozilla/IMEStateManager.h" 1.52 +#include "mozilla/InternalMutationEvent.h" 1.53 +#include "mozilla/Likely.h" 1.54 +#include "mozilla/MouseEvents.h" 1.55 +#include "mozilla/Preferences.h" 1.56 +#include "mozilla/dom/Selection.h" 1.57 +#include "mozilla/TextEvents.h" 1.58 +#include "nsAString.h" 1.59 +#include "nsAttrName.h" 1.60 +#include "nsAttrValue.h" 1.61 +#include "nsAttrValueInlines.h" 1.62 +#include "nsBindingManager.h" 1.63 +#include "nsCCUncollectableMarker.h" 1.64 +#include "nsChannelPolicy.h" 1.65 +#include "nsCharSeparatedTokenizer.h" 1.66 +#include "nsCOMPtr.h" 1.67 +#include "nsContentCreatorFunctions.h" 1.68 +#include "nsContentDLF.h" 1.69 +#include "nsContentList.h" 1.70 +#include "nsContentPolicyUtils.h" 1.71 +#include "nsCPrefetchService.h" 1.72 +#include "nsCRT.h" 1.73 +#include "nsCycleCollectionParticipant.h" 1.74 +#include "nsCycleCollector.h" 1.75 +#include "nsDataHashtable.h" 1.76 +#include "nsDocShellCID.h" 1.77 +#include "nsDocument.h" 1.78 +#include "nsDOMCID.h" 1.79 +#include "mozilla/dom/DataTransfer.h" 1.80 +#include "nsDOMJSUtils.h" 1.81 +#include "nsDOMMutationObserver.h" 1.82 +#include "nsError.h" 1.83 +#include "nsFocusManager.h" 1.84 +#include "nsGenericHTMLElement.h" 1.85 +#include "nsGenericHTMLFrameElement.h" 1.86 +#include "nsGkAtoms.h" 1.87 +#include "nsHostObjectProtocolHandler.h" 1.88 +#include "nsHtml5Module.h" 1.89 +#include "nsHtml5StringParser.h" 1.90 +#include "nsIAsyncVerifyRedirectCallback.h" 1.91 +#include "nsICategoryManager.h" 1.92 +#include "nsIChannelEventSink.h" 1.93 +#include "nsIChannelPolicy.h" 1.94 +#include "nsIChromeRegistry.h" 1.95 +#include "nsIConsoleService.h" 1.96 +#include "nsIContent.h" 1.97 +#include "nsIContentSecurityPolicy.h" 1.98 +#include "nsIContentSink.h" 1.99 +#include "nsIContentViewer.h" 1.100 +#include "nsIDocShell.h" 1.101 +#include "nsIDocument.h" 1.102 +#include "nsIDocumentEncoder.h" 1.103 +#include "nsIDOMDocument.h" 1.104 +#include "nsIDOMDocumentType.h" 1.105 +#include "nsIDOMEvent.h" 1.106 +#include "nsIDOMHTMLElement.h" 1.107 +#include "nsIDOMHTMLFormElement.h" 1.108 +#include "nsIDOMHTMLInputElement.h" 1.109 +#include "nsIDOMNode.h" 1.110 +#include "nsIDOMNodeList.h" 1.111 +#include "nsIDOMScriptObjectFactory.h" 1.112 +#include "nsIDOMUserDataHandler.h" 1.113 +#include "nsIDOMXULCommandEvent.h" 1.114 +#include "nsIDragService.h" 1.115 +#include "nsIEditor.h" 1.116 +#include "nsIFormControl.h" 1.117 +#include "nsIForm.h" 1.118 +#include "nsIFragmentContentSink.h" 1.119 +#include "nsIFrame.h" 1.120 +#include "nsIHTMLDocument.h" 1.121 +#include "nsIIdleService.h" 1.122 +#include "nsIImageLoadingContent.h" 1.123 +#include "nsIInterfaceRequestor.h" 1.124 +#include "nsIInterfaceRequestorUtils.h" 1.125 +#include "nsIIOService.h" 1.126 +#include "nsIJSRuntimeService.h" 1.127 +#include "nsILineBreaker.h" 1.128 +#include "nsILoadContext.h" 1.129 +#include "nsILoadGroup.h" 1.130 +#include "nsIMemoryReporter.h" 1.131 +#include "nsIMIMEService.h" 1.132 +#include "nsINode.h" 1.133 +#include "nsINodeInfo.h" 1.134 +#include "nsIObjectLoadingContent.h" 1.135 +#include "nsIObserver.h" 1.136 +#include "nsIObserverService.h" 1.137 +#include "nsIOfflineCacheUpdate.h" 1.138 +#include "nsIParser.h" 1.139 +#include "nsIParserService.h" 1.140 +#include "nsIPermissionManager.h" 1.141 +#include "nsIPluginHost.h" 1.142 +#include "nsIRunnable.h" 1.143 +#include "nsIScriptContext.h" 1.144 +#include "nsIScriptError.h" 1.145 +#include "nsIScriptGlobalObject.h" 1.146 +#include "nsIScriptObjectPrincipal.h" 1.147 +#include "nsIScriptSecurityManager.h" 1.148 +#include "nsIStringBundle.h" 1.149 +#include "nsIURI.h" 1.150 +#include "nsIURL.h" 1.151 +#include "nsIWebNavigation.h" 1.152 +#include "nsIWordBreaker.h" 1.153 +#include "nsIXPConnect.h" 1.154 +#include "nsJSUtils.h" 1.155 +#include "nsLWBrkCIID.h" 1.156 +#include "nsNetCID.h" 1.157 +#include "nsNetUtil.h" 1.158 +#include "nsNodeInfoManager.h" 1.159 +#include "nsNullPrincipal.h" 1.160 +#include "nsParserCIID.h" 1.161 +#include "nsParserConstants.h" 1.162 +#include "nsPIDOMWindow.h" 1.163 +#include "nsPresContext.h" 1.164 +#include "nsPrintfCString.h" 1.165 +#include "nsReferencedElement.h" 1.166 +#include "nsSandboxFlags.h" 1.167 +#include "nsScriptSecurityManager.h" 1.168 +#include "nsSVGFeatures.h" 1.169 +#include "nsTextEditorState.h" 1.170 +#include "nsTextFragment.h" 1.171 +#include "nsTextNode.h" 1.172 +#include "nsThreadUtils.h" 1.173 +#include "nsUnicharUtilCIID.h" 1.174 +#include "nsUnicodeProperties.h" 1.175 +#include "nsViewManager.h" 1.176 +#include "nsViewportInfo.h" 1.177 +#include "nsWrapperCacheInlines.h" 1.178 +#include "nsXULPopupManager.h" 1.179 +#include "xpcprivate.h" // nsXPConnect 1.180 +#include "HTMLSplitOnSpacesTokenizer.h" 1.181 +#include "nsContentTypeParser.h" 1.182 +#include "mozIThirdPartyUtil.h" 1.183 + 1.184 +#include "nsIBidiKeyboard.h" 1.185 + 1.186 +extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end, 1.187 + const char** next, char16_t* result); 1.188 +extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end, 1.189 + int ns_aware, const char** colon); 1.190 + 1.191 +class imgLoader; 1.192 + 1.193 +using namespace mozilla::dom; 1.194 +using namespace mozilla::layers; 1.195 +using namespace mozilla::widget; 1.196 +using namespace mozilla; 1.197 + 1.198 +const char kLoadAsData[] = "loadAsData"; 1.199 + 1.200 +nsIXPConnect *nsContentUtils::sXPConnect; 1.201 +nsIScriptSecurityManager *nsContentUtils::sSecurityManager; 1.202 +nsIParserService *nsContentUtils::sParserService = nullptr; 1.203 +nsNameSpaceManager *nsContentUtils::sNameSpaceManager; 1.204 +nsIIOService *nsContentUtils::sIOService; 1.205 +nsIConsoleService *nsContentUtils::sConsoleService; 1.206 +nsDataHashtable<nsISupportsHashKey, EventNameMapping>* nsContentUtils::sAtomEventTable = nullptr; 1.207 +nsDataHashtable<nsStringHashKey, EventNameMapping>* nsContentUtils::sStringEventTable = nullptr; 1.208 +nsCOMArray<nsIAtom>* nsContentUtils::sUserDefinedEvents = nullptr; 1.209 +nsIStringBundleService *nsContentUtils::sStringBundleService; 1.210 +nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT]; 1.211 +nsIContentPolicy *nsContentUtils::sContentPolicyService; 1.212 +bool nsContentUtils::sTriedToGetContentPolicy = false; 1.213 +nsILineBreaker *nsContentUtils::sLineBreaker; 1.214 +nsIWordBreaker *nsContentUtils::sWordBreaker; 1.215 +nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nullptr; 1.216 +uint32_t nsContentUtils::sScriptBlockerCount = 0; 1.217 +#ifdef DEBUG 1.218 +uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0; 1.219 +#endif 1.220 +uint32_t nsContentUtils::sMicroTaskLevel = 0; 1.221 +nsTArray< nsCOMPtr<nsIRunnable> >* nsContentUtils::sBlockedScriptRunners = nullptr; 1.222 +uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0; 1.223 +nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr; 1.224 + 1.225 +bool nsContentUtils::sIsHandlingKeyBoardEvent = false; 1.226 +bool nsContentUtils::sAllowXULXBL_for_file = false; 1.227 + 1.228 +nsString* nsContentUtils::sShiftText = nullptr; 1.229 +nsString* nsContentUtils::sControlText = nullptr; 1.230 +nsString* nsContentUtils::sMetaText = nullptr; 1.231 +nsString* nsContentUtils::sOSText = nullptr; 1.232 +nsString* nsContentUtils::sAltText = nullptr; 1.233 +nsString* nsContentUtils::sModifierSeparator = nullptr; 1.234 + 1.235 +bool nsContentUtils::sInitialized = false; 1.236 +bool nsContentUtils::sIsFullScreenApiEnabled = false; 1.237 +bool nsContentUtils::sTrustedFullScreenOnly = true; 1.238 +bool nsContentUtils::sFullscreenApiIsContentOnly = false; 1.239 +bool nsContentUtils::sIsIdleObserverAPIEnabled = false; 1.240 +bool nsContentUtils::sIsPerformanceTimingEnabled = false; 1.241 +bool nsContentUtils::sIsResourceTimingEnabled = false; 1.242 + 1.243 +uint32_t nsContentUtils::sHandlingInputTimeout = 1000; 1.244 + 1.245 +nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr; 1.246 +nsIParser* nsContentUtils::sXMLFragmentParser = nullptr; 1.247 +nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr; 1.248 +bool nsContentUtils::sFragmentParsingActive = false; 1.249 + 1.250 +#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP)) 1.251 +bool nsContentUtils::sDOMWindowDumpEnabled; 1.252 +#endif 1.253 + 1.254 +namespace { 1.255 + 1.256 +static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID); 1.257 +static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); 1.258 + 1.259 +static PLDHashTable sEventListenerManagersHash; 1.260 + 1.261 +class DOMEventListenerManagersHashReporter MOZ_FINAL : public nsIMemoryReporter 1.262 +{ 1.263 + MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) 1.264 + 1.265 +public: 1.266 + NS_DECL_ISUPPORTS 1.267 + 1.268 + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, 1.269 + nsISupports* aData) 1.270 + { 1.271 + // We don't measure the |EventListenerManager| objects pointed to by the 1.272 + // entries because those references are non-owning. 1.273 + int64_t amount = sEventListenerManagersHash.ops 1.274 + ? PL_DHashTableSizeOfExcludingThis( 1.275 + &sEventListenerManagersHash, nullptr, MallocSizeOf) 1.276 + : 0; 1.277 + 1.278 + return MOZ_COLLECT_REPORT( 1.279 + "explicit/dom/event-listener-managers-hash", KIND_HEAP, UNITS_BYTES, 1.280 + amount, 1.281 + "Memory used by the event listener manager's hash table."); 1.282 + } 1.283 +}; 1.284 + 1.285 +NS_IMPL_ISUPPORTS(DOMEventListenerManagersHashReporter, nsIMemoryReporter) 1.286 + 1.287 +class EventListenerManagerMapEntry : public PLDHashEntryHdr 1.288 +{ 1.289 +public: 1.290 + EventListenerManagerMapEntry(const void *aKey) 1.291 + : mKey(aKey) 1.292 + { 1.293 + } 1.294 + 1.295 + ~EventListenerManagerMapEntry() 1.296 + { 1.297 + NS_ASSERTION(!mListenerManager, "caller must release and disconnect ELM"); 1.298 + } 1.299 + 1.300 +protected: // declared protected to silence clang warnings 1.301 + const void *mKey; // must be first, to look like PLDHashEntryStub 1.302 + 1.303 +public: 1.304 + nsRefPtr<EventListenerManager> mListenerManager; 1.305 +}; 1.306 + 1.307 +static bool 1.308 +EventListenerManagerHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, 1.309 + const void *key) 1.310 +{ 1.311 + // Initialize the entry with placement new 1.312 + new (entry) EventListenerManagerMapEntry(key); 1.313 + return true; 1.314 +} 1.315 + 1.316 +static void 1.317 +EventListenerManagerHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) 1.318 +{ 1.319 + EventListenerManagerMapEntry *lm = 1.320 + static_cast<EventListenerManagerMapEntry *>(entry); 1.321 + 1.322 + // Let the EventListenerManagerMapEntry clean itself up... 1.323 + lm->~EventListenerManagerMapEntry(); 1.324 +} 1.325 + 1.326 +class SameOriginChecker MOZ_FINAL : public nsIChannelEventSink, 1.327 + public nsIInterfaceRequestor 1.328 +{ 1.329 + NS_DECL_ISUPPORTS 1.330 + NS_DECL_NSICHANNELEVENTSINK 1.331 + NS_DECL_NSIINTERFACEREQUESTOR 1.332 +}; 1.333 + 1.334 +class CharsetDetectionObserver MOZ_FINAL : public nsICharsetDetectionObserver 1.335 +{ 1.336 +public: 1.337 + NS_DECL_ISUPPORTS 1.338 + 1.339 + NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf) 1.340 + { 1.341 + mCharset = aCharset; 1.342 + return NS_OK; 1.343 + } 1.344 + 1.345 + const nsACString& GetResult() const 1.346 + { 1.347 + return mCharset; 1.348 + } 1.349 + 1.350 +private: 1.351 + nsCString mCharset; 1.352 +}; 1.353 + 1.354 +} // anonymous namespace 1.355 + 1.356 +/* static */ 1.357 +TimeDuration 1.358 +nsContentUtils::HandlingUserInputTimeout() 1.359 +{ 1.360 + return TimeDuration::FromMilliseconds(sHandlingInputTimeout); 1.361 +} 1.362 + 1.363 +// static 1.364 +nsresult 1.365 +nsContentUtils::Init() 1.366 +{ 1.367 + if (sInitialized) { 1.368 + NS_WARNING("Init() called twice"); 1.369 + 1.370 + return NS_OK; 1.371 + } 1.372 + 1.373 + sNameSpaceManager = nsNameSpaceManager::GetInstance(); 1.374 + NS_ENSURE_TRUE(sNameSpaceManager, NS_ERROR_OUT_OF_MEMORY); 1.375 + 1.376 + sXPConnect = nsXPConnect::XPConnect(); 1.377 + 1.378 + sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager(); 1.379 + if(!sSecurityManager) 1.380 + return NS_ERROR_FAILURE; 1.381 + NS_ADDREF(sSecurityManager); 1.382 + 1.383 + // Getting the first context can trigger GC, so do this non-lazily. 1.384 + sXPConnect->InitSafeJSContext(); 1.385 + 1.386 + nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService); 1.387 + if (NS_FAILED(rv)) { 1.388 + // This makes life easier, but we can live without it. 1.389 + 1.390 + sIOService = nullptr; 1.391 + } 1.392 + 1.393 + rv = CallGetService(NS_LBRK_CONTRACTID, &sLineBreaker); 1.394 + NS_ENSURE_SUCCESS(rv, rv); 1.395 + 1.396 + rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker); 1.397 + NS_ENSURE_SUCCESS(rv, rv); 1.398 + 1.399 + if (!InitializeEventTable()) 1.400 + return NS_ERROR_FAILURE; 1.401 + 1.402 + if (!sEventListenerManagersHash.ops) { 1.403 + static const PLDHashTableOps hash_table_ops = 1.404 + { 1.405 + PL_DHashAllocTable, 1.406 + PL_DHashFreeTable, 1.407 + PL_DHashVoidPtrKeyStub, 1.408 + PL_DHashMatchEntryStub, 1.409 + PL_DHashMoveEntryStub, 1.410 + EventListenerManagerHashClearEntry, 1.411 + PL_DHashFinalizeStub, 1.412 + EventListenerManagerHashInitEntry 1.413 + }; 1.414 + 1.415 + PL_DHashTableInit(&sEventListenerManagersHash, &hash_table_ops, 1.416 + nullptr, sizeof(EventListenerManagerMapEntry), 16); 1.417 + 1.418 + RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter()); 1.419 + } 1.420 + 1.421 + sBlockedScriptRunners = new nsTArray< nsCOMPtr<nsIRunnable> >; 1.422 + 1.423 + Preferences::AddBoolVarCache(&sAllowXULXBL_for_file, 1.424 + "dom.allow_XUL_XBL_for_file"); 1.425 + 1.426 + Preferences::AddBoolVarCache(&sIsFullScreenApiEnabled, 1.427 + "full-screen-api.enabled"); 1.428 + 1.429 + // Note: We deliberately read this pref here because this code runs 1.430 + // before the profile loads, so users' changes to this pref in about:config 1.431 + // won't have any effect on behaviour. We don't really want users messing 1.432 + // with this pref, as it affects the security model of the fullscreen API. 1.433 + sFullscreenApiIsContentOnly = Preferences::GetBool("full-screen-api.content-only", false); 1.434 + 1.435 + Preferences::AddBoolVarCache(&sTrustedFullScreenOnly, 1.436 + "full-screen-api.allow-trusted-requests-only"); 1.437 + 1.438 + sIsIdleObserverAPIEnabled = Preferences::GetBool("dom.idle-observers-api.enabled", true); 1.439 + 1.440 + Preferences::AddBoolVarCache(&sIsPerformanceTimingEnabled, 1.441 + "dom.enable_performance", true); 1.442 + 1.443 + Preferences::AddBoolVarCache(&sIsResourceTimingEnabled, 1.444 + "dom.enable_resource_timing", true); 1.445 + 1.446 + Preferences::AddUintVarCache(&sHandlingInputTimeout, 1.447 + "dom.event.handling-user-input-time-limit", 1.448 + 1000); 1.449 + 1.450 +#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP)) 1.451 + Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled, 1.452 + "browser.dom.window.dump.enabled"); 1.453 +#endif 1.454 + 1.455 + Element::InitCCCallbacks(); 1.456 + 1.457 + sInitialized = true; 1.458 + 1.459 + return NS_OK; 1.460 +} 1.461 + 1.462 +void 1.463 +nsContentUtils::GetShiftText(nsAString& text) 1.464 +{ 1.465 + if (!sShiftText) 1.466 + InitializeModifierStrings(); 1.467 + text.Assign(*sShiftText); 1.468 +} 1.469 + 1.470 +void 1.471 +nsContentUtils::GetControlText(nsAString& text) 1.472 +{ 1.473 + if (!sControlText) 1.474 + InitializeModifierStrings(); 1.475 + text.Assign(*sControlText); 1.476 +} 1.477 + 1.478 +void 1.479 +nsContentUtils::GetMetaText(nsAString& text) 1.480 +{ 1.481 + if (!sMetaText) 1.482 + InitializeModifierStrings(); 1.483 + text.Assign(*sMetaText); 1.484 +} 1.485 + 1.486 +void 1.487 +nsContentUtils::GetOSText(nsAString& text) 1.488 +{ 1.489 + if (!sOSText) { 1.490 + InitializeModifierStrings(); 1.491 + } 1.492 + text.Assign(*sOSText); 1.493 +} 1.494 + 1.495 +void 1.496 +nsContentUtils::GetAltText(nsAString& text) 1.497 +{ 1.498 + if (!sAltText) 1.499 + InitializeModifierStrings(); 1.500 + text.Assign(*sAltText); 1.501 +} 1.502 + 1.503 +void 1.504 +nsContentUtils::GetModifierSeparatorText(nsAString& text) 1.505 +{ 1.506 + if (!sModifierSeparator) 1.507 + InitializeModifierStrings(); 1.508 + text.Assign(*sModifierSeparator); 1.509 +} 1.510 + 1.511 +void 1.512 +nsContentUtils::InitializeModifierStrings() 1.513 +{ 1.514 + //load the display strings for the keyboard accelerators 1.515 + nsCOMPtr<nsIStringBundleService> bundleService = 1.516 + mozilla::services::GetStringBundleService(); 1.517 + nsCOMPtr<nsIStringBundle> bundle; 1.518 + DebugOnly<nsresult> rv = NS_OK; 1.519 + if (bundleService) { 1.520 + rv = bundleService->CreateBundle( "chrome://global-platform/locale/platformKeys.properties", 1.521 + getter_AddRefs(bundle)); 1.522 + } 1.523 + 1.524 + NS_ASSERTION(NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/platformKeys.properties could not be loaded"); 1.525 + nsXPIDLString shiftModifier; 1.526 + nsXPIDLString metaModifier; 1.527 + nsXPIDLString osModifier; 1.528 + nsXPIDLString altModifier; 1.529 + nsXPIDLString controlModifier; 1.530 + nsXPIDLString modifierSeparator; 1.531 + if (bundle) { 1.532 + //macs use symbols for each modifier key, so fetch each from the bundle, which also covers i18n 1.533 + bundle->GetStringFromName(MOZ_UTF16("VK_SHIFT"), getter_Copies(shiftModifier)); 1.534 + bundle->GetStringFromName(MOZ_UTF16("VK_META"), getter_Copies(metaModifier)); 1.535 + bundle->GetStringFromName(MOZ_UTF16("VK_WIN"), getter_Copies(osModifier)); 1.536 + bundle->GetStringFromName(MOZ_UTF16("VK_ALT"), getter_Copies(altModifier)); 1.537 + bundle->GetStringFromName(MOZ_UTF16("VK_CONTROL"), getter_Copies(controlModifier)); 1.538 + bundle->GetStringFromName(MOZ_UTF16("MODIFIER_SEPARATOR"), getter_Copies(modifierSeparator)); 1.539 + } 1.540 + //if any of these don't exist, we get an empty string 1.541 + sShiftText = new nsString(shiftModifier); 1.542 + sMetaText = new nsString(metaModifier); 1.543 + sOSText = new nsString(osModifier); 1.544 + sAltText = new nsString(altModifier); 1.545 + sControlText = new nsString(controlModifier); 1.546 + sModifierSeparator = new nsString(modifierSeparator); 1.547 +} 1.548 + 1.549 +bool 1.550 +nsContentUtils::InitializeEventTable() { 1.551 + NS_ASSERTION(!sAtomEventTable, "EventTable already initialized!"); 1.552 + NS_ASSERTION(!sStringEventTable, "EventTable already initialized!"); 1.553 + 1.554 + static const EventNameMapping eventArray[] = { 1.555 +#define EVENT(name_, _id, _type, _struct) \ 1.556 + { nsGkAtoms::on##name_, _id, _type, _struct }, 1.557 +#define WINDOW_ONLY_EVENT EVENT 1.558 +#define NON_IDL_EVENT EVENT 1.559 +#include "mozilla/EventNameList.h" 1.560 +#undef WINDOW_ONLY_EVENT 1.561 +#undef EVENT 1.562 + { nullptr } 1.563 + }; 1.564 + 1.565 + sAtomEventTable = new nsDataHashtable<nsISupportsHashKey, EventNameMapping>( 1.566 + int(ArrayLength(eventArray) / 0.75) + 1); 1.567 + sStringEventTable = new nsDataHashtable<nsStringHashKey, EventNameMapping>( 1.568 + int(ArrayLength(eventArray) / 0.75) + 1); 1.569 + sUserDefinedEvents = new nsCOMArray<nsIAtom>(64); 1.570 + 1.571 + // Subtract one from the length because of the trailing null 1.572 + for (uint32_t i = 0; i < ArrayLength(eventArray) - 1; ++i) { 1.573 + sAtomEventTable->Put(eventArray[i].mAtom, eventArray[i]); 1.574 + sStringEventTable->Put(Substring(nsDependentAtomString(eventArray[i].mAtom), 2), 1.575 + eventArray[i]); 1.576 + } 1.577 + 1.578 + return true; 1.579 +} 1.580 + 1.581 +void 1.582 +nsContentUtils::InitializeTouchEventTable() 1.583 +{ 1.584 + static bool sEventTableInitialized = false; 1.585 + if (!sEventTableInitialized && sAtomEventTable && sStringEventTable) { 1.586 + sEventTableInitialized = true; 1.587 + static const EventNameMapping touchEventArray[] = { 1.588 +#define EVENT(name_, _id, _type, _struct) 1.589 +#define TOUCH_EVENT(name_, _id, _type, _struct) \ 1.590 + { nsGkAtoms::on##name_, _id, _type, _struct }, 1.591 +#include "mozilla/EventNameList.h" 1.592 +#undef TOUCH_EVENT 1.593 +#undef EVENT 1.594 + { nullptr } 1.595 + }; 1.596 + // Subtract one from the length because of the trailing null 1.597 + for (uint32_t i = 0; i < ArrayLength(touchEventArray) - 1; ++i) { 1.598 + sAtomEventTable->Put(touchEventArray[i].mAtom, touchEventArray[i]); 1.599 + sStringEventTable->Put(Substring(nsDependentAtomString(touchEventArray[i].mAtom), 2), 1.600 + touchEventArray[i]); 1.601 + } 1.602 + } 1.603 +} 1.604 + 1.605 +static bool 1.606 +Is8bit(const nsAString& aString) 1.607 +{ 1.608 + static const char16_t EIGHT_BIT = char16_t(~0x00FF); 1.609 + 1.610 + nsAString::const_iterator done_reading; 1.611 + aString.EndReading(done_reading); 1.612 + 1.613 + // for each chunk of |aString|... 1.614 + uint32_t fragmentLength = 0; 1.615 + nsAString::const_iterator iter; 1.616 + for (aString.BeginReading(iter); iter != done_reading; 1.617 + iter.advance(int32_t(fragmentLength))) { 1.618 + fragmentLength = uint32_t(iter.size_forward()); 1.619 + const char16_t* c = iter.get(); 1.620 + const char16_t* fragmentEnd = c + fragmentLength; 1.621 + 1.622 + // for each character in this chunk... 1.623 + while (c < fragmentEnd) { 1.624 + if (*c++ & EIGHT_BIT) { 1.625 + return false; 1.626 + } 1.627 + } 1.628 + } 1.629 + 1.630 + return true; 1.631 +} 1.632 + 1.633 +nsresult 1.634 +nsContentUtils::Btoa(const nsAString& aBinaryData, 1.635 + nsAString& aAsciiBase64String) 1.636 +{ 1.637 + if (!Is8bit(aBinaryData)) { 1.638 + aAsciiBase64String.Truncate(); 1.639 + return NS_ERROR_DOM_INVALID_CHARACTER_ERR; 1.640 + } 1.641 + 1.642 + return Base64Encode(aBinaryData, aAsciiBase64String); 1.643 +} 1.644 + 1.645 +nsresult 1.646 +nsContentUtils::Atob(const nsAString& aAsciiBase64String, 1.647 + nsAString& aBinaryData) 1.648 +{ 1.649 + if (!Is8bit(aAsciiBase64String)) { 1.650 + aBinaryData.Truncate(); 1.651 + return NS_ERROR_DOM_INVALID_CHARACTER_ERR; 1.652 + } 1.653 + 1.654 + const char16_t* start = aAsciiBase64String.BeginReading(); 1.655 + const char16_t* end = aAsciiBase64String.EndReading(); 1.656 + nsString trimmedString; 1.657 + if (!trimmedString.SetCapacity(aAsciiBase64String.Length(), fallible_t())) { 1.658 + return NS_ERROR_DOM_INVALID_CHARACTER_ERR; 1.659 + } 1.660 + while (start < end) { 1.661 + if (!nsContentUtils::IsHTMLWhitespace(*start)) { 1.662 + trimmedString.Append(*start); 1.663 + } 1.664 + start++; 1.665 + } 1.666 + nsresult rv = Base64Decode(trimmedString, aBinaryData); 1.667 + if (NS_FAILED(rv) && rv == NS_ERROR_INVALID_ARG) { 1.668 + return NS_ERROR_DOM_INVALID_CHARACTER_ERR; 1.669 + } 1.670 + return rv; 1.671 +} 1.672 + 1.673 +bool 1.674 +nsContentUtils::IsAutocompleteEnabled(nsIDOMHTMLInputElement* aInput) 1.675 +{ 1.676 + NS_PRECONDITION(aInput, "aInput should not be null!"); 1.677 + 1.678 + nsAutoString autocomplete; 1.679 + aInput->GetAutocomplete(autocomplete); 1.680 + 1.681 + if (autocomplete.IsEmpty()) { 1.682 + nsCOMPtr<nsIDOMHTMLFormElement> form; 1.683 + aInput->GetForm(getter_AddRefs(form)); 1.684 + if (!form) { 1.685 + return true; 1.686 + } 1.687 + 1.688 + form->GetAutocomplete(autocomplete); 1.689 + } 1.690 + 1.691 + return autocomplete.EqualsLiteral("on"); 1.692 +} 1.693 + 1.694 +#define SKIP_WHITESPACE(iter, end_iter, end_res) \ 1.695 + while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \ 1.696 + ++(iter); \ 1.697 + } \ 1.698 + if ((iter) == (end_iter)) { \ 1.699 + return (end_res); \ 1.700 + } 1.701 + 1.702 +#define SKIP_ATTR_NAME(iter, end_iter) \ 1.703 + while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \ 1.704 + *(iter) != '=') { \ 1.705 + ++(iter); \ 1.706 + } 1.707 + 1.708 +bool 1.709 +nsContentUtils::GetPseudoAttributeValue(const nsString& aSource, nsIAtom *aName, 1.710 + nsAString& aValue) 1.711 +{ 1.712 + aValue.Truncate(); 1.713 + 1.714 + const char16_t *start = aSource.get(); 1.715 + const char16_t *end = start + aSource.Length(); 1.716 + const char16_t *iter; 1.717 + 1.718 + while (start != end) { 1.719 + SKIP_WHITESPACE(start, end, false) 1.720 + iter = start; 1.721 + SKIP_ATTR_NAME(iter, end) 1.722 + 1.723 + if (start == iter) { 1.724 + return false; 1.725 + } 1.726 + 1.727 + // Remember the attr name. 1.728 + const nsDependentSubstring & attrName = Substring(start, iter); 1.729 + 1.730 + // Now check whether this is a valid name="value" pair. 1.731 + start = iter; 1.732 + SKIP_WHITESPACE(start, end, false) 1.733 + if (*start != '=') { 1.734 + // No '=', so this is not a name="value" pair. We don't know 1.735 + // what it is, and we have no way to handle it. 1.736 + return false; 1.737 + } 1.738 + 1.739 + // Have to skip the value. 1.740 + ++start; 1.741 + SKIP_WHITESPACE(start, end, false) 1.742 + char16_t q = *start; 1.743 + if (q != kQuote && q != kApostrophe) { 1.744 + // Not a valid quoted value, so bail. 1.745 + return false; 1.746 + } 1.747 + 1.748 + ++start; // Point to the first char of the value. 1.749 + iter = start; 1.750 + 1.751 + while (iter != end && *iter != q) { 1.752 + ++iter; 1.753 + } 1.754 + 1.755 + if (iter == end) { 1.756 + // Oops, unterminated quoted string. 1.757 + return false; 1.758 + } 1.759 + 1.760 + // At this point attrName holds the name of the "attribute" and 1.761 + // the value is between start and iter. 1.762 + 1.763 + if (aName->Equals(attrName)) { 1.764 + // We'll accumulate as many characters as possible (until we hit either 1.765 + // the end of the string or the beginning of an entity). Chunks will be 1.766 + // delimited by start and chunkEnd. 1.767 + const char16_t *chunkEnd = start; 1.768 + while (chunkEnd != iter) { 1.769 + if (*chunkEnd == kLessThan) { 1.770 + aValue.Truncate(); 1.771 + 1.772 + return false; 1.773 + } 1.774 + 1.775 + if (*chunkEnd == kAmpersand) { 1.776 + aValue.Append(start, chunkEnd - start); 1.777 + 1.778 + // Point to first character after the ampersand. 1.779 + ++chunkEnd; 1.780 + 1.781 + const char16_t *afterEntity = nullptr; 1.782 + char16_t result[2]; 1.783 + uint32_t count = 1.784 + MOZ_XMLTranslateEntity(reinterpret_cast<const char*>(chunkEnd), 1.785 + reinterpret_cast<const char*>(iter), 1.786 + reinterpret_cast<const char**>(&afterEntity), 1.787 + result); 1.788 + if (count == 0) { 1.789 + aValue.Truncate(); 1.790 + 1.791 + return false; 1.792 + } 1.793 + 1.794 + aValue.Append(result, count); 1.795 + 1.796 + // Advance to after the entity and begin a new chunk. 1.797 + start = chunkEnd = afterEntity; 1.798 + } 1.799 + else { 1.800 + ++chunkEnd; 1.801 + } 1.802 + } 1.803 + 1.804 + // Append remainder. 1.805 + aValue.Append(start, iter - start); 1.806 + 1.807 + return true; 1.808 + } 1.809 + 1.810 + // Resume scanning after the end of the attribute value (past the quote 1.811 + // char). 1.812 + start = iter + 1; 1.813 + } 1.814 + 1.815 + return false; 1.816 +} 1.817 + 1.818 +bool 1.819 +nsContentUtils::IsJavaScriptLanguage(const nsString& aName) 1.820 +{ 1.821 + return aName.LowerCaseEqualsLiteral("javascript") || 1.822 + aName.LowerCaseEqualsLiteral("livescript") || 1.823 + aName.LowerCaseEqualsLiteral("mocha") || 1.824 + aName.LowerCaseEqualsLiteral("javascript1.0") || 1.825 + aName.LowerCaseEqualsLiteral("javascript1.1") || 1.826 + aName.LowerCaseEqualsLiteral("javascript1.2") || 1.827 + aName.LowerCaseEqualsLiteral("javascript1.3") || 1.828 + aName.LowerCaseEqualsLiteral("javascript1.4") || 1.829 + aName.LowerCaseEqualsLiteral("javascript1.5"); 1.830 +} 1.831 + 1.832 +JSVersion 1.833 +nsContentUtils::ParseJavascriptVersion(const nsAString& aVersionStr) 1.834 +{ 1.835 + if (aVersionStr.Length() != 3 || aVersionStr[0] != '1' || 1.836 + aVersionStr[1] != '.') { 1.837 + return JSVERSION_UNKNOWN; 1.838 + } 1.839 + 1.840 + switch (aVersionStr[2]) { 1.841 + case '0': /* fall through */ 1.842 + case '1': /* fall through */ 1.843 + case '2': /* fall through */ 1.844 + case '3': /* fall through */ 1.845 + case '4': /* fall through */ 1.846 + case '5': return JSVERSION_DEFAULT; 1.847 + case '6': return JSVERSION_1_6; 1.848 + case '7': return JSVERSION_1_7; 1.849 + case '8': return JSVERSION_1_8; 1.850 + default: return JSVERSION_UNKNOWN; 1.851 + } 1.852 +} 1.853 + 1.854 +void 1.855 +nsContentUtils::SplitMimeType(const nsAString& aValue, nsString& aType, 1.856 + nsString& aParams) 1.857 +{ 1.858 + aType.Truncate(); 1.859 + aParams.Truncate(); 1.860 + int32_t semiIndex = aValue.FindChar(char16_t(';')); 1.861 + if (-1 != semiIndex) { 1.862 + aType = Substring(aValue, 0, semiIndex); 1.863 + aParams = Substring(aValue, semiIndex + 1, 1.864 + aValue.Length() - (semiIndex + 1)); 1.865 + aParams.StripWhitespace(); 1.866 + } 1.867 + else { 1.868 + aType = aValue; 1.869 + } 1.870 + aType.StripWhitespace(); 1.871 +} 1.872 + 1.873 +nsresult 1.874 +nsContentUtils::IsUserIdle(uint32_t aRequestedIdleTimeInMS, bool* aUserIsIdle) 1.875 +{ 1.876 + nsresult rv; 1.877 + nsCOMPtr<nsIIdleService> idleService = 1.878 + do_GetService("@mozilla.org/widget/idleservice;1", &rv); 1.879 + NS_ENSURE_SUCCESS(rv, rv); 1.880 + 1.881 + uint32_t idleTimeInMS; 1.882 + rv = idleService->GetIdleTime(&idleTimeInMS); 1.883 + NS_ENSURE_SUCCESS(rv, rv); 1.884 + 1.885 + *aUserIsIdle = idleTimeInMS >= aRequestedIdleTimeInMS; 1.886 + return NS_OK; 1.887 +} 1.888 + 1.889 +/** 1.890 + * Access a cached parser service. Don't addref. We need only one 1.891 + * reference to it and this class has that one. 1.892 + */ 1.893 +/* static */ 1.894 +nsIParserService* 1.895 +nsContentUtils::GetParserService() 1.896 +{ 1.897 + // XXX: This isn't accessed from several threads, is it? 1.898 + if (!sParserService) { 1.899 + // Lock, recheck sCachedParserService and aquire if this should be 1.900 + // safe for multiple threads. 1.901 + nsresult rv = CallGetService(kParserServiceCID, &sParserService); 1.902 + if (NS_FAILED(rv)) { 1.903 + sParserService = nullptr; 1.904 + } 1.905 + } 1.906 + 1.907 + return sParserService; 1.908 +} 1.909 + 1.910 +/** 1.911 + * A helper function that parses a sandbox attribute (of an <iframe> or 1.912 + * a CSP directive) and converts it to the set of flags used internally. 1.913 + * 1.914 + * @param sandboxAttr the sandbox attribute 1.915 + * @return the set of flags (0 if sandboxAttr is null) 1.916 + */ 1.917 +uint32_t 1.918 +nsContentUtils::ParseSandboxAttributeToFlags(const nsAttrValue* sandboxAttr) 1.919 +{ 1.920 + // No sandbox attribute, no sandbox flags. 1.921 + if (!sandboxAttr) { return 0; } 1.922 + 1.923 + // Start off by setting all the restriction flags. 1.924 + uint32_t out = SANDBOXED_NAVIGATION 1.925 + | SANDBOXED_AUXILIARY_NAVIGATION 1.926 + | SANDBOXED_TOPLEVEL_NAVIGATION 1.927 + | SANDBOXED_PLUGINS 1.928 + | SANDBOXED_ORIGIN 1.929 + | SANDBOXED_FORMS 1.930 + | SANDBOXED_SCRIPTS 1.931 + | SANDBOXED_AUTOMATIC_FEATURES 1.932 + | SANDBOXED_POINTER_LOCK 1.933 + | SANDBOXED_DOMAIN; 1.934 + 1.935 +// Macro for updating the flag according to the keywords 1.936 +#define IF_KEYWORD(atom, flags) \ 1.937 + if (sandboxAttr->Contains(nsGkAtoms::atom, eIgnoreCase)) { out &= ~(flags); } 1.938 + 1.939 + IF_KEYWORD(allowsameorigin, SANDBOXED_ORIGIN) 1.940 + IF_KEYWORD(allowforms, SANDBOXED_FORMS) 1.941 + IF_KEYWORD(allowscripts, SANDBOXED_SCRIPTS | SANDBOXED_AUTOMATIC_FEATURES) 1.942 + IF_KEYWORD(allowtopnavigation, SANDBOXED_TOPLEVEL_NAVIGATION) 1.943 + IF_KEYWORD(allowpointerlock, SANDBOXED_POINTER_LOCK) 1.944 + IF_KEYWORD(allowpopups, SANDBOXED_AUXILIARY_NAVIGATION) 1.945 + 1.946 + return out; 1.947 +#undef IF_KEYWORD 1.948 +} 1.949 + 1.950 +nsIBidiKeyboard* 1.951 +nsContentUtils::GetBidiKeyboard() 1.952 +{ 1.953 + if (!sBidiKeyboard) { 1.954 + nsresult rv = CallGetService("@mozilla.org/widget/bidikeyboard;1", &sBidiKeyboard); 1.955 + if (NS_FAILED(rv)) { 1.956 + sBidiKeyboard = nullptr; 1.957 + } 1.958 + } 1.959 + return sBidiKeyboard; 1.960 +} 1.961 + 1.962 +template <class OutputIterator> 1.963 +struct NormalizeNewlinesCharTraits { 1.964 + public: 1.965 + typedef typename OutputIterator::value_type value_type; 1.966 + 1.967 + public: 1.968 + NormalizeNewlinesCharTraits(OutputIterator& aIterator) : mIterator(aIterator) { } 1.969 + void writechar(typename OutputIterator::value_type aChar) { 1.970 + *mIterator++ = aChar; 1.971 + } 1.972 + 1.973 + private: 1.974 + OutputIterator mIterator; 1.975 +}; 1.976 + 1.977 +template <class CharT> 1.978 +struct NormalizeNewlinesCharTraits<CharT*> { 1.979 + public: 1.980 + typedef CharT value_type; 1.981 + 1.982 + public: 1.983 + NormalizeNewlinesCharTraits(CharT* aCharPtr) : mCharPtr(aCharPtr) { } 1.984 + void writechar(CharT aChar) { 1.985 + *mCharPtr++ = aChar; 1.986 + } 1.987 + 1.988 + private: 1.989 + CharT* mCharPtr; 1.990 +}; 1.991 + 1.992 +template <class OutputIterator> 1.993 +class CopyNormalizeNewlines 1.994 +{ 1.995 + public: 1.996 + typedef typename OutputIterator::value_type value_type; 1.997 + 1.998 + public: 1.999 + CopyNormalizeNewlines(OutputIterator* aDestination, 1.1000 + bool aLastCharCR=false) : 1.1001 + mLastCharCR(aLastCharCR), 1.1002 + mDestination(aDestination), 1.1003 + mWritten(0) 1.1004 + { } 1.1005 + 1.1006 + uint32_t GetCharsWritten() { 1.1007 + return mWritten; 1.1008 + } 1.1009 + 1.1010 + bool IsLastCharCR() { 1.1011 + return mLastCharCR; 1.1012 + } 1.1013 + 1.1014 + void write(const typename OutputIterator::value_type* aSource, uint32_t aSourceLength) { 1.1015 + 1.1016 + const typename OutputIterator::value_type* done_writing = aSource + aSourceLength; 1.1017 + 1.1018 + // If the last source buffer ended with a CR... 1.1019 + if (mLastCharCR) { 1.1020 + // ..and if the next one is a LF, then skip it since 1.1021 + // we've already written out a newline 1.1022 + if (aSourceLength && (*aSource == value_type('\n'))) { 1.1023 + ++aSource; 1.1024 + } 1.1025 + mLastCharCR = false; 1.1026 + } 1.1027 + 1.1028 + uint32_t num_written = 0; 1.1029 + while ( aSource < done_writing ) { 1.1030 + if (*aSource == value_type('\r')) { 1.1031 + mDestination->writechar('\n'); 1.1032 + ++aSource; 1.1033 + // If we've reached the end of the buffer, record 1.1034 + // that we wrote out a CR 1.1035 + if (aSource == done_writing) { 1.1036 + mLastCharCR = true; 1.1037 + } 1.1038 + // If the next character is a LF, skip it 1.1039 + else if (*aSource == value_type('\n')) { 1.1040 + ++aSource; 1.1041 + } 1.1042 + } 1.1043 + else { 1.1044 + mDestination->writechar(*aSource++); 1.1045 + } 1.1046 + ++num_written; 1.1047 + } 1.1048 + 1.1049 + mWritten += num_written; 1.1050 + } 1.1051 + 1.1052 + private: 1.1053 + bool mLastCharCR; 1.1054 + OutputIterator* mDestination; 1.1055 + uint32_t mWritten; 1.1056 +}; 1.1057 + 1.1058 +// static 1.1059 +uint32_t 1.1060 +nsContentUtils::CopyNewlineNormalizedUnicodeTo(const nsAString& aSource, 1.1061 + uint32_t aSrcOffset, 1.1062 + char16_t* aDest, 1.1063 + uint32_t aLength, 1.1064 + bool& aLastCharCR) 1.1065 +{ 1.1066 + typedef NormalizeNewlinesCharTraits<char16_t*> sink_traits; 1.1067 + 1.1068 + sink_traits dest_traits(aDest); 1.1069 + CopyNormalizeNewlines<sink_traits> normalizer(&dest_traits,aLastCharCR); 1.1070 + nsReadingIterator<char16_t> fromBegin, fromEnd; 1.1071 + copy_string(aSource.BeginReading(fromBegin).advance( int32_t(aSrcOffset) ), 1.1072 + aSource.BeginReading(fromEnd).advance( int32_t(aSrcOffset+aLength) ), 1.1073 + normalizer); 1.1074 + aLastCharCR = normalizer.IsLastCharCR(); 1.1075 + return normalizer.GetCharsWritten(); 1.1076 +} 1.1077 + 1.1078 +// static 1.1079 +uint32_t 1.1080 +nsContentUtils::CopyNewlineNormalizedUnicodeTo(nsReadingIterator<char16_t>& aSrcStart, const nsReadingIterator<char16_t>& aSrcEnd, nsAString& aDest) 1.1081 +{ 1.1082 + typedef nsWritingIterator<char16_t> WritingIterator; 1.1083 + typedef NormalizeNewlinesCharTraits<WritingIterator> sink_traits; 1.1084 + 1.1085 + WritingIterator iter; 1.1086 + aDest.BeginWriting(iter); 1.1087 + sink_traits dest_traits(iter); 1.1088 + CopyNormalizeNewlines<sink_traits> normalizer(&dest_traits); 1.1089 + copy_string(aSrcStart, aSrcEnd, normalizer); 1.1090 + return normalizer.GetCharsWritten(); 1.1091 +} 1.1092 + 1.1093 +/** 1.1094 + * This is used to determine whether a character is in one of the punctuation 1.1095 + * mark classes which CSS says should be part of the first-letter. 1.1096 + * See http://www.w3.org/TR/CSS2/selector.html#first-letter and 1.1097 + * http://www.w3.org/TR/selectors/#first-letter 1.1098 + */ 1.1099 + 1.1100 +// static 1.1101 +bool 1.1102 +nsContentUtils::IsFirstLetterPunctuation(uint32_t aChar) 1.1103 +{ 1.1104 + uint8_t cat = mozilla::unicode::GetGeneralCategory(aChar); 1.1105 + 1.1106 + return (cat == HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION || // Ps 1.1107 + cat == HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION || // Pe 1.1108 + cat == HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION || // Pi 1.1109 + cat == HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION || // Pf 1.1110 + cat == HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION); // Po 1.1111 +} 1.1112 + 1.1113 +// static 1.1114 +bool 1.1115 +nsContentUtils::IsFirstLetterPunctuationAt(const nsTextFragment* aFrag, uint32_t aOffset) 1.1116 +{ 1.1117 + char16_t h = aFrag->CharAt(aOffset); 1.1118 + if (!IS_SURROGATE(h)) { 1.1119 + return IsFirstLetterPunctuation(h); 1.1120 + } 1.1121 + if (NS_IS_HIGH_SURROGATE(h) && aOffset + 1 < aFrag->GetLength()) { 1.1122 + char16_t l = aFrag->CharAt(aOffset + 1); 1.1123 + if (NS_IS_LOW_SURROGATE(l)) { 1.1124 + return IsFirstLetterPunctuation(SURROGATE_TO_UCS4(h, l)); 1.1125 + } 1.1126 + } 1.1127 + return false; 1.1128 +} 1.1129 + 1.1130 +// static 1.1131 +bool nsContentUtils::IsAlphanumeric(uint32_t aChar) 1.1132 +{ 1.1133 + nsIUGenCategory::nsUGenCategory cat = mozilla::unicode::GetGenCategory(aChar); 1.1134 + 1.1135 + return (cat == nsIUGenCategory::kLetter || cat == nsIUGenCategory::kNumber); 1.1136 +} 1.1137 + 1.1138 +// static 1.1139 +bool nsContentUtils::IsAlphanumericAt(const nsTextFragment* aFrag, uint32_t aOffset) 1.1140 +{ 1.1141 + char16_t h = aFrag->CharAt(aOffset); 1.1142 + if (!IS_SURROGATE(h)) { 1.1143 + return IsAlphanumeric(h); 1.1144 + } 1.1145 + if (NS_IS_HIGH_SURROGATE(h) && aOffset + 1 < aFrag->GetLength()) { 1.1146 + char16_t l = aFrag->CharAt(aOffset + 1); 1.1147 + if (NS_IS_LOW_SURROGATE(l)) { 1.1148 + return IsAlphanumeric(SURROGATE_TO_UCS4(h, l)); 1.1149 + } 1.1150 + } 1.1151 + return false; 1.1152 +} 1.1153 + 1.1154 +/* static */ 1.1155 +bool 1.1156 +nsContentUtils::IsHTMLWhitespace(char16_t aChar) 1.1157 +{ 1.1158 + return aChar == char16_t(0x0009) || 1.1159 + aChar == char16_t(0x000A) || 1.1160 + aChar == char16_t(0x000C) || 1.1161 + aChar == char16_t(0x000D) || 1.1162 + aChar == char16_t(0x0020); 1.1163 +} 1.1164 + 1.1165 +/* static */ 1.1166 +bool 1.1167 +nsContentUtils::IsHTMLWhitespaceOrNBSP(char16_t aChar) 1.1168 +{ 1.1169 + return IsHTMLWhitespace(aChar) || aChar == char16_t(0xA0); 1.1170 +} 1.1171 + 1.1172 +/* static */ 1.1173 +bool 1.1174 +nsContentUtils::IsHTMLBlock(nsIAtom* aLocalName) 1.1175 +{ 1.1176 + return 1.1177 + (aLocalName == nsGkAtoms::address) || 1.1178 + (aLocalName == nsGkAtoms::article) || 1.1179 + (aLocalName == nsGkAtoms::aside) || 1.1180 + (aLocalName == nsGkAtoms::blockquote) || 1.1181 + (aLocalName == nsGkAtoms::center) || 1.1182 + (aLocalName == nsGkAtoms::dir) || 1.1183 + (aLocalName == nsGkAtoms::div) || 1.1184 + (aLocalName == nsGkAtoms::dl) || // XXX why not dt and dd? 1.1185 + (aLocalName == nsGkAtoms::fieldset) || 1.1186 + (aLocalName == nsGkAtoms::figure) || // XXX shouldn't figcaption be on this list 1.1187 + (aLocalName == nsGkAtoms::footer) || 1.1188 + (aLocalName == nsGkAtoms::form) || 1.1189 + (aLocalName == nsGkAtoms::h1) || 1.1190 + (aLocalName == nsGkAtoms::h2) || 1.1191 + (aLocalName == nsGkAtoms::h3) || 1.1192 + (aLocalName == nsGkAtoms::h4) || 1.1193 + (aLocalName == nsGkAtoms::h5) || 1.1194 + (aLocalName == nsGkAtoms::h6) || 1.1195 + (aLocalName == nsGkAtoms::header) || 1.1196 + (aLocalName == nsGkAtoms::hgroup) || 1.1197 + (aLocalName == nsGkAtoms::hr) || 1.1198 + (aLocalName == nsGkAtoms::li) || 1.1199 + (aLocalName == nsGkAtoms::listing) || 1.1200 + (aLocalName == nsGkAtoms::menu) || 1.1201 + (aLocalName == nsGkAtoms::multicol) || // XXX get rid of this one? 1.1202 + (aLocalName == nsGkAtoms::nav) || 1.1203 + (aLocalName == nsGkAtoms::ol) || 1.1204 + (aLocalName == nsGkAtoms::p) || 1.1205 + (aLocalName == nsGkAtoms::pre) || 1.1206 + (aLocalName == nsGkAtoms::section) || 1.1207 + (aLocalName == nsGkAtoms::table) || 1.1208 + (aLocalName == nsGkAtoms::ul) || 1.1209 + (aLocalName == nsGkAtoms::xmp); 1.1210 +} 1.1211 + 1.1212 +/* static */ 1.1213 +bool 1.1214 +nsContentUtils::IsHTMLVoid(nsIAtom* aLocalName) 1.1215 +{ 1.1216 + return 1.1217 + (aLocalName == nsGkAtoms::area) || 1.1218 + (aLocalName == nsGkAtoms::base) || 1.1219 + (aLocalName == nsGkAtoms::basefont) || 1.1220 + (aLocalName == nsGkAtoms::bgsound) || 1.1221 + (aLocalName == nsGkAtoms::br) || 1.1222 + (aLocalName == nsGkAtoms::col) || 1.1223 + (aLocalName == nsGkAtoms::command) || 1.1224 + (aLocalName == nsGkAtoms::embed) || 1.1225 + (aLocalName == nsGkAtoms::frame) || 1.1226 + (aLocalName == nsGkAtoms::hr) || 1.1227 + (aLocalName == nsGkAtoms::img) || 1.1228 + (aLocalName == nsGkAtoms::input) || 1.1229 + (aLocalName == nsGkAtoms::keygen) || 1.1230 + (aLocalName == nsGkAtoms::link) || 1.1231 + (aLocalName == nsGkAtoms::meta) || 1.1232 + (aLocalName == nsGkAtoms::param) || 1.1233 + (aLocalName == nsGkAtoms::source) || 1.1234 + (aLocalName == nsGkAtoms::track) || 1.1235 + (aLocalName == nsGkAtoms::wbr); 1.1236 +} 1.1237 + 1.1238 +/* static */ 1.1239 +bool 1.1240 +nsContentUtils::ParseIntMarginValue(const nsAString& aString, nsIntMargin& result) 1.1241 +{ 1.1242 + nsAutoString marginStr(aString); 1.1243 + marginStr.CompressWhitespace(true, true); 1.1244 + if (marginStr.IsEmpty()) { 1.1245 + return false; 1.1246 + } 1.1247 + 1.1248 + int32_t start = 0, end = 0; 1.1249 + for (int count = 0; count < 4; count++) { 1.1250 + if ((uint32_t)end >= marginStr.Length()) 1.1251 + return false; 1.1252 + 1.1253 + // top, right, bottom, left 1.1254 + if (count < 3) 1.1255 + end = Substring(marginStr, start).FindChar(','); 1.1256 + else 1.1257 + end = Substring(marginStr, start).Length(); 1.1258 + 1.1259 + if (end <= 0) 1.1260 + return false; 1.1261 + 1.1262 + nsresult ec; 1.1263 + int32_t val = nsString(Substring(marginStr, start, end)).ToInteger(&ec); 1.1264 + if (NS_FAILED(ec)) 1.1265 + return false; 1.1266 + 1.1267 + switch(count) { 1.1268 + case 0: 1.1269 + result.top = val; 1.1270 + break; 1.1271 + case 1: 1.1272 + result.right = val; 1.1273 + break; 1.1274 + case 2: 1.1275 + result.bottom = val; 1.1276 + break; 1.1277 + case 3: 1.1278 + result.left = val; 1.1279 + break; 1.1280 + } 1.1281 + start += end + 1; 1.1282 + } 1.1283 + return true; 1.1284 +} 1.1285 + 1.1286 +// static 1.1287 +int32_t 1.1288 +nsContentUtils::ParseLegacyFontSize(const nsAString& aValue) 1.1289 +{ 1.1290 + nsAString::const_iterator iter, end; 1.1291 + aValue.BeginReading(iter); 1.1292 + aValue.EndReading(end); 1.1293 + 1.1294 + while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { 1.1295 + ++iter; 1.1296 + } 1.1297 + 1.1298 + if (iter == end) { 1.1299 + return 0; 1.1300 + } 1.1301 + 1.1302 + bool relative = false; 1.1303 + bool negate = false; 1.1304 + if (*iter == char16_t('-')) { 1.1305 + relative = true; 1.1306 + negate = true; 1.1307 + ++iter; 1.1308 + } else if (*iter == char16_t('+')) { 1.1309 + relative = true; 1.1310 + ++iter; 1.1311 + } 1.1312 + 1.1313 + if (*iter < char16_t('0') || *iter > char16_t('9')) { 1.1314 + return 0; 1.1315 + } 1.1316 + 1.1317 + // We don't have to worry about overflow, since we can bail out as soon as 1.1318 + // we're bigger than 7. 1.1319 + int32_t value = 0; 1.1320 + while (iter != end && *iter >= char16_t('0') && *iter <= char16_t('9')) { 1.1321 + value = 10*value + (*iter - char16_t('0')); 1.1322 + if (value >= 7) { 1.1323 + break; 1.1324 + } 1.1325 + ++iter; 1.1326 + } 1.1327 + 1.1328 + if (relative) { 1.1329 + if (negate) { 1.1330 + value = 3 - value; 1.1331 + } else { 1.1332 + value = 3 + value; 1.1333 + } 1.1334 + } 1.1335 + 1.1336 + return clamped(value, 1, 7); 1.1337 +} 1.1338 + 1.1339 +/* static */ 1.1340 +void 1.1341 +nsContentUtils::GetOfflineAppManifest(nsIDocument *aDocument, nsIURI **aURI) 1.1342 +{ 1.1343 + Element* docElement = aDocument->GetRootElement(); 1.1344 + if (!docElement) { 1.1345 + return; 1.1346 + } 1.1347 + 1.1348 + nsAutoString manifestSpec; 1.1349 + docElement->GetAttr(kNameSpaceID_None, nsGkAtoms::manifest, manifestSpec); 1.1350 + 1.1351 + // Manifest URIs can't have fragment identifiers. 1.1352 + if (manifestSpec.IsEmpty() || 1.1353 + manifestSpec.FindChar('#') != kNotFound) { 1.1354 + return; 1.1355 + } 1.1356 + 1.1357 + nsContentUtils::NewURIWithDocumentCharset(aURI, manifestSpec, 1.1358 + aDocument, 1.1359 + aDocument->GetDocBaseURI()); 1.1360 +} 1.1361 + 1.1362 +/* static */ 1.1363 +bool 1.1364 +nsContentUtils::OfflineAppAllowed(nsIURI *aURI) 1.1365 +{ 1.1366 + nsCOMPtr<nsIOfflineCacheUpdateService> updateService = 1.1367 + do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID); 1.1368 + if (!updateService) { 1.1369 + return false; 1.1370 + } 1.1371 + 1.1372 + bool allowed; 1.1373 + nsresult rv = 1.1374 + updateService->OfflineAppAllowedForURI(aURI, 1.1375 + Preferences::GetRootBranch(), 1.1376 + &allowed); 1.1377 + return NS_SUCCEEDED(rv) && allowed; 1.1378 +} 1.1379 + 1.1380 +/* static */ 1.1381 +bool 1.1382 +nsContentUtils::OfflineAppAllowed(nsIPrincipal *aPrincipal) 1.1383 +{ 1.1384 + nsCOMPtr<nsIOfflineCacheUpdateService> updateService = 1.1385 + do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID); 1.1386 + if (!updateService) { 1.1387 + return false; 1.1388 + } 1.1389 + 1.1390 + bool allowed; 1.1391 + nsresult rv = updateService->OfflineAppAllowed(aPrincipal, 1.1392 + Preferences::GetRootBranch(), 1.1393 + &allowed); 1.1394 + return NS_SUCCEEDED(rv) && allowed; 1.1395 +} 1.1396 + 1.1397 +bool 1.1398 +nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal, 1.1399 + nsIDOMWindow *aWindow) 1.1400 +{ 1.1401 + if (!Preferences::GetRootBranch()) 1.1402 + return false; 1.1403 + 1.1404 + nsresult rv; 1.1405 + 1.1406 + bool allowedByDefault; 1.1407 + rv = Preferences::GetRootBranch()->GetBoolPref( 1.1408 + "offline-apps.allow_by_default", &allowedByDefault); 1.1409 + if (NS_FAILED(rv)) 1.1410 + return false; 1.1411 + 1.1412 + if (!allowedByDefault) 1.1413 + return false; 1.1414 + 1.1415 + nsCOMPtr<nsIOfflineCacheUpdateService> updateService = 1.1416 + do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID); 1.1417 + if (!updateService) { 1.1418 + return false; 1.1419 + } 1.1420 + 1.1421 + rv = updateService->AllowOfflineApp(aWindow, aPrincipal); 1.1422 + return NS_SUCCEEDED(rv); 1.1423 +} 1.1424 + 1.1425 +// static 1.1426 +void 1.1427 +nsContentUtils::Shutdown() 1.1428 +{ 1.1429 + sInitialized = false; 1.1430 + 1.1431 + NS_IF_RELEASE(sContentPolicyService); 1.1432 + sTriedToGetContentPolicy = false; 1.1433 + uint32_t i; 1.1434 + for (i = 0; i < PropertiesFile_COUNT; ++i) 1.1435 + NS_IF_RELEASE(sStringBundles[i]); 1.1436 + 1.1437 + NS_IF_RELEASE(sStringBundleService); 1.1438 + NS_IF_RELEASE(sConsoleService); 1.1439 + sXPConnect = nullptr; 1.1440 + NS_IF_RELEASE(sSecurityManager); 1.1441 + NS_IF_RELEASE(sParserService); 1.1442 + NS_IF_RELEASE(sIOService); 1.1443 + NS_IF_RELEASE(sLineBreaker); 1.1444 + NS_IF_RELEASE(sWordBreaker); 1.1445 + NS_IF_RELEASE(sBidiKeyboard); 1.1446 + 1.1447 + delete sAtomEventTable; 1.1448 + sAtomEventTable = nullptr; 1.1449 + delete sStringEventTable; 1.1450 + sStringEventTable = nullptr; 1.1451 + delete sUserDefinedEvents; 1.1452 + sUserDefinedEvents = nullptr; 1.1453 + 1.1454 + if (sEventListenerManagersHash.ops) { 1.1455 + NS_ASSERTION(sEventListenerManagersHash.entryCount == 0, 1.1456 + "Event listener manager hash not empty at shutdown!"); 1.1457 + 1.1458 + // See comment above. 1.1459 + 1.1460 + // However, we have to handle this table differently. If it still 1.1461 + // has entries, we want to leak it too, so that we can keep it alive 1.1462 + // in case any elements are destroyed. Because if they are, we need 1.1463 + // their event listener managers to be destroyed too, or otherwise 1.1464 + // it could leave dangling references in DOMClassInfo's preserved 1.1465 + // wrapper table. 1.1466 + 1.1467 + if (sEventListenerManagersHash.entryCount == 0) { 1.1468 + PL_DHashTableFinish(&sEventListenerManagersHash); 1.1469 + sEventListenerManagersHash.ops = nullptr; 1.1470 + } 1.1471 + } 1.1472 + 1.1473 + NS_ASSERTION(!sBlockedScriptRunners || 1.1474 + sBlockedScriptRunners->Length() == 0, 1.1475 + "How'd this happen?"); 1.1476 + delete sBlockedScriptRunners; 1.1477 + sBlockedScriptRunners = nullptr; 1.1478 + 1.1479 + delete sShiftText; 1.1480 + sShiftText = nullptr; 1.1481 + delete sControlText; 1.1482 + sControlText = nullptr; 1.1483 + delete sMetaText; 1.1484 + sMetaText = nullptr; 1.1485 + delete sOSText; 1.1486 + sOSText = nullptr; 1.1487 + delete sAltText; 1.1488 + sAltText = nullptr; 1.1489 + delete sModifierSeparator; 1.1490 + sModifierSeparator = nullptr; 1.1491 + 1.1492 + NS_IF_RELEASE(sSameOriginChecker); 1.1493 +} 1.1494 + 1.1495 +/** 1.1496 + * Checks whether two nodes come from the same origin. aTrustedNode is 1.1497 + * considered 'safe' in that a user can operate on it and that it isn't 1.1498 + * a js-object that implements nsIDOMNode. 1.1499 + * Never call this function with the first node provided by script, it 1.1500 + * must always be known to be a 'real' node! 1.1501 + */ 1.1502 +// static 1.1503 +nsresult 1.1504 +nsContentUtils::CheckSameOrigin(const nsINode *aTrustedNode, 1.1505 + nsIDOMNode *aUnTrustedNode) 1.1506 +{ 1.1507 + MOZ_ASSERT(aTrustedNode); 1.1508 + 1.1509 + // Make sure it's a real node. 1.1510 + nsCOMPtr<nsINode> unTrustedNode = do_QueryInterface(aUnTrustedNode); 1.1511 + NS_ENSURE_TRUE(unTrustedNode, NS_ERROR_UNEXPECTED); 1.1512 + return CheckSameOrigin(aTrustedNode, unTrustedNode); 1.1513 +} 1.1514 + 1.1515 +nsresult 1.1516 +nsContentUtils::CheckSameOrigin(const nsINode* aTrustedNode, 1.1517 + const nsINode* unTrustedNode) 1.1518 +{ 1.1519 + MOZ_ASSERT(aTrustedNode); 1.1520 + MOZ_ASSERT(unTrustedNode); 1.1521 + 1.1522 + bool isSystem = false; 1.1523 + nsresult rv = sSecurityManager->SubjectPrincipalIsSystem(&isSystem); 1.1524 + NS_ENSURE_SUCCESS(rv, rv); 1.1525 + 1.1526 + if (isSystem) { 1.1527 + // we're running as system, grant access to the node. 1.1528 + 1.1529 + return NS_OK; 1.1530 + } 1.1531 + 1.1532 + /* 1.1533 + * Get hold of each node's principal 1.1534 + */ 1.1535 + 1.1536 + nsIPrincipal* trustedPrincipal = aTrustedNode->NodePrincipal(); 1.1537 + nsIPrincipal* unTrustedPrincipal = unTrustedNode->NodePrincipal(); 1.1538 + 1.1539 + if (trustedPrincipal == unTrustedPrincipal) { 1.1540 + return NS_OK; 1.1541 + } 1.1542 + 1.1543 + bool equal; 1.1544 + // XXXbz should we actually have a Subsumes() check here instead? Or perhaps 1.1545 + // a separate method for that, with callers using one or the other? 1.1546 + if (NS_FAILED(trustedPrincipal->Equals(unTrustedPrincipal, &equal)) || 1.1547 + !equal) { 1.1548 + return NS_ERROR_DOM_PROP_ACCESS_DENIED; 1.1549 + } 1.1550 + 1.1551 + return NS_OK; 1.1552 +} 1.1553 + 1.1554 +// static 1.1555 +bool 1.1556 +nsContentUtils::CanCallerAccess(nsIPrincipal* aSubjectPrincipal, 1.1557 + nsIPrincipal* aPrincipal) 1.1558 +{ 1.1559 + bool subsumes; 1.1560 + nsresult rv = aSubjectPrincipal->Subsumes(aPrincipal, &subsumes); 1.1561 + NS_ENSURE_SUCCESS(rv, false); 1.1562 + 1.1563 + if (subsumes) { 1.1564 + return true; 1.1565 + } 1.1566 + 1.1567 + // The subject doesn't subsume aPrincipal. Allow access only if the subject 1.1568 + // is chrome. 1.1569 + return IsCallerChrome(); 1.1570 +} 1.1571 + 1.1572 +// static 1.1573 +bool 1.1574 +nsContentUtils::CanCallerAccess(nsIDOMNode *aNode) 1.1575 +{ 1.1576 + nsCOMPtr<nsINode> node = do_QueryInterface(aNode); 1.1577 + NS_ENSURE_TRUE(node, false); 1.1578 + return CanCallerAccess(node); 1.1579 +} 1.1580 + 1.1581 +// static 1.1582 +bool 1.1583 +nsContentUtils::CanCallerAccess(nsINode* aNode) 1.1584 +{ 1.1585 + // XXXbz why not check the IsCapabilityEnabled thing up front, and not bother 1.1586 + // with the system principal games? But really, there should be a simpler 1.1587 + // API here, dammit. 1.1588 + nsCOMPtr<nsIPrincipal> subjectPrincipal; 1.1589 + nsresult rv = sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal)); 1.1590 + NS_ENSURE_SUCCESS(rv, false); 1.1591 + 1.1592 + if (!subjectPrincipal) { 1.1593 + // we're running as system, grant access to the node. 1.1594 + 1.1595 + return true; 1.1596 + } 1.1597 + 1.1598 + return CanCallerAccess(subjectPrincipal, aNode->NodePrincipal()); 1.1599 +} 1.1600 + 1.1601 +// static 1.1602 +bool 1.1603 +nsContentUtils::CanCallerAccess(nsPIDOMWindow* aWindow) 1.1604 +{ 1.1605 + // XXXbz why not check the IsCapabilityEnabled thing up front, and not bother 1.1606 + // with the system principal games? But really, there should be a simpler 1.1607 + // API here, dammit. 1.1608 + nsCOMPtr<nsIPrincipal> subjectPrincipal; 1.1609 + nsresult rv = sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal)); 1.1610 + NS_ENSURE_SUCCESS(rv, false); 1.1611 + 1.1612 + if (!subjectPrincipal) { 1.1613 + // we're running as system, grant access to the node. 1.1614 + 1.1615 + return true; 1.1616 + } 1.1617 + 1.1618 + nsCOMPtr<nsIScriptObjectPrincipal> scriptObject = 1.1619 + do_QueryInterface(aWindow->IsOuterWindow() ? 1.1620 + aWindow->GetCurrentInnerWindow() : aWindow); 1.1621 + NS_ENSURE_TRUE(scriptObject, false); 1.1622 + 1.1623 + return CanCallerAccess(subjectPrincipal, scriptObject->GetPrincipal()); 1.1624 +} 1.1625 + 1.1626 +//static 1.1627 +bool 1.1628 +nsContentUtils::InProlog(nsINode *aNode) 1.1629 +{ 1.1630 + NS_PRECONDITION(aNode, "missing node to nsContentUtils::InProlog"); 1.1631 + 1.1632 + nsINode* parent = aNode->GetParentNode(); 1.1633 + if (!parent || !parent->IsNodeOfType(nsINode::eDOCUMENT)) { 1.1634 + return false; 1.1635 + } 1.1636 + 1.1637 + nsIDocument* doc = static_cast<nsIDocument*>(parent); 1.1638 + nsIContent* root = doc->GetRootElement(); 1.1639 + 1.1640 + return !root || doc->IndexOf(aNode) < doc->IndexOf(root); 1.1641 +} 1.1642 + 1.1643 +JSContext * 1.1644 +nsContentUtils::GetContextFromDocument(nsIDocument *aDocument) 1.1645 +{ 1.1646 + nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aDocument->GetScopeObject()); 1.1647 + if (!sgo) { 1.1648 + // No script global, no context. 1.1649 + return nullptr; 1.1650 + } 1.1651 + 1.1652 + nsIScriptContext *scx = sgo->GetContext(); 1.1653 + if (!scx) { 1.1654 + // No context left in the scope... 1.1655 + return nullptr; 1.1656 + } 1.1657 + 1.1658 + return scx->GetNativeContext(); 1.1659 +} 1.1660 + 1.1661 +//static 1.1662 +void 1.1663 +nsContentUtils::TraceSafeJSContext(JSTracer* aTrc) 1.1664 +{ 1.1665 + JSContext* cx = GetSafeJSContext(); 1.1666 + if (!cx) { 1.1667 + return; 1.1668 + } 1.1669 + if (JSObject* global = js::DefaultObjectForContextOrNull(cx)) { 1.1670 + JS::AssertGCThingMustBeTenured(global); 1.1671 + JS_CallObjectTracer(aTrc, &global, "safe context"); 1.1672 + MOZ_ASSERT(global == js::DefaultObjectForContextOrNull(cx)); 1.1673 + } 1.1674 +} 1.1675 + 1.1676 +nsPIDOMWindow * 1.1677 +nsContentUtils::GetWindowFromCaller() 1.1678 +{ 1.1679 + JSContext *cx = GetCurrentJSContext(); 1.1680 + if (cx) { 1.1681 + nsCOMPtr<nsPIDOMWindow> win = 1.1682 + do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx)); 1.1683 + return win; 1.1684 + } 1.1685 + 1.1686 + return nullptr; 1.1687 +} 1.1688 + 1.1689 +nsIDocument* 1.1690 +nsContentUtils::GetDocumentFromCaller() 1.1691 +{ 1.1692 + AutoJSContext cx; 1.1693 + 1.1694 + nsCOMPtr<nsPIDOMWindow> win = 1.1695 + do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(cx))); 1.1696 + if (!win) { 1.1697 + return nullptr; 1.1698 + } 1.1699 + 1.1700 + return win->GetExtantDoc(); 1.1701 +} 1.1702 + 1.1703 +nsIDocument* 1.1704 +nsContentUtils::GetDocumentFromContext() 1.1705 +{ 1.1706 + JSContext *cx = GetCurrentJSContext(); 1.1707 + if (cx) { 1.1708 + nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(cx); 1.1709 + 1.1710 + if (sgo) { 1.1711 + nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(sgo); 1.1712 + if (pwin) { 1.1713 + return pwin->GetExtantDoc(); 1.1714 + } 1.1715 + } 1.1716 + } 1.1717 + 1.1718 + return nullptr; 1.1719 +} 1.1720 + 1.1721 +bool 1.1722 +nsContentUtils::IsCallerChrome() 1.1723 +{ 1.1724 + MOZ_ASSERT(NS_IsMainThread()); 1.1725 + bool is_caller_chrome = false; 1.1726 + nsresult rv = sSecurityManager->SubjectPrincipalIsSystem(&is_caller_chrome); 1.1727 + if (NS_FAILED(rv)) { 1.1728 + return false; 1.1729 + } 1.1730 + if (is_caller_chrome) { 1.1731 + return true; 1.1732 + } 1.1733 + 1.1734 + // If the check failed, look for UniversalXPConnect on the cx compartment. 1.1735 + return xpc::IsUniversalXPConnectEnabled(GetCurrentJSContext()); 1.1736 +} 1.1737 + 1.1738 +namespace mozilla { 1.1739 +namespace dom { 1.1740 +namespace workers { 1.1741 +extern bool IsCurrentThreadRunningChromeWorker(); 1.1742 +extern JSContext* GetCurrentThreadJSContext(); 1.1743 +} 1.1744 +} 1.1745 +} 1.1746 + 1.1747 +bool 1.1748 +nsContentUtils::ThreadsafeIsCallerChrome() 1.1749 +{ 1.1750 + return NS_IsMainThread() ? 1.1751 + IsCallerChrome() : 1.1752 + mozilla::dom::workers::IsCurrentThreadRunningChromeWorker(); 1.1753 +} 1.1754 + 1.1755 +bool 1.1756 +nsContentUtils::IsCallerXBL() 1.1757 +{ 1.1758 + JSContext *cx = GetCurrentJSContext(); 1.1759 + if (!cx) 1.1760 + return false; 1.1761 + 1.1762 + JSCompartment *c = js::GetContextCompartment(cx); 1.1763 + 1.1764 + // For remote XUL, we run XBL in the XUL scope. Given that we care about 1.1765 + // compat and not security for remote XUL, just always claim to be XBL. 1.1766 + if (!xpc::AllowXBLScope(c)) { 1.1767 + MOZ_ASSERT(nsContentUtils::AllowXULXBLForPrincipal(xpc::GetCompartmentPrincipal(c))); 1.1768 + return true; 1.1769 + } 1.1770 + 1.1771 + return xpc::IsXBLScope(c); 1.1772 +} 1.1773 + 1.1774 + 1.1775 +bool 1.1776 +nsContentUtils::IsImageSrcSetDisabled() 1.1777 +{ 1.1778 + return Preferences::GetBool("dom.disable_image_src_set") && 1.1779 + !IsCallerChrome(); 1.1780 +} 1.1781 + 1.1782 +// static 1.1783 +bool 1.1784 +nsContentUtils::LookupBindingMember(JSContext* aCx, nsIContent *aContent, 1.1785 + JS::Handle<jsid> aId, 1.1786 + JS::MutableHandle<JSPropertyDescriptor> aDesc) 1.1787 +{ 1.1788 + nsXBLBinding* binding = aContent->GetXBLBinding(); 1.1789 + if (!binding) 1.1790 + return true; 1.1791 + return binding->LookupMember(aCx, aId, aDesc); 1.1792 +} 1.1793 + 1.1794 +// static 1.1795 +nsINode* 1.1796 +nsContentUtils::GetCrossDocParentNode(nsINode* aChild) 1.1797 +{ 1.1798 + NS_PRECONDITION(aChild, "The child is null!"); 1.1799 + 1.1800 + nsINode* parent = aChild->GetParentNode(); 1.1801 + if (parent || !aChild->IsNodeOfType(nsINode::eDOCUMENT)) 1.1802 + return parent; 1.1803 + 1.1804 + nsIDocument* doc = static_cast<nsIDocument*>(aChild); 1.1805 + nsIDocument* parentDoc = doc->GetParentDocument(); 1.1806 + return parentDoc ? parentDoc->FindContentForSubDocument(doc) : nullptr; 1.1807 +} 1.1808 + 1.1809 +// static 1.1810 +bool 1.1811 +nsContentUtils::ContentIsDescendantOf(const nsINode* aPossibleDescendant, 1.1812 + const nsINode* aPossibleAncestor) 1.1813 +{ 1.1814 + NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!"); 1.1815 + NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!"); 1.1816 + 1.1817 + do { 1.1818 + if (aPossibleDescendant == aPossibleAncestor) 1.1819 + return true; 1.1820 + aPossibleDescendant = aPossibleDescendant->GetParentNode(); 1.1821 + } while (aPossibleDescendant); 1.1822 + 1.1823 + return false; 1.1824 +} 1.1825 + 1.1826 +bool 1.1827 +nsContentUtils::ContentIsHostIncludingDescendantOf( 1.1828 + const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor) 1.1829 +{ 1.1830 + NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!"); 1.1831 + NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!"); 1.1832 + 1.1833 + do { 1.1834 + if (aPossibleDescendant == aPossibleAncestor) 1.1835 + return true; 1.1836 + if (aPossibleDescendant->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) { 1.1837 + aPossibleDescendant = 1.1838 + static_cast<const DocumentFragment*>(aPossibleDescendant)->GetHost(); 1.1839 + } else { 1.1840 + aPossibleDescendant = aPossibleDescendant->GetParentNode(); 1.1841 + } 1.1842 + } while (aPossibleDescendant); 1.1843 + 1.1844 + return false; 1.1845 +} 1.1846 + 1.1847 +// static 1.1848 +bool 1.1849 +nsContentUtils::ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant, 1.1850 + nsINode* aPossibleAncestor) 1.1851 +{ 1.1852 + NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!"); 1.1853 + NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!"); 1.1854 + 1.1855 + do { 1.1856 + if (aPossibleDescendant == aPossibleAncestor) 1.1857 + return true; 1.1858 + aPossibleDescendant = GetCrossDocParentNode(aPossibleDescendant); 1.1859 + } while (aPossibleDescendant); 1.1860 + 1.1861 + return false; 1.1862 +} 1.1863 + 1.1864 + 1.1865 +// static 1.1866 +nsresult 1.1867 +nsContentUtils::GetAncestors(nsINode* aNode, 1.1868 + nsTArray<nsINode*>& aArray) 1.1869 +{ 1.1870 + while (aNode) { 1.1871 + aArray.AppendElement(aNode); 1.1872 + aNode = aNode->GetParentNode(); 1.1873 + } 1.1874 + return NS_OK; 1.1875 +} 1.1876 + 1.1877 +// static 1.1878 +nsresult 1.1879 +nsContentUtils::GetAncestorsAndOffsets(nsIDOMNode* aNode, 1.1880 + int32_t aOffset, 1.1881 + nsTArray<nsIContent*>* aAncestorNodes, 1.1882 + nsTArray<int32_t>* aAncestorOffsets) 1.1883 +{ 1.1884 + NS_ENSURE_ARG_POINTER(aNode); 1.1885 + 1.1886 + nsCOMPtr<nsIContent> content(do_QueryInterface(aNode)); 1.1887 + 1.1888 + if (!content) { 1.1889 + return NS_ERROR_FAILURE; 1.1890 + } 1.1891 + 1.1892 + if (!aAncestorNodes->IsEmpty()) { 1.1893 + NS_WARNING("aAncestorNodes is not empty"); 1.1894 + aAncestorNodes->Clear(); 1.1895 + } 1.1896 + 1.1897 + if (!aAncestorOffsets->IsEmpty()) { 1.1898 + NS_WARNING("aAncestorOffsets is not empty"); 1.1899 + aAncestorOffsets->Clear(); 1.1900 + } 1.1901 + 1.1902 + // insert the node itself 1.1903 + aAncestorNodes->AppendElement(content.get()); 1.1904 + aAncestorOffsets->AppendElement(aOffset); 1.1905 + 1.1906 + // insert all the ancestors 1.1907 + nsIContent* child = content; 1.1908 + nsIContent* parent = child->GetParent(); 1.1909 + while (parent) { 1.1910 + aAncestorNodes->AppendElement(parent); 1.1911 + aAncestorOffsets->AppendElement(parent->IndexOf(child)); 1.1912 + child = parent; 1.1913 + parent = parent->GetParent(); 1.1914 + } 1.1915 + 1.1916 + return NS_OK; 1.1917 +} 1.1918 + 1.1919 +// static 1.1920 +nsresult 1.1921 +nsContentUtils::GetCommonAncestor(nsIDOMNode *aNode, 1.1922 + nsIDOMNode *aOther, 1.1923 + nsIDOMNode** aCommonAncestor) 1.1924 +{ 1.1925 + *aCommonAncestor = nullptr; 1.1926 + 1.1927 + nsCOMPtr<nsINode> node1 = do_QueryInterface(aNode); 1.1928 + nsCOMPtr<nsINode> node2 = do_QueryInterface(aOther); 1.1929 + 1.1930 + NS_ENSURE_TRUE(node1 && node2, NS_ERROR_UNEXPECTED); 1.1931 + 1.1932 + nsINode* common = GetCommonAncestor(node1, node2); 1.1933 + NS_ENSURE_TRUE(common, NS_ERROR_NOT_AVAILABLE); 1.1934 + 1.1935 + return CallQueryInterface(common, aCommonAncestor); 1.1936 +} 1.1937 + 1.1938 +// static 1.1939 +nsINode* 1.1940 +nsContentUtils::GetCommonAncestor(nsINode* aNode1, 1.1941 + nsINode* aNode2) 1.1942 +{ 1.1943 + if (aNode1 == aNode2) { 1.1944 + return aNode1; 1.1945 + } 1.1946 + 1.1947 + // Build the chain of parents 1.1948 + nsAutoTArray<nsINode*, 30> parents1, parents2; 1.1949 + do { 1.1950 + parents1.AppendElement(aNode1); 1.1951 + aNode1 = aNode1->GetParentNode(); 1.1952 + } while (aNode1); 1.1953 + do { 1.1954 + parents2.AppendElement(aNode2); 1.1955 + aNode2 = aNode2->GetParentNode(); 1.1956 + } while (aNode2); 1.1957 + 1.1958 + // Find where the parent chain differs 1.1959 + uint32_t pos1 = parents1.Length(); 1.1960 + uint32_t pos2 = parents2.Length(); 1.1961 + nsINode* parent = nullptr; 1.1962 + uint32_t len; 1.1963 + for (len = std::min(pos1, pos2); len > 0; --len) { 1.1964 + nsINode* child1 = parents1.ElementAt(--pos1); 1.1965 + nsINode* child2 = parents2.ElementAt(--pos2); 1.1966 + if (child1 != child2) { 1.1967 + break; 1.1968 + } 1.1969 + parent = child1; 1.1970 + } 1.1971 + 1.1972 + return parent; 1.1973 +} 1.1974 + 1.1975 +/* static */ 1.1976 +bool 1.1977 +nsContentUtils::PositionIsBefore(nsINode* aNode1, nsINode* aNode2) 1.1978 +{ 1.1979 + return (aNode2->CompareDocumentPosition(*aNode1) & 1.1980 + (nsIDOMNode::DOCUMENT_POSITION_PRECEDING | 1.1981 + nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED)) == 1.1982 + nsIDOMNode::DOCUMENT_POSITION_PRECEDING; 1.1983 +} 1.1984 + 1.1985 +/* static */ 1.1986 +int32_t 1.1987 +nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1, 1.1988 + nsINode* aParent2, int32_t aOffset2, 1.1989 + bool* aDisconnected) 1.1990 +{ 1.1991 + if (aParent1 == aParent2) { 1.1992 + return aOffset1 < aOffset2 ? -1 : 1.1993 + aOffset1 > aOffset2 ? 1 : 1.1994 + 0; 1.1995 + } 1.1996 + 1.1997 + nsAutoTArray<nsINode*, 32> parents1, parents2; 1.1998 + nsINode* node1 = aParent1; 1.1999 + nsINode* node2 = aParent2; 1.2000 + do { 1.2001 + parents1.AppendElement(node1); 1.2002 + node1 = node1->GetParentNode(); 1.2003 + } while (node1); 1.2004 + do { 1.2005 + parents2.AppendElement(node2); 1.2006 + node2 = node2->GetParentNode(); 1.2007 + } while (node2); 1.2008 + 1.2009 + uint32_t pos1 = parents1.Length() - 1; 1.2010 + uint32_t pos2 = parents2.Length() - 1; 1.2011 + 1.2012 + bool disconnected = parents1.ElementAt(pos1) != parents2.ElementAt(pos2); 1.2013 + if (aDisconnected) { 1.2014 + *aDisconnected = disconnected; 1.2015 + } 1.2016 + if (disconnected) { 1.2017 + NS_ASSERTION(aDisconnected, "unexpected disconnected nodes"); 1.2018 + return 1; 1.2019 + } 1.2020 + 1.2021 + // Find where the parent chains differ 1.2022 + nsINode* parent = parents1.ElementAt(pos1); 1.2023 + uint32_t len; 1.2024 + for (len = std::min(pos1, pos2); len > 0; --len) { 1.2025 + nsINode* child1 = parents1.ElementAt(--pos1); 1.2026 + nsINode* child2 = parents2.ElementAt(--pos2); 1.2027 + if (child1 != child2) { 1.2028 + return parent->IndexOf(child1) < parent->IndexOf(child2) ? -1 : 1; 1.2029 + } 1.2030 + parent = child1; 1.2031 + } 1.2032 + 1.2033 + 1.2034 + // The parent chains never differed, so one of the nodes is an ancestor of 1.2035 + // the other 1.2036 + 1.2037 + NS_ASSERTION(!pos1 || !pos2, 1.2038 + "should have run out of parent chain for one of the nodes"); 1.2039 + 1.2040 + if (!pos1) { 1.2041 + nsINode* child2 = parents2.ElementAt(--pos2); 1.2042 + return aOffset1 <= parent->IndexOf(child2) ? -1 : 1; 1.2043 + } 1.2044 + 1.2045 + nsINode* child1 = parents1.ElementAt(--pos1); 1.2046 + return parent->IndexOf(child1) < aOffset2 ? -1 : 1; 1.2047 +} 1.2048 + 1.2049 +/* static */ 1.2050 +int32_t 1.2051 +nsContentUtils::ComparePoints(nsIDOMNode* aParent1, int32_t aOffset1, 1.2052 + nsIDOMNode* aParent2, int32_t aOffset2, 1.2053 + bool* aDisconnected) 1.2054 +{ 1.2055 + nsCOMPtr<nsINode> parent1 = do_QueryInterface(aParent1); 1.2056 + nsCOMPtr<nsINode> parent2 = do_QueryInterface(aParent2); 1.2057 + NS_ENSURE_TRUE(parent1 && parent2, -1); 1.2058 + return ComparePoints(parent1, aOffset1, parent2, aOffset2); 1.2059 +} 1.2060 + 1.2061 +inline bool 1.2062 +IsCharInSet(const char* aSet, 1.2063 + const char16_t aChar) 1.2064 +{ 1.2065 + char16_t ch; 1.2066 + while ((ch = *aSet)) { 1.2067 + if (aChar == char16_t(ch)) { 1.2068 + return true; 1.2069 + } 1.2070 + ++aSet; 1.2071 + } 1.2072 + return false; 1.2073 +} 1.2074 + 1.2075 +/** 1.2076 + * This method strips leading/trailing chars, in given set, from string. 1.2077 + */ 1.2078 + 1.2079 +// static 1.2080 +const nsDependentSubstring 1.2081 +nsContentUtils::TrimCharsInSet(const char* aSet, 1.2082 + const nsAString& aValue) 1.2083 +{ 1.2084 + nsAString::const_iterator valueCurrent, valueEnd; 1.2085 + 1.2086 + aValue.BeginReading(valueCurrent); 1.2087 + aValue.EndReading(valueEnd); 1.2088 + 1.2089 + // Skip characters in the beginning 1.2090 + while (valueCurrent != valueEnd) { 1.2091 + if (!IsCharInSet(aSet, *valueCurrent)) { 1.2092 + break; 1.2093 + } 1.2094 + ++valueCurrent; 1.2095 + } 1.2096 + 1.2097 + if (valueCurrent != valueEnd) { 1.2098 + for (;;) { 1.2099 + --valueEnd; 1.2100 + if (!IsCharInSet(aSet, *valueEnd)) { 1.2101 + break; 1.2102 + } 1.2103 + } 1.2104 + ++valueEnd; // Step beyond the last character we want in the value. 1.2105 + } 1.2106 + 1.2107 + // valueEnd should point to the char after the last to copy 1.2108 + return Substring(valueCurrent, valueEnd); 1.2109 +} 1.2110 + 1.2111 +/** 1.2112 + * This method strips leading and trailing whitespace from a string. 1.2113 + */ 1.2114 + 1.2115 +// static 1.2116 +template<bool IsWhitespace(char16_t)> 1.2117 +const nsDependentSubstring 1.2118 +nsContentUtils::TrimWhitespace(const nsAString& aStr, bool aTrimTrailing) 1.2119 +{ 1.2120 + nsAString::const_iterator start, end; 1.2121 + 1.2122 + aStr.BeginReading(start); 1.2123 + aStr.EndReading(end); 1.2124 + 1.2125 + // Skip whitespace characters in the beginning 1.2126 + while (start != end && IsWhitespace(*start)) { 1.2127 + ++start; 1.2128 + } 1.2129 + 1.2130 + if (aTrimTrailing) { 1.2131 + // Skip whitespace characters in the end. 1.2132 + while (end != start) { 1.2133 + --end; 1.2134 + 1.2135 + if (!IsWhitespace(*end)) { 1.2136 + // Step back to the last non-whitespace character. 1.2137 + ++end; 1.2138 + 1.2139 + break; 1.2140 + } 1.2141 + } 1.2142 + } 1.2143 + 1.2144 + // Return a substring for the string w/o leading and/or trailing 1.2145 + // whitespace 1.2146 + 1.2147 + return Substring(start, end); 1.2148 +} 1.2149 + 1.2150 +// Declaring the templates we are going to use avoid linking issues without 1.2151 +// inlining the method. Considering there is not so much spaces checking 1.2152 +// methods we can consider this to be better than inlining. 1.2153 +template 1.2154 +const nsDependentSubstring 1.2155 +nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(const nsAString&, bool); 1.2156 +template 1.2157 +const nsDependentSubstring 1.2158 +nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(const nsAString&, bool); 1.2159 +template 1.2160 +const nsDependentSubstring 1.2161 +nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespaceOrNBSP>(const nsAString&, bool); 1.2162 + 1.2163 +static inline void KeyAppendSep(nsACString& aKey) 1.2164 +{ 1.2165 + if (!aKey.IsEmpty()) { 1.2166 + aKey.Append('>'); 1.2167 + } 1.2168 +} 1.2169 + 1.2170 +static inline void KeyAppendString(const nsAString& aString, nsACString& aKey) 1.2171 +{ 1.2172 + KeyAppendSep(aKey); 1.2173 + 1.2174 + // Could escape separator here if collisions happen. > is not a legal char 1.2175 + // for a name or type attribute, so we should be safe avoiding that extra work. 1.2176 + 1.2177 + AppendUTF16toUTF8(aString, aKey); 1.2178 +} 1.2179 + 1.2180 +static inline void KeyAppendString(const nsACString& aString, nsACString& aKey) 1.2181 +{ 1.2182 + KeyAppendSep(aKey); 1.2183 + 1.2184 + // Could escape separator here if collisions happen. > is not a legal char 1.2185 + // for a name or type attribute, so we should be safe avoiding that extra work. 1.2186 + 1.2187 + aKey.Append(aString); 1.2188 +} 1.2189 + 1.2190 +static inline void KeyAppendInt(int32_t aInt, nsACString& aKey) 1.2191 +{ 1.2192 + KeyAppendSep(aKey); 1.2193 + 1.2194 + aKey.Append(nsPrintfCString("%d", aInt)); 1.2195 +} 1.2196 + 1.2197 +static inline bool IsAutocompleteOff(const nsIContent* aElement) 1.2198 +{ 1.2199 + return aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::autocomplete, 1.2200 + NS_LITERAL_STRING("off"), eIgnoreCase); 1.2201 +} 1.2202 + 1.2203 +/*static*/ nsresult 1.2204 +nsContentUtils::GenerateStateKey(nsIContent* aContent, 1.2205 + const nsIDocument* aDocument, 1.2206 + nsACString& aKey) 1.2207 +{ 1.2208 + aKey.Truncate(); 1.2209 + 1.2210 + uint32_t partID = aDocument ? aDocument->GetPartID() : 0; 1.2211 + 1.2212 + // We must have content if we're not using a special state id 1.2213 + NS_ENSURE_TRUE(aContent, NS_ERROR_FAILURE); 1.2214 + 1.2215 + // Don't capture state for anonymous content 1.2216 + if (aContent->IsInAnonymousSubtree()) { 1.2217 + return NS_OK; 1.2218 + } 1.2219 + 1.2220 + if (IsAutocompleteOff(aContent)) { 1.2221 + return NS_OK; 1.2222 + } 1.2223 + 1.2224 + nsCOMPtr<nsIHTMLDocument> htmlDocument(do_QueryInterface(aContent->GetCurrentDoc())); 1.2225 + 1.2226 + KeyAppendInt(partID, aKey); // first append a partID 1.2227 + bool generatedUniqueKey = false; 1.2228 + 1.2229 + if (htmlDocument) { 1.2230 + // Flush our content model so it'll be up to date 1.2231 + // If this becomes unnecessary and the following line is removed, 1.2232 + // please also remove the corresponding flush operation from 1.2233 + // nsHtml5TreeBuilderCppSupplement.h. (Look for "See bug 497861." there.) 1.2234 + aContent->GetCurrentDoc()->FlushPendingNotifications(Flush_Content); 1.2235 + 1.2236 + nsContentList *htmlForms = htmlDocument->GetForms(); 1.2237 + nsContentList *htmlFormControls = htmlDocument->GetFormControls(); 1.2238 + 1.2239 + NS_ENSURE_TRUE(htmlForms && htmlFormControls, NS_ERROR_OUT_OF_MEMORY); 1.2240 + 1.2241 + // If we have a form control and can calculate form information, use that 1.2242 + // as the key - it is more reliable than just recording position in the 1.2243 + // DOM. 1.2244 + // XXXbz Is it, really? We have bugs on this, I think... 1.2245 + // Important to have a unique key, and tag/type/name may not be. 1.2246 + // 1.2247 + // If the control has a form, the format of the key is: 1.2248 + // f>type>IndOfFormInDoc>IndOfControlInForm>FormName>name 1.2249 + // else: 1.2250 + // d>type>IndOfControlInDoc>name 1.2251 + // 1.2252 + // XXX We don't need to use index if name is there 1.2253 + // XXXbz We don't? Why not? I don't follow. 1.2254 + // 1.2255 + nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent)); 1.2256 + if (control && htmlFormControls && htmlForms) { 1.2257 + 1.2258 + // Append the control type 1.2259 + KeyAppendInt(control->GetType(), aKey); 1.2260 + 1.2261 + // If in a form, add form name / index of form / index in form 1.2262 + int32_t index = -1; 1.2263 + Element *formElement = control->GetFormElement(); 1.2264 + if (formElement) { 1.2265 + if (IsAutocompleteOff(formElement)) { 1.2266 + aKey.Truncate(); 1.2267 + return NS_OK; 1.2268 + } 1.2269 + 1.2270 + KeyAppendString(NS_LITERAL_CSTRING("f"), aKey); 1.2271 + 1.2272 + // Append the index of the form in the document 1.2273 + index = htmlForms->IndexOf(formElement, false); 1.2274 + if (index <= -1) { 1.2275 + // 1.2276 + // XXX HACK this uses some state that was dumped into the document 1.2277 + // specifically to fix bug 138892. What we are trying to do is *guess* 1.2278 + // which form this control's state is found in, with the highly likely 1.2279 + // guess that the highest form parsed so far is the one. 1.2280 + // This code should not be on trunk, only branch. 1.2281 + // 1.2282 + index = htmlDocument->GetNumFormsSynchronous() - 1; 1.2283 + } 1.2284 + if (index > -1) { 1.2285 + KeyAppendInt(index, aKey); 1.2286 + 1.2287 + // Append the index of the control in the form 1.2288 + nsCOMPtr<nsIForm> form(do_QueryInterface(formElement)); 1.2289 + index = form->IndexOfControl(control); 1.2290 + 1.2291 + if (index > -1) { 1.2292 + KeyAppendInt(index, aKey); 1.2293 + generatedUniqueKey = true; 1.2294 + } 1.2295 + } 1.2296 + 1.2297 + // Append the form name 1.2298 + nsAutoString formName; 1.2299 + formElement->GetAttr(kNameSpaceID_None, nsGkAtoms::name, formName); 1.2300 + KeyAppendString(formName, aKey); 1.2301 + 1.2302 + } else { 1.2303 + 1.2304 + KeyAppendString(NS_LITERAL_CSTRING("d"), aKey); 1.2305 + 1.2306 + // If not in a form, add index of control in document 1.2307 + // Less desirable than indexing by form info. 1.2308 + 1.2309 + // Hash by index of control in doc (we are not in a form) 1.2310 + // These are important as they are unique, and type/name may not be. 1.2311 + 1.2312 + // We have to flush sink notifications at this point to make 1.2313 + // sure that htmlFormControls is up to date. 1.2314 + index = htmlFormControls->IndexOf(aContent, true); 1.2315 + if (index > -1) { 1.2316 + KeyAppendInt(index, aKey); 1.2317 + generatedUniqueKey = true; 1.2318 + } 1.2319 + } 1.2320 + 1.2321 + // Append the control name 1.2322 + nsAutoString name; 1.2323 + aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); 1.2324 + KeyAppendString(name, aKey); 1.2325 + } 1.2326 + } 1.2327 + 1.2328 + if (!generatedUniqueKey) { 1.2329 + // Either we didn't have a form control or we aren't in an HTML document so 1.2330 + // we can't figure out form info. Append the tag name if it's an element 1.2331 + // to avoid restoring state for one type of element on another type. 1.2332 + if (aContent->IsElement()) { 1.2333 + KeyAppendString(nsDependentAtomString(aContent->Tag()), aKey); 1.2334 + } 1.2335 + else { 1.2336 + // Append a character that is not "d" or "f" to disambiguate from 1.2337 + // the case when we were a form control in an HTML document. 1.2338 + KeyAppendString(NS_LITERAL_CSTRING("o"), aKey); 1.2339 + } 1.2340 + 1.2341 + // Now start at aContent and append the indices of it and all its ancestors 1.2342 + // in their containers. That should at least pin down its position in the 1.2343 + // DOM... 1.2344 + nsINode* parent = aContent->GetParentNode(); 1.2345 + nsINode* content = aContent; 1.2346 + while (parent) { 1.2347 + KeyAppendInt(parent->IndexOf(content), aKey); 1.2348 + content = parent; 1.2349 + parent = content->GetParentNode(); 1.2350 + } 1.2351 + } 1.2352 + 1.2353 + return NS_OK; 1.2354 +} 1.2355 + 1.2356 +// static 1.2357 +nsIPrincipal* 1.2358 +nsContentUtils::GetSubjectPrincipal() 1.2359 +{ 1.2360 + nsCOMPtr<nsIPrincipal> subject; 1.2361 + sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subject)); 1.2362 + 1.2363 + // When the ssm says the subject is null, that means system principal. 1.2364 + if (!subject) 1.2365 + sSecurityManager->GetSystemPrincipal(getter_AddRefs(subject)); 1.2366 + 1.2367 + return subject; 1.2368 +} 1.2369 + 1.2370 +// static 1.2371 +nsIPrincipal* 1.2372 +nsContentUtils::GetObjectPrincipal(JSObject* aObj) 1.2373 +{ 1.2374 + // This is duplicated from nsScriptSecurityManager. We don't call through there 1.2375 + // because the API unnecessarily requires a JSContext for historical reasons. 1.2376 + JSCompartment *compartment = js::GetObjectCompartment(aObj); 1.2377 + JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment); 1.2378 + return nsJSPrincipals::get(principals); 1.2379 +} 1.2380 + 1.2381 +// static 1.2382 +nsresult 1.2383 +nsContentUtils::NewURIWithDocumentCharset(nsIURI** aResult, 1.2384 + const nsAString& aSpec, 1.2385 + nsIDocument* aDocument, 1.2386 + nsIURI* aBaseURI) 1.2387 +{ 1.2388 + return NS_NewURI(aResult, aSpec, 1.2389 + aDocument ? aDocument->GetDocumentCharacterSet().get() : nullptr, 1.2390 + aBaseURI, sIOService); 1.2391 +} 1.2392 + 1.2393 +// static 1.2394 +bool 1.2395 +nsContentUtils::IsCustomElementName(nsIAtom* aName) 1.2396 +{ 1.2397 + // The custom element name identifies a custom element and is a sequence of 1.2398 + // alphanumeric ASCII characters that must match the NCName production and 1.2399 + // contain a U+002D HYPHEN-MINUS character. 1.2400 + nsDependentAtomString str(aName); 1.2401 + const char16_t* colon; 1.2402 + if (NS_FAILED(nsContentUtils::CheckQName(str, false, &colon)) || colon || 1.2403 + str.FindChar('-') == -1) { 1.2404 + return false; 1.2405 + } 1.2406 + 1.2407 + // The custom element name must not be one of the following values: 1.2408 + // annotation-xml 1.2409 + // color-profile 1.2410 + // font-face 1.2411 + // font-face-src 1.2412 + // font-face-uri 1.2413 + // font-face-format 1.2414 + // font-face-name 1.2415 + // missing-glyph 1.2416 + return aName != nsGkAtoms::annotation_xml_ && 1.2417 + aName != nsGkAtoms::colorProfile && 1.2418 + aName != nsGkAtoms::font_face && 1.2419 + aName != nsGkAtoms::font_face_src && 1.2420 + aName != nsGkAtoms::font_face_uri && 1.2421 + aName != nsGkAtoms::font_face_format && 1.2422 + aName != nsGkAtoms::font_face_name && 1.2423 + aName != nsGkAtoms::missingGlyph; 1.2424 +} 1.2425 + 1.2426 +// static 1.2427 +nsresult 1.2428 +nsContentUtils::CheckQName(const nsAString& aQualifiedName, 1.2429 + bool aNamespaceAware, 1.2430 + const char16_t** aColon) 1.2431 +{ 1.2432 + const char* colon = nullptr; 1.2433 + const char16_t* begin = aQualifiedName.BeginReading(); 1.2434 + const char16_t* end = aQualifiedName.EndReading(); 1.2435 + 1.2436 + int result = MOZ_XMLCheckQName(reinterpret_cast<const char*>(begin), 1.2437 + reinterpret_cast<const char*>(end), 1.2438 + aNamespaceAware, &colon); 1.2439 + 1.2440 + if (!result) { 1.2441 + if (aColon) { 1.2442 + *aColon = reinterpret_cast<const char16_t*>(colon); 1.2443 + } 1.2444 + 1.2445 + return NS_OK; 1.2446 + } 1.2447 + 1.2448 + // MOZ_EXPAT_EMPTY_QNAME || MOZ_EXPAT_INVALID_CHARACTER 1.2449 + if (result == (1 << 0) || result == (1 << 1)) { 1.2450 + return NS_ERROR_DOM_INVALID_CHARACTER_ERR; 1.2451 + } 1.2452 + 1.2453 + return NS_ERROR_DOM_NAMESPACE_ERR; 1.2454 +} 1.2455 + 1.2456 +//static 1.2457 +nsresult 1.2458 +nsContentUtils::SplitQName(const nsIContent* aNamespaceResolver, 1.2459 + const nsAFlatString& aQName, 1.2460 + int32_t *aNamespace, nsIAtom **aLocalName) 1.2461 +{ 1.2462 + const char16_t* colon; 1.2463 + nsresult rv = nsContentUtils::CheckQName(aQName, true, &colon); 1.2464 + NS_ENSURE_SUCCESS(rv, rv); 1.2465 + 1.2466 + if (colon) { 1.2467 + const char16_t* end; 1.2468 + aQName.EndReading(end); 1.2469 + nsAutoString nameSpace; 1.2470 + rv = aNamespaceResolver->LookupNamespaceURIInternal(Substring(aQName.get(), 1.2471 + colon), 1.2472 + nameSpace); 1.2473 + NS_ENSURE_SUCCESS(rv, rv); 1.2474 + 1.2475 + *aNamespace = NameSpaceManager()->GetNameSpaceID(nameSpace); 1.2476 + if (*aNamespace == kNameSpaceID_Unknown) 1.2477 + return NS_ERROR_FAILURE; 1.2478 + 1.2479 + *aLocalName = NS_NewAtom(Substring(colon + 1, end)).take(); 1.2480 + } 1.2481 + else { 1.2482 + *aNamespace = kNameSpaceID_None; 1.2483 + *aLocalName = NS_NewAtom(aQName).take(); 1.2484 + } 1.2485 + NS_ENSURE_TRUE(aLocalName, NS_ERROR_OUT_OF_MEMORY); 1.2486 + return NS_OK; 1.2487 +} 1.2488 + 1.2489 +// static 1.2490 +nsresult 1.2491 +nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI, 1.2492 + const nsAString& aQualifiedName, 1.2493 + nsNodeInfoManager* aNodeInfoManager, 1.2494 + uint16_t aNodeType, 1.2495 + nsINodeInfo** aNodeInfo) 1.2496 +{ 1.2497 + const nsAFlatString& qName = PromiseFlatString(aQualifiedName); 1.2498 + const char16_t* colon; 1.2499 + nsresult rv = nsContentUtils::CheckQName(qName, true, &colon); 1.2500 + NS_ENSURE_SUCCESS(rv, rv); 1.2501 + 1.2502 + int32_t nsID; 1.2503 + sNameSpaceManager->RegisterNameSpace(aNamespaceURI, nsID); 1.2504 + if (colon) { 1.2505 + const char16_t* end; 1.2506 + qName.EndReading(end); 1.2507 + 1.2508 + nsCOMPtr<nsIAtom> prefix = do_GetAtom(Substring(qName.get(), colon)); 1.2509 + 1.2510 + rv = aNodeInfoManager->GetNodeInfo(Substring(colon + 1, end), prefix, 1.2511 + nsID, aNodeType, aNodeInfo); 1.2512 + } 1.2513 + else { 1.2514 + rv = aNodeInfoManager->GetNodeInfo(aQualifiedName, nullptr, nsID, 1.2515 + aNodeType, aNodeInfo); 1.2516 + } 1.2517 + NS_ENSURE_SUCCESS(rv, rv); 1.2518 + 1.2519 + return nsContentUtils::IsValidNodeName((*aNodeInfo)->NameAtom(), 1.2520 + (*aNodeInfo)->GetPrefixAtom(), 1.2521 + (*aNodeInfo)->NamespaceID()) ? 1.2522 + NS_OK : NS_ERROR_DOM_NAMESPACE_ERR; 1.2523 +} 1.2524 + 1.2525 +// static 1.2526 +void 1.2527 +nsContentUtils::SplitExpatName(const char16_t *aExpatName, nsIAtom **aPrefix, 1.2528 + nsIAtom **aLocalName, int32_t* aNameSpaceID) 1.2529 +{ 1.2530 + /** 1.2531 + * Expat can send the following: 1.2532 + * localName 1.2533 + * namespaceURI<separator>localName 1.2534 + * namespaceURI<separator>localName<separator>prefix 1.2535 + * 1.2536 + * and we use 0xFFFF for the <separator>. 1.2537 + * 1.2538 + */ 1.2539 + 1.2540 + const char16_t *uriEnd = nullptr; 1.2541 + const char16_t *nameEnd = nullptr; 1.2542 + const char16_t *pos; 1.2543 + for (pos = aExpatName; *pos; ++pos) { 1.2544 + if (*pos == 0xFFFF) { 1.2545 + if (uriEnd) { 1.2546 + nameEnd = pos; 1.2547 + } 1.2548 + else { 1.2549 + uriEnd = pos; 1.2550 + } 1.2551 + } 1.2552 + } 1.2553 + 1.2554 + const char16_t *nameStart; 1.2555 + if (uriEnd) { 1.2556 + if (sNameSpaceManager) { 1.2557 + sNameSpaceManager->RegisterNameSpace(nsDependentSubstring(aExpatName, 1.2558 + uriEnd), 1.2559 + *aNameSpaceID); 1.2560 + } 1.2561 + else { 1.2562 + *aNameSpaceID = kNameSpaceID_Unknown; 1.2563 + } 1.2564 + 1.2565 + nameStart = (uriEnd + 1); 1.2566 + if (nameEnd) { 1.2567 + const char16_t *prefixStart = nameEnd + 1; 1.2568 + *aPrefix = NS_NewAtom(Substring(prefixStart, pos)).take(); 1.2569 + } 1.2570 + else { 1.2571 + nameEnd = pos; 1.2572 + *aPrefix = nullptr; 1.2573 + } 1.2574 + } 1.2575 + else { 1.2576 + *aNameSpaceID = kNameSpaceID_None; 1.2577 + nameStart = aExpatName; 1.2578 + nameEnd = pos; 1.2579 + *aPrefix = nullptr; 1.2580 + } 1.2581 + *aLocalName = NS_NewAtom(Substring(nameStart, nameEnd)).take(); 1.2582 +} 1.2583 + 1.2584 +// static 1.2585 +nsPresContext* 1.2586 +nsContentUtils::GetContextForContent(const nsIContent* aContent) 1.2587 +{ 1.2588 + nsIDocument* doc = aContent->GetCurrentDoc(); 1.2589 + if (doc) { 1.2590 + nsIPresShell *presShell = doc->GetShell(); 1.2591 + if (presShell) { 1.2592 + return presShell->GetPresContext(); 1.2593 + } 1.2594 + } 1.2595 + return nullptr; 1.2596 +} 1.2597 + 1.2598 +// static 1.2599 +bool 1.2600 +nsContentUtils::CanLoadImage(nsIURI* aURI, nsISupports* aContext, 1.2601 + nsIDocument* aLoadingDocument, 1.2602 + nsIPrincipal* aLoadingPrincipal, 1.2603 + int16_t* aImageBlockingStatus) 1.2604 +{ 1.2605 + NS_PRECONDITION(aURI, "Must have a URI"); 1.2606 + NS_PRECONDITION(aLoadingDocument, "Must have a document"); 1.2607 + NS_PRECONDITION(aLoadingPrincipal, "Must have a loading principal"); 1.2608 + 1.2609 + nsresult rv; 1.2610 + 1.2611 + uint32_t appType = nsIDocShell::APP_TYPE_UNKNOWN; 1.2612 + 1.2613 + { 1.2614 + nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = aLoadingDocument->GetDocShell(); 1.2615 + if (docShellTreeItem) { 1.2616 + nsCOMPtr<nsIDocShellTreeItem> root; 1.2617 + docShellTreeItem->GetRootTreeItem(getter_AddRefs(root)); 1.2618 + 1.2619 + nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root)); 1.2620 + 1.2621 + if (!docShell || NS_FAILED(docShell->GetAppType(&appType))) { 1.2622 + appType = nsIDocShell::APP_TYPE_UNKNOWN; 1.2623 + } 1.2624 + } 1.2625 + } 1.2626 + 1.2627 + if (appType != nsIDocShell::APP_TYPE_EDITOR) { 1.2628 + // Editor apps get special treatment here, editors can load images 1.2629 + // from anywhere. This allows editor to insert images from file:// 1.2630 + // into documents that are being edited. 1.2631 + rv = sSecurityManager-> 1.2632 + CheckLoadURIWithPrincipal(aLoadingPrincipal, aURI, 1.2633 + nsIScriptSecurityManager::ALLOW_CHROME); 1.2634 + if (NS_FAILED(rv)) { 1.2635 + if (aImageBlockingStatus) { 1.2636 + // Reject the request itself, not all requests to the relevant 1.2637 + // server... 1.2638 + *aImageBlockingStatus = nsIContentPolicy::REJECT_REQUEST; 1.2639 + } 1.2640 + return false; 1.2641 + } 1.2642 + } 1.2643 + 1.2644 + int16_t decision = nsIContentPolicy::ACCEPT; 1.2645 + 1.2646 + rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_IMAGE, 1.2647 + aURI, 1.2648 + aLoadingPrincipal, 1.2649 + aContext, 1.2650 + EmptyCString(), //mime guess 1.2651 + nullptr, //extra 1.2652 + &decision, 1.2653 + GetContentPolicy(), 1.2654 + sSecurityManager); 1.2655 + 1.2656 + if (aImageBlockingStatus) { 1.2657 + *aImageBlockingStatus = 1.2658 + NS_FAILED(rv) ? nsIContentPolicy::REJECT_REQUEST : decision; 1.2659 + } 1.2660 + return NS_FAILED(rv) ? false : NS_CP_ACCEPTED(decision); 1.2661 +} 1.2662 + 1.2663 +imgLoader* 1.2664 +nsContentUtils::GetImgLoaderForDocument(nsIDocument* aDoc) 1.2665 +{ 1.2666 + if (!aDoc) 1.2667 + return imgLoader::Singleton(); 1.2668 + bool isPrivate = false; 1.2669 + nsCOMPtr<nsILoadGroup> loadGroup = aDoc->GetDocumentLoadGroup(); 1.2670 + nsCOMPtr<nsIInterfaceRequestor> callbacks; 1.2671 + if (loadGroup) { 1.2672 + loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks)); 1.2673 + if (callbacks) { 1.2674 + nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks); 1.2675 + isPrivate = loadContext && loadContext->UsePrivateBrowsing(); 1.2676 + } 1.2677 + } else { 1.2678 + nsCOMPtr<nsIChannel> channel = aDoc->GetChannel(); 1.2679 + isPrivate = channel && NS_UsePrivateBrowsing(channel); 1.2680 + } 1.2681 + return isPrivate ? imgLoader::PBSingleton() : imgLoader::Singleton(); 1.2682 +} 1.2683 + 1.2684 +// static 1.2685 +imgLoader* 1.2686 +nsContentUtils::GetImgLoaderForChannel(nsIChannel* aChannel) 1.2687 +{ 1.2688 + if (!aChannel) 1.2689 + return imgLoader::Singleton(); 1.2690 + nsCOMPtr<nsILoadContext> context; 1.2691 + NS_QueryNotificationCallbacks(aChannel, context); 1.2692 + return context && context->UsePrivateBrowsing() ? imgLoader::PBSingleton() : imgLoader::Singleton(); 1.2693 +} 1.2694 + 1.2695 +// static 1.2696 +bool 1.2697 +nsContentUtils::IsImageInCache(nsIURI* aURI, nsIDocument* aDocument) 1.2698 +{ 1.2699 + imgILoader* loader = GetImgLoaderForDocument(aDocument); 1.2700 + nsCOMPtr<imgICache> cache = do_QueryInterface(loader); 1.2701 + 1.2702 + // If something unexpected happened we return false, otherwise if props 1.2703 + // is set, the image is cached and we return true 1.2704 + nsCOMPtr<nsIProperties> props; 1.2705 + nsresult rv = cache->FindEntryProperties(aURI, getter_AddRefs(props)); 1.2706 + return (NS_SUCCEEDED(rv) && props); 1.2707 +} 1.2708 + 1.2709 +// static 1.2710 +nsresult 1.2711 +nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument, 1.2712 + nsIPrincipal* aLoadingPrincipal, nsIURI* aReferrer, 1.2713 + imgINotificationObserver* aObserver, int32_t aLoadFlags, 1.2714 + const nsAString& initiatorType, 1.2715 + imgRequestProxy** aRequest) 1.2716 +{ 1.2717 + NS_PRECONDITION(aURI, "Must have a URI"); 1.2718 + NS_PRECONDITION(aLoadingDocument, "Must have a document"); 1.2719 + NS_PRECONDITION(aLoadingPrincipal, "Must have a principal"); 1.2720 + NS_PRECONDITION(aRequest, "Null out param"); 1.2721 + 1.2722 + imgLoader* imgLoader = GetImgLoaderForDocument(aLoadingDocument); 1.2723 + if (!imgLoader) { 1.2724 + // nothing we can do here 1.2725 + return NS_OK; 1.2726 + } 1.2727 + 1.2728 + nsCOMPtr<nsILoadGroup> loadGroup = aLoadingDocument->GetDocumentLoadGroup(); 1.2729 + 1.2730 + nsIURI *documentURI = aLoadingDocument->GetDocumentURI(); 1.2731 + 1.2732 + NS_ASSERTION(loadGroup || IsFontTableURI(documentURI), 1.2733 + "Could not get loadgroup; onload may fire too early"); 1.2734 + 1.2735 + // check for a Content Security Policy to pass down to the channel that 1.2736 + // will get created to load the image 1.2737 + nsCOMPtr<nsIChannelPolicy> channelPolicy; 1.2738 + nsCOMPtr<nsIContentSecurityPolicy> csp; 1.2739 + if (aLoadingPrincipal) { 1.2740 + nsresult rv = aLoadingPrincipal->GetCsp(getter_AddRefs(csp)); 1.2741 + NS_ENSURE_SUCCESS(rv, rv); 1.2742 + if (csp) { 1.2743 + channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); 1.2744 + channelPolicy->SetContentSecurityPolicy(csp); 1.2745 + channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE); 1.2746 + } 1.2747 + } 1.2748 + 1.2749 + // Make the URI immutable so people won't change it under us 1.2750 + NS_TryToSetImmutable(aURI); 1.2751 + 1.2752 + nsCOMPtr<nsIURI> firstPartyIsolationURI; 1.2753 + nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc 1.2754 + = do_GetService(THIRDPARTYUTIL_CONTRACTID); 1.2755 + thirdPartySvc->GetFirstPartyIsolationURI(nullptr, aLoadingDocument, 1.2756 + getter_AddRefs(firstPartyIsolationURI)); 1.2757 + 1.2758 + return imgLoader->LoadImage(aURI, /* uri to load */ 1.2759 + firstPartyIsolationURI, /* firstPartyIsolationURI */ 1.2760 + aReferrer, /* referrer */ 1.2761 + aLoadingPrincipal, /* loading principal */ 1.2762 + loadGroup, /* loadgroup */ 1.2763 + aObserver, /* imgINotificationObserver */ 1.2764 + aLoadingDocument, /* uniquification key */ 1.2765 + aLoadFlags, /* load flags */ 1.2766 + nullptr, /* cache key */ 1.2767 + channelPolicy, /* CSP info */ 1.2768 + initiatorType, /* the load initiator */ 1.2769 + aRequest); 1.2770 +} 1.2771 + 1.2772 +// static 1.2773 +already_AddRefed<imgIContainer> 1.2774 +nsContentUtils::GetImageFromContent(nsIImageLoadingContent* aContent, 1.2775 + imgIRequest **aRequest) 1.2776 +{ 1.2777 + if (aRequest) { 1.2778 + *aRequest = nullptr; 1.2779 + } 1.2780 + 1.2781 + NS_ENSURE_TRUE(aContent, nullptr); 1.2782 + 1.2783 + nsCOMPtr<imgIRequest> imgRequest; 1.2784 + aContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, 1.2785 + getter_AddRefs(imgRequest)); 1.2786 + if (!imgRequest) { 1.2787 + return nullptr; 1.2788 + } 1.2789 + 1.2790 + nsCOMPtr<imgIContainer> imgContainer; 1.2791 + imgRequest->GetImage(getter_AddRefs(imgContainer)); 1.2792 + 1.2793 + if (!imgContainer) { 1.2794 + return nullptr; 1.2795 + } 1.2796 + 1.2797 + if (aRequest) { 1.2798 + imgRequest.swap(*aRequest); 1.2799 + } 1.2800 + 1.2801 + return imgContainer.forget(); 1.2802 +} 1.2803 + 1.2804 +//static 1.2805 +already_AddRefed<imgRequestProxy> 1.2806 +nsContentUtils::GetStaticRequest(imgRequestProxy* aRequest) 1.2807 +{ 1.2808 + NS_ENSURE_TRUE(aRequest, nullptr); 1.2809 + nsRefPtr<imgRequestProxy> retval; 1.2810 + aRequest->GetStaticRequest(getter_AddRefs(retval)); 1.2811 + return retval.forget(); 1.2812 +} 1.2813 + 1.2814 +// static 1.2815 +bool 1.2816 +nsContentUtils::ContentIsDraggable(nsIContent* aContent) 1.2817 +{ 1.2818 + nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(aContent); 1.2819 + if (htmlElement) { 1.2820 + bool draggable = false; 1.2821 + htmlElement->GetDraggable(&draggable); 1.2822 + if (draggable) 1.2823 + return true; 1.2824 + 1.2825 + if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable, 1.2826 + nsGkAtoms::_false, eIgnoreCase)) 1.2827 + return false; 1.2828 + } 1.2829 + 1.2830 + // special handling for content area image and link dragging 1.2831 + return IsDraggableImage(aContent) || IsDraggableLink(aContent); 1.2832 +} 1.2833 + 1.2834 +// static 1.2835 +bool 1.2836 +nsContentUtils::IsDraggableImage(nsIContent* aContent) 1.2837 +{ 1.2838 + NS_PRECONDITION(aContent, "Must have content node to test"); 1.2839 + 1.2840 + nsCOMPtr<nsIImageLoadingContent> imageContent(do_QueryInterface(aContent)); 1.2841 + if (!imageContent) { 1.2842 + return false; 1.2843 + } 1.2844 + 1.2845 + nsCOMPtr<imgIRequest> imgRequest; 1.2846 + imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, 1.2847 + getter_AddRefs(imgRequest)); 1.2848 + 1.2849 + // XXXbz It may be draggable even if the request resulted in an error. Why? 1.2850 + // Not sure; that's what the old nsContentAreaDragDrop/nsFrame code did. 1.2851 + return imgRequest != nullptr; 1.2852 +} 1.2853 + 1.2854 +// static 1.2855 +bool 1.2856 +nsContentUtils::IsDraggableLink(const nsIContent* aContent) { 1.2857 + nsCOMPtr<nsIURI> absURI; 1.2858 + return aContent->IsLink(getter_AddRefs(absURI)); 1.2859 +} 1.2860 + 1.2861 +// static 1.2862 +nsresult 1.2863 +nsContentUtils::NameChanged(nsINodeInfo* aNodeInfo, nsIAtom* aName, 1.2864 + nsINodeInfo** aResult) 1.2865 +{ 1.2866 + nsNodeInfoManager *niMgr = aNodeInfo->NodeInfoManager(); 1.2867 + 1.2868 + *aResult = niMgr->GetNodeInfo(aName, aNodeInfo->GetPrefixAtom(), 1.2869 + aNodeInfo->NamespaceID(), 1.2870 + aNodeInfo->NodeType(), 1.2871 + aNodeInfo->GetExtraName()).take(); 1.2872 + return NS_OK; 1.2873 +} 1.2874 + 1.2875 + 1.2876 +static bool 1.2877 +TestSitePerm(nsIPrincipal* aPrincipal, const char* aType, uint32_t aPerm, bool aExactHostMatch) 1.2878 +{ 1.2879 + if (!aPrincipal) { 1.2880 + // We always deny (i.e. don't allow) the permission if we don't have a 1.2881 + // principal. 1.2882 + return aPerm != nsIPermissionManager::ALLOW_ACTION; 1.2883 + } 1.2884 + 1.2885 + nsCOMPtr<nsIPermissionManager> permMgr = 1.2886 + do_GetService("@mozilla.org/permissionmanager;1"); 1.2887 + NS_ENSURE_TRUE(permMgr, false); 1.2888 + 1.2889 + uint32_t perm; 1.2890 + nsresult rv; 1.2891 + if (aExactHostMatch) { 1.2892 + rv = permMgr->TestExactPermissionFromPrincipal(aPrincipal, aType, &perm); 1.2893 + } else { 1.2894 + rv = permMgr->TestPermissionFromPrincipal(aPrincipal, aType, &perm); 1.2895 + } 1.2896 + NS_ENSURE_SUCCESS(rv, false); 1.2897 + 1.2898 + return perm == aPerm; 1.2899 +} 1.2900 + 1.2901 +bool 1.2902 +nsContentUtils::IsSitePermAllow(nsIPrincipal* aPrincipal, const char* aType) 1.2903 +{ 1.2904 + return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION, false); 1.2905 +} 1.2906 + 1.2907 +bool 1.2908 +nsContentUtils::IsSitePermDeny(nsIPrincipal* aPrincipal, const char* aType) 1.2909 +{ 1.2910 + return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION, false); 1.2911 +} 1.2912 + 1.2913 +bool 1.2914 +nsContentUtils::IsExactSitePermAllow(nsIPrincipal* aPrincipal, const char* aType) 1.2915 +{ 1.2916 + return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION, true); 1.2917 +} 1.2918 + 1.2919 +bool 1.2920 +nsContentUtils::IsExactSitePermDeny(nsIPrincipal* aPrincipal, const char* aType) 1.2921 +{ 1.2922 + return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION, true); 1.2923 +} 1.2924 + 1.2925 +static const char *gEventNames[] = {"event"}; 1.2926 +static const char *gSVGEventNames[] = {"evt"}; 1.2927 +// for b/w compat, the first name to onerror is still 'event', even though it 1.2928 +// is actually the error message. (pre this code, the other 2 were not avail.) 1.2929 +// XXXmarkh - a quick lxr shows no affected code - should we correct this? 1.2930 +static const char *gOnErrorNames[] = {"event", "source", "lineno"}; 1.2931 + 1.2932 +// static 1.2933 +void 1.2934 +nsContentUtils::GetEventArgNames(int32_t aNameSpaceID, 1.2935 + nsIAtom *aEventName, 1.2936 + uint32_t *aArgCount, 1.2937 + const char*** aArgArray) 1.2938 +{ 1.2939 +#define SET_EVENT_ARG_NAMES(names) \ 1.2940 + *aArgCount = sizeof(names)/sizeof(names[0]); \ 1.2941 + *aArgArray = names; 1.2942 + 1.2943 + // JSEventHandler is what does the arg magic for onerror, and it does 1.2944 + // not seem to take the namespace into account. So we let onerror in all 1.2945 + // namespaces get the 3 arg names. 1.2946 + if (aEventName == nsGkAtoms::onerror) { 1.2947 + SET_EVENT_ARG_NAMES(gOnErrorNames); 1.2948 + } else if (aNameSpaceID == kNameSpaceID_SVG) { 1.2949 + SET_EVENT_ARG_NAMES(gSVGEventNames); 1.2950 + } else { 1.2951 + SET_EVENT_ARG_NAMES(gEventNames); 1.2952 + } 1.2953 +} 1.2954 + 1.2955 +static const char gPropertiesFiles[nsContentUtils::PropertiesFile_COUNT][56] = { 1.2956 + // Must line up with the enum values in |PropertiesFile| enum. 1.2957 + "chrome://global/locale/css.properties", 1.2958 + "chrome://global/locale/xbl.properties", 1.2959 + "chrome://global/locale/xul.properties", 1.2960 + "chrome://global/locale/layout_errors.properties", 1.2961 + "chrome://global/locale/layout/HtmlForm.properties", 1.2962 + "chrome://global/locale/printing.properties", 1.2963 + "chrome://global/locale/dom/dom.properties", 1.2964 + "chrome://global/locale/layout/htmlparser.properties", 1.2965 + "chrome://global/locale/svg/svg.properties", 1.2966 + "chrome://branding/locale/brand.properties", 1.2967 + "chrome://global/locale/commonDialogs.properties", 1.2968 + "chrome://global/locale/mathml/mathml.properties", 1.2969 + "chrome://global/locale/security/security.properties" 1.2970 +}; 1.2971 + 1.2972 +/* static */ nsresult 1.2973 +nsContentUtils::EnsureStringBundle(PropertiesFile aFile) 1.2974 +{ 1.2975 + if (!sStringBundles[aFile]) { 1.2976 + if (!sStringBundleService) { 1.2977 + nsresult rv = 1.2978 + CallGetService(NS_STRINGBUNDLE_CONTRACTID, &sStringBundleService); 1.2979 + NS_ENSURE_SUCCESS(rv, rv); 1.2980 + } 1.2981 + nsIStringBundle *bundle; 1.2982 + nsresult rv = 1.2983 + sStringBundleService->CreateBundle(gPropertiesFiles[aFile], &bundle); 1.2984 + NS_ENSURE_SUCCESS(rv, rv); 1.2985 + sStringBundles[aFile] = bundle; // transfer ownership 1.2986 + } 1.2987 + return NS_OK; 1.2988 +} 1.2989 + 1.2990 +/* static */ 1.2991 +nsresult nsContentUtils::GetLocalizedString(PropertiesFile aFile, 1.2992 + const char* aKey, 1.2993 + nsXPIDLString& aResult) 1.2994 +{ 1.2995 + nsresult rv = EnsureStringBundle(aFile); 1.2996 + NS_ENSURE_SUCCESS(rv, rv); 1.2997 + nsIStringBundle *bundle = sStringBundles[aFile]; 1.2998 + 1.2999 + return bundle->GetStringFromName(NS_ConvertASCIItoUTF16(aKey).get(), 1.3000 + getter_Copies(aResult)); 1.3001 +} 1.3002 + 1.3003 +/* static */ 1.3004 +nsresult nsContentUtils::FormatLocalizedString(PropertiesFile aFile, 1.3005 + const char* aKey, 1.3006 + const char16_t **aParams, 1.3007 + uint32_t aParamsLength, 1.3008 + nsXPIDLString& aResult) 1.3009 +{ 1.3010 + nsresult rv = EnsureStringBundle(aFile); 1.3011 + NS_ENSURE_SUCCESS(rv, rv); 1.3012 + nsIStringBundle *bundle = sStringBundles[aFile]; 1.3013 + 1.3014 + return bundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aKey).get(), 1.3015 + aParams, aParamsLength, 1.3016 + getter_Copies(aResult)); 1.3017 +} 1.3018 + 1.3019 +/* static */ void 1.3020 +nsContentUtils::LogSimpleConsoleError(const nsAString& aErrorText, 1.3021 + const char * classification) 1.3022 +{ 1.3023 + nsCOMPtr<nsIScriptError> scriptError = 1.3024 + do_CreateInstance(NS_SCRIPTERROR_CONTRACTID); 1.3025 + if (scriptError) { 1.3026 + nsCOMPtr<nsIConsoleService> console = 1.3027 + do_GetService(NS_CONSOLESERVICE_CONTRACTID); 1.3028 + if (console && NS_SUCCEEDED(scriptError->Init(aErrorText, EmptyString(), 1.3029 + EmptyString(), 0, 0, 1.3030 + nsIScriptError::errorFlag, 1.3031 + classification))) { 1.3032 + console->LogMessage(scriptError); 1.3033 + } 1.3034 + } 1.3035 +} 1.3036 + 1.3037 +/* static */ nsresult 1.3038 +nsContentUtils::ReportToConsole(uint32_t aErrorFlags, 1.3039 + const nsACString& aCategory, 1.3040 + nsIDocument* aDocument, 1.3041 + PropertiesFile aFile, 1.3042 + const char *aMessageName, 1.3043 + const char16_t **aParams, 1.3044 + uint32_t aParamsLength, 1.3045 + nsIURI* aURI, 1.3046 + const nsAFlatString& aSourceLine, 1.3047 + uint32_t aLineNumber, 1.3048 + uint32_t aColumnNumber) 1.3049 +{ 1.3050 + NS_ASSERTION((aParams && aParamsLength) || (!aParams && !aParamsLength), 1.3051 + "Supply either both parameters and their number or no" 1.3052 + "parameters and 0."); 1.3053 + 1.3054 + nsresult rv; 1.3055 + nsXPIDLString errorText; 1.3056 + if (aParams) { 1.3057 + rv = FormatLocalizedString(aFile, aMessageName, aParams, aParamsLength, 1.3058 + errorText); 1.3059 + } 1.3060 + else { 1.3061 + rv = GetLocalizedString(aFile, aMessageName, errorText); 1.3062 + } 1.3063 + NS_ENSURE_SUCCESS(rv, rv); 1.3064 + 1.3065 + return ReportToConsoleNonLocalized(errorText, aErrorFlags, aCategory, 1.3066 + aDocument, aURI, aSourceLine, 1.3067 + aLineNumber, aColumnNumber); 1.3068 +} 1.3069 + 1.3070 + 1.3071 +/* static */ nsresult 1.3072 +nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText, 1.3073 + uint32_t aErrorFlags, 1.3074 + const nsACString& aCategory, 1.3075 + nsIDocument* aDocument, 1.3076 + nsIURI* aURI, 1.3077 + const nsAFlatString& aSourceLine, 1.3078 + uint32_t aLineNumber, 1.3079 + uint32_t aColumnNumber) 1.3080 +{ 1.3081 + uint64_t innerWindowID = 0; 1.3082 + if (aDocument) { 1.3083 + if (!aURI) { 1.3084 + aURI = aDocument->GetDocumentURI(); 1.3085 + } 1.3086 + innerWindowID = aDocument->InnerWindowID(); 1.3087 + } 1.3088 + 1.3089 + nsresult rv; 1.3090 + if (!sConsoleService) { // only need to bother null-checking here 1.3091 + rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService); 1.3092 + NS_ENSURE_SUCCESS(rv, rv); 1.3093 + } 1.3094 + 1.3095 + nsAutoCString spec; 1.3096 + if (!aLineNumber) { 1.3097 + JSContext *cx = GetCurrentJSContext(); 1.3098 + if (cx) { 1.3099 + const char* filename; 1.3100 + uint32_t lineno; 1.3101 + if (nsJSUtils::GetCallingLocation(cx, &filename, &lineno)) { 1.3102 + spec = filename; 1.3103 + aLineNumber = lineno; 1.3104 + } 1.3105 + } 1.3106 + } 1.3107 + if (spec.IsEmpty() && aURI) 1.3108 + aURI->GetSpec(spec); 1.3109 + 1.3110 + nsCOMPtr<nsIScriptError> errorObject = 1.3111 + do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv); 1.3112 + NS_ENSURE_SUCCESS(rv, rv); 1.3113 + 1.3114 + rv = errorObject->InitWithWindowID(aErrorText, 1.3115 + NS_ConvertUTF8toUTF16(spec), // file name 1.3116 + aSourceLine, 1.3117 + aLineNumber, aColumnNumber, 1.3118 + aErrorFlags, aCategory, 1.3119 + innerWindowID); 1.3120 + NS_ENSURE_SUCCESS(rv, rv); 1.3121 + 1.3122 + return sConsoleService->LogMessage(errorObject); 1.3123 +} 1.3124 + 1.3125 +void 1.3126 +nsContentUtils::LogMessageToConsole(const char* aMsg, ...) 1.3127 +{ 1.3128 + if (!sConsoleService) { // only need to bother null-checking here 1.3129 + CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService); 1.3130 + if (!sConsoleService) { 1.3131 + return; 1.3132 + } 1.3133 + } 1.3134 + 1.3135 + va_list args; 1.3136 + va_start(args, aMsg); 1.3137 + char* formatted = PR_vsmprintf(aMsg, args); 1.3138 + va_end(args); 1.3139 + if (!formatted) { 1.3140 + return; 1.3141 + } 1.3142 + 1.3143 + sConsoleService->LogStringMessage(NS_ConvertUTF8toUTF16(formatted).get()); 1.3144 + PR_smprintf_free(formatted); 1.3145 +} 1.3146 + 1.3147 +bool 1.3148 +nsContentUtils::IsChromeDoc(nsIDocument *aDocument) 1.3149 +{ 1.3150 + if (!aDocument) { 1.3151 + return false; 1.3152 + } 1.3153 + 1.3154 + nsCOMPtr<nsIPrincipal> systemPrincipal; 1.3155 + sSecurityManager->GetSystemPrincipal(getter_AddRefs(systemPrincipal)); 1.3156 + 1.3157 + return aDocument->NodePrincipal() == systemPrincipal; 1.3158 +} 1.3159 + 1.3160 +bool 1.3161 +nsContentUtils::IsChildOfSameType(nsIDocument* aDoc) 1.3162 +{ 1.3163 + nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(aDoc->GetDocShell()); 1.3164 + nsCOMPtr<nsIDocShellTreeItem> sameTypeParent; 1.3165 + if (docShellAsItem) { 1.3166 + docShellAsItem->GetSameTypeParent(getter_AddRefs(sameTypeParent)); 1.3167 + } 1.3168 + return sameTypeParent != nullptr; 1.3169 +} 1.3170 + 1.3171 +bool 1.3172 +nsContentUtils::IsPlainTextType(const nsACString& aContentType) 1.3173 +{ 1.3174 + return aContentType.EqualsLiteral(TEXT_PLAIN) || 1.3175 + aContentType.EqualsLiteral(TEXT_CSS) || 1.3176 + aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) || 1.3177 + aContentType.EqualsLiteral(APPLICATION_JAVASCRIPT) || 1.3178 + aContentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) || 1.3179 + aContentType.EqualsLiteral(TEXT_ECMASCRIPT) || 1.3180 + aContentType.EqualsLiteral(APPLICATION_ECMASCRIPT) || 1.3181 + aContentType.EqualsLiteral(TEXT_JAVASCRIPT) || 1.3182 + aContentType.EqualsLiteral(APPLICATION_JSON); 1.3183 +} 1.3184 + 1.3185 +bool 1.3186 +nsContentUtils::GetWrapperSafeScriptFilename(nsIDocument *aDocument, 1.3187 + nsIURI *aURI, 1.3188 + nsACString& aScriptURI) 1.3189 +{ 1.3190 + bool scriptFileNameModified = false; 1.3191 + aURI->GetSpec(aScriptURI); 1.3192 + 1.3193 + if (IsChromeDoc(aDocument)) { 1.3194 + nsCOMPtr<nsIChromeRegistry> chromeReg = 1.3195 + mozilla::services::GetChromeRegistryService(); 1.3196 + 1.3197 + if (!chromeReg) { 1.3198 + // If we're running w/o a chrome registry we won't modify any 1.3199 + // script file names. 1.3200 + 1.3201 + return scriptFileNameModified; 1.3202 + } 1.3203 + 1.3204 + bool docWrappersEnabled = 1.3205 + chromeReg->WrappersEnabled(aDocument->GetDocumentURI()); 1.3206 + 1.3207 + bool uriWrappersEnabled = chromeReg->WrappersEnabled(aURI); 1.3208 + 1.3209 + nsIURI *docURI = aDocument->GetDocumentURI(); 1.3210 + 1.3211 + if (docURI && docWrappersEnabled && !uriWrappersEnabled) { 1.3212 + // aURI is a script from a URL that doesn't get wrapper 1.3213 + // automation. aDocument is a chrome document that does get 1.3214 + // wrapper automation. Prepend the chrome document's URI 1.3215 + // followed by the string " -> " to the URI of the script we're 1.3216 + // loading here so that script in that URI gets the same wrapper 1.3217 + // automation that the chrome document expects. 1.3218 + nsAutoCString spec; 1.3219 + docURI->GetSpec(spec); 1.3220 + spec.AppendLiteral(" -> "); 1.3221 + spec.Append(aScriptURI); 1.3222 + 1.3223 + aScriptURI = spec; 1.3224 + 1.3225 + scriptFileNameModified = true; 1.3226 + } 1.3227 + } 1.3228 + 1.3229 + return scriptFileNameModified; 1.3230 +} 1.3231 + 1.3232 +// static 1.3233 +bool 1.3234 +nsContentUtils::IsInChromeDocshell(nsIDocument *aDocument) 1.3235 +{ 1.3236 + if (!aDocument) { 1.3237 + return false; 1.3238 + } 1.3239 + 1.3240 + if (aDocument->GetDisplayDocument()) { 1.3241 + return IsInChromeDocshell(aDocument->GetDisplayDocument()); 1.3242 + } 1.3243 + 1.3244 + nsCOMPtr<nsIDocShellTreeItem> docShell = aDocument->GetDocShell(); 1.3245 + if (!docShell) { 1.3246 + return false; 1.3247 + } 1.3248 + 1.3249 + return docShell->ItemType() == nsIDocShellTreeItem::typeChrome; 1.3250 +} 1.3251 + 1.3252 +// static 1.3253 +nsIContentPolicy* 1.3254 +nsContentUtils::GetContentPolicy() 1.3255 +{ 1.3256 + if (!sTriedToGetContentPolicy) { 1.3257 + CallGetService(NS_CONTENTPOLICY_CONTRACTID, &sContentPolicyService); 1.3258 + // It's OK to not have a content policy service 1.3259 + sTriedToGetContentPolicy = true; 1.3260 + } 1.3261 + 1.3262 + return sContentPolicyService; 1.3263 +} 1.3264 + 1.3265 +// static 1.3266 +bool 1.3267 +nsContentUtils::IsEventAttributeName(nsIAtom* aName, int32_t aType) 1.3268 +{ 1.3269 + const char16_t* name = aName->GetUTF16String(); 1.3270 + if (name[0] != 'o' || name[1] != 'n') 1.3271 + return false; 1.3272 + 1.3273 + EventNameMapping mapping; 1.3274 + return (sAtomEventTable->Get(aName, &mapping) && mapping.mType & aType); 1.3275 +} 1.3276 + 1.3277 +// static 1.3278 +uint32_t 1.3279 +nsContentUtils::GetEventId(nsIAtom* aName) 1.3280 +{ 1.3281 + if (aName) { 1.3282 + EventNameMapping mapping; 1.3283 + if (sAtomEventTable->Get(aName, &mapping)) { 1.3284 + return mapping.mId; 1.3285 + } 1.3286 + } 1.3287 + 1.3288 + return NS_USER_DEFINED_EVENT; 1.3289 +} 1.3290 + 1.3291 +// static 1.3292 +uint32_t 1.3293 +nsContentUtils::GetEventCategory(const nsAString& aName) 1.3294 +{ 1.3295 + EventNameMapping mapping; 1.3296 + if (sStringEventTable->Get(aName, &mapping)) 1.3297 + return mapping.mStructType; 1.3298 + 1.3299 + return NS_EVENT; 1.3300 +} 1.3301 + 1.3302 +nsIAtom* 1.3303 +nsContentUtils::GetEventIdAndAtom(const nsAString& aName, 1.3304 + uint32_t aEventStruct, 1.3305 + uint32_t* aEventID) 1.3306 +{ 1.3307 + EventNameMapping mapping; 1.3308 + if (sStringEventTable->Get(aName, &mapping)) { 1.3309 + *aEventID = 1.3310 + mapping.mStructType == aEventStruct ? mapping.mId : NS_USER_DEFINED_EVENT; 1.3311 + return mapping.mAtom; 1.3312 + } 1.3313 + 1.3314 + // If we have cached lots of user defined event names, clear some of them. 1.3315 + if (sUserDefinedEvents->Count() > 127) { 1.3316 + while (sUserDefinedEvents->Count() > 64) { 1.3317 + nsIAtom* first = sUserDefinedEvents->ObjectAt(0); 1.3318 + sStringEventTable->Remove(Substring(nsDependentAtomString(first), 2)); 1.3319 + sUserDefinedEvents->RemoveObjectAt(0); 1.3320 + } 1.3321 + } 1.3322 + 1.3323 + *aEventID = NS_USER_DEFINED_EVENT; 1.3324 + nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aName); 1.3325 + sUserDefinedEvents->AppendObject(atom); 1.3326 + mapping.mAtom = atom; 1.3327 + mapping.mId = NS_USER_DEFINED_EVENT; 1.3328 + mapping.mType = EventNameType_None; 1.3329 + mapping.mStructType = NS_EVENT_NULL; 1.3330 + sStringEventTable->Put(aName, mapping); 1.3331 + return mapping.mAtom; 1.3332 +} 1.3333 + 1.3334 +static 1.3335 +nsresult GetEventAndTarget(nsIDocument* aDoc, nsISupports* aTarget, 1.3336 + const nsAString& aEventName, 1.3337 + bool aCanBubble, bool aCancelable, 1.3338 + bool aTrusted, nsIDOMEvent** aEvent, 1.3339 + EventTarget** aTargetOut) 1.3340 +{ 1.3341 + nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc); 1.3342 + nsCOMPtr<EventTarget> target(do_QueryInterface(aTarget)); 1.3343 + NS_ENSURE_TRUE(domDoc && target, NS_ERROR_INVALID_ARG); 1.3344 + 1.3345 + nsCOMPtr<nsIDOMEvent> event; 1.3346 + nsresult rv = 1.3347 + domDoc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event)); 1.3348 + NS_ENSURE_SUCCESS(rv, rv); 1.3349 + 1.3350 + rv = event->InitEvent(aEventName, aCanBubble, aCancelable); 1.3351 + NS_ENSURE_SUCCESS(rv, rv); 1.3352 + 1.3353 + event->SetTrusted(aTrusted); 1.3354 + 1.3355 + rv = event->SetTarget(target); 1.3356 + NS_ENSURE_SUCCESS(rv, rv); 1.3357 + 1.3358 + event.forget(aEvent); 1.3359 + target.forget(aTargetOut); 1.3360 + return NS_OK; 1.3361 +} 1.3362 + 1.3363 +// static 1.3364 +nsresult 1.3365 +nsContentUtils::DispatchTrustedEvent(nsIDocument* aDoc, nsISupports* aTarget, 1.3366 + const nsAString& aEventName, 1.3367 + bool aCanBubble, bool aCancelable, 1.3368 + bool *aDefaultAction) 1.3369 +{ 1.3370 + return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable, 1.3371 + true, aDefaultAction); 1.3372 +} 1.3373 + 1.3374 +// static 1.3375 +nsresult 1.3376 +nsContentUtils::DispatchUntrustedEvent(nsIDocument* aDoc, nsISupports* aTarget, 1.3377 + const nsAString& aEventName, 1.3378 + bool aCanBubble, bool aCancelable, 1.3379 + bool *aDefaultAction) 1.3380 +{ 1.3381 + return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable, 1.3382 + false, aDefaultAction); 1.3383 +} 1.3384 + 1.3385 +// static 1.3386 +nsresult 1.3387 +nsContentUtils::DispatchEvent(nsIDocument* aDoc, nsISupports* aTarget, 1.3388 + const nsAString& aEventName, 1.3389 + bool aCanBubble, bool aCancelable, 1.3390 + bool aTrusted, bool *aDefaultAction) 1.3391 +{ 1.3392 + nsCOMPtr<nsIDOMEvent> event; 1.3393 + nsCOMPtr<EventTarget> target; 1.3394 + nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble, 1.3395 + aCancelable, aTrusted, getter_AddRefs(event), 1.3396 + getter_AddRefs(target)); 1.3397 + NS_ENSURE_SUCCESS(rv, rv); 1.3398 + 1.3399 + bool dummy; 1.3400 + return target->DispatchEvent(event, aDefaultAction ? aDefaultAction : &dummy); 1.3401 +} 1.3402 + 1.3403 +nsresult 1.3404 +nsContentUtils::DispatchChromeEvent(nsIDocument *aDoc, 1.3405 + nsISupports *aTarget, 1.3406 + const nsAString& aEventName, 1.3407 + bool aCanBubble, bool aCancelable, 1.3408 + bool *aDefaultAction) 1.3409 +{ 1.3410 + 1.3411 + nsCOMPtr<nsIDOMEvent> event; 1.3412 + nsCOMPtr<EventTarget> target; 1.3413 + nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble, 1.3414 + aCancelable, true, getter_AddRefs(event), 1.3415 + getter_AddRefs(target)); 1.3416 + NS_ENSURE_SUCCESS(rv, rv); 1.3417 + 1.3418 + NS_ASSERTION(aDoc, "GetEventAndTarget lied?"); 1.3419 + if (!aDoc->GetWindow()) 1.3420 + return NS_ERROR_INVALID_ARG; 1.3421 + 1.3422 + EventTarget* piTarget = aDoc->GetWindow()->GetParentTarget(); 1.3423 + if (!piTarget) 1.3424 + return NS_ERROR_INVALID_ARG; 1.3425 + 1.3426 + nsEventStatus status = nsEventStatus_eIgnore; 1.3427 + rv = piTarget->DispatchDOMEvent(nullptr, event, nullptr, &status); 1.3428 + if (aDefaultAction) { 1.3429 + *aDefaultAction = (status != nsEventStatus_eConsumeNoDefault); 1.3430 + } 1.3431 + return rv; 1.3432 +} 1.3433 + 1.3434 +/* static */ 1.3435 +Element* 1.3436 +nsContentUtils::MatchElementId(nsIContent *aContent, const nsIAtom* aId) 1.3437 +{ 1.3438 + for (nsIContent* cur = aContent; 1.3439 + cur; 1.3440 + cur = cur->GetNextNode(aContent)) { 1.3441 + if (aId == cur->GetID()) { 1.3442 + return cur->AsElement(); 1.3443 + } 1.3444 + } 1.3445 + 1.3446 + return nullptr; 1.3447 +} 1.3448 + 1.3449 +/* static */ 1.3450 +Element * 1.3451 +nsContentUtils::MatchElementId(nsIContent *aContent, const nsAString& aId) 1.3452 +{ 1.3453 + NS_PRECONDITION(!aId.IsEmpty(), "Will match random elements"); 1.3454 + 1.3455 + // ID attrs are generally stored as atoms, so just atomize this up front 1.3456 + nsCOMPtr<nsIAtom> id(do_GetAtom(aId)); 1.3457 + if (!id) { 1.3458 + // OOM, so just bail 1.3459 + return nullptr; 1.3460 + } 1.3461 + 1.3462 + return MatchElementId(aContent, id); 1.3463 +} 1.3464 + 1.3465 +// Convert the string from the given encoding to Unicode. 1.3466 +/* static */ 1.3467 +nsresult 1.3468 +nsContentUtils::ConvertStringFromEncoding(const nsACString& aEncoding, 1.3469 + const nsACString& aInput, 1.3470 + nsAString& aOutput) 1.3471 +{ 1.3472 + nsAutoCString encoding; 1.3473 + if (aEncoding.IsEmpty()) { 1.3474 + encoding.AssignLiteral("UTF-8"); 1.3475 + } else { 1.3476 + encoding.Assign(aEncoding); 1.3477 + } 1.3478 + 1.3479 + ErrorResult rv; 1.3480 + nsAutoPtr<TextDecoder> decoder(new TextDecoder()); 1.3481 + decoder->InitWithEncoding(encoding, false); 1.3482 + 1.3483 + decoder->Decode(aInput.BeginReading(), aInput.Length(), false, 1.3484 + aOutput, rv); 1.3485 + return rv.ErrorCode(); 1.3486 +} 1.3487 + 1.3488 +/* static */ 1.3489 +bool 1.3490 +nsContentUtils::CheckForBOM(const unsigned char* aBuffer, uint32_t aLength, 1.3491 + nsACString& aCharset) 1.3492 +{ 1.3493 + bool found = true; 1.3494 + aCharset.Truncate(); 1.3495 + if (aLength >= 3 && 1.3496 + aBuffer[0] == 0xEF && 1.3497 + aBuffer[1] == 0xBB && 1.3498 + aBuffer[2] == 0xBF) { 1.3499 + aCharset = "UTF-8"; 1.3500 + } 1.3501 + else if (aLength >= 2 && 1.3502 + aBuffer[0] == 0xFE && aBuffer[1] == 0xFF) { 1.3503 + aCharset = "UTF-16BE"; 1.3504 + } 1.3505 + else if (aLength >= 2 && 1.3506 + aBuffer[0] == 0xFF && aBuffer[1] == 0xFE) { 1.3507 + aCharset = "UTF-16LE"; 1.3508 + } else { 1.3509 + found = false; 1.3510 + } 1.3511 + 1.3512 + return found; 1.3513 +} 1.3514 + 1.3515 +/* static */ 1.3516 +void 1.3517 +nsContentUtils::RegisterShutdownObserver(nsIObserver* aObserver) 1.3518 +{ 1.3519 + nsCOMPtr<nsIObserverService> observerService = 1.3520 + mozilla::services::GetObserverService(); 1.3521 + if (observerService) { 1.3522 + observerService->AddObserver(aObserver, 1.3523 + NS_XPCOM_SHUTDOWN_OBSERVER_ID, 1.3524 + false); 1.3525 + } 1.3526 +} 1.3527 + 1.3528 +/* static */ 1.3529 +void 1.3530 +nsContentUtils::UnregisterShutdownObserver(nsIObserver* aObserver) 1.3531 +{ 1.3532 + nsCOMPtr<nsIObserverService> observerService = 1.3533 + mozilla::services::GetObserverService(); 1.3534 + if (observerService) { 1.3535 + observerService->RemoveObserver(aObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID); 1.3536 + } 1.3537 +} 1.3538 + 1.3539 +/* static */ 1.3540 +bool 1.3541 +nsContentUtils::HasNonEmptyAttr(const nsIContent* aContent, int32_t aNameSpaceID, 1.3542 + nsIAtom* aName) 1.3543 +{ 1.3544 + static nsIContent::AttrValuesArray strings[] = {&nsGkAtoms::_empty, nullptr}; 1.3545 + return aContent->FindAttrValueIn(aNameSpaceID, aName, strings, eCaseMatters) 1.3546 + == nsIContent::ATTR_VALUE_NO_MATCH; 1.3547 +} 1.3548 + 1.3549 +/* static */ 1.3550 +bool 1.3551 +nsContentUtils::HasMutationListeners(nsINode* aNode, 1.3552 + uint32_t aType, 1.3553 + nsINode* aTargetForSubtreeModified) 1.3554 +{ 1.3555 + nsIDocument* doc = aNode->OwnerDoc(); 1.3556 + 1.3557 + // global object will be null for documents that don't have windows. 1.3558 + nsPIDOMWindow* window = doc->GetInnerWindow(); 1.3559 + // This relies on EventListenerManager::AddEventListener, which sets 1.3560 + // all mutation bits when there is a listener for DOMSubtreeModified event. 1.3561 + if (window && !window->HasMutationListeners(aType)) { 1.3562 + return false; 1.3563 + } 1.3564 + 1.3565 + if (aNode->IsNodeOfType(nsINode::eCONTENT) && 1.3566 + static_cast<nsIContent*>(aNode)->ChromeOnlyAccess()) { 1.3567 + return false; 1.3568 + } 1.3569 + 1.3570 + doc->MayDispatchMutationEvent(aTargetForSubtreeModified); 1.3571 + 1.3572 + // If we have a window, we can check it for mutation listeners now. 1.3573 + if (aNode->IsInDoc()) { 1.3574 + nsCOMPtr<EventTarget> piTarget(do_QueryInterface(window)); 1.3575 + if (piTarget) { 1.3576 + EventListenerManager* manager = piTarget->GetExistingListenerManager(); 1.3577 + if (manager && manager->HasMutationListeners()) { 1.3578 + return true; 1.3579 + } 1.3580 + } 1.3581 + } 1.3582 + 1.3583 + // If we have a window, we know a mutation listener is registered, but it 1.3584 + // might not be in our chain. If we don't have a window, we might have a 1.3585 + // mutation listener. Check quickly to see. 1.3586 + while (aNode) { 1.3587 + EventListenerManager* manager = aNode->GetExistingListenerManager(); 1.3588 + if (manager && manager->HasMutationListeners()) { 1.3589 + return true; 1.3590 + } 1.3591 + 1.3592 + if (aNode->IsNodeOfType(nsINode::eCONTENT)) { 1.3593 + nsIContent* content = static_cast<nsIContent*>(aNode); 1.3594 + nsIContent* insertionParent = content->GetXBLInsertionParent(); 1.3595 + if (insertionParent) { 1.3596 + aNode = insertionParent; 1.3597 + continue; 1.3598 + } 1.3599 + } 1.3600 + aNode = aNode->GetParentNode(); 1.3601 + } 1.3602 + 1.3603 + return false; 1.3604 +} 1.3605 + 1.3606 +/* static */ 1.3607 +bool 1.3608 +nsContentUtils::HasMutationListeners(nsIDocument* aDocument, 1.3609 + uint32_t aType) 1.3610 +{ 1.3611 + nsPIDOMWindow* window = aDocument ? 1.3612 + aDocument->GetInnerWindow() : nullptr; 1.3613 + 1.3614 + // This relies on EventListenerManager::AddEventListener, which sets 1.3615 + // all mutation bits when there is a listener for DOMSubtreeModified event. 1.3616 + return !window || window->HasMutationListeners(aType); 1.3617 +} 1.3618 + 1.3619 +void 1.3620 +nsContentUtils::MaybeFireNodeRemoved(nsINode* aChild, nsINode* aParent, 1.3621 + nsIDocument* aOwnerDoc) 1.3622 +{ 1.3623 + NS_PRECONDITION(aChild, "Missing child"); 1.3624 + NS_PRECONDITION(aChild->GetParentNode() == aParent, "Wrong parent"); 1.3625 + NS_PRECONDITION(aChild->OwnerDoc() == aOwnerDoc, "Wrong owner-doc"); 1.3626 + 1.3627 + // This checks that IsSafeToRunScript is true since we don't want to fire 1.3628 + // events when that is false. We can't rely on EventDispatcher to assert 1.3629 + // this in this situation since most of the time there are no mutation 1.3630 + // event listeners, in which case we won't even attempt to dispatch events. 1.3631 + // However this also allows for two exceptions. First off, we don't assert 1.3632 + // if the mutation happens to native anonymous content since we never fire 1.3633 + // mutation events on such content anyway. 1.3634 + // Second, we don't assert if sDOMNodeRemovedSuppressCount is true since 1.3635 + // that is a know case when we'd normally fire a mutation event, but can't 1.3636 + // make that safe and so we suppress it at this time. Ideally this should 1.3637 + // go away eventually. 1.3638 + NS_ASSERTION((aChild->IsNodeOfType(nsINode::eCONTENT) && 1.3639 + static_cast<nsIContent*>(aChild)-> 1.3640 + IsInNativeAnonymousSubtree()) || 1.3641 + IsSafeToRunScript() || 1.3642 + sDOMNodeRemovedSuppressCount, 1.3643 + "Want to fire DOMNodeRemoved event, but it's not safe"); 1.3644 + 1.3645 + // Having an explicit check here since it's an easy mistake to fall into, 1.3646 + // and there might be existing code with problems. We'd rather be safe 1.3647 + // than fire DOMNodeRemoved in all corner cases. We also rely on it for 1.3648 + // nsAutoScriptBlockerSuppressNodeRemoved. 1.3649 + if (!IsSafeToRunScript()) { 1.3650 + return; 1.3651 + } 1.3652 + 1.3653 + if (HasMutationListeners(aChild, 1.3654 + NS_EVENT_BITS_MUTATION_NODEREMOVED, aParent)) { 1.3655 + InternalMutationEvent mutation(true, NS_MUTATION_NODEREMOVED); 1.3656 + mutation.mRelatedNode = do_QueryInterface(aParent); 1.3657 + 1.3658 + mozAutoSubtreeModified subtree(aOwnerDoc, aParent); 1.3659 + EventDispatcher::Dispatch(aChild, nullptr, &mutation); 1.3660 + } 1.3661 +} 1.3662 + 1.3663 +PLDHashOperator 1.3664 +ListenerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aEntry, 1.3665 + uint32_t aNumber, void* aArg) 1.3666 +{ 1.3667 + EventListenerManagerMapEntry* entry = 1.3668 + static_cast<EventListenerManagerMapEntry*>(aEntry); 1.3669 + if (entry) { 1.3670 + nsINode* n = static_cast<nsINode*>(entry->mListenerManager->GetTarget()); 1.3671 + if (n && n->IsInDoc() && 1.3672 + nsCCUncollectableMarker::InGeneration(n->OwnerDoc()->GetMarkedCCGeneration())) { 1.3673 + entry->mListenerManager->MarkForCC(); 1.3674 + } 1.3675 + } 1.3676 + return PL_DHASH_NEXT; 1.3677 +} 1.3678 + 1.3679 +void 1.3680 +nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(uint32_t aGeneration) 1.3681 +{ 1.3682 + if (sEventListenerManagersHash.ops) { 1.3683 + PL_DHashTableEnumerate(&sEventListenerManagersHash, ListenerEnumerator, 1.3684 + &aGeneration); 1.3685 + } 1.3686 +} 1.3687 + 1.3688 +/* static */ 1.3689 +void 1.3690 +nsContentUtils::TraverseListenerManager(nsINode *aNode, 1.3691 + nsCycleCollectionTraversalCallback &cb) 1.3692 +{ 1.3693 + if (!sEventListenerManagersHash.ops) { 1.3694 + // We're already shut down, just return. 1.3695 + return; 1.3696 + } 1.3697 + 1.3698 + EventListenerManagerMapEntry *entry = 1.3699 + static_cast<EventListenerManagerMapEntry *> 1.3700 + (PL_DHashTableOperate(&sEventListenerManagersHash, aNode, 1.3701 + PL_DHASH_LOOKUP)); 1.3702 + if (PL_DHASH_ENTRY_IS_BUSY(entry)) { 1.3703 + CycleCollectionNoteChild(cb, entry->mListenerManager.get(), 1.3704 + "[via hash] mListenerManager"); 1.3705 + } 1.3706 +} 1.3707 + 1.3708 +EventListenerManager* 1.3709 +nsContentUtils::GetListenerManagerForNode(nsINode *aNode) 1.3710 +{ 1.3711 + if (!sEventListenerManagersHash.ops) { 1.3712 + // We're already shut down, don't bother creating an event listener 1.3713 + // manager. 1.3714 + 1.3715 + return nullptr; 1.3716 + } 1.3717 + 1.3718 + EventListenerManagerMapEntry *entry = 1.3719 + static_cast<EventListenerManagerMapEntry *> 1.3720 + (PL_DHashTableOperate(&sEventListenerManagersHash, aNode, 1.3721 + PL_DHASH_ADD)); 1.3722 + 1.3723 + if (!entry) { 1.3724 + return nullptr; 1.3725 + } 1.3726 + 1.3727 + if (!entry->mListenerManager) { 1.3728 + entry->mListenerManager = new EventListenerManager(aNode); 1.3729 + 1.3730 + aNode->SetFlags(NODE_HAS_LISTENERMANAGER); 1.3731 + } 1.3732 + 1.3733 + return entry->mListenerManager; 1.3734 +} 1.3735 + 1.3736 +EventListenerManager* 1.3737 +nsContentUtils::GetExistingListenerManagerForNode(const nsINode *aNode) 1.3738 +{ 1.3739 + if (!aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) { 1.3740 + return nullptr; 1.3741 + } 1.3742 + 1.3743 + if (!sEventListenerManagersHash.ops) { 1.3744 + // We're already shut down, don't bother creating an event listener 1.3745 + // manager. 1.3746 + 1.3747 + return nullptr; 1.3748 + } 1.3749 + 1.3750 + EventListenerManagerMapEntry *entry = 1.3751 + static_cast<EventListenerManagerMapEntry *> 1.3752 + (PL_DHashTableOperate(&sEventListenerManagersHash, aNode, 1.3753 + PL_DHASH_LOOKUP)); 1.3754 + if (PL_DHASH_ENTRY_IS_BUSY(entry)) { 1.3755 + return entry->mListenerManager; 1.3756 + } 1.3757 + 1.3758 + return nullptr; 1.3759 +} 1.3760 + 1.3761 +/* static */ 1.3762 +void 1.3763 +nsContentUtils::RemoveListenerManager(nsINode *aNode) 1.3764 +{ 1.3765 + if (sEventListenerManagersHash.ops) { 1.3766 + EventListenerManagerMapEntry *entry = 1.3767 + static_cast<EventListenerManagerMapEntry *> 1.3768 + (PL_DHashTableOperate(&sEventListenerManagersHash, aNode, 1.3769 + PL_DHASH_LOOKUP)); 1.3770 + if (PL_DHASH_ENTRY_IS_BUSY(entry)) { 1.3771 + nsRefPtr<EventListenerManager> listenerManager; 1.3772 + listenerManager.swap(entry->mListenerManager); 1.3773 + // Remove the entry and *then* do operations that could cause further 1.3774 + // modification of sEventListenerManagersHash. See bug 334177. 1.3775 + PL_DHashTableRawRemove(&sEventListenerManagersHash, entry); 1.3776 + if (listenerManager) { 1.3777 + listenerManager->Disconnect(); 1.3778 + } 1.3779 + } 1.3780 + } 1.3781 +} 1.3782 + 1.3783 +/* static */ 1.3784 +bool 1.3785 +nsContentUtils::IsValidNodeName(nsIAtom *aLocalName, nsIAtom *aPrefix, 1.3786 + int32_t aNamespaceID) 1.3787 +{ 1.3788 + if (aNamespaceID == kNameSpaceID_Unknown) { 1.3789 + return false; 1.3790 + } 1.3791 + 1.3792 + if (!aPrefix) { 1.3793 + // If the prefix is null, then either the QName must be xmlns or the 1.3794 + // namespace must not be XMLNS. 1.3795 + return (aLocalName == nsGkAtoms::xmlns) == 1.3796 + (aNamespaceID == kNameSpaceID_XMLNS); 1.3797 + } 1.3798 + 1.3799 + // If the prefix is non-null then the namespace must not be null. 1.3800 + if (aNamespaceID == kNameSpaceID_None) { 1.3801 + return false; 1.3802 + } 1.3803 + 1.3804 + // If the namespace is the XMLNS namespace then the prefix must be xmlns, 1.3805 + // but the localname must not be xmlns. 1.3806 + if (aNamespaceID == kNameSpaceID_XMLNS) { 1.3807 + return aPrefix == nsGkAtoms::xmlns && aLocalName != nsGkAtoms::xmlns; 1.3808 + } 1.3809 + 1.3810 + // If the namespace is not the XMLNS namespace then the prefix must not be 1.3811 + // xmlns. 1.3812 + // If the namespace is the XML namespace then the prefix can be anything. 1.3813 + // If the namespace is not the XML namespace then the prefix must not be xml. 1.3814 + return aPrefix != nsGkAtoms::xmlns && 1.3815 + (aNamespaceID == kNameSpaceID_XML || aPrefix != nsGkAtoms::xml); 1.3816 +} 1.3817 + 1.3818 +/* static */ 1.3819 +nsresult 1.3820 +nsContentUtils::CreateContextualFragment(nsINode* aContextNode, 1.3821 + const nsAString& aFragment, 1.3822 + bool aPreventScriptExecution, 1.3823 + nsIDOMDocumentFragment** aReturn) 1.3824 +{ 1.3825 + ErrorResult rv; 1.3826 + *aReturn = CreateContextualFragment(aContextNode, aFragment, 1.3827 + aPreventScriptExecution, rv).take(); 1.3828 + return rv.ErrorCode(); 1.3829 +} 1.3830 + 1.3831 +already_AddRefed<DocumentFragment> 1.3832 +nsContentUtils::CreateContextualFragment(nsINode* aContextNode, 1.3833 + const nsAString& aFragment, 1.3834 + bool aPreventScriptExecution, 1.3835 + ErrorResult& aRv) 1.3836 +{ 1.3837 + if (!aContextNode) { 1.3838 + aRv.Throw(NS_ERROR_INVALID_ARG); 1.3839 + return nullptr; 1.3840 + } 1.3841 + 1.3842 + // If we don't have a document here, we can't get the right security context 1.3843 + // for compiling event handlers... so just bail out. 1.3844 + nsCOMPtr<nsIDocument> document = aContextNode->OwnerDoc(); 1.3845 + bool isHTML = document->IsHTML(); 1.3846 +#ifdef DEBUG 1.3847 + nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(document); 1.3848 + NS_ASSERTION(!isHTML || htmlDoc, "Should have HTMLDocument here!"); 1.3849 +#endif 1.3850 + 1.3851 + if (isHTML) { 1.3852 + nsRefPtr<DocumentFragment> frag = 1.3853 + new DocumentFragment(document->NodeInfoManager()); 1.3854 + 1.3855 + nsCOMPtr<nsIContent> contextAsContent = do_QueryInterface(aContextNode); 1.3856 + if (contextAsContent && !contextAsContent->IsElement()) { 1.3857 + contextAsContent = contextAsContent->GetParent(); 1.3858 + if (contextAsContent && !contextAsContent->IsElement()) { 1.3859 + // can this even happen? 1.3860 + contextAsContent = nullptr; 1.3861 + } 1.3862 + } 1.3863 + 1.3864 + if (contextAsContent && !contextAsContent->IsHTML(nsGkAtoms::html)) { 1.3865 + aRv = ParseFragmentHTML(aFragment, frag, 1.3866 + contextAsContent->Tag(), 1.3867 + contextAsContent->GetNameSpaceID(), 1.3868 + (document->GetCompatibilityMode() == 1.3869 + eCompatibility_NavQuirks), 1.3870 + aPreventScriptExecution); 1.3871 + } else { 1.3872 + aRv = ParseFragmentHTML(aFragment, frag, 1.3873 + nsGkAtoms::body, 1.3874 + kNameSpaceID_XHTML, 1.3875 + (document->GetCompatibilityMode() == 1.3876 + eCompatibility_NavQuirks), 1.3877 + aPreventScriptExecution); 1.3878 + } 1.3879 + 1.3880 + return frag.forget(); 1.3881 + } 1.3882 + 1.3883 + nsAutoTArray<nsString, 32> tagStack; 1.3884 + nsAutoString uriStr, nameStr; 1.3885 + nsCOMPtr<nsIContent> content = do_QueryInterface(aContextNode); 1.3886 + // just in case we have a text node 1.3887 + if (content && !content->IsElement()) 1.3888 + content = content->GetParent(); 1.3889 + 1.3890 + while (content && content->IsElement()) { 1.3891 + nsString& tagName = *tagStack.AppendElement(); 1.3892 + if (!&tagName) { 1.3893 + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.3894 + return nullptr; 1.3895 + } 1.3896 + 1.3897 + tagName = content->NodeInfo()->QualifiedName(); 1.3898 + 1.3899 + // see if we need to add xmlns declarations 1.3900 + uint32_t count = content->GetAttrCount(); 1.3901 + bool setDefaultNamespace = false; 1.3902 + if (count > 0) { 1.3903 + uint32_t index; 1.3904 + 1.3905 + for (index = 0; index < count; index++) { 1.3906 + const nsAttrName* name = content->GetAttrNameAt(index); 1.3907 + if (name->NamespaceEquals(kNameSpaceID_XMLNS)) { 1.3908 + content->GetAttr(kNameSpaceID_XMLNS, name->LocalName(), uriStr); 1.3909 + 1.3910 + // really want something like nsXMLContentSerializer::SerializeAttr 1.3911 + tagName.Append(NS_LITERAL_STRING(" xmlns")); // space important 1.3912 + if (name->GetPrefix()) { 1.3913 + tagName.Append(char16_t(':')); 1.3914 + name->LocalName()->ToString(nameStr); 1.3915 + tagName.Append(nameStr); 1.3916 + } else { 1.3917 + setDefaultNamespace = true; 1.3918 + } 1.3919 + tagName.Append(NS_LITERAL_STRING("=\"") + uriStr + 1.3920 + NS_LITERAL_STRING("\"")); 1.3921 + } 1.3922 + } 1.3923 + } 1.3924 + 1.3925 + if (!setDefaultNamespace) { 1.3926 + nsINodeInfo* info = content->NodeInfo(); 1.3927 + if (!info->GetPrefixAtom() && 1.3928 + info->NamespaceID() != kNameSpaceID_None) { 1.3929 + // We have no namespace prefix, but have a namespace ID. Push 1.3930 + // default namespace attr in, so that our kids will be in our 1.3931 + // namespace. 1.3932 + info->GetNamespaceURI(uriStr); 1.3933 + tagName.Append(NS_LITERAL_STRING(" xmlns=\"") + uriStr + 1.3934 + NS_LITERAL_STRING("\"")); 1.3935 + } 1.3936 + } 1.3937 + 1.3938 + content = content->GetParent(); 1.3939 + } 1.3940 + 1.3941 + nsCOMPtr<nsIDOMDocumentFragment> frag; 1.3942 + aRv = ParseFragmentXML(aFragment, document, tagStack, 1.3943 + aPreventScriptExecution, getter_AddRefs(frag)); 1.3944 + return frag.forget().downcast<DocumentFragment>(); 1.3945 +} 1.3946 + 1.3947 +/* static */ 1.3948 +void 1.3949 +nsContentUtils::DropFragmentParsers() 1.3950 +{ 1.3951 + NS_IF_RELEASE(sHTMLFragmentParser); 1.3952 + NS_IF_RELEASE(sXMLFragmentParser); 1.3953 + NS_IF_RELEASE(sXMLFragmentSink); 1.3954 +} 1.3955 + 1.3956 +/* static */ 1.3957 +void 1.3958 +nsContentUtils::XPCOMShutdown() 1.3959 +{ 1.3960 + nsContentUtils::DropFragmentParsers(); 1.3961 +} 1.3962 + 1.3963 +/* static */ 1.3964 +nsresult 1.3965 +nsContentUtils::ParseFragmentHTML(const nsAString& aSourceBuffer, 1.3966 + nsIContent* aTargetNode, 1.3967 + nsIAtom* aContextLocalName, 1.3968 + int32_t aContextNamespace, 1.3969 + bool aQuirks, 1.3970 + bool aPreventScriptExecution) 1.3971 +{ 1.3972 + if (nsContentUtils::sFragmentParsingActive) { 1.3973 + NS_NOTREACHED("Re-entrant fragment parsing attempted."); 1.3974 + return NS_ERROR_DOM_INVALID_STATE_ERR; 1.3975 + } 1.3976 + mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive); 1.3977 + nsContentUtils::sFragmentParsingActive = true; 1.3978 + if (!sHTMLFragmentParser) { 1.3979 + NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser()); 1.3980 + // Now sHTMLFragmentParser owns the object 1.3981 + } 1.3982 + nsresult rv = 1.3983 + sHTMLFragmentParser->ParseFragment(aSourceBuffer, 1.3984 + aTargetNode, 1.3985 + aContextLocalName, 1.3986 + aContextNamespace, 1.3987 + aQuirks, 1.3988 + aPreventScriptExecution); 1.3989 + return rv; 1.3990 +} 1.3991 + 1.3992 +/* static */ 1.3993 +nsresult 1.3994 +nsContentUtils::ParseDocumentHTML(const nsAString& aSourceBuffer, 1.3995 + nsIDocument* aTargetDocument, 1.3996 + bool aScriptingEnabledForNoscriptParsing) 1.3997 +{ 1.3998 + if (nsContentUtils::sFragmentParsingActive) { 1.3999 + NS_NOTREACHED("Re-entrant fragment parsing attempted."); 1.4000 + return NS_ERROR_DOM_INVALID_STATE_ERR; 1.4001 + } 1.4002 + mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive); 1.4003 + nsContentUtils::sFragmentParsingActive = true; 1.4004 + if (!sHTMLFragmentParser) { 1.4005 + NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser()); 1.4006 + // Now sHTMLFragmentParser owns the object 1.4007 + } 1.4008 + nsresult rv = 1.4009 + sHTMLFragmentParser->ParseDocument(aSourceBuffer, 1.4010 + aTargetDocument, 1.4011 + aScriptingEnabledForNoscriptParsing); 1.4012 + return rv; 1.4013 +} 1.4014 + 1.4015 +/* static */ 1.4016 +nsresult 1.4017 +nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer, 1.4018 + nsIDocument* aDocument, 1.4019 + nsTArray<nsString>& aTagStack, 1.4020 + bool aPreventScriptExecution, 1.4021 + nsIDOMDocumentFragment** aReturn) 1.4022 +{ 1.4023 + if (nsContentUtils::sFragmentParsingActive) { 1.4024 + NS_NOTREACHED("Re-entrant fragment parsing attempted."); 1.4025 + return NS_ERROR_DOM_INVALID_STATE_ERR; 1.4026 + } 1.4027 + mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive); 1.4028 + nsContentUtils::sFragmentParsingActive = true; 1.4029 + if (!sXMLFragmentParser) { 1.4030 + nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID); 1.4031 + parser.forget(&sXMLFragmentParser); 1.4032 + // sXMLFragmentParser now owns the parser 1.4033 + } 1.4034 + if (!sXMLFragmentSink) { 1.4035 + NS_NewXMLFragmentContentSink(&sXMLFragmentSink); 1.4036 + // sXMLFragmentSink now owns the sink 1.4037 + } 1.4038 + nsCOMPtr<nsIContentSink> contentsink = do_QueryInterface(sXMLFragmentSink); 1.4039 + NS_ABORT_IF_FALSE(contentsink, "Sink doesn't QI to nsIContentSink!"); 1.4040 + sXMLFragmentParser->SetContentSink(contentsink); 1.4041 + 1.4042 + sXMLFragmentSink->SetTargetDocument(aDocument); 1.4043 + sXMLFragmentSink->SetPreventScriptExecution(aPreventScriptExecution); 1.4044 + 1.4045 + nsresult rv = 1.4046 + sXMLFragmentParser->ParseFragment(aSourceBuffer, 1.4047 + aTagStack); 1.4048 + if (NS_FAILED(rv)) { 1.4049 + // Drop the fragment parser and sink that might be in an inconsistent state 1.4050 + NS_IF_RELEASE(sXMLFragmentParser); 1.4051 + NS_IF_RELEASE(sXMLFragmentSink); 1.4052 + return rv; 1.4053 + } 1.4054 + 1.4055 + rv = sXMLFragmentSink->FinishFragmentParsing(aReturn); 1.4056 + 1.4057 + sXMLFragmentParser->Reset(); 1.4058 + 1.4059 + return rv; 1.4060 +} 1.4061 + 1.4062 +/* static */ 1.4063 +nsresult 1.4064 +nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer, 1.4065 + nsAString& aResultBuffer, 1.4066 + uint32_t aFlags, 1.4067 + uint32_t aWrapCol) 1.4068 +{ 1.4069 + nsCOMPtr<nsIURI> uri; 1.4070 + NS_NewURI(getter_AddRefs(uri), "about:blank"); 1.4071 + nsCOMPtr<nsIPrincipal> principal = 1.4072 + do_CreateInstance(NS_NULLPRINCIPAL_CONTRACTID); 1.4073 + nsCOMPtr<nsIDOMDocument> domDocument; 1.4074 + nsresult rv = NS_NewDOMDocument(getter_AddRefs(domDocument), 1.4075 + EmptyString(), 1.4076 + EmptyString(), 1.4077 + nullptr, 1.4078 + uri, 1.4079 + uri, 1.4080 + principal, 1.4081 + true, 1.4082 + nullptr, 1.4083 + DocumentFlavorHTML); 1.4084 + NS_ENSURE_SUCCESS(rv, rv); 1.4085 + 1.4086 + nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument); 1.4087 + rv = nsContentUtils::ParseDocumentHTML(aSourceBuffer, document, 1.4088 + !(aFlags & nsIDocumentEncoder::OutputNoScriptContent)); 1.4089 + NS_ENSURE_SUCCESS(rv, rv); 1.4090 + 1.4091 + nsCOMPtr<nsIDocumentEncoder> encoder = do_CreateInstance( 1.4092 + "@mozilla.org/layout/documentEncoder;1?type=text/plain"); 1.4093 + 1.4094 + rv = encoder->Init(domDocument, NS_LITERAL_STRING("text/plain"), aFlags); 1.4095 + NS_ENSURE_SUCCESS(rv, rv); 1.4096 + 1.4097 + encoder->SetWrapColumn(aWrapCol); 1.4098 + 1.4099 + return encoder->EncodeToString(aResultBuffer); 1.4100 +} 1.4101 + 1.4102 +/* static */ 1.4103 +nsresult 1.4104 +nsContentUtils::SetNodeTextContent(nsIContent* aContent, 1.4105 + const nsAString& aValue, 1.4106 + bool aTryReuse) 1.4107 +{ 1.4108 + // Fire DOMNodeRemoved mutation events before we do anything else. 1.4109 + nsCOMPtr<nsIContent> owningContent; 1.4110 + 1.4111 + // Batch possible DOMSubtreeModified events. 1.4112 + mozAutoSubtreeModified subtree(nullptr, nullptr); 1.4113 + 1.4114 + // Scope firing mutation events so that we don't carry any state that 1.4115 + // might be stale 1.4116 + { 1.4117 + // We're relying on mozAutoSubtreeModified to keep a strong reference if 1.4118 + // needed. 1.4119 + nsIDocument* doc = aContent->OwnerDoc(); 1.4120 + 1.4121 + // Optimize the common case of there being no observers 1.4122 + if (HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED)) { 1.4123 + subtree.UpdateTarget(doc, nullptr); 1.4124 + owningContent = aContent; 1.4125 + nsCOMPtr<nsINode> child; 1.4126 + bool skipFirst = aTryReuse; 1.4127 + for (child = aContent->GetFirstChild(); 1.4128 + child && child->GetParentNode() == aContent; 1.4129 + child = child->GetNextSibling()) { 1.4130 + if (skipFirst && child->IsNodeOfType(nsINode::eTEXT)) { 1.4131 + skipFirst = false; 1.4132 + continue; 1.4133 + } 1.4134 + nsContentUtils::MaybeFireNodeRemoved(child, aContent, doc); 1.4135 + } 1.4136 + } 1.4137 + } 1.4138 + 1.4139 + // Might as well stick a batch around this since we're performing several 1.4140 + // mutations. 1.4141 + mozAutoDocUpdate updateBatch(aContent->GetCurrentDoc(), 1.4142 + UPDATE_CONTENT_MODEL, true); 1.4143 + nsAutoMutationBatch mb; 1.4144 + 1.4145 + uint32_t childCount = aContent->GetChildCount(); 1.4146 + 1.4147 + if (aTryReuse && !aValue.IsEmpty()) { 1.4148 + uint32_t removeIndex = 0; 1.4149 + 1.4150 + for (uint32_t i = 0; i < childCount; ++i) { 1.4151 + nsIContent* child = aContent->GetChildAt(removeIndex); 1.4152 + if (removeIndex == 0 && child && child->IsNodeOfType(nsINode::eTEXT)) { 1.4153 + nsresult rv = child->SetText(aValue, true); 1.4154 + NS_ENSURE_SUCCESS(rv, rv); 1.4155 + 1.4156 + removeIndex = 1; 1.4157 + } 1.4158 + else { 1.4159 + aContent->RemoveChildAt(removeIndex, true); 1.4160 + } 1.4161 + } 1.4162 + 1.4163 + if (removeIndex == 1) { 1.4164 + return NS_OK; 1.4165 + } 1.4166 + } 1.4167 + else { 1.4168 + mb.Init(aContent, true, false); 1.4169 + for (uint32_t i = 0; i < childCount; ++i) { 1.4170 + aContent->RemoveChildAt(0, true); 1.4171 + } 1.4172 + } 1.4173 + mb.RemovalDone(); 1.4174 + 1.4175 + if (aValue.IsEmpty()) { 1.4176 + return NS_OK; 1.4177 + } 1.4178 + 1.4179 + nsRefPtr<nsTextNode> textContent = 1.4180 + new nsTextNode(aContent->NodeInfo()->NodeInfoManager()); 1.4181 + 1.4182 + textContent->SetText(aValue, true); 1.4183 + 1.4184 + nsresult rv = aContent->AppendChildTo(textContent, true); 1.4185 + mb.NodesAdded(); 1.4186 + return rv; 1.4187 +} 1.4188 + 1.4189 +static bool 1.4190 +AppendNodeTextContentsRecurse(nsINode* aNode, nsAString& aResult, 1.4191 + const mozilla::fallible_t&) 1.4192 +{ 1.4193 + for (nsIContent* child = aNode->GetFirstChild(); 1.4194 + child; 1.4195 + child = child->GetNextSibling()) { 1.4196 + if (child->IsElement()) { 1.4197 + bool ok = AppendNodeTextContentsRecurse(child, aResult, 1.4198 + mozilla::fallible_t()); 1.4199 + if (!ok) { 1.4200 + return false; 1.4201 + } 1.4202 + } 1.4203 + else if (child->IsNodeOfType(nsINode::eTEXT)) { 1.4204 + bool ok = child->AppendTextTo(aResult, mozilla::fallible_t()); 1.4205 + if (!ok) { 1.4206 + return false; 1.4207 + } 1.4208 + } 1.4209 + } 1.4210 + 1.4211 + return true; 1.4212 +} 1.4213 + 1.4214 +/* static */ 1.4215 +bool 1.4216 +nsContentUtils::AppendNodeTextContent(nsINode* aNode, bool aDeep, 1.4217 + nsAString& aResult, 1.4218 + const mozilla::fallible_t&) 1.4219 +{ 1.4220 + if (aNode->IsNodeOfType(nsINode::eTEXT)) { 1.4221 + return static_cast<nsIContent*>(aNode)->AppendTextTo(aResult, 1.4222 + mozilla::fallible_t()); 1.4223 + } 1.4224 + else if (aDeep) { 1.4225 + return AppendNodeTextContentsRecurse(aNode, aResult, mozilla::fallible_t()); 1.4226 + } 1.4227 + else { 1.4228 + for (nsIContent* child = aNode->GetFirstChild(); 1.4229 + child; 1.4230 + child = child->GetNextSibling()) { 1.4231 + if (child->IsNodeOfType(nsINode::eTEXT)) { 1.4232 + bool ok = child->AppendTextTo(aResult, mozilla::fallible_t()); 1.4233 + if (!ok) { 1.4234 + return false; 1.4235 + } 1.4236 + } 1.4237 + } 1.4238 + } 1.4239 + 1.4240 + return true; 1.4241 +} 1.4242 + 1.4243 +bool 1.4244 +nsContentUtils::HasNonEmptyTextContent(nsINode* aNode) 1.4245 +{ 1.4246 + for (nsIContent* child = aNode->GetFirstChild(); 1.4247 + child; 1.4248 + child = child->GetNextSibling()) { 1.4249 + if (child->IsNodeOfType(nsINode::eTEXT) && 1.4250 + child->TextLength() > 0) { 1.4251 + return true; 1.4252 + } 1.4253 + } 1.4254 + 1.4255 + return false; 1.4256 +} 1.4257 + 1.4258 +/* static */ 1.4259 +bool 1.4260 +nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode, 1.4261 + const nsIContent* aContent) 1.4262 +{ 1.4263 + NS_PRECONDITION(aNode, 1.4264 + "Must have a node to work with"); 1.4265 + NS_PRECONDITION(aContent, 1.4266 + "Must have a content to work with"); 1.4267 + 1.4268 + if (!aNode->IsNodeOfType(nsINode::eCONTENT)) { 1.4269 + /** 1.4270 + * The root isn't an nsIContent, so it's a document or attribute. The only 1.4271 + * nodes in the same anonymous subtree as it will have a null 1.4272 + * bindingParent. 1.4273 + * 1.4274 + * XXXbz strictly speaking, that's not true for attribute nodes. 1.4275 + */ 1.4276 + return aContent->GetBindingParent() == nullptr; 1.4277 + } 1.4278 + 1.4279 + const nsIContent* nodeAsContent = static_cast<const nsIContent*>(aNode); 1.4280 + 1.4281 + // For nodes in a shadow tree, it is insufficient to simply compare 1.4282 + // the binding parent because a node may host multiple ShadowRoots, 1.4283 + // thus nodes in different shadow tree may have the same binding parent. 1.4284 + if (aNode->HasFlag(NODE_IS_IN_SHADOW_TREE)) { 1.4285 + return nodeAsContent->GetContainingShadow() == 1.4286 + aContent->GetContainingShadow(); 1.4287 + } 1.4288 + 1.4289 + return nodeAsContent->GetBindingParent() == aContent->GetBindingParent(); 1.4290 +} 1.4291 + 1.4292 +class AnonymousContentDestroyer : public nsRunnable { 1.4293 +public: 1.4294 + AnonymousContentDestroyer(nsCOMPtr<nsIContent>* aContent) { 1.4295 + mContent.swap(*aContent); 1.4296 + mParent = mContent->GetParent(); 1.4297 + mDoc = mContent->OwnerDoc(); 1.4298 + } 1.4299 + AnonymousContentDestroyer(nsCOMPtr<Element>* aElement) { 1.4300 + mContent = aElement->forget(); 1.4301 + mParent = mContent->GetParent(); 1.4302 + mDoc = mContent->OwnerDoc(); 1.4303 + } 1.4304 + NS_IMETHOD Run() { 1.4305 + mContent->UnbindFromTree(); 1.4306 + return NS_OK; 1.4307 + } 1.4308 +private: 1.4309 + nsCOMPtr<nsIContent> mContent; 1.4310 + // Hold strong refs to the parent content and document so that they 1.4311 + // don't die unexpectedly 1.4312 + nsCOMPtr<nsIDocument> mDoc; 1.4313 + nsCOMPtr<nsIContent> mParent; 1.4314 +}; 1.4315 + 1.4316 +/* static */ 1.4317 +void 1.4318 +nsContentUtils::DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent) 1.4319 +{ 1.4320 + if (*aContent) { 1.4321 + AddScriptRunner(new AnonymousContentDestroyer(aContent)); 1.4322 + } 1.4323 +} 1.4324 + 1.4325 +/* static */ 1.4326 +void 1.4327 +nsContentUtils::DestroyAnonymousContent(nsCOMPtr<Element>* aElement) 1.4328 +{ 1.4329 + if (*aElement) { 1.4330 + AddScriptRunner(new AnonymousContentDestroyer(aElement)); 1.4331 + } 1.4332 +} 1.4333 + 1.4334 +/* static */ 1.4335 +void 1.4336 +nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling) 1.4337 +{ 1.4338 + IMEStateManager::OnInstalledMenuKeyboardListener(aInstalling); 1.4339 +} 1.4340 + 1.4341 +static bool SchemeIs(nsIURI* aURI, const char* aScheme) 1.4342 +{ 1.4343 + nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI); 1.4344 + NS_ENSURE_TRUE(baseURI, false); 1.4345 + 1.4346 + bool isScheme = false; 1.4347 + return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme; 1.4348 +} 1.4349 + 1.4350 +/* static */ 1.4351 +nsresult 1.4352 +nsContentUtils::CheckSecurityBeforeLoad(nsIURI* aURIToLoad, 1.4353 + nsIPrincipal* aLoadingPrincipal, 1.4354 + uint32_t aCheckLoadFlags, 1.4355 + bool aAllowData, 1.4356 + uint32_t aContentPolicyType, 1.4357 + nsISupports* aContext, 1.4358 + const nsAFlatCString& aMimeGuess, 1.4359 + nsISupports* aExtra) 1.4360 +{ 1.4361 + NS_PRECONDITION(aLoadingPrincipal, "Must have a loading principal here"); 1.4362 + 1.4363 + bool isSystemPrin = false; 1.4364 + if (NS_SUCCEEDED(sSecurityManager->IsSystemPrincipal(aLoadingPrincipal, 1.4365 + &isSystemPrin)) && 1.4366 + isSystemPrin) { 1.4367 + return NS_OK; 1.4368 + } 1.4369 + 1.4370 + // XXXbz do we want to fast-path skin stylesheets loading XBL here somehow? 1.4371 + // CheckLoadURIWithPrincipal 1.4372 + nsresult rv = sSecurityManager-> 1.4373 + CheckLoadURIWithPrincipal(aLoadingPrincipal, aURIToLoad, aCheckLoadFlags); 1.4374 + NS_ENSURE_SUCCESS(rv, rv); 1.4375 + 1.4376 + // Content Policy 1.4377 + int16_t shouldLoad = nsIContentPolicy::ACCEPT; 1.4378 + rv = NS_CheckContentLoadPolicy(aContentPolicyType, 1.4379 + aURIToLoad, 1.4380 + aLoadingPrincipal, 1.4381 + aContext, 1.4382 + aMimeGuess, 1.4383 + aExtra, 1.4384 + &shouldLoad, 1.4385 + GetContentPolicy(), 1.4386 + sSecurityManager); 1.4387 + NS_ENSURE_SUCCESS(rv, rv); 1.4388 + if (NS_CP_REJECTED(shouldLoad)) { 1.4389 + return NS_ERROR_CONTENT_BLOCKED; 1.4390 + } 1.4391 + 1.4392 + // Same Origin 1.4393 + if ((aAllowData && SchemeIs(aURIToLoad, "data")) || 1.4394 + ((aCheckLoadFlags & nsIScriptSecurityManager::ALLOW_CHROME) && 1.4395 + SchemeIs(aURIToLoad, "chrome"))) { 1.4396 + return NS_OK; 1.4397 + } 1.4398 + 1.4399 + return aLoadingPrincipal->CheckMayLoad(aURIToLoad, true, false); 1.4400 +} 1.4401 + 1.4402 +bool 1.4403 +nsContentUtils::IsSystemPrincipal(nsIPrincipal* aPrincipal) 1.4404 +{ 1.4405 + bool isSystem; 1.4406 + nsresult rv = sSecurityManager->IsSystemPrincipal(aPrincipal, &isSystem); 1.4407 + return NS_SUCCEEDED(rv) && isSystem; 1.4408 +} 1.4409 + 1.4410 +bool 1.4411 +nsContentUtils::IsExpandedPrincipal(nsIPrincipal* aPrincipal) 1.4412 +{ 1.4413 + nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal); 1.4414 + return !!ep; 1.4415 +} 1.4416 + 1.4417 +nsIPrincipal* 1.4418 +nsContentUtils::GetSystemPrincipal() 1.4419 +{ 1.4420 + nsCOMPtr<nsIPrincipal> sysPrin; 1.4421 + DebugOnly<nsresult> rv = 1.4422 + sSecurityManager->GetSystemPrincipal(getter_AddRefs(sysPrin)); 1.4423 + MOZ_ASSERT(NS_SUCCEEDED(rv) && sysPrin); 1.4424 + return sysPrin; 1.4425 +} 1.4426 + 1.4427 +bool 1.4428 +nsContentUtils::CombineResourcePrincipals(nsCOMPtr<nsIPrincipal>* aResourcePrincipal, 1.4429 + nsIPrincipal* aExtraPrincipal) 1.4430 +{ 1.4431 + if (!aExtraPrincipal) { 1.4432 + return false; 1.4433 + } 1.4434 + if (!*aResourcePrincipal) { 1.4435 + *aResourcePrincipal = aExtraPrincipal; 1.4436 + return true; 1.4437 + } 1.4438 + if (*aResourcePrincipal == aExtraPrincipal) { 1.4439 + return false; 1.4440 + } 1.4441 + bool subsumes; 1.4442 + if (NS_SUCCEEDED((*aResourcePrincipal)->Subsumes(aExtraPrincipal, &subsumes)) && 1.4443 + subsumes) { 1.4444 + return false; 1.4445 + } 1.4446 + sSecurityManager->GetSystemPrincipal(getter_AddRefs(*aResourcePrincipal)); 1.4447 + return true; 1.4448 +} 1.4449 + 1.4450 +/* static */ 1.4451 +void 1.4452 +nsContentUtils::TriggerLink(nsIContent *aContent, nsPresContext *aPresContext, 1.4453 + nsIURI *aLinkURI, const nsString &aTargetSpec, 1.4454 + bool aClick, bool aIsUserTriggered, 1.4455 + bool aIsTrusted) 1.4456 +{ 1.4457 + NS_ASSERTION(aPresContext, "Need a nsPresContext"); 1.4458 + NS_PRECONDITION(aLinkURI, "No link URI"); 1.4459 + 1.4460 + if (aContent->IsEditable()) { 1.4461 + return; 1.4462 + } 1.4463 + 1.4464 + nsILinkHandler *handler = aPresContext->GetLinkHandler(); 1.4465 + if (!handler) { 1.4466 + return; 1.4467 + } 1.4468 + 1.4469 + if (!aClick) { 1.4470 + handler->OnOverLink(aContent, aLinkURI, aTargetSpec.get()); 1.4471 + return; 1.4472 + } 1.4473 + 1.4474 + // Check that this page is allowed to load this URI. 1.4475 + nsresult proceed = NS_OK; 1.4476 + 1.4477 + if (sSecurityManager) { 1.4478 + uint32_t flag = 1.4479 + aIsUserTriggered ? 1.4480 + (uint32_t)nsIScriptSecurityManager::STANDARD : 1.4481 + (uint32_t)nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT; 1.4482 + proceed = 1.4483 + sSecurityManager->CheckLoadURIWithPrincipal(aContent->NodePrincipal(), 1.4484 + aLinkURI, flag); 1.4485 + } 1.4486 + 1.4487 + // Only pass off the click event if the script security manager says it's ok. 1.4488 + // We need to rest aTargetSpec for forced downloads. 1.4489 + if (NS_SUCCEEDED(proceed)) { 1.4490 + 1.4491 + // A link/area element with a download attribute is allowed to set 1.4492 + // a pseudo Content-Disposition header. 1.4493 + // For security reasons we only allow websites to declare same-origin resources 1.4494 + // as downloadable. If this check fails we will just do the normal thing 1.4495 + // (i.e. navigate to the resource). 1.4496 + nsAutoString fileName; 1.4497 + if ((!aContent->IsHTML(nsGkAtoms::a) && !aContent->IsHTML(nsGkAtoms::area) && 1.4498 + !aContent->IsSVG(nsGkAtoms::a)) || 1.4499 + !aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::download, fileName) || 1.4500 + NS_FAILED(aContent->NodePrincipal()->CheckMayLoad(aLinkURI, false, true))) { 1.4501 + fileName.SetIsVoid(true); // No actionable download attribute was found. 1.4502 + } 1.4503 + 1.4504 + handler->OnLinkClick(aContent, aLinkURI, 1.4505 + fileName.IsVoid() ? aTargetSpec.get() : EmptyString().get(), 1.4506 + fileName, nullptr, nullptr, aIsTrusted); 1.4507 + } 1.4508 +} 1.4509 + 1.4510 +/* static */ 1.4511 +void 1.4512 +nsContentUtils::GetLinkLocation(Element* aElement, nsString& aLocationString) 1.4513 +{ 1.4514 + nsCOMPtr<nsIURI> hrefURI = aElement->GetHrefURI(); 1.4515 + if (hrefURI) { 1.4516 + nsAutoCString specUTF8; 1.4517 + nsresult rv = hrefURI->GetSpec(specUTF8); 1.4518 + if (NS_SUCCEEDED(rv)) 1.4519 + CopyUTF8toUTF16(specUTF8, aLocationString); 1.4520 + } 1.4521 +} 1.4522 + 1.4523 +/* static */ 1.4524 +nsIWidget* 1.4525 +nsContentUtils::GetTopLevelWidget(nsIWidget* aWidget) 1.4526 +{ 1.4527 + if (!aWidget) 1.4528 + return nullptr; 1.4529 + 1.4530 + return aWidget->GetTopLevelWidget(); 1.4531 +} 1.4532 + 1.4533 +/* static */ 1.4534 +const nsDependentString 1.4535 +nsContentUtils::GetLocalizedEllipsis() 1.4536 +{ 1.4537 + static char16_t sBuf[4] = { 0, 0, 0, 0 }; 1.4538 + if (!sBuf[0]) { 1.4539 + nsAdoptingString tmp = Preferences::GetLocalizedString("intl.ellipsis"); 1.4540 + uint32_t len = std::min(uint32_t(tmp.Length()), 1.4541 + uint32_t(ArrayLength(sBuf) - 1)); 1.4542 + CopyUnicodeTo(tmp, 0, sBuf, len); 1.4543 + if (!sBuf[0]) 1.4544 + sBuf[0] = char16_t(0x2026); 1.4545 + } 1.4546 + return nsDependentString(sBuf); 1.4547 +} 1.4548 + 1.4549 +static bool 1.4550 +HasASCIIDigit(const nsTArray<nsShortcutCandidate>& aCandidates) 1.4551 +{ 1.4552 + for (uint32_t i = 0; i < aCandidates.Length(); ++i) { 1.4553 + uint32_t ch = aCandidates[i].mCharCode; 1.4554 + if (ch >= '0' && ch <= '9') 1.4555 + return true; 1.4556 + } 1.4557 + return false; 1.4558 +} 1.4559 + 1.4560 +static bool 1.4561 +CharsCaseInsensitiveEqual(uint32_t aChar1, uint32_t aChar2) 1.4562 +{ 1.4563 + return aChar1 == aChar2 || 1.4564 + (IS_IN_BMP(aChar1) && IS_IN_BMP(aChar2) && 1.4565 + ToLowerCase(char16_t(aChar1)) == ToLowerCase(char16_t(aChar2))); 1.4566 +} 1.4567 + 1.4568 +static bool 1.4569 +IsCaseChangeableChar(uint32_t aChar) 1.4570 +{ 1.4571 + return IS_IN_BMP(aChar) && 1.4572 + ToLowerCase(char16_t(aChar)) != ToUpperCase(char16_t(aChar)); 1.4573 +} 1.4574 + 1.4575 +/* static */ 1.4576 +void 1.4577 +nsContentUtils::GetAccelKeyCandidates(nsIDOMKeyEvent* aDOMKeyEvent, 1.4578 + nsTArray<nsShortcutCandidate>& aCandidates) 1.4579 +{ 1.4580 + NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty"); 1.4581 + 1.4582 + nsAutoString eventType; 1.4583 + aDOMKeyEvent->GetType(eventType); 1.4584 + // Don't process if aDOMKeyEvent is not a keypress event. 1.4585 + if (!eventType.EqualsLiteral("keypress")) 1.4586 + return; 1.4587 + 1.4588 + WidgetKeyboardEvent* nativeKeyEvent = 1.4589 + aDOMKeyEvent->GetInternalNSEvent()->AsKeyboardEvent(); 1.4590 + if (nativeKeyEvent) { 1.4591 + NS_ASSERTION(nativeKeyEvent->eventStructType == NS_KEY_EVENT, 1.4592 + "wrong type of native event"); 1.4593 + // nsShortcutCandidate::mCharCode is a candidate charCode. 1.4594 + // nsShoftcutCandidate::mIgnoreShift means the mCharCode should be tried to 1.4595 + // execute a command with/without shift key state. If this is TRUE, the 1.4596 + // shifted key state should be ignored. Otherwise, don't ignore the state. 1.4597 + // the priority of the charCodes are (shift key is not pressed): 1.4598 + // 0: charCode/false, 1.4599 + // 1: unshiftedCharCodes[0]/false, 2: unshiftedCharCodes[1]/false... 1.4600 + // the priority of the charCodes are (shift key is pressed): 1.4601 + // 0: charCode/false, 1.4602 + // 1: shiftedCharCodes[0]/false, 2: shiftedCharCodes[0]/true, 1.4603 + // 3: shiftedCharCodes[1]/false, 4: shiftedCharCodes[1]/true... 1.4604 + if (nativeKeyEvent->charCode) { 1.4605 + nsShortcutCandidate key(nativeKeyEvent->charCode, false); 1.4606 + aCandidates.AppendElement(key); 1.4607 + } 1.4608 + 1.4609 + uint32_t len = nativeKeyEvent->alternativeCharCodes.Length(); 1.4610 + if (!nativeKeyEvent->IsShift()) { 1.4611 + for (uint32_t i = 0; i < len; ++i) { 1.4612 + uint32_t ch = 1.4613 + nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode; 1.4614 + if (!ch || ch == nativeKeyEvent->charCode) 1.4615 + continue; 1.4616 + 1.4617 + nsShortcutCandidate key(ch, false); 1.4618 + aCandidates.AppendElement(key); 1.4619 + } 1.4620 + // If unshiftedCharCodes doesn't have numeric but shiftedCharCode has it, 1.4621 + // this keyboard layout is AZERTY or similar layout, probably. 1.4622 + // In this case, Accel+[0-9] should be accessible without shift key. 1.4623 + // However, the priority should be lowest. 1.4624 + if (!HasASCIIDigit(aCandidates)) { 1.4625 + for (uint32_t i = 0; i < len; ++i) { 1.4626 + uint32_t ch = 1.4627 + nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode; 1.4628 + if (ch >= '0' && ch <= '9') { 1.4629 + nsShortcutCandidate key(ch, false); 1.4630 + aCandidates.AppendElement(key); 1.4631 + break; 1.4632 + } 1.4633 + } 1.4634 + } 1.4635 + } else { 1.4636 + for (uint32_t i = 0; i < len; ++i) { 1.4637 + uint32_t ch = nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode; 1.4638 + if (!ch) 1.4639 + continue; 1.4640 + 1.4641 + if (ch != nativeKeyEvent->charCode) { 1.4642 + nsShortcutCandidate key(ch, false); 1.4643 + aCandidates.AppendElement(key); 1.4644 + } 1.4645 + 1.4646 + // If the char is an alphabet, the shift key state should not be 1.4647 + // ignored. E.g., Ctrl+Shift+C should not execute Ctrl+C. 1.4648 + 1.4649 + // And checking the charCode is same as unshiftedCharCode too. 1.4650 + // E.g., for Ctrl+Shift+(Plus of Numpad) should not run Ctrl+Plus. 1.4651 + uint32_t unshiftCh = 1.4652 + nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode; 1.4653 + if (CharsCaseInsensitiveEqual(ch, unshiftCh)) 1.4654 + continue; 1.4655 + 1.4656 + // On the Hebrew keyboard layout on Windows, the unshifted char is a 1.4657 + // localized character but the shifted char is a Latin alphabet, 1.4658 + // then, we should not execute without the shift state. See bug 433192. 1.4659 + if (IsCaseChangeableChar(ch)) 1.4660 + continue; 1.4661 + 1.4662 + // Setting the alternative charCode candidates for retry without shift 1.4663 + // key state only when the shift key is pressed. 1.4664 + nsShortcutCandidate key(ch, true); 1.4665 + aCandidates.AppendElement(key); 1.4666 + } 1.4667 + } 1.4668 + } else { 1.4669 + uint32_t charCode; 1.4670 + aDOMKeyEvent->GetCharCode(&charCode); 1.4671 + if (charCode) { 1.4672 + nsShortcutCandidate key(charCode, false); 1.4673 + aCandidates.AppendElement(key); 1.4674 + } 1.4675 + } 1.4676 +} 1.4677 + 1.4678 +/* static */ 1.4679 +void 1.4680 +nsContentUtils::GetAccessKeyCandidates(WidgetKeyboardEvent* aNativeKeyEvent, 1.4681 + nsTArray<uint32_t>& aCandidates) 1.4682 +{ 1.4683 + NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty"); 1.4684 + 1.4685 + // return the lower cased charCode candidates for access keys. 1.4686 + // the priority of the charCodes are: 1.4687 + // 0: charCode, 1: unshiftedCharCodes[0], 2: shiftedCharCodes[0] 1.4688 + // 3: unshiftedCharCodes[1], 4: shiftedCharCodes[1],... 1.4689 + if (aNativeKeyEvent->charCode) { 1.4690 + uint32_t ch = aNativeKeyEvent->charCode; 1.4691 + if (IS_IN_BMP(ch)) 1.4692 + ch = ToLowerCase(char16_t(ch)); 1.4693 + aCandidates.AppendElement(ch); 1.4694 + } 1.4695 + for (uint32_t i = 0; 1.4696 + i < aNativeKeyEvent->alternativeCharCodes.Length(); ++i) { 1.4697 + uint32_t ch[2] = 1.4698 + { aNativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode, 1.4699 + aNativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode }; 1.4700 + for (uint32_t j = 0; j < 2; ++j) { 1.4701 + if (!ch[j]) 1.4702 + continue; 1.4703 + if (IS_IN_BMP(ch[j])) 1.4704 + ch[j] = ToLowerCase(char16_t(ch[j])); 1.4705 + // Don't append the charCode that was already appended. 1.4706 + if (aCandidates.IndexOf(ch[j]) == aCandidates.NoIndex) 1.4707 + aCandidates.AppendElement(ch[j]); 1.4708 + } 1.4709 + } 1.4710 + return; 1.4711 +} 1.4712 + 1.4713 +/* static */ 1.4714 +void 1.4715 +nsContentUtils::AddScriptBlocker() 1.4716 +{ 1.4717 + if (!sScriptBlockerCount) { 1.4718 + NS_ASSERTION(sRunnersCountAtFirstBlocker == 0, 1.4719 + "Should not already have a count"); 1.4720 + sRunnersCountAtFirstBlocker = sBlockedScriptRunners->Length(); 1.4721 + } 1.4722 + ++sScriptBlockerCount; 1.4723 +} 1.4724 + 1.4725 +#ifdef DEBUG 1.4726 +static bool sRemovingScriptBlockers = false; 1.4727 +#endif 1.4728 + 1.4729 +/* static */ 1.4730 +void 1.4731 +nsContentUtils::RemoveScriptBlocker() 1.4732 +{ 1.4733 + MOZ_ASSERT(!sRemovingScriptBlockers); 1.4734 + NS_ASSERTION(sScriptBlockerCount != 0, "Negative script blockers"); 1.4735 + --sScriptBlockerCount; 1.4736 + if (sScriptBlockerCount) { 1.4737 + return; 1.4738 + } 1.4739 + 1.4740 + uint32_t firstBlocker = sRunnersCountAtFirstBlocker; 1.4741 + uint32_t lastBlocker = sBlockedScriptRunners->Length(); 1.4742 + uint32_t originalFirstBlocker = firstBlocker; 1.4743 + uint32_t blockersCount = lastBlocker - firstBlocker; 1.4744 + sRunnersCountAtFirstBlocker = 0; 1.4745 + NS_ASSERTION(firstBlocker <= lastBlocker, 1.4746 + "bad sRunnersCountAtFirstBlocker"); 1.4747 + 1.4748 + while (firstBlocker < lastBlocker) { 1.4749 + nsCOMPtr<nsIRunnable> runnable; 1.4750 + runnable.swap((*sBlockedScriptRunners)[firstBlocker]); 1.4751 + ++firstBlocker; 1.4752 + 1.4753 + // Calling the runnable can reenter us 1.4754 + runnable->Run(); 1.4755 + // So can dropping the reference to the runnable 1.4756 + runnable = nullptr; 1.4757 + 1.4758 + NS_ASSERTION(sRunnersCountAtFirstBlocker == 0, 1.4759 + "Bad count"); 1.4760 + NS_ASSERTION(!sScriptBlockerCount, "This is really bad"); 1.4761 + } 1.4762 +#ifdef DEBUG 1.4763 + AutoRestore<bool> removingScriptBlockers(sRemovingScriptBlockers); 1.4764 + sRemovingScriptBlockers = true; 1.4765 +#endif 1.4766 + sBlockedScriptRunners->RemoveElementsAt(originalFirstBlocker, blockersCount); 1.4767 +} 1.4768 + 1.4769 +/* static */ 1.4770 +bool 1.4771 +nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable) 1.4772 +{ 1.4773 + if (!aRunnable) { 1.4774 + return false; 1.4775 + } 1.4776 + 1.4777 + if (sScriptBlockerCount) { 1.4778 + return sBlockedScriptRunners->AppendElement(aRunnable) != nullptr; 1.4779 + } 1.4780 + 1.4781 + nsCOMPtr<nsIRunnable> run = aRunnable; 1.4782 + run->Run(); 1.4783 + 1.4784 + return true; 1.4785 +} 1.4786 + 1.4787 +void 1.4788 +nsContentUtils::EnterMicroTask() 1.4789 +{ 1.4790 + MOZ_ASSERT(NS_IsMainThread()); 1.4791 + ++sMicroTaskLevel; 1.4792 +} 1.4793 + 1.4794 +void 1.4795 +nsContentUtils::LeaveMicroTask() 1.4796 +{ 1.4797 + MOZ_ASSERT(NS_IsMainThread()); 1.4798 + if (--sMicroTaskLevel == 0) { 1.4799 + nsDOMMutationObserver::HandleMutations(); 1.4800 + nsDocument::ProcessBaseElementQueue(); 1.4801 + } 1.4802 +} 1.4803 + 1.4804 +bool 1.4805 +nsContentUtils::IsInMicroTask() 1.4806 +{ 1.4807 + MOZ_ASSERT(NS_IsMainThread()); 1.4808 + return sMicroTaskLevel != 0; 1.4809 +} 1.4810 + 1.4811 +uint32_t 1.4812 +nsContentUtils::MicroTaskLevel() 1.4813 +{ 1.4814 + MOZ_ASSERT(NS_IsMainThread()); 1.4815 + return sMicroTaskLevel; 1.4816 +} 1.4817 + 1.4818 +void 1.4819 +nsContentUtils::SetMicroTaskLevel(uint32_t aLevel) 1.4820 +{ 1.4821 + MOZ_ASSERT(NS_IsMainThread()); 1.4822 + sMicroTaskLevel = aLevel; 1.4823 +} 1.4824 + 1.4825 +/* 1.4826 + * Helper function for nsContentUtils::ProcessViewportInfo. 1.4827 + * 1.4828 + * Handles a single key=value pair. If it corresponds to a valid viewport 1.4829 + * attribute, add it to the document header data. No validation is done on the 1.4830 + * value itself (this is done at display time). 1.4831 + */ 1.4832 +static void ProcessViewportToken(nsIDocument *aDocument, 1.4833 + const nsAString &token) { 1.4834 + 1.4835 + /* Iterators. */ 1.4836 + nsAString::const_iterator tip, tail, end; 1.4837 + token.BeginReading(tip); 1.4838 + tail = tip; 1.4839 + token.EndReading(end); 1.4840 + 1.4841 + /* Move tip to the '='. */ 1.4842 + while ((tip != end) && (*tip != '=')) 1.4843 + ++tip; 1.4844 + 1.4845 + /* If we didn't find an '=', punt. */ 1.4846 + if (tip == end) 1.4847 + return; 1.4848 + 1.4849 + /* Extract the key and value. */ 1.4850 + const nsAString &key = 1.4851 + nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(Substring(tail, tip), 1.4852 + true); 1.4853 + const nsAString &value = 1.4854 + nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(Substring(++tip, end), 1.4855 + true); 1.4856 + 1.4857 + /* Check for known keys. If we find a match, insert the appropriate 1.4858 + * information into the document header. */ 1.4859 + nsCOMPtr<nsIAtom> key_atom = do_GetAtom(key); 1.4860 + if (key_atom == nsGkAtoms::height) 1.4861 + aDocument->SetHeaderData(nsGkAtoms::viewport_height, value); 1.4862 + else if (key_atom == nsGkAtoms::width) 1.4863 + aDocument->SetHeaderData(nsGkAtoms::viewport_width, value); 1.4864 + else if (key_atom == nsGkAtoms::initial_scale) 1.4865 + aDocument->SetHeaderData(nsGkAtoms::viewport_initial_scale, value); 1.4866 + else if (key_atom == nsGkAtoms::minimum_scale) 1.4867 + aDocument->SetHeaderData(nsGkAtoms::viewport_minimum_scale, value); 1.4868 + else if (key_atom == nsGkAtoms::maximum_scale) 1.4869 + aDocument->SetHeaderData(nsGkAtoms::viewport_maximum_scale, value); 1.4870 + else if (key_atom == nsGkAtoms::user_scalable) 1.4871 + aDocument->SetHeaderData(nsGkAtoms::viewport_user_scalable, value); 1.4872 +} 1.4873 + 1.4874 +#define IS_SEPARATOR(c) ((c == '=') || (c == ',') || (c == ';') || \ 1.4875 + (c == '\t') || (c == '\n') || (c == '\r')) 1.4876 + 1.4877 +/* static */ 1.4878 +nsViewportInfo 1.4879 +nsContentUtils::GetViewportInfo(nsIDocument *aDocument, 1.4880 + const ScreenIntSize& aDisplaySize) 1.4881 +{ 1.4882 + return aDocument->GetViewportInfo(aDisplaySize); 1.4883 +} 1.4884 + 1.4885 +/* static */ 1.4886 +nsresult 1.4887 +nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument, 1.4888 + const nsAString &viewportInfo) { 1.4889 + 1.4890 + /* We never fail. */ 1.4891 + nsresult rv = NS_OK; 1.4892 + 1.4893 + aDocument->SetHeaderData(nsGkAtoms::viewport, viewportInfo); 1.4894 + 1.4895 + /* Iterators. */ 1.4896 + nsAString::const_iterator tip, tail, end; 1.4897 + viewportInfo.BeginReading(tip); 1.4898 + tail = tip; 1.4899 + viewportInfo.EndReading(end); 1.4900 + 1.4901 + /* Read the tip to the first non-separator character. */ 1.4902 + while ((tip != end) && (IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip))) 1.4903 + ++tip; 1.4904 + 1.4905 + /* Read through and find tokens separated by separators. */ 1.4906 + while (tip != end) { 1.4907 + 1.4908 + /* Synchronize tip and tail. */ 1.4909 + tail = tip; 1.4910 + 1.4911 + /* Advance tip past non-separator characters. */ 1.4912 + while ((tip != end) && !IS_SEPARATOR(*tip)) 1.4913 + ++tip; 1.4914 + 1.4915 + /* Allow white spaces that surround the '=' character */ 1.4916 + if ((tip != end) && (*tip == '=')) { 1.4917 + ++tip; 1.4918 + 1.4919 + while ((tip != end) && nsCRT::IsAsciiSpace(*tip)) 1.4920 + ++tip; 1.4921 + 1.4922 + while ((tip != end) && !(IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip))) 1.4923 + ++tip; 1.4924 + } 1.4925 + 1.4926 + /* Our token consists of the characters between tail and tip. */ 1.4927 + ProcessViewportToken(aDocument, Substring(tail, tip)); 1.4928 + 1.4929 + /* Skip separators. */ 1.4930 + while ((tip != end) && (IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip))) 1.4931 + ++tip; 1.4932 + } 1.4933 + 1.4934 + return rv; 1.4935 + 1.4936 +} 1.4937 + 1.4938 +#undef IS_SEPARATOR 1.4939 + 1.4940 +/* static */ 1.4941 +void 1.4942 +nsContentUtils::HidePopupsInDocument(nsIDocument* aDocument) 1.4943 +{ 1.4944 +#ifdef MOZ_XUL 1.4945 + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); 1.4946 + if (pm && aDocument) { 1.4947 + nsCOMPtr<nsIDocShellTreeItem> docShellToHide = aDocument->GetDocShell(); 1.4948 + if (docShellToHide) 1.4949 + pm->HidePopupsInDocShell(docShellToHide); 1.4950 + } 1.4951 +#endif 1.4952 +} 1.4953 + 1.4954 +/* static */ 1.4955 +already_AddRefed<nsIDragSession> 1.4956 +nsContentUtils::GetDragSession() 1.4957 +{ 1.4958 + nsCOMPtr<nsIDragSession> dragSession; 1.4959 + nsCOMPtr<nsIDragService> dragService = 1.4960 + do_GetService("@mozilla.org/widget/dragservice;1"); 1.4961 + if (dragService) 1.4962 + dragService->GetCurrentSession(getter_AddRefs(dragSession)); 1.4963 + return dragSession.forget(); 1.4964 +} 1.4965 + 1.4966 +/* static */ 1.4967 +nsresult 1.4968 +nsContentUtils::SetDataTransferInEvent(WidgetDragEvent* aDragEvent) 1.4969 +{ 1.4970 + if (aDragEvent->dataTransfer || !aDragEvent->mFlags.mIsTrusted) 1.4971 + return NS_OK; 1.4972 + 1.4973 + // For draggesture and dragstart events, the data transfer object is 1.4974 + // created before the event fires, so it should already be set. For other 1.4975 + // drag events, get the object from the drag session. 1.4976 + NS_ASSERTION(aDragEvent->message != NS_DRAGDROP_GESTURE && 1.4977 + aDragEvent->message != NS_DRAGDROP_START, 1.4978 + "draggesture event created without a dataTransfer"); 1.4979 + 1.4980 + nsCOMPtr<nsIDragSession> dragSession = GetDragSession(); 1.4981 + NS_ENSURE_TRUE(dragSession, NS_OK); // no drag in progress 1.4982 + 1.4983 + nsCOMPtr<nsIDOMDataTransfer> dataTransfer; 1.4984 + nsCOMPtr<DataTransfer> initialDataTransfer; 1.4985 + dragSession->GetDataTransfer(getter_AddRefs(dataTransfer)); 1.4986 + if (dataTransfer) { 1.4987 + initialDataTransfer = do_QueryInterface(dataTransfer); 1.4988 + if (!initialDataTransfer) { 1.4989 + return NS_ERROR_FAILURE; 1.4990 + } 1.4991 + } else { 1.4992 + // A dataTransfer won't exist when a drag was started by some other 1.4993 + // means, for instance calling the drag service directly, or a drag 1.4994 + // from another application. In either case, a new dataTransfer should 1.4995 + // be created that reflects the data. 1.4996 + initialDataTransfer = new DataTransfer(aDragEvent->target, aDragEvent->message, true, -1); 1.4997 + 1.4998 + // now set it in the drag session so we don't need to create it again 1.4999 + dragSession->SetDataTransfer(initialDataTransfer); 1.5000 + } 1.5001 + 1.5002 + bool isCrossDomainSubFrameDrop = false; 1.5003 + if (aDragEvent->message == NS_DRAGDROP_DROP || 1.5004 + aDragEvent->message == NS_DRAGDROP_DRAGDROP) { 1.5005 + isCrossDomainSubFrameDrop = CheckForSubFrameDrop(dragSession, aDragEvent); 1.5006 + } 1.5007 + 1.5008 + // each event should use a clone of the original dataTransfer. 1.5009 + initialDataTransfer->Clone(aDragEvent->target, aDragEvent->message, aDragEvent->userCancelled, 1.5010 + isCrossDomainSubFrameDrop, 1.5011 + getter_AddRefs(aDragEvent->dataTransfer)); 1.5012 + NS_ENSURE_TRUE(aDragEvent->dataTransfer, NS_ERROR_OUT_OF_MEMORY); 1.5013 + 1.5014 + // for the dragenter and dragover events, initialize the drop effect 1.5015 + // from the drop action, which platform specific widget code sets before 1.5016 + // the event is fired based on the keyboard state. 1.5017 + if (aDragEvent->message == NS_DRAGDROP_ENTER || 1.5018 + aDragEvent->message == NS_DRAGDROP_OVER) { 1.5019 + uint32_t action, effectAllowed; 1.5020 + dragSession->GetDragAction(&action); 1.5021 + aDragEvent->dataTransfer->GetEffectAllowedInt(&effectAllowed); 1.5022 + aDragEvent->dataTransfer->SetDropEffectInt(FilterDropEffect(action, effectAllowed)); 1.5023 + } 1.5024 + else if (aDragEvent->message == NS_DRAGDROP_DROP || 1.5025 + aDragEvent->message == NS_DRAGDROP_DRAGDROP || 1.5026 + aDragEvent->message == NS_DRAGDROP_END) { 1.5027 + // For the drop and dragend events, set the drop effect based on the 1.5028 + // last value that the dropEffect had. This will have been set in 1.5029 + // EventStateManager::PostHandleEvent for the last dragenter or 1.5030 + // dragover event. 1.5031 + uint32_t dropEffect; 1.5032 + initialDataTransfer->GetDropEffectInt(&dropEffect); 1.5033 + aDragEvent->dataTransfer->SetDropEffectInt(dropEffect); 1.5034 + } 1.5035 + 1.5036 + return NS_OK; 1.5037 +} 1.5038 + 1.5039 +/* static */ 1.5040 +uint32_t 1.5041 +nsContentUtils::FilterDropEffect(uint32_t aAction, uint32_t aEffectAllowed) 1.5042 +{ 1.5043 + // It is possible for the drag action to include more than one action, but 1.5044 + // the widget code which sets the action from the keyboard state should only 1.5045 + // be including one. If multiple actions were set, we just consider them in 1.5046 + // the following order: 1.5047 + // copy, link, move 1.5048 + if (aAction & nsIDragService::DRAGDROP_ACTION_COPY) 1.5049 + aAction = nsIDragService::DRAGDROP_ACTION_COPY; 1.5050 + else if (aAction & nsIDragService::DRAGDROP_ACTION_LINK) 1.5051 + aAction = nsIDragService::DRAGDROP_ACTION_LINK; 1.5052 + else if (aAction & nsIDragService::DRAGDROP_ACTION_MOVE) 1.5053 + aAction = nsIDragService::DRAGDROP_ACTION_MOVE; 1.5054 + 1.5055 + // Filter the action based on the effectAllowed. If the effectAllowed 1.5056 + // doesn't include the action, then that action cannot be done, so adjust 1.5057 + // the action to something that is allowed. For a copy, adjust to move or 1.5058 + // link. For a move, adjust to copy or link. For a link, adjust to move or 1.5059 + // link. Otherwise, use none. 1.5060 + if (aAction & aEffectAllowed || 1.5061 + aEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) 1.5062 + return aAction; 1.5063 + if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_MOVE) 1.5064 + return nsIDragService::DRAGDROP_ACTION_MOVE; 1.5065 + if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_COPY) 1.5066 + return nsIDragService::DRAGDROP_ACTION_COPY; 1.5067 + if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_LINK) 1.5068 + return nsIDragService::DRAGDROP_ACTION_LINK; 1.5069 + return nsIDragService::DRAGDROP_ACTION_NONE; 1.5070 +} 1.5071 + 1.5072 +/* static */ 1.5073 +bool 1.5074 +nsContentUtils::CheckForSubFrameDrop(nsIDragSession* aDragSession, 1.5075 + WidgetDragEvent* aDropEvent) 1.5076 +{ 1.5077 + nsCOMPtr<nsIContent> target = do_QueryInterface(aDropEvent->originalTarget); 1.5078 + if (!target) { 1.5079 + return true; 1.5080 + } 1.5081 + 1.5082 + nsIDocument* targetDoc = target->OwnerDoc(); 1.5083 + nsCOMPtr<nsIWebNavigation> twebnav = do_GetInterface(targetDoc->GetWindow()); 1.5084 + nsCOMPtr<nsIDocShellTreeItem> tdsti = do_QueryInterface(twebnav); 1.5085 + if (!tdsti) { 1.5086 + return true; 1.5087 + } 1.5088 + 1.5089 + // Always allow dropping onto chrome shells. 1.5090 + if (tdsti->ItemType() == nsIDocShellTreeItem::typeChrome) { 1.5091 + return false; 1.5092 + } 1.5093 + 1.5094 + // If there is no source node, then this is a drag from another 1.5095 + // application, which should be allowed. 1.5096 + nsCOMPtr<nsIDOMDocument> sourceDocument; 1.5097 + aDragSession->GetSourceDocument(getter_AddRefs(sourceDocument)); 1.5098 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(sourceDocument); 1.5099 + if (doc) { 1.5100 + // Get each successive parent of the source document and compare it to 1.5101 + // the drop document. If they match, then this is a drag from a child frame. 1.5102 + do { 1.5103 + doc = doc->GetParentDocument(); 1.5104 + if (doc == targetDoc) { 1.5105 + // The drag is from a child frame. 1.5106 + return true; 1.5107 + } 1.5108 + } while (doc); 1.5109 + } 1.5110 + 1.5111 + return false; 1.5112 +} 1.5113 + 1.5114 +/* static */ 1.5115 +bool 1.5116 +nsContentUtils::URIIsLocalFile(nsIURI *aURI) 1.5117 +{ 1.5118 + bool isFile; 1.5119 + nsCOMPtr<nsINetUtil> util = do_QueryInterface(sIOService); 1.5120 + 1.5121 + // Important: we do NOT test the entire URI chain here! 1.5122 + return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI, 1.5123 + nsIProtocolHandler::URI_IS_LOCAL_FILE, 1.5124 + &isFile)) && 1.5125 + isFile; 1.5126 +} 1.5127 + 1.5128 +nsresult 1.5129 +nsContentUtils::SplitURIAtHash(nsIURI *aURI, 1.5130 + nsACString &aBeforeHash, 1.5131 + nsACString &aAfterHash) 1.5132 +{ 1.5133 + // See bug 225910 for why we can't do this using nsIURL. 1.5134 + 1.5135 + aBeforeHash.Truncate(); 1.5136 + aAfterHash.Truncate(); 1.5137 + 1.5138 + NS_ENSURE_ARG_POINTER(aURI); 1.5139 + 1.5140 + nsAutoCString spec; 1.5141 + nsresult rv = aURI->GetSpec(spec); 1.5142 + NS_ENSURE_SUCCESS(rv, rv); 1.5143 + 1.5144 + int32_t index = spec.FindChar('#'); 1.5145 + if (index == -1) { 1.5146 + index = spec.Length(); 1.5147 + } 1.5148 + 1.5149 + aBeforeHash.Assign(Substring(spec, 0, index)); 1.5150 + aAfterHash.Assign(Substring(spec, index)); 1.5151 + return NS_OK; 1.5152 +} 1.5153 + 1.5154 +/* static */ 1.5155 +nsIScriptContext* 1.5156 +nsContentUtils::GetContextForEventHandlers(nsINode* aNode, 1.5157 + nsresult* aRv) 1.5158 +{ 1.5159 + *aRv = NS_OK; 1.5160 + bool hasHadScriptObject = true; 1.5161 + nsIScriptGlobalObject* sgo = 1.5162 + aNode->OwnerDoc()->GetScriptHandlingObject(hasHadScriptObject); 1.5163 + // It is bad if the document doesn't have event handling context, 1.5164 + // but it used to have one. 1.5165 + if (!sgo && hasHadScriptObject) { 1.5166 + *aRv = NS_ERROR_UNEXPECTED; 1.5167 + return nullptr; 1.5168 + } 1.5169 + 1.5170 + if (sgo) { 1.5171 + nsIScriptContext* scx = sgo->GetContext(); 1.5172 + // Bad, no context from script global object! 1.5173 + if (!scx) { 1.5174 + *aRv = NS_ERROR_UNEXPECTED; 1.5175 + return nullptr; 1.5176 + } 1.5177 + return scx; 1.5178 + } 1.5179 + 1.5180 + return nullptr; 1.5181 +} 1.5182 + 1.5183 +/* static */ 1.5184 +JSContext * 1.5185 +nsContentUtils::GetCurrentJSContext() 1.5186 +{ 1.5187 + MOZ_ASSERT(NS_IsMainThread()); 1.5188 + return sXPConnect->GetCurrentJSContext(); 1.5189 +} 1.5190 + 1.5191 +/* static */ 1.5192 +JSContext * 1.5193 +nsContentUtils::GetSafeJSContext() 1.5194 +{ 1.5195 + MOZ_ASSERT(NS_IsMainThread()); 1.5196 + return sXPConnect->GetSafeJSContext(); 1.5197 +} 1.5198 + 1.5199 +/* static */ 1.5200 +JSContext * 1.5201 +nsContentUtils::GetDefaultJSContextForThread() 1.5202 +{ 1.5203 + if (MOZ_LIKELY(NS_IsMainThread())) { 1.5204 + return GetSafeJSContext(); 1.5205 + } else { 1.5206 + return workers::GetCurrentThreadJSContext(); 1.5207 + } 1.5208 +} 1.5209 + 1.5210 +/* static */ 1.5211 +JSContext * 1.5212 +nsContentUtils::GetCurrentJSContextForThread() 1.5213 +{ 1.5214 + if (MOZ_LIKELY(NS_IsMainThread())) { 1.5215 + return GetCurrentJSContext(); 1.5216 + } else { 1.5217 + return workers::GetCurrentThreadJSContext(); 1.5218 + } 1.5219 +} 1.5220 + 1.5221 +/* static */ 1.5222 +nsresult 1.5223 +nsContentUtils::ASCIIToLower(nsAString& aStr) 1.5224 +{ 1.5225 + char16_t* iter = aStr.BeginWriting(); 1.5226 + char16_t* end = aStr.EndWriting(); 1.5227 + if (MOZ_UNLIKELY(!iter || !end)) { 1.5228 + return NS_ERROR_OUT_OF_MEMORY; 1.5229 + } 1.5230 + while (iter != end) { 1.5231 + char16_t c = *iter; 1.5232 + if (c >= 'A' && c <= 'Z') { 1.5233 + *iter = c + ('a' - 'A'); 1.5234 + } 1.5235 + ++iter; 1.5236 + } 1.5237 + return NS_OK; 1.5238 +} 1.5239 + 1.5240 +/* static */ 1.5241 +nsresult 1.5242 +nsContentUtils::ASCIIToLower(const nsAString& aSource, nsAString& aDest) 1.5243 +{ 1.5244 + uint32_t len = aSource.Length(); 1.5245 + aDest.SetLength(len); 1.5246 + if (aDest.Length() == len) { 1.5247 + char16_t* dest = aDest.BeginWriting(); 1.5248 + if (MOZ_UNLIKELY(!dest)) { 1.5249 + return NS_ERROR_OUT_OF_MEMORY; 1.5250 + } 1.5251 + const char16_t* iter = aSource.BeginReading(); 1.5252 + const char16_t* end = aSource.EndReading(); 1.5253 + while (iter != end) { 1.5254 + char16_t c = *iter; 1.5255 + *dest = (c >= 'A' && c <= 'Z') ? 1.5256 + c + ('a' - 'A') : c; 1.5257 + ++iter; 1.5258 + ++dest; 1.5259 + } 1.5260 + return NS_OK; 1.5261 + } 1.5262 + return NS_ERROR_OUT_OF_MEMORY; 1.5263 +} 1.5264 + 1.5265 +/* static */ 1.5266 +nsresult 1.5267 +nsContentUtils::ASCIIToUpper(nsAString& aStr) 1.5268 +{ 1.5269 + char16_t* iter = aStr.BeginWriting(); 1.5270 + char16_t* end = aStr.EndWriting(); 1.5271 + if (MOZ_UNLIKELY(!iter || !end)) { 1.5272 + return NS_ERROR_OUT_OF_MEMORY; 1.5273 + } 1.5274 + while (iter != end) { 1.5275 + char16_t c = *iter; 1.5276 + if (c >= 'a' && c <= 'z') { 1.5277 + *iter = c + ('A' - 'a'); 1.5278 + } 1.5279 + ++iter; 1.5280 + } 1.5281 + return NS_OK; 1.5282 +} 1.5283 + 1.5284 +/* static */ 1.5285 +nsresult 1.5286 +nsContentUtils::ASCIIToUpper(const nsAString& aSource, nsAString& aDest) 1.5287 +{ 1.5288 + uint32_t len = aSource.Length(); 1.5289 + aDest.SetLength(len); 1.5290 + if (aDest.Length() == len) { 1.5291 + char16_t* dest = aDest.BeginWriting(); 1.5292 + if (MOZ_UNLIKELY(!dest)) { 1.5293 + return NS_ERROR_OUT_OF_MEMORY; 1.5294 + } 1.5295 + const char16_t* iter = aSource.BeginReading(); 1.5296 + const char16_t* end = aSource.EndReading(); 1.5297 + while (iter != end) { 1.5298 + char16_t c = *iter; 1.5299 + *dest = (c >= 'a' && c <= 'z') ? 1.5300 + c + ('A' - 'a') : c; 1.5301 + ++iter; 1.5302 + ++dest; 1.5303 + } 1.5304 + return NS_OK; 1.5305 + } 1.5306 + return NS_ERROR_OUT_OF_MEMORY; 1.5307 +} 1.5308 + 1.5309 +/* static */ 1.5310 +bool 1.5311 +nsContentUtils::EqualsIgnoreASCIICase(const nsAString& aStr1, 1.5312 + const nsAString& aStr2) 1.5313 +{ 1.5314 + uint32_t len = aStr1.Length(); 1.5315 + if (len != aStr2.Length()) { 1.5316 + return false; 1.5317 + } 1.5318 + 1.5319 + const char16_t* str1 = aStr1.BeginReading(); 1.5320 + const char16_t* str2 = aStr2.BeginReading(); 1.5321 + const char16_t* end = str1 + len; 1.5322 + 1.5323 + while (str1 < end) { 1.5324 + char16_t c1 = *str1++; 1.5325 + char16_t c2 = *str2++; 1.5326 + 1.5327 + // First check if any bits other than the 0x0020 differs 1.5328 + if ((c1 ^ c2) & 0xffdf) { 1.5329 + return false; 1.5330 + } 1.5331 + 1.5332 + // We know they can only differ in the 0x0020 bit. 1.5333 + // Likely the two chars are the same, so check that first 1.5334 + if (c1 != c2) { 1.5335 + // They do differ, but since it's only in the 0x0020 bit, check if it's 1.5336 + // the same ascii char, but just differing in case 1.5337 + char16_t c1Upper = c1 & 0xffdf; 1.5338 + if (!('A' <= c1Upper && c1Upper <= 'Z')) { 1.5339 + return false; 1.5340 + } 1.5341 + } 1.5342 + } 1.5343 + 1.5344 + return true; 1.5345 +} 1.5346 + 1.5347 +/* static */ 1.5348 +bool 1.5349 +nsContentUtils::StringContainsASCIIUpper(const nsAString& aStr) 1.5350 +{ 1.5351 + const char16_t* iter = aStr.BeginReading(); 1.5352 + const char16_t* end = aStr.EndReading(); 1.5353 + while (iter != end) { 1.5354 + char16_t c = *iter; 1.5355 + if (c >= 'A' && c <= 'Z') { 1.5356 + return true; 1.5357 + } 1.5358 + ++iter; 1.5359 + } 1.5360 + 1.5361 + return false; 1.5362 +} 1.5363 + 1.5364 +/* static */ 1.5365 +nsIInterfaceRequestor* 1.5366 +nsContentUtils::GetSameOriginChecker() 1.5367 +{ 1.5368 + if (!sSameOriginChecker) { 1.5369 + sSameOriginChecker = new SameOriginChecker(); 1.5370 + NS_IF_ADDREF(sSameOriginChecker); 1.5371 + } 1.5372 + return sSameOriginChecker; 1.5373 +} 1.5374 + 1.5375 +/* static */ 1.5376 +nsresult 1.5377 +nsContentUtils::CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel) 1.5378 +{ 1.5379 + if (!nsContentUtils::GetSecurityManager()) 1.5380 + return NS_ERROR_NOT_AVAILABLE; 1.5381 + 1.5382 + nsCOMPtr<nsIPrincipal> oldPrincipal; 1.5383 + nsContentUtils::GetSecurityManager()-> 1.5384 + GetChannelPrincipal(aOldChannel, getter_AddRefs(oldPrincipal)); 1.5385 + 1.5386 + nsCOMPtr<nsIURI> newURI; 1.5387 + aNewChannel->GetURI(getter_AddRefs(newURI)); 1.5388 + nsCOMPtr<nsIURI> newOriginalURI; 1.5389 + aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI)); 1.5390 + 1.5391 + NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI); 1.5392 + 1.5393 + nsresult rv = oldPrincipal->CheckMayLoad(newURI, false, false); 1.5394 + if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) { 1.5395 + rv = oldPrincipal->CheckMayLoad(newOriginalURI, false, false); 1.5396 + } 1.5397 + 1.5398 + return rv; 1.5399 +} 1.5400 + 1.5401 +NS_IMPL_ISUPPORTS(SameOriginChecker, 1.5402 + nsIChannelEventSink, 1.5403 + nsIInterfaceRequestor) 1.5404 + 1.5405 +NS_IMETHODIMP 1.5406 +SameOriginChecker::AsyncOnChannelRedirect(nsIChannel *aOldChannel, 1.5407 + nsIChannel *aNewChannel, 1.5408 + uint32_t aFlags, 1.5409 + nsIAsyncVerifyRedirectCallback *cb) 1.5410 +{ 1.5411 + NS_PRECONDITION(aNewChannel, "Redirecting to null channel?"); 1.5412 + 1.5413 + nsresult rv = nsContentUtils::CheckSameOrigin(aOldChannel, aNewChannel); 1.5414 + if (NS_SUCCEEDED(rv)) { 1.5415 + cb->OnRedirectVerifyCallback(NS_OK); 1.5416 + } 1.5417 + 1.5418 + return rv; 1.5419 +} 1.5420 + 1.5421 +NS_IMETHODIMP 1.5422 +SameOriginChecker::GetInterface(const nsIID & aIID, void **aResult) 1.5423 +{ 1.5424 + return QueryInterface(aIID, aResult); 1.5425 +} 1.5426 + 1.5427 +/* static */ 1.5428 +nsresult 1.5429 +nsContentUtils::GetASCIIOrigin(nsIPrincipal* aPrincipal, nsCString& aOrigin) 1.5430 +{ 1.5431 + NS_PRECONDITION(aPrincipal, "missing principal"); 1.5432 + 1.5433 + aOrigin.Truncate(); 1.5434 + 1.5435 + nsCOMPtr<nsIURI> uri; 1.5436 + nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri)); 1.5437 + NS_ENSURE_SUCCESS(rv, rv); 1.5438 + 1.5439 + if (uri) { 1.5440 + return GetASCIIOrigin(uri, aOrigin); 1.5441 + } 1.5442 + 1.5443 + aOrigin.AssignLiteral("null"); 1.5444 + 1.5445 + return NS_OK; 1.5446 +} 1.5447 + 1.5448 +/* static */ 1.5449 +nsresult 1.5450 +nsContentUtils::GetASCIIOrigin(nsIURI* aURI, nsCString& aOrigin) 1.5451 +{ 1.5452 + NS_PRECONDITION(aURI, "missing uri"); 1.5453 + 1.5454 + aOrigin.Truncate(); 1.5455 + 1.5456 + nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI); 1.5457 + NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED); 1.5458 + 1.5459 + nsCString host; 1.5460 + nsresult rv = uri->GetAsciiHost(host); 1.5461 + 1.5462 + if (NS_SUCCEEDED(rv) && !host.IsEmpty()) { 1.5463 + nsCString scheme; 1.5464 + rv = uri->GetScheme(scheme); 1.5465 + NS_ENSURE_SUCCESS(rv, rv); 1.5466 + 1.5467 + int32_t port = -1; 1.5468 + uri->GetPort(&port); 1.5469 + if (port != -1 && port == NS_GetDefaultPort(scheme.get())) 1.5470 + port = -1; 1.5471 + 1.5472 + nsCString hostPort; 1.5473 + rv = NS_GenerateHostPort(host, port, hostPort); 1.5474 + NS_ENSURE_SUCCESS(rv, rv); 1.5475 + 1.5476 + aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort; 1.5477 + } 1.5478 + else { 1.5479 + aOrigin.AssignLiteral("null"); 1.5480 + } 1.5481 + 1.5482 + return NS_OK; 1.5483 +} 1.5484 + 1.5485 +/* static */ 1.5486 +nsresult 1.5487 +nsContentUtils::GetUTFOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin) 1.5488 +{ 1.5489 + NS_PRECONDITION(aPrincipal, "missing principal"); 1.5490 + 1.5491 + aOrigin.Truncate(); 1.5492 + 1.5493 + nsCOMPtr<nsIURI> uri; 1.5494 + nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri)); 1.5495 + NS_ENSURE_SUCCESS(rv, rv); 1.5496 + 1.5497 + if (uri) { 1.5498 + return GetUTFOrigin(uri, aOrigin); 1.5499 + } 1.5500 + 1.5501 + aOrigin.AssignLiteral("null"); 1.5502 + 1.5503 + return NS_OK; 1.5504 +} 1.5505 + 1.5506 +/* static */ 1.5507 +nsresult 1.5508 +nsContentUtils::GetUTFOrigin(nsIURI* aURI, nsString& aOrigin) 1.5509 +{ 1.5510 + NS_PRECONDITION(aURI, "missing uri"); 1.5511 + 1.5512 + aOrigin.Truncate(); 1.5513 + 1.5514 + nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI); 1.5515 + NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED); 1.5516 + 1.5517 + nsCString host; 1.5518 + nsresult rv = uri->GetHost(host); 1.5519 + 1.5520 + if (NS_SUCCEEDED(rv) && !host.IsEmpty()) { 1.5521 + nsCString scheme; 1.5522 + rv = uri->GetScheme(scheme); 1.5523 + NS_ENSURE_SUCCESS(rv, rv); 1.5524 + 1.5525 + int32_t port = -1; 1.5526 + uri->GetPort(&port); 1.5527 + if (port != -1 && port == NS_GetDefaultPort(scheme.get())) 1.5528 + port = -1; 1.5529 + 1.5530 + nsCString hostPort; 1.5531 + rv = NS_GenerateHostPort(host, port, hostPort); 1.5532 + NS_ENSURE_SUCCESS(rv, rv); 1.5533 + 1.5534 + aOrigin = NS_ConvertUTF8toUTF16( 1.5535 + scheme + NS_LITERAL_CSTRING("://") + hostPort); 1.5536 + } 1.5537 + else { 1.5538 + aOrigin.AssignLiteral("null"); 1.5539 + } 1.5540 + 1.5541 + return NS_OK; 1.5542 +} 1.5543 + 1.5544 +/* static */ 1.5545 +void 1.5546 +nsContentUtils::GetUTFNonNullOrigin(nsIURI* aURI, nsString& aOrigin) 1.5547 +{ 1.5548 + aOrigin.Truncate(); 1.5549 + 1.5550 + nsString origin; 1.5551 + nsresult rv = GetUTFOrigin(aURI, origin); 1.5552 + if (NS_SUCCEEDED(rv) && !origin.EqualsLiteral("null")) { 1.5553 + aOrigin.Assign(origin); 1.5554 + } 1.5555 +} 1.5556 + 1.5557 +/* static */ 1.5558 +nsIDocument* 1.5559 +nsContentUtils::GetDocumentFromScriptContext(nsIScriptContext *aScriptContext) 1.5560 +{ 1.5561 + if (!aScriptContext) { 1.5562 + return nullptr; 1.5563 + } 1.5564 + 1.5565 + nsCOMPtr<nsPIDOMWindow> window = 1.5566 + do_QueryInterface(aScriptContext->GetGlobalObject()); 1.5567 + if (!window) { 1.5568 + return nullptr; 1.5569 + } 1.5570 + 1.5571 + return window->GetDoc(); 1.5572 +} 1.5573 + 1.5574 +/* static */ 1.5575 +bool 1.5576 +nsContentUtils::CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel, bool aAllowIfInheritsPrincipal) 1.5577 +{ 1.5578 + nsCOMPtr<nsIURI> channelURI; 1.5579 + nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI)); 1.5580 + NS_ENSURE_SUCCESS(rv, false); 1.5581 + 1.5582 + return NS_SUCCEEDED(aPrincipal->CheckMayLoad(channelURI, false, aAllowIfInheritsPrincipal)); 1.5583 +} 1.5584 + 1.5585 +nsContentTypeParser::nsContentTypeParser(const nsAString& aString) 1.5586 + : mString(aString), mService(nullptr) 1.5587 +{ 1.5588 + CallGetService("@mozilla.org/network/mime-hdrparam;1", &mService); 1.5589 +} 1.5590 + 1.5591 +nsContentTypeParser::~nsContentTypeParser() 1.5592 +{ 1.5593 + NS_IF_RELEASE(mService); 1.5594 +} 1.5595 + 1.5596 +nsresult 1.5597 +nsContentTypeParser::GetParameter(const char* aParameterName, nsAString& aResult) 1.5598 +{ 1.5599 + NS_ENSURE_TRUE(mService, NS_ERROR_FAILURE); 1.5600 + return mService->GetParameterHTTP(mString, aParameterName, 1.5601 + EmptyCString(), false, nullptr, 1.5602 + aResult); 1.5603 +} 1.5604 + 1.5605 +/* static */ 1.5606 + 1.5607 +bool 1.5608 +nsContentUtils::CanAccessNativeAnon() 1.5609 +{ 1.5610 + return IsCallerChrome() || IsCallerXBL(); 1.5611 +} 1.5612 + 1.5613 +/* static */ nsresult 1.5614 +nsContentUtils::DispatchXULCommand(nsIContent* aTarget, 1.5615 + bool aTrusted, 1.5616 + nsIDOMEvent* aSourceEvent, 1.5617 + nsIPresShell* aShell, 1.5618 + bool aCtrl, 1.5619 + bool aAlt, 1.5620 + bool aShift, 1.5621 + bool aMeta) 1.5622 +{ 1.5623 + NS_ENSURE_STATE(aTarget); 1.5624 + nsIDocument* doc = aTarget->OwnerDoc(); 1.5625 + nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc); 1.5626 + NS_ENSURE_STATE(domDoc); 1.5627 + nsCOMPtr<nsIDOMEvent> event; 1.5628 + domDoc->CreateEvent(NS_LITERAL_STRING("xulcommandevent"), 1.5629 + getter_AddRefs(event)); 1.5630 + nsCOMPtr<nsIDOMXULCommandEvent> xulCommand = do_QueryInterface(event); 1.5631 + nsresult rv = xulCommand->InitCommandEvent(NS_LITERAL_STRING("command"), 1.5632 + true, true, doc->GetWindow(), 1.5633 + 0, aCtrl, aAlt, aShift, aMeta, 1.5634 + aSourceEvent); 1.5635 + NS_ENSURE_SUCCESS(rv, rv); 1.5636 + 1.5637 + if (aShell) { 1.5638 + nsEventStatus status = nsEventStatus_eIgnore; 1.5639 + nsCOMPtr<nsIPresShell> kungFuDeathGrip = aShell; 1.5640 + return aShell->HandleDOMEventWithTarget(aTarget, event, &status); 1.5641 + } 1.5642 + 1.5643 + nsCOMPtr<EventTarget> target = do_QueryInterface(aTarget); 1.5644 + NS_ENSURE_STATE(target); 1.5645 + bool dummy; 1.5646 + return target->DispatchEvent(event, &dummy); 1.5647 +} 1.5648 + 1.5649 +// static 1.5650 +nsresult 1.5651 +nsContentUtils::WrapNative(JSContext *cx, nsISupports *native, 1.5652 + nsWrapperCache *cache, const nsIID* aIID, 1.5653 + JS::MutableHandle<JS::Value> vp, bool aAllowWrapping) 1.5654 +{ 1.5655 + if (!native) { 1.5656 + vp.setNull(); 1.5657 + 1.5658 + return NS_OK; 1.5659 + } 1.5660 + 1.5661 + JSObject *wrapper = xpc_FastGetCachedWrapper(cx, cache, vp); 1.5662 + if (wrapper) { 1.5663 + return NS_OK; 1.5664 + } 1.5665 + 1.5666 + NS_ENSURE_TRUE(sXPConnect, NS_ERROR_UNEXPECTED); 1.5667 + 1.5668 + if (!NS_IsMainThread()) { 1.5669 + MOZ_CRASH(); 1.5670 + } 1.5671 + 1.5672 + nsresult rv = NS_OK; 1.5673 + JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx)); 1.5674 + AutoPushJSContext context(cx); 1.5675 + rv = sXPConnect->WrapNativeToJSVal(context, scope, native, cache, aIID, 1.5676 + aAllowWrapping, vp); 1.5677 + return rv; 1.5678 +} 1.5679 + 1.5680 +nsresult 1.5681 +nsContentUtils::CreateArrayBuffer(JSContext *aCx, const nsACString& aData, 1.5682 + JSObject** aResult) 1.5683 +{ 1.5684 + if (!aCx) { 1.5685 + return NS_ERROR_FAILURE; 1.5686 + } 1.5687 + 1.5688 + int32_t dataLen = aData.Length(); 1.5689 + *aResult = JS_NewArrayBuffer(aCx, dataLen); 1.5690 + if (!*aResult) { 1.5691 + return NS_ERROR_FAILURE; 1.5692 + } 1.5693 + 1.5694 + if (dataLen > 0) { 1.5695 + NS_ASSERTION(JS_IsArrayBufferObject(*aResult), "What happened?"); 1.5696 + memcpy(JS_GetArrayBufferData(*aResult), aData.BeginReading(), dataLen); 1.5697 + } 1.5698 + 1.5699 + return NS_OK; 1.5700 +} 1.5701 + 1.5702 +// Initial implementation: only stores to RAM, not file 1.5703 +// TODO: bug 704447: large file support 1.5704 +nsresult 1.5705 +nsContentUtils::CreateBlobBuffer(JSContext* aCx, 1.5706 + const nsACString& aData, 1.5707 + JS::MutableHandle<JS::Value> aBlob) 1.5708 +{ 1.5709 + uint32_t blobLen = aData.Length(); 1.5710 + void* blobData = moz_malloc(blobLen); 1.5711 + nsCOMPtr<nsIDOMBlob> blob; 1.5712 + if (blobData) { 1.5713 + memcpy(blobData, aData.BeginReading(), blobLen); 1.5714 + blob = new nsDOMMemoryFile(blobData, blobLen, EmptyString()); 1.5715 + } else { 1.5716 + return NS_ERROR_OUT_OF_MEMORY; 1.5717 + } 1.5718 + return nsContentUtils::WrapNative(aCx, blob, aBlob); 1.5719 +} 1.5720 + 1.5721 +void 1.5722 +nsContentUtils::StripNullChars(const nsAString& aInStr, nsAString& aOutStr) 1.5723 +{ 1.5724 + // In common cases where we don't have nulls in the 1.5725 + // string we can simple simply bypass the checking code. 1.5726 + int32_t firstNullPos = aInStr.FindChar('\0'); 1.5727 + if (firstNullPos == kNotFound) { 1.5728 + aOutStr.Assign(aInStr); 1.5729 + return; 1.5730 + } 1.5731 + 1.5732 + aOutStr.SetCapacity(aInStr.Length() - 1); 1.5733 + nsAString::const_iterator start, end; 1.5734 + aInStr.BeginReading(start); 1.5735 + aInStr.EndReading(end); 1.5736 + while (start != end) { 1.5737 + if (*start != '\0') 1.5738 + aOutStr.Append(*start); 1.5739 + ++start; 1.5740 + } 1.5741 +} 1.5742 + 1.5743 +struct ClassMatchingInfo { 1.5744 + nsAttrValue::AtomArray mClasses; 1.5745 + nsCaseTreatment mCaseTreatment; 1.5746 +}; 1.5747 + 1.5748 +// static 1.5749 +bool 1.5750 +nsContentUtils::MatchClassNames(nsIContent* aContent, int32_t aNamespaceID, 1.5751 + nsIAtom* aAtom, void* aData) 1.5752 +{ 1.5753 + // We can't match if there are no class names 1.5754 + const nsAttrValue* classAttr = aContent->GetClasses(); 1.5755 + if (!classAttr) { 1.5756 + return false; 1.5757 + } 1.5758 + 1.5759 + // need to match *all* of the classes 1.5760 + ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData); 1.5761 + uint32_t length = info->mClasses.Length(); 1.5762 + if (!length) { 1.5763 + // If we actually had no classes, don't match. 1.5764 + return false; 1.5765 + } 1.5766 + uint32_t i; 1.5767 + for (i = 0; i < length; ++i) { 1.5768 + if (!classAttr->Contains(info->mClasses[i], 1.5769 + info->mCaseTreatment)) { 1.5770 + return false; 1.5771 + } 1.5772 + } 1.5773 + 1.5774 + return true; 1.5775 +} 1.5776 + 1.5777 +// static 1.5778 +void 1.5779 +nsContentUtils::DestroyClassNameArray(void* aData) 1.5780 +{ 1.5781 + ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData); 1.5782 + delete info; 1.5783 +} 1.5784 + 1.5785 +// static 1.5786 +void* 1.5787 +nsContentUtils::AllocClassMatchingInfo(nsINode* aRootNode, 1.5788 + const nsString* aClasses) 1.5789 +{ 1.5790 + nsAttrValue attrValue; 1.5791 + attrValue.ParseAtomArray(*aClasses); 1.5792 + // nsAttrValue::Equals is sensitive to order, so we'll send an array 1.5793 + ClassMatchingInfo* info = new ClassMatchingInfo; 1.5794 + if (attrValue.Type() == nsAttrValue::eAtomArray) { 1.5795 + info->mClasses.SwapElements(*(attrValue.GetAtomArrayValue())); 1.5796 + } else if (attrValue.Type() == nsAttrValue::eAtom) { 1.5797 + info->mClasses.AppendElement(attrValue.GetAtomValue()); 1.5798 + } 1.5799 + 1.5800 + info->mCaseTreatment = 1.5801 + aRootNode->OwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks ? 1.5802 + eIgnoreCase : eCaseMatters; 1.5803 + return info; 1.5804 +} 1.5805 + 1.5806 +// static 1.5807 +void 1.5808 +nsContentUtils::DeferredFinalize(nsISupports* aSupports) 1.5809 +{ 1.5810 + cyclecollector::DeferredFinalize(aSupports); 1.5811 +} 1.5812 + 1.5813 +// static 1.5814 +void 1.5815 +nsContentUtils::DeferredFinalize(mozilla::DeferredFinalizeAppendFunction aAppendFunc, 1.5816 + mozilla::DeferredFinalizeFunction aFunc, 1.5817 + void* aThing) 1.5818 +{ 1.5819 + cyclecollector::DeferredFinalize(aAppendFunc, aFunc, aThing); 1.5820 +} 1.5821 + 1.5822 +// static 1.5823 +bool 1.5824 +nsContentUtils::IsFocusedContent(const nsIContent* aContent) 1.5825 +{ 1.5826 + nsFocusManager* fm = nsFocusManager::GetFocusManager(); 1.5827 + 1.5828 + return fm && fm->GetFocusedContent() == aContent; 1.5829 +} 1.5830 + 1.5831 +bool 1.5832 +nsContentUtils::IsSubDocumentTabbable(nsIContent* aContent) 1.5833 +{ 1.5834 + nsIDocument* doc = aContent->GetCurrentDoc(); 1.5835 + if (!doc) { 1.5836 + return false; 1.5837 + } 1.5838 + 1.5839 + // If the subdocument lives in another process, the frame is 1.5840 + // tabbable. 1.5841 + if (EventStateManager::IsRemoteTarget(aContent)) { 1.5842 + return true; 1.5843 + } 1.5844 + 1.5845 + // XXXbz should this use OwnerDoc() for GetSubDocumentFor? 1.5846 + // sXBL/XBL2 issue! 1.5847 + nsIDocument* subDoc = doc->GetSubDocumentFor(aContent); 1.5848 + if (!subDoc) { 1.5849 + return false; 1.5850 + } 1.5851 + 1.5852 + nsCOMPtr<nsIDocShell> docShell = subDoc->GetDocShell(); 1.5853 + if (!docShell) { 1.5854 + return false; 1.5855 + } 1.5856 + 1.5857 + nsCOMPtr<nsIContentViewer> contentViewer; 1.5858 + docShell->GetContentViewer(getter_AddRefs(contentViewer)); 1.5859 + if (!contentViewer) { 1.5860 + return false; 1.5861 + } 1.5862 + 1.5863 + nsCOMPtr<nsIContentViewer> zombieViewer; 1.5864 + contentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer)); 1.5865 + 1.5866 + // If there are 2 viewers for the current docshell, that 1.5867 + // means the current document is a zombie document. 1.5868 + // Only navigate into the subdocument if it's not a zombie. 1.5869 + return !zombieViewer; 1.5870 +} 1.5871 + 1.5872 +bool 1.5873 +nsContentUtils::IsUserFocusIgnored(nsINode* aNode) 1.5874 +{ 1.5875 + if (!nsGenericHTMLFrameElement::BrowserFramesEnabled()) { 1.5876 + return false; 1.5877 + } 1.5878 + 1.5879 + // Check if our mozbrowser iframe ancestors has ignoreuserfocus attribute. 1.5880 + while (aNode) { 1.5881 + nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(aNode); 1.5882 + if (browserFrame && 1.5883 + aNode->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::ignoreuserfocus) && 1.5884 + browserFrame->GetReallyIsBrowserOrApp()) { 1.5885 + return true; 1.5886 + } 1.5887 + nsPIDOMWindow* win = aNode->OwnerDoc()->GetWindow(); 1.5888 + aNode = win ? win->GetFrameElementInternal() : nullptr; 1.5889 + } 1.5890 + 1.5891 + return false; 1.5892 +} 1.5893 + 1.5894 +bool 1.5895 +nsContentUtils::HasScrollgrab(nsIContent* aContent) 1.5896 +{ 1.5897 + nsGenericHTMLElement* element = nsGenericHTMLElement::FromContentOrNull(aContent); 1.5898 + return element && element->Scrollgrab(); 1.5899 +} 1.5900 + 1.5901 +void 1.5902 +nsContentUtils::FlushLayoutForTree(nsIDOMWindow* aWindow) 1.5903 +{ 1.5904 + nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow); 1.5905 + if (!piWin) 1.5906 + return; 1.5907 + 1.5908 + // Note that because FlushPendingNotifications flushes parents, this 1.5909 + // is O(N^2) in docshell tree depth. However, the docshell tree is 1.5910 + // usually pretty shallow. 1.5911 + 1.5912 + nsCOMPtr<nsIDOMDocument> domDoc; 1.5913 + aWindow->GetDocument(getter_AddRefs(domDoc)); 1.5914 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); 1.5915 + if (doc) { 1.5916 + doc->FlushPendingNotifications(Flush_Layout); 1.5917 + } 1.5918 + 1.5919 + nsCOMPtr<nsIDocShell> docShell = piWin->GetDocShell(); 1.5920 + if (docShell) { 1.5921 + int32_t i = 0, i_end; 1.5922 + docShell->GetChildCount(&i_end); 1.5923 + for (; i < i_end; ++i) { 1.5924 + nsCOMPtr<nsIDocShellTreeItem> item; 1.5925 + docShell->GetChildAt(i, getter_AddRefs(item)); 1.5926 + nsCOMPtr<nsIDOMWindow> win = do_GetInterface(item); 1.5927 + if (win) { 1.5928 + FlushLayoutForTree(win); 1.5929 + } 1.5930 + } 1.5931 + } 1.5932 +} 1.5933 + 1.5934 +void nsContentUtils::RemoveNewlines(nsString &aString) 1.5935 +{ 1.5936 + // strip CR/LF and null 1.5937 + static const char badChars[] = {'\r', '\n', 0}; 1.5938 + aString.StripChars(badChars); 1.5939 +} 1.5940 + 1.5941 +void 1.5942 +nsContentUtils::PlatformToDOMLineBreaks(nsString &aString) 1.5943 +{ 1.5944 + if (aString.FindChar(char16_t('\r')) != -1) { 1.5945 + // Windows linebreaks: Map CRLF to LF: 1.5946 + aString.ReplaceSubstring(MOZ_UTF16("\r\n"), 1.5947 + MOZ_UTF16("\n")); 1.5948 + 1.5949 + // Mac linebreaks: Map any remaining CR to LF: 1.5950 + aString.ReplaceSubstring(MOZ_UTF16("\r"), 1.5951 + MOZ_UTF16("\n")); 1.5952 + } 1.5953 +} 1.5954 + 1.5955 +void 1.5956 +nsContentUtils::PopulateStringFromStringBuffer(nsStringBuffer* aBuf, 1.5957 + nsAString& aResultString) 1.5958 +{ 1.5959 + MOZ_ASSERT(aBuf, "Expecting a non-null string buffer"); 1.5960 + 1.5961 + uint32_t stringLen = NS_strlen(static_cast<char16_t*>(aBuf->Data())); 1.5962 + 1.5963 + // SANITY CHECK: In case the nsStringBuffer isn't correctly 1.5964 + // null-terminated, let's clamp its length using the allocated size, to be 1.5965 + // sure the resulting string doesn't sample past the end of the the buffer. 1.5966 + // (Note that StorageSize() is in units of bytes, so we have to convert that 1.5967 + // to units of PRUnichars, and subtract 1 for the null-terminator.) 1.5968 + uint32_t allocStringLen = (aBuf->StorageSize() / sizeof(char16_t)) - 1; 1.5969 + MOZ_ASSERT(stringLen <= allocStringLen, 1.5970 + "string buffer lacks null terminator!"); 1.5971 + stringLen = std::min(stringLen, allocStringLen); 1.5972 + 1.5973 + aBuf->ToString(stringLen, aResultString); 1.5974 +} 1.5975 + 1.5976 +nsIPresShell* 1.5977 +nsContentUtils::FindPresShellForDocument(const nsIDocument* aDoc) 1.5978 +{ 1.5979 + const nsIDocument* doc = aDoc; 1.5980 + nsIDocument* displayDoc = doc->GetDisplayDocument(); 1.5981 + if (displayDoc) { 1.5982 + doc = displayDoc; 1.5983 + } 1.5984 + 1.5985 + nsIPresShell* shell = doc->GetShell(); 1.5986 + if (shell) { 1.5987 + return shell; 1.5988 + } 1.5989 + 1.5990 + nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell(); 1.5991 + while (docShellTreeItem) { 1.5992 + // We may be in a display:none subdocument, or we may not have a presshell 1.5993 + // created yet. 1.5994 + // Walk the docshell tree to find the nearest container that has a presshell, 1.5995 + // and return that. 1.5996 + nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(docShellTreeItem); 1.5997 + nsIPresShell* presShell = docShell->GetPresShell(); 1.5998 + if (presShell) { 1.5999 + return presShell; 1.6000 + } 1.6001 + nsCOMPtr<nsIDocShellTreeItem> parent; 1.6002 + docShellTreeItem->GetParent(getter_AddRefs(parent)); 1.6003 + docShellTreeItem = parent; 1.6004 + } 1.6005 + 1.6006 + return nullptr; 1.6007 +} 1.6008 + 1.6009 +nsIWidget* 1.6010 +nsContentUtils::WidgetForDocument(const nsIDocument* aDoc) 1.6011 +{ 1.6012 + nsIPresShell* shell = FindPresShellForDocument(aDoc); 1.6013 + if (shell) { 1.6014 + nsViewManager* VM = shell->GetViewManager(); 1.6015 + if (VM) { 1.6016 + nsView* rootView = VM->GetRootView(); 1.6017 + if (rootView) { 1.6018 + nsView* displayRoot = nsViewManager::GetDisplayRootFor(rootView); 1.6019 + if (displayRoot) { 1.6020 + return displayRoot->GetNearestWidget(nullptr); 1.6021 + } 1.6022 + } 1.6023 + } 1.6024 + } 1.6025 + 1.6026 + return nullptr; 1.6027 +} 1.6028 + 1.6029 +static already_AddRefed<LayerManager> 1.6030 +LayerManagerForDocumentInternal(const nsIDocument *aDoc, bool aRequirePersistent, 1.6031 + bool* aAllowRetaining) 1.6032 +{ 1.6033 + nsIWidget *widget = nsContentUtils::WidgetForDocument(aDoc); 1.6034 + if (widget) { 1.6035 + nsRefPtr<LayerManager> manager = 1.6036 + widget->GetLayerManager(aRequirePersistent ? nsIWidget::LAYER_MANAGER_PERSISTENT : 1.6037 + nsIWidget::LAYER_MANAGER_CURRENT, 1.6038 + aAllowRetaining); 1.6039 + return manager.forget(); 1.6040 + } 1.6041 + 1.6042 + return nullptr; 1.6043 +} 1.6044 + 1.6045 +already_AddRefed<LayerManager> 1.6046 +nsContentUtils::LayerManagerForDocument(const nsIDocument *aDoc, bool *aAllowRetaining) 1.6047 +{ 1.6048 + return LayerManagerForDocumentInternal(aDoc, false, aAllowRetaining); 1.6049 +} 1.6050 + 1.6051 +already_AddRefed<LayerManager> 1.6052 +nsContentUtils::PersistentLayerManagerForDocument(nsIDocument *aDoc, bool *aAllowRetaining) 1.6053 +{ 1.6054 + return LayerManagerForDocumentInternal(aDoc, true, aAllowRetaining); 1.6055 +} 1.6056 + 1.6057 +bool 1.6058 +nsContentUtils::AllowXULXBLForPrincipal(nsIPrincipal* aPrincipal) 1.6059 +{ 1.6060 + if (IsSystemPrincipal(aPrincipal)) { 1.6061 + return true; 1.6062 + } 1.6063 + 1.6064 + nsCOMPtr<nsIURI> princURI; 1.6065 + aPrincipal->GetURI(getter_AddRefs(princURI)); 1.6066 + 1.6067 + return princURI && 1.6068 + ((sAllowXULXBL_for_file && SchemeIs(princURI, "file")) || 1.6069 + IsSitePermAllow(aPrincipal, "allowXULXBL")); 1.6070 +} 1.6071 + 1.6072 +already_AddRefed<nsIDocumentLoaderFactory> 1.6073 +nsContentUtils::FindInternalContentViewer(const char* aType, 1.6074 + ContentViewerType* aLoaderType) 1.6075 +{ 1.6076 + if (aLoaderType) { 1.6077 + *aLoaderType = TYPE_UNSUPPORTED; 1.6078 + } 1.6079 + 1.6080 + // one helper factory, please 1.6081 + nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); 1.6082 + if (!catMan) 1.6083 + return nullptr; 1.6084 + 1.6085 + nsCOMPtr<nsIDocumentLoaderFactory> docFactory; 1.6086 + 1.6087 + nsXPIDLCString contractID; 1.6088 + nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", aType, getter_Copies(contractID)); 1.6089 + if (NS_SUCCEEDED(rv)) { 1.6090 + docFactory = do_GetService(contractID); 1.6091 + if (docFactory && aLoaderType) { 1.6092 + if (contractID.EqualsLiteral(CONTENT_DLF_CONTRACTID)) 1.6093 + *aLoaderType = TYPE_CONTENT; 1.6094 + else if (contractID.EqualsLiteral(PLUGIN_DLF_CONTRACTID)) 1.6095 + *aLoaderType = TYPE_PLUGIN; 1.6096 + else 1.6097 + *aLoaderType = TYPE_UNKNOWN; 1.6098 + } 1.6099 + return docFactory.forget(); 1.6100 + } 1.6101 + 1.6102 + if (DecoderTraits::IsSupportedInVideoDocument(nsDependentCString(aType))) { 1.6103 + docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1"); 1.6104 + if (docFactory && aLoaderType) { 1.6105 + *aLoaderType = TYPE_CONTENT; 1.6106 + } 1.6107 + return docFactory.forget(); 1.6108 + } 1.6109 + 1.6110 + return nullptr; 1.6111 +} 1.6112 + 1.6113 +bool 1.6114 +nsContentUtils::GetContentSecurityPolicy(JSContext* aCx, 1.6115 + nsIContentSecurityPolicy** aCSP) 1.6116 +{ 1.6117 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.6118 + 1.6119 + // Get the security manager 1.6120 + nsCOMPtr<nsIScriptSecurityManager> ssm = nsContentUtils::GetSecurityManager(); 1.6121 + 1.6122 + if (!ssm) { 1.6123 + NS_ERROR("Failed to get security manager service"); 1.6124 + return false; 1.6125 + } 1.6126 + 1.6127 + nsCOMPtr<nsIPrincipal> subjectPrincipal = ssm->GetCxSubjectPrincipal(aCx); 1.6128 + NS_ASSERTION(subjectPrincipal, "Failed to get subjectPrincipal"); 1.6129 + 1.6130 + nsCOMPtr<nsIContentSecurityPolicy> csp; 1.6131 + nsresult rv = subjectPrincipal->GetCsp(getter_AddRefs(csp)); 1.6132 + if (NS_FAILED(rv)) { 1.6133 + NS_ERROR("CSP: Failed to get CSP from principal."); 1.6134 + return false; 1.6135 + } 1.6136 + 1.6137 + csp.forget(aCSP); 1.6138 + return true; 1.6139 +} 1.6140 + 1.6141 +// static 1.6142 +bool 1.6143 +nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern, 1.6144 + nsIDocument* aDocument) 1.6145 +{ 1.6146 + NS_ASSERTION(aDocument, "aDocument should be a valid pointer (not null)"); 1.6147 + nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aDocument->GetWindow()); 1.6148 + NS_ENSURE_TRUE(sgo, true); 1.6149 + 1.6150 + AutoPushJSContext cx(sgo->GetContext()->GetNativeContext()); 1.6151 + NS_ENSURE_TRUE(cx, true); 1.6152 + 1.6153 + // The pattern has to match the entire value. 1.6154 + aPattern.Insert(NS_LITERAL_STRING("^(?:"), 0); 1.6155 + aPattern.Append(NS_LITERAL_STRING(")$")); 1.6156 + 1.6157 + JS::Rooted<JSObject*> re(cx, 1.6158 + JS_NewUCRegExpObjectNoStatics(cx, 1.6159 + static_cast<jschar*>(aPattern.BeginWriting()), 1.6160 + aPattern.Length(), 0)); 1.6161 + if (!re) { 1.6162 + JS_ClearPendingException(cx); 1.6163 + return true; 1.6164 + } 1.6165 + 1.6166 + JS::Rooted<JS::Value> rval(cx, JS::NullValue()); 1.6167 + size_t idx = 0; 1.6168 + if (!JS_ExecuteRegExpNoStatics(cx, re, 1.6169 + static_cast<jschar*>(aValue.BeginWriting()), 1.6170 + aValue.Length(), &idx, true, &rval)) { 1.6171 + JS_ClearPendingException(cx); 1.6172 + return true; 1.6173 + } 1.6174 + 1.6175 + return !rval.isNull(); 1.6176 +} 1.6177 + 1.6178 +// static 1.6179 +nsresult 1.6180 +nsContentUtils::URIInheritsSecurityContext(nsIURI *aURI, bool *aResult) 1.6181 +{ 1.6182 + // Note: about:blank URIs do NOT inherit the security context from the 1.6183 + // current document, which is what this function tests for... 1.6184 + return NS_URIChainHasFlags(aURI, 1.6185 + nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, 1.6186 + aResult); 1.6187 +} 1.6188 + 1.6189 +// static 1.6190 +bool 1.6191 +nsContentUtils::SetUpChannelOwner(nsIPrincipal* aLoadingPrincipal, 1.6192 + nsIChannel* aChannel, 1.6193 + nsIURI* aURI, 1.6194 + bool aSetUpForAboutBlank, 1.6195 + bool aForceOwner) 1.6196 +{ 1.6197 + // 1.6198 + // Set the owner of the channel, but only for channels that can't 1.6199 + // provide their own security context. 1.6200 + // 1.6201 + // XXX: It seems wrong that the owner is ignored - even if one is 1.6202 + // supplied) unless the URI is javascript or data or about:blank. 1.6203 + // XXX: If this is ever changed, check all callers for what owners 1.6204 + // they're passing in. In particular, see the code and 1.6205 + // comments in nsDocShell::LoadURI where we fall back on 1.6206 + // inheriting the owner if called from chrome. That would be 1.6207 + // very wrong if this code changed anything but channels that 1.6208 + // can't provide their own security context! 1.6209 + // 1.6210 + // (Currently chrome URIs set the owner when they are created! 1.6211 + // So setting a nullptr owner would be bad!) 1.6212 + // 1.6213 + // If aForceOwner is true, the owner will be set, even for a channel that 1.6214 + // can provide its own security context. This is used for the HTML5 IFRAME 1.6215 + // sandbox attribute, so we can force the channel (and its document) to 1.6216 + // explicitly have a null principal. 1.6217 + bool inherit; 1.6218 + // We expect URIInheritsSecurityContext to return success for an 1.6219 + // about:blank URI, so don't call NS_IsAboutBlank() if this call fails. 1.6220 + // This condition needs to match the one in nsDocShell::InternalLoad where 1.6221 + // we're checking for things that will use the owner. 1.6222 + if (aForceOwner || ((NS_SUCCEEDED(URIInheritsSecurityContext(aURI, &inherit)) && 1.6223 + (inherit || (aSetUpForAboutBlank && NS_IsAboutBlank(aURI)))))) { 1.6224 +#ifdef DEBUG 1.6225 + // Assert that aForceOwner is only set for null principals for non-srcdoc 1.6226 + // loads. (Strictly speaking not all uses of about:srcdoc would be 1.6227 + // srcdoc loads, but the URI is non-resolvable in cases where it is not). 1.6228 + if (aForceOwner) { 1.6229 + nsAutoCString uriStr; 1.6230 + aURI->GetSpec(uriStr); 1.6231 + if(!uriStr.EqualsLiteral("about:srcdoc") && 1.6232 + !uriStr.EqualsLiteral("view-source:about:srcdoc")) { 1.6233 + nsCOMPtr<nsIURI> ownerURI; 1.6234 + nsresult rv = aLoadingPrincipal->GetURI(getter_AddRefs(ownerURI)); 1.6235 + MOZ_ASSERT(NS_SUCCEEDED(rv) && SchemeIs(ownerURI, NS_NULLPRINCIPAL_SCHEME)); 1.6236 + } 1.6237 + } 1.6238 +#endif 1.6239 + aChannel->SetOwner(aLoadingPrincipal); 1.6240 + return true; 1.6241 + } 1.6242 + 1.6243 + // 1.6244 + // file: uri special-casing 1.6245 + // 1.6246 + // If this is a file: load opened from another file: then it may need 1.6247 + // to inherit the owner from the referrer so they can script each other. 1.6248 + // If we don't set the owner explicitly then each file: gets an owner 1.6249 + // based on its own codebase later. 1.6250 + // 1.6251 + if (URIIsLocalFile(aURI) && aLoadingPrincipal && 1.6252 + NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, false, false)) && 1.6253 + // One more check here. CheckMayLoad will always return true for the 1.6254 + // system principal, but we do NOT want to inherit in that case. 1.6255 + !IsSystemPrincipal(aLoadingPrincipal)) { 1.6256 + aChannel->SetOwner(aLoadingPrincipal); 1.6257 + return true; 1.6258 + } 1.6259 + 1.6260 + return false; 1.6261 +} 1.6262 + 1.6263 +/* static */ 1.6264 +bool 1.6265 +nsContentUtils::IsFullScreenApiEnabled() 1.6266 +{ 1.6267 + return sIsFullScreenApiEnabled; 1.6268 +} 1.6269 + 1.6270 +/* static */ 1.6271 +bool 1.6272 +nsContentUtils::IsRequestFullScreenAllowed() 1.6273 +{ 1.6274 + return !sTrustedFullScreenOnly || 1.6275 + EventStateManager::IsHandlingUserInput() || 1.6276 + IsCallerChrome(); 1.6277 +} 1.6278 + 1.6279 +/* static */ 1.6280 +bool 1.6281 +nsContentUtils::IsFullscreenApiContentOnly() 1.6282 +{ 1.6283 + return sFullscreenApiIsContentOnly; 1.6284 +} 1.6285 + 1.6286 +/* static */ 1.6287 +bool 1.6288 +nsContentUtils::HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2) 1.6289 +{ 1.6290 + if (!aDoc1 || !aDoc2) { 1.6291 + return false; 1.6292 + } 1.6293 + bool principalsEqual = false; 1.6294 + aDoc1->NodePrincipal()->Equals(aDoc2->NodePrincipal(), &principalsEqual); 1.6295 + return principalsEqual; 1.6296 +} 1.6297 + 1.6298 +static void 1.6299 +CheckForWindowedPlugins(nsIContent* aContent, void* aResult) 1.6300 +{ 1.6301 + if (!aContent->IsInDoc()) { 1.6302 + return; 1.6303 + } 1.6304 + nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent)); 1.6305 + if (!olc) { 1.6306 + return; 1.6307 + } 1.6308 + nsRefPtr<nsNPAPIPluginInstance> plugin; 1.6309 + olc->GetPluginInstance(getter_AddRefs(plugin)); 1.6310 + if (!plugin) { 1.6311 + return; 1.6312 + } 1.6313 + bool isWindowless = false; 1.6314 + nsresult res = plugin->IsWindowless(&isWindowless); 1.6315 + if (NS_SUCCEEDED(res) && !isWindowless) { 1.6316 + *static_cast<bool*>(aResult) = true; 1.6317 + } 1.6318 +} 1.6319 + 1.6320 +static bool 1.6321 +DocTreeContainsWindowedPlugins(nsIDocument* aDoc, void* aResult) 1.6322 +{ 1.6323 + if (!nsContentUtils::IsChromeDoc(aDoc)) { 1.6324 + aDoc->EnumerateFreezableElements(CheckForWindowedPlugins, aResult); 1.6325 + } 1.6326 + if (*static_cast<bool*>(aResult)) { 1.6327 + // Return false to stop iteration, we found a windowed plugin. 1.6328 + return false; 1.6329 + } 1.6330 + aDoc->EnumerateSubDocuments(DocTreeContainsWindowedPlugins, aResult); 1.6331 + // Return false to stop iteration if we found a windowed plugin in 1.6332 + // the sub documents. 1.6333 + return !*static_cast<bool*>(aResult); 1.6334 +} 1.6335 + 1.6336 +/* static */ 1.6337 +bool 1.6338 +nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc) 1.6339 +{ 1.6340 +#ifdef XP_MACOSX 1.6341 + // We control dispatch to all mac plugins. 1.6342 + return false; 1.6343 +#endif 1.6344 + bool result = false; 1.6345 + 1.6346 + // Find the top of the document's branch, the child of the chrome document. 1.6347 + nsIDocument* doc = aDoc; 1.6348 + nsIDocument* parent = nullptr; 1.6349 + while (doc && (parent = doc->GetParentDocument()) && !IsChromeDoc(parent)) { 1.6350 + doc = parent; 1.6351 + } 1.6352 + 1.6353 + DocTreeContainsWindowedPlugins(doc, &result); 1.6354 + return result; 1.6355 +} 1.6356 + 1.6357 +/* static */ 1.6358 +bool 1.6359 +nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent) 1.6360 +{ 1.6361 +#ifdef XP_MACOSX 1.6362 + // We control dispatch to all mac plugins. 1.6363 + return false; 1.6364 +#endif 1.6365 + bool result = false; 1.6366 + CheckForWindowedPlugins(aContent, &result); 1.6367 + return result; 1.6368 +} 1.6369 + 1.6370 +/* static */ 1.6371 +void 1.6372 +nsContentUtils::FireMutationEventsForDirectParsing(nsIDocument* aDoc, 1.6373 + nsIContent* aDest, 1.6374 + int32_t aOldChildCount) 1.6375 +{ 1.6376 + // Fire mutation events. Optimize for the case when there are no listeners 1.6377 + int32_t newChildCount = aDest->GetChildCount(); 1.6378 + if (newChildCount && nsContentUtils:: 1.6379 + HasMutationListeners(aDoc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) { 1.6380 + nsAutoTArray<nsCOMPtr<nsIContent>, 50> childNodes; 1.6381 + NS_ASSERTION(newChildCount - aOldChildCount >= 0, 1.6382 + "What, some unexpected dom mutation has happened?"); 1.6383 + childNodes.SetCapacity(newChildCount - aOldChildCount); 1.6384 + for (nsIContent* child = aDest->GetFirstChild(); 1.6385 + child; 1.6386 + child = child->GetNextSibling()) { 1.6387 + childNodes.AppendElement(child); 1.6388 + } 1.6389 + FragmentOrElement::FireNodeInserted(aDoc, aDest, childNodes); 1.6390 + } 1.6391 +} 1.6392 + 1.6393 +/* static */ 1.6394 +nsIDocument* 1.6395 +nsContentUtils::GetFullscreenAncestor(nsIDocument* aDoc) 1.6396 +{ 1.6397 + nsIDocument* doc = aDoc; 1.6398 + while (doc) { 1.6399 + if (doc->IsFullScreenDoc()) { 1.6400 + return doc; 1.6401 + } 1.6402 + doc = doc->GetParentDocument(); 1.6403 + } 1.6404 + return nullptr; 1.6405 +} 1.6406 + 1.6407 +/* static */ 1.6408 +bool 1.6409 +nsContentUtils::IsInPointerLockContext(nsIDOMWindow* aWin) 1.6410 +{ 1.6411 + if (!aWin) { 1.6412 + return false; 1.6413 + } 1.6414 + 1.6415 + nsCOMPtr<nsIDocument> pointerLockedDoc = 1.6416 + do_QueryReferent(EventStateManager::sPointerLockedDoc); 1.6417 + if (!pointerLockedDoc || !pointerLockedDoc->GetWindow()) { 1.6418 + return false; 1.6419 + } 1.6420 + 1.6421 + nsCOMPtr<nsIDOMWindow> lockTop; 1.6422 + pointerLockedDoc->GetWindow()->GetScriptableTop(getter_AddRefs(lockTop)); 1.6423 + 1.6424 + nsCOMPtr<nsIDOMWindow> top; 1.6425 + aWin->GetScriptableTop(getter_AddRefs(top)); 1.6426 + 1.6427 + return top == lockTop; 1.6428 +} 1.6429 + 1.6430 +// static 1.6431 +int32_t 1.6432 +nsContentUtils::GetAdjustedOffsetInTextControl(nsIFrame* aOffsetFrame, 1.6433 + int32_t aOffset) 1.6434 +{ 1.6435 + // The structure of the anonymous frames within a text control frame is 1.6436 + // an optional block frame, followed by an optional br frame. 1.6437 + 1.6438 + // If the offset frame has a child, then this frame is the block which 1.6439 + // has the text frames (containing the content) as its children. This will 1.6440 + // be the case if we click to the right of any of the text frames, or at the 1.6441 + // bottom of the text area. 1.6442 + nsIFrame* firstChild = aOffsetFrame->GetFirstPrincipalChild(); 1.6443 + if (firstChild) { 1.6444 + // In this case, the passed-in offset is incorrect, and we want the length 1.6445 + // of the entire content in the text control frame. 1.6446 + return firstChild->GetContent()->Length(); 1.6447 + } 1.6448 + 1.6449 + if (aOffsetFrame->GetPrevSibling() && 1.6450 + !aOffsetFrame->GetNextSibling()) { 1.6451 + // In this case, we're actually within the last frame, which is a br 1.6452 + // frame. Our offset should therefore be the length of the first child of 1.6453 + // our parent. 1.6454 + int32_t aOutOffset = 1.6455 + aOffsetFrame->GetParent()->GetFirstPrincipalChild()->GetContent()->Length(); 1.6456 + return aOutOffset; 1.6457 + } 1.6458 + 1.6459 + // Otherwise, we're within one of the text frames, in which case our offset 1.6460 + // has already been correctly calculated. 1.6461 + return aOffset; 1.6462 +} 1.6463 + 1.6464 +// static 1.6465 +void 1.6466 +nsContentUtils::GetSelectionInTextControl(Selection* aSelection, 1.6467 + Element* aRoot, 1.6468 + int32_t& aOutStartOffset, 1.6469 + int32_t& aOutEndOffset) 1.6470 +{ 1.6471 + MOZ_ASSERT(aSelection && aRoot); 1.6472 + 1.6473 + if (!aSelection->GetRangeCount()) { 1.6474 + // Nothing selected 1.6475 + aOutStartOffset = aOutEndOffset = 0; 1.6476 + return; 1.6477 + } 1.6478 + 1.6479 + nsCOMPtr<nsINode> anchorNode = aSelection->GetAnchorNode(); 1.6480 + uint32_t anchorOffset = aSelection->AnchorOffset(); 1.6481 + nsCOMPtr<nsINode> focusNode = aSelection->GetFocusNode(); 1.6482 + uint32_t focusOffset = aSelection->FocusOffset(); 1.6483 + 1.6484 + // We have at most two children, consisting of an optional text node followed 1.6485 + // by an optional <br>. 1.6486 + NS_ASSERTION(aRoot->GetChildCount() <= 2, "Unexpected children"); 1.6487 + nsCOMPtr<nsIContent> firstChild = aRoot->GetFirstChild(); 1.6488 +#ifdef DEBUG 1.6489 + nsCOMPtr<nsIContent> lastChild = aRoot->GetLastChild(); 1.6490 + NS_ASSERTION(anchorNode == aRoot || anchorNode == firstChild || 1.6491 + anchorNode == lastChild, "Unexpected anchorNode"); 1.6492 + NS_ASSERTION(focusNode == aRoot || focusNode == firstChild || 1.6493 + focusNode == lastChild, "Unexpected focusNode"); 1.6494 +#endif 1.6495 + if (!firstChild || !firstChild->IsNodeOfType(nsINode::eTEXT)) { 1.6496 + // No text node, so everything is 0 1.6497 + anchorOffset = focusOffset = 0; 1.6498 + } else { 1.6499 + // First child is text. If the anchor/focus is already in the text node, 1.6500 + // or the start of the root node, no change needed. If it's in the root 1.6501 + // node but not the start, or in the trailing <br>, we need to set the 1.6502 + // offset to the end. 1.6503 + if ((anchorNode == aRoot && anchorOffset != 0) || 1.6504 + (anchorNode != aRoot && anchorNode != firstChild)) { 1.6505 + anchorOffset = firstChild->Length(); 1.6506 + } 1.6507 + if ((focusNode == aRoot && focusOffset != 0) || 1.6508 + (focusNode != aRoot && focusNode != firstChild)) { 1.6509 + focusOffset = firstChild->Length(); 1.6510 + } 1.6511 + } 1.6512 + 1.6513 + // Make sure aOutStartOffset <= aOutEndOffset. 1.6514 + aOutStartOffset = std::min(anchorOffset, focusOffset); 1.6515 + aOutEndOffset = std::max(anchorOffset, focusOffset); 1.6516 +} 1.6517 + 1.6518 +nsIEditor* 1.6519 +nsContentUtils::GetHTMLEditor(nsPresContext* aPresContext) 1.6520 +{ 1.6521 + nsCOMPtr<nsIDocShell> docShell(aPresContext->GetDocShell()); 1.6522 + bool isEditable; 1.6523 + if (!docShell || 1.6524 + NS_FAILED(docShell->GetEditable(&isEditable)) || !isEditable) 1.6525 + return nullptr; 1.6526 + 1.6527 + nsCOMPtr<nsIEditor> editor; 1.6528 + docShell->GetEditor(getter_AddRefs(editor)); 1.6529 + return editor; 1.6530 +} 1.6531 + 1.6532 +bool 1.6533 +nsContentUtils::InternalIsSupported(nsISupports* aObject, 1.6534 + const nsAString& aFeature, 1.6535 + const nsAString& aVersion) 1.6536 +{ 1.6537 + // If it looks like an SVG feature string, forward to nsSVGFeatures 1.6538 + if (StringBeginsWith(aFeature, 1.6539 + NS_LITERAL_STRING("http://www.w3.org/TR/SVG"), 1.6540 + nsASCIICaseInsensitiveStringComparator()) || 1.6541 + StringBeginsWith(aFeature, NS_LITERAL_STRING("org.w3c.dom.svg"), 1.6542 + nsASCIICaseInsensitiveStringComparator()) || 1.6543 + StringBeginsWith(aFeature, NS_LITERAL_STRING("org.w3c.svg"), 1.6544 + nsASCIICaseInsensitiveStringComparator())) { 1.6545 + return (aVersion.IsEmpty() || aVersion.EqualsLiteral("1.0") || 1.6546 + aVersion.EqualsLiteral("1.1")) && 1.6547 + nsSVGFeatures::HasFeature(aObject, aFeature); 1.6548 + } 1.6549 + 1.6550 + // Otherwise, we claim to support everything 1.6551 + return true; 1.6552 +} 1.6553 + 1.6554 +bool 1.6555 +nsContentUtils::IsContentInsertionPoint(const nsIContent* aContent) 1.6556 +{ 1.6557 + // Check if the content is a XBL insertion point. 1.6558 + if (aContent->IsActiveChildrenElement()) { 1.6559 + return true; 1.6560 + } 1.6561 + 1.6562 + // Check if the content is a web components content insertion point. 1.6563 + if (aContent->IsHTML(nsGkAtoms::content)) { 1.6564 + return static_cast<const HTMLContentElement*>(aContent)->IsInsertionPoint(); 1.6565 + } 1.6566 + 1.6567 + return false; 1.6568 +} 1.6569 + 1.6570 +bool 1.6571 +nsContentUtils::DOMWindowDumpEnabled() 1.6572 +{ 1.6573 +#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP)) 1.6574 + // In optimized builds we check a pref that controls if we should 1.6575 + // enable output from dump() or not, in debug builds it's always 1.6576 + // enabled. 1.6577 + return nsContentUtils::sDOMWindowDumpEnabled; 1.6578 +#else 1.6579 + return true; 1.6580 +#endif 1.6581 +} 1.6582 + 1.6583 +bool 1.6584 +nsContentUtils::GetNodeTextContent(nsINode* aNode, bool aDeep, nsAString& aResult) 1.6585 +{ 1.6586 + aResult.Truncate(); 1.6587 + return AppendNodeTextContent(aNode, aDeep, aResult, mozilla::fallible_t()); 1.6588 +} 1.6589 + 1.6590 +void 1.6591 +nsContentUtils::DestroyMatchString(void* aData) 1.6592 +{ 1.6593 + if (aData) { 1.6594 + nsString* matchString = static_cast<nsString*>(aData); 1.6595 + delete matchString; 1.6596 + } 1.6597 +} 1.6598 + 1.6599 +bool 1.6600 +nsContentUtils::IsJavascriptMIMEType(const nsAString& aMIMEType) 1.6601 +{ 1.6602 + // Table ordered from most to least likely JS MIME types. 1.6603 + static const char* jsTypes[] = { 1.6604 + "text/javascript", 1.6605 + "text/ecmascript", 1.6606 + "application/javascript", 1.6607 + "application/ecmascript", 1.6608 + "application/x-javascript", 1.6609 + "application/x-ecmascript", 1.6610 + "text/javascript1.0", 1.6611 + "text/javascript1.1", 1.6612 + "text/javascript1.2", 1.6613 + "text/javascript1.3", 1.6614 + "text/javascript1.4", 1.6615 + "text/javascript1.5", 1.6616 + "text/jscript", 1.6617 + "text/livescript", 1.6618 + "text/x-ecmascript", 1.6619 + "text/x-javascript", 1.6620 + nullptr 1.6621 + }; 1.6622 + 1.6623 + for (uint32_t i = 0; jsTypes[i]; ++i) { 1.6624 + if (aMIMEType.LowerCaseEqualsASCII(jsTypes[i])) { 1.6625 + return true; 1.6626 + } 1.6627 + } 1.6628 + 1.6629 + return false; 1.6630 +}