/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* A namespace class for static layout utilities. */ #include "nsContentUtils.h" #include #include #include "DecoderTraits.h" #include "harfbuzz/hb.h" #include "imgICache.h" #include "imgIContainer.h" #include "imgINotificationObserver.h" #include "imgLoader.h" #include "imgRequestProxy.h" #include "jsapi.h" #include "jsfriendapi.h" #include "js/Array.h" // JS::NewArrayObject #include "js/ArrayBuffer.h" // JS::{GetArrayBufferData,IsArrayBufferObject,NewArrayBuffer} #include "js/JSON.h" #include "js/RegExp.h" // JS::ExecuteRegExpNoStatics, JS::NewUCRegExpObject, JS::RegExpFlags #include "js/Value.h" #include "Layers.h" #include "nsAppRunner.h" // nsNPAPIPluginInstance must be included before mozilla/dom/Document.h, which // is included in mozAutoDocUpdate.h. #include "nsNPAPIPluginInstance.h" #include "gfxDrawable.h" #include "ImageOps.h" #include "mozAutoDocUpdate.h" #include "mozilla/net/UrlClassifierCommon.h" #include "mozilla/ArrayUtils.h" #include "mozilla/Attributes.h" #include "mozilla/AutoRestore.h" #include "mozilla/AutoTimelineMarker.h" #include "mozilla/BackgroundHangMonitor.h" #include "mozilla/Base64.h" #include "mozilla/BasePrincipal.h" #include "mozilla/CheckedInt.h" #include "mozilla/Components.h" #include "mozilla/DebugOnly.h" #include "mozilla/LoadInfo.h" #include "mozilla/dom/AncestorIterator.h" #include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/BrowsingContext.h" #include "mozilla/dom/BrowsingContextGroup.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/CustomElementRegistry.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/DocumentInlines.h" #include "mozilla/dom/MessageBroadcaster.h" #include "mozilla/dom/DocumentFragment.h" #include "mozilla/dom/DOMException.h" #include "mozilla/dom/DOMExceptionBinding.h" #include "mozilla/dom/DOMSecurityMonitor.h" #include "mozilla/dom/DOMTypes.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/ElementInlines.h" #include "mozilla/dom/Event.h" #include "mozilla/dom/FileSystemSecurity.h" #include "mozilla/dom/FileBlobImpl.h" #include "mozilla/dom/FontTableURIProtocolHandler.h" #include "mozilla/dom/HTMLInputElement.h" #include "mozilla/dom/HTMLSlotElement.h" #include "mozilla/dom/HTMLTemplateElement.h" #include "mozilla/dom/HTMLTextAreaElement.h" #include "mozilla/dom/IDTracker.h" #include "mozilla/dom/MouseEventBinding.h" #include "mozilla/dom/KeyboardEventBinding.h" #include "mozilla/dom/IPCBlobUtils.h" #include "mozilla/dom/NodeBinding.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/BrowserBridgeChild.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/BrowserParent.h" #include "mozilla/dom/Text.h" #include "mozilla/dom/TouchEvent.h" #include "mozilla/dom/ShadowRoot.h" #include "mozilla/dom/XULCommandEvent.h" #include "mozilla/dom/UserActivation.h" #include "mozilla/dom/WorkerCommon.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/extensions/WebExtensionPolicy.h" #include "mozilla/net/CookieJarSettings.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventListenerManager.h" #include "mozilla/EventStateManager.h" #include "mozilla/gfx/DataSurfaceHelpers.h" #include "mozilla/HTMLEditor.h" #include "mozilla/IMEStateManager.h" #include "mozilla/InputEventOptions.h" #include "mozilla/InternalMutationEvent.h" #include "mozilla/Likely.h" #include "mozilla/ManualNAC.h" #include "mozilla/MouseEvents.h" #include "mozilla/Preferences.h" #include "mozilla/PresShell.h" #include "mozilla/ResultExtensions.h" #include "mozilla/dom/Selection.h" #include "mozilla/Services.h" #include "mozilla/StaticPrefs_dom.h" #include "mozilla/StaticPrefs_full_screen_api.h" #ifdef FUZZING # include "mozilla/StaticPrefs_fuzzing.h" #endif #include "mozilla/StaticPrefs_privacy.h" #include "mozilla/StaticPrefs_test.h" #include "mozilla/StaticPrefs_ui.h" #include "mozilla/StoragePrincipalHelper.h" #include "mozilla/TextControlState.h" #include "mozilla/TextEditor.h" #include "mozilla/TextEvents.h" #include "mozilla/ViewportUtils.h" #include "nsArrayUtils.h" #include "nsAString.h" #include "nsAttrName.h" #include "nsAttrValue.h" #include "nsAttrValueInlines.h" #include "nsCanvasFrame.h" #include "nsCaret.h" #include "nsCCUncollectableMarker.h" #include "nsCharSeparatedTokenizer.h" #include "nsCOMPtr.h" #include "nsContentCreatorFunctions.h" #include "nsContentDLF.h" #include "nsContentList.h" #include "nsContentPolicyUtils.h" #include "nsContentSecurityManager.h" #include "nsCRT.h" #include "nsCycleCollectionParticipant.h" #include "nsCycleCollector.h" #include "nsDataHashtable.h" #include "nsDocShellCID.h" #include "nsDOMCID.h" #include "mozilla/dom/DataTransfer.h" #include "nsDOMJSUtils.h" #include "nsDOMMutationObserver.h" #include "nsError.h" #include "nsFocusManager.h" #include "nsFrameLoaderOwner.h" #include "nsGenericHTMLElement.h" #include "nsGenericHTMLFrameElement.h" #include "nsGkAtoms.h" #include "nsHtml5Module.h" #include "nsHtml5StringParser.h" #include "nsHTMLDocument.h" #include "nsHTMLTags.h" #include "nsIAnonymousContentCreator.h" #include "nsIAsyncVerifyRedirectCallback.h" #include "nsICategoryManager.h" #include "nsIChannelEventSink.h" #include "nsIConsoleService.h" #include "nsIContent.h" #include "nsIContentInlines.h" #include "nsIContentSecurityPolicy.h" #include "nsIContentSink.h" #include "nsIContentViewer.h" #include "nsIDocShell.h" #include "nsIDocShellTreeOwner.h" #include "mozilla/dom/Document.h" #include "nsIDocumentEncoder.h" #include "nsIDOMWindowUtils.h" #include "nsIDragService.h" #include "nsIFormControl.h" #include "nsIForm.h" #include "nsIFragmentContentSink.h" #include "nsContainerFrame.h" #include "nsIClassifiedChannel.h" #include "nsIHttpChannelInternal.h" #include "nsIIdleService.h" #include "nsIImageLoadingContent.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIIOService.h" #include "nsILoadContext.h" #include "nsILoadGroup.h" #include "nsIMemoryReporter.h" #include "nsIMIMEService.h" #include "nsINode.h" #include "mozilla/dom/NodeInfo.h" #include "mozilla/NullPrincipal.h" #include "nsIObjectLoadingContent.h" #include "nsIObserver.h" #include "nsIObserverService.h" #include "nsIOfflineCacheUpdate.h" #include "nsIParser.h" #include "nsIParserUtils.h" #include "nsIPermissionManager.h" #include "nsIRequest.h" #include "nsIRunnable.h" #include "nsIScriptContext.h" #include "nsIScriptError.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptObjectPrincipal.h" #include "nsIScriptSecurityManager.h" #include "nsIStreamConverter.h" #include "nsIStreamConverterService.h" #include "nsIStringBundle.h" #include "nsIURI.h" #include "nsIURIMutator.h" #include "nsIURIWithSpecialOrigin.h" #include "nsIUUIDGenerator.h" #include "nsIWebNavigation.h" #include "nsIWidget.h" #include "nsIWindowMediator.h" #include "nsIXPConnect.h" #include "nsJSUtils.h" #include "nsMappedAttributes.h" #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsNodeInfoManager.h" #include "nsParserCIID.h" #include "nsParserConstants.h" #include "nsPIDOMWindow.h" #include "nsPresContext.h" #include "nsPrintfCString.h" #include "nsQueryObject.h" #include "nsSandboxFlags.h" #include "nsScriptSecurityManager.h" #include "nsSerializationHelper.h" #include "nsStreamUtils.h" #include "nsTextFragment.h" #include "nsTextNode.h" #include "nsThreadUtils.h" #include "nsTreeSanitizer.h" #include "nsUnicodeProperties.h" #include "nsURLHelper.h" #include "nsViewManager.h" #include "nsViewportInfo.h" #include "nsWidgetsCID.h" #include "nsWrapperCacheInlines.h" #include "nsXULPopupManager.h" #include "xpcprivate.h" // nsXPConnect #include "HTMLSplitOnSpacesTokenizer.h" #include "InProcessBrowserChildMessageManager.h" #include "nsContentTypeParser.h" #include "ThirdPartyUtil.h" #include "mozilla/EnumSet.h" #include "mozilla/BloomFilter.h" #include "BrowserChild.h" #include "mozilla/dom/DocGroup.h" #include "nsIWebNavigationInfo.h" #include "nsPluginHost.h" #include "nsIBrowser.h" #include "mozilla/HangAnnotations.h" #include "mozilla/Encoding.h" #include "nsXULElement.h" #include "nsThreadManager.h" #include "nsIBidiKeyboard.h" #include "ReferrerInfo.h" #include "nsAboutProtocolUtils.h" #if defined(XP_WIN) // Undefine LoadImage to prevent naming conflict with Windows. # undef LoadImage #endif extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end, const char** next, char16_t* result); extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end, int ns_aware, const char** colon); class imgLoader; class nsAtom; using namespace mozilla::dom; using namespace mozilla::ipc; using namespace mozilla::gfx; using namespace mozilla::layers; using namespace mozilla::widget; using namespace mozilla; const char kLoadAsData[] = "loadAsData"; nsIXPConnect* nsContentUtils::sXPConnect; nsIScriptSecurityManager* nsContentUtils::sSecurityManager; nsIPrincipal* nsContentUtils::sSystemPrincipal; nsIPrincipal* nsContentUtils::sNullSubjectPrincipal; nsNameSpaceManager* nsContentUtils::sNameSpaceManager; nsIIOService* nsContentUtils::sIOService; nsIUUIDGenerator* nsContentUtils::sUUIDGenerator; nsIConsoleService* nsContentUtils::sConsoleService; nsDataHashtable, EventNameMapping>* nsContentUtils::sAtomEventTable = nullptr; nsDataHashtable* nsContentUtils::sStringEventTable = nullptr; nsTArray>* nsContentUtils::sUserDefinedEvents = nullptr; nsIStringBundleService* nsContentUtils::sStringBundleService; nsIStringBundle* nsContentUtils::sStringBundles[PropertiesFile_COUNT]; nsIContentPolicy* nsContentUtils::sContentPolicyService; bool nsContentUtils::sTriedToGetContentPolicy = false; RefPtr nsContentUtils::sLineBreaker; RefPtr nsContentUtils::sWordBreaker; StaticRefPtr nsContentUtils::sBidiKeyboard; uint32_t nsContentUtils::sScriptBlockerCount = 0; uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0; AutoTArray, 8>* nsContentUtils::sBlockedScriptRunners = nullptr; uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0; nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr; bool nsContentUtils::sIsHandlingKeyBoardEvent = false; nsString* nsContentUtils::sShiftText = nullptr; nsString* nsContentUtils::sControlText = nullptr; nsString* nsContentUtils::sMetaText = nullptr; nsString* nsContentUtils::sOSText = nullptr; nsString* nsContentUtils::sAltText = nullptr; nsString* nsContentUtils::sModifierSeparator = nullptr; bool nsContentUtils::sInitialized = false; #ifndef RELEASE_OR_BETA bool nsContentUtils::sBypassCSSOMOriginCheck = false; #endif nsCString* nsContentUtils::sJSBytecodeMimeType = nullptr; nsContentUtils::UserInteractionObserver* nsContentUtils::sUserInteractionObserver = nullptr; nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr; nsIParser* nsContentUtils::sXMLFragmentParser = nullptr; nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr; bool nsContentUtils::sFragmentParsingActive = false; mozilla::LazyLogModule nsContentUtils::sDOMDumpLog("Dump"); int32_t nsContentUtils::sInnerOrOuterWindowCount = 0; uint32_t nsContentUtils::sInnerOrOuterWindowSerialCounter = 0; template Maybe nsContentUtils::ComparePoints( const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary); template Maybe nsContentUtils::ComparePoints( const RangeBoundary& aFirstBoundary, const RawRangeBoundary& aSecondBoundary); template Maybe nsContentUtils::ComparePoints( const RawRangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary); template Maybe nsContentUtils::ComparePoints( const RawRangeBoundary& aFirstBoundary, const RawRangeBoundary& aSecondBoundary); template int32_t nsContentUtils::ComparePoints_Deprecated( const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary, bool* aDisconnected); template int32_t nsContentUtils::ComparePoints_Deprecated( const RangeBoundary& aFirstBoundary, const RawRangeBoundary& aSecondBoundary, bool* aDisconnected); template int32_t nsContentUtils::ComparePoints_Deprecated( const RawRangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary, bool* aDisconnected); template int32_t nsContentUtils::ComparePoints_Deprecated( const RawRangeBoundary& aFirstBoundary, const RawRangeBoundary& aSecondBoundary, bool* aDisconnected); // Subset of // http://www.whatwg.org/specs/web-apps/current-work/#autofill-field-name enum AutocompleteUnsupportedFieldName : uint8_t { #define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \ eAutocompleteUnsupportedFieldName_##name_, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME }; enum AutocompleteNoPersistFieldName : uint8_t { #define AUTOCOMPLETE_NO_PERSIST_FIELD_NAME(name_, value_) \ eAutocompleteNoPersistFieldName_##name_, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_NO_PERSIST_FIELD_NAME }; enum AutocompleteUnsupportFieldContactHint : uint8_t { #define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \ eAutocompleteUnsupportedFieldContactHint_##name_, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT }; enum AutocompleteFieldName : uint8_t { #define AUTOCOMPLETE_FIELD_NAME(name_, value_) eAutocompleteFieldName_##name_, #define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \ AUTOCOMPLETE_FIELD_NAME(name_, value_) #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_FIELD_NAME #undef AUTOCOMPLETE_CONTACT_FIELD_NAME }; enum AutocompleteFieldHint : uint8_t { #define AUTOCOMPLETE_FIELD_HINT(name_, value_) eAutocompleteFieldHint_##name_, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_FIELD_HINT }; enum AutocompleteFieldContactHint : uint8_t { #define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \ eAutocompleteFieldContactHint_##name_, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_FIELD_CONTACT_HINT }; enum AutocompleteCategory { #define AUTOCOMPLETE_CATEGORY(name_, value_) eAutocompleteCategory_##name_, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_CATEGORY }; static const nsAttrValue::EnumTable kAutocompleteUnsupportedFieldNameTable[] = { #define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \ {value_, eAutocompleteUnsupportedFieldName_##name_}, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME {nullptr, 0}}; static const nsAttrValue::EnumTable kAutocompleteNoPersistFieldNameTable[] = { #define AUTOCOMPLETE_NO_PERSIST_FIELD_NAME(name_, value_) \ {value_, eAutocompleteNoPersistFieldName_##name_}, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_NO_PERSIST_FIELD_NAME {nullptr, 0}}; static const nsAttrValue::EnumTable kAutocompleteUnsupportedContactFieldHintTable[] = { #define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \ {value_, eAutocompleteUnsupportedFieldContactHint_##name_}, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT {nullptr, 0}}; static const nsAttrValue::EnumTable kAutocompleteFieldNameTable[] = { #define AUTOCOMPLETE_FIELD_NAME(name_, value_) \ {value_, eAutocompleteFieldName_##name_}, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_FIELD_NAME {nullptr, 0}}; static const nsAttrValue::EnumTable kAutocompleteContactFieldNameTable[] = { #define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \ {value_, eAutocompleteFieldName_##name_}, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_CONTACT_FIELD_NAME {nullptr, 0}}; static const nsAttrValue::EnumTable kAutocompleteFieldHintTable[] = { #define AUTOCOMPLETE_FIELD_HINT(name_, value_) \ {value_, eAutocompleteFieldHint_##name_}, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_FIELD_HINT {nullptr, 0}}; static const nsAttrValue::EnumTable kAutocompleteContactFieldHintTable[] = { #define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \ {value_, eAutocompleteFieldContactHint_##name_}, #include "AutocompleteFieldList.h" #undef AUTOCOMPLETE_FIELD_CONTACT_HINT {nullptr, 0}}; namespace { static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); static PLDHashTable* sEventListenerManagersHash; // A global hashtable to for keeping the arena alive for cross docGroup node // adoption. static nsRefPtrHashtable, mozilla::dom::DOMArena>* sDOMArenaHashtable; class DOMEventListenerManagersHashReporter final : public nsIMemoryReporter { MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) ~DOMEventListenerManagersHashReporter() = default; public: NS_DECL_ISUPPORTS NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize) override { // We don't measure the |EventListenerManager| objects pointed to by the // entries because those references are non-owning. int64_t amount = sEventListenerManagersHash ? sEventListenerManagersHash->ShallowSizeOfIncludingThis( MallocSizeOf) : 0; MOZ_COLLECT_REPORT( "explicit/dom/event-listener-managers-hash", KIND_HEAP, UNITS_BYTES, amount, "Memory used by the event listener manager's hash table."); return NS_OK; } }; NS_IMPL_ISUPPORTS(DOMEventListenerManagersHashReporter, nsIMemoryReporter) class EventListenerManagerMapEntry : public PLDHashEntryHdr { public: explicit EventListenerManagerMapEntry(const void* aKey) : mKey(aKey) {} ~EventListenerManagerMapEntry() { NS_ASSERTION(!mListenerManager, "caller must release and disconnect ELM"); } protected: // declared protected to silence clang warnings const void* mKey; // must be first, to look like PLDHashEntryStub public: RefPtr mListenerManager; }; static void EventListenerManagerHashInitEntry(PLDHashEntryHdr* entry, const void* key) { // Initialize the entry with placement new new (entry) EventListenerManagerMapEntry(key); } static void EventListenerManagerHashClearEntry(PLDHashTable* table, PLDHashEntryHdr* entry) { EventListenerManagerMapEntry* lm = static_cast(entry); // Let the EventListenerManagerMapEntry clean itself up... lm->~EventListenerManagerMapEntry(); } class SameOriginCheckerImpl final : public nsIChannelEventSink, public nsIInterfaceRequestor { ~SameOriginCheckerImpl() = default; NS_DECL_ISUPPORTS NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSIINTERFACEREQUESTOR }; } // namespace AutoSuppressEventHandlingAndSuspend::AutoSuppressEventHandlingAndSuspend( BrowsingContextGroup* aGroup) { for (const auto& bc : aGroup->Toplevels()) { SuppressBrowsingContext(bc); } } void AutoSuppressEventHandlingAndSuspend::SuppressBrowsingContext( BrowsingContext* aBC) { if (nsCOMPtr win = aBC->GetDOMWindow()) { if (RefPtr doc = win->GetExtantDoc()) { mDocuments.AppendElement(doc); mWindows.AppendElement(win->GetCurrentInnerWindow()); // Note: Document::SuppressEventHandling will also automatically suppress // event handling for any in-process sub-documents. However, since we need // to deal with cases where remote BrowsingContexts may be interleaved // with in-process ones, we still need to walk the entire tree ourselves. // This may be slightly redundant in some cases, but since event handling // suppressions maintain a count of current blockers, it does not cause // any problems. doc->SuppressEventHandling(); win->GetCurrentInnerWindow()->Suspend(); } } for (const auto& bc : aBC->Children()) { SuppressBrowsingContext(bc); } } AutoSuppressEventHandlingAndSuspend::~AutoSuppressEventHandlingAndSuspend() { for (const auto& win : mWindows) { win->Resume(); } for (const auto& doc : mDocuments) { doc->UnsuppressEventHandlingAndFireEvents(true); } } /** * This class is used to determine whether or not the user is currently * interacting with the browser. It listens to observer events to toggle the * value of the sUserActive static. * * This class is an internal implementation detail. * nsContentUtils::GetUserIsInteracting() should be used to access current * user interaction status. */ class nsContentUtils::UserInteractionObserver final : public nsIObserver, public BackgroundHangAnnotator { public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER void Init(); void Shutdown(); void AnnotateHang(BackgroundHangAnnotations& aAnnotations) override; static Atomic sUserActive; private: ~UserInteractionObserver() = default; }; // static nsresult nsContentUtils::Init() { if (sInitialized) { NS_WARNING("Init() called twice"); return NS_OK; } nsHTMLTags::AddRefTable(); sNameSpaceManager = nsNameSpaceManager::GetInstance(); NS_ENSURE_TRUE(sNameSpaceManager, NS_ERROR_OUT_OF_MEMORY); sXPConnect = nsXPConnect::XPConnect(); // We hold a strong ref to sXPConnect to ensure that it does not go away until // nsLayoutStatics::Shutdown is happening. Otherwise ~nsXPConnect can be // triggered by xpcModuleDtor late in shutdown and cause crashes due to // various stuff already being torn down by then. Note that this means that // we are effectively making sure that if we leak nsLayoutStatics then we also // leak nsXPConnect. NS_ADDREF(sXPConnect); sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager(); if (!sSecurityManager) return NS_ERROR_FAILURE; NS_ADDREF(sSecurityManager); sSecurityManager->GetSystemPrincipal(&sSystemPrincipal); MOZ_ASSERT(sSystemPrincipal); RefPtr nullPrincipal = NullPrincipal::CreateWithoutOriginAttributes(); if (!nullPrincipal) { return NS_ERROR_FAILURE; } nullPrincipal.forget(&sNullSubjectPrincipal); nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService); if (NS_FAILED(rv)) { // This makes life easier, but we can live without it. sIOService = nullptr; } sLineBreaker = mozilla::intl::LineBreaker::Create(); sWordBreaker = mozilla::intl::WordBreaker::Create(); if (!InitializeEventTable()) return NS_ERROR_FAILURE; if (!sEventListenerManagersHash) { static const PLDHashTableOps hash_table_ops = { PLDHashTable::HashVoidPtrKeyStub, PLDHashTable::MatchEntryStub, PLDHashTable::MoveEntryStub, EventListenerManagerHashClearEntry, EventListenerManagerHashInitEntry}; sEventListenerManagersHash = new PLDHashTable(&hash_table_ops, sizeof(EventListenerManagerMapEntry)); RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter()); } sBlockedScriptRunners = new AutoTArray, 8>; #ifndef RELEASE_OR_BETA sBypassCSSOMOriginCheck = getenv("MOZ_BYPASS_CSSOM_ORIGIN_CHECK"); #endif nsDependentCString buildID(mozilla::PlatformBuildID()); sJSBytecodeMimeType = new nsCString(NS_LITERAL_CSTRING("javascript/moz-bytecode-") + buildID); Element::InitCCCallbacks(); Unused << nsRFPService::GetOrCreate(); nsCOMPtr uuidGenerator = do_GetService("@mozilla.org/uuid-generator;1", &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } uuidGenerator.forget(&sUUIDGenerator); if (XRE_IsParentProcess()) { AsyncPrecreateStringBundles(); } RefPtr uio = new UserInteractionObserver(); uio->Init(); uio.forget(&sUserInteractionObserver); sInitialized = true; return NS_OK; } void nsContentUtils::GetShiftText(nsAString& text) { if (!sShiftText) InitializeModifierStrings(); text.Assign(*sShiftText); } void nsContentUtils::GetControlText(nsAString& text) { if (!sControlText) InitializeModifierStrings(); text.Assign(*sControlText); } void nsContentUtils::GetMetaText(nsAString& text) { if (!sMetaText) InitializeModifierStrings(); text.Assign(*sMetaText); } void nsContentUtils::GetOSText(nsAString& text) { if (!sOSText) { InitializeModifierStrings(); } text.Assign(*sOSText); } void nsContentUtils::GetAltText(nsAString& text) { if (!sAltText) InitializeModifierStrings(); text.Assign(*sAltText); } void nsContentUtils::GetModifierSeparatorText(nsAString& text) { if (!sModifierSeparator) InitializeModifierStrings(); text.Assign(*sModifierSeparator); } void nsContentUtils::InitializeModifierStrings() { // load the display strings for the keyboard accelerators nsCOMPtr bundleService = mozilla::services::GetStringBundleService(); nsCOMPtr bundle; DebugOnly rv = NS_OK; if (bundleService) { rv = bundleService->CreateBundle( "chrome://global-platform/locale/platformKeys.properties", getter_AddRefs(bundle)); } NS_ASSERTION( NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/platformKeys.properties could not be loaded"); nsAutoString shiftModifier; nsAutoString metaModifier; nsAutoString osModifier; nsAutoString altModifier; nsAutoString controlModifier; nsAutoString modifierSeparator; if (bundle) { // macs use symbols for each modifier key, so fetch each from the bundle, // which also covers i18n bundle->GetStringFromName("VK_SHIFT", shiftModifier); bundle->GetStringFromName("VK_META", metaModifier); bundle->GetStringFromName("VK_WIN", osModifier); bundle->GetStringFromName("VK_ALT", altModifier); bundle->GetStringFromName("VK_CONTROL", controlModifier); bundle->GetStringFromName("MODIFIER_SEPARATOR", modifierSeparator); } // if any of these don't exist, we get an empty string sShiftText = new nsString(shiftModifier); sMetaText = new nsString(metaModifier); sOSText = new nsString(osModifier); sAltText = new nsString(altModifier); sControlText = new nsString(controlModifier); sModifierSeparator = new nsString(modifierSeparator); } mozilla::EventClassID nsContentUtils::GetEventClassIDFromMessage( EventMessage aEventMessage) { switch (aEventMessage) { #define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \ case message_: \ return struct_; #include "mozilla/EventNameList.h" #undef MESSAGE_TO_EVENT default: MOZ_ASSERT_UNREACHABLE("Invalid event message?"); return eBasicEventClass; } } static nsAtom* GetEventTypeFromMessage(EventMessage aEventMessage) { switch (aEventMessage) { #define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \ case message_: \ return nsGkAtoms::on##name_; #include "mozilla/EventNameList.h" #undef MESSAGE_TO_EVENT default: return nullptr; } } // Because of SVG/SMIL we have several atoms mapped to the same // id, but we can rely on MESSAGE_TO_EVENT to map id to only one atom. static bool ShouldAddEventToStringEventTable(const EventNameMapping& aMapping) { MOZ_ASSERT(aMapping.mAtom); return GetEventTypeFromMessage(aMapping.mMessage) == aMapping.mAtom; } bool nsContentUtils::InitializeEventTable() { NS_ASSERTION(!sAtomEventTable, "EventTable already initialized!"); NS_ASSERTION(!sStringEventTable, "EventTable already initialized!"); static const EventNameMapping eventArray[] = { #define EVENT(name_, _message, _type, _class) \ {nsGkAtoms::on##name_, _type, _message, _class, false}, #define WINDOW_ONLY_EVENT EVENT #define DOCUMENT_ONLY_EVENT EVENT #define NON_IDL_EVENT EVENT #include "mozilla/EventNameList.h" #undef WINDOW_ONLY_EVENT #undef NON_IDL_EVENT #undef EVENT {nullptr}}; sAtomEventTable = new nsDataHashtable, EventNameMapping>( ArrayLength(eventArray)); sStringEventTable = new nsDataHashtable( ArrayLength(eventArray)); sUserDefinedEvents = new nsTArray>(64); // Subtract one from the length because of the trailing null for (uint32_t i = 0; i < ArrayLength(eventArray) - 1; ++i) { MOZ_ASSERT(!sAtomEventTable->Lookup(eventArray[i].mAtom), "Double-defining event name; fix your EventNameList.h"); sAtomEventTable->Put(eventArray[i].mAtom, eventArray[i]); if (ShouldAddEventToStringEventTable(eventArray[i])) { sStringEventTable->Put( Substring(nsDependentAtomString(eventArray[i].mAtom), 2), eventArray[i]); } } return true; } void nsContentUtils::InitializeTouchEventTable() { static bool sEventTableInitialized = false; if (!sEventTableInitialized && sAtomEventTable && sStringEventTable) { sEventTableInitialized = true; static const EventNameMapping touchEventArray[] = { #define EVENT(name_, _message, _type, _class) #define TOUCH_EVENT(name_, _message, _type, _class) \ {nsGkAtoms::on##name_, _type, _message, _class}, #include "mozilla/EventNameList.h" #undef TOUCH_EVENT #undef EVENT {nullptr}}; // Subtract one from the length because of the trailing null for (uint32_t i = 0; i < ArrayLength(touchEventArray) - 1; ++i) { sAtomEventTable->Put(touchEventArray[i].mAtom, touchEventArray[i]); sStringEventTable->Put( Substring(nsDependentAtomString(touchEventArray[i].mAtom), 2), touchEventArray[i]); } } } static bool Is8bit(const nsAString& aString) { static const char16_t EIGHT_BIT = char16_t(~0x00FF); for (nsAString::const_char_iterator start = aString.BeginReading(), end = aString.EndReading(); start != end; ++start) { if (*start & EIGHT_BIT) { return false; } } return true; } nsresult nsContentUtils::Btoa(const nsAString& aBinaryData, nsAString& aAsciiBase64String) { if (!Is8bit(aBinaryData)) { aAsciiBase64String.Truncate(); return NS_ERROR_DOM_INVALID_CHARACTER_ERR; } return Base64Encode(aBinaryData, aAsciiBase64String); } nsresult nsContentUtils::Atob(const nsAString& aAsciiBase64String, nsAString& aBinaryData) { if (!Is8bit(aAsciiBase64String)) { aBinaryData.Truncate(); return NS_ERROR_DOM_INVALID_CHARACTER_ERR; } const char16_t* start = aAsciiBase64String.BeginReading(); const char16_t* cur = start; const char16_t* end = aAsciiBase64String.EndReading(); bool hasWhitespace = false; while (cur < end) { if (nsContentUtils::IsHTMLWhitespace(*cur)) { hasWhitespace = true; break; } cur++; } nsresult rv; if (hasWhitespace) { nsString trimmedString; if (!trimmedString.SetCapacity(aAsciiBase64String.Length(), fallible)) { return NS_ERROR_DOM_INVALID_CHARACTER_ERR; } trimmedString.Append(start, cur - start); while (cur < end) { if (!nsContentUtils::IsHTMLWhitespace(*cur)) { trimmedString.Append(*cur); } cur++; } rv = Base64Decode(trimmedString, aBinaryData); } else { rv = Base64Decode(aAsciiBase64String, aBinaryData); } if (NS_FAILED(rv) && rv == NS_ERROR_INVALID_ARG) { return NS_ERROR_DOM_INVALID_CHARACTER_ERR; } return rv; } bool nsContentUtils::IsAutocompleteEnabled( mozilla::dom::HTMLInputElement* aInput) { MOZ_ASSERT(aInput, "aInput should not be null!"); nsAutoString autocomplete; aInput->GetAutocomplete(autocomplete); if (autocomplete.IsEmpty()) { auto* form = aInput->GetForm(); if (!form) { return true; } form->GetAutocomplete(autocomplete); } return !autocomplete.EqualsLiteral("off"); } nsContentUtils::AutocompleteAttrState nsContentUtils::SerializeAutocompleteAttribute( const nsAttrValue* aAttr, nsAString& aResult, AutocompleteAttrState aCachedState) { if (!aAttr || aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) { return aCachedState; } if (aCachedState == nsContentUtils::eAutocompleteAttrState_Valid) { uint32_t atomCount = aAttr->GetAtomCount(); for (uint32_t i = 0; i < atomCount; i++) { if (i != 0) { aResult.Append(' '); } aResult.Append(nsDependentAtomString(aAttr->AtomAt(i))); } nsContentUtils::ASCIIToLower(aResult); return aCachedState; } aResult.Truncate(); mozilla::dom::AutocompleteInfo info; AutocompleteAttrState state = InternalSerializeAutocompleteAttribute(aAttr, info); if (state == eAutocompleteAttrState_Valid) { // Concatenate the info fields. aResult = info.mSection; if (!info.mAddressType.IsEmpty()) { if (!aResult.IsEmpty()) { aResult += ' '; } aResult += info.mAddressType; } if (!info.mContactType.IsEmpty()) { if (!aResult.IsEmpty()) { aResult += ' '; } aResult += info.mContactType; } if (!info.mFieldName.IsEmpty()) { if (!aResult.IsEmpty()) { aResult += ' '; } aResult += info.mFieldName; } } return state; } nsContentUtils::AutocompleteAttrState nsContentUtils::SerializeAutocompleteAttribute( const nsAttrValue* aAttr, mozilla::dom::AutocompleteInfo& aInfo, AutocompleteAttrState aCachedState, bool aGrantAllValidValue) { if (!aAttr || aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) { return aCachedState; } return InternalSerializeAutocompleteAttribute(aAttr, aInfo, aGrantAllValidValue); } /** * Helper to validate the @autocomplete tokens. * * @return {AutocompleteAttrState} The state of the attribute (invalid/valid). */ nsContentUtils::AutocompleteAttrState nsContentUtils::InternalSerializeAutocompleteAttribute( const nsAttrValue* aAttrVal, mozilla::dom::AutocompleteInfo& aInfo, bool aGrantAllValidValue) { // No autocomplete attribute so we are done if (!aAttrVal) { return eAutocompleteAttrState_Invalid; } uint32_t numTokens = aAttrVal->GetAtomCount(); if (!numTokens) { return eAutocompleteAttrState_Invalid; } uint32_t index = numTokens - 1; nsString tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); AutocompleteCategory category; nsAttrValue enumValue; bool unsupported = false; if (!aGrantAllValidValue) { unsupported = enumValue.ParseEnumValue( tokenString, kAutocompleteUnsupportedFieldNameTable, false); if (unsupported) { return eAutocompleteAttrState_Invalid; } } nsAutoString str; bool result = enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, false); if (result) { // Off/Automatic/Normal categories. if (enumValue.Equals(NS_LITERAL_STRING("off"), eIgnoreCase) || enumValue.Equals(NS_LITERAL_STRING("on"), eIgnoreCase)) { if (numTokens > 1) { return eAutocompleteAttrState_Invalid; } enumValue.ToString(str); ASCIIToLower(str); aInfo.mFieldName.Assign(str); aInfo.mCanAutomaticallyPersist = !enumValue.Equals(NS_LITERAL_STRING("off"), eIgnoreCase); return eAutocompleteAttrState_Valid; } // Only allow on/off if form autofill @autocomplete values aren't enabled // and it doesn't grant all valid values. if (!StaticPrefs::dom_forms_autocomplete_formautofill() && !aGrantAllValidValue) { return eAutocompleteAttrState_Invalid; } // Normal category if (numTokens > 3) { return eAutocompleteAttrState_Invalid; } category = eAutocompleteCategory_NORMAL; } else { // Check if the last token is of the contact category instead. // Only allow on/off if form autofill @autocomplete values aren't enabled // and it doesn't grant all valid values. if (!StaticPrefs::dom_forms_autocomplete_formautofill() && !aGrantAllValidValue) { return eAutocompleteAttrState_Invalid; } result = enumValue.ParseEnumValue( tokenString, kAutocompleteContactFieldNameTable, false); if (!result || numTokens > 4) { return eAutocompleteAttrState_Invalid; } category = eAutocompleteCategory_CONTACT; } enumValue.ToString(str); ASCIIToLower(str); aInfo.mFieldName.Assign(str); aInfo.mCanAutomaticallyPersist = !enumValue.ParseEnumValue( tokenString, kAutocompleteNoPersistFieldNameTable, false); // We are done if this was the only token. if (numTokens == 1) { return eAutocompleteAttrState_Valid; } --index; tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); if (category == eAutocompleteCategory_CONTACT) { if (!aGrantAllValidValue) { unsupported = enumValue.ParseEnumValue( tokenString, kAutocompleteUnsupportedContactFieldHintTable, false); if (unsupported) { return eAutocompleteAttrState_Invalid; } } nsAttrValue contactFieldHint; result = contactFieldHint.ParseEnumValue( tokenString, kAutocompleteContactFieldHintTable, false); if (result) { nsAutoString contactFieldHintString; contactFieldHint.ToString(contactFieldHintString); ASCIIToLower(contactFieldHintString); aInfo.mContactType.Assign(contactFieldHintString); if (index == 0) { return eAutocompleteAttrState_Valid; } --index; tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); } } // Check for billing/shipping tokens nsAttrValue fieldHint; if (fieldHint.ParseEnumValue(tokenString, kAutocompleteFieldHintTable, false)) { nsString fieldHintString; fieldHint.ToString(fieldHintString); ASCIIToLower(fieldHintString); aInfo.mAddressType.Assign(fieldHintString); if (index == 0) { return eAutocompleteAttrState_Valid; } --index; tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); } // Check for section-* token const nsDependentSubstring& section = Substring(tokenString, 0, 8); if (section.LowerCaseEqualsASCII("section-")) { ASCIIToLower(tokenString); aInfo.mSection.Assign(tokenString); if (index == 0) { return eAutocompleteAttrState_Valid; } } // Clear the fields as the autocomplete attribute is invalid. aInfo.mSection.Truncate(); aInfo.mAddressType.Truncate(); aInfo.mContactType.Truncate(); aInfo.mFieldName.Truncate(); return eAutocompleteAttrState_Invalid; } // Parse an integer according to HTML spec template int32_t nsContentUtils::ParseHTMLIntegerImpl( const StringT& aValue, ParseHTMLIntegerResultFlags* aResult) { using CharT = typename StringT::char_type; int result = eParseHTMLInteger_NoFlags; typename StringT::const_iterator iter, end; aValue.BeginReading(iter); aValue.EndReading(end); while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { result |= eParseHTMLInteger_NonStandard; ++iter; } if (iter == end) { result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorNoValue; *aResult = (ParseHTMLIntegerResultFlags)result; return 0; } int sign = 1; if (*iter == CharT('-')) { sign = -1; result |= eParseHTMLInteger_Negative; ++iter; } else if (*iter == CharT('+')) { result |= eParseHTMLInteger_NonStandard; ++iter; } bool foundValue = false; CheckedInt32 value = 0; // Check for leading zeros first. uint64_t leadingZeros = 0; while (iter != end) { if (*iter != CharT('0')) { break; } ++leadingZeros; foundValue = true; ++iter; } while (iter != end) { if (*iter >= CharT('0') && *iter <= CharT('9')) { value = (value * 10) + (*iter - CharT('0')) * sign; ++iter; if (!value.isValid()) { result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorOverflow; break; } foundValue = true; } else { break; } } if (!foundValue) { result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorNoValue; } if (value.isValid() && ((leadingZeros > 1 || (leadingZeros == 1 && !(value == 0))) || (sign == -1 && value == 0))) { result |= eParseHTMLInteger_NonStandard; } if (iter != end) { result |= eParseHTMLInteger_DidNotConsumeAllInput; } *aResult = (ParseHTMLIntegerResultFlags)result; return value.isValid() ? value.value() : 0; } // Parse an integer according to HTML spec int32_t nsContentUtils::ParseHTMLInteger(const nsAString& aValue, ParseHTMLIntegerResultFlags* aResult) { return ParseHTMLIntegerImpl(aValue, aResult); } int32_t nsContentUtils::ParseHTMLInteger(const nsACString& aValue, ParseHTMLIntegerResultFlags* aResult) { return ParseHTMLIntegerImpl(aValue, aResult); } #define SKIP_WHITESPACE(iter, end_iter, end_res) \ while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \ ++(iter); \ } \ if ((iter) == (end_iter)) { \ return (end_res); \ } #define SKIP_ATTR_NAME(iter, end_iter) \ while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \ *(iter) != '=') { \ ++(iter); \ } bool nsContentUtils::GetPseudoAttributeValue(const nsString& aSource, nsAtom* aName, nsAString& aValue) { aValue.Truncate(); const char16_t* start = aSource.get(); const char16_t* end = start + aSource.Length(); const char16_t* iter; while (start != end) { SKIP_WHITESPACE(start, end, false) iter = start; SKIP_ATTR_NAME(iter, end) if (start == iter) { return false; } // Remember the attr name. const nsDependentSubstring& attrName = Substring(start, iter); // Now check whether this is a valid name="value" pair. start = iter; SKIP_WHITESPACE(start, end, false) if (*start != '=') { // No '=', so this is not a name="value" pair. We don't know // what it is, and we have no way to handle it. return false; } // Have to skip the value. ++start; SKIP_WHITESPACE(start, end, false) char16_t q = *start; if (q != kQuote && q != kApostrophe) { // Not a valid quoted value, so bail. return false; } ++start; // Point to the first char of the value. iter = start; while (iter != end && *iter != q) { ++iter; } if (iter == end) { // Oops, unterminated quoted string. return false; } // At this point attrName holds the name of the "attribute" and // the value is between start and iter. if (aName->Equals(attrName)) { // We'll accumulate as many characters as possible (until we hit either // the end of the string or the beginning of an entity). Chunks will be // delimited by start and chunkEnd. const char16_t* chunkEnd = start; while (chunkEnd != iter) { if (*chunkEnd == kLessThan) { aValue.Truncate(); return false; } if (*chunkEnd == kAmpersand) { aValue.Append(start, chunkEnd - start); const char16_t* afterEntity = nullptr; char16_t result[2]; uint32_t count = MOZ_XMLTranslateEntity( reinterpret_cast(chunkEnd), reinterpret_cast(iter), reinterpret_cast(&afterEntity), result); if (count == 0) { aValue.Truncate(); return false; } aValue.Append(result, count); // Advance to after the entity and begin a new chunk. start = chunkEnd = afterEntity; } else { ++chunkEnd; } } // Append remainder. aValue.Append(start, iter - start); return true; } // Resume scanning after the end of the attribute value (past the quote // char). start = iter + 1; } return false; } bool nsContentUtils::IsJavaScriptLanguage(const nsString& aName) { return aName.LowerCaseEqualsLiteral("javascript") || aName.LowerCaseEqualsLiteral("livescript") || aName.LowerCaseEqualsLiteral("mocha") || aName.LowerCaseEqualsLiteral("javascript1.0") || aName.LowerCaseEqualsLiteral("javascript1.1") || aName.LowerCaseEqualsLiteral("javascript1.2") || aName.LowerCaseEqualsLiteral("javascript1.3") || aName.LowerCaseEqualsLiteral("javascript1.4") || aName.LowerCaseEqualsLiteral("javascript1.5"); } void nsContentUtils::SplitMimeType(const nsAString& aValue, nsString& aType, nsString& aParams) { aType.Truncate(); aParams.Truncate(); int32_t semiIndex = aValue.FindChar(char16_t(';')); if (-1 != semiIndex) { aType = Substring(aValue, 0, semiIndex); aParams = Substring(aValue, semiIndex + 1, aValue.Length() - (semiIndex + 1)); aParams.StripWhitespace(); } else { aType = aValue; } aType.StripWhitespace(); } nsresult nsContentUtils::IsUserIdle(uint32_t aRequestedIdleTimeInMS, bool* aUserIsIdle) { nsresult rv; nsCOMPtr idleService = do_GetService("@mozilla.org/widget/idleservice;1", &rv); NS_ENSURE_SUCCESS(rv, rv); uint32_t idleTimeInMS; rv = idleService->GetIdleTime(&idleTimeInMS); NS_ENSURE_SUCCESS(rv, rv); *aUserIsIdle = idleTimeInMS >= aRequestedIdleTimeInMS; return NS_OK; } /** * A helper function that parses a sandbox attribute (of an