From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- dom/base/nsContentUtils.cpp | 9783 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 9783 insertions(+) create mode 100644 dom/base/nsContentUtils.cpp (limited to 'dom/base/nsContentUtils.cpp') diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp new file mode 100644 index 000000000..29d28f8ce --- /dev/null +++ b/dom/base/nsContentUtils.cpp @@ -0,0 +1,9783 @@ +/* -*- 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/Value.h" +#include "Layers.h" +#include "MediaDecoder.h" +// nsNPAPIPluginInstance must be included before nsIDocument.h, which is included in mozAutoDocUpdate.h. +#include "nsNPAPIPluginInstance.h" +#include "gfxDrawable.h" +#include "gfxPrefs.h" +#include "ImageOps.h" +#include "mozAutoDocUpdate.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/Attributes.h" +#include "mozilla/AutoRestore.h" +#include "mozilla/AutoTimelineMarker.h" +#include "mozilla/Base64.h" +#include "mozilla/CheckedInt.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/LoadInfo.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/CustomElementRegistry.h" +#include "mozilla/dom/DocumentFragment.h" +#include "mozilla/dom/DOMTypes.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/FileSystemSecurity.h" +#include "mozilla/dom/HTMLMediaElement.h" +#include "mozilla/dom/HTMLTemplateElement.h" +#include "mozilla/dom/HTMLContentElement.h" +#include "mozilla/dom/HTMLShadowElement.h" +#include "mozilla/dom/ipc/BlobChild.h" +#include "mozilla/dom/ipc/BlobParent.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/ScriptSettings.h" +#include "mozilla/dom/TabParent.h" +#include "mozilla/dom/TextDecoder.h" +#include "mozilla/dom/TouchEvent.h" +#include "mozilla/dom/ShadowRoot.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/workers/ServiceWorkerManager.h" +#include "mozilla/EventDispatcher.h" +#include "mozilla/EventListenerManager.h" +#include "mozilla/EventStateManager.h" +#include "mozilla/gfx/DataSurfaceHelpers.h" +#include "mozilla/IMEStateManager.h" +#include "mozilla/InternalMutationEvent.h" +#include "mozilla/Likely.h" +#include "mozilla/MouseEvents.h" +#include "mozilla/Preferences.h" +#include "mozilla/dom/Selection.h" +#include "mozilla/TextEvents.h" +#include "nsArrayUtils.h" +#include "nsAString.h" +#include "nsAttrName.h" +#include "nsAttrValue.h" +#include "nsAttrValueInlines.h" +#include "nsBindingManager.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 "nsCPrefetchService.h" +#include "nsCRT.h" +#include "nsCycleCollectionParticipant.h" +#include "nsCycleCollector.h" +#include "nsDataHashtable.h" +#include "nsDocShellCID.h" +#include "nsDocument.h" +#include "nsDOMCID.h" +#include "mozilla/dom/DataTransfer.h" +#include "nsDOMJSUtils.h" +#include "nsDOMMutationObserver.h" +#include "nsError.h" +#include "nsFocusManager.h" +#include "nsGenericHTMLElement.h" +#include "nsGenericHTMLFrameElement.h" +#include "nsGkAtoms.h" +#include "nsHostObjectProtocolHandler.h" +#include "nsHtml5Module.h" +#include "nsHtml5StringParser.h" +#include "nsIAddonPolicyService.h" +#include "nsIAsyncVerifyRedirectCallback.h" +#include "nsICategoryManager.h" +#include "nsIChannelEventSink.h" +#include "nsICharsetDetectionObserver.h" +#include "nsIChromeRegistry.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 "nsIDocument.h" +#include "nsIDocumentEncoder.h" +#include "nsIDOMChromeWindow.h" +#include "nsIDOMDocument.h" +#include "nsIDOMDocumentType.h" +#include "nsIDOMEvent.h" +#include "nsIDOMElement.h" +#include "nsIDOMHTMLElement.h" +#include "nsIDOMHTMLFormElement.h" +#include "nsIDOMHTMLInputElement.h" +#include "nsIDOMNode.h" +#include "nsIDOMNodeList.h" +#include "nsIDOMWindowUtils.h" +#include "nsIDOMXULCommandEvent.h" +#include "nsIDragService.h" +#include "nsIEditor.h" +#include "nsIFormControl.h" +#include "nsIForm.h" +#include "nsIFragmentContentSink.h" +#include "nsContainerFrame.h" +#include "nsIHTMLDocument.h" +#include "nsIIdleService.h" +#include "nsIImageLoadingContent.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIIOService.h" +#include "nsILineBreaker.h" +#include "nsILoadContext.h" +#include "nsILoadGroup.h" +#include "nsIMemoryReporter.h" +#include "nsIMIMEHeaderParam.h" +#include "nsIMIMEService.h" +#include "nsINode.h" +#include "mozilla/dom/NodeInfo.h" +#include "nsIObjectLoadingContent.h" +#include "nsIObserver.h" +#include "nsIObserverService.h" +#include "nsIOfflineCacheUpdate.h" +#include "nsIParser.h" +#include "nsIParserService.h" +#include "nsIPermissionManager.h" +#include "nsIPluginHost.h" +#include "nsIRequest.h" +#include "nsIRunnable.h" +#include "nsIScriptContext.h" +#include "nsIScriptError.h" +#include "nsIScriptGlobalObject.h" +#include "nsIScriptObjectPrincipal.h" +#include "nsIScriptSecurityManager.h" +#include "nsIScrollable.h" +#include "nsIStreamConverterService.h" +#include "nsIStringBundle.h" +#include "nsIURI.h" +#include "nsIURIWithPrincipal.h" +#include "nsIURL.h" +#include "nsIWebNavigation.h" +#include "nsIWindowMediator.h" +#include "nsIWordBreaker.h" +#include "nsIXPConnect.h" +#include "nsJSUtils.h" +#include "nsLWBrkCIID.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" +#include "nsNodeInfoManager.h" +#include "nsNullPrincipal.h" +#include "nsParserCIID.h" +#include "nsParserConstants.h" +#include "nsPIDOMWindow.h" +#include "nsPresContext.h" +#include "nsPrintfCString.h" +#include "nsReferencedElement.h" +#include "nsSandboxFlags.h" +#include "nsScriptSecurityManager.h" +#include "nsStreamUtils.h" +#include "nsTextEditorState.h" +#include "nsTextFragment.h" +#include "nsTextNode.h" +#include "nsThreadUtils.h" +#include "nsUnicharUtilCIID.h" +#include "nsUnicodeProperties.h" +#include "nsViewManager.h" +#include "nsViewportInfo.h" +#include "nsWidgetsCID.h" +#include "nsIWindowProvider.h" +#include "nsWrapperCacheInlines.h" +#include "nsXULPopupManager.h" +#include "xpcprivate.h" // nsXPConnect +#include "HTMLSplitOnSpacesTokenizer.h" +#include "nsContentTypeParser.h" +#include "nsICookiePermission.h" +#include "mozIThirdPartyUtil.h" +#include "nsICookieService.h" +#include "mozilla/EnumSet.h" +#include "mozilla/BloomFilter.h" +#include "TabChild.h" +#include "mozilla/dom/DocGroup.h" +#include "mozilla/dom/TabGroup.h" + +#include "nsIBidiKeyboard.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; + +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; +nsIParserService *nsContentUtils::sParserService = nullptr; +nsNameSpaceManager *nsContentUtils::sNameSpaceManager; +nsIIOService *nsContentUtils::sIOService; +nsIUUIDGenerator *nsContentUtils::sUUIDGenerator; +nsIConsoleService *nsContentUtils::sConsoleService; +nsDataHashtable* nsContentUtils::sAtomEventTable = nullptr; +nsDataHashtable* nsContentUtils::sStringEventTable = nullptr; +nsCOMArray* nsContentUtils::sUserDefinedEvents = nullptr; +nsIStringBundleService *nsContentUtils::sStringBundleService; +nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT]; +nsIContentPolicy *nsContentUtils::sContentPolicyService; +bool nsContentUtils::sTriedToGetContentPolicy = false; +nsILineBreaker *nsContentUtils::sLineBreaker; +nsIWordBreaker *nsContentUtils::sWordBreaker; +nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nullptr; +uint32_t nsContentUtils::sScriptBlockerCount = 0; +uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0; +uint32_t nsContentUtils::sMicroTaskLevel = 0; +AutoTArray, 8>* nsContentUtils::sBlockedScriptRunners = nullptr; +uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0; +nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr; + +bool nsContentUtils::sIsHandlingKeyBoardEvent = false; +bool nsContentUtils::sAllowXULXBL_for_file = 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; +bool nsContentUtils::sIsFullScreenApiEnabled = false; +bool nsContentUtils::sIsUnprefixedFullscreenApiEnabled = false; +bool nsContentUtils::sTrustedFullScreenOnly = true; +bool nsContentUtils::sIsCutCopyAllowed = true; +bool nsContentUtils::sIsFrameTimingPrefEnabled = false; +bool nsContentUtils::sIsPerformanceTimingEnabled = false; +bool nsContentUtils::sIsResourceTimingEnabled = false; +bool nsContentUtils::sIsUserTimingLoggingEnabled = false; +bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false; +bool nsContentUtils::sEncodeDecodeURLHash = false; +bool nsContentUtils::sGettersDecodeURLHash = false; +bool nsContentUtils::sPrivacyResistFingerprinting = false; +bool nsContentUtils::sSendPerformanceTimingNotifications = false; +bool nsContentUtils::sUseActivityCursor = false; + +uint32_t nsContentUtils::sHandlingInputTimeout = 1000; + +uint32_t nsContentUtils::sCookiesLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; +uint32_t nsContentUtils::sCookiesBehavior = nsICookieService::BEHAVIOR_ACCEPT; + +nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr; +nsIParser* nsContentUtils::sXMLFragmentParser = nullptr; +nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr; +bool nsContentUtils::sFragmentParsingActive = false; + +#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP)) +bool nsContentUtils::sDOMWindowDumpEnabled; +#endif + +bool nsContentUtils::sDoNotTrackEnabled = false; + +mozilla::LazyLogModule nsContentUtils::sDOMDumpLog("Dump"); + +// Subset of http://www.whatwg.org/specs/web-apps/current-work/#autofill-field-name +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 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(kParserServiceCID, NS_PARSERSERVICE_CID); +static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); + +static PLDHashTable* sEventListenerManagersHash; + +class DOMEventListenerManagersHashReporter final : public nsIMemoryReporter +{ + MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) + + ~DOMEventListenerManagersHashReporter() {} + +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() {} + + NS_DECL_ISUPPORTS + NS_DECL_NSICHANNELEVENTSINK + NS_DECL_NSIINTERFACEREQUESTOR +}; + +class CharsetDetectionObserver final : public nsICharsetDetectionObserver +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf) override + { + mCharset = aCharset; + return NS_OK; + } + + const nsACString& GetResult() const + { + return mCharset; + } + +private: + nsCString mCharset; +}; + +} // namespace + +/* static */ +TimeDuration +nsContentUtils::HandlingUserInputTimeout() +{ + return TimeDuration::FromMilliseconds(sHandlingInputTimeout); +} + +// static +nsresult +nsContentUtils::Init() +{ + if (sInitialized) { + NS_WARNING("Init() called twice"); + + return NS_OK; + } + + sNameSpaceManager = nsNameSpaceManager::GetInstance(); + NS_ENSURE_TRUE(sNameSpaceManager, NS_ERROR_OUT_OF_MEMORY); + + sXPConnect = nsXPConnect::XPConnect(); + + sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager(); + if(!sSecurityManager) + return NS_ERROR_FAILURE; + NS_ADDREF(sSecurityManager); + + sSecurityManager->GetSystemPrincipal(&sSystemPrincipal); + MOZ_ASSERT(sSystemPrincipal); + + // We use the constructor here because we want infallible initialization; we + // apparently don't care whether sNullSubjectPrincipal has a sane URI or not. + RefPtr nullPrincipal = new nsNullPrincipal(); + nullPrincipal->Init(); + 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; + } + + rv = CallGetService(NS_LBRK_CONTRACTID, &sLineBreaker); + NS_ENSURE_SUCCESS(rv, rv); + + rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker); + NS_ENSURE_SUCCESS(rv, rv); + + 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>; + + Preferences::AddBoolVarCache(&sAllowXULXBL_for_file, + "dom.allow_XUL_XBL_for_file"); + + Preferences::AddBoolVarCache(&sIsFullScreenApiEnabled, + "full-screen-api.enabled"); + + Preferences::AddBoolVarCache(&sIsUnprefixedFullscreenApiEnabled, + "full-screen-api.unprefix.enabled"); + + Preferences::AddBoolVarCache(&sTrustedFullScreenOnly, + "full-screen-api.allow-trusted-requests-only"); + + Preferences::AddBoolVarCache(&sIsCutCopyAllowed, + "dom.allow_cut_copy", true); + + Preferences::AddBoolVarCache(&sIsPerformanceTimingEnabled, + "dom.enable_performance", true); + + Preferences::AddBoolVarCache(&sIsResourceTimingEnabled, + "dom.enable_resource_timing", true); + + Preferences::AddBoolVarCache(&sIsUserTimingLoggingEnabled, + "dom.performance.enable_user_timing_logging", false); + + Preferences::AddBoolVarCache(&sIsFrameTimingPrefEnabled, + "dom.enable_frame_timing", false); + + Preferences::AddBoolVarCache(&sIsExperimentalAutocompleteEnabled, + "dom.forms.autocomplete.experimental", false); + + Preferences::AddBoolVarCache(&sEncodeDecodeURLHash, + "dom.url.encode_decode_hash", false); + + Preferences::AddBoolVarCache(&sGettersDecodeURLHash, + "dom.url.getters_decode_hash", false); + + Preferences::AddBoolVarCache(&sPrivacyResistFingerprinting, + "privacy.resistFingerprinting", false); + + Preferences::AddUintVarCache(&sHandlingInputTimeout, + "dom.event.handling-user-input-time-limit", + 1000); + + Preferences::AddBoolVarCache(&sSendPerformanceTimingNotifications, + "dom.performance.enable_notify_performance_timing", false); + + Preferences::AddUintVarCache(&sCookiesLifetimePolicy, + "network.cookie.lifetimePolicy", + nsICookieService::ACCEPT_NORMALLY); + + Preferences::AddUintVarCache(&sCookiesBehavior, + "network.cookie.cookieBehavior", + nsICookieService::BEHAVIOR_ACCEPT); + +#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP)) + Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled, + "browser.dom.window.dump.enabled"); +#endif + + Preferences::AddBoolVarCache(&sDoNotTrackEnabled, + "privacy.donottrackheader.enabled", false); + + Preferences::AddBoolVarCache(&sUseActivityCursor, + "ui.use_activity_cursor", false); + + Element::InitCCCallbacks(); + + nsCOMPtr uuidGenerator = + do_GetService("@mozilla.org/uuid-generator;1", &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + uuidGenerator.forget(&sUUIDGenerator); + + 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"); + nsXPIDLString shiftModifier; + nsXPIDLString metaModifier; + nsXPIDLString osModifier; + nsXPIDLString altModifier; + nsXPIDLString controlModifier; + nsXPIDLString modifierSeparator; + if (bundle) { + //macs use symbols for each modifier key, so fetch each from the bundle, which also covers i18n + bundle->GetStringFromName(u"VK_SHIFT", getter_Copies(shiftModifier)); + bundle->GetStringFromName(u"VK_META", getter_Copies(metaModifier)); + bundle->GetStringFromName(u"VK_WIN", getter_Copies(osModifier)); + bundle->GetStringFromName(u"VK_ALT", getter_Copies(altModifier)); + bundle->GetStringFromName(u"VK_CONTROL", getter_Copies(controlModifier)); + bundle->GetStringFromName(u"MODIFIER_SEPARATOR", getter_Copies(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); +} + +// 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) +{ + switch(aMapping.mMessage) { +#define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \ + case message_: return nsGkAtoms::on##name_ == aMapping.mAtom; +#include "mozilla/EventNameList.h" +#undef MESSAGE_TO_EVENT + default: + break; + } + return false; +} + +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 NON_IDL_EVENT EVENT +#include "mozilla/EventNameList.h" +#undef WINDOW_ONLY_EVENT +#undef NON_IDL_EVENT +#undef EVENT + { nullptr } + }; + + sAtomEventTable = new nsDataHashtable( + ArrayLength(eventArray)); + sStringEventTable = new nsDataHashtable( + ArrayLength(eventArray)); + sUserDefinedEvents = new nsCOMArray(64); + + // Subtract one from the length because of the trailing null + for (uint32_t i = 0; i < ArrayLength(eventArray) - 1; ++i) { + 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* end = aAsciiBase64String.EndReading(); + nsString trimmedString; + if (!trimmedString.SetCapacity(aAsciiBase64String.Length(), fallible)) { + return NS_ERROR_DOM_INVALID_CHARACTER_ERR; + } + while (start < end) { + if (!nsContentUtils::IsHTMLWhitespace(*start)) { + trimmedString.Append(*start); + } + start++; + } + nsresult rv = Base64Decode(trimmedString, aBinaryData); + if (NS_FAILED(rv) && rv == NS_ERROR_INVALID_ARG) { + return NS_ERROR_DOM_INVALID_CHARACTER_ERR; + } + return rv; +} + +bool +nsContentUtils::IsAutocompleteEnabled(nsIDOMHTMLInputElement* aInput) +{ + NS_PRECONDITION(aInput, "aInput should not be null!"); + + nsAutoString autocomplete; + aInput->GetAutocomplete(autocomplete); + + if (autocomplete.IsEmpty()) { + nsCOMPtr form; + aInput->GetForm(getter_AddRefs(form)); + 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) +{ + if (!aAttr || + aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) { + return aCachedState; + } + + return InternalSerializeAutocompleteAttribute(aAttr, aInfo); +} + +/** + * 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) +{ + // No sandbox 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; + + 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); + return eAutocompleteAttrState_Valid; + } + + // Only allow on/off if experimental @autocomplete values aren't enabled. + if (!sIsExperimentalAutocompleteEnabled) { + return eAutocompleteAttrState_Invalid; + } + + // Normal category + if (numTokens > 2) { + return eAutocompleteAttrState_Invalid; + } + category = eAutocompleteCategory_NORMAL; + } else { // Check if the last token is of the contact category instead. + // Only allow on/off if experimental @autocomplete values aren't enabled. + if (!sIsExperimentalAutocompleteEnabled) { + return eAutocompleteAttrState_Invalid; + } + + result = enumValue.ParseEnumValue(tokenString, kAutocompleteContactFieldNameTable, false); + if (!result || numTokens > 3) { + return eAutocompleteAttrState_Invalid; + } + + category = eAutocompleteCategory_CONTACT; + } + + enumValue.ToString(str); + ASCIIToLower(str); + aInfo.mFieldName.Assign(str); + + // 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) { + 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; + } + + // Clear the fields as the autocomplete attribute is invalid. + aInfo.mAddressType.Truncate(); + aInfo.mContactType.Truncate(); + aInfo.mFieldName.Truncate(); + + return eAutocompleteAttrState_Invalid; +} + +// Parse an integer according to HTML spec +int32_t +nsContentUtils::ParseHTMLInteger(const nsAString& aValue, + ParseHTMLIntegerResultFlags *aResult) +{ + int result = eParseHTMLInteger_NoFlags; + + nsAString::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 == char16_t('-')) { + sign = -1; + ++iter; + } else if (*iter == char16_t('+')) { + result |= eParseHTMLInteger_NonStandard; + ++iter; + } + + bool foundValue = false; + CheckedInt32 value = 0; + + // Check for leading zeros first. + uint64_t leadingZeros = 0; + while (iter != end) { + if (*iter != char16_t('0')) { + break; + } + + ++leadingZeros; + foundValue = true; + ++iter; + } + + while (iter != end) { + if (*iter >= char16_t('0') && *iter <= char16_t('9')) { + value = (value * 10) + (*iter - char16_t('0')) * sign; + ++iter; + if (!value.isValid()) { + result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorOverflow; + break; + } else { + foundValue = true; + } + } else if (*iter == char16_t('%')) { + ++iter; + result |= eParseHTMLInteger_IsPercent; + break; + } 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; +} + +#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, nsIAtom *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"); +} + +JSVersion +nsContentUtils::ParseJavascriptVersion(const nsAString& aVersionStr) +{ + if (aVersionStr.Length() != 3 || aVersionStr[0] != '1' || + aVersionStr[1] != '.') { + return JSVERSION_UNKNOWN; + } + + switch (aVersionStr[2]) { + case '0': /* fall through */ + case '1': /* fall through */ + case '2': /* fall through */ + case '3': /* fall through */ + case '4': /* fall through */ + case '5': return JSVERSION_DEFAULT; + case '6': return JSVERSION_1_6; + case '7': return JSVERSION_1_7; + case '8': return JSVERSION_1_8; + default: return JSVERSION_UNKNOWN; + } +} + +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; +} + +/** + * Access a cached parser service. Don't addref. We need only one + * reference to it and this class has that one. + */ +/* static */ +nsIParserService* +nsContentUtils::GetParserService() +{ + // XXX: This isn't accessed from several threads, is it? + if (!sParserService) { + // Lock, recheck sCachedParserService and aquire if this should be + // safe for multiple threads. + nsresult rv = CallGetService(kParserServiceCID, &sParserService); + if (NS_FAILED(rv)) { + sParserService = nullptr; + } + } + + return sParserService; +} + +/** +* A helper function that parses a sandbox attribute (of an