michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* A namespace class for static layout utilities. */ michael@0: michael@0: #include "nsContentUtils.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "prprf.h" michael@0: #include "nsCxPusher.h" michael@0: #include "DecoderTraits.h" michael@0: #include "harfbuzz/hb.h" michael@0: #include "imgICache.h" michael@0: #include "imgIContainer.h" michael@0: #include "imgINotificationObserver.h" michael@0: #include "imgLoader.h" michael@0: #include "imgRequestProxy.h" michael@0: #include "jsapi.h" michael@0: #include "jsfriendapi.h" michael@0: #include "js/OldDebugAPI.h" michael@0: #include "js/Value.h" michael@0: #include "Layers.h" michael@0: #include "MediaDecoder.h" michael@0: // nsNPAPIPluginInstance must be included before nsIDocument.h, which is included in mozAutoDocUpdate.h. michael@0: #include "nsNPAPIPluginInstance.h" michael@0: #include "mozAutoDocUpdate.h" michael@0: #include "mozilla/ArrayUtils.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/AutoRestore.h" michael@0: #include "mozilla/Base64.h" michael@0: #include "mozilla/DebugOnly.h" michael@0: #include "mozilla/dom/DocumentFragment.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "mozilla/dom/HTMLMediaElement.h" michael@0: #include "mozilla/dom/HTMLTemplateElement.h" michael@0: #include "mozilla/dom/HTMLContentElement.h" michael@0: #include "mozilla/dom/TextDecoder.h" michael@0: #include "mozilla/dom/TouchEvent.h" michael@0: #include "mozilla/dom/ShadowRoot.h" michael@0: #include "mozilla/EventDispatcher.h" michael@0: #include "mozilla/EventListenerManager.h" michael@0: #include "mozilla/EventStateManager.h" michael@0: #include "mozilla/IMEStateManager.h" michael@0: #include "mozilla/InternalMutationEvent.h" michael@0: #include "mozilla/Likely.h" michael@0: #include "mozilla/MouseEvents.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/dom/Selection.h" michael@0: #include "mozilla/TextEvents.h" michael@0: #include "nsAString.h" michael@0: #include "nsAttrName.h" michael@0: #include "nsAttrValue.h" michael@0: #include "nsAttrValueInlines.h" michael@0: #include "nsBindingManager.h" michael@0: #include "nsCCUncollectableMarker.h" michael@0: #include "nsChannelPolicy.h" michael@0: #include "nsCharSeparatedTokenizer.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsContentCreatorFunctions.h" michael@0: #include "nsContentDLF.h" michael@0: #include "nsContentList.h" michael@0: #include "nsContentPolicyUtils.h" michael@0: #include "nsCPrefetchService.h" michael@0: #include "nsCRT.h" michael@0: #include "nsCycleCollectionParticipant.h" michael@0: #include "nsCycleCollector.h" michael@0: #include "nsDataHashtable.h" michael@0: #include "nsDocShellCID.h" michael@0: #include "nsDocument.h" michael@0: #include "nsDOMCID.h" michael@0: #include "mozilla/dom/DataTransfer.h" michael@0: #include "nsDOMJSUtils.h" michael@0: #include "nsDOMMutationObserver.h" michael@0: #include "nsError.h" michael@0: #include "nsFocusManager.h" michael@0: #include "nsGenericHTMLElement.h" michael@0: #include "nsGenericHTMLFrameElement.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsHostObjectProtocolHandler.h" michael@0: #include "nsHtml5Module.h" michael@0: #include "nsHtml5StringParser.h" michael@0: #include "nsIAsyncVerifyRedirectCallback.h" michael@0: #include "nsICategoryManager.h" michael@0: #include "nsIChannelEventSink.h" michael@0: #include "nsIChannelPolicy.h" michael@0: #include "nsIChromeRegistry.h" michael@0: #include "nsIConsoleService.h" michael@0: #include "nsIContent.h" michael@0: #include "nsIContentSecurityPolicy.h" michael@0: #include "nsIContentSink.h" michael@0: #include "nsIContentViewer.h" michael@0: #include "nsIDocShell.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIDocumentEncoder.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsIDOMDocumentType.h" michael@0: #include "nsIDOMEvent.h" michael@0: #include "nsIDOMHTMLElement.h" michael@0: #include "nsIDOMHTMLFormElement.h" michael@0: #include "nsIDOMHTMLInputElement.h" michael@0: #include "nsIDOMNode.h" michael@0: #include "nsIDOMNodeList.h" michael@0: #include "nsIDOMScriptObjectFactory.h" michael@0: #include "nsIDOMUserDataHandler.h" michael@0: #include "nsIDOMXULCommandEvent.h" michael@0: #include "nsIDragService.h" michael@0: #include "nsIEditor.h" michael@0: #include "nsIFormControl.h" michael@0: #include "nsIForm.h" michael@0: #include "nsIFragmentContentSink.h" michael@0: #include "nsIFrame.h" michael@0: #include "nsIHTMLDocument.h" michael@0: #include "nsIIdleService.h" michael@0: #include "nsIImageLoadingContent.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsIIOService.h" michael@0: #include "nsIJSRuntimeService.h" michael@0: #include "nsILineBreaker.h" michael@0: #include "nsILoadContext.h" michael@0: #include "nsILoadGroup.h" michael@0: #include "nsIMemoryReporter.h" michael@0: #include "nsIMIMEService.h" michael@0: #include "nsINode.h" michael@0: #include "nsINodeInfo.h" michael@0: #include "nsIObjectLoadingContent.h" michael@0: #include "nsIObserver.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsIOfflineCacheUpdate.h" michael@0: #include "nsIParser.h" michael@0: #include "nsIParserService.h" michael@0: #include "nsIPermissionManager.h" michael@0: #include "nsIPluginHost.h" michael@0: #include "nsIRunnable.h" michael@0: #include "nsIScriptContext.h" michael@0: #include "nsIScriptError.h" michael@0: #include "nsIScriptGlobalObject.h" michael@0: #include "nsIScriptObjectPrincipal.h" michael@0: #include "nsIScriptSecurityManager.h" michael@0: #include "nsIStringBundle.h" michael@0: #include "nsIURI.h" michael@0: #include "nsIURL.h" michael@0: #include "nsIWebNavigation.h" michael@0: #include "nsIWordBreaker.h" michael@0: #include "nsIXPConnect.h" michael@0: #include "nsJSUtils.h" michael@0: #include "nsLWBrkCIID.h" michael@0: #include "nsNetCID.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsNodeInfoManager.h" michael@0: #include "nsNullPrincipal.h" michael@0: #include "nsParserCIID.h" michael@0: #include "nsParserConstants.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsPrintfCString.h" michael@0: #include "nsReferencedElement.h" michael@0: #include "nsSandboxFlags.h" michael@0: #include "nsScriptSecurityManager.h" michael@0: #include "nsSVGFeatures.h" michael@0: #include "nsTextEditorState.h" michael@0: #include "nsTextFragment.h" michael@0: #include "nsTextNode.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsUnicharUtilCIID.h" michael@0: #include "nsUnicodeProperties.h" michael@0: #include "nsViewManager.h" michael@0: #include "nsViewportInfo.h" michael@0: #include "nsWrapperCacheInlines.h" michael@0: #include "nsXULPopupManager.h" michael@0: #include "xpcprivate.h" // nsXPConnect michael@0: #include "HTMLSplitOnSpacesTokenizer.h" michael@0: #include "nsContentTypeParser.h" michael@0: #include "mozIThirdPartyUtil.h" michael@0: michael@0: #include "nsIBidiKeyboard.h" michael@0: michael@0: extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end, michael@0: const char** next, char16_t* result); michael@0: extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end, michael@0: int ns_aware, const char** colon); michael@0: michael@0: class imgLoader; michael@0: michael@0: using namespace mozilla::dom; michael@0: using namespace mozilla::layers; michael@0: using namespace mozilla::widget; michael@0: using namespace mozilla; michael@0: michael@0: const char kLoadAsData[] = "loadAsData"; michael@0: michael@0: nsIXPConnect *nsContentUtils::sXPConnect; michael@0: nsIScriptSecurityManager *nsContentUtils::sSecurityManager; michael@0: nsIParserService *nsContentUtils::sParserService = nullptr; michael@0: nsNameSpaceManager *nsContentUtils::sNameSpaceManager; michael@0: nsIIOService *nsContentUtils::sIOService; michael@0: nsIConsoleService *nsContentUtils::sConsoleService; michael@0: nsDataHashtable* nsContentUtils::sAtomEventTable = nullptr; michael@0: nsDataHashtable* nsContentUtils::sStringEventTable = nullptr; michael@0: nsCOMArray* nsContentUtils::sUserDefinedEvents = nullptr; michael@0: nsIStringBundleService *nsContentUtils::sStringBundleService; michael@0: nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT]; michael@0: nsIContentPolicy *nsContentUtils::sContentPolicyService; michael@0: bool nsContentUtils::sTriedToGetContentPolicy = false; michael@0: nsILineBreaker *nsContentUtils::sLineBreaker; michael@0: nsIWordBreaker *nsContentUtils::sWordBreaker; michael@0: nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nullptr; michael@0: uint32_t nsContentUtils::sScriptBlockerCount = 0; michael@0: #ifdef DEBUG michael@0: uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0; michael@0: #endif michael@0: uint32_t nsContentUtils::sMicroTaskLevel = 0; michael@0: nsTArray< nsCOMPtr >* nsContentUtils::sBlockedScriptRunners = nullptr; michael@0: uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0; michael@0: nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr; michael@0: michael@0: bool nsContentUtils::sIsHandlingKeyBoardEvent = false; michael@0: bool nsContentUtils::sAllowXULXBL_for_file = false; michael@0: michael@0: nsString* nsContentUtils::sShiftText = nullptr; michael@0: nsString* nsContentUtils::sControlText = nullptr; michael@0: nsString* nsContentUtils::sMetaText = nullptr; michael@0: nsString* nsContentUtils::sOSText = nullptr; michael@0: nsString* nsContentUtils::sAltText = nullptr; michael@0: nsString* nsContentUtils::sModifierSeparator = nullptr; michael@0: michael@0: bool nsContentUtils::sInitialized = false; michael@0: bool nsContentUtils::sIsFullScreenApiEnabled = false; michael@0: bool nsContentUtils::sTrustedFullScreenOnly = true; michael@0: bool nsContentUtils::sFullscreenApiIsContentOnly = false; michael@0: bool nsContentUtils::sIsIdleObserverAPIEnabled = false; michael@0: bool nsContentUtils::sIsPerformanceTimingEnabled = false; michael@0: bool nsContentUtils::sIsResourceTimingEnabled = false; michael@0: michael@0: uint32_t nsContentUtils::sHandlingInputTimeout = 1000; michael@0: michael@0: nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr; michael@0: nsIParser* nsContentUtils::sXMLFragmentParser = nullptr; michael@0: nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr; michael@0: bool nsContentUtils::sFragmentParsingActive = false; michael@0: michael@0: #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP)) michael@0: bool nsContentUtils::sDOMWindowDumpEnabled; michael@0: #endif michael@0: michael@0: namespace { michael@0: michael@0: static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID); michael@0: static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); michael@0: michael@0: static PLDHashTable sEventListenerManagersHash; michael@0: michael@0: class DOMEventListenerManagersHashReporter MOZ_FINAL : public nsIMemoryReporter michael@0: { michael@0: MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) michael@0: michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, michael@0: nsISupports* aData) michael@0: { michael@0: // We don't measure the |EventListenerManager| objects pointed to by the michael@0: // entries because those references are non-owning. michael@0: int64_t amount = sEventListenerManagersHash.ops michael@0: ? PL_DHashTableSizeOfExcludingThis( michael@0: &sEventListenerManagersHash, nullptr, MallocSizeOf) michael@0: : 0; michael@0: michael@0: return MOZ_COLLECT_REPORT( michael@0: "explicit/dom/event-listener-managers-hash", KIND_HEAP, UNITS_BYTES, michael@0: amount, michael@0: "Memory used by the event listener manager's hash table."); michael@0: } michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(DOMEventListenerManagersHashReporter, nsIMemoryReporter) michael@0: michael@0: class EventListenerManagerMapEntry : public PLDHashEntryHdr michael@0: { michael@0: public: michael@0: EventListenerManagerMapEntry(const void *aKey) michael@0: : mKey(aKey) michael@0: { michael@0: } michael@0: michael@0: ~EventListenerManagerMapEntry() michael@0: { michael@0: NS_ASSERTION(!mListenerManager, "caller must release and disconnect ELM"); michael@0: } michael@0: michael@0: protected: // declared protected to silence clang warnings michael@0: const void *mKey; // must be first, to look like PLDHashEntryStub michael@0: michael@0: public: michael@0: nsRefPtr mListenerManager; michael@0: }; michael@0: michael@0: static bool michael@0: EventListenerManagerHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, michael@0: const void *key) michael@0: { michael@0: // Initialize the entry with placement new michael@0: new (entry) EventListenerManagerMapEntry(key); michael@0: return true; michael@0: } michael@0: michael@0: static void michael@0: EventListenerManagerHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) michael@0: { michael@0: EventListenerManagerMapEntry *lm = michael@0: static_cast(entry); michael@0: michael@0: // Let the EventListenerManagerMapEntry clean itself up... michael@0: lm->~EventListenerManagerMapEntry(); michael@0: } michael@0: michael@0: class SameOriginChecker MOZ_FINAL : public nsIChannelEventSink, michael@0: public nsIInterfaceRequestor michael@0: { michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSICHANNELEVENTSINK michael@0: NS_DECL_NSIINTERFACEREQUESTOR michael@0: }; michael@0: michael@0: class CharsetDetectionObserver MOZ_FINAL : public nsICharsetDetectionObserver michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf) michael@0: { michael@0: mCharset = aCharset; michael@0: return NS_OK; michael@0: } michael@0: michael@0: const nsACString& GetResult() const michael@0: { michael@0: return mCharset; michael@0: } michael@0: michael@0: private: michael@0: nsCString mCharset; michael@0: }; michael@0: michael@0: } // anonymous namespace michael@0: michael@0: /* static */ michael@0: TimeDuration michael@0: nsContentUtils::HandlingUserInputTimeout() michael@0: { michael@0: return TimeDuration::FromMilliseconds(sHandlingInputTimeout); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: nsContentUtils::Init() michael@0: { michael@0: if (sInitialized) { michael@0: NS_WARNING("Init() called twice"); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: sNameSpaceManager = nsNameSpaceManager::GetInstance(); michael@0: NS_ENSURE_TRUE(sNameSpaceManager, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: sXPConnect = nsXPConnect::XPConnect(); michael@0: michael@0: sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager(); michael@0: if(!sSecurityManager) michael@0: return NS_ERROR_FAILURE; michael@0: NS_ADDREF(sSecurityManager); michael@0: michael@0: // Getting the first context can trigger GC, so do this non-lazily. michael@0: sXPConnect->InitSafeJSContext(); michael@0: michael@0: nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService); michael@0: if (NS_FAILED(rv)) { michael@0: // This makes life easier, but we can live without it. michael@0: michael@0: sIOService = nullptr; michael@0: } michael@0: michael@0: rv = CallGetService(NS_LBRK_CONTRACTID, &sLineBreaker); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (!InitializeEventTable()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: if (!sEventListenerManagersHash.ops) { michael@0: static const PLDHashTableOps hash_table_ops = michael@0: { michael@0: PL_DHashAllocTable, michael@0: PL_DHashFreeTable, michael@0: PL_DHashVoidPtrKeyStub, michael@0: PL_DHashMatchEntryStub, michael@0: PL_DHashMoveEntryStub, michael@0: EventListenerManagerHashClearEntry, michael@0: PL_DHashFinalizeStub, michael@0: EventListenerManagerHashInitEntry michael@0: }; michael@0: michael@0: PL_DHashTableInit(&sEventListenerManagersHash, &hash_table_ops, michael@0: nullptr, sizeof(EventListenerManagerMapEntry), 16); michael@0: michael@0: RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter()); michael@0: } michael@0: michael@0: sBlockedScriptRunners = new nsTArray< nsCOMPtr >; michael@0: michael@0: Preferences::AddBoolVarCache(&sAllowXULXBL_for_file, michael@0: "dom.allow_XUL_XBL_for_file"); michael@0: michael@0: Preferences::AddBoolVarCache(&sIsFullScreenApiEnabled, michael@0: "full-screen-api.enabled"); michael@0: michael@0: // Note: We deliberately read this pref here because this code runs michael@0: // before the profile loads, so users' changes to this pref in about:config michael@0: // won't have any effect on behaviour. We don't really want users messing michael@0: // with this pref, as it affects the security model of the fullscreen API. michael@0: sFullscreenApiIsContentOnly = Preferences::GetBool("full-screen-api.content-only", false); michael@0: michael@0: Preferences::AddBoolVarCache(&sTrustedFullScreenOnly, michael@0: "full-screen-api.allow-trusted-requests-only"); michael@0: michael@0: sIsIdleObserverAPIEnabled = Preferences::GetBool("dom.idle-observers-api.enabled", true); michael@0: michael@0: Preferences::AddBoolVarCache(&sIsPerformanceTimingEnabled, michael@0: "dom.enable_performance", true); michael@0: michael@0: Preferences::AddBoolVarCache(&sIsResourceTimingEnabled, michael@0: "dom.enable_resource_timing", true); michael@0: michael@0: Preferences::AddUintVarCache(&sHandlingInputTimeout, michael@0: "dom.event.handling-user-input-time-limit", michael@0: 1000); michael@0: michael@0: #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP)) michael@0: Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled, michael@0: "browser.dom.window.dump.enabled"); michael@0: #endif michael@0: michael@0: Element::InitCCCallbacks(); michael@0: michael@0: sInitialized = true; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsContentUtils::GetShiftText(nsAString& text) michael@0: { michael@0: if (!sShiftText) michael@0: InitializeModifierStrings(); michael@0: text.Assign(*sShiftText); michael@0: } michael@0: michael@0: void michael@0: nsContentUtils::GetControlText(nsAString& text) michael@0: { michael@0: if (!sControlText) michael@0: InitializeModifierStrings(); michael@0: text.Assign(*sControlText); michael@0: } michael@0: michael@0: void michael@0: nsContentUtils::GetMetaText(nsAString& text) michael@0: { michael@0: if (!sMetaText) michael@0: InitializeModifierStrings(); michael@0: text.Assign(*sMetaText); michael@0: } michael@0: michael@0: void michael@0: nsContentUtils::GetOSText(nsAString& text) michael@0: { michael@0: if (!sOSText) { michael@0: InitializeModifierStrings(); michael@0: } michael@0: text.Assign(*sOSText); michael@0: } michael@0: michael@0: void michael@0: nsContentUtils::GetAltText(nsAString& text) michael@0: { michael@0: if (!sAltText) michael@0: InitializeModifierStrings(); michael@0: text.Assign(*sAltText); michael@0: } michael@0: michael@0: void michael@0: nsContentUtils::GetModifierSeparatorText(nsAString& text) michael@0: { michael@0: if (!sModifierSeparator) michael@0: InitializeModifierStrings(); michael@0: text.Assign(*sModifierSeparator); michael@0: } michael@0: michael@0: void michael@0: nsContentUtils::InitializeModifierStrings() michael@0: { michael@0: //load the display strings for the keyboard accelerators michael@0: nsCOMPtr bundleService = michael@0: mozilla::services::GetStringBundleService(); michael@0: nsCOMPtr bundle; michael@0: DebugOnly rv = NS_OK; michael@0: if (bundleService) { michael@0: rv = bundleService->CreateBundle( "chrome://global-platform/locale/platformKeys.properties", michael@0: getter_AddRefs(bundle)); michael@0: } michael@0: michael@0: NS_ASSERTION(NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/platformKeys.properties could not be loaded"); michael@0: nsXPIDLString shiftModifier; michael@0: nsXPIDLString metaModifier; michael@0: nsXPIDLString osModifier; michael@0: nsXPIDLString altModifier; michael@0: nsXPIDLString controlModifier; michael@0: nsXPIDLString modifierSeparator; michael@0: if (bundle) { michael@0: //macs use symbols for each modifier key, so fetch each from the bundle, which also covers i18n michael@0: bundle->GetStringFromName(MOZ_UTF16("VK_SHIFT"), getter_Copies(shiftModifier)); michael@0: bundle->GetStringFromName(MOZ_UTF16("VK_META"), getter_Copies(metaModifier)); michael@0: bundle->GetStringFromName(MOZ_UTF16("VK_WIN"), getter_Copies(osModifier)); michael@0: bundle->GetStringFromName(MOZ_UTF16("VK_ALT"), getter_Copies(altModifier)); michael@0: bundle->GetStringFromName(MOZ_UTF16("VK_CONTROL"), getter_Copies(controlModifier)); michael@0: bundle->GetStringFromName(MOZ_UTF16("MODIFIER_SEPARATOR"), getter_Copies(modifierSeparator)); michael@0: } michael@0: //if any of these don't exist, we get an empty string michael@0: sShiftText = new nsString(shiftModifier); michael@0: sMetaText = new nsString(metaModifier); michael@0: sOSText = new nsString(osModifier); michael@0: sAltText = new nsString(altModifier); michael@0: sControlText = new nsString(controlModifier); michael@0: sModifierSeparator = new nsString(modifierSeparator); michael@0: } michael@0: michael@0: bool michael@0: nsContentUtils::InitializeEventTable() { michael@0: NS_ASSERTION(!sAtomEventTable, "EventTable already initialized!"); michael@0: NS_ASSERTION(!sStringEventTable, "EventTable already initialized!"); michael@0: michael@0: static const EventNameMapping eventArray[] = { michael@0: #define EVENT(name_, _id, _type, _struct) \ michael@0: { nsGkAtoms::on##name_, _id, _type, _struct }, michael@0: #define WINDOW_ONLY_EVENT EVENT michael@0: #define NON_IDL_EVENT EVENT michael@0: #include "mozilla/EventNameList.h" michael@0: #undef WINDOW_ONLY_EVENT michael@0: #undef EVENT michael@0: { nullptr } michael@0: }; michael@0: michael@0: sAtomEventTable = new nsDataHashtable( michael@0: int(ArrayLength(eventArray) / 0.75) + 1); michael@0: sStringEventTable = new nsDataHashtable( michael@0: int(ArrayLength(eventArray) / 0.75) + 1); michael@0: sUserDefinedEvents = new nsCOMArray(64); michael@0: michael@0: // Subtract one from the length because of the trailing null michael@0: for (uint32_t i = 0; i < ArrayLength(eventArray) - 1; ++i) { michael@0: sAtomEventTable->Put(eventArray[i].mAtom, eventArray[i]); michael@0: sStringEventTable->Put(Substring(nsDependentAtomString(eventArray[i].mAtom), 2), michael@0: eventArray[i]); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: nsContentUtils::InitializeTouchEventTable() michael@0: { michael@0: static bool sEventTableInitialized = false; michael@0: if (!sEventTableInitialized && sAtomEventTable && sStringEventTable) { michael@0: sEventTableInitialized = true; michael@0: static const EventNameMapping touchEventArray[] = { michael@0: #define EVENT(name_, _id, _type, _struct) michael@0: #define TOUCH_EVENT(name_, _id, _type, _struct) \ michael@0: { nsGkAtoms::on##name_, _id, _type, _struct }, michael@0: #include "mozilla/EventNameList.h" michael@0: #undef TOUCH_EVENT michael@0: #undef EVENT michael@0: { nullptr } michael@0: }; michael@0: // Subtract one from the length because of the trailing null michael@0: for (uint32_t i = 0; i < ArrayLength(touchEventArray) - 1; ++i) { michael@0: sAtomEventTable->Put(touchEventArray[i].mAtom, touchEventArray[i]); michael@0: sStringEventTable->Put(Substring(nsDependentAtomString(touchEventArray[i].mAtom), 2), michael@0: touchEventArray[i]); michael@0: } michael@0: } michael@0: } michael@0: michael@0: static bool michael@0: Is8bit(const nsAString& aString) michael@0: { michael@0: static const char16_t EIGHT_BIT = char16_t(~0x00FF); michael@0: michael@0: nsAString::const_iterator done_reading; michael@0: aString.EndReading(done_reading); michael@0: michael@0: // for each chunk of |aString|... michael@0: uint32_t fragmentLength = 0; michael@0: nsAString::const_iterator iter; michael@0: for (aString.BeginReading(iter); iter != done_reading; michael@0: iter.advance(int32_t(fragmentLength))) { michael@0: fragmentLength = uint32_t(iter.size_forward()); michael@0: const char16_t* c = iter.get(); michael@0: const char16_t* fragmentEnd = c + fragmentLength; michael@0: michael@0: // for each character in this chunk... michael@0: while (c < fragmentEnd) { michael@0: if (*c++ & EIGHT_BIT) { michael@0: return false; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: nsresult michael@0: nsContentUtils::Btoa(const nsAString& aBinaryData, michael@0: nsAString& aAsciiBase64String) michael@0: { michael@0: if (!Is8bit(aBinaryData)) { michael@0: aAsciiBase64String.Truncate(); michael@0: return NS_ERROR_DOM_INVALID_CHARACTER_ERR; michael@0: } michael@0: michael@0: return Base64Encode(aBinaryData, aAsciiBase64String); michael@0: } michael@0: michael@0: nsresult michael@0: nsContentUtils::Atob(const nsAString& aAsciiBase64String, michael@0: nsAString& aBinaryData) michael@0: { michael@0: if (!Is8bit(aAsciiBase64String)) { michael@0: aBinaryData.Truncate(); michael@0: return NS_ERROR_DOM_INVALID_CHARACTER_ERR; michael@0: } michael@0: michael@0: const char16_t* start = aAsciiBase64String.BeginReading(); michael@0: const char16_t* end = aAsciiBase64String.EndReading(); michael@0: nsString trimmedString; michael@0: if (!trimmedString.SetCapacity(aAsciiBase64String.Length(), fallible_t())) { michael@0: return NS_ERROR_DOM_INVALID_CHARACTER_ERR; michael@0: } michael@0: while (start < end) { michael@0: if (!nsContentUtils::IsHTMLWhitespace(*start)) { michael@0: trimmedString.Append(*start); michael@0: } michael@0: start++; michael@0: } michael@0: nsresult rv = Base64Decode(trimmedString, aBinaryData); michael@0: if (NS_FAILED(rv) && rv == NS_ERROR_INVALID_ARG) { michael@0: return NS_ERROR_DOM_INVALID_CHARACTER_ERR; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: bool michael@0: nsContentUtils::IsAutocompleteEnabled(nsIDOMHTMLInputElement* aInput) michael@0: { michael@0: NS_PRECONDITION(aInput, "aInput should not be null!"); michael@0: michael@0: nsAutoString autocomplete; michael@0: aInput->GetAutocomplete(autocomplete); michael@0: michael@0: if (autocomplete.IsEmpty()) { michael@0: nsCOMPtr form; michael@0: aInput->GetForm(getter_AddRefs(form)); michael@0: if (!form) { michael@0: return true; michael@0: } michael@0: michael@0: form->GetAutocomplete(autocomplete); michael@0: } michael@0: michael@0: return autocomplete.EqualsLiteral("on"); michael@0: } michael@0: michael@0: #define SKIP_WHITESPACE(iter, end_iter, end_res) \ michael@0: while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \ michael@0: ++(iter); \ michael@0: } \ michael@0: if ((iter) == (end_iter)) { \ michael@0: return (end_res); \ michael@0: } michael@0: michael@0: #define SKIP_ATTR_NAME(iter, end_iter) \ michael@0: while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \ michael@0: *(iter) != '=') { \ michael@0: ++(iter); \ michael@0: } michael@0: michael@0: bool michael@0: nsContentUtils::GetPseudoAttributeValue(const nsString& aSource, nsIAtom *aName, michael@0: nsAString& aValue) michael@0: { michael@0: aValue.Truncate(); michael@0: michael@0: const char16_t *start = aSource.get(); michael@0: const char16_t *end = start + aSource.Length(); michael@0: const char16_t *iter; michael@0: michael@0: while (start != end) { michael@0: SKIP_WHITESPACE(start, end, false) michael@0: iter = start; michael@0: SKIP_ATTR_NAME(iter, end) michael@0: michael@0: if (start == iter) { michael@0: return false; michael@0: } michael@0: michael@0: // Remember the attr name. michael@0: const nsDependentSubstring & attrName = Substring(start, iter); michael@0: michael@0: // Now check whether this is a valid name="value" pair. michael@0: start = iter; michael@0: SKIP_WHITESPACE(start, end, false) michael@0: if (*start != '=') { michael@0: // No '=', so this is not a name="value" pair. We don't know michael@0: // what it is, and we have no way to handle it. michael@0: return false; michael@0: } michael@0: michael@0: // Have to skip the value. michael@0: ++start; michael@0: SKIP_WHITESPACE(start, end, false) michael@0: char16_t q = *start; michael@0: if (q != kQuote && q != kApostrophe) { michael@0: // Not a valid quoted value, so bail. michael@0: return false; michael@0: } michael@0: michael@0: ++start; // Point to the first char of the value. michael@0: iter = start; michael@0: michael@0: while (iter != end && *iter != q) { michael@0: ++iter; michael@0: } michael@0: michael@0: if (iter == end) { michael@0: // Oops, unterminated quoted string. michael@0: return false; michael@0: } michael@0: michael@0: // At this point attrName holds the name of the "attribute" and michael@0: // the value is between start and iter. michael@0: michael@0: if (aName->Equals(attrName)) { michael@0: // We'll accumulate as many characters as possible (until we hit either michael@0: // the end of the string or the beginning of an entity). Chunks will be michael@0: // delimited by start and chunkEnd. michael@0: const char16_t *chunkEnd = start; michael@0: while (chunkEnd != iter) { michael@0: if (*chunkEnd == kLessThan) { michael@0: aValue.Truncate(); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: if (*chunkEnd == kAmpersand) { michael@0: aValue.Append(start, chunkEnd - start); michael@0: michael@0: // Point to first character after the ampersand. michael@0: ++chunkEnd; michael@0: michael@0: const char16_t *afterEntity = nullptr; michael@0: char16_t result[2]; michael@0: uint32_t count = michael@0: MOZ_XMLTranslateEntity(reinterpret_cast(chunkEnd), michael@0: reinterpret_cast(iter), michael@0: reinterpret_cast(&afterEntity), michael@0: result); michael@0: if (count == 0) { michael@0: aValue.Truncate(); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: aValue.Append(result, count); michael@0: michael@0: // Advance to after the entity and begin a new chunk. michael@0: start = chunkEnd = afterEntity; michael@0: } michael@0: else { michael@0: ++chunkEnd; michael@0: } michael@0: } michael@0: michael@0: // Append remainder. michael@0: aValue.Append(start, iter - start); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // Resume scanning after the end of the attribute value (past the quote michael@0: // char). michael@0: start = iter + 1; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: nsContentUtils::IsJavaScriptLanguage(const nsString& aName) michael@0: { michael@0: return aName.LowerCaseEqualsLiteral("javascript") || michael@0: aName.LowerCaseEqualsLiteral("livescript") || michael@0: aName.LowerCaseEqualsLiteral("mocha") || michael@0: aName.LowerCaseEqualsLiteral("javascript1.0") || michael@0: aName.LowerCaseEqualsLiteral("javascript1.1") || michael@0: aName.LowerCaseEqualsLiteral("javascript1.2") || michael@0: aName.LowerCaseEqualsLiteral("javascript1.3") || michael@0: aName.LowerCaseEqualsLiteral("javascript1.4") || michael@0: aName.LowerCaseEqualsLiteral("javascript1.5"); michael@0: } michael@0: michael@0: JSVersion michael@0: nsContentUtils::ParseJavascriptVersion(const nsAString& aVersionStr) michael@0: { michael@0: if (aVersionStr.Length() != 3 || aVersionStr[0] != '1' || michael@0: aVersionStr[1] != '.') { michael@0: return JSVERSION_UNKNOWN; michael@0: } michael@0: michael@0: switch (aVersionStr[2]) { michael@0: case '0': /* fall through */ michael@0: case '1': /* fall through */ michael@0: case '2': /* fall through */ michael@0: case '3': /* fall through */ michael@0: case '4': /* fall through */ michael@0: case '5': return JSVERSION_DEFAULT; michael@0: case '6': return JSVERSION_1_6; michael@0: case '7': return JSVERSION_1_7; michael@0: case '8': return JSVERSION_1_8; michael@0: default: return JSVERSION_UNKNOWN; michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsContentUtils::SplitMimeType(const nsAString& aValue, nsString& aType, michael@0: nsString& aParams) michael@0: { michael@0: aType.Truncate(); michael@0: aParams.Truncate(); michael@0: int32_t semiIndex = aValue.FindChar(char16_t(';')); michael@0: if (-1 != semiIndex) { michael@0: aType = Substring(aValue, 0, semiIndex); michael@0: aParams = Substring(aValue, semiIndex + 1, michael@0: aValue.Length() - (semiIndex + 1)); michael@0: aParams.StripWhitespace(); michael@0: } michael@0: else { michael@0: aType = aValue; michael@0: } michael@0: aType.StripWhitespace(); michael@0: } michael@0: michael@0: nsresult michael@0: nsContentUtils::IsUserIdle(uint32_t aRequestedIdleTimeInMS, bool* aUserIsIdle) michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr idleService = michael@0: do_GetService("@mozilla.org/widget/idleservice;1", &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: uint32_t idleTimeInMS; michael@0: rv = idleService->GetIdleTime(&idleTimeInMS); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: *aUserIsIdle = idleTimeInMS >= aRequestedIdleTimeInMS; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /** michael@0: * Access a cached parser service. Don't addref. We need only one michael@0: * reference to it and this class has that one. michael@0: */ michael@0: /* static */ michael@0: nsIParserService* michael@0: nsContentUtils::GetParserService() michael@0: { michael@0: // XXX: This isn't accessed from several threads, is it? michael@0: if (!sParserService) { michael@0: // Lock, recheck sCachedParserService and aquire if this should be michael@0: // safe for multiple threads. michael@0: nsresult rv = CallGetService(kParserServiceCID, &sParserService); michael@0: if (NS_FAILED(rv)) { michael@0: sParserService = nullptr; michael@0: } michael@0: } michael@0: michael@0: return sParserService; michael@0: } michael@0: michael@0: /** michael@0: * A helper function that parses a sandbox attribute (of an