content/base/src/nsContentUtils.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /* A namespace class for static layout utilities. */
     9 #include "nsContentUtils.h"
    11 #include <algorithm>
    12 #include <math.h>
    14 #include "prprf.h"
    15 #include "nsCxPusher.h"
    16 #include "DecoderTraits.h"
    17 #include "harfbuzz/hb.h"
    18 #include "imgICache.h"
    19 #include "imgIContainer.h"
    20 #include "imgINotificationObserver.h"
    21 #include "imgLoader.h"
    22 #include "imgRequestProxy.h"
    23 #include "jsapi.h"
    24 #include "jsfriendapi.h"
    25 #include "js/OldDebugAPI.h"
    26 #include "js/Value.h"
    27 #include "Layers.h"
    28 #include "MediaDecoder.h"
    29 // nsNPAPIPluginInstance must be included before nsIDocument.h, which is included in mozAutoDocUpdate.h.
    30 #include "nsNPAPIPluginInstance.h"
    31 #include "mozAutoDocUpdate.h"
    32 #include "mozilla/ArrayUtils.h"
    33 #include "mozilla/Attributes.h"
    34 #include "mozilla/AutoRestore.h"
    35 #include "mozilla/Base64.h"
    36 #include "mozilla/DebugOnly.h"
    37 #include "mozilla/dom/DocumentFragment.h"
    38 #include "mozilla/dom/Element.h"
    39 #include "mozilla/dom/HTMLMediaElement.h"
    40 #include "mozilla/dom/HTMLTemplateElement.h"
    41 #include "mozilla/dom/HTMLContentElement.h"
    42 #include "mozilla/dom/TextDecoder.h"
    43 #include "mozilla/dom/TouchEvent.h"
    44 #include "mozilla/dom/ShadowRoot.h"
    45 #include "mozilla/EventDispatcher.h"
    46 #include "mozilla/EventListenerManager.h"
    47 #include "mozilla/EventStateManager.h"
    48 #include "mozilla/IMEStateManager.h"
    49 #include "mozilla/InternalMutationEvent.h"
    50 #include "mozilla/Likely.h"
    51 #include "mozilla/MouseEvents.h"
    52 #include "mozilla/Preferences.h"
    53 #include "mozilla/dom/Selection.h"
    54 #include "mozilla/TextEvents.h"
    55 #include "nsAString.h"
    56 #include "nsAttrName.h"
    57 #include "nsAttrValue.h"
    58 #include "nsAttrValueInlines.h"
    59 #include "nsBindingManager.h"
    60 #include "nsCCUncollectableMarker.h"
    61 #include "nsChannelPolicy.h"
    62 #include "nsCharSeparatedTokenizer.h"
    63 #include "nsCOMPtr.h"
    64 #include "nsContentCreatorFunctions.h"
    65 #include "nsContentDLF.h"
    66 #include "nsContentList.h"
    67 #include "nsContentPolicyUtils.h"
    68 #include "nsCPrefetchService.h"
    69 #include "nsCRT.h"
    70 #include "nsCycleCollectionParticipant.h"
    71 #include "nsCycleCollector.h"
    72 #include "nsDataHashtable.h"
    73 #include "nsDocShellCID.h"
    74 #include "nsDocument.h"
    75 #include "nsDOMCID.h"
    76 #include "mozilla/dom/DataTransfer.h"
    77 #include "nsDOMJSUtils.h"
    78 #include "nsDOMMutationObserver.h"
    79 #include "nsError.h"
    80 #include "nsFocusManager.h"
    81 #include "nsGenericHTMLElement.h"
    82 #include "nsGenericHTMLFrameElement.h"
    83 #include "nsGkAtoms.h"
    84 #include "nsHostObjectProtocolHandler.h"
    85 #include "nsHtml5Module.h"
    86 #include "nsHtml5StringParser.h"
    87 #include "nsIAsyncVerifyRedirectCallback.h"
    88 #include "nsICategoryManager.h"
    89 #include "nsIChannelEventSink.h"
    90 #include "nsIChannelPolicy.h"
    91 #include "nsIChromeRegistry.h"
    92 #include "nsIConsoleService.h"
    93 #include "nsIContent.h"
    94 #include "nsIContentSecurityPolicy.h"
    95 #include "nsIContentSink.h"
    96 #include "nsIContentViewer.h"
    97 #include "nsIDocShell.h"
    98 #include "nsIDocument.h"
    99 #include "nsIDocumentEncoder.h"
   100 #include "nsIDOMDocument.h"
   101 #include "nsIDOMDocumentType.h"
   102 #include "nsIDOMEvent.h"
   103 #include "nsIDOMHTMLElement.h"
   104 #include "nsIDOMHTMLFormElement.h"
   105 #include "nsIDOMHTMLInputElement.h"
   106 #include "nsIDOMNode.h"
   107 #include "nsIDOMNodeList.h"
   108 #include "nsIDOMScriptObjectFactory.h"
   109 #include "nsIDOMUserDataHandler.h"
   110 #include "nsIDOMXULCommandEvent.h"
   111 #include "nsIDragService.h"
   112 #include "nsIEditor.h"
   113 #include "nsIFormControl.h"
   114 #include "nsIForm.h"
   115 #include "nsIFragmentContentSink.h"
   116 #include "nsIFrame.h"
   117 #include "nsIHTMLDocument.h"
   118 #include "nsIIdleService.h"
   119 #include "nsIImageLoadingContent.h"
   120 #include "nsIInterfaceRequestor.h"
   121 #include "nsIInterfaceRequestorUtils.h"
   122 #include "nsIIOService.h"
   123 #include "nsIJSRuntimeService.h"
   124 #include "nsILineBreaker.h"
   125 #include "nsILoadContext.h"
   126 #include "nsILoadGroup.h"
   127 #include "nsIMemoryReporter.h"
   128 #include "nsIMIMEService.h"
   129 #include "nsINode.h"
   130 #include "nsINodeInfo.h"
   131 #include "nsIObjectLoadingContent.h"
   132 #include "nsIObserver.h"
   133 #include "nsIObserverService.h"
   134 #include "nsIOfflineCacheUpdate.h"
   135 #include "nsIParser.h"
   136 #include "nsIParserService.h"
   137 #include "nsIPermissionManager.h"
   138 #include "nsIPluginHost.h"
   139 #include "nsIRunnable.h"
   140 #include "nsIScriptContext.h"
   141 #include "nsIScriptError.h"
   142 #include "nsIScriptGlobalObject.h"
   143 #include "nsIScriptObjectPrincipal.h"
   144 #include "nsIScriptSecurityManager.h"
   145 #include "nsIStringBundle.h"
   146 #include "nsIURI.h"
   147 #include "nsIURL.h"
   148 #include "nsIWebNavigation.h"
   149 #include "nsIWordBreaker.h"
   150 #include "nsIXPConnect.h"
   151 #include "nsJSUtils.h"
   152 #include "nsLWBrkCIID.h"
   153 #include "nsNetCID.h"
   154 #include "nsNetUtil.h"
   155 #include "nsNodeInfoManager.h"
   156 #include "nsNullPrincipal.h"
   157 #include "nsParserCIID.h"
   158 #include "nsParserConstants.h"
   159 #include "nsPIDOMWindow.h"
   160 #include "nsPresContext.h"
   161 #include "nsPrintfCString.h"
   162 #include "nsReferencedElement.h"
   163 #include "nsSandboxFlags.h"
   164 #include "nsScriptSecurityManager.h"
   165 #include "nsSVGFeatures.h"
   166 #include "nsTextEditorState.h"
   167 #include "nsTextFragment.h"
   168 #include "nsTextNode.h"
   169 #include "nsThreadUtils.h"
   170 #include "nsUnicharUtilCIID.h"
   171 #include "nsUnicodeProperties.h"
   172 #include "nsViewManager.h"
   173 #include "nsViewportInfo.h"
   174 #include "nsWrapperCacheInlines.h"
   175 #include "nsXULPopupManager.h"
   176 #include "xpcprivate.h" // nsXPConnect
   177 #include "HTMLSplitOnSpacesTokenizer.h"
   178 #include "nsContentTypeParser.h"
   179 #include "mozIThirdPartyUtil.h"
   181 #include "nsIBidiKeyboard.h"
   183 extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end,
   184                                       const char** next, char16_t* result);
   185 extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end,
   186                                  int ns_aware, const char** colon);
   188 class imgLoader;
   190 using namespace mozilla::dom;
   191 using namespace mozilla::layers;
   192 using namespace mozilla::widget;
   193 using namespace mozilla;
   195 const char kLoadAsData[] = "loadAsData";
   197 nsIXPConnect *nsContentUtils::sXPConnect;
   198 nsIScriptSecurityManager *nsContentUtils::sSecurityManager;
   199 nsIParserService *nsContentUtils::sParserService = nullptr;
   200 nsNameSpaceManager *nsContentUtils::sNameSpaceManager;
   201 nsIIOService *nsContentUtils::sIOService;
   202 nsIConsoleService *nsContentUtils::sConsoleService;
   203 nsDataHashtable<nsISupportsHashKey, EventNameMapping>* nsContentUtils::sAtomEventTable = nullptr;
   204 nsDataHashtable<nsStringHashKey, EventNameMapping>* nsContentUtils::sStringEventTable = nullptr;
   205 nsCOMArray<nsIAtom>* nsContentUtils::sUserDefinedEvents = nullptr;
   206 nsIStringBundleService *nsContentUtils::sStringBundleService;
   207 nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT];
   208 nsIContentPolicy *nsContentUtils::sContentPolicyService;
   209 bool nsContentUtils::sTriedToGetContentPolicy = false;
   210 nsILineBreaker *nsContentUtils::sLineBreaker;
   211 nsIWordBreaker *nsContentUtils::sWordBreaker;
   212 nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nullptr;
   213 uint32_t nsContentUtils::sScriptBlockerCount = 0;
   214 #ifdef DEBUG
   215 uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
   216 #endif
   217 uint32_t nsContentUtils::sMicroTaskLevel = 0;
   218 nsTArray< nsCOMPtr<nsIRunnable> >* nsContentUtils::sBlockedScriptRunners = nullptr;
   219 uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0;
   220 nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr;
   222 bool nsContentUtils::sIsHandlingKeyBoardEvent = false;
   223 bool nsContentUtils::sAllowXULXBL_for_file = false;
   225 nsString* nsContentUtils::sShiftText = nullptr;
   226 nsString* nsContentUtils::sControlText = nullptr;
   227 nsString* nsContentUtils::sMetaText = nullptr;
   228 nsString* nsContentUtils::sOSText = nullptr;
   229 nsString* nsContentUtils::sAltText = nullptr;
   230 nsString* nsContentUtils::sModifierSeparator = nullptr;
   232 bool nsContentUtils::sInitialized = false;
   233 bool nsContentUtils::sIsFullScreenApiEnabled = false;
   234 bool nsContentUtils::sTrustedFullScreenOnly = true;
   235 bool nsContentUtils::sFullscreenApiIsContentOnly = false;
   236 bool nsContentUtils::sIsIdleObserverAPIEnabled = false;
   237 bool nsContentUtils::sIsPerformanceTimingEnabled = false;
   238 bool nsContentUtils::sIsResourceTimingEnabled = false;
   240 uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
   242 nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr;
   243 nsIParser* nsContentUtils::sXMLFragmentParser = nullptr;
   244 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
   245 bool nsContentUtils::sFragmentParsingActive = false;
   247 #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
   248 bool nsContentUtils::sDOMWindowDumpEnabled;
   249 #endif
   251 namespace {
   253 static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
   254 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
   256 static PLDHashTable sEventListenerManagersHash;
   258 class DOMEventListenerManagersHashReporter MOZ_FINAL : public nsIMemoryReporter
   259 {
   260   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
   262 public:
   263   NS_DECL_ISUPPORTS
   265   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
   266                             nsISupports* aData)
   267   {
   268     // We don't measure the |EventListenerManager| objects pointed to by the
   269     // entries because those references are non-owning.
   270     int64_t amount = sEventListenerManagersHash.ops
   271                    ? PL_DHashTableSizeOfExcludingThis(
   272                        &sEventListenerManagersHash, nullptr, MallocSizeOf)
   273                    : 0;
   275     return MOZ_COLLECT_REPORT(
   276       "explicit/dom/event-listener-managers-hash", KIND_HEAP, UNITS_BYTES,
   277       amount,
   278       "Memory used by the event listener manager's hash table.");
   279   }
   280 };
   282 NS_IMPL_ISUPPORTS(DOMEventListenerManagersHashReporter, nsIMemoryReporter)
   284 class EventListenerManagerMapEntry : public PLDHashEntryHdr
   285 {
   286 public:
   287   EventListenerManagerMapEntry(const void *aKey)
   288     : mKey(aKey)
   289   {
   290   }
   292   ~EventListenerManagerMapEntry()
   293   {
   294     NS_ASSERTION(!mListenerManager, "caller must release and disconnect ELM");
   295   }
   297 protected:          // declared protected to silence clang warnings
   298   const void *mKey; // must be first, to look like PLDHashEntryStub
   300 public:
   301   nsRefPtr<EventListenerManager> mListenerManager;
   302 };
   304 static bool
   305 EventListenerManagerHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
   306                                   const void *key)
   307 {
   308   // Initialize the entry with placement new
   309   new (entry) EventListenerManagerMapEntry(key);
   310   return true;
   311 }
   313 static void
   314 EventListenerManagerHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
   315 {
   316   EventListenerManagerMapEntry *lm =
   317     static_cast<EventListenerManagerMapEntry *>(entry);
   319   // Let the EventListenerManagerMapEntry clean itself up...
   320   lm->~EventListenerManagerMapEntry();
   321 }
   323 class SameOriginChecker MOZ_FINAL : public nsIChannelEventSink,
   324                                     public nsIInterfaceRequestor
   325 {
   326   NS_DECL_ISUPPORTS
   327   NS_DECL_NSICHANNELEVENTSINK
   328   NS_DECL_NSIINTERFACEREQUESTOR
   329 };
   331 class CharsetDetectionObserver MOZ_FINAL : public nsICharsetDetectionObserver
   332 {
   333 public:
   334   NS_DECL_ISUPPORTS
   336   NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf)
   337   {
   338     mCharset = aCharset;
   339     return NS_OK;
   340   }
   342   const nsACString& GetResult() const
   343   {
   344     return mCharset;
   345   }
   347 private:
   348   nsCString mCharset;
   349 };
   351 } // anonymous namespace
   353 /* static */
   354 TimeDuration
   355 nsContentUtils::HandlingUserInputTimeout()
   356 {
   357   return TimeDuration::FromMilliseconds(sHandlingInputTimeout);
   358 }
   360 // static
   361 nsresult
   362 nsContentUtils::Init()
   363 {
   364   if (sInitialized) {
   365     NS_WARNING("Init() called twice");
   367     return NS_OK;
   368   }
   370   sNameSpaceManager = nsNameSpaceManager::GetInstance();
   371   NS_ENSURE_TRUE(sNameSpaceManager, NS_ERROR_OUT_OF_MEMORY);
   373   sXPConnect = nsXPConnect::XPConnect();
   375   sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager();
   376   if(!sSecurityManager)
   377     return NS_ERROR_FAILURE;
   378   NS_ADDREF(sSecurityManager);
   380   // Getting the first context can trigger GC, so do this non-lazily.
   381   sXPConnect->InitSafeJSContext();
   383   nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
   384   if (NS_FAILED(rv)) {
   385     // This makes life easier, but we can live without it.
   387     sIOService = nullptr;
   388   }
   390   rv = CallGetService(NS_LBRK_CONTRACTID, &sLineBreaker);
   391   NS_ENSURE_SUCCESS(rv, rv);
   393   rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker);
   394   NS_ENSURE_SUCCESS(rv, rv);
   396   if (!InitializeEventTable())
   397     return NS_ERROR_FAILURE;
   399   if (!sEventListenerManagersHash.ops) {
   400     static const PLDHashTableOps hash_table_ops =
   401     {
   402       PL_DHashAllocTable,
   403       PL_DHashFreeTable,
   404       PL_DHashVoidPtrKeyStub,
   405       PL_DHashMatchEntryStub,
   406       PL_DHashMoveEntryStub,
   407       EventListenerManagerHashClearEntry,
   408       PL_DHashFinalizeStub,
   409       EventListenerManagerHashInitEntry
   410     };
   412     PL_DHashTableInit(&sEventListenerManagersHash, &hash_table_ops,
   413                       nullptr, sizeof(EventListenerManagerMapEntry), 16);
   415     RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter());
   416   }
   418   sBlockedScriptRunners = new nsTArray< nsCOMPtr<nsIRunnable> >;
   420   Preferences::AddBoolVarCache(&sAllowXULXBL_for_file,
   421                                "dom.allow_XUL_XBL_for_file");
   423   Preferences::AddBoolVarCache(&sIsFullScreenApiEnabled,
   424                                "full-screen-api.enabled");
   426   // Note: We deliberately read this pref here because this code runs
   427   // before the profile loads, so users' changes to this pref in about:config
   428   // won't have any effect on behaviour. We don't really want users messing
   429   // with this pref, as it affects the security model of the fullscreen API.
   430   sFullscreenApiIsContentOnly = Preferences::GetBool("full-screen-api.content-only", false);
   432   Preferences::AddBoolVarCache(&sTrustedFullScreenOnly,
   433                                "full-screen-api.allow-trusted-requests-only");
   435   sIsIdleObserverAPIEnabled = Preferences::GetBool("dom.idle-observers-api.enabled", true);
   437   Preferences::AddBoolVarCache(&sIsPerformanceTimingEnabled,
   438                                "dom.enable_performance", true);
   440   Preferences::AddBoolVarCache(&sIsResourceTimingEnabled,
   441                                "dom.enable_resource_timing", true);
   443   Preferences::AddUintVarCache(&sHandlingInputTimeout,
   444                                "dom.event.handling-user-input-time-limit",
   445                                1000);
   447 #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
   448   Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled,
   449                                "browser.dom.window.dump.enabled");
   450 #endif
   452   Element::InitCCCallbacks();
   454   sInitialized = true;
   456   return NS_OK;
   457 }
   459 void
   460 nsContentUtils::GetShiftText(nsAString& text)
   461 {
   462   if (!sShiftText)
   463     InitializeModifierStrings();
   464   text.Assign(*sShiftText);
   465 }
   467 void
   468 nsContentUtils::GetControlText(nsAString& text)
   469 {
   470   if (!sControlText)
   471     InitializeModifierStrings();
   472   text.Assign(*sControlText);
   473 }
   475 void
   476 nsContentUtils::GetMetaText(nsAString& text)
   477 {
   478   if (!sMetaText)
   479     InitializeModifierStrings();
   480   text.Assign(*sMetaText);
   481 }
   483 void
   484 nsContentUtils::GetOSText(nsAString& text)
   485 {
   486   if (!sOSText) {
   487     InitializeModifierStrings();
   488   }
   489   text.Assign(*sOSText);
   490 }
   492 void
   493 nsContentUtils::GetAltText(nsAString& text)
   494 {
   495   if (!sAltText)
   496     InitializeModifierStrings();
   497   text.Assign(*sAltText);
   498 }
   500 void
   501 nsContentUtils::GetModifierSeparatorText(nsAString& text)
   502 {
   503   if (!sModifierSeparator)
   504     InitializeModifierStrings();
   505   text.Assign(*sModifierSeparator);
   506 }
   508 void
   509 nsContentUtils::InitializeModifierStrings()
   510 {
   511   //load the display strings for the keyboard accelerators
   512   nsCOMPtr<nsIStringBundleService> bundleService =
   513     mozilla::services::GetStringBundleService();
   514   nsCOMPtr<nsIStringBundle> bundle;
   515   DebugOnly<nsresult> rv = NS_OK;
   516   if (bundleService) {
   517     rv = bundleService->CreateBundle( "chrome://global-platform/locale/platformKeys.properties",
   518                                       getter_AddRefs(bundle));
   519   }
   521   NS_ASSERTION(NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/platformKeys.properties could not be loaded");
   522   nsXPIDLString shiftModifier;
   523   nsXPIDLString metaModifier;
   524   nsXPIDLString osModifier;
   525   nsXPIDLString altModifier;
   526   nsXPIDLString controlModifier;
   527   nsXPIDLString modifierSeparator;
   528   if (bundle) {
   529     //macs use symbols for each modifier key, so fetch each from the bundle, which also covers i18n
   530     bundle->GetStringFromName(MOZ_UTF16("VK_SHIFT"), getter_Copies(shiftModifier));
   531     bundle->GetStringFromName(MOZ_UTF16("VK_META"), getter_Copies(metaModifier));
   532     bundle->GetStringFromName(MOZ_UTF16("VK_WIN"), getter_Copies(osModifier));
   533     bundle->GetStringFromName(MOZ_UTF16("VK_ALT"), getter_Copies(altModifier));
   534     bundle->GetStringFromName(MOZ_UTF16("VK_CONTROL"), getter_Copies(controlModifier));
   535     bundle->GetStringFromName(MOZ_UTF16("MODIFIER_SEPARATOR"), getter_Copies(modifierSeparator));
   536   }
   537   //if any of these don't exist, we get  an empty string
   538   sShiftText = new nsString(shiftModifier);
   539   sMetaText = new nsString(metaModifier);
   540   sOSText = new nsString(osModifier);
   541   sAltText = new nsString(altModifier);
   542   sControlText = new nsString(controlModifier);
   543   sModifierSeparator = new nsString(modifierSeparator);  
   544 }
   546 bool
   547 nsContentUtils::InitializeEventTable() {
   548   NS_ASSERTION(!sAtomEventTable, "EventTable already initialized!");
   549   NS_ASSERTION(!sStringEventTable, "EventTable already initialized!");
   551   static const EventNameMapping eventArray[] = {
   552 #define EVENT(name_,  _id, _type, _struct)          \
   553     { nsGkAtoms::on##name_, _id, _type, _struct },
   554 #define WINDOW_ONLY_EVENT EVENT
   555 #define NON_IDL_EVENT EVENT
   556 #include "mozilla/EventNameList.h"
   557 #undef WINDOW_ONLY_EVENT
   558 #undef EVENT
   559     { nullptr }
   560   };
   562   sAtomEventTable = new nsDataHashtable<nsISupportsHashKey, EventNameMapping>(
   563       int(ArrayLength(eventArray) / 0.75) + 1);
   564   sStringEventTable = new nsDataHashtable<nsStringHashKey, EventNameMapping>(
   565       int(ArrayLength(eventArray) / 0.75) + 1);
   566   sUserDefinedEvents = new nsCOMArray<nsIAtom>(64);
   568   // Subtract one from the length because of the trailing null
   569   for (uint32_t i = 0; i < ArrayLength(eventArray) - 1; ++i) {
   570     sAtomEventTable->Put(eventArray[i].mAtom, eventArray[i]);
   571     sStringEventTable->Put(Substring(nsDependentAtomString(eventArray[i].mAtom), 2),
   572                            eventArray[i]);
   573   }
   575   return true;
   576 }
   578 void
   579 nsContentUtils::InitializeTouchEventTable()
   580 {
   581   static bool sEventTableInitialized = false;
   582   if (!sEventTableInitialized && sAtomEventTable && sStringEventTable) {
   583     sEventTableInitialized = true;
   584     static const EventNameMapping touchEventArray[] = {
   585 #define EVENT(name_,  _id, _type, _struct)
   586 #define TOUCH_EVENT(name_,  _id, _type, _struct)      \
   587       { nsGkAtoms::on##name_, _id, _type, _struct },
   588 #include "mozilla/EventNameList.h"
   589 #undef TOUCH_EVENT
   590 #undef EVENT
   591       { nullptr }
   592     };
   593     // Subtract one from the length because of the trailing null
   594     for (uint32_t i = 0; i < ArrayLength(touchEventArray) - 1; ++i) {
   595       sAtomEventTable->Put(touchEventArray[i].mAtom, touchEventArray[i]);
   596       sStringEventTable->Put(Substring(nsDependentAtomString(touchEventArray[i].mAtom), 2),
   597                              touchEventArray[i]);
   598     }
   599   }
   600 }
   602 static bool
   603 Is8bit(const nsAString& aString)
   604 {
   605   static const char16_t EIGHT_BIT = char16_t(~0x00FF);
   607   nsAString::const_iterator done_reading;
   608   aString.EndReading(done_reading);
   610   // for each chunk of |aString|...
   611   uint32_t fragmentLength = 0;
   612   nsAString::const_iterator iter;
   613   for (aString.BeginReading(iter); iter != done_reading;
   614        iter.advance(int32_t(fragmentLength))) {
   615     fragmentLength = uint32_t(iter.size_forward());
   616     const char16_t* c = iter.get();
   617     const char16_t* fragmentEnd = c + fragmentLength;
   619     // for each character in this chunk...
   620     while (c < fragmentEnd) {
   621       if (*c++ & EIGHT_BIT) {
   622         return false;
   623       }
   624     }
   625   }
   627   return true;
   628 }
   630 nsresult
   631 nsContentUtils::Btoa(const nsAString& aBinaryData,
   632                      nsAString& aAsciiBase64String)
   633 {
   634   if (!Is8bit(aBinaryData)) {
   635     aAsciiBase64String.Truncate();
   636     return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
   637   }
   639   return Base64Encode(aBinaryData, aAsciiBase64String);
   640 }
   642 nsresult
   643 nsContentUtils::Atob(const nsAString& aAsciiBase64String,
   644                      nsAString& aBinaryData)
   645 {
   646   if (!Is8bit(aAsciiBase64String)) {
   647     aBinaryData.Truncate();
   648     return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
   649   }
   651   const char16_t* start = aAsciiBase64String.BeginReading();
   652   const char16_t* end = aAsciiBase64String.EndReading();
   653   nsString trimmedString;
   654   if (!trimmedString.SetCapacity(aAsciiBase64String.Length(), fallible_t())) {
   655     return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
   656   }
   657   while (start < end) {
   658     if (!nsContentUtils::IsHTMLWhitespace(*start)) {
   659       trimmedString.Append(*start);
   660     }
   661     start++;
   662   }
   663   nsresult rv = Base64Decode(trimmedString, aBinaryData);
   664   if (NS_FAILED(rv) && rv == NS_ERROR_INVALID_ARG) {
   665     return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
   666   }
   667   return rv;
   668 }
   670 bool
   671 nsContentUtils::IsAutocompleteEnabled(nsIDOMHTMLInputElement* aInput)
   672 {
   673   NS_PRECONDITION(aInput, "aInput should not be null!");
   675   nsAutoString autocomplete;
   676   aInput->GetAutocomplete(autocomplete);
   678   if (autocomplete.IsEmpty()) {
   679     nsCOMPtr<nsIDOMHTMLFormElement> form;
   680     aInput->GetForm(getter_AddRefs(form));
   681     if (!form) {
   682       return true;
   683     }
   685     form->GetAutocomplete(autocomplete);
   686   }
   688   return autocomplete.EqualsLiteral("on");
   689 }
   691 #define SKIP_WHITESPACE(iter, end_iter, end_res)                 \
   692   while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \
   693     ++(iter);                                                    \
   694   }                                                              \
   695   if ((iter) == (end_iter)) {                                    \
   696     return (end_res);                                            \
   697   }
   699 #define SKIP_ATTR_NAME(iter, end_iter)                            \
   700   while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \
   701          *(iter) != '=') {                                        \
   702     ++(iter);                                                     \
   703   }
   705 bool
   706 nsContentUtils::GetPseudoAttributeValue(const nsString& aSource, nsIAtom *aName,
   707                                         nsAString& aValue)
   708 {
   709   aValue.Truncate();
   711   const char16_t *start = aSource.get();
   712   const char16_t *end = start + aSource.Length();
   713   const char16_t *iter;
   715   while (start != end) {
   716     SKIP_WHITESPACE(start, end, false)
   717     iter = start;
   718     SKIP_ATTR_NAME(iter, end)
   720     if (start == iter) {
   721       return false;
   722     }
   724     // Remember the attr name.
   725     const nsDependentSubstring & attrName = Substring(start, iter);
   727     // Now check whether this is a valid name="value" pair.
   728     start = iter;
   729     SKIP_WHITESPACE(start, end, false)
   730     if (*start != '=') {
   731       // No '=', so this is not a name="value" pair.  We don't know
   732       // what it is, and we have no way to handle it.
   733       return false;
   734     }
   736     // Have to skip the value.
   737     ++start;
   738     SKIP_WHITESPACE(start, end, false)
   739     char16_t q = *start;
   740     if (q != kQuote && q != kApostrophe) {
   741       // Not a valid quoted value, so bail.
   742       return false;
   743     }
   745     ++start;  // Point to the first char of the value.
   746     iter = start;
   748     while (iter != end && *iter != q) {
   749       ++iter;
   750     }
   752     if (iter == end) {
   753       // Oops, unterminated quoted string.
   754       return false;
   755     }
   757     // At this point attrName holds the name of the "attribute" and
   758     // the value is between start and iter.
   760     if (aName->Equals(attrName)) {
   761       // We'll accumulate as many characters as possible (until we hit either
   762       // the end of the string or the beginning of an entity). Chunks will be
   763       // delimited by start and chunkEnd.
   764       const char16_t *chunkEnd = start;
   765       while (chunkEnd != iter) {
   766         if (*chunkEnd == kLessThan) {
   767           aValue.Truncate();
   769           return false;
   770         }
   772         if (*chunkEnd == kAmpersand) {
   773           aValue.Append(start, chunkEnd - start);
   775           // Point to first character after the ampersand.
   776           ++chunkEnd;
   778           const char16_t *afterEntity = nullptr;
   779           char16_t result[2];
   780           uint32_t count =
   781             MOZ_XMLTranslateEntity(reinterpret_cast<const char*>(chunkEnd),
   782                                   reinterpret_cast<const char*>(iter),
   783                                   reinterpret_cast<const char**>(&afterEntity),
   784                                   result);
   785           if (count == 0) {
   786             aValue.Truncate();
   788             return false;
   789           }
   791           aValue.Append(result, count);
   793           // Advance to after the entity and begin a new chunk.
   794           start = chunkEnd = afterEntity;
   795         }
   796         else {
   797           ++chunkEnd;
   798         }
   799       }
   801       // Append remainder.
   802       aValue.Append(start, iter - start);
   804       return true;
   805     }
   807     // Resume scanning after the end of the attribute value (past the quote
   808     // char).
   809     start = iter + 1;
   810   }
   812   return false;
   813 }
   815 bool
   816 nsContentUtils::IsJavaScriptLanguage(const nsString& aName)
   817 {
   818   return aName.LowerCaseEqualsLiteral("javascript") ||
   819          aName.LowerCaseEqualsLiteral("livescript") ||
   820          aName.LowerCaseEqualsLiteral("mocha") ||
   821          aName.LowerCaseEqualsLiteral("javascript1.0") ||
   822          aName.LowerCaseEqualsLiteral("javascript1.1") ||
   823          aName.LowerCaseEqualsLiteral("javascript1.2") ||
   824          aName.LowerCaseEqualsLiteral("javascript1.3") ||
   825          aName.LowerCaseEqualsLiteral("javascript1.4") ||
   826          aName.LowerCaseEqualsLiteral("javascript1.5");
   827 }
   829 JSVersion
   830 nsContentUtils::ParseJavascriptVersion(const nsAString& aVersionStr)
   831 {
   832   if (aVersionStr.Length() != 3 || aVersionStr[0] != '1' ||
   833       aVersionStr[1] != '.') {
   834     return JSVERSION_UNKNOWN;
   835   }
   837   switch (aVersionStr[2]) {
   838   case '0': /* fall through */
   839   case '1': /* fall through */
   840   case '2': /* fall through */
   841   case '3': /* fall through */
   842   case '4': /* fall through */
   843   case '5': return JSVERSION_DEFAULT;
   844   case '6': return JSVERSION_1_6;
   845   case '7': return JSVERSION_1_7;
   846   case '8': return JSVERSION_1_8;
   847   default:  return JSVERSION_UNKNOWN;
   848   }
   849 }
   851 void
   852 nsContentUtils::SplitMimeType(const nsAString& aValue, nsString& aType,
   853                               nsString& aParams)
   854 {
   855   aType.Truncate();
   856   aParams.Truncate();
   857   int32_t semiIndex = aValue.FindChar(char16_t(';'));
   858   if (-1 != semiIndex) {
   859     aType = Substring(aValue, 0, semiIndex);
   860     aParams = Substring(aValue, semiIndex + 1,
   861                        aValue.Length() - (semiIndex + 1));
   862     aParams.StripWhitespace();
   863   }
   864   else {
   865     aType = aValue;
   866   }
   867   aType.StripWhitespace();
   868 }
   870 nsresult 
   871 nsContentUtils::IsUserIdle(uint32_t aRequestedIdleTimeInMS, bool* aUserIsIdle)
   872 {
   873   nsresult rv;
   874   nsCOMPtr<nsIIdleService> idleService = 
   875     do_GetService("@mozilla.org/widget/idleservice;1", &rv);
   876   NS_ENSURE_SUCCESS(rv, rv);
   878   uint32_t idleTimeInMS;
   879   rv = idleService->GetIdleTime(&idleTimeInMS);
   880   NS_ENSURE_SUCCESS(rv, rv);
   882   *aUserIsIdle = idleTimeInMS >= aRequestedIdleTimeInMS;
   883   return NS_OK;
   884 }
   886 /**
   887  * Access a cached parser service. Don't addref. We need only one
   888  * reference to it and this class has that one.
   889  */
   890 /* static */
   891 nsIParserService*
   892 nsContentUtils::GetParserService()
   893 {
   894   // XXX: This isn't accessed from several threads, is it?
   895   if (!sParserService) {
   896     // Lock, recheck sCachedParserService and aquire if this should be
   897     // safe for multiple threads.
   898     nsresult rv = CallGetService(kParserServiceCID, &sParserService);
   899     if (NS_FAILED(rv)) {
   900       sParserService = nullptr;
   901     }
   902   }
   904   return sParserService;
   905 }
   907 /**
   908  * A helper function that parses a sandbox attribute (of an <iframe> or
   909  * a CSP directive) and converts it to the set of flags used internally.
   910  *
   911  * @param sandboxAttr   the sandbox attribute
   912  * @return              the set of flags (0 if sandboxAttr is null)
   913  */
   914 uint32_t
   915 nsContentUtils::ParseSandboxAttributeToFlags(const nsAttrValue* sandboxAttr)
   916 {
   917   // No sandbox attribute, no sandbox flags.
   918   if (!sandboxAttr) { return 0; }
   920   //  Start off by setting all the restriction flags.
   921   uint32_t out = SANDBOXED_NAVIGATION
   922                | SANDBOXED_AUXILIARY_NAVIGATION
   923                | SANDBOXED_TOPLEVEL_NAVIGATION
   924                | SANDBOXED_PLUGINS
   925                | SANDBOXED_ORIGIN
   926                | SANDBOXED_FORMS
   927                | SANDBOXED_SCRIPTS
   928                | SANDBOXED_AUTOMATIC_FEATURES
   929                | SANDBOXED_POINTER_LOCK
   930                | SANDBOXED_DOMAIN;
   932 // Macro for updating the flag according to the keywords
   933 #define IF_KEYWORD(atom, flags) \
   934   if (sandboxAttr->Contains(nsGkAtoms::atom, eIgnoreCase)) { out &= ~(flags); }
   936   IF_KEYWORD(allowsameorigin, SANDBOXED_ORIGIN)
   937   IF_KEYWORD(allowforms,  SANDBOXED_FORMS)
   938   IF_KEYWORD(allowscripts, SANDBOXED_SCRIPTS | SANDBOXED_AUTOMATIC_FEATURES)
   939   IF_KEYWORD(allowtopnavigation, SANDBOXED_TOPLEVEL_NAVIGATION)
   940   IF_KEYWORD(allowpointerlock, SANDBOXED_POINTER_LOCK)
   941   IF_KEYWORD(allowpopups, SANDBOXED_AUXILIARY_NAVIGATION)
   943   return out;
   944 #undef IF_KEYWORD
   945 }
   947 nsIBidiKeyboard*
   948 nsContentUtils::GetBidiKeyboard()
   949 {
   950   if (!sBidiKeyboard) {
   951     nsresult rv = CallGetService("@mozilla.org/widget/bidikeyboard;1", &sBidiKeyboard);
   952     if (NS_FAILED(rv)) {
   953       sBidiKeyboard = nullptr;
   954     }
   955   }
   956   return sBidiKeyboard;
   957 }
   959 template <class OutputIterator>
   960 struct NormalizeNewlinesCharTraits {
   961   public:
   962     typedef typename OutputIterator::value_type value_type;
   964   public:
   965     NormalizeNewlinesCharTraits(OutputIterator& aIterator) : mIterator(aIterator) { }
   966     void writechar(typename OutputIterator::value_type aChar) {
   967       *mIterator++ = aChar;
   968     }
   970   private:
   971     OutputIterator mIterator;
   972 };
   974 template <class CharT>
   975 struct NormalizeNewlinesCharTraits<CharT*> {
   976   public:
   977     typedef CharT value_type;
   979   public:
   980     NormalizeNewlinesCharTraits(CharT* aCharPtr) : mCharPtr(aCharPtr) { }
   981     void writechar(CharT aChar) {
   982       *mCharPtr++ = aChar;
   983     }
   985   private:
   986     CharT* mCharPtr;
   987 };
   989 template <class OutputIterator>
   990 class CopyNormalizeNewlines
   991 {
   992   public:
   993     typedef typename OutputIterator::value_type value_type;
   995   public:
   996     CopyNormalizeNewlines(OutputIterator* aDestination,
   997                           bool aLastCharCR=false) :
   998       mLastCharCR(aLastCharCR),
   999       mDestination(aDestination),
  1000       mWritten(0)
  1001     { }
  1003     uint32_t GetCharsWritten() {
  1004       return mWritten;
  1007     bool IsLastCharCR() {
  1008       return mLastCharCR;
  1011     void write(const typename OutputIterator::value_type* aSource, uint32_t aSourceLength) {
  1013       const typename OutputIterator::value_type* done_writing = aSource + aSourceLength;
  1015       // If the last source buffer ended with a CR...
  1016       if (mLastCharCR) {
  1017         // ..and if the next one is a LF, then skip it since
  1018         // we've already written out a newline
  1019         if (aSourceLength && (*aSource == value_type('\n'))) {
  1020           ++aSource;
  1022         mLastCharCR = false;
  1025       uint32_t num_written = 0;
  1026       while ( aSource < done_writing ) {
  1027         if (*aSource == value_type('\r')) {
  1028           mDestination->writechar('\n');
  1029           ++aSource;
  1030           // If we've reached the end of the buffer, record
  1031           // that we wrote out a CR
  1032           if (aSource == done_writing) {
  1033             mLastCharCR = true;
  1035           // If the next character is a LF, skip it
  1036           else if (*aSource == value_type('\n')) {
  1037             ++aSource;
  1040         else {
  1041           mDestination->writechar(*aSource++);
  1043         ++num_written;
  1046       mWritten += num_written;
  1049   private:
  1050     bool mLastCharCR;
  1051     OutputIterator* mDestination;
  1052     uint32_t mWritten;
  1053 };
  1055 // static
  1056 uint32_t
  1057 nsContentUtils::CopyNewlineNormalizedUnicodeTo(const nsAString& aSource,
  1058                                                uint32_t aSrcOffset,
  1059                                                char16_t* aDest,
  1060                                                uint32_t aLength,
  1061                                                bool& aLastCharCR)
  1063   typedef NormalizeNewlinesCharTraits<char16_t*> sink_traits;
  1065   sink_traits dest_traits(aDest);
  1066   CopyNormalizeNewlines<sink_traits> normalizer(&dest_traits,aLastCharCR);
  1067   nsReadingIterator<char16_t> fromBegin, fromEnd;
  1068   copy_string(aSource.BeginReading(fromBegin).advance( int32_t(aSrcOffset) ),
  1069               aSource.BeginReading(fromEnd).advance( int32_t(aSrcOffset+aLength) ),
  1070               normalizer);
  1071   aLastCharCR = normalizer.IsLastCharCR();
  1072   return normalizer.GetCharsWritten();
  1075 // static
  1076 uint32_t
  1077 nsContentUtils::CopyNewlineNormalizedUnicodeTo(nsReadingIterator<char16_t>& aSrcStart, const nsReadingIterator<char16_t>& aSrcEnd, nsAString& aDest)
  1079   typedef nsWritingIterator<char16_t> WritingIterator;
  1080   typedef NormalizeNewlinesCharTraits<WritingIterator> sink_traits;
  1082   WritingIterator iter;
  1083   aDest.BeginWriting(iter);
  1084   sink_traits dest_traits(iter);
  1085   CopyNormalizeNewlines<sink_traits> normalizer(&dest_traits);
  1086   copy_string(aSrcStart, aSrcEnd, normalizer);
  1087   return normalizer.GetCharsWritten();
  1090 /**
  1091  * This is used to determine whether a character is in one of the punctuation
  1092  * mark classes which CSS says should be part of the first-letter.
  1093  * See http://www.w3.org/TR/CSS2/selector.html#first-letter and
  1094  *     http://www.w3.org/TR/selectors/#first-letter
  1095  */
  1097 // static
  1098 bool
  1099 nsContentUtils::IsFirstLetterPunctuation(uint32_t aChar)
  1101   uint8_t cat = mozilla::unicode::GetGeneralCategory(aChar);
  1103   return (cat == HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION ||     // Ps
  1104           cat == HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION ||    // Pe
  1105           cat == HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION ||  // Pi
  1106           cat == HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION ||    // Pf
  1107           cat == HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION);     // Po
  1110 // static
  1111 bool
  1112 nsContentUtils::IsFirstLetterPunctuationAt(const nsTextFragment* aFrag, uint32_t aOffset)
  1114   char16_t h = aFrag->CharAt(aOffset);
  1115   if (!IS_SURROGATE(h)) {
  1116     return IsFirstLetterPunctuation(h);
  1118   if (NS_IS_HIGH_SURROGATE(h) && aOffset + 1 < aFrag->GetLength()) {
  1119     char16_t l = aFrag->CharAt(aOffset + 1);
  1120     if (NS_IS_LOW_SURROGATE(l)) {
  1121       return IsFirstLetterPunctuation(SURROGATE_TO_UCS4(h, l));
  1124   return false;
  1127 // static
  1128 bool nsContentUtils::IsAlphanumeric(uint32_t aChar)
  1130   nsIUGenCategory::nsUGenCategory cat = mozilla::unicode::GetGenCategory(aChar);
  1132   return (cat == nsIUGenCategory::kLetter || cat == nsIUGenCategory::kNumber);
  1135 // static
  1136 bool nsContentUtils::IsAlphanumericAt(const nsTextFragment* aFrag, uint32_t aOffset)
  1138   char16_t h = aFrag->CharAt(aOffset);
  1139   if (!IS_SURROGATE(h)) {
  1140     return IsAlphanumeric(h);
  1142   if (NS_IS_HIGH_SURROGATE(h) && aOffset + 1 < aFrag->GetLength()) {
  1143     char16_t l = aFrag->CharAt(aOffset + 1);
  1144     if (NS_IS_LOW_SURROGATE(l)) {
  1145       return IsAlphanumeric(SURROGATE_TO_UCS4(h, l));
  1148   return false;
  1151 /* static */
  1152 bool
  1153 nsContentUtils::IsHTMLWhitespace(char16_t aChar)
  1155   return aChar == char16_t(0x0009) ||
  1156          aChar == char16_t(0x000A) ||
  1157          aChar == char16_t(0x000C) ||
  1158          aChar == char16_t(0x000D) ||
  1159          aChar == char16_t(0x0020);
  1162 /* static */
  1163 bool
  1164 nsContentUtils::IsHTMLWhitespaceOrNBSP(char16_t aChar)
  1166   return IsHTMLWhitespace(aChar) || aChar == char16_t(0xA0);
  1169 /* static */
  1170 bool
  1171 nsContentUtils::IsHTMLBlock(nsIAtom* aLocalName)
  1173   return
  1174     (aLocalName == nsGkAtoms::address) ||
  1175     (aLocalName == nsGkAtoms::article) ||
  1176     (aLocalName == nsGkAtoms::aside) ||
  1177     (aLocalName == nsGkAtoms::blockquote) ||
  1178     (aLocalName == nsGkAtoms::center) ||
  1179     (aLocalName == nsGkAtoms::dir) ||
  1180     (aLocalName == nsGkAtoms::div) ||
  1181     (aLocalName == nsGkAtoms::dl) || // XXX why not dt and dd?
  1182     (aLocalName == nsGkAtoms::fieldset) ||
  1183     (aLocalName == nsGkAtoms::figure) || // XXX shouldn't figcaption be on this list
  1184     (aLocalName == nsGkAtoms::footer) ||
  1185     (aLocalName == nsGkAtoms::form) ||
  1186     (aLocalName == nsGkAtoms::h1) ||
  1187     (aLocalName == nsGkAtoms::h2) ||
  1188     (aLocalName == nsGkAtoms::h3) ||
  1189     (aLocalName == nsGkAtoms::h4) ||
  1190     (aLocalName == nsGkAtoms::h5) ||
  1191     (aLocalName == nsGkAtoms::h6) ||
  1192     (aLocalName == nsGkAtoms::header) ||
  1193     (aLocalName == nsGkAtoms::hgroup) ||
  1194     (aLocalName == nsGkAtoms::hr) ||
  1195     (aLocalName == nsGkAtoms::li) ||
  1196     (aLocalName == nsGkAtoms::listing) ||
  1197     (aLocalName == nsGkAtoms::menu) ||
  1198     (aLocalName == nsGkAtoms::multicol) || // XXX get rid of this one?
  1199     (aLocalName == nsGkAtoms::nav) ||
  1200     (aLocalName == nsGkAtoms::ol) ||
  1201     (aLocalName == nsGkAtoms::p) ||
  1202     (aLocalName == nsGkAtoms::pre) ||
  1203     (aLocalName == nsGkAtoms::section) ||
  1204     (aLocalName == nsGkAtoms::table) ||
  1205     (aLocalName == nsGkAtoms::ul) ||
  1206     (aLocalName == nsGkAtoms::xmp);
  1209 /* static */
  1210 bool
  1211 nsContentUtils::IsHTMLVoid(nsIAtom* aLocalName)
  1213   return
  1214     (aLocalName == nsGkAtoms::area) ||
  1215     (aLocalName == nsGkAtoms::base) ||
  1216     (aLocalName == nsGkAtoms::basefont) ||
  1217     (aLocalName == nsGkAtoms::bgsound) ||
  1218     (aLocalName == nsGkAtoms::br) ||
  1219     (aLocalName == nsGkAtoms::col) ||
  1220     (aLocalName == nsGkAtoms::command) ||
  1221     (aLocalName == nsGkAtoms::embed) ||
  1222     (aLocalName == nsGkAtoms::frame) ||
  1223     (aLocalName == nsGkAtoms::hr) ||
  1224     (aLocalName == nsGkAtoms::img) ||
  1225     (aLocalName == nsGkAtoms::input) ||
  1226     (aLocalName == nsGkAtoms::keygen) ||
  1227     (aLocalName == nsGkAtoms::link) ||
  1228     (aLocalName == nsGkAtoms::meta) ||
  1229     (aLocalName == nsGkAtoms::param) ||
  1230     (aLocalName == nsGkAtoms::source) ||
  1231     (aLocalName == nsGkAtoms::track) ||
  1232     (aLocalName == nsGkAtoms::wbr);
  1235 /* static */
  1236 bool
  1237 nsContentUtils::ParseIntMarginValue(const nsAString& aString, nsIntMargin& result)
  1239   nsAutoString marginStr(aString);
  1240   marginStr.CompressWhitespace(true, true);
  1241   if (marginStr.IsEmpty()) {
  1242     return false;
  1245   int32_t start = 0, end = 0;
  1246   for (int count = 0; count < 4; count++) {
  1247     if ((uint32_t)end >= marginStr.Length())
  1248       return false;
  1250     // top, right, bottom, left
  1251     if (count < 3)
  1252       end = Substring(marginStr, start).FindChar(',');
  1253     else
  1254       end = Substring(marginStr, start).Length();
  1256     if (end <= 0)
  1257       return false;
  1259     nsresult ec;
  1260     int32_t val = nsString(Substring(marginStr, start, end)).ToInteger(&ec);
  1261     if (NS_FAILED(ec))
  1262       return false;
  1264     switch(count) {
  1265       case 0:
  1266         result.top = val;
  1267       break;
  1268       case 1:
  1269         result.right = val;
  1270       break;
  1271       case 2:
  1272         result.bottom = val;
  1273       break;
  1274       case 3:
  1275         result.left = val;
  1276       break;
  1278     start += end + 1;
  1280   return true;
  1283 // static
  1284 int32_t
  1285 nsContentUtils::ParseLegacyFontSize(const nsAString& aValue)
  1287   nsAString::const_iterator iter, end;
  1288   aValue.BeginReading(iter);
  1289   aValue.EndReading(end);
  1291   while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
  1292     ++iter;
  1295   if (iter == end) {
  1296     return 0;
  1299   bool relative = false;
  1300   bool negate = false;
  1301   if (*iter == char16_t('-')) {
  1302     relative = true;
  1303     negate = true;
  1304     ++iter;
  1305   } else if (*iter == char16_t('+')) {
  1306     relative = true;
  1307     ++iter;
  1310   if (*iter < char16_t('0') || *iter > char16_t('9')) {
  1311     return 0;
  1314   // We don't have to worry about overflow, since we can bail out as soon as
  1315   // we're bigger than 7.
  1316   int32_t value = 0;
  1317   while (iter != end && *iter >= char16_t('0') && *iter <= char16_t('9')) {
  1318     value = 10*value + (*iter - char16_t('0'));
  1319     if (value >= 7) {
  1320       break;
  1322     ++iter;
  1325   if (relative) {
  1326     if (negate) {
  1327       value = 3 - value;
  1328     } else {
  1329       value = 3 + value;
  1333   return clamped(value, 1, 7);
  1336 /* static */
  1337 void
  1338 nsContentUtils::GetOfflineAppManifest(nsIDocument *aDocument, nsIURI **aURI)
  1340   Element* docElement = aDocument->GetRootElement();
  1341   if (!docElement) {
  1342     return;
  1345   nsAutoString manifestSpec;
  1346   docElement->GetAttr(kNameSpaceID_None, nsGkAtoms::manifest, manifestSpec);
  1348   // Manifest URIs can't have fragment identifiers.
  1349   if (manifestSpec.IsEmpty() ||
  1350       manifestSpec.FindChar('#') != kNotFound) {
  1351     return;
  1354   nsContentUtils::NewURIWithDocumentCharset(aURI, manifestSpec,
  1355                                             aDocument,
  1356                                             aDocument->GetDocBaseURI());
  1359 /* static */
  1360 bool
  1361 nsContentUtils::OfflineAppAllowed(nsIURI *aURI)
  1363   nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
  1364     do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
  1365   if (!updateService) {
  1366     return false;
  1369   bool allowed;
  1370   nsresult rv =
  1371     updateService->OfflineAppAllowedForURI(aURI,
  1372                                            Preferences::GetRootBranch(),
  1373                                            &allowed);
  1374   return NS_SUCCEEDED(rv) && allowed;
  1377 /* static */
  1378 bool
  1379 nsContentUtils::OfflineAppAllowed(nsIPrincipal *aPrincipal)
  1381   nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
  1382     do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
  1383   if (!updateService) {
  1384     return false;
  1387   bool allowed;
  1388   nsresult rv = updateService->OfflineAppAllowed(aPrincipal,
  1389                                                  Preferences::GetRootBranch(),
  1390                                                  &allowed);
  1391   return NS_SUCCEEDED(rv) && allowed;
  1394 bool
  1395 nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal,
  1396                                               nsIDOMWindow *aWindow)
  1398   if (!Preferences::GetRootBranch())
  1399     return false;
  1401   nsresult rv;
  1403   bool allowedByDefault;
  1404   rv = Preferences::GetRootBranch()->GetBoolPref(
  1405     "offline-apps.allow_by_default", &allowedByDefault);
  1406   if (NS_FAILED(rv))
  1407     return false;
  1409   if (!allowedByDefault)
  1410     return false;
  1412   nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
  1413     do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
  1414   if (!updateService) {
  1415     return false;
  1418   rv = updateService->AllowOfflineApp(aWindow, aPrincipal);
  1419   return NS_SUCCEEDED(rv);
  1422 // static
  1423 void
  1424 nsContentUtils::Shutdown()
  1426   sInitialized = false;
  1428   NS_IF_RELEASE(sContentPolicyService);
  1429   sTriedToGetContentPolicy = false;
  1430   uint32_t i;
  1431   for (i = 0; i < PropertiesFile_COUNT; ++i)
  1432     NS_IF_RELEASE(sStringBundles[i]);
  1434   NS_IF_RELEASE(sStringBundleService);
  1435   NS_IF_RELEASE(sConsoleService);
  1436   sXPConnect = nullptr;
  1437   NS_IF_RELEASE(sSecurityManager);
  1438   NS_IF_RELEASE(sParserService);
  1439   NS_IF_RELEASE(sIOService);
  1440   NS_IF_RELEASE(sLineBreaker);
  1441   NS_IF_RELEASE(sWordBreaker);
  1442   NS_IF_RELEASE(sBidiKeyboard);
  1444   delete sAtomEventTable;
  1445   sAtomEventTable = nullptr;
  1446   delete sStringEventTable;
  1447   sStringEventTable = nullptr;
  1448   delete sUserDefinedEvents;
  1449   sUserDefinedEvents = nullptr;
  1451   if (sEventListenerManagersHash.ops) {
  1452     NS_ASSERTION(sEventListenerManagersHash.entryCount == 0,
  1453                  "Event listener manager hash not empty at shutdown!");
  1455     // See comment above.
  1457     // However, we have to handle this table differently.  If it still
  1458     // has entries, we want to leak it too, so that we can keep it alive
  1459     // in case any elements are destroyed.  Because if they are, we need
  1460     // their event listener managers to be destroyed too, or otherwise
  1461     // it could leave dangling references in DOMClassInfo's preserved
  1462     // wrapper table.
  1464     if (sEventListenerManagersHash.entryCount == 0) {
  1465       PL_DHashTableFinish(&sEventListenerManagersHash);
  1466       sEventListenerManagersHash.ops = nullptr;
  1470   NS_ASSERTION(!sBlockedScriptRunners ||
  1471                sBlockedScriptRunners->Length() == 0,
  1472                "How'd this happen?");
  1473   delete sBlockedScriptRunners;
  1474   sBlockedScriptRunners = nullptr;
  1476   delete sShiftText;
  1477   sShiftText = nullptr;
  1478   delete sControlText;  
  1479   sControlText = nullptr;
  1480   delete sMetaText;  
  1481   sMetaText = nullptr;
  1482   delete sOSText;
  1483   sOSText = nullptr;
  1484   delete sAltText;  
  1485   sAltText = nullptr;
  1486   delete sModifierSeparator;
  1487   sModifierSeparator = nullptr;
  1489   NS_IF_RELEASE(sSameOriginChecker);
  1492 /**
  1493  * Checks whether two nodes come from the same origin. aTrustedNode is
  1494  * considered 'safe' in that a user can operate on it and that it isn't
  1495  * a js-object that implements nsIDOMNode.
  1496  * Never call this function with the first node provided by script, it
  1497  * must always be known to be a 'real' node!
  1498  */
  1499 // static
  1500 nsresult
  1501 nsContentUtils::CheckSameOrigin(const nsINode *aTrustedNode,
  1502                                 nsIDOMNode *aUnTrustedNode)
  1504   MOZ_ASSERT(aTrustedNode);
  1506   // Make sure it's a real node.
  1507   nsCOMPtr<nsINode> unTrustedNode = do_QueryInterface(aUnTrustedNode);
  1508   NS_ENSURE_TRUE(unTrustedNode, NS_ERROR_UNEXPECTED);
  1509   return CheckSameOrigin(aTrustedNode, unTrustedNode);
  1512 nsresult
  1513 nsContentUtils::CheckSameOrigin(const nsINode* aTrustedNode,
  1514                                 const nsINode* unTrustedNode)
  1516   MOZ_ASSERT(aTrustedNode);
  1517   MOZ_ASSERT(unTrustedNode);
  1519   bool isSystem = false;
  1520   nsresult rv = sSecurityManager->SubjectPrincipalIsSystem(&isSystem);
  1521   NS_ENSURE_SUCCESS(rv, rv);
  1523   if (isSystem) {
  1524     // we're running as system, grant access to the node.
  1526     return NS_OK;
  1529   /*
  1530    * Get hold of each node's principal
  1531    */
  1533   nsIPrincipal* trustedPrincipal = aTrustedNode->NodePrincipal();
  1534   nsIPrincipal* unTrustedPrincipal = unTrustedNode->NodePrincipal();
  1536   if (trustedPrincipal == unTrustedPrincipal) {
  1537     return NS_OK;
  1540   bool equal;
  1541   // XXXbz should we actually have a Subsumes() check here instead?  Or perhaps
  1542   // a separate method for that, with callers using one or the other?
  1543   if (NS_FAILED(trustedPrincipal->Equals(unTrustedPrincipal, &equal)) ||
  1544       !equal) {
  1545     return NS_ERROR_DOM_PROP_ACCESS_DENIED;
  1548   return NS_OK;
  1551 // static
  1552 bool
  1553 nsContentUtils::CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
  1554                                 nsIPrincipal* aPrincipal)
  1556   bool subsumes;
  1557   nsresult rv = aSubjectPrincipal->Subsumes(aPrincipal, &subsumes);
  1558   NS_ENSURE_SUCCESS(rv, false);
  1560   if (subsumes) {
  1561     return true;
  1564   // The subject doesn't subsume aPrincipal. Allow access only if the subject
  1565   // is chrome.
  1566   return IsCallerChrome();
  1569 // static
  1570 bool
  1571 nsContentUtils::CanCallerAccess(nsIDOMNode *aNode)
  1573   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
  1574   NS_ENSURE_TRUE(node, false);
  1575   return CanCallerAccess(node);
  1578 // static
  1579 bool
  1580 nsContentUtils::CanCallerAccess(nsINode* aNode)
  1582   // XXXbz why not check the IsCapabilityEnabled thing up front, and not bother
  1583   // with the system principal games?  But really, there should be a simpler
  1584   // API here, dammit.
  1585   nsCOMPtr<nsIPrincipal> subjectPrincipal;
  1586   nsresult rv = sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
  1587   NS_ENSURE_SUCCESS(rv, false);
  1589   if (!subjectPrincipal) {
  1590     // we're running as system, grant access to the node.
  1592     return true;
  1595   return CanCallerAccess(subjectPrincipal, aNode->NodePrincipal());
  1598 // static
  1599 bool
  1600 nsContentUtils::CanCallerAccess(nsPIDOMWindow* aWindow)
  1602   // XXXbz why not check the IsCapabilityEnabled thing up front, and not bother
  1603   // with the system principal games?  But really, there should be a simpler
  1604   // API here, dammit.
  1605   nsCOMPtr<nsIPrincipal> subjectPrincipal;
  1606   nsresult rv = sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
  1607   NS_ENSURE_SUCCESS(rv, false);
  1609   if (!subjectPrincipal) {
  1610     // we're running as system, grant access to the node.
  1612     return true;
  1615   nsCOMPtr<nsIScriptObjectPrincipal> scriptObject =
  1616     do_QueryInterface(aWindow->IsOuterWindow() ?
  1617                       aWindow->GetCurrentInnerWindow() : aWindow);
  1618   NS_ENSURE_TRUE(scriptObject, false);
  1620   return CanCallerAccess(subjectPrincipal, scriptObject->GetPrincipal());
  1623 //static
  1624 bool
  1625 nsContentUtils::InProlog(nsINode *aNode)
  1627   NS_PRECONDITION(aNode, "missing node to nsContentUtils::InProlog");
  1629   nsINode* parent = aNode->GetParentNode();
  1630   if (!parent || !parent->IsNodeOfType(nsINode::eDOCUMENT)) {
  1631     return false;
  1634   nsIDocument* doc = static_cast<nsIDocument*>(parent);
  1635   nsIContent* root = doc->GetRootElement();
  1637   return !root || doc->IndexOf(aNode) < doc->IndexOf(root);
  1640 JSContext *
  1641 nsContentUtils::GetContextFromDocument(nsIDocument *aDocument)
  1643   nsCOMPtr<nsIScriptGlobalObject> sgo =  do_QueryInterface(aDocument->GetScopeObject());
  1644   if (!sgo) {
  1645     // No script global, no context.
  1646     return nullptr;
  1649   nsIScriptContext *scx = sgo->GetContext();
  1650   if (!scx) {
  1651     // No context left in the scope...
  1652     return nullptr;
  1655   return scx->GetNativeContext();
  1658 //static
  1659 void
  1660 nsContentUtils::TraceSafeJSContext(JSTracer* aTrc)
  1662   JSContext* cx = GetSafeJSContext();
  1663   if (!cx) {
  1664     return;
  1666   if (JSObject* global = js::DefaultObjectForContextOrNull(cx)) {
  1667     JS::AssertGCThingMustBeTenured(global);
  1668     JS_CallObjectTracer(aTrc, &global, "safe context");
  1669     MOZ_ASSERT(global == js::DefaultObjectForContextOrNull(cx));
  1673 nsPIDOMWindow *
  1674 nsContentUtils::GetWindowFromCaller()
  1676   JSContext *cx = GetCurrentJSContext();
  1677   if (cx) {
  1678     nsCOMPtr<nsPIDOMWindow> win =
  1679       do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
  1680     return win;
  1683   return nullptr;
  1686 nsIDocument*
  1687 nsContentUtils::GetDocumentFromCaller()
  1689   AutoJSContext cx;
  1691   nsCOMPtr<nsPIDOMWindow> win =
  1692     do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(cx)));
  1693   if (!win) {
  1694     return nullptr;
  1697   return win->GetExtantDoc();
  1700 nsIDocument*
  1701 nsContentUtils::GetDocumentFromContext()
  1703   JSContext *cx = GetCurrentJSContext();
  1704   if (cx) {
  1705     nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(cx);
  1707     if (sgo) {
  1708       nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(sgo);
  1709       if (pwin) {
  1710         return pwin->GetExtantDoc();
  1715   return nullptr;
  1718 bool
  1719 nsContentUtils::IsCallerChrome()
  1721   MOZ_ASSERT(NS_IsMainThread());
  1722   bool is_caller_chrome = false;
  1723   nsresult rv = sSecurityManager->SubjectPrincipalIsSystem(&is_caller_chrome);
  1724   if (NS_FAILED(rv)) {
  1725     return false;
  1727   if (is_caller_chrome) {
  1728     return true;
  1731   // If the check failed, look for UniversalXPConnect on the cx compartment.
  1732   return xpc::IsUniversalXPConnectEnabled(GetCurrentJSContext());
  1735 namespace mozilla {
  1736 namespace dom {
  1737 namespace workers {
  1738 extern bool IsCurrentThreadRunningChromeWorker();
  1739 extern JSContext* GetCurrentThreadJSContext();
  1744 bool
  1745 nsContentUtils::ThreadsafeIsCallerChrome()
  1747   return NS_IsMainThread() ?
  1748     IsCallerChrome() :
  1749     mozilla::dom::workers::IsCurrentThreadRunningChromeWorker();
  1752 bool
  1753 nsContentUtils::IsCallerXBL()
  1755     JSContext *cx = GetCurrentJSContext();
  1756     if (!cx)
  1757         return false;
  1759     JSCompartment *c = js::GetContextCompartment(cx);
  1761     // For remote XUL, we run XBL in the XUL scope. Given that we care about
  1762     // compat and not security for remote XUL, just always claim to be XBL.
  1763     if (!xpc::AllowXBLScope(c)) {
  1764       MOZ_ASSERT(nsContentUtils::AllowXULXBLForPrincipal(xpc::GetCompartmentPrincipal(c)));
  1765       return true;
  1768     return xpc::IsXBLScope(c);
  1772 bool
  1773 nsContentUtils::IsImageSrcSetDisabled()
  1775   return Preferences::GetBool("dom.disable_image_src_set") &&
  1776          !IsCallerChrome();
  1779 // static
  1780 bool
  1781 nsContentUtils::LookupBindingMember(JSContext* aCx, nsIContent *aContent,
  1782                                     JS::Handle<jsid> aId,
  1783                                     JS::MutableHandle<JSPropertyDescriptor> aDesc)
  1785   nsXBLBinding* binding = aContent->GetXBLBinding();
  1786   if (!binding)
  1787     return true;
  1788   return binding->LookupMember(aCx, aId, aDesc);
  1791 // static
  1792 nsINode*
  1793 nsContentUtils::GetCrossDocParentNode(nsINode* aChild)
  1795   NS_PRECONDITION(aChild, "The child is null!");
  1797   nsINode* parent = aChild->GetParentNode();
  1798   if (parent || !aChild->IsNodeOfType(nsINode::eDOCUMENT))
  1799     return parent;
  1801   nsIDocument* doc = static_cast<nsIDocument*>(aChild);
  1802   nsIDocument* parentDoc = doc->GetParentDocument();
  1803   return parentDoc ? parentDoc->FindContentForSubDocument(doc) : nullptr;
  1806 // static
  1807 bool
  1808 nsContentUtils::ContentIsDescendantOf(const nsINode* aPossibleDescendant,
  1809                                       const nsINode* aPossibleAncestor)
  1811   NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
  1812   NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
  1814   do {
  1815     if (aPossibleDescendant == aPossibleAncestor)
  1816       return true;
  1817     aPossibleDescendant = aPossibleDescendant->GetParentNode();
  1818   } while (aPossibleDescendant);
  1820   return false;
  1823 bool
  1824 nsContentUtils::ContentIsHostIncludingDescendantOf(
  1825   const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor)
  1827   NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
  1828   NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
  1830   do {
  1831     if (aPossibleDescendant == aPossibleAncestor)
  1832       return true;
  1833     if (aPossibleDescendant->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
  1834       aPossibleDescendant =
  1835         static_cast<const DocumentFragment*>(aPossibleDescendant)->GetHost();
  1836     } else {
  1837       aPossibleDescendant = aPossibleDescendant->GetParentNode();
  1839   } while (aPossibleDescendant);
  1841   return false;
  1844 // static
  1845 bool
  1846 nsContentUtils::ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
  1847                                               nsINode* aPossibleAncestor)
  1849   NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
  1850   NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
  1852   do {
  1853     if (aPossibleDescendant == aPossibleAncestor)
  1854       return true;
  1855     aPossibleDescendant = GetCrossDocParentNode(aPossibleDescendant);
  1856   } while (aPossibleDescendant);
  1858   return false;
  1862 // static
  1863 nsresult
  1864 nsContentUtils::GetAncestors(nsINode* aNode,
  1865                              nsTArray<nsINode*>& aArray)
  1867   while (aNode) {
  1868     aArray.AppendElement(aNode);
  1869     aNode = aNode->GetParentNode();
  1871   return NS_OK;
  1874 // static
  1875 nsresult
  1876 nsContentUtils::GetAncestorsAndOffsets(nsIDOMNode* aNode,
  1877                                        int32_t aOffset,
  1878                                        nsTArray<nsIContent*>* aAncestorNodes,
  1879                                        nsTArray<int32_t>* aAncestorOffsets)
  1881   NS_ENSURE_ARG_POINTER(aNode);
  1883   nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
  1885   if (!content) {
  1886     return NS_ERROR_FAILURE;
  1889   if (!aAncestorNodes->IsEmpty()) {
  1890     NS_WARNING("aAncestorNodes is not empty");
  1891     aAncestorNodes->Clear();
  1894   if (!aAncestorOffsets->IsEmpty()) {
  1895     NS_WARNING("aAncestorOffsets is not empty");
  1896     aAncestorOffsets->Clear();
  1899   // insert the node itself
  1900   aAncestorNodes->AppendElement(content.get());
  1901   aAncestorOffsets->AppendElement(aOffset);
  1903   // insert all the ancestors
  1904   nsIContent* child = content;
  1905   nsIContent* parent = child->GetParent();
  1906   while (parent) {
  1907     aAncestorNodes->AppendElement(parent);
  1908     aAncestorOffsets->AppendElement(parent->IndexOf(child));
  1909     child = parent;
  1910     parent = parent->GetParent();
  1913   return NS_OK;
  1916 // static
  1917 nsresult
  1918 nsContentUtils::GetCommonAncestor(nsIDOMNode *aNode,
  1919                                   nsIDOMNode *aOther,
  1920                                   nsIDOMNode** aCommonAncestor)
  1922   *aCommonAncestor = nullptr;
  1924   nsCOMPtr<nsINode> node1 = do_QueryInterface(aNode);
  1925   nsCOMPtr<nsINode> node2 = do_QueryInterface(aOther);
  1927   NS_ENSURE_TRUE(node1 && node2, NS_ERROR_UNEXPECTED);
  1929   nsINode* common = GetCommonAncestor(node1, node2);
  1930   NS_ENSURE_TRUE(common, NS_ERROR_NOT_AVAILABLE);
  1932   return CallQueryInterface(common, aCommonAncestor);
  1935 // static
  1936 nsINode*
  1937 nsContentUtils::GetCommonAncestor(nsINode* aNode1,
  1938                                   nsINode* aNode2)
  1940   if (aNode1 == aNode2) {
  1941     return aNode1;
  1944   // Build the chain of parents
  1945   nsAutoTArray<nsINode*, 30> parents1, parents2;
  1946   do {
  1947     parents1.AppendElement(aNode1);
  1948     aNode1 = aNode1->GetParentNode();
  1949   } while (aNode1);
  1950   do {
  1951     parents2.AppendElement(aNode2);
  1952     aNode2 = aNode2->GetParentNode();
  1953   } while (aNode2);
  1955   // Find where the parent chain differs
  1956   uint32_t pos1 = parents1.Length();
  1957   uint32_t pos2 = parents2.Length();
  1958   nsINode* parent = nullptr;
  1959   uint32_t len;
  1960   for (len = std::min(pos1, pos2); len > 0; --len) {
  1961     nsINode* child1 = parents1.ElementAt(--pos1);
  1962     nsINode* child2 = parents2.ElementAt(--pos2);
  1963     if (child1 != child2) {
  1964       break;
  1966     parent = child1;
  1969   return parent;
  1972 /* static */
  1973 bool
  1974 nsContentUtils::PositionIsBefore(nsINode* aNode1, nsINode* aNode2)
  1976   return (aNode2->CompareDocumentPosition(*aNode1) &
  1977     (nsIDOMNode::DOCUMENT_POSITION_PRECEDING |
  1978      nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED)) ==
  1979     nsIDOMNode::DOCUMENT_POSITION_PRECEDING;
  1982 /* static */
  1983 int32_t
  1984 nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
  1985                               nsINode* aParent2, int32_t aOffset2,
  1986                               bool* aDisconnected)
  1988   if (aParent1 == aParent2) {
  1989     return aOffset1 < aOffset2 ? -1 :
  1990            aOffset1 > aOffset2 ? 1 :
  1991            0;
  1994   nsAutoTArray<nsINode*, 32> parents1, parents2;
  1995   nsINode* node1 = aParent1;
  1996   nsINode* node2 = aParent2;
  1997   do {
  1998     parents1.AppendElement(node1);
  1999     node1 = node1->GetParentNode();
  2000   } while (node1);
  2001   do {
  2002     parents2.AppendElement(node2);
  2003     node2 = node2->GetParentNode();
  2004   } while (node2);
  2006   uint32_t pos1 = parents1.Length() - 1;
  2007   uint32_t pos2 = parents2.Length() - 1;
  2009   bool disconnected = parents1.ElementAt(pos1) != parents2.ElementAt(pos2);
  2010   if (aDisconnected) {
  2011     *aDisconnected = disconnected;
  2013   if (disconnected) {
  2014     NS_ASSERTION(aDisconnected, "unexpected disconnected nodes");
  2015     return 1;
  2018   // Find where the parent chains differ
  2019   nsINode* parent = parents1.ElementAt(pos1);
  2020   uint32_t len;
  2021   for (len = std::min(pos1, pos2); len > 0; --len) {
  2022     nsINode* child1 = parents1.ElementAt(--pos1);
  2023     nsINode* child2 = parents2.ElementAt(--pos2);
  2024     if (child1 != child2) {
  2025       return parent->IndexOf(child1) < parent->IndexOf(child2) ? -1 : 1;
  2027     parent = child1;
  2031   // The parent chains never differed, so one of the nodes is an ancestor of
  2032   // the other
  2034   NS_ASSERTION(!pos1 || !pos2,
  2035                "should have run out of parent chain for one of the nodes");
  2037   if (!pos1) {
  2038     nsINode* child2 = parents2.ElementAt(--pos2);
  2039     return aOffset1 <= parent->IndexOf(child2) ? -1 : 1;
  2042   nsINode* child1 = parents1.ElementAt(--pos1);
  2043   return parent->IndexOf(child1) < aOffset2 ? -1 : 1;
  2046 /* static */
  2047 int32_t
  2048 nsContentUtils::ComparePoints(nsIDOMNode* aParent1, int32_t aOffset1,
  2049                               nsIDOMNode* aParent2, int32_t aOffset2,
  2050                               bool* aDisconnected)
  2052   nsCOMPtr<nsINode> parent1 = do_QueryInterface(aParent1);
  2053   nsCOMPtr<nsINode> parent2 = do_QueryInterface(aParent2);
  2054   NS_ENSURE_TRUE(parent1 && parent2, -1);
  2055   return ComparePoints(parent1, aOffset1, parent2, aOffset2);
  2058 inline bool
  2059 IsCharInSet(const char* aSet,
  2060             const char16_t aChar)
  2062   char16_t ch;
  2063   while ((ch = *aSet)) {
  2064     if (aChar == char16_t(ch)) {
  2065       return true;
  2067     ++aSet;
  2069   return false;
  2072 /**
  2073  * This method strips leading/trailing chars, in given set, from string.
  2074  */
  2076 // static
  2077 const nsDependentSubstring
  2078 nsContentUtils::TrimCharsInSet(const char* aSet,
  2079                                const nsAString& aValue)
  2081   nsAString::const_iterator valueCurrent, valueEnd;
  2083   aValue.BeginReading(valueCurrent);
  2084   aValue.EndReading(valueEnd);
  2086   // Skip characters in the beginning
  2087   while (valueCurrent != valueEnd) {
  2088     if (!IsCharInSet(aSet, *valueCurrent)) {
  2089       break;
  2091     ++valueCurrent;
  2094   if (valueCurrent != valueEnd) {
  2095     for (;;) {
  2096       --valueEnd;
  2097       if (!IsCharInSet(aSet, *valueEnd)) {
  2098         break;
  2101     ++valueEnd; // Step beyond the last character we want in the value.
  2104   // valueEnd should point to the char after the last to copy
  2105   return Substring(valueCurrent, valueEnd);
  2108 /**
  2109  * This method strips leading and trailing whitespace from a string.
  2110  */
  2112 // static
  2113 template<bool IsWhitespace(char16_t)>
  2114 const nsDependentSubstring
  2115 nsContentUtils::TrimWhitespace(const nsAString& aStr, bool aTrimTrailing)
  2117   nsAString::const_iterator start, end;
  2119   aStr.BeginReading(start);
  2120   aStr.EndReading(end);
  2122   // Skip whitespace characters in the beginning
  2123   while (start != end && IsWhitespace(*start)) {
  2124     ++start;
  2127   if (aTrimTrailing) {
  2128     // Skip whitespace characters in the end.
  2129     while (end != start) {
  2130       --end;
  2132       if (!IsWhitespace(*end)) {
  2133         // Step back to the last non-whitespace character.
  2134         ++end;
  2136         break;
  2141   // Return a substring for the string w/o leading and/or trailing
  2142   // whitespace
  2144   return Substring(start, end);
  2147 // Declaring the templates we are going to use avoid linking issues without
  2148 // inlining the method. Considering there is not so much spaces checking
  2149 // methods we can consider this to be better than inlining.
  2150 template
  2151 const nsDependentSubstring
  2152 nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(const nsAString&, bool);
  2153 template
  2154 const nsDependentSubstring
  2155 nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(const nsAString&, bool);
  2156 template
  2157 const nsDependentSubstring
  2158 nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespaceOrNBSP>(const nsAString&, bool);
  2160 static inline void KeyAppendSep(nsACString& aKey)
  2162   if (!aKey.IsEmpty()) {
  2163     aKey.Append('>');
  2167 static inline void KeyAppendString(const nsAString& aString, nsACString& aKey)
  2169   KeyAppendSep(aKey);
  2171   // Could escape separator here if collisions happen.  > is not a legal char
  2172   // for a name or type attribute, so we should be safe avoiding that extra work.
  2174   AppendUTF16toUTF8(aString, aKey);
  2177 static inline void KeyAppendString(const nsACString& aString, nsACString& aKey)
  2179   KeyAppendSep(aKey);
  2181   // Could escape separator here if collisions happen.  > is not a legal char
  2182   // for a name or type attribute, so we should be safe avoiding that extra work.
  2184   aKey.Append(aString);
  2187 static inline void KeyAppendInt(int32_t aInt, nsACString& aKey)
  2189   KeyAppendSep(aKey);
  2191   aKey.Append(nsPrintfCString("%d", aInt));
  2194 static inline bool IsAutocompleteOff(const nsIContent* aElement)
  2196   return aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::autocomplete,
  2197                                NS_LITERAL_STRING("off"), eIgnoreCase);
  2200 /*static*/ nsresult
  2201 nsContentUtils::GenerateStateKey(nsIContent* aContent,
  2202                                  const nsIDocument* aDocument,
  2203                                  nsACString& aKey)
  2205   aKey.Truncate();
  2207   uint32_t partID = aDocument ? aDocument->GetPartID() : 0;
  2209   // We must have content if we're not using a special state id
  2210   NS_ENSURE_TRUE(aContent, NS_ERROR_FAILURE);
  2212   // Don't capture state for anonymous content
  2213   if (aContent->IsInAnonymousSubtree()) {
  2214     return NS_OK;
  2217   if (IsAutocompleteOff(aContent)) {
  2218     return NS_OK;
  2221   nsCOMPtr<nsIHTMLDocument> htmlDocument(do_QueryInterface(aContent->GetCurrentDoc()));
  2223   KeyAppendInt(partID, aKey);  // first append a partID
  2224   bool generatedUniqueKey = false;
  2226   if (htmlDocument) {
  2227     // Flush our content model so it'll be up to date
  2228     // If this becomes unnecessary and the following line is removed,
  2229     // please also remove the corresponding flush operation from
  2230     // nsHtml5TreeBuilderCppSupplement.h. (Look for "See bug 497861." there.)
  2231     aContent->GetCurrentDoc()->FlushPendingNotifications(Flush_Content);
  2233     nsContentList *htmlForms = htmlDocument->GetForms();
  2234     nsContentList *htmlFormControls = htmlDocument->GetFormControls();
  2236     NS_ENSURE_TRUE(htmlForms && htmlFormControls, NS_ERROR_OUT_OF_MEMORY);
  2238     // If we have a form control and can calculate form information, use that
  2239     // as the key - it is more reliable than just recording position in the
  2240     // DOM.
  2241     // XXXbz Is it, really?  We have bugs on this, I think...
  2242     // Important to have a unique key, and tag/type/name may not be.
  2243     //
  2244     // If the control has a form, the format of the key is:
  2245     // f>type>IndOfFormInDoc>IndOfControlInForm>FormName>name
  2246     // else:
  2247     // d>type>IndOfControlInDoc>name
  2248     //
  2249     // XXX We don't need to use index if name is there
  2250     // XXXbz We don't?  Why not?  I don't follow.
  2251     //
  2252     nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent));
  2253     if (control && htmlFormControls && htmlForms) {
  2255       // Append the control type
  2256       KeyAppendInt(control->GetType(), aKey);
  2258       // If in a form, add form name / index of form / index in form
  2259       int32_t index = -1;
  2260       Element *formElement = control->GetFormElement();
  2261       if (formElement) {
  2262         if (IsAutocompleteOff(formElement)) {
  2263           aKey.Truncate();
  2264           return NS_OK;
  2267         KeyAppendString(NS_LITERAL_CSTRING("f"), aKey);
  2269         // Append the index of the form in the document
  2270         index = htmlForms->IndexOf(formElement, false);
  2271         if (index <= -1) {
  2272           //
  2273           // XXX HACK this uses some state that was dumped into the document
  2274           // specifically to fix bug 138892.  What we are trying to do is *guess*
  2275           // which form this control's state is found in, with the highly likely
  2276           // guess that the highest form parsed so far is the one.
  2277           // This code should not be on trunk, only branch.
  2278           //
  2279           index = htmlDocument->GetNumFormsSynchronous() - 1;
  2281         if (index > -1) {
  2282           KeyAppendInt(index, aKey);
  2284           // Append the index of the control in the form
  2285           nsCOMPtr<nsIForm> form(do_QueryInterface(formElement));
  2286           index = form->IndexOfControl(control);
  2288           if (index > -1) {
  2289             KeyAppendInt(index, aKey);
  2290             generatedUniqueKey = true;
  2294         // Append the form name
  2295         nsAutoString formName;
  2296         formElement->GetAttr(kNameSpaceID_None, nsGkAtoms::name, formName);
  2297         KeyAppendString(formName, aKey);
  2299       } else {
  2301         KeyAppendString(NS_LITERAL_CSTRING("d"), aKey);
  2303         // If not in a form, add index of control in document
  2304         // Less desirable than indexing by form info.
  2306         // Hash by index of control in doc (we are not in a form)
  2307         // These are important as they are unique, and type/name may not be.
  2309         // We have to flush sink notifications at this point to make
  2310         // sure that htmlFormControls is up to date.
  2311         index = htmlFormControls->IndexOf(aContent, true);
  2312         if (index > -1) {
  2313           KeyAppendInt(index, aKey);
  2314           generatedUniqueKey = true;
  2318       // Append the control name
  2319       nsAutoString name;
  2320       aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
  2321       KeyAppendString(name, aKey);
  2325   if (!generatedUniqueKey) {
  2326     // Either we didn't have a form control or we aren't in an HTML document so
  2327     // we can't figure out form info.  Append the tag name if it's an element
  2328     // to avoid restoring state for one type of element on another type.
  2329     if (aContent->IsElement()) {
  2330       KeyAppendString(nsDependentAtomString(aContent->Tag()), aKey);
  2332     else {
  2333       // Append a character that is not "d" or "f" to disambiguate from
  2334       // the case when we were a form control in an HTML document.
  2335       KeyAppendString(NS_LITERAL_CSTRING("o"), aKey);
  2338     // Now start at aContent and append the indices of it and all its ancestors
  2339     // in their containers.  That should at least pin down its position in the
  2340     // DOM...
  2341     nsINode* parent = aContent->GetParentNode();
  2342     nsINode* content = aContent;
  2343     while (parent) {
  2344       KeyAppendInt(parent->IndexOf(content), aKey);
  2345       content = parent;
  2346       parent = content->GetParentNode();
  2350   return NS_OK;
  2353 // static
  2354 nsIPrincipal*
  2355 nsContentUtils::GetSubjectPrincipal()
  2357   nsCOMPtr<nsIPrincipal> subject;
  2358   sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subject));
  2360   // When the ssm says the subject is null, that means system principal.
  2361   if (!subject)
  2362     sSecurityManager->GetSystemPrincipal(getter_AddRefs(subject));
  2364   return subject;
  2367 // static
  2368 nsIPrincipal*
  2369 nsContentUtils::GetObjectPrincipal(JSObject* aObj)
  2371   // This is duplicated from nsScriptSecurityManager. We don't call through there
  2372   // because the API unnecessarily requires a JSContext for historical reasons.
  2373   JSCompartment *compartment = js::GetObjectCompartment(aObj);
  2374   JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
  2375   return nsJSPrincipals::get(principals);
  2378 // static
  2379 nsresult
  2380 nsContentUtils::NewURIWithDocumentCharset(nsIURI** aResult,
  2381                                           const nsAString& aSpec,
  2382                                           nsIDocument* aDocument,
  2383                                           nsIURI* aBaseURI)
  2385   return NS_NewURI(aResult, aSpec,
  2386                    aDocument ? aDocument->GetDocumentCharacterSet().get() : nullptr,
  2387                    aBaseURI, sIOService);
  2390 // static
  2391 bool
  2392 nsContentUtils::IsCustomElementName(nsIAtom* aName)
  2394   // The custom element name identifies a custom element and is a sequence of
  2395   // alphanumeric ASCII characters that must match the NCName production and
  2396   // contain a U+002D HYPHEN-MINUS character.
  2397   nsDependentAtomString str(aName);
  2398   const char16_t* colon;
  2399   if (NS_FAILED(nsContentUtils::CheckQName(str, false, &colon)) || colon ||
  2400       str.FindChar('-') == -1) {
  2401     return false;
  2404   // The custom element name must not be one of the following values:
  2405   //  annotation-xml
  2406   //  color-profile
  2407   //  font-face
  2408   //  font-face-src
  2409   //  font-face-uri
  2410   //  font-face-format
  2411   //  font-face-name
  2412   //  missing-glyph
  2413   return aName != nsGkAtoms::annotation_xml_ &&
  2414          aName != nsGkAtoms::colorProfile &&
  2415          aName != nsGkAtoms::font_face &&
  2416          aName != nsGkAtoms::font_face_src &&
  2417          aName != nsGkAtoms::font_face_uri &&
  2418          aName != nsGkAtoms::font_face_format &&
  2419          aName != nsGkAtoms::font_face_name &&
  2420          aName != nsGkAtoms::missingGlyph;
  2423 // static
  2424 nsresult
  2425 nsContentUtils::CheckQName(const nsAString& aQualifiedName,
  2426                            bool aNamespaceAware,
  2427                            const char16_t** aColon)
  2429   const char* colon = nullptr;
  2430   const char16_t* begin = aQualifiedName.BeginReading();
  2431   const char16_t* end = aQualifiedName.EndReading();
  2433   int result = MOZ_XMLCheckQName(reinterpret_cast<const char*>(begin),
  2434                                  reinterpret_cast<const char*>(end),
  2435                                  aNamespaceAware, &colon);
  2437   if (!result) {
  2438     if (aColon) {
  2439       *aColon = reinterpret_cast<const char16_t*>(colon);
  2442     return NS_OK;
  2445   // MOZ_EXPAT_EMPTY_QNAME || MOZ_EXPAT_INVALID_CHARACTER
  2446   if (result == (1 << 0) || result == (1 << 1)) {
  2447     return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
  2450   return NS_ERROR_DOM_NAMESPACE_ERR;
  2453 //static
  2454 nsresult
  2455 nsContentUtils::SplitQName(const nsIContent* aNamespaceResolver,
  2456                            const nsAFlatString& aQName,
  2457                            int32_t *aNamespace, nsIAtom **aLocalName)
  2459   const char16_t* colon;
  2460   nsresult rv = nsContentUtils::CheckQName(aQName, true, &colon);
  2461   NS_ENSURE_SUCCESS(rv, rv);
  2463   if (colon) {
  2464     const char16_t* end;
  2465     aQName.EndReading(end);
  2466     nsAutoString nameSpace;
  2467     rv = aNamespaceResolver->LookupNamespaceURIInternal(Substring(aQName.get(),
  2468                                                                   colon),
  2469                                                         nameSpace);
  2470     NS_ENSURE_SUCCESS(rv, rv);
  2472     *aNamespace = NameSpaceManager()->GetNameSpaceID(nameSpace);
  2473     if (*aNamespace == kNameSpaceID_Unknown)
  2474       return NS_ERROR_FAILURE;
  2476     *aLocalName = NS_NewAtom(Substring(colon + 1, end)).take();
  2478   else {
  2479     *aNamespace = kNameSpaceID_None;
  2480     *aLocalName = NS_NewAtom(aQName).take();
  2482   NS_ENSURE_TRUE(aLocalName, NS_ERROR_OUT_OF_MEMORY);
  2483   return NS_OK;
  2486 // static
  2487 nsresult
  2488 nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI,
  2489                                      const nsAString& aQualifiedName,
  2490                                      nsNodeInfoManager* aNodeInfoManager,
  2491                                      uint16_t aNodeType,
  2492                                      nsINodeInfo** aNodeInfo)
  2494   const nsAFlatString& qName = PromiseFlatString(aQualifiedName);
  2495   const char16_t* colon;
  2496   nsresult rv = nsContentUtils::CheckQName(qName, true, &colon);
  2497   NS_ENSURE_SUCCESS(rv, rv);
  2499   int32_t nsID;
  2500   sNameSpaceManager->RegisterNameSpace(aNamespaceURI, nsID);
  2501   if (colon) {
  2502     const char16_t* end;
  2503     qName.EndReading(end);
  2505     nsCOMPtr<nsIAtom> prefix = do_GetAtom(Substring(qName.get(), colon));
  2507     rv = aNodeInfoManager->GetNodeInfo(Substring(colon + 1, end), prefix,
  2508                                        nsID, aNodeType, aNodeInfo);
  2510   else {
  2511     rv = aNodeInfoManager->GetNodeInfo(aQualifiedName, nullptr, nsID,
  2512                                        aNodeType, aNodeInfo);
  2514   NS_ENSURE_SUCCESS(rv, rv);
  2516   return nsContentUtils::IsValidNodeName((*aNodeInfo)->NameAtom(),
  2517                                          (*aNodeInfo)->GetPrefixAtom(),
  2518                                          (*aNodeInfo)->NamespaceID()) ?
  2519          NS_OK : NS_ERROR_DOM_NAMESPACE_ERR;
  2522 // static
  2523 void
  2524 nsContentUtils::SplitExpatName(const char16_t *aExpatName, nsIAtom **aPrefix,
  2525                                nsIAtom **aLocalName, int32_t* aNameSpaceID)
  2527   /**
  2528    *  Expat can send the following:
  2529    *    localName
  2530    *    namespaceURI<separator>localName
  2531    *    namespaceURI<separator>localName<separator>prefix
  2533    *  and we use 0xFFFF for the <separator>.
  2535    */
  2537   const char16_t *uriEnd = nullptr;
  2538   const char16_t *nameEnd = nullptr;
  2539   const char16_t *pos;
  2540   for (pos = aExpatName; *pos; ++pos) {
  2541     if (*pos == 0xFFFF) {
  2542       if (uriEnd) {
  2543         nameEnd = pos;
  2545       else {
  2546         uriEnd = pos;
  2551   const char16_t *nameStart;
  2552   if (uriEnd) {
  2553     if (sNameSpaceManager) {
  2554       sNameSpaceManager->RegisterNameSpace(nsDependentSubstring(aExpatName,
  2555                                                                 uriEnd),
  2556                                            *aNameSpaceID);
  2558     else {
  2559       *aNameSpaceID = kNameSpaceID_Unknown;
  2562     nameStart = (uriEnd + 1);
  2563     if (nameEnd)  {
  2564       const char16_t *prefixStart = nameEnd + 1;
  2565       *aPrefix = NS_NewAtom(Substring(prefixStart, pos)).take();
  2567     else {
  2568       nameEnd = pos;
  2569       *aPrefix = nullptr;
  2572   else {
  2573     *aNameSpaceID = kNameSpaceID_None;
  2574     nameStart = aExpatName;
  2575     nameEnd = pos;
  2576     *aPrefix = nullptr;
  2578   *aLocalName = NS_NewAtom(Substring(nameStart, nameEnd)).take();
  2581 // static
  2582 nsPresContext*
  2583 nsContentUtils::GetContextForContent(const nsIContent* aContent)
  2585   nsIDocument* doc = aContent->GetCurrentDoc();
  2586   if (doc) {
  2587     nsIPresShell *presShell = doc->GetShell();
  2588     if (presShell) {
  2589       return presShell->GetPresContext();
  2592   return nullptr;
  2595 // static
  2596 bool
  2597 nsContentUtils::CanLoadImage(nsIURI* aURI, nsISupports* aContext,
  2598                              nsIDocument* aLoadingDocument,
  2599                              nsIPrincipal* aLoadingPrincipal,
  2600                              int16_t* aImageBlockingStatus)
  2602   NS_PRECONDITION(aURI, "Must have a URI");
  2603   NS_PRECONDITION(aLoadingDocument, "Must have a document");
  2604   NS_PRECONDITION(aLoadingPrincipal, "Must have a loading principal");
  2606   nsresult rv;
  2608   uint32_t appType = nsIDocShell::APP_TYPE_UNKNOWN;
  2611     nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = aLoadingDocument->GetDocShell();
  2612     if (docShellTreeItem) {
  2613       nsCOMPtr<nsIDocShellTreeItem> root;
  2614       docShellTreeItem->GetRootTreeItem(getter_AddRefs(root));
  2616       nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root));
  2618       if (!docShell || NS_FAILED(docShell->GetAppType(&appType))) {
  2619         appType = nsIDocShell::APP_TYPE_UNKNOWN;
  2624   if (appType != nsIDocShell::APP_TYPE_EDITOR) {
  2625     // Editor apps get special treatment here, editors can load images
  2626     // from anywhere.  This allows editor to insert images from file://
  2627     // into documents that are being edited.
  2628     rv = sSecurityManager->
  2629       CheckLoadURIWithPrincipal(aLoadingPrincipal, aURI,
  2630                                 nsIScriptSecurityManager::ALLOW_CHROME);
  2631     if (NS_FAILED(rv)) {
  2632       if (aImageBlockingStatus) {
  2633         // Reject the request itself, not all requests to the relevant
  2634         // server...
  2635         *aImageBlockingStatus = nsIContentPolicy::REJECT_REQUEST;
  2637       return false;
  2641   int16_t decision = nsIContentPolicy::ACCEPT;
  2643   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_IMAGE,
  2644                                  aURI,
  2645                                  aLoadingPrincipal,
  2646                                  aContext,
  2647                                  EmptyCString(), //mime guess
  2648                                  nullptr,         //extra
  2649                                  &decision,
  2650                                  GetContentPolicy(),
  2651                                  sSecurityManager);
  2653   if (aImageBlockingStatus) {
  2654     *aImageBlockingStatus =
  2655       NS_FAILED(rv) ? nsIContentPolicy::REJECT_REQUEST : decision;
  2657   return NS_FAILED(rv) ? false : NS_CP_ACCEPTED(decision);
  2660 imgLoader*
  2661 nsContentUtils::GetImgLoaderForDocument(nsIDocument* aDoc)
  2663   if (!aDoc)
  2664     return imgLoader::Singleton();
  2665   bool isPrivate = false;
  2666   nsCOMPtr<nsILoadGroup> loadGroup = aDoc->GetDocumentLoadGroup();
  2667   nsCOMPtr<nsIInterfaceRequestor> callbacks;
  2668   if (loadGroup) {
  2669     loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
  2670     if (callbacks) {
  2671       nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
  2672       isPrivate = loadContext && loadContext->UsePrivateBrowsing();
  2674   } else {
  2675     nsCOMPtr<nsIChannel> channel = aDoc->GetChannel();
  2676     isPrivate = channel && NS_UsePrivateBrowsing(channel);
  2678   return isPrivate ? imgLoader::PBSingleton() : imgLoader::Singleton();
  2681 // static
  2682 imgLoader*
  2683 nsContentUtils::GetImgLoaderForChannel(nsIChannel* aChannel)
  2685   if (!aChannel)
  2686     return imgLoader::Singleton();
  2687   nsCOMPtr<nsILoadContext> context;
  2688   NS_QueryNotificationCallbacks(aChannel, context);
  2689   return context && context->UsePrivateBrowsing() ? imgLoader::PBSingleton() : imgLoader::Singleton();
  2692 // static
  2693 bool
  2694 nsContentUtils::IsImageInCache(nsIURI* aURI, nsIDocument* aDocument)
  2696     imgILoader* loader = GetImgLoaderForDocument(aDocument);
  2697     nsCOMPtr<imgICache> cache = do_QueryInterface(loader);
  2699     // If something unexpected happened we return false, otherwise if props
  2700     // is set, the image is cached and we return true
  2701     nsCOMPtr<nsIProperties> props;
  2702     nsresult rv = cache->FindEntryProperties(aURI, getter_AddRefs(props));
  2703     return (NS_SUCCEEDED(rv) && props);
  2706 // static
  2707 nsresult
  2708 nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
  2709                           nsIPrincipal* aLoadingPrincipal, nsIURI* aReferrer,
  2710                           imgINotificationObserver* aObserver, int32_t aLoadFlags,
  2711                           const nsAString& initiatorType,
  2712                           imgRequestProxy** aRequest)
  2714   NS_PRECONDITION(aURI, "Must have a URI");
  2715   NS_PRECONDITION(aLoadingDocument, "Must have a document");
  2716   NS_PRECONDITION(aLoadingPrincipal, "Must have a principal");
  2717   NS_PRECONDITION(aRequest, "Null out param");
  2719   imgLoader* imgLoader = GetImgLoaderForDocument(aLoadingDocument);
  2720   if (!imgLoader) {
  2721     // nothing we can do here
  2722     return NS_OK;
  2725   nsCOMPtr<nsILoadGroup> loadGroup = aLoadingDocument->GetDocumentLoadGroup();
  2727   nsIURI *documentURI = aLoadingDocument->GetDocumentURI();
  2729   NS_ASSERTION(loadGroup || IsFontTableURI(documentURI),
  2730                "Could not get loadgroup; onload may fire too early");
  2732   // check for a Content Security Policy to pass down to the channel that
  2733   // will get created to load the image
  2734   nsCOMPtr<nsIChannelPolicy> channelPolicy;
  2735   nsCOMPtr<nsIContentSecurityPolicy> csp;
  2736   if (aLoadingPrincipal) {
  2737     nsresult rv = aLoadingPrincipal->GetCsp(getter_AddRefs(csp));
  2738     NS_ENSURE_SUCCESS(rv, rv);
  2739     if (csp) {
  2740       channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
  2741       channelPolicy->SetContentSecurityPolicy(csp);
  2742       channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE);
  2746   // Make the URI immutable so people won't change it under us
  2747   NS_TryToSetImmutable(aURI);
  2749   nsCOMPtr<nsIURI> firstPartyIsolationURI;
  2750   nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
  2751                                = do_GetService(THIRDPARTYUTIL_CONTRACTID);
  2752   thirdPartySvc->GetFirstPartyIsolationURI(nullptr, aLoadingDocument,
  2753                                            getter_AddRefs(firstPartyIsolationURI));
  2755   return imgLoader->LoadImage(aURI,                   /* uri to load */
  2756                               firstPartyIsolationURI, /* firstPartyIsolationURI */
  2757                               aReferrer,              /* referrer */
  2758                               aLoadingPrincipal,      /* loading principal */
  2759                               loadGroup,              /* loadgroup */
  2760                               aObserver,              /* imgINotificationObserver */
  2761                               aLoadingDocument,       /* uniquification key */
  2762                               aLoadFlags,             /* load flags */
  2763                               nullptr,                /* cache key */
  2764                               channelPolicy,          /* CSP info */
  2765                               initiatorType,          /* the load initiator */
  2766                               aRequest);
  2769 // static
  2770 already_AddRefed<imgIContainer>
  2771 nsContentUtils::GetImageFromContent(nsIImageLoadingContent* aContent,
  2772                                     imgIRequest **aRequest)
  2774   if (aRequest) {
  2775     *aRequest = nullptr;
  2778   NS_ENSURE_TRUE(aContent, nullptr);
  2780   nsCOMPtr<imgIRequest> imgRequest;
  2781   aContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
  2782                       getter_AddRefs(imgRequest));
  2783   if (!imgRequest) {
  2784     return nullptr;
  2787   nsCOMPtr<imgIContainer> imgContainer;
  2788   imgRequest->GetImage(getter_AddRefs(imgContainer));
  2790   if (!imgContainer) {
  2791     return nullptr;
  2794   if (aRequest) {
  2795     imgRequest.swap(*aRequest);
  2798   return imgContainer.forget();
  2801 //static
  2802 already_AddRefed<imgRequestProxy>
  2803 nsContentUtils::GetStaticRequest(imgRequestProxy* aRequest)
  2805   NS_ENSURE_TRUE(aRequest, nullptr);
  2806   nsRefPtr<imgRequestProxy> retval;
  2807   aRequest->GetStaticRequest(getter_AddRefs(retval));
  2808   return retval.forget();
  2811 // static
  2812 bool
  2813 nsContentUtils::ContentIsDraggable(nsIContent* aContent)
  2815   nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(aContent);
  2816   if (htmlElement) {
  2817     bool draggable = false;
  2818     htmlElement->GetDraggable(&draggable);
  2819     if (draggable)
  2820       return true;
  2822     if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
  2823                               nsGkAtoms::_false, eIgnoreCase))
  2824       return false;
  2827   // special handling for content area image and link dragging
  2828   return IsDraggableImage(aContent) || IsDraggableLink(aContent);
  2831 // static
  2832 bool
  2833 nsContentUtils::IsDraggableImage(nsIContent* aContent)
  2835   NS_PRECONDITION(aContent, "Must have content node to test");
  2837   nsCOMPtr<nsIImageLoadingContent> imageContent(do_QueryInterface(aContent));
  2838   if (!imageContent) {
  2839     return false;
  2842   nsCOMPtr<imgIRequest> imgRequest;
  2843   imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
  2844                            getter_AddRefs(imgRequest));
  2846   // XXXbz It may be draggable even if the request resulted in an error.  Why?
  2847   // Not sure; that's what the old nsContentAreaDragDrop/nsFrame code did.
  2848   return imgRequest != nullptr;
  2851 // static
  2852 bool
  2853 nsContentUtils::IsDraggableLink(const nsIContent* aContent) {
  2854   nsCOMPtr<nsIURI> absURI;
  2855   return aContent->IsLink(getter_AddRefs(absURI));
  2858 // static
  2859 nsresult
  2860 nsContentUtils::NameChanged(nsINodeInfo* aNodeInfo, nsIAtom* aName,
  2861                             nsINodeInfo** aResult)
  2863   nsNodeInfoManager *niMgr = aNodeInfo->NodeInfoManager();
  2865   *aResult = niMgr->GetNodeInfo(aName, aNodeInfo->GetPrefixAtom(),
  2866                                 aNodeInfo->NamespaceID(),
  2867                                 aNodeInfo->NodeType(),
  2868                                 aNodeInfo->GetExtraName()).take();
  2869   return NS_OK;
  2873 static bool
  2874 TestSitePerm(nsIPrincipal* aPrincipal, const char* aType, uint32_t aPerm, bool aExactHostMatch)
  2876   if (!aPrincipal) {
  2877     // We always deny (i.e. don't allow) the permission if we don't have a
  2878     // principal.
  2879     return aPerm != nsIPermissionManager::ALLOW_ACTION;
  2882   nsCOMPtr<nsIPermissionManager> permMgr =
  2883     do_GetService("@mozilla.org/permissionmanager;1");
  2884   NS_ENSURE_TRUE(permMgr, false);
  2886   uint32_t perm;
  2887   nsresult rv;
  2888   if (aExactHostMatch) {
  2889     rv = permMgr->TestExactPermissionFromPrincipal(aPrincipal, aType, &perm);
  2890   } else {
  2891     rv = permMgr->TestPermissionFromPrincipal(aPrincipal, aType, &perm);
  2893   NS_ENSURE_SUCCESS(rv, false);
  2895   return perm == aPerm;
  2898 bool
  2899 nsContentUtils::IsSitePermAllow(nsIPrincipal* aPrincipal, const char* aType)
  2901   return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION, false);
  2904 bool
  2905 nsContentUtils::IsSitePermDeny(nsIPrincipal* aPrincipal, const char* aType)
  2907   return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION, false);
  2910 bool
  2911 nsContentUtils::IsExactSitePermAllow(nsIPrincipal* aPrincipal, const char* aType)
  2913   return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION, true);
  2916 bool
  2917 nsContentUtils::IsExactSitePermDeny(nsIPrincipal* aPrincipal, const char* aType)
  2919   return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION, true);
  2922 static const char *gEventNames[] = {"event"};
  2923 static const char *gSVGEventNames[] = {"evt"};
  2924 // for b/w compat, the first name to onerror is still 'event', even though it
  2925 // is actually the error message.  (pre this code, the other 2 were not avail.)
  2926 // XXXmarkh - a quick lxr shows no affected code - should we correct this?
  2927 static const char *gOnErrorNames[] = {"event", "source", "lineno"};
  2929 // static
  2930 void
  2931 nsContentUtils::GetEventArgNames(int32_t aNameSpaceID,
  2932                                  nsIAtom *aEventName,
  2933                                  uint32_t *aArgCount,
  2934                                  const char*** aArgArray)
  2936 #define SET_EVENT_ARG_NAMES(names) \
  2937     *aArgCount = sizeof(names)/sizeof(names[0]); \
  2938     *aArgArray = names;
  2940   // JSEventHandler is what does the arg magic for onerror, and it does
  2941   // not seem to take the namespace into account.  So we let onerror in all
  2942   // namespaces get the 3 arg names.
  2943   if (aEventName == nsGkAtoms::onerror) {
  2944     SET_EVENT_ARG_NAMES(gOnErrorNames);
  2945   } else if (aNameSpaceID == kNameSpaceID_SVG) {
  2946     SET_EVENT_ARG_NAMES(gSVGEventNames);
  2947   } else {
  2948     SET_EVENT_ARG_NAMES(gEventNames);
  2952 static const char gPropertiesFiles[nsContentUtils::PropertiesFile_COUNT][56] = {
  2953   // Must line up with the enum values in |PropertiesFile| enum.
  2954   "chrome://global/locale/css.properties",
  2955   "chrome://global/locale/xbl.properties",
  2956   "chrome://global/locale/xul.properties",
  2957   "chrome://global/locale/layout_errors.properties",
  2958   "chrome://global/locale/layout/HtmlForm.properties",
  2959   "chrome://global/locale/printing.properties",
  2960   "chrome://global/locale/dom/dom.properties",
  2961   "chrome://global/locale/layout/htmlparser.properties",
  2962   "chrome://global/locale/svg/svg.properties",
  2963   "chrome://branding/locale/brand.properties",
  2964   "chrome://global/locale/commonDialogs.properties",
  2965   "chrome://global/locale/mathml/mathml.properties",
  2966   "chrome://global/locale/security/security.properties"
  2967 };
  2969 /* static */ nsresult
  2970 nsContentUtils::EnsureStringBundle(PropertiesFile aFile)
  2972   if (!sStringBundles[aFile]) {
  2973     if (!sStringBundleService) {
  2974       nsresult rv =
  2975         CallGetService(NS_STRINGBUNDLE_CONTRACTID, &sStringBundleService);
  2976       NS_ENSURE_SUCCESS(rv, rv);
  2978     nsIStringBundle *bundle;
  2979     nsresult rv =
  2980       sStringBundleService->CreateBundle(gPropertiesFiles[aFile], &bundle);
  2981     NS_ENSURE_SUCCESS(rv, rv);
  2982     sStringBundles[aFile] = bundle; // transfer ownership
  2984   return NS_OK;
  2987 /* static */
  2988 nsresult nsContentUtils::GetLocalizedString(PropertiesFile aFile,
  2989                                             const char* aKey,
  2990                                             nsXPIDLString& aResult)
  2992   nsresult rv = EnsureStringBundle(aFile);
  2993   NS_ENSURE_SUCCESS(rv, rv);
  2994   nsIStringBundle *bundle = sStringBundles[aFile];
  2996   return bundle->GetStringFromName(NS_ConvertASCIItoUTF16(aKey).get(),
  2997                                    getter_Copies(aResult));
  3000 /* static */
  3001 nsresult nsContentUtils::FormatLocalizedString(PropertiesFile aFile,
  3002                                                const char* aKey,
  3003                                                const char16_t **aParams,
  3004                                                uint32_t aParamsLength,
  3005                                                nsXPIDLString& aResult)
  3007   nsresult rv = EnsureStringBundle(aFile);
  3008   NS_ENSURE_SUCCESS(rv, rv);
  3009   nsIStringBundle *bundle = sStringBundles[aFile];
  3011   return bundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aKey).get(),
  3012                                       aParams, aParamsLength,
  3013                                       getter_Copies(aResult));
  3016 /* static */ void
  3017 nsContentUtils::LogSimpleConsoleError(const nsAString& aErrorText,
  3018                                       const char * classification)
  3020   nsCOMPtr<nsIScriptError> scriptError =
  3021     do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
  3022   if (scriptError) {
  3023     nsCOMPtr<nsIConsoleService> console =
  3024       do_GetService(NS_CONSOLESERVICE_CONTRACTID);
  3025     if (console && NS_SUCCEEDED(scriptError->Init(aErrorText, EmptyString(),
  3026                                                   EmptyString(), 0, 0,
  3027                                                   nsIScriptError::errorFlag,
  3028                                                   classification))) {
  3029       console->LogMessage(scriptError);
  3034 /* static */ nsresult
  3035 nsContentUtils::ReportToConsole(uint32_t aErrorFlags,
  3036                                 const nsACString& aCategory,
  3037                                 nsIDocument* aDocument,
  3038                                 PropertiesFile aFile,
  3039                                 const char *aMessageName,
  3040                                 const char16_t **aParams,
  3041                                 uint32_t aParamsLength,
  3042                                 nsIURI* aURI,
  3043                                 const nsAFlatString& aSourceLine,
  3044                                 uint32_t aLineNumber,
  3045                                 uint32_t aColumnNumber)
  3047   NS_ASSERTION((aParams && aParamsLength) || (!aParams && !aParamsLength),
  3048                "Supply either both parameters and their number or no"
  3049                "parameters and 0.");
  3051   nsresult rv;
  3052   nsXPIDLString errorText;
  3053   if (aParams) {
  3054     rv = FormatLocalizedString(aFile, aMessageName, aParams, aParamsLength,
  3055                                errorText);
  3057   else {
  3058     rv = GetLocalizedString(aFile, aMessageName, errorText);
  3060   NS_ENSURE_SUCCESS(rv, rv);
  3062   return ReportToConsoleNonLocalized(errorText, aErrorFlags, aCategory,
  3063                                      aDocument, aURI, aSourceLine,
  3064                                      aLineNumber, aColumnNumber);
  3068 /* static */ nsresult
  3069 nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
  3070                                             uint32_t aErrorFlags,
  3071                                             const nsACString& aCategory,
  3072                                             nsIDocument* aDocument,
  3073                                             nsIURI* aURI,
  3074                                             const nsAFlatString& aSourceLine,
  3075                                             uint32_t aLineNumber,
  3076                                             uint32_t aColumnNumber)
  3078   uint64_t innerWindowID = 0;
  3079   if (aDocument) {
  3080     if (!aURI) {
  3081       aURI = aDocument->GetDocumentURI();
  3083     innerWindowID = aDocument->InnerWindowID();
  3086   nsresult rv;
  3087   if (!sConsoleService) { // only need to bother null-checking here
  3088     rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService);
  3089     NS_ENSURE_SUCCESS(rv, rv);
  3092   nsAutoCString spec;
  3093   if (!aLineNumber) {
  3094     JSContext *cx = GetCurrentJSContext();
  3095     if (cx) {
  3096       const char* filename;
  3097       uint32_t lineno;
  3098       if (nsJSUtils::GetCallingLocation(cx, &filename, &lineno)) {
  3099         spec = filename;
  3100         aLineNumber = lineno;
  3104   if (spec.IsEmpty() && aURI)
  3105     aURI->GetSpec(spec);
  3107   nsCOMPtr<nsIScriptError> errorObject =
  3108       do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
  3109   NS_ENSURE_SUCCESS(rv, rv);
  3111   rv = errorObject->InitWithWindowID(aErrorText,
  3112                                      NS_ConvertUTF8toUTF16(spec), // file name
  3113                                      aSourceLine,
  3114                                      aLineNumber, aColumnNumber,
  3115                                      aErrorFlags, aCategory,
  3116                                      innerWindowID);
  3117   NS_ENSURE_SUCCESS(rv, rv);
  3119   return sConsoleService->LogMessage(errorObject);
  3122 void
  3123 nsContentUtils::LogMessageToConsole(const char* aMsg, ...)
  3125   if (!sConsoleService) { // only need to bother null-checking here
  3126     CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService);
  3127     if (!sConsoleService) {
  3128       return;
  3132   va_list args;
  3133   va_start(args, aMsg);
  3134   char* formatted = PR_vsmprintf(aMsg, args);
  3135   va_end(args);
  3136   if (!formatted) {
  3137     return;
  3140   sConsoleService->LogStringMessage(NS_ConvertUTF8toUTF16(formatted).get());
  3141   PR_smprintf_free(formatted);
  3144 bool
  3145 nsContentUtils::IsChromeDoc(nsIDocument *aDocument)
  3147   if (!aDocument) {
  3148     return false;
  3151   nsCOMPtr<nsIPrincipal> systemPrincipal;
  3152   sSecurityManager->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
  3154   return aDocument->NodePrincipal() == systemPrincipal;
  3157 bool
  3158 nsContentUtils::IsChildOfSameType(nsIDocument* aDoc)
  3160   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(aDoc->GetDocShell());
  3161   nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
  3162   if (docShellAsItem) {
  3163     docShellAsItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
  3165   return sameTypeParent != nullptr;
  3168 bool
  3169 nsContentUtils::IsPlainTextType(const nsACString& aContentType)
  3171   return aContentType.EqualsLiteral(TEXT_PLAIN) ||
  3172          aContentType.EqualsLiteral(TEXT_CSS) ||
  3173          aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) ||
  3174          aContentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
  3175          aContentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
  3176          aContentType.EqualsLiteral(TEXT_ECMASCRIPT) ||
  3177          aContentType.EqualsLiteral(APPLICATION_ECMASCRIPT) ||
  3178          aContentType.EqualsLiteral(TEXT_JAVASCRIPT) ||
  3179          aContentType.EqualsLiteral(APPLICATION_JSON);
  3182 bool
  3183 nsContentUtils::GetWrapperSafeScriptFilename(nsIDocument *aDocument,
  3184                                              nsIURI *aURI,
  3185                                              nsACString& aScriptURI)
  3187   bool scriptFileNameModified = false;
  3188   aURI->GetSpec(aScriptURI);
  3190   if (IsChromeDoc(aDocument)) {
  3191     nsCOMPtr<nsIChromeRegistry> chromeReg =
  3192       mozilla::services::GetChromeRegistryService();
  3194     if (!chromeReg) {
  3195       // If we're running w/o a chrome registry we won't modify any
  3196       // script file names.
  3198       return scriptFileNameModified;
  3201     bool docWrappersEnabled =
  3202       chromeReg->WrappersEnabled(aDocument->GetDocumentURI());
  3204     bool uriWrappersEnabled = chromeReg->WrappersEnabled(aURI);
  3206     nsIURI *docURI = aDocument->GetDocumentURI();
  3208     if (docURI && docWrappersEnabled && !uriWrappersEnabled) {
  3209       // aURI is a script from a URL that doesn't get wrapper
  3210       // automation. aDocument is a chrome document that does get
  3211       // wrapper automation. Prepend the chrome document's URI
  3212       // followed by the string " -> " to the URI of the script we're
  3213       // loading here so that script in that URI gets the same wrapper
  3214       // automation that the chrome document expects.
  3215       nsAutoCString spec;
  3216       docURI->GetSpec(spec);
  3217       spec.AppendLiteral(" -> ");
  3218       spec.Append(aScriptURI);
  3220       aScriptURI = spec;
  3222       scriptFileNameModified = true;
  3226   return scriptFileNameModified;
  3229 // static
  3230 bool
  3231 nsContentUtils::IsInChromeDocshell(nsIDocument *aDocument)
  3233   if (!aDocument) {
  3234     return false;
  3237   if (aDocument->GetDisplayDocument()) {
  3238     return IsInChromeDocshell(aDocument->GetDisplayDocument());
  3241   nsCOMPtr<nsIDocShellTreeItem> docShell = aDocument->GetDocShell();
  3242   if (!docShell) {
  3243     return false;
  3246   return docShell->ItemType() == nsIDocShellTreeItem::typeChrome;
  3249 // static
  3250 nsIContentPolicy*
  3251 nsContentUtils::GetContentPolicy()
  3253   if (!sTriedToGetContentPolicy) {
  3254     CallGetService(NS_CONTENTPOLICY_CONTRACTID, &sContentPolicyService);
  3255     // It's OK to not have a content policy service
  3256     sTriedToGetContentPolicy = true;
  3259   return sContentPolicyService;
  3262 // static
  3263 bool
  3264 nsContentUtils::IsEventAttributeName(nsIAtom* aName, int32_t aType)
  3266   const char16_t* name = aName->GetUTF16String();
  3267   if (name[0] != 'o' || name[1] != 'n')
  3268     return false;
  3270   EventNameMapping mapping;
  3271   return (sAtomEventTable->Get(aName, &mapping) && mapping.mType & aType);
  3274 // static
  3275 uint32_t
  3276 nsContentUtils::GetEventId(nsIAtom* aName)
  3278   if (aName) {
  3279     EventNameMapping mapping;
  3280     if (sAtomEventTable->Get(aName, &mapping)) {
  3281       return mapping.mId;
  3285   return NS_USER_DEFINED_EVENT;
  3288 // static
  3289 uint32_t
  3290 nsContentUtils::GetEventCategory(const nsAString& aName)
  3292   EventNameMapping mapping;
  3293   if (sStringEventTable->Get(aName, &mapping))
  3294     return mapping.mStructType;
  3296   return NS_EVENT;
  3299 nsIAtom*
  3300 nsContentUtils::GetEventIdAndAtom(const nsAString& aName,
  3301                                   uint32_t aEventStruct,
  3302                                   uint32_t* aEventID)
  3304   EventNameMapping mapping;
  3305   if (sStringEventTable->Get(aName, &mapping)) {
  3306     *aEventID =
  3307       mapping.mStructType == aEventStruct ? mapping.mId : NS_USER_DEFINED_EVENT;
  3308     return mapping.mAtom;
  3311   // If we have cached lots of user defined event names, clear some of them.
  3312   if (sUserDefinedEvents->Count() > 127) {
  3313     while (sUserDefinedEvents->Count() > 64) {
  3314       nsIAtom* first = sUserDefinedEvents->ObjectAt(0);
  3315       sStringEventTable->Remove(Substring(nsDependentAtomString(first), 2));
  3316       sUserDefinedEvents->RemoveObjectAt(0);
  3320   *aEventID = NS_USER_DEFINED_EVENT;
  3321   nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aName);
  3322   sUserDefinedEvents->AppendObject(atom);
  3323   mapping.mAtom = atom;
  3324   mapping.mId = NS_USER_DEFINED_EVENT;
  3325   mapping.mType = EventNameType_None;
  3326   mapping.mStructType = NS_EVENT_NULL;
  3327   sStringEventTable->Put(aName, mapping);
  3328   return mapping.mAtom;
  3331 static
  3332 nsresult GetEventAndTarget(nsIDocument* aDoc, nsISupports* aTarget,
  3333                            const nsAString& aEventName,
  3334                            bool aCanBubble, bool aCancelable,
  3335                            bool aTrusted, nsIDOMEvent** aEvent,
  3336                            EventTarget** aTargetOut)
  3338   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
  3339   nsCOMPtr<EventTarget> target(do_QueryInterface(aTarget));
  3340   NS_ENSURE_TRUE(domDoc && target, NS_ERROR_INVALID_ARG);
  3342   nsCOMPtr<nsIDOMEvent> event;
  3343   nsresult rv =
  3344     domDoc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
  3345   NS_ENSURE_SUCCESS(rv, rv);
  3347   rv = event->InitEvent(aEventName, aCanBubble, aCancelable);
  3348   NS_ENSURE_SUCCESS(rv, rv);
  3350   event->SetTrusted(aTrusted);
  3352   rv = event->SetTarget(target);
  3353   NS_ENSURE_SUCCESS(rv, rv);
  3355   event.forget(aEvent);
  3356   target.forget(aTargetOut);
  3357   return NS_OK;
  3360 // static
  3361 nsresult
  3362 nsContentUtils::DispatchTrustedEvent(nsIDocument* aDoc, nsISupports* aTarget,
  3363                                      const nsAString& aEventName,
  3364                                      bool aCanBubble, bool aCancelable,
  3365                                      bool *aDefaultAction)
  3367   return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
  3368                        true, aDefaultAction);
  3371 // static
  3372 nsresult
  3373 nsContentUtils::DispatchUntrustedEvent(nsIDocument* aDoc, nsISupports* aTarget,
  3374                                        const nsAString& aEventName,
  3375                                        bool aCanBubble, bool aCancelable,
  3376                                        bool *aDefaultAction)
  3378   return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
  3379                        false, aDefaultAction);
  3382 // static
  3383 nsresult
  3384 nsContentUtils::DispatchEvent(nsIDocument* aDoc, nsISupports* aTarget,
  3385                               const nsAString& aEventName,
  3386                               bool aCanBubble, bool aCancelable,
  3387                               bool aTrusted, bool *aDefaultAction)
  3389   nsCOMPtr<nsIDOMEvent> event;
  3390   nsCOMPtr<EventTarget> target;
  3391   nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble,
  3392                                   aCancelable, aTrusted, getter_AddRefs(event),
  3393                                   getter_AddRefs(target));
  3394   NS_ENSURE_SUCCESS(rv, rv);
  3396   bool dummy;
  3397   return target->DispatchEvent(event, aDefaultAction ? aDefaultAction : &dummy);
  3400 nsresult
  3401 nsContentUtils::DispatchChromeEvent(nsIDocument *aDoc,
  3402                                     nsISupports *aTarget,
  3403                                     const nsAString& aEventName,
  3404                                     bool aCanBubble, bool aCancelable,
  3405                                     bool *aDefaultAction)
  3408   nsCOMPtr<nsIDOMEvent> event;
  3409   nsCOMPtr<EventTarget> target;
  3410   nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble,
  3411                                   aCancelable, true, getter_AddRefs(event),
  3412                                   getter_AddRefs(target));
  3413   NS_ENSURE_SUCCESS(rv, rv);
  3415   NS_ASSERTION(aDoc, "GetEventAndTarget lied?");
  3416   if (!aDoc->GetWindow())
  3417     return NS_ERROR_INVALID_ARG;
  3419   EventTarget* piTarget = aDoc->GetWindow()->GetParentTarget();
  3420   if (!piTarget)
  3421     return NS_ERROR_INVALID_ARG;
  3423   nsEventStatus status = nsEventStatus_eIgnore;
  3424   rv = piTarget->DispatchDOMEvent(nullptr, event, nullptr, &status);
  3425   if (aDefaultAction) {
  3426     *aDefaultAction = (status != nsEventStatus_eConsumeNoDefault);
  3428   return rv;
  3431 /* static */
  3432 Element*
  3433 nsContentUtils::MatchElementId(nsIContent *aContent, const nsIAtom* aId)
  3435   for (nsIContent* cur = aContent;
  3436        cur;
  3437        cur = cur->GetNextNode(aContent)) {
  3438     if (aId == cur->GetID()) {
  3439       return cur->AsElement();
  3443   return nullptr;
  3446 /* static */
  3447 Element *
  3448 nsContentUtils::MatchElementId(nsIContent *aContent, const nsAString& aId)
  3450   NS_PRECONDITION(!aId.IsEmpty(), "Will match random elements");
  3452   // ID attrs are generally stored as atoms, so just atomize this up front
  3453   nsCOMPtr<nsIAtom> id(do_GetAtom(aId));
  3454   if (!id) {
  3455     // OOM, so just bail
  3456     return nullptr;
  3459   return MatchElementId(aContent, id);
  3462 // Convert the string from the given encoding to Unicode.
  3463 /* static */
  3464 nsresult
  3465 nsContentUtils::ConvertStringFromEncoding(const nsACString& aEncoding,
  3466                                           const nsACString& aInput,
  3467                                           nsAString& aOutput)
  3469   nsAutoCString encoding;
  3470   if (aEncoding.IsEmpty()) {
  3471     encoding.AssignLiteral("UTF-8");
  3472   } else {
  3473     encoding.Assign(aEncoding);
  3476   ErrorResult rv;
  3477   nsAutoPtr<TextDecoder> decoder(new TextDecoder());
  3478   decoder->InitWithEncoding(encoding, false);
  3480   decoder->Decode(aInput.BeginReading(), aInput.Length(), false,
  3481                   aOutput, rv);
  3482   return rv.ErrorCode();
  3485 /* static */
  3486 bool
  3487 nsContentUtils::CheckForBOM(const unsigned char* aBuffer, uint32_t aLength,
  3488                             nsACString& aCharset)
  3490   bool found = true;
  3491   aCharset.Truncate();
  3492   if (aLength >= 3 &&
  3493       aBuffer[0] == 0xEF &&
  3494       aBuffer[1] == 0xBB &&
  3495       aBuffer[2] == 0xBF) {
  3496     aCharset = "UTF-8";
  3498   else if (aLength >= 2 &&
  3499            aBuffer[0] == 0xFE && aBuffer[1] == 0xFF) {
  3500     aCharset = "UTF-16BE";
  3502   else if (aLength >= 2 &&
  3503            aBuffer[0] == 0xFF && aBuffer[1] == 0xFE) {
  3504     aCharset = "UTF-16LE";
  3505   } else {
  3506     found = false;
  3509   return found;
  3512 /* static */
  3513 void
  3514 nsContentUtils::RegisterShutdownObserver(nsIObserver* aObserver)
  3516   nsCOMPtr<nsIObserverService> observerService =
  3517     mozilla::services::GetObserverService();
  3518   if (observerService) {
  3519     observerService->AddObserver(aObserver, 
  3520                                  NS_XPCOM_SHUTDOWN_OBSERVER_ID, 
  3521                                  false);
  3525 /* static */
  3526 void
  3527 nsContentUtils::UnregisterShutdownObserver(nsIObserver* aObserver)
  3529   nsCOMPtr<nsIObserverService> observerService =
  3530     mozilla::services::GetObserverService();
  3531   if (observerService) {
  3532     observerService->RemoveObserver(aObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
  3536 /* static */
  3537 bool
  3538 nsContentUtils::HasNonEmptyAttr(const nsIContent* aContent, int32_t aNameSpaceID,
  3539                                 nsIAtom* aName)
  3541   static nsIContent::AttrValuesArray strings[] = {&nsGkAtoms::_empty, nullptr};
  3542   return aContent->FindAttrValueIn(aNameSpaceID, aName, strings, eCaseMatters)
  3543     == nsIContent::ATTR_VALUE_NO_MATCH;
  3546 /* static */
  3547 bool
  3548 nsContentUtils::HasMutationListeners(nsINode* aNode,
  3549                                      uint32_t aType,
  3550                                      nsINode* aTargetForSubtreeModified)
  3552   nsIDocument* doc = aNode->OwnerDoc();
  3554   // global object will be null for documents that don't have windows.
  3555   nsPIDOMWindow* window = doc->GetInnerWindow();
  3556   // This relies on EventListenerManager::AddEventListener, which sets
  3557   // all mutation bits when there is a listener for DOMSubtreeModified event.
  3558   if (window && !window->HasMutationListeners(aType)) {
  3559     return false;
  3562   if (aNode->IsNodeOfType(nsINode::eCONTENT) &&
  3563       static_cast<nsIContent*>(aNode)->ChromeOnlyAccess()) {
  3564     return false;
  3567   doc->MayDispatchMutationEvent(aTargetForSubtreeModified);
  3569   // If we have a window, we can check it for mutation listeners now.
  3570   if (aNode->IsInDoc()) {
  3571     nsCOMPtr<EventTarget> piTarget(do_QueryInterface(window));
  3572     if (piTarget) {
  3573       EventListenerManager* manager = piTarget->GetExistingListenerManager();
  3574       if (manager && manager->HasMutationListeners()) {
  3575         return true;
  3580   // If we have a window, we know a mutation listener is registered, but it
  3581   // might not be in our chain.  If we don't have a window, we might have a
  3582   // mutation listener.  Check quickly to see.
  3583   while (aNode) {
  3584     EventListenerManager* manager = aNode->GetExistingListenerManager();
  3585     if (manager && manager->HasMutationListeners()) {
  3586       return true;
  3589     if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
  3590       nsIContent* content = static_cast<nsIContent*>(aNode);
  3591       nsIContent* insertionParent = content->GetXBLInsertionParent();
  3592       if (insertionParent) {
  3593         aNode = insertionParent;
  3594         continue;
  3597     aNode = aNode->GetParentNode();
  3600   return false;
  3603 /* static */
  3604 bool
  3605 nsContentUtils::HasMutationListeners(nsIDocument* aDocument,
  3606                                      uint32_t aType)
  3608   nsPIDOMWindow* window = aDocument ?
  3609     aDocument->GetInnerWindow() : nullptr;
  3611   // This relies on EventListenerManager::AddEventListener, which sets
  3612   // all mutation bits when there is a listener for DOMSubtreeModified event.
  3613   return !window || window->HasMutationListeners(aType);
  3616 void
  3617 nsContentUtils::MaybeFireNodeRemoved(nsINode* aChild, nsINode* aParent,
  3618                                      nsIDocument* aOwnerDoc)
  3620   NS_PRECONDITION(aChild, "Missing child");
  3621   NS_PRECONDITION(aChild->GetParentNode() == aParent, "Wrong parent");
  3622   NS_PRECONDITION(aChild->OwnerDoc() == aOwnerDoc, "Wrong owner-doc");
  3624   // This checks that IsSafeToRunScript is true since we don't want to fire
  3625   // events when that is false. We can't rely on EventDispatcher to assert
  3626   // this in this situation since most of the time there are no mutation
  3627   // event listeners, in which case we won't even attempt to dispatch events.
  3628   // However this also allows for two exceptions. First off, we don't assert
  3629   // if the mutation happens to native anonymous content since we never fire
  3630   // mutation events on such content anyway.
  3631   // Second, we don't assert if sDOMNodeRemovedSuppressCount is true since
  3632   // that is a know case when we'd normally fire a mutation event, but can't
  3633   // make that safe and so we suppress it at this time. Ideally this should
  3634   // go away eventually.
  3635   NS_ASSERTION((aChild->IsNodeOfType(nsINode::eCONTENT) &&
  3636                static_cast<nsIContent*>(aChild)->
  3637                  IsInNativeAnonymousSubtree()) ||
  3638                IsSafeToRunScript() ||
  3639                sDOMNodeRemovedSuppressCount,
  3640                "Want to fire DOMNodeRemoved event, but it's not safe");
  3642   // Having an explicit check here since it's an easy mistake to fall into,
  3643   // and there might be existing code with problems. We'd rather be safe
  3644   // than fire DOMNodeRemoved in all corner cases. We also rely on it for
  3645   // nsAutoScriptBlockerSuppressNodeRemoved.
  3646   if (!IsSafeToRunScript()) {
  3647     return;
  3650   if (HasMutationListeners(aChild,
  3651         NS_EVENT_BITS_MUTATION_NODEREMOVED, aParent)) {
  3652     InternalMutationEvent mutation(true, NS_MUTATION_NODEREMOVED);
  3653     mutation.mRelatedNode = do_QueryInterface(aParent);
  3655     mozAutoSubtreeModified subtree(aOwnerDoc, aParent);
  3656     EventDispatcher::Dispatch(aChild, nullptr, &mutation);
  3660 PLDHashOperator
  3661 ListenerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aEntry,
  3662                    uint32_t aNumber, void* aArg)
  3664   EventListenerManagerMapEntry* entry =
  3665     static_cast<EventListenerManagerMapEntry*>(aEntry);
  3666   if (entry) {
  3667     nsINode* n = static_cast<nsINode*>(entry->mListenerManager->GetTarget());
  3668     if (n && n->IsInDoc() &&
  3669         nsCCUncollectableMarker::InGeneration(n->OwnerDoc()->GetMarkedCCGeneration())) {
  3670       entry->mListenerManager->MarkForCC();
  3673   return PL_DHASH_NEXT;
  3676 void
  3677 nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(uint32_t aGeneration)
  3679   if (sEventListenerManagersHash.ops) {
  3680     PL_DHashTableEnumerate(&sEventListenerManagersHash, ListenerEnumerator,
  3681                            &aGeneration);
  3685 /* static */
  3686 void
  3687 nsContentUtils::TraverseListenerManager(nsINode *aNode,
  3688                                         nsCycleCollectionTraversalCallback &cb)
  3690   if (!sEventListenerManagersHash.ops) {
  3691     // We're already shut down, just return.
  3692     return;
  3695   EventListenerManagerMapEntry *entry =
  3696     static_cast<EventListenerManagerMapEntry *>
  3697                (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
  3698                                         PL_DHASH_LOOKUP));
  3699   if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
  3700     CycleCollectionNoteChild(cb, entry->mListenerManager.get(),
  3701                              "[via hash] mListenerManager");
  3705 EventListenerManager*
  3706 nsContentUtils::GetListenerManagerForNode(nsINode *aNode)
  3708   if (!sEventListenerManagersHash.ops) {
  3709     // We're already shut down, don't bother creating an event listener
  3710     // manager.
  3712     return nullptr;
  3715   EventListenerManagerMapEntry *entry =
  3716     static_cast<EventListenerManagerMapEntry *>
  3717                (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
  3718                                         PL_DHASH_ADD));
  3720   if (!entry) {
  3721     return nullptr;
  3724   if (!entry->mListenerManager) {
  3725     entry->mListenerManager = new EventListenerManager(aNode);
  3727     aNode->SetFlags(NODE_HAS_LISTENERMANAGER);
  3730   return entry->mListenerManager;
  3733 EventListenerManager*
  3734 nsContentUtils::GetExistingListenerManagerForNode(const nsINode *aNode)
  3736   if (!aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) {
  3737     return nullptr;
  3740   if (!sEventListenerManagersHash.ops) {
  3741     // We're already shut down, don't bother creating an event listener
  3742     // manager.
  3744     return nullptr;
  3747   EventListenerManagerMapEntry *entry =
  3748     static_cast<EventListenerManagerMapEntry *>
  3749                (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
  3750                                         PL_DHASH_LOOKUP));
  3751   if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
  3752     return entry->mListenerManager;
  3755   return nullptr;
  3758 /* static */
  3759 void
  3760 nsContentUtils::RemoveListenerManager(nsINode *aNode)
  3762   if (sEventListenerManagersHash.ops) {
  3763     EventListenerManagerMapEntry *entry =
  3764       static_cast<EventListenerManagerMapEntry *>
  3765                  (PL_DHashTableOperate(&sEventListenerManagersHash, aNode,
  3766                                           PL_DHASH_LOOKUP));
  3767     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
  3768       nsRefPtr<EventListenerManager> listenerManager;
  3769       listenerManager.swap(entry->mListenerManager);
  3770       // Remove the entry and *then* do operations that could cause further
  3771       // modification of sEventListenerManagersHash.  See bug 334177.
  3772       PL_DHashTableRawRemove(&sEventListenerManagersHash, entry);
  3773       if (listenerManager) {
  3774         listenerManager->Disconnect();
  3780 /* static */
  3781 bool
  3782 nsContentUtils::IsValidNodeName(nsIAtom *aLocalName, nsIAtom *aPrefix,
  3783                                 int32_t aNamespaceID)
  3785   if (aNamespaceID == kNameSpaceID_Unknown) {
  3786     return false;
  3789   if (!aPrefix) {
  3790     // If the prefix is null, then either the QName must be xmlns or the
  3791     // namespace must not be XMLNS.
  3792     return (aLocalName == nsGkAtoms::xmlns) ==
  3793            (aNamespaceID == kNameSpaceID_XMLNS);
  3796   // If the prefix is non-null then the namespace must not be null.
  3797   if (aNamespaceID == kNameSpaceID_None) {
  3798     return false;
  3801   // If the namespace is the XMLNS namespace then the prefix must be xmlns,
  3802   // but the localname must not be xmlns.
  3803   if (aNamespaceID == kNameSpaceID_XMLNS) {
  3804     return aPrefix == nsGkAtoms::xmlns && aLocalName != nsGkAtoms::xmlns;
  3807   // If the namespace is not the XMLNS namespace then the prefix must not be
  3808   // xmlns.
  3809   // If the namespace is the XML namespace then the prefix can be anything.
  3810   // If the namespace is not the XML namespace then the prefix must not be xml.
  3811   return aPrefix != nsGkAtoms::xmlns &&
  3812          (aNamespaceID == kNameSpaceID_XML || aPrefix != nsGkAtoms::xml);
  3815 /* static */
  3816 nsresult
  3817 nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
  3818                                          const nsAString& aFragment,
  3819                                          bool aPreventScriptExecution,
  3820                                          nsIDOMDocumentFragment** aReturn)
  3822   ErrorResult rv;
  3823   *aReturn = CreateContextualFragment(aContextNode, aFragment,
  3824                                       aPreventScriptExecution, rv).take();
  3825   return rv.ErrorCode();
  3828 already_AddRefed<DocumentFragment>
  3829 nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
  3830                                          const nsAString& aFragment,
  3831                                          bool aPreventScriptExecution,
  3832                                          ErrorResult& aRv)
  3834   if (!aContextNode) {
  3835     aRv.Throw(NS_ERROR_INVALID_ARG);
  3836     return nullptr;
  3839   // If we don't have a document here, we can't get the right security context
  3840   // for compiling event handlers... so just bail out.
  3841   nsCOMPtr<nsIDocument> document = aContextNode->OwnerDoc();
  3842   bool isHTML = document->IsHTML();
  3843 #ifdef DEBUG
  3844   nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(document);
  3845   NS_ASSERTION(!isHTML || htmlDoc, "Should have HTMLDocument here!");
  3846 #endif
  3848   if (isHTML) {
  3849     nsRefPtr<DocumentFragment> frag =
  3850       new DocumentFragment(document->NodeInfoManager());
  3852     nsCOMPtr<nsIContent> contextAsContent = do_QueryInterface(aContextNode);
  3853     if (contextAsContent && !contextAsContent->IsElement()) {
  3854       contextAsContent = contextAsContent->GetParent();
  3855       if (contextAsContent && !contextAsContent->IsElement()) {
  3856         // can this even happen?
  3857         contextAsContent = nullptr;
  3861     if (contextAsContent && !contextAsContent->IsHTML(nsGkAtoms::html)) {
  3862       aRv = ParseFragmentHTML(aFragment, frag,
  3863                               contextAsContent->Tag(),
  3864                               contextAsContent->GetNameSpaceID(),
  3865                               (document->GetCompatibilityMode() ==
  3866                                eCompatibility_NavQuirks),
  3867                               aPreventScriptExecution);
  3868     } else {
  3869       aRv = ParseFragmentHTML(aFragment, frag,
  3870                               nsGkAtoms::body,
  3871                               kNameSpaceID_XHTML,
  3872                               (document->GetCompatibilityMode() ==
  3873                                eCompatibility_NavQuirks),
  3874                               aPreventScriptExecution);
  3877     return frag.forget();
  3880   nsAutoTArray<nsString, 32> tagStack;
  3881   nsAutoString uriStr, nameStr;
  3882   nsCOMPtr<nsIContent> content = do_QueryInterface(aContextNode);
  3883   // just in case we have a text node
  3884   if (content && !content->IsElement())
  3885     content = content->GetParent();
  3887   while (content && content->IsElement()) {
  3888     nsString& tagName = *tagStack.AppendElement();
  3889     if (!&tagName) {
  3890       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
  3891       return nullptr;
  3894     tagName = content->NodeInfo()->QualifiedName();
  3896     // see if we need to add xmlns declarations
  3897     uint32_t count = content->GetAttrCount();
  3898     bool setDefaultNamespace = false;
  3899     if (count > 0) {
  3900       uint32_t index;
  3902       for (index = 0; index < count; index++) {
  3903         const nsAttrName* name = content->GetAttrNameAt(index);
  3904         if (name->NamespaceEquals(kNameSpaceID_XMLNS)) {
  3905           content->GetAttr(kNameSpaceID_XMLNS, name->LocalName(), uriStr);
  3907           // really want something like nsXMLContentSerializer::SerializeAttr
  3908           tagName.Append(NS_LITERAL_STRING(" xmlns")); // space important
  3909           if (name->GetPrefix()) {
  3910             tagName.Append(char16_t(':'));
  3911             name->LocalName()->ToString(nameStr);
  3912             tagName.Append(nameStr);
  3913           } else {
  3914             setDefaultNamespace = true;
  3916           tagName.Append(NS_LITERAL_STRING("=\"") + uriStr +
  3917             NS_LITERAL_STRING("\""));
  3922     if (!setDefaultNamespace) {
  3923       nsINodeInfo* info = content->NodeInfo();
  3924       if (!info->GetPrefixAtom() &&
  3925           info->NamespaceID() != kNameSpaceID_None) {
  3926         // We have no namespace prefix, but have a namespace ID.  Push
  3927         // default namespace attr in, so that our kids will be in our
  3928         // namespace.
  3929         info->GetNamespaceURI(uriStr);
  3930         tagName.Append(NS_LITERAL_STRING(" xmlns=\"") + uriStr +
  3931                        NS_LITERAL_STRING("\""));
  3935     content = content->GetParent();
  3938   nsCOMPtr<nsIDOMDocumentFragment> frag;
  3939   aRv = ParseFragmentXML(aFragment, document, tagStack,
  3940                          aPreventScriptExecution, getter_AddRefs(frag));
  3941   return frag.forget().downcast<DocumentFragment>();
  3944 /* static */
  3945 void
  3946 nsContentUtils::DropFragmentParsers()
  3948   NS_IF_RELEASE(sHTMLFragmentParser);
  3949   NS_IF_RELEASE(sXMLFragmentParser);
  3950   NS_IF_RELEASE(sXMLFragmentSink);
  3953 /* static */
  3954 void
  3955 nsContentUtils::XPCOMShutdown()
  3957   nsContentUtils::DropFragmentParsers();
  3960 /* static */
  3961 nsresult
  3962 nsContentUtils::ParseFragmentHTML(const nsAString& aSourceBuffer,
  3963                                   nsIContent* aTargetNode,
  3964                                   nsIAtom* aContextLocalName,
  3965                                   int32_t aContextNamespace,
  3966                                   bool aQuirks,
  3967                                   bool aPreventScriptExecution)
  3969   if (nsContentUtils::sFragmentParsingActive) {
  3970     NS_NOTREACHED("Re-entrant fragment parsing attempted.");
  3971     return NS_ERROR_DOM_INVALID_STATE_ERR;
  3973   mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
  3974   nsContentUtils::sFragmentParsingActive = true;
  3975   if (!sHTMLFragmentParser) {
  3976     NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
  3977     // Now sHTMLFragmentParser owns the object
  3979   nsresult rv =
  3980     sHTMLFragmentParser->ParseFragment(aSourceBuffer,
  3981                                        aTargetNode,
  3982                                        aContextLocalName,
  3983                                        aContextNamespace,
  3984                                        aQuirks,
  3985                                        aPreventScriptExecution);
  3986   return rv;
  3989 /* static */
  3990 nsresult
  3991 nsContentUtils::ParseDocumentHTML(const nsAString& aSourceBuffer,
  3992                                   nsIDocument* aTargetDocument,
  3993                                   bool aScriptingEnabledForNoscriptParsing)
  3995   if (nsContentUtils::sFragmentParsingActive) {
  3996     NS_NOTREACHED("Re-entrant fragment parsing attempted.");
  3997     return NS_ERROR_DOM_INVALID_STATE_ERR;
  3999   mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
  4000   nsContentUtils::sFragmentParsingActive = true;
  4001   if (!sHTMLFragmentParser) {
  4002     NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
  4003     // Now sHTMLFragmentParser owns the object
  4005   nsresult rv =
  4006     sHTMLFragmentParser->ParseDocument(aSourceBuffer,
  4007                                        aTargetDocument,
  4008                                        aScriptingEnabledForNoscriptParsing);
  4009   return rv;
  4012 /* static */
  4013 nsresult
  4014 nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
  4015                                  nsIDocument* aDocument,
  4016                                  nsTArray<nsString>& aTagStack,
  4017                                  bool aPreventScriptExecution,
  4018                                  nsIDOMDocumentFragment** aReturn)
  4020   if (nsContentUtils::sFragmentParsingActive) {
  4021     NS_NOTREACHED("Re-entrant fragment parsing attempted.");
  4022     return NS_ERROR_DOM_INVALID_STATE_ERR;
  4024   mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
  4025   nsContentUtils::sFragmentParsingActive = true;
  4026   if (!sXMLFragmentParser) {
  4027     nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID);
  4028     parser.forget(&sXMLFragmentParser);
  4029     // sXMLFragmentParser now owns the parser
  4031   if (!sXMLFragmentSink) {
  4032     NS_NewXMLFragmentContentSink(&sXMLFragmentSink);
  4033     // sXMLFragmentSink now owns the sink
  4035   nsCOMPtr<nsIContentSink> contentsink = do_QueryInterface(sXMLFragmentSink);
  4036   NS_ABORT_IF_FALSE(contentsink, "Sink doesn't QI to nsIContentSink!");
  4037   sXMLFragmentParser->SetContentSink(contentsink);
  4039   sXMLFragmentSink->SetTargetDocument(aDocument);
  4040   sXMLFragmentSink->SetPreventScriptExecution(aPreventScriptExecution);
  4042   nsresult rv =
  4043     sXMLFragmentParser->ParseFragment(aSourceBuffer,
  4044                                       aTagStack);
  4045   if (NS_FAILED(rv)) {
  4046     // Drop the fragment parser and sink that might be in an inconsistent state
  4047     NS_IF_RELEASE(sXMLFragmentParser);
  4048     NS_IF_RELEASE(sXMLFragmentSink);
  4049     return rv;
  4052   rv = sXMLFragmentSink->FinishFragmentParsing(aReturn);
  4054   sXMLFragmentParser->Reset();
  4056   return rv;
  4059 /* static */
  4060 nsresult
  4061 nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer,
  4062                                    nsAString& aResultBuffer,
  4063                                    uint32_t aFlags,
  4064                                    uint32_t aWrapCol)
  4066   nsCOMPtr<nsIURI> uri;
  4067   NS_NewURI(getter_AddRefs(uri), "about:blank");
  4068   nsCOMPtr<nsIPrincipal> principal =
  4069     do_CreateInstance(NS_NULLPRINCIPAL_CONTRACTID);
  4070   nsCOMPtr<nsIDOMDocument> domDocument;
  4071   nsresult rv = NS_NewDOMDocument(getter_AddRefs(domDocument),
  4072                                   EmptyString(),
  4073                                   EmptyString(),
  4074                                   nullptr,
  4075                                   uri,
  4076                                   uri,
  4077                                   principal,
  4078                                   true,
  4079                                   nullptr,
  4080                                   DocumentFlavorHTML);
  4081   NS_ENSURE_SUCCESS(rv, rv);
  4083   nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
  4084   rv = nsContentUtils::ParseDocumentHTML(aSourceBuffer, document,
  4085     !(aFlags & nsIDocumentEncoder::OutputNoScriptContent));
  4086   NS_ENSURE_SUCCESS(rv, rv);
  4088   nsCOMPtr<nsIDocumentEncoder> encoder = do_CreateInstance(
  4089     "@mozilla.org/layout/documentEncoder;1?type=text/plain");
  4091   rv = encoder->Init(domDocument, NS_LITERAL_STRING("text/plain"), aFlags);
  4092   NS_ENSURE_SUCCESS(rv, rv);
  4094   encoder->SetWrapColumn(aWrapCol);
  4096   return encoder->EncodeToString(aResultBuffer);
  4099 /* static */
  4100 nsresult
  4101 nsContentUtils::SetNodeTextContent(nsIContent* aContent,
  4102                                    const nsAString& aValue,
  4103                                    bool aTryReuse)
  4105   // Fire DOMNodeRemoved mutation events before we do anything else.
  4106   nsCOMPtr<nsIContent> owningContent;
  4108   // Batch possible DOMSubtreeModified events.
  4109   mozAutoSubtreeModified subtree(nullptr, nullptr);
  4111   // Scope firing mutation events so that we don't carry any state that
  4112   // might be stale
  4114     // We're relying on mozAutoSubtreeModified to keep a strong reference if
  4115     // needed.
  4116     nsIDocument* doc = aContent->OwnerDoc();
  4118     // Optimize the common case of there being no observers
  4119     if (HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED)) {
  4120       subtree.UpdateTarget(doc, nullptr);
  4121       owningContent = aContent;
  4122       nsCOMPtr<nsINode> child;
  4123       bool skipFirst = aTryReuse;
  4124       for (child = aContent->GetFirstChild();
  4125            child && child->GetParentNode() == aContent;
  4126            child = child->GetNextSibling()) {
  4127         if (skipFirst && child->IsNodeOfType(nsINode::eTEXT)) {
  4128           skipFirst = false;
  4129           continue;
  4131         nsContentUtils::MaybeFireNodeRemoved(child, aContent, doc);
  4136   // Might as well stick a batch around this since we're performing several
  4137   // mutations.
  4138   mozAutoDocUpdate updateBatch(aContent->GetCurrentDoc(),
  4139     UPDATE_CONTENT_MODEL, true);
  4140   nsAutoMutationBatch mb;
  4142   uint32_t childCount = aContent->GetChildCount();
  4144   if (aTryReuse && !aValue.IsEmpty()) {
  4145     uint32_t removeIndex = 0;
  4147     for (uint32_t i = 0; i < childCount; ++i) {
  4148       nsIContent* child = aContent->GetChildAt(removeIndex);
  4149       if (removeIndex == 0 && child && child->IsNodeOfType(nsINode::eTEXT)) {
  4150         nsresult rv = child->SetText(aValue, true);
  4151         NS_ENSURE_SUCCESS(rv, rv);
  4153         removeIndex = 1;
  4155       else {
  4156         aContent->RemoveChildAt(removeIndex, true);
  4160     if (removeIndex == 1) {
  4161       return NS_OK;
  4164   else {
  4165     mb.Init(aContent, true, false);
  4166     for (uint32_t i = 0; i < childCount; ++i) {
  4167       aContent->RemoveChildAt(0, true);
  4170   mb.RemovalDone();
  4172   if (aValue.IsEmpty()) {
  4173     return NS_OK;
  4176   nsRefPtr<nsTextNode> textContent =
  4177     new nsTextNode(aContent->NodeInfo()->NodeInfoManager());
  4179   textContent->SetText(aValue, true);
  4181   nsresult rv = aContent->AppendChildTo(textContent, true);
  4182   mb.NodesAdded();
  4183   return rv;
  4186 static bool
  4187 AppendNodeTextContentsRecurse(nsINode* aNode, nsAString& aResult,
  4188                               const mozilla::fallible_t&)
  4190   for (nsIContent* child = aNode->GetFirstChild();
  4191        child;
  4192        child = child->GetNextSibling()) {
  4193     if (child->IsElement()) {
  4194       bool ok = AppendNodeTextContentsRecurse(child, aResult,
  4195                                               mozilla::fallible_t());
  4196       if (!ok) {
  4197         return false;
  4200     else if (child->IsNodeOfType(nsINode::eTEXT)) {
  4201       bool ok = child->AppendTextTo(aResult, mozilla::fallible_t());
  4202       if (!ok) {
  4203         return false;
  4208   return true;
  4211 /* static */
  4212 bool
  4213 nsContentUtils::AppendNodeTextContent(nsINode* aNode, bool aDeep,
  4214                                       nsAString& aResult,
  4215                                       const mozilla::fallible_t&)
  4217   if (aNode->IsNodeOfType(nsINode::eTEXT)) {
  4218     return static_cast<nsIContent*>(aNode)->AppendTextTo(aResult,
  4219                                                          mozilla::fallible_t());
  4221   else if (aDeep) {
  4222     return AppendNodeTextContentsRecurse(aNode, aResult, mozilla::fallible_t());
  4224   else {
  4225     for (nsIContent* child = aNode->GetFirstChild();
  4226          child;
  4227          child = child->GetNextSibling()) {
  4228       if (child->IsNodeOfType(nsINode::eTEXT)) {
  4229         bool ok = child->AppendTextTo(aResult, mozilla::fallible_t());
  4230         if (!ok) {
  4231             return false;
  4237   return true;
  4240 bool
  4241 nsContentUtils::HasNonEmptyTextContent(nsINode* aNode)
  4243   for (nsIContent* child = aNode->GetFirstChild();
  4244        child;
  4245        child = child->GetNextSibling()) {
  4246     if (child->IsNodeOfType(nsINode::eTEXT) &&
  4247         child->TextLength() > 0) {
  4248       return true;
  4252   return false;
  4255 /* static */
  4256 bool
  4257 nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode,
  4258                                       const nsIContent* aContent)
  4260   NS_PRECONDITION(aNode,
  4261                   "Must have a node to work with");
  4262   NS_PRECONDITION(aContent,
  4263                   "Must have a content to work with");
  4265   if (!aNode->IsNodeOfType(nsINode::eCONTENT)) {
  4266     /**
  4267      * The root isn't an nsIContent, so it's a document or attribute.  The only
  4268      * nodes in the same anonymous subtree as it will have a null
  4269      * bindingParent.
  4271      * XXXbz strictly speaking, that's not true for attribute nodes.
  4272      */
  4273     return aContent->GetBindingParent() == nullptr;
  4276   const nsIContent* nodeAsContent = static_cast<const nsIContent*>(aNode);
  4278   // For nodes in a shadow tree, it is insufficient to simply compare
  4279   // the binding parent because a node may host multiple ShadowRoots,
  4280   // thus nodes in different shadow tree may have the same binding parent.
  4281   if (aNode->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
  4282     return nodeAsContent->GetContainingShadow() ==
  4283       aContent->GetContainingShadow();
  4286   return nodeAsContent->GetBindingParent() == aContent->GetBindingParent();
  4289 class AnonymousContentDestroyer : public nsRunnable {
  4290 public:
  4291   AnonymousContentDestroyer(nsCOMPtr<nsIContent>* aContent) {
  4292     mContent.swap(*aContent);
  4293     mParent = mContent->GetParent();
  4294     mDoc = mContent->OwnerDoc();
  4296   AnonymousContentDestroyer(nsCOMPtr<Element>* aElement) {
  4297     mContent = aElement->forget();
  4298     mParent = mContent->GetParent();
  4299     mDoc = mContent->OwnerDoc();
  4301   NS_IMETHOD Run() {
  4302     mContent->UnbindFromTree();
  4303     return NS_OK;
  4305 private:
  4306   nsCOMPtr<nsIContent> mContent;
  4307   // Hold strong refs to the parent content and document so that they
  4308   // don't die unexpectedly
  4309   nsCOMPtr<nsIDocument> mDoc;
  4310   nsCOMPtr<nsIContent> mParent;
  4311 };
  4313 /* static */
  4314 void
  4315 nsContentUtils::DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent)
  4317   if (*aContent) {
  4318     AddScriptRunner(new AnonymousContentDestroyer(aContent));
  4322 /* static */
  4323 void
  4324 nsContentUtils::DestroyAnonymousContent(nsCOMPtr<Element>* aElement)
  4326   if (*aElement) {
  4327     AddScriptRunner(new AnonymousContentDestroyer(aElement));
  4331 /* static */
  4332 void
  4333 nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling)
  4335   IMEStateManager::OnInstalledMenuKeyboardListener(aInstalling);
  4338 static bool SchemeIs(nsIURI* aURI, const char* aScheme)
  4340   nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
  4341   NS_ENSURE_TRUE(baseURI, false);
  4343   bool isScheme = false;
  4344   return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme;
  4347 /* static */
  4348 nsresult
  4349 nsContentUtils::CheckSecurityBeforeLoad(nsIURI* aURIToLoad,
  4350                                         nsIPrincipal* aLoadingPrincipal,
  4351                                         uint32_t aCheckLoadFlags,
  4352                                         bool aAllowData,
  4353                                         uint32_t aContentPolicyType,
  4354                                         nsISupports* aContext,
  4355                                         const nsAFlatCString& aMimeGuess,
  4356                                         nsISupports* aExtra)
  4358   NS_PRECONDITION(aLoadingPrincipal, "Must have a loading principal here");
  4360   bool isSystemPrin = false;
  4361   if (NS_SUCCEEDED(sSecurityManager->IsSystemPrincipal(aLoadingPrincipal,
  4362                                                        &isSystemPrin)) &&
  4363       isSystemPrin) {
  4364     return NS_OK;
  4367   // XXXbz do we want to fast-path skin stylesheets loading XBL here somehow?
  4368   // CheckLoadURIWithPrincipal
  4369   nsresult rv = sSecurityManager->
  4370     CheckLoadURIWithPrincipal(aLoadingPrincipal, aURIToLoad, aCheckLoadFlags);
  4371   NS_ENSURE_SUCCESS(rv, rv);
  4373   // Content Policy
  4374   int16_t shouldLoad = nsIContentPolicy::ACCEPT;
  4375   rv = NS_CheckContentLoadPolicy(aContentPolicyType,
  4376                                  aURIToLoad,
  4377                                  aLoadingPrincipal,
  4378                                  aContext,
  4379                                  aMimeGuess,
  4380                                  aExtra,
  4381                                  &shouldLoad,
  4382                                  GetContentPolicy(),
  4383                                  sSecurityManager);
  4384   NS_ENSURE_SUCCESS(rv, rv);
  4385   if (NS_CP_REJECTED(shouldLoad)) {
  4386     return NS_ERROR_CONTENT_BLOCKED;
  4389   // Same Origin
  4390   if ((aAllowData && SchemeIs(aURIToLoad, "data")) ||
  4391       ((aCheckLoadFlags & nsIScriptSecurityManager::ALLOW_CHROME) &&
  4392        SchemeIs(aURIToLoad, "chrome"))) {
  4393     return NS_OK;
  4396   return aLoadingPrincipal->CheckMayLoad(aURIToLoad, true, false);
  4399 bool
  4400 nsContentUtils::IsSystemPrincipal(nsIPrincipal* aPrincipal)
  4402   bool isSystem;
  4403   nsresult rv = sSecurityManager->IsSystemPrincipal(aPrincipal, &isSystem);
  4404   return NS_SUCCEEDED(rv) && isSystem;
  4407 bool
  4408 nsContentUtils::IsExpandedPrincipal(nsIPrincipal* aPrincipal)
  4410   nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal);
  4411   return !!ep;
  4414 nsIPrincipal*
  4415 nsContentUtils::GetSystemPrincipal()
  4417   nsCOMPtr<nsIPrincipal> sysPrin;
  4418   DebugOnly<nsresult> rv =
  4419     sSecurityManager->GetSystemPrincipal(getter_AddRefs(sysPrin));
  4420   MOZ_ASSERT(NS_SUCCEEDED(rv) && sysPrin);
  4421   return sysPrin;
  4424 bool
  4425 nsContentUtils::CombineResourcePrincipals(nsCOMPtr<nsIPrincipal>* aResourcePrincipal,
  4426                                           nsIPrincipal* aExtraPrincipal)
  4428   if (!aExtraPrincipal) {
  4429     return false;
  4431   if (!*aResourcePrincipal) {
  4432     *aResourcePrincipal = aExtraPrincipal;
  4433     return true;
  4435   if (*aResourcePrincipal == aExtraPrincipal) {
  4436     return false;
  4438   bool subsumes;
  4439   if (NS_SUCCEEDED((*aResourcePrincipal)->Subsumes(aExtraPrincipal, &subsumes)) &&
  4440       subsumes) {
  4441     return false;
  4443   sSecurityManager->GetSystemPrincipal(getter_AddRefs(*aResourcePrincipal));
  4444   return true;
  4447 /* static */
  4448 void
  4449 nsContentUtils::TriggerLink(nsIContent *aContent, nsPresContext *aPresContext,
  4450                             nsIURI *aLinkURI, const nsString &aTargetSpec,
  4451                             bool aClick, bool aIsUserTriggered,
  4452                             bool aIsTrusted)
  4454   NS_ASSERTION(aPresContext, "Need a nsPresContext");
  4455   NS_PRECONDITION(aLinkURI, "No link URI");
  4457   if (aContent->IsEditable()) {
  4458     return;
  4461   nsILinkHandler *handler = aPresContext->GetLinkHandler();
  4462   if (!handler) {
  4463     return;
  4466   if (!aClick) {
  4467     handler->OnOverLink(aContent, aLinkURI, aTargetSpec.get());
  4468     return;
  4471   // Check that this page is allowed to load this URI.
  4472   nsresult proceed = NS_OK;
  4474   if (sSecurityManager) {
  4475     uint32_t flag =
  4476       aIsUserTriggered ?
  4477       (uint32_t)nsIScriptSecurityManager::STANDARD :
  4478       (uint32_t)nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT;
  4479     proceed =
  4480       sSecurityManager->CheckLoadURIWithPrincipal(aContent->NodePrincipal(),
  4481                                                   aLinkURI, flag);
  4484   // Only pass off the click event if the script security manager says it's ok.
  4485   // We need to rest aTargetSpec for forced downloads.
  4486   if (NS_SUCCEEDED(proceed)) {
  4488     // A link/area element with a download attribute is allowed to set
  4489     // a pseudo Content-Disposition header.
  4490     // For security reasons we only allow websites to declare same-origin resources
  4491     // as downloadable. If this check fails we will just do the normal thing
  4492     // (i.e. navigate to the resource).
  4493     nsAutoString fileName;
  4494     if ((!aContent->IsHTML(nsGkAtoms::a) && !aContent->IsHTML(nsGkAtoms::area) &&
  4495          !aContent->IsSVG(nsGkAtoms::a)) ||
  4496         !aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::download, fileName) ||
  4497         NS_FAILED(aContent->NodePrincipal()->CheckMayLoad(aLinkURI, false, true))) {
  4498       fileName.SetIsVoid(true); // No actionable download attribute was found.
  4501     handler->OnLinkClick(aContent, aLinkURI,
  4502                          fileName.IsVoid() ? aTargetSpec.get() : EmptyString().get(),
  4503                          fileName, nullptr, nullptr, aIsTrusted);
  4507 /* static */
  4508 void
  4509 nsContentUtils::GetLinkLocation(Element* aElement, nsString& aLocationString)
  4511   nsCOMPtr<nsIURI> hrefURI = aElement->GetHrefURI();
  4512   if (hrefURI) {
  4513     nsAutoCString specUTF8;
  4514     nsresult rv = hrefURI->GetSpec(specUTF8);
  4515     if (NS_SUCCEEDED(rv))
  4516       CopyUTF8toUTF16(specUTF8, aLocationString);
  4520 /* static */
  4521 nsIWidget*
  4522 nsContentUtils::GetTopLevelWidget(nsIWidget* aWidget)
  4524   if (!aWidget)
  4525     return nullptr;
  4527   return aWidget->GetTopLevelWidget();
  4530 /* static */
  4531 const nsDependentString
  4532 nsContentUtils::GetLocalizedEllipsis()
  4534   static char16_t sBuf[4] = { 0, 0, 0, 0 };
  4535   if (!sBuf[0]) {
  4536     nsAdoptingString tmp = Preferences::GetLocalizedString("intl.ellipsis");
  4537     uint32_t len = std::min(uint32_t(tmp.Length()),
  4538                           uint32_t(ArrayLength(sBuf) - 1));
  4539     CopyUnicodeTo(tmp, 0, sBuf, len);
  4540     if (!sBuf[0])
  4541       sBuf[0] = char16_t(0x2026);
  4543   return nsDependentString(sBuf);
  4546 static bool
  4547 HasASCIIDigit(const nsTArray<nsShortcutCandidate>& aCandidates)
  4549   for (uint32_t i = 0; i < aCandidates.Length(); ++i) {
  4550     uint32_t ch = aCandidates[i].mCharCode;
  4551     if (ch >= '0' && ch <= '9')
  4552       return true;
  4554   return false;
  4557 static bool
  4558 CharsCaseInsensitiveEqual(uint32_t aChar1, uint32_t aChar2)
  4560   return aChar1 == aChar2 ||
  4561          (IS_IN_BMP(aChar1) && IS_IN_BMP(aChar2) &&
  4562           ToLowerCase(char16_t(aChar1)) == ToLowerCase(char16_t(aChar2)));
  4565 static bool
  4566 IsCaseChangeableChar(uint32_t aChar)
  4568   return IS_IN_BMP(aChar) &&
  4569          ToLowerCase(char16_t(aChar)) != ToUpperCase(char16_t(aChar));
  4572 /* static */
  4573 void
  4574 nsContentUtils::GetAccelKeyCandidates(nsIDOMKeyEvent* aDOMKeyEvent,
  4575                   nsTArray<nsShortcutCandidate>& aCandidates)
  4577   NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
  4579   nsAutoString eventType;
  4580   aDOMKeyEvent->GetType(eventType);
  4581   // Don't process if aDOMKeyEvent is not a keypress event.
  4582   if (!eventType.EqualsLiteral("keypress"))
  4583     return;
  4585   WidgetKeyboardEvent* nativeKeyEvent =
  4586     aDOMKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
  4587   if (nativeKeyEvent) {
  4588     NS_ASSERTION(nativeKeyEvent->eventStructType == NS_KEY_EVENT,
  4589                  "wrong type of native event");
  4590     // nsShortcutCandidate::mCharCode is a candidate charCode.
  4591     // nsShoftcutCandidate::mIgnoreShift means the mCharCode should be tried to
  4592     // execute a command with/without shift key state. If this is TRUE, the
  4593     // shifted key state should be ignored. Otherwise, don't ignore the state.
  4594     // the priority of the charCodes are (shift key is not pressed):
  4595     //   0: charCode/false,
  4596     //   1: unshiftedCharCodes[0]/false, 2: unshiftedCharCodes[1]/false...
  4597     // the priority of the charCodes are (shift key is pressed):
  4598     //   0: charCode/false,
  4599     //   1: shiftedCharCodes[0]/false, 2: shiftedCharCodes[0]/true,
  4600     //   3: shiftedCharCodes[1]/false, 4: shiftedCharCodes[1]/true...
  4601     if (nativeKeyEvent->charCode) {
  4602       nsShortcutCandidate key(nativeKeyEvent->charCode, false);
  4603       aCandidates.AppendElement(key);
  4606     uint32_t len = nativeKeyEvent->alternativeCharCodes.Length();
  4607     if (!nativeKeyEvent->IsShift()) {
  4608       for (uint32_t i = 0; i < len; ++i) {
  4609         uint32_t ch =
  4610           nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode;
  4611         if (!ch || ch == nativeKeyEvent->charCode)
  4612           continue;
  4614         nsShortcutCandidate key(ch, false);
  4615         aCandidates.AppendElement(key);
  4617       // If unshiftedCharCodes doesn't have numeric but shiftedCharCode has it,
  4618       // this keyboard layout is AZERTY or similar layout, probably.
  4619       // In this case, Accel+[0-9] should be accessible without shift key.
  4620       // However, the priority should be lowest.
  4621       if (!HasASCIIDigit(aCandidates)) {
  4622         for (uint32_t i = 0; i < len; ++i) {
  4623           uint32_t ch =
  4624             nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode;
  4625           if (ch >= '0' && ch <= '9') {
  4626             nsShortcutCandidate key(ch, false);
  4627             aCandidates.AppendElement(key);
  4628             break;
  4632     } else {
  4633       for (uint32_t i = 0; i < len; ++i) {
  4634         uint32_t ch = nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode;
  4635         if (!ch)
  4636           continue;
  4638         if (ch != nativeKeyEvent->charCode) {
  4639           nsShortcutCandidate key(ch, false);
  4640           aCandidates.AppendElement(key);
  4643         // If the char is an alphabet, the shift key state should not be
  4644         // ignored. E.g., Ctrl+Shift+C should not execute Ctrl+C.
  4646         // And checking the charCode is same as unshiftedCharCode too.
  4647         // E.g., for Ctrl+Shift+(Plus of Numpad) should not run Ctrl+Plus.
  4648         uint32_t unshiftCh =
  4649           nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode;
  4650         if (CharsCaseInsensitiveEqual(ch, unshiftCh))
  4651           continue;
  4653         // On the Hebrew keyboard layout on Windows, the unshifted char is a
  4654         // localized character but the shifted char is a Latin alphabet,
  4655         // then, we should not execute without the shift state. See bug 433192.
  4656         if (IsCaseChangeableChar(ch))
  4657           continue;
  4659         // Setting the alternative charCode candidates for retry without shift
  4660         // key state only when the shift key is pressed.
  4661         nsShortcutCandidate key(ch, true);
  4662         aCandidates.AppendElement(key);
  4665   } else {
  4666     uint32_t charCode;
  4667     aDOMKeyEvent->GetCharCode(&charCode);
  4668     if (charCode) {
  4669       nsShortcutCandidate key(charCode, false);
  4670       aCandidates.AppendElement(key);
  4675 /* static */
  4676 void
  4677 nsContentUtils::GetAccessKeyCandidates(WidgetKeyboardEvent* aNativeKeyEvent,
  4678                                        nsTArray<uint32_t>& aCandidates)
  4680   NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
  4682   // return the lower cased charCode candidates for access keys.
  4683   // the priority of the charCodes are:
  4684   //   0: charCode, 1: unshiftedCharCodes[0], 2: shiftedCharCodes[0]
  4685   //   3: unshiftedCharCodes[1], 4: shiftedCharCodes[1],...
  4686   if (aNativeKeyEvent->charCode) {
  4687     uint32_t ch = aNativeKeyEvent->charCode;
  4688     if (IS_IN_BMP(ch))
  4689       ch = ToLowerCase(char16_t(ch));
  4690     aCandidates.AppendElement(ch);
  4692   for (uint32_t i = 0;
  4693        i < aNativeKeyEvent->alternativeCharCodes.Length(); ++i) {
  4694     uint32_t ch[2] =
  4695       { aNativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode,
  4696         aNativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode };
  4697     for (uint32_t j = 0; j < 2; ++j) {
  4698       if (!ch[j])
  4699         continue;
  4700       if (IS_IN_BMP(ch[j]))
  4701         ch[j] = ToLowerCase(char16_t(ch[j]));
  4702       // Don't append the charCode that was already appended.
  4703       if (aCandidates.IndexOf(ch[j]) == aCandidates.NoIndex)
  4704         aCandidates.AppendElement(ch[j]);
  4707   return;
  4710 /* static */
  4711 void
  4712 nsContentUtils::AddScriptBlocker()
  4714   if (!sScriptBlockerCount) {
  4715     NS_ASSERTION(sRunnersCountAtFirstBlocker == 0,
  4716                  "Should not already have a count");
  4717     sRunnersCountAtFirstBlocker = sBlockedScriptRunners->Length();
  4719   ++sScriptBlockerCount;
  4722 #ifdef DEBUG
  4723 static bool sRemovingScriptBlockers = false;
  4724 #endif
  4726 /* static */
  4727 void
  4728 nsContentUtils::RemoveScriptBlocker()
  4730   MOZ_ASSERT(!sRemovingScriptBlockers);
  4731   NS_ASSERTION(sScriptBlockerCount != 0, "Negative script blockers");
  4732   --sScriptBlockerCount;
  4733   if (sScriptBlockerCount) {
  4734     return;
  4737   uint32_t firstBlocker = sRunnersCountAtFirstBlocker;
  4738   uint32_t lastBlocker = sBlockedScriptRunners->Length();
  4739   uint32_t originalFirstBlocker = firstBlocker;
  4740   uint32_t blockersCount = lastBlocker - firstBlocker;
  4741   sRunnersCountAtFirstBlocker = 0;
  4742   NS_ASSERTION(firstBlocker <= lastBlocker,
  4743                "bad sRunnersCountAtFirstBlocker");
  4745   while (firstBlocker < lastBlocker) {
  4746     nsCOMPtr<nsIRunnable> runnable;
  4747     runnable.swap((*sBlockedScriptRunners)[firstBlocker]);
  4748     ++firstBlocker;
  4750     // Calling the runnable can reenter us
  4751     runnable->Run();
  4752     // So can dropping the reference to the runnable
  4753     runnable = nullptr;
  4755     NS_ASSERTION(sRunnersCountAtFirstBlocker == 0,
  4756                  "Bad count");
  4757     NS_ASSERTION(!sScriptBlockerCount, "This is really bad");
  4759 #ifdef DEBUG
  4760   AutoRestore<bool> removingScriptBlockers(sRemovingScriptBlockers);
  4761   sRemovingScriptBlockers = true;
  4762 #endif
  4763   sBlockedScriptRunners->RemoveElementsAt(originalFirstBlocker, blockersCount);
  4766 /* static */
  4767 bool
  4768 nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable)
  4770   if (!aRunnable) {
  4771     return false;
  4774   if (sScriptBlockerCount) {
  4775     return sBlockedScriptRunners->AppendElement(aRunnable) != nullptr;
  4778   nsCOMPtr<nsIRunnable> run = aRunnable;
  4779   run->Run();
  4781   return true;
  4784 void
  4785 nsContentUtils::EnterMicroTask()
  4787   MOZ_ASSERT(NS_IsMainThread());
  4788   ++sMicroTaskLevel;
  4791 void
  4792 nsContentUtils::LeaveMicroTask()
  4794   MOZ_ASSERT(NS_IsMainThread());
  4795   if (--sMicroTaskLevel == 0) {
  4796     nsDOMMutationObserver::HandleMutations();
  4797     nsDocument::ProcessBaseElementQueue();
  4801 bool
  4802 nsContentUtils::IsInMicroTask()
  4804   MOZ_ASSERT(NS_IsMainThread());
  4805   return sMicroTaskLevel != 0;
  4808 uint32_t
  4809 nsContentUtils::MicroTaskLevel()
  4811   MOZ_ASSERT(NS_IsMainThread());
  4812   return sMicroTaskLevel;
  4815 void
  4816 nsContentUtils::SetMicroTaskLevel(uint32_t aLevel)
  4818   MOZ_ASSERT(NS_IsMainThread());
  4819   sMicroTaskLevel = aLevel;
  4822 /* 
  4823  * Helper function for nsContentUtils::ProcessViewportInfo.
  4825  * Handles a single key=value pair. If it corresponds to a valid viewport
  4826  * attribute, add it to the document header data. No validation is done on the
  4827  * value itself (this is done at display time).
  4828  */
  4829 static void ProcessViewportToken(nsIDocument *aDocument, 
  4830                                  const nsAString &token) {
  4832   /* Iterators. */
  4833   nsAString::const_iterator tip, tail, end;
  4834   token.BeginReading(tip);
  4835   tail = tip;
  4836   token.EndReading(end);
  4838   /* Move tip to the '='. */
  4839   while ((tip != end) && (*tip != '='))
  4840     ++tip;
  4842   /* If we didn't find an '=', punt. */
  4843   if (tip == end)
  4844     return;
  4846   /* Extract the key and value. */
  4847   const nsAString &key =
  4848     nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(Substring(tail, tip),
  4849                                                         true);
  4850   const nsAString &value =
  4851     nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(Substring(++tip, end),
  4852                                                         true);
  4854   /* Check for known keys. If we find a match, insert the appropriate
  4855    * information into the document header. */
  4856   nsCOMPtr<nsIAtom> key_atom = do_GetAtom(key);
  4857   if (key_atom == nsGkAtoms::height)
  4858     aDocument->SetHeaderData(nsGkAtoms::viewport_height, value);
  4859   else if (key_atom == nsGkAtoms::width)
  4860     aDocument->SetHeaderData(nsGkAtoms::viewport_width, value);
  4861   else if (key_atom == nsGkAtoms::initial_scale)
  4862     aDocument->SetHeaderData(nsGkAtoms::viewport_initial_scale, value);
  4863   else if (key_atom == nsGkAtoms::minimum_scale)
  4864     aDocument->SetHeaderData(nsGkAtoms::viewport_minimum_scale, value);
  4865   else if (key_atom == nsGkAtoms::maximum_scale)
  4866     aDocument->SetHeaderData(nsGkAtoms::viewport_maximum_scale, value);
  4867   else if (key_atom == nsGkAtoms::user_scalable)
  4868     aDocument->SetHeaderData(nsGkAtoms::viewport_user_scalable, value);
  4871 #define IS_SEPARATOR(c) ((c == '=') || (c == ',') || (c == ';') || \
  4872                          (c == '\t') || (c == '\n') || (c == '\r'))
  4874 /* static */
  4875 nsViewportInfo
  4876 nsContentUtils::GetViewportInfo(nsIDocument *aDocument,
  4877                                 const ScreenIntSize& aDisplaySize)
  4879   return aDocument->GetViewportInfo(aDisplaySize);
  4882 /* static */
  4883 nsresult
  4884 nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument,
  4885                                     const nsAString &viewportInfo) {
  4887   /* We never fail. */
  4888   nsresult rv = NS_OK;
  4890   aDocument->SetHeaderData(nsGkAtoms::viewport, viewportInfo);
  4892   /* Iterators. */
  4893   nsAString::const_iterator tip, tail, end;
  4894   viewportInfo.BeginReading(tip);
  4895   tail = tip;
  4896   viewportInfo.EndReading(end);
  4898   /* Read the tip to the first non-separator character. */
  4899   while ((tip != end) && (IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip)))
  4900     ++tip;
  4902   /* Read through and find tokens separated by separators. */
  4903   while (tip != end) {
  4905     /* Synchronize tip and tail. */
  4906     tail = tip;
  4908     /* Advance tip past non-separator characters. */
  4909     while ((tip != end) && !IS_SEPARATOR(*tip))
  4910       ++tip;
  4912     /* Allow white spaces that surround the '=' character */
  4913     if ((tip != end) && (*tip == '=')) {
  4914       ++tip;
  4916       while ((tip != end) && nsCRT::IsAsciiSpace(*tip))
  4917         ++tip;
  4919       while ((tip != end) && !(IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip)))
  4920         ++tip;
  4923     /* Our token consists of the characters between tail and tip. */
  4924     ProcessViewportToken(aDocument, Substring(tail, tip));
  4926     /* Skip separators. */
  4927     while ((tip != end) && (IS_SEPARATOR(*tip) || nsCRT::IsAsciiSpace(*tip)))
  4928       ++tip;
  4931   return rv;
  4935 #undef IS_SEPARATOR
  4937 /* static */
  4938 void
  4939 nsContentUtils::HidePopupsInDocument(nsIDocument* aDocument)
  4941 #ifdef MOZ_XUL
  4942   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  4943   if (pm && aDocument) {
  4944     nsCOMPtr<nsIDocShellTreeItem> docShellToHide = aDocument->GetDocShell();
  4945     if (docShellToHide)
  4946       pm->HidePopupsInDocShell(docShellToHide);
  4948 #endif
  4951 /* static */
  4952 already_AddRefed<nsIDragSession>
  4953 nsContentUtils::GetDragSession()
  4955   nsCOMPtr<nsIDragSession> dragSession;
  4956   nsCOMPtr<nsIDragService> dragService =
  4957     do_GetService("@mozilla.org/widget/dragservice;1");
  4958   if (dragService)
  4959     dragService->GetCurrentSession(getter_AddRefs(dragSession));
  4960   return dragSession.forget();
  4963 /* static */
  4964 nsresult
  4965 nsContentUtils::SetDataTransferInEvent(WidgetDragEvent* aDragEvent)
  4967   if (aDragEvent->dataTransfer || !aDragEvent->mFlags.mIsTrusted)
  4968     return NS_OK;
  4970   // For draggesture and dragstart events, the data transfer object is
  4971   // created before the event fires, so it should already be set. For other
  4972   // drag events, get the object from the drag session.
  4973   NS_ASSERTION(aDragEvent->message != NS_DRAGDROP_GESTURE &&
  4974                aDragEvent->message != NS_DRAGDROP_START,
  4975                "draggesture event created without a dataTransfer");
  4977   nsCOMPtr<nsIDragSession> dragSession = GetDragSession();
  4978   NS_ENSURE_TRUE(dragSession, NS_OK); // no drag in progress
  4980   nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
  4981   nsCOMPtr<DataTransfer> initialDataTransfer;
  4982   dragSession->GetDataTransfer(getter_AddRefs(dataTransfer));
  4983   if (dataTransfer) {
  4984     initialDataTransfer = do_QueryInterface(dataTransfer);
  4985     if (!initialDataTransfer) {
  4986       return NS_ERROR_FAILURE;
  4988   } else {
  4989     // A dataTransfer won't exist when a drag was started by some other
  4990     // means, for instance calling the drag service directly, or a drag
  4991     // from another application. In either case, a new dataTransfer should
  4992     // be created that reflects the data.
  4993     initialDataTransfer = new DataTransfer(aDragEvent->target, aDragEvent->message, true, -1);
  4995     // now set it in the drag session so we don't need to create it again
  4996     dragSession->SetDataTransfer(initialDataTransfer);
  4999   bool isCrossDomainSubFrameDrop = false;
  5000   if (aDragEvent->message == NS_DRAGDROP_DROP ||
  5001       aDragEvent->message == NS_DRAGDROP_DRAGDROP) {
  5002     isCrossDomainSubFrameDrop = CheckForSubFrameDrop(dragSession, aDragEvent);
  5005   // each event should use a clone of the original dataTransfer.
  5006   initialDataTransfer->Clone(aDragEvent->target, aDragEvent->message, aDragEvent->userCancelled,
  5007                              isCrossDomainSubFrameDrop,
  5008                              getter_AddRefs(aDragEvent->dataTransfer));
  5009   NS_ENSURE_TRUE(aDragEvent->dataTransfer, NS_ERROR_OUT_OF_MEMORY);
  5011   // for the dragenter and dragover events, initialize the drop effect
  5012   // from the drop action, which platform specific widget code sets before
  5013   // the event is fired based on the keyboard state.
  5014   if (aDragEvent->message == NS_DRAGDROP_ENTER ||
  5015       aDragEvent->message == NS_DRAGDROP_OVER) {
  5016     uint32_t action, effectAllowed;
  5017     dragSession->GetDragAction(&action);
  5018     aDragEvent->dataTransfer->GetEffectAllowedInt(&effectAllowed);
  5019     aDragEvent->dataTransfer->SetDropEffectInt(FilterDropEffect(action, effectAllowed));
  5021   else if (aDragEvent->message == NS_DRAGDROP_DROP ||
  5022            aDragEvent->message == NS_DRAGDROP_DRAGDROP ||
  5023            aDragEvent->message == NS_DRAGDROP_END) {
  5024     // For the drop and dragend events, set the drop effect based on the
  5025     // last value that the dropEffect had. This will have been set in
  5026     // EventStateManager::PostHandleEvent for the last dragenter or
  5027     // dragover event.
  5028     uint32_t dropEffect;
  5029     initialDataTransfer->GetDropEffectInt(&dropEffect);
  5030     aDragEvent->dataTransfer->SetDropEffectInt(dropEffect);
  5033   return NS_OK;
  5036 /* static */
  5037 uint32_t
  5038 nsContentUtils::FilterDropEffect(uint32_t aAction, uint32_t aEffectAllowed)
  5040   // It is possible for the drag action to include more than one action, but
  5041   // the widget code which sets the action from the keyboard state should only
  5042   // be including one. If multiple actions were set, we just consider them in
  5043   //  the following order:
  5044   //   copy, link, move
  5045   if (aAction & nsIDragService::DRAGDROP_ACTION_COPY)
  5046     aAction = nsIDragService::DRAGDROP_ACTION_COPY;
  5047   else if (aAction & nsIDragService::DRAGDROP_ACTION_LINK)
  5048     aAction = nsIDragService::DRAGDROP_ACTION_LINK;
  5049   else if (aAction & nsIDragService::DRAGDROP_ACTION_MOVE)
  5050     aAction = nsIDragService::DRAGDROP_ACTION_MOVE;
  5052   // Filter the action based on the effectAllowed. If the effectAllowed
  5053   // doesn't include the action, then that action cannot be done, so adjust
  5054   // the action to something that is allowed. For a copy, adjust to move or
  5055   // link. For a move, adjust to copy or link. For a link, adjust to move or
  5056   // link. Otherwise, use none.
  5057   if (aAction & aEffectAllowed ||
  5058       aEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
  5059     return aAction;
  5060   if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_MOVE)
  5061     return nsIDragService::DRAGDROP_ACTION_MOVE;
  5062   if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_COPY)
  5063     return nsIDragService::DRAGDROP_ACTION_COPY;
  5064   if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_LINK)
  5065     return nsIDragService::DRAGDROP_ACTION_LINK;
  5066   return nsIDragService::DRAGDROP_ACTION_NONE;
  5069 /* static */
  5070 bool
  5071 nsContentUtils::CheckForSubFrameDrop(nsIDragSession* aDragSession,
  5072                                      WidgetDragEvent* aDropEvent)
  5074   nsCOMPtr<nsIContent> target = do_QueryInterface(aDropEvent->originalTarget);
  5075   if (!target) {
  5076     return true;
  5079   nsIDocument* targetDoc = target->OwnerDoc();
  5080   nsCOMPtr<nsIWebNavigation> twebnav = do_GetInterface(targetDoc->GetWindow());
  5081   nsCOMPtr<nsIDocShellTreeItem> tdsti = do_QueryInterface(twebnav);
  5082   if (!tdsti) {
  5083     return true;
  5086   // Always allow dropping onto chrome shells.
  5087   if (tdsti->ItemType() == nsIDocShellTreeItem::typeChrome) {
  5088     return false;
  5091   // If there is no source node, then this is a drag from another
  5092   // application, which should be allowed.
  5093   nsCOMPtr<nsIDOMDocument> sourceDocument;
  5094   aDragSession->GetSourceDocument(getter_AddRefs(sourceDocument));
  5095   nsCOMPtr<nsIDocument> doc = do_QueryInterface(sourceDocument);
  5096   if (doc) {
  5097     // Get each successive parent of the source document and compare it to
  5098     // the drop document. If they match, then this is a drag from a child frame.
  5099     do {
  5100       doc = doc->GetParentDocument();
  5101       if (doc == targetDoc) {
  5102         // The drag is from a child frame.
  5103         return true;
  5105     } while (doc);
  5108   return false;
  5111 /* static */
  5112 bool
  5113 nsContentUtils::URIIsLocalFile(nsIURI *aURI)
  5115   bool isFile;
  5116   nsCOMPtr<nsINetUtil> util = do_QueryInterface(sIOService);
  5118   // Important: we do NOT test the entire URI chain here!
  5119   return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
  5120                                 nsIProtocolHandler::URI_IS_LOCAL_FILE,
  5121                                 &isFile)) &&
  5122          isFile;
  5125 nsresult
  5126 nsContentUtils::SplitURIAtHash(nsIURI *aURI,
  5127                                nsACString &aBeforeHash,
  5128                                nsACString &aAfterHash)
  5130   // See bug 225910 for why we can't do this using nsIURL.
  5132   aBeforeHash.Truncate();
  5133   aAfterHash.Truncate();
  5135   NS_ENSURE_ARG_POINTER(aURI);
  5137   nsAutoCString spec;
  5138   nsresult rv = aURI->GetSpec(spec);
  5139   NS_ENSURE_SUCCESS(rv, rv);
  5141   int32_t index = spec.FindChar('#');
  5142   if (index == -1) {
  5143     index = spec.Length();
  5146   aBeforeHash.Assign(Substring(spec, 0, index));
  5147   aAfterHash.Assign(Substring(spec, index));
  5148   return NS_OK;
  5151 /* static */
  5152 nsIScriptContext*
  5153 nsContentUtils::GetContextForEventHandlers(nsINode* aNode,
  5154                                            nsresult* aRv)
  5156   *aRv = NS_OK;
  5157   bool hasHadScriptObject = true;
  5158   nsIScriptGlobalObject* sgo =
  5159     aNode->OwnerDoc()->GetScriptHandlingObject(hasHadScriptObject);
  5160   // It is bad if the document doesn't have event handling context,
  5161   // but it used to have one.
  5162   if (!sgo && hasHadScriptObject) {
  5163     *aRv = NS_ERROR_UNEXPECTED;
  5164     return nullptr;
  5167   if (sgo) {
  5168     nsIScriptContext* scx = sgo->GetContext();
  5169     // Bad, no context from script global object!
  5170     if (!scx) {
  5171       *aRv = NS_ERROR_UNEXPECTED;
  5172       return nullptr;
  5174     return scx;
  5177   return nullptr;
  5180 /* static */
  5181 JSContext *
  5182 nsContentUtils::GetCurrentJSContext()
  5184   MOZ_ASSERT(NS_IsMainThread());
  5185   return sXPConnect->GetCurrentJSContext();
  5188 /* static */
  5189 JSContext *
  5190 nsContentUtils::GetSafeJSContext()
  5192   MOZ_ASSERT(NS_IsMainThread());
  5193   return sXPConnect->GetSafeJSContext();
  5196 /* static */
  5197 JSContext *
  5198 nsContentUtils::GetDefaultJSContextForThread()
  5200   if (MOZ_LIKELY(NS_IsMainThread())) {
  5201     return GetSafeJSContext();
  5202   } else {
  5203     return workers::GetCurrentThreadJSContext();
  5207 /* static */
  5208 JSContext *
  5209 nsContentUtils::GetCurrentJSContextForThread()
  5211   if (MOZ_LIKELY(NS_IsMainThread())) {
  5212     return GetCurrentJSContext();
  5213   } else {
  5214     return workers::GetCurrentThreadJSContext();
  5218 /* static */
  5219 nsresult
  5220 nsContentUtils::ASCIIToLower(nsAString& aStr)
  5222   char16_t* iter = aStr.BeginWriting();
  5223   char16_t* end = aStr.EndWriting();
  5224   if (MOZ_UNLIKELY(!iter || !end)) {
  5225     return NS_ERROR_OUT_OF_MEMORY;
  5227   while (iter != end) {
  5228     char16_t c = *iter;
  5229     if (c >= 'A' && c <= 'Z') {
  5230       *iter = c + ('a' - 'A');
  5232     ++iter;
  5234   return NS_OK;
  5237 /* static */
  5238 nsresult
  5239 nsContentUtils::ASCIIToLower(const nsAString& aSource, nsAString& aDest)
  5241   uint32_t len = aSource.Length();
  5242   aDest.SetLength(len);
  5243   if (aDest.Length() == len) {
  5244     char16_t* dest = aDest.BeginWriting();
  5245     if (MOZ_UNLIKELY(!dest)) {
  5246       return NS_ERROR_OUT_OF_MEMORY;
  5248     const char16_t* iter = aSource.BeginReading();
  5249     const char16_t* end = aSource.EndReading();
  5250     while (iter != end) {
  5251       char16_t c = *iter;
  5252       *dest = (c >= 'A' && c <= 'Z') ?
  5253          c + ('a' - 'A') : c;
  5254       ++iter;
  5255       ++dest;
  5257     return NS_OK;
  5259   return NS_ERROR_OUT_OF_MEMORY;
  5262 /* static */
  5263 nsresult
  5264 nsContentUtils::ASCIIToUpper(nsAString& aStr)
  5266   char16_t* iter = aStr.BeginWriting();
  5267   char16_t* end = aStr.EndWriting();
  5268   if (MOZ_UNLIKELY(!iter || !end)) {
  5269     return NS_ERROR_OUT_OF_MEMORY;
  5271   while (iter != end) {
  5272     char16_t c = *iter;
  5273     if (c >= 'a' && c <= 'z') {
  5274       *iter = c + ('A' - 'a');
  5276     ++iter;
  5278   return NS_OK;
  5281 /* static */
  5282 nsresult
  5283 nsContentUtils::ASCIIToUpper(const nsAString& aSource, nsAString& aDest)
  5285   uint32_t len = aSource.Length();
  5286   aDest.SetLength(len);
  5287   if (aDest.Length() == len) {
  5288     char16_t* dest = aDest.BeginWriting();
  5289     if (MOZ_UNLIKELY(!dest)) {
  5290       return NS_ERROR_OUT_OF_MEMORY;
  5292     const char16_t* iter = aSource.BeginReading();
  5293     const char16_t* end = aSource.EndReading();
  5294     while (iter != end) {
  5295       char16_t c = *iter;
  5296       *dest = (c >= 'a' && c <= 'z') ?
  5297          c + ('A' - 'a') : c;
  5298       ++iter;
  5299       ++dest;
  5301     return NS_OK;
  5303   return NS_ERROR_OUT_OF_MEMORY;
  5306 /* static */
  5307 bool
  5308 nsContentUtils::EqualsIgnoreASCIICase(const nsAString& aStr1,
  5309                                       const nsAString& aStr2)
  5311   uint32_t len = aStr1.Length();
  5312   if (len != aStr2.Length()) {
  5313     return false;
  5316   const char16_t* str1 = aStr1.BeginReading();
  5317   const char16_t* str2 = aStr2.BeginReading();
  5318   const char16_t* end = str1 + len;
  5320   while (str1 < end) {
  5321     char16_t c1 = *str1++;
  5322     char16_t c2 = *str2++;
  5324     // First check if any bits other than the 0x0020 differs
  5325     if ((c1 ^ c2) & 0xffdf) {
  5326       return false;
  5329     // We know they can only differ in the 0x0020 bit.
  5330     // Likely the two chars are the same, so check that first
  5331     if (c1 != c2) {
  5332       // They do differ, but since it's only in the 0x0020 bit, check if it's
  5333       // the same ascii char, but just differing in case
  5334       char16_t c1Upper = c1 & 0xffdf;
  5335       if (!('A' <= c1Upper && c1Upper <= 'Z')) {
  5336         return false;
  5341   return true;
  5344 /* static */
  5345 bool
  5346 nsContentUtils::StringContainsASCIIUpper(const nsAString& aStr)
  5348   const char16_t* iter = aStr.BeginReading();
  5349   const char16_t* end = aStr.EndReading();
  5350   while (iter != end) {
  5351     char16_t c = *iter;
  5352     if (c >= 'A' && c <= 'Z') {
  5353       return true;
  5355     ++iter;
  5358   return false;
  5361 /* static */
  5362 nsIInterfaceRequestor*
  5363 nsContentUtils::GetSameOriginChecker()
  5365   if (!sSameOriginChecker) {
  5366     sSameOriginChecker = new SameOriginChecker();
  5367     NS_IF_ADDREF(sSameOriginChecker);
  5369   return sSameOriginChecker;
  5372 /* static */
  5373 nsresult
  5374 nsContentUtils::CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel)
  5376   if (!nsContentUtils::GetSecurityManager())
  5377     return NS_ERROR_NOT_AVAILABLE;
  5379   nsCOMPtr<nsIPrincipal> oldPrincipal;
  5380   nsContentUtils::GetSecurityManager()->
  5381     GetChannelPrincipal(aOldChannel, getter_AddRefs(oldPrincipal));
  5383   nsCOMPtr<nsIURI> newURI;
  5384   aNewChannel->GetURI(getter_AddRefs(newURI));
  5385   nsCOMPtr<nsIURI> newOriginalURI;
  5386   aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
  5388   NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
  5390   nsresult rv = oldPrincipal->CheckMayLoad(newURI, false, false);
  5391   if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
  5392     rv = oldPrincipal->CheckMayLoad(newOriginalURI, false, false);
  5395   return rv;
  5398 NS_IMPL_ISUPPORTS(SameOriginChecker,
  5399                   nsIChannelEventSink,
  5400                   nsIInterfaceRequestor)
  5402 NS_IMETHODIMP
  5403 SameOriginChecker::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
  5404                                           nsIChannel *aNewChannel,
  5405                                           uint32_t aFlags,
  5406                                           nsIAsyncVerifyRedirectCallback *cb)
  5408   NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
  5410   nsresult rv = nsContentUtils::CheckSameOrigin(aOldChannel, aNewChannel);
  5411   if (NS_SUCCEEDED(rv)) {
  5412     cb->OnRedirectVerifyCallback(NS_OK);
  5415   return rv;
  5418 NS_IMETHODIMP
  5419 SameOriginChecker::GetInterface(const nsIID & aIID, void **aResult)
  5421   return QueryInterface(aIID, aResult);
  5424 /* static */
  5425 nsresult
  5426 nsContentUtils::GetASCIIOrigin(nsIPrincipal* aPrincipal, nsCString& aOrigin)
  5428   NS_PRECONDITION(aPrincipal, "missing principal");
  5430   aOrigin.Truncate();
  5432   nsCOMPtr<nsIURI> uri;
  5433   nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
  5434   NS_ENSURE_SUCCESS(rv, rv);
  5436   if (uri) {
  5437     return GetASCIIOrigin(uri, aOrigin);
  5440   aOrigin.AssignLiteral("null");
  5442   return NS_OK;
  5445 /* static */
  5446 nsresult
  5447 nsContentUtils::GetASCIIOrigin(nsIURI* aURI, nsCString& aOrigin)
  5449   NS_PRECONDITION(aURI, "missing uri");
  5451   aOrigin.Truncate();
  5453   nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
  5454   NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
  5456   nsCString host;
  5457   nsresult rv = uri->GetAsciiHost(host);
  5459   if (NS_SUCCEEDED(rv) && !host.IsEmpty()) {
  5460     nsCString scheme;
  5461     rv = uri->GetScheme(scheme);
  5462     NS_ENSURE_SUCCESS(rv, rv);
  5464     int32_t port = -1;
  5465     uri->GetPort(&port);
  5466     if (port != -1 && port == NS_GetDefaultPort(scheme.get()))
  5467       port = -1;
  5469     nsCString hostPort;
  5470     rv = NS_GenerateHostPort(host, port, hostPort);
  5471     NS_ENSURE_SUCCESS(rv, rv);
  5473     aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort;
  5475   else {
  5476     aOrigin.AssignLiteral("null");
  5479   return NS_OK;
  5482 /* static */
  5483 nsresult
  5484 nsContentUtils::GetUTFOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin)
  5486   NS_PRECONDITION(aPrincipal, "missing principal");
  5488   aOrigin.Truncate();
  5490   nsCOMPtr<nsIURI> uri;
  5491   nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
  5492   NS_ENSURE_SUCCESS(rv, rv);
  5494   if (uri) {
  5495     return GetUTFOrigin(uri, aOrigin);
  5498   aOrigin.AssignLiteral("null");
  5500   return NS_OK;
  5503 /* static */
  5504 nsresult
  5505 nsContentUtils::GetUTFOrigin(nsIURI* aURI, nsString& aOrigin)
  5507   NS_PRECONDITION(aURI, "missing uri");
  5509   aOrigin.Truncate();
  5511   nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
  5512   NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
  5514   nsCString host;
  5515   nsresult rv = uri->GetHost(host);
  5517   if (NS_SUCCEEDED(rv) && !host.IsEmpty()) {
  5518     nsCString scheme;
  5519     rv = uri->GetScheme(scheme);
  5520     NS_ENSURE_SUCCESS(rv, rv);
  5522     int32_t port = -1;
  5523     uri->GetPort(&port);
  5524     if (port != -1 && port == NS_GetDefaultPort(scheme.get()))
  5525       port = -1;
  5527     nsCString hostPort;
  5528     rv = NS_GenerateHostPort(host, port, hostPort);
  5529     NS_ENSURE_SUCCESS(rv, rv);
  5531     aOrigin = NS_ConvertUTF8toUTF16(
  5532       scheme + NS_LITERAL_CSTRING("://") + hostPort);
  5534   else {
  5535     aOrigin.AssignLiteral("null");
  5538   return NS_OK;
  5541 /* static */
  5542 void
  5543 nsContentUtils::GetUTFNonNullOrigin(nsIURI* aURI, nsString& aOrigin)
  5545   aOrigin.Truncate();
  5547   nsString origin;
  5548   nsresult rv = GetUTFOrigin(aURI, origin);
  5549   if (NS_SUCCEEDED(rv) && !origin.EqualsLiteral("null")) {
  5550     aOrigin.Assign(origin);
  5554 /* static */
  5555 nsIDocument*
  5556 nsContentUtils::GetDocumentFromScriptContext(nsIScriptContext *aScriptContext)
  5558   if (!aScriptContext) {
  5559     return nullptr;
  5562   nsCOMPtr<nsPIDOMWindow> window =
  5563     do_QueryInterface(aScriptContext->GetGlobalObject());
  5564   if (!window) {
  5565     return nullptr;
  5568   return window->GetDoc();
  5571 /* static */
  5572 bool
  5573 nsContentUtils::CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel, bool aAllowIfInheritsPrincipal)
  5575   nsCOMPtr<nsIURI> channelURI;
  5576   nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
  5577   NS_ENSURE_SUCCESS(rv, false);
  5579   return NS_SUCCEEDED(aPrincipal->CheckMayLoad(channelURI, false, aAllowIfInheritsPrincipal));
  5582 nsContentTypeParser::nsContentTypeParser(const nsAString& aString)
  5583   : mString(aString), mService(nullptr)
  5585   CallGetService("@mozilla.org/network/mime-hdrparam;1", &mService);
  5588 nsContentTypeParser::~nsContentTypeParser()
  5590   NS_IF_RELEASE(mService);
  5593 nsresult
  5594 nsContentTypeParser::GetParameter(const char* aParameterName, nsAString& aResult)
  5596   NS_ENSURE_TRUE(mService, NS_ERROR_FAILURE);
  5597   return mService->GetParameterHTTP(mString, aParameterName,
  5598                                     EmptyCString(), false, nullptr,
  5599                                     aResult);
  5602 /* static */
  5604 bool
  5605 nsContentUtils::CanAccessNativeAnon()
  5607   return IsCallerChrome() || IsCallerXBL();
  5610 /* static */ nsresult
  5611 nsContentUtils::DispatchXULCommand(nsIContent* aTarget,
  5612                                    bool aTrusted,
  5613                                    nsIDOMEvent* aSourceEvent,
  5614                                    nsIPresShell* aShell,
  5615                                    bool aCtrl,
  5616                                    bool aAlt,
  5617                                    bool aShift,
  5618                                    bool aMeta)
  5620   NS_ENSURE_STATE(aTarget);
  5621   nsIDocument* doc = aTarget->OwnerDoc();
  5622   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
  5623   NS_ENSURE_STATE(domDoc);
  5624   nsCOMPtr<nsIDOMEvent> event;
  5625   domDoc->CreateEvent(NS_LITERAL_STRING("xulcommandevent"),
  5626                       getter_AddRefs(event));
  5627   nsCOMPtr<nsIDOMXULCommandEvent> xulCommand = do_QueryInterface(event);
  5628   nsresult rv = xulCommand->InitCommandEvent(NS_LITERAL_STRING("command"),
  5629                                              true, true, doc->GetWindow(),
  5630                                              0, aCtrl, aAlt, aShift, aMeta,
  5631                                              aSourceEvent);
  5632   NS_ENSURE_SUCCESS(rv, rv);
  5634   if (aShell) {
  5635     nsEventStatus status = nsEventStatus_eIgnore;
  5636     nsCOMPtr<nsIPresShell> kungFuDeathGrip = aShell;
  5637     return aShell->HandleDOMEventWithTarget(aTarget, event, &status);
  5640   nsCOMPtr<EventTarget> target = do_QueryInterface(aTarget);
  5641   NS_ENSURE_STATE(target);
  5642   bool dummy;
  5643   return target->DispatchEvent(event, &dummy);
  5646 // static
  5647 nsresult
  5648 nsContentUtils::WrapNative(JSContext *cx, nsISupports *native,
  5649                            nsWrapperCache *cache, const nsIID* aIID,
  5650                            JS::MutableHandle<JS::Value> vp, bool aAllowWrapping)
  5652   if (!native) {
  5653     vp.setNull();
  5655     return NS_OK;
  5658   JSObject *wrapper = xpc_FastGetCachedWrapper(cx, cache, vp);
  5659   if (wrapper) {
  5660     return NS_OK;
  5663   NS_ENSURE_TRUE(sXPConnect, NS_ERROR_UNEXPECTED);
  5665   if (!NS_IsMainThread()) {
  5666     MOZ_CRASH();
  5669   nsresult rv = NS_OK;
  5670   JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
  5671   AutoPushJSContext context(cx);
  5672   rv = sXPConnect->WrapNativeToJSVal(context, scope, native, cache, aIID,
  5673                                      aAllowWrapping, vp);
  5674   return rv;
  5677 nsresult
  5678 nsContentUtils::CreateArrayBuffer(JSContext *aCx, const nsACString& aData,
  5679                                   JSObject** aResult)
  5681   if (!aCx) {
  5682     return NS_ERROR_FAILURE;
  5685   int32_t dataLen = aData.Length();
  5686   *aResult = JS_NewArrayBuffer(aCx, dataLen);
  5687   if (!*aResult) {
  5688     return NS_ERROR_FAILURE;
  5691   if (dataLen > 0) {
  5692     NS_ASSERTION(JS_IsArrayBufferObject(*aResult), "What happened?");
  5693     memcpy(JS_GetArrayBufferData(*aResult), aData.BeginReading(), dataLen);
  5696   return NS_OK;
  5699 // Initial implementation: only stores to RAM, not file
  5700 // TODO: bug 704447: large file support
  5701 nsresult
  5702 nsContentUtils::CreateBlobBuffer(JSContext* aCx,
  5703                                  const nsACString& aData,
  5704                                  JS::MutableHandle<JS::Value> aBlob)
  5706   uint32_t blobLen = aData.Length();
  5707   void* blobData = moz_malloc(blobLen);
  5708   nsCOMPtr<nsIDOMBlob> blob;
  5709   if (blobData) {
  5710     memcpy(blobData, aData.BeginReading(), blobLen);
  5711     blob = new nsDOMMemoryFile(blobData, blobLen, EmptyString());
  5712   } else {
  5713     return NS_ERROR_OUT_OF_MEMORY;
  5715   return nsContentUtils::WrapNative(aCx, blob, aBlob);
  5718 void
  5719 nsContentUtils::StripNullChars(const nsAString& aInStr, nsAString& aOutStr)
  5721   // In common cases where we don't have nulls in the
  5722   // string we can simple simply bypass the checking code.
  5723   int32_t firstNullPos = aInStr.FindChar('\0');
  5724   if (firstNullPos == kNotFound) {
  5725     aOutStr.Assign(aInStr);
  5726     return;
  5729   aOutStr.SetCapacity(aInStr.Length() - 1);
  5730   nsAString::const_iterator start, end;
  5731   aInStr.BeginReading(start);
  5732   aInStr.EndReading(end);
  5733   while (start != end) {
  5734     if (*start != '\0')
  5735       aOutStr.Append(*start);
  5736     ++start;
  5740 struct ClassMatchingInfo {
  5741   nsAttrValue::AtomArray mClasses;
  5742   nsCaseTreatment mCaseTreatment;
  5743 };
  5745 // static
  5746 bool
  5747 nsContentUtils::MatchClassNames(nsIContent* aContent, int32_t aNamespaceID,
  5748                                 nsIAtom* aAtom, void* aData)
  5750   // We can't match if there are no class names
  5751   const nsAttrValue* classAttr = aContent->GetClasses();
  5752   if (!classAttr) {
  5753     return false;
  5756   // need to match *all* of the classes
  5757   ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData);
  5758   uint32_t length = info->mClasses.Length();
  5759   if (!length) {
  5760     // If we actually had no classes, don't match.
  5761     return false;
  5763   uint32_t i;
  5764   for (i = 0; i < length; ++i) {
  5765     if (!classAttr->Contains(info->mClasses[i],
  5766                              info->mCaseTreatment)) {
  5767       return false;
  5771   return true;
  5774 // static
  5775 void
  5776 nsContentUtils::DestroyClassNameArray(void* aData)
  5778   ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData);
  5779   delete info;
  5782 // static
  5783 void*
  5784 nsContentUtils::AllocClassMatchingInfo(nsINode* aRootNode,
  5785                                        const nsString* aClasses)
  5787   nsAttrValue attrValue;
  5788   attrValue.ParseAtomArray(*aClasses);
  5789   // nsAttrValue::Equals is sensitive to order, so we'll send an array
  5790   ClassMatchingInfo* info = new ClassMatchingInfo;
  5791   if (attrValue.Type() == nsAttrValue::eAtomArray) {
  5792     info->mClasses.SwapElements(*(attrValue.GetAtomArrayValue()));
  5793   } else if (attrValue.Type() == nsAttrValue::eAtom) {
  5794     info->mClasses.AppendElement(attrValue.GetAtomValue());
  5797   info->mCaseTreatment =
  5798     aRootNode->OwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks ?
  5799     eIgnoreCase : eCaseMatters;
  5800   return info;
  5803 // static
  5804 void
  5805 nsContentUtils::DeferredFinalize(nsISupports* aSupports)
  5807   cyclecollector::DeferredFinalize(aSupports);
  5810 // static
  5811 void
  5812 nsContentUtils::DeferredFinalize(mozilla::DeferredFinalizeAppendFunction aAppendFunc,
  5813                                  mozilla::DeferredFinalizeFunction aFunc,
  5814                                  void* aThing)
  5816   cyclecollector::DeferredFinalize(aAppendFunc, aFunc, aThing);
  5819 // static
  5820 bool
  5821 nsContentUtils::IsFocusedContent(const nsIContent* aContent)
  5823   nsFocusManager* fm = nsFocusManager::GetFocusManager();
  5825   return fm && fm->GetFocusedContent() == aContent;
  5828 bool
  5829 nsContentUtils::IsSubDocumentTabbable(nsIContent* aContent)
  5831   nsIDocument* doc = aContent->GetCurrentDoc();
  5832   if (!doc) {
  5833     return false;
  5836   // If the subdocument lives in another process, the frame is
  5837   // tabbable.
  5838   if (EventStateManager::IsRemoteTarget(aContent)) {
  5839     return true;
  5842   // XXXbz should this use OwnerDoc() for GetSubDocumentFor?
  5843   // sXBL/XBL2 issue!
  5844   nsIDocument* subDoc = doc->GetSubDocumentFor(aContent);
  5845   if (!subDoc) {
  5846     return false;
  5849   nsCOMPtr<nsIDocShell> docShell = subDoc->GetDocShell();
  5850   if (!docShell) {
  5851     return false;
  5854   nsCOMPtr<nsIContentViewer> contentViewer;
  5855   docShell->GetContentViewer(getter_AddRefs(contentViewer));
  5856   if (!contentViewer) {
  5857     return false;
  5860   nsCOMPtr<nsIContentViewer> zombieViewer;
  5861   contentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
  5863   // If there are 2 viewers for the current docshell, that
  5864   // means the current document is a zombie document.
  5865   // Only navigate into the subdocument if it's not a zombie.
  5866   return !zombieViewer;
  5869 bool
  5870 nsContentUtils::IsUserFocusIgnored(nsINode* aNode)
  5872   if (!nsGenericHTMLFrameElement::BrowserFramesEnabled()) {
  5873     return false;
  5876   // Check if our mozbrowser iframe ancestors has ignoreuserfocus attribute.
  5877   while (aNode) {
  5878     nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(aNode);
  5879     if (browserFrame &&
  5880         aNode->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::ignoreuserfocus) &&
  5881         browserFrame->GetReallyIsBrowserOrApp()) {
  5882       return true;
  5884     nsPIDOMWindow* win = aNode->OwnerDoc()->GetWindow();
  5885     aNode = win ? win->GetFrameElementInternal() : nullptr;
  5888   return false;
  5891 bool
  5892 nsContentUtils::HasScrollgrab(nsIContent* aContent)
  5894   nsGenericHTMLElement* element = nsGenericHTMLElement::FromContentOrNull(aContent);
  5895   return element && element->Scrollgrab();
  5898 void
  5899 nsContentUtils::FlushLayoutForTree(nsIDOMWindow* aWindow)
  5901     nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
  5902     if (!piWin)
  5903         return;
  5905     // Note that because FlushPendingNotifications flushes parents, this
  5906     // is O(N^2) in docshell tree depth.  However, the docshell tree is
  5907     // usually pretty shallow.
  5909     nsCOMPtr<nsIDOMDocument> domDoc;
  5910     aWindow->GetDocument(getter_AddRefs(domDoc));
  5911     nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
  5912     if (doc) {
  5913         doc->FlushPendingNotifications(Flush_Layout);
  5916     nsCOMPtr<nsIDocShell> docShell = piWin->GetDocShell();
  5917     if (docShell) {
  5918         int32_t i = 0, i_end;
  5919         docShell->GetChildCount(&i_end);
  5920         for (; i < i_end; ++i) {
  5921             nsCOMPtr<nsIDocShellTreeItem> item;
  5922             docShell->GetChildAt(i, getter_AddRefs(item));
  5923             nsCOMPtr<nsIDOMWindow> win = do_GetInterface(item);
  5924             if (win) {
  5925                 FlushLayoutForTree(win);
  5931 void nsContentUtils::RemoveNewlines(nsString &aString)
  5933   // strip CR/LF and null
  5934   static const char badChars[] = {'\r', '\n', 0};
  5935   aString.StripChars(badChars);
  5938 void
  5939 nsContentUtils::PlatformToDOMLineBreaks(nsString &aString)
  5941   if (aString.FindChar(char16_t('\r')) != -1) {
  5942     // Windows linebreaks: Map CRLF to LF:
  5943     aString.ReplaceSubstring(MOZ_UTF16("\r\n"),
  5944                              MOZ_UTF16("\n"));
  5946     // Mac linebreaks: Map any remaining CR to LF:
  5947     aString.ReplaceSubstring(MOZ_UTF16("\r"),
  5948                              MOZ_UTF16("\n"));
  5952 void
  5953 nsContentUtils::PopulateStringFromStringBuffer(nsStringBuffer* aBuf,
  5954                                                nsAString& aResultString)
  5956   MOZ_ASSERT(aBuf, "Expecting a non-null string buffer");
  5958   uint32_t stringLen = NS_strlen(static_cast<char16_t*>(aBuf->Data()));
  5960   // SANITY CHECK: In case the nsStringBuffer isn't correctly
  5961   // null-terminated, let's clamp its length using the allocated size, to be
  5962   // sure the resulting string doesn't sample past the end of the the buffer.
  5963   // (Note that StorageSize() is in units of bytes, so we have to convert that
  5964   // to units of PRUnichars, and subtract 1 for the null-terminator.)
  5965   uint32_t allocStringLen = (aBuf->StorageSize() / sizeof(char16_t)) - 1;
  5966   MOZ_ASSERT(stringLen <= allocStringLen,
  5967              "string buffer lacks null terminator!");
  5968   stringLen = std::min(stringLen, allocStringLen);
  5970   aBuf->ToString(stringLen, aResultString);
  5973 nsIPresShell*
  5974 nsContentUtils::FindPresShellForDocument(const nsIDocument* aDoc)
  5976   const nsIDocument* doc = aDoc;
  5977   nsIDocument* displayDoc = doc->GetDisplayDocument();
  5978   if (displayDoc) {
  5979     doc = displayDoc;
  5982   nsIPresShell* shell = doc->GetShell();
  5983   if (shell) {
  5984     return shell;
  5987   nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell();
  5988   while (docShellTreeItem) {
  5989     // We may be in a display:none subdocument, or we may not have a presshell
  5990     // created yet.
  5991     // Walk the docshell tree to find the nearest container that has a presshell,
  5992     // and return that.
  5993     nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(docShellTreeItem);
  5994     nsIPresShell* presShell = docShell->GetPresShell();
  5995     if (presShell) {
  5996       return presShell;
  5998     nsCOMPtr<nsIDocShellTreeItem> parent;
  5999     docShellTreeItem->GetParent(getter_AddRefs(parent));
  6000     docShellTreeItem = parent;
  6003   return nullptr;
  6006 nsIWidget*
  6007 nsContentUtils::WidgetForDocument(const nsIDocument* aDoc)
  6009   nsIPresShell* shell = FindPresShellForDocument(aDoc);
  6010   if (shell) {
  6011     nsViewManager* VM = shell->GetViewManager();
  6012     if (VM) {
  6013       nsView* rootView = VM->GetRootView();
  6014       if (rootView) {
  6015         nsView* displayRoot = nsViewManager::GetDisplayRootFor(rootView);
  6016         if (displayRoot) {
  6017           return displayRoot->GetNearestWidget(nullptr);
  6023   return nullptr;
  6026 static already_AddRefed<LayerManager>
  6027 LayerManagerForDocumentInternal(const nsIDocument *aDoc, bool aRequirePersistent,
  6028                                 bool* aAllowRetaining)
  6030   nsIWidget *widget = nsContentUtils::WidgetForDocument(aDoc);
  6031   if (widget) {
  6032     nsRefPtr<LayerManager> manager =
  6033       widget->GetLayerManager(aRequirePersistent ? nsIWidget::LAYER_MANAGER_PERSISTENT : 
  6034                               nsIWidget::LAYER_MANAGER_CURRENT,
  6035                               aAllowRetaining);
  6036     return manager.forget();
  6039   return nullptr;
  6042 already_AddRefed<LayerManager>
  6043 nsContentUtils::LayerManagerForDocument(const nsIDocument *aDoc, bool *aAllowRetaining)
  6045   return LayerManagerForDocumentInternal(aDoc, false, aAllowRetaining);
  6048 already_AddRefed<LayerManager>
  6049 nsContentUtils::PersistentLayerManagerForDocument(nsIDocument *aDoc, bool *aAllowRetaining)
  6051   return LayerManagerForDocumentInternal(aDoc, true, aAllowRetaining);
  6054 bool
  6055 nsContentUtils::AllowXULXBLForPrincipal(nsIPrincipal* aPrincipal)
  6057   if (IsSystemPrincipal(aPrincipal)) {
  6058     return true;
  6061   nsCOMPtr<nsIURI> princURI;
  6062   aPrincipal->GetURI(getter_AddRefs(princURI));
  6064   return princURI &&
  6065          ((sAllowXULXBL_for_file && SchemeIs(princURI, "file")) ||
  6066           IsSitePermAllow(aPrincipal, "allowXULXBL"));
  6069 already_AddRefed<nsIDocumentLoaderFactory>
  6070 nsContentUtils::FindInternalContentViewer(const char* aType,
  6071                                           ContentViewerType* aLoaderType)
  6073   if (aLoaderType) {
  6074     *aLoaderType = TYPE_UNSUPPORTED;
  6077   // one helper factory, please
  6078   nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
  6079   if (!catMan)
  6080     return nullptr;
  6082   nsCOMPtr<nsIDocumentLoaderFactory> docFactory;
  6084   nsXPIDLCString contractID;
  6085   nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", aType, getter_Copies(contractID));
  6086   if (NS_SUCCEEDED(rv)) {
  6087     docFactory = do_GetService(contractID);
  6088     if (docFactory && aLoaderType) {
  6089       if (contractID.EqualsLiteral(CONTENT_DLF_CONTRACTID))
  6090         *aLoaderType = TYPE_CONTENT;
  6091       else if (contractID.EqualsLiteral(PLUGIN_DLF_CONTRACTID))
  6092         *aLoaderType = TYPE_PLUGIN;
  6093       else
  6094       *aLoaderType = TYPE_UNKNOWN;
  6096     return docFactory.forget();
  6099   if (DecoderTraits::IsSupportedInVideoDocument(nsDependentCString(aType))) {
  6100     docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
  6101     if (docFactory && aLoaderType) {
  6102       *aLoaderType = TYPE_CONTENT;
  6104     return docFactory.forget();
  6107   return nullptr;
  6110 bool
  6111 nsContentUtils::GetContentSecurityPolicy(JSContext* aCx,
  6112                                          nsIContentSecurityPolicy** aCSP)
  6114   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  6116   // Get the security manager
  6117   nsCOMPtr<nsIScriptSecurityManager> ssm = nsContentUtils::GetSecurityManager();
  6119   if (!ssm) {
  6120     NS_ERROR("Failed to get security manager service");
  6121     return false;
  6124   nsCOMPtr<nsIPrincipal> subjectPrincipal = ssm->GetCxSubjectPrincipal(aCx);
  6125   NS_ASSERTION(subjectPrincipal, "Failed to get subjectPrincipal");
  6127   nsCOMPtr<nsIContentSecurityPolicy> csp;
  6128   nsresult rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
  6129   if (NS_FAILED(rv)) {
  6130     NS_ERROR("CSP: Failed to get CSP from principal.");
  6131     return false;
  6134   csp.forget(aCSP);
  6135   return true;
  6138 // static
  6139 bool
  6140 nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
  6141                                   nsIDocument* aDocument)
  6143   NS_ASSERTION(aDocument, "aDocument should be a valid pointer (not null)");
  6144   nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aDocument->GetWindow());
  6145   NS_ENSURE_TRUE(sgo, true);
  6147   AutoPushJSContext cx(sgo->GetContext()->GetNativeContext());
  6148   NS_ENSURE_TRUE(cx, true);
  6150   // The pattern has to match the entire value.
  6151   aPattern.Insert(NS_LITERAL_STRING("^(?:"), 0);
  6152   aPattern.Append(NS_LITERAL_STRING(")$"));
  6154   JS::Rooted<JSObject*> re(cx,
  6155     JS_NewUCRegExpObjectNoStatics(cx,
  6156                                   static_cast<jschar*>(aPattern.BeginWriting()),
  6157                                   aPattern.Length(), 0));
  6158   if (!re) {
  6159     JS_ClearPendingException(cx);
  6160     return true;
  6163   JS::Rooted<JS::Value> rval(cx, JS::NullValue());
  6164   size_t idx = 0;
  6165   if (!JS_ExecuteRegExpNoStatics(cx, re,
  6166                                  static_cast<jschar*>(aValue.BeginWriting()),
  6167                                  aValue.Length(), &idx, true, &rval)) {
  6168     JS_ClearPendingException(cx);
  6169     return true;
  6172   return !rval.isNull();
  6175 // static
  6176 nsresult
  6177 nsContentUtils::URIInheritsSecurityContext(nsIURI *aURI, bool *aResult)
  6179   // Note: about:blank URIs do NOT inherit the security context from the
  6180   // current document, which is what this function tests for...
  6181   return NS_URIChainHasFlags(aURI,
  6182                              nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
  6183                              aResult);
  6186 // static
  6187 bool
  6188 nsContentUtils::SetUpChannelOwner(nsIPrincipal* aLoadingPrincipal,
  6189                                   nsIChannel* aChannel,
  6190                                   nsIURI* aURI,
  6191                                   bool aSetUpForAboutBlank,
  6192                                   bool aForceOwner)
  6194   //
  6195   // Set the owner of the channel, but only for channels that can't
  6196   // provide their own security context.
  6197   //
  6198   // XXX: It seems wrong that the owner is ignored - even if one is
  6199   //      supplied) unless the URI is javascript or data or about:blank.
  6200   // XXX: If this is ever changed, check all callers for what owners
  6201   //      they're passing in.  In particular, see the code and
  6202   //      comments in nsDocShell::LoadURI where we fall back on
  6203   //      inheriting the owner if called from chrome.  That would be
  6204   //      very wrong if this code changed anything but channels that
  6205   //      can't provide their own security context!
  6206   //
  6207   //      (Currently chrome URIs set the owner when they are created!
  6208   //      So setting a nullptr owner would be bad!)
  6209   //
  6210   // If aForceOwner is true, the owner will be set, even for a channel that
  6211   // can provide its own security context. This is used for the HTML5 IFRAME
  6212   // sandbox attribute, so we can force the channel (and its document) to
  6213   // explicitly have a null principal.
  6214   bool inherit;
  6215   // We expect URIInheritsSecurityContext to return success for an
  6216   // about:blank URI, so don't call NS_IsAboutBlank() if this call fails.
  6217   // This condition needs to match the one in nsDocShell::InternalLoad where
  6218   // we're checking for things that will use the owner.
  6219   if (aForceOwner || ((NS_SUCCEEDED(URIInheritsSecurityContext(aURI, &inherit)) &&
  6220       (inherit || (aSetUpForAboutBlank && NS_IsAboutBlank(aURI)))))) {
  6221 #ifdef DEBUG
  6222     // Assert that aForceOwner is only set for null principals for non-srcdoc
  6223     // loads.  (Strictly speaking not all uses of about:srcdoc would be 
  6224     // srcdoc loads, but the URI is non-resolvable in cases where it is not).
  6225     if (aForceOwner) {
  6226       nsAutoCString uriStr;
  6227       aURI->GetSpec(uriStr);
  6228       if(!uriStr.EqualsLiteral("about:srcdoc") &&
  6229          !uriStr.EqualsLiteral("view-source:about:srcdoc")) {
  6230         nsCOMPtr<nsIURI> ownerURI;
  6231         nsresult rv = aLoadingPrincipal->GetURI(getter_AddRefs(ownerURI));
  6232         MOZ_ASSERT(NS_SUCCEEDED(rv) && SchemeIs(ownerURI, NS_NULLPRINCIPAL_SCHEME));
  6235 #endif
  6236     aChannel->SetOwner(aLoadingPrincipal);
  6237     return true;
  6240   //
  6241   // file: uri special-casing
  6242   //
  6243   // If this is a file: load opened from another file: then it may need
  6244   // to inherit the owner from the referrer so they can script each other.
  6245   // If we don't set the owner explicitly then each file: gets an owner
  6246   // based on its own codebase later.
  6247   //
  6248   if (URIIsLocalFile(aURI) && aLoadingPrincipal &&
  6249       NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, false, false)) &&
  6250       // One more check here.  CheckMayLoad will always return true for the
  6251       // system principal, but we do NOT want to inherit in that case.
  6252       !IsSystemPrincipal(aLoadingPrincipal)) {
  6253     aChannel->SetOwner(aLoadingPrincipal);
  6254     return true;
  6257   return false;
  6260 /* static */
  6261 bool
  6262 nsContentUtils::IsFullScreenApiEnabled()
  6264   return sIsFullScreenApiEnabled;
  6267 /* static */
  6268 bool
  6269 nsContentUtils::IsRequestFullScreenAllowed()
  6271   return !sTrustedFullScreenOnly ||
  6272          EventStateManager::IsHandlingUserInput() ||
  6273          IsCallerChrome();
  6276 /* static */
  6277 bool
  6278 nsContentUtils::IsFullscreenApiContentOnly()
  6280   return sFullscreenApiIsContentOnly;
  6283 /* static */
  6284 bool
  6285 nsContentUtils::HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2)
  6287   if (!aDoc1 || !aDoc2) {
  6288     return false;
  6290   bool principalsEqual = false;
  6291   aDoc1->NodePrincipal()->Equals(aDoc2->NodePrincipal(), &principalsEqual);
  6292   return principalsEqual;
  6295 static void
  6296 CheckForWindowedPlugins(nsIContent* aContent, void* aResult)
  6298   if (!aContent->IsInDoc()) {
  6299     return;
  6301   nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent));
  6302   if (!olc) {
  6303     return;
  6305   nsRefPtr<nsNPAPIPluginInstance> plugin;
  6306   olc->GetPluginInstance(getter_AddRefs(plugin));
  6307   if (!plugin) {
  6308     return;
  6310   bool isWindowless = false;
  6311   nsresult res = plugin->IsWindowless(&isWindowless);
  6312   if (NS_SUCCEEDED(res) && !isWindowless) {
  6313     *static_cast<bool*>(aResult) = true;
  6317 static bool
  6318 DocTreeContainsWindowedPlugins(nsIDocument* aDoc, void* aResult)
  6320   if (!nsContentUtils::IsChromeDoc(aDoc)) {
  6321     aDoc->EnumerateFreezableElements(CheckForWindowedPlugins, aResult);
  6323   if (*static_cast<bool*>(aResult)) {
  6324     // Return false to stop iteration, we found a windowed plugin.
  6325     return false;
  6327   aDoc->EnumerateSubDocuments(DocTreeContainsWindowedPlugins, aResult);
  6328   // Return false to stop iteration if we found a windowed plugin in
  6329   // the sub documents.
  6330   return !*static_cast<bool*>(aResult);
  6333 /* static */
  6334 bool
  6335 nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc)
  6337 #ifdef XP_MACOSX
  6338   // We control dispatch to all mac plugins.
  6339   return false;
  6340 #endif
  6341   bool result = false;
  6343   // Find the top of the document's branch, the child of the chrome document.
  6344   nsIDocument* doc = aDoc;
  6345   nsIDocument* parent = nullptr;
  6346   while (doc && (parent = doc->GetParentDocument()) && !IsChromeDoc(parent)) {
  6347     doc = parent;
  6350   DocTreeContainsWindowedPlugins(doc, &result);
  6351   return result;
  6354 /* static */
  6355 bool
  6356 nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent)
  6358 #ifdef XP_MACOSX
  6359   // We control dispatch to all mac plugins.
  6360   return false;
  6361 #endif
  6362   bool result = false;
  6363   CheckForWindowedPlugins(aContent, &result);
  6364   return result;
  6367 /* static */
  6368 void
  6369 nsContentUtils::FireMutationEventsForDirectParsing(nsIDocument* aDoc,
  6370                                                    nsIContent* aDest,
  6371                                                    int32_t aOldChildCount)
  6373   // Fire mutation events. Optimize for the case when there are no listeners
  6374   int32_t newChildCount = aDest->GetChildCount();
  6375   if (newChildCount && nsContentUtils::
  6376         HasMutationListeners(aDoc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
  6377     nsAutoTArray<nsCOMPtr<nsIContent>, 50> childNodes;
  6378     NS_ASSERTION(newChildCount - aOldChildCount >= 0,
  6379                  "What, some unexpected dom mutation has happened?");
  6380     childNodes.SetCapacity(newChildCount - aOldChildCount);
  6381     for (nsIContent* child = aDest->GetFirstChild();
  6382          child;
  6383          child = child->GetNextSibling()) {
  6384       childNodes.AppendElement(child);
  6386     FragmentOrElement::FireNodeInserted(aDoc, aDest, childNodes);
  6390 /* static */
  6391 nsIDocument*
  6392 nsContentUtils::GetFullscreenAncestor(nsIDocument* aDoc)
  6394   nsIDocument* doc = aDoc;
  6395   while (doc) {
  6396     if (doc->IsFullScreenDoc()) {
  6397       return doc;
  6399     doc = doc->GetParentDocument();
  6401   return nullptr;
  6404 /* static */
  6405 bool
  6406 nsContentUtils::IsInPointerLockContext(nsIDOMWindow* aWin)
  6408   if (!aWin) {
  6409     return false;
  6412   nsCOMPtr<nsIDocument> pointerLockedDoc =
  6413     do_QueryReferent(EventStateManager::sPointerLockedDoc);
  6414   if (!pointerLockedDoc || !pointerLockedDoc->GetWindow()) {
  6415     return false;
  6418   nsCOMPtr<nsIDOMWindow> lockTop;
  6419   pointerLockedDoc->GetWindow()->GetScriptableTop(getter_AddRefs(lockTop));
  6421   nsCOMPtr<nsIDOMWindow> top;
  6422   aWin->GetScriptableTop(getter_AddRefs(top));
  6424   return top == lockTop;
  6427 // static
  6428 int32_t
  6429 nsContentUtils::GetAdjustedOffsetInTextControl(nsIFrame* aOffsetFrame,
  6430                                                int32_t aOffset)
  6432   // The structure of the anonymous frames within a text control frame is
  6433   // an optional block frame, followed by an optional br frame.
  6435   // If the offset frame has a child, then this frame is the block which
  6436   // has the text frames (containing the content) as its children. This will
  6437   // be the case if we click to the right of any of the text frames, or at the
  6438   // bottom of the text area.
  6439   nsIFrame* firstChild = aOffsetFrame->GetFirstPrincipalChild();
  6440   if (firstChild) {
  6441     // In this case, the passed-in offset is incorrect, and we want the length
  6442     // of the entire content in the text control frame.
  6443     return firstChild->GetContent()->Length();
  6446   if (aOffsetFrame->GetPrevSibling() &&
  6447       !aOffsetFrame->GetNextSibling()) {
  6448     // In this case, we're actually within the last frame, which is a br
  6449     // frame. Our offset should therefore be the length of the first child of
  6450     // our parent.
  6451     int32_t aOutOffset =
  6452       aOffsetFrame->GetParent()->GetFirstPrincipalChild()->GetContent()->Length();
  6453     return aOutOffset;
  6456   // Otherwise, we're within one of the text frames, in which case our offset
  6457   // has already been correctly calculated.
  6458   return aOffset;
  6461 // static
  6462 void
  6463 nsContentUtils::GetSelectionInTextControl(Selection* aSelection,
  6464                                           Element* aRoot,
  6465                                           int32_t& aOutStartOffset,
  6466                                           int32_t& aOutEndOffset)
  6468   MOZ_ASSERT(aSelection && aRoot);
  6470   if (!aSelection->GetRangeCount()) {
  6471     // Nothing selected
  6472     aOutStartOffset = aOutEndOffset = 0;
  6473     return;
  6476   nsCOMPtr<nsINode> anchorNode = aSelection->GetAnchorNode();
  6477   uint32_t anchorOffset = aSelection->AnchorOffset();
  6478   nsCOMPtr<nsINode> focusNode = aSelection->GetFocusNode();
  6479   uint32_t focusOffset = aSelection->FocusOffset();
  6481   // We have at most two children, consisting of an optional text node followed
  6482   // by an optional <br>.
  6483   NS_ASSERTION(aRoot->GetChildCount() <= 2, "Unexpected children");
  6484   nsCOMPtr<nsIContent> firstChild = aRoot->GetFirstChild();
  6485 #ifdef DEBUG
  6486   nsCOMPtr<nsIContent> lastChild = aRoot->GetLastChild();
  6487   NS_ASSERTION(anchorNode == aRoot || anchorNode == firstChild ||
  6488                anchorNode == lastChild, "Unexpected anchorNode");
  6489   NS_ASSERTION(focusNode == aRoot || focusNode == firstChild ||
  6490                focusNode == lastChild, "Unexpected focusNode");
  6491 #endif
  6492   if (!firstChild || !firstChild->IsNodeOfType(nsINode::eTEXT)) {
  6493     // No text node, so everything is 0
  6494     anchorOffset = focusOffset = 0;
  6495   } else {
  6496     // First child is text.  If the anchor/focus is already in the text node,
  6497     // or the start of the root node, no change needed.  If it's in the root
  6498     // node but not the start, or in the trailing <br>, we need to set the
  6499     // offset to the end.
  6500     if ((anchorNode == aRoot && anchorOffset != 0) ||
  6501         (anchorNode != aRoot && anchorNode != firstChild)) {
  6502       anchorOffset = firstChild->Length();
  6504     if ((focusNode == aRoot && focusOffset != 0) ||
  6505         (focusNode != aRoot && focusNode != firstChild)) {
  6506       focusOffset = firstChild->Length();
  6510   // Make sure aOutStartOffset <= aOutEndOffset.
  6511   aOutStartOffset = std::min(anchorOffset, focusOffset);
  6512   aOutEndOffset = std::max(anchorOffset, focusOffset);
  6515 nsIEditor*
  6516 nsContentUtils::GetHTMLEditor(nsPresContext* aPresContext)
  6518   nsCOMPtr<nsIDocShell> docShell(aPresContext->GetDocShell());
  6519   bool isEditable;
  6520   if (!docShell ||
  6521       NS_FAILED(docShell->GetEditable(&isEditable)) || !isEditable)
  6522     return nullptr;
  6524   nsCOMPtr<nsIEditor> editor;
  6525   docShell->GetEditor(getter_AddRefs(editor));
  6526   return editor;
  6529 bool
  6530 nsContentUtils::InternalIsSupported(nsISupports* aObject,
  6531                                     const nsAString& aFeature,
  6532                                     const nsAString& aVersion)
  6534   // If it looks like an SVG feature string, forward to nsSVGFeatures
  6535   if (StringBeginsWith(aFeature,
  6536                        NS_LITERAL_STRING("http://www.w3.org/TR/SVG"),
  6537                        nsASCIICaseInsensitiveStringComparator()) ||
  6538       StringBeginsWith(aFeature, NS_LITERAL_STRING("org.w3c.dom.svg"),
  6539                        nsASCIICaseInsensitiveStringComparator()) ||
  6540       StringBeginsWith(aFeature, NS_LITERAL_STRING("org.w3c.svg"),
  6541                        nsASCIICaseInsensitiveStringComparator())) {
  6542     return (aVersion.IsEmpty() || aVersion.EqualsLiteral("1.0") ||
  6543             aVersion.EqualsLiteral("1.1")) &&
  6544            nsSVGFeatures::HasFeature(aObject, aFeature);
  6547   // Otherwise, we claim to support everything
  6548   return true;
  6551 bool
  6552 nsContentUtils::IsContentInsertionPoint(const nsIContent* aContent)
  6554   // Check if the content is a XBL insertion point.
  6555   if (aContent->IsActiveChildrenElement()) {
  6556     return true;
  6559   // Check if the content is a web components content insertion point.
  6560   if (aContent->IsHTML(nsGkAtoms::content)) {
  6561     return static_cast<const HTMLContentElement*>(aContent)->IsInsertionPoint();
  6564   return false;
  6567 bool
  6568 nsContentUtils::DOMWindowDumpEnabled()
  6570 #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
  6571   // In optimized builds we check a pref that controls if we should
  6572   // enable output from dump() or not, in debug builds it's always
  6573   // enabled.
  6574   return nsContentUtils::sDOMWindowDumpEnabled;
  6575 #else
  6576   return true;
  6577 #endif
  6580 bool
  6581 nsContentUtils::GetNodeTextContent(nsINode* aNode, bool aDeep, nsAString& aResult)
  6583   aResult.Truncate();
  6584   return AppendNodeTextContent(aNode, aDeep, aResult, mozilla::fallible_t());
  6587 void
  6588 nsContentUtils::DestroyMatchString(void* aData)
  6590   if (aData) {
  6591     nsString* matchString = static_cast<nsString*>(aData);
  6592     delete matchString;
  6596 bool
  6597 nsContentUtils::IsJavascriptMIMEType(const nsAString& aMIMEType)
  6599   // Table ordered from most to least likely JS MIME types.
  6600   static const char* jsTypes[] = {
  6601     "text/javascript",
  6602     "text/ecmascript",
  6603     "application/javascript",
  6604     "application/ecmascript",
  6605     "application/x-javascript",
  6606     "application/x-ecmascript",
  6607     "text/javascript1.0",
  6608     "text/javascript1.1",
  6609     "text/javascript1.2",
  6610     "text/javascript1.3",
  6611     "text/javascript1.4",
  6612     "text/javascript1.5",
  6613     "text/jscript",
  6614     "text/livescript",
  6615     "text/x-ecmascript",
  6616     "text/x-javascript",
  6617     nullptr
  6618   };
  6620   for (uint32_t i = 0; jsTypes[i]; ++i) {
  6621     if (aMIMEType.LowerCaseEqualsASCII(jsTypes[i])) {
  6622       return true;
  6626   return false;

mercurial