From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- dom/base/nsContentUtils.cpp | 11471 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 11471 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 0000000000..d849b13927 --- /dev/null +++ b/dom/base/nsContentUtils.cpp @@ -0,0 +1,11471 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include "BrowserChild.h" +#include "DecoderTraits.h" +#include "ErrorList.h" +#include "HTMLSplitOnSpacesTokenizer.h" +#include "ImageOps.h" +#include "InProcessBrowserChildMessageManager.h" +#include "MainThreadUtils.h" +#include "PLDHashTable.h" +#include "ReferrerInfo.h" +#include "ScopedNSSTypes.h" +#include "ThirdPartyUtil.h" +#include "Units.h" +#include "chrome/common/ipc_message.h" +#include "gfxDrawable.h" +#include "harfbuzz/hb.h" +#include "imgICache.h" +#include "imgIContainer.h" +#include "imgILoader.h" +#include "imgIRequest.h" +#include "imgLoader.h" +#include "js/Array.h" +#include "js/ArrayBuffer.h" +#include "js/BuildId.h" +#include "js/GCAPI.h" +#include "js/Id.h" +#include "js/JSON.h" +#include "js/PropertyAndElement.h" // JS_DefineElement, JS_GetProperty +#include "js/PropertyDescriptor.h" +#include "js/Realm.h" +#include "js/RegExp.h" +#include "js/RegExpFlags.h" +#include "js/RootingAPI.h" +#include "js/TypeDecls.h" +#include "js/Value.h" +#include "js/Wrapper.h" +#include "jsapi.h" +#include "jsfriendapi.h" +#include "mozAutoDocUpdate.h" +#include "mozIDOMWindow.h" +#include "nsIOService.h" +#include "nsObjectLoadingContent.h" +#include "mozilla/AlreadyAddRefed.h" +#include "mozilla/ArrayIterator.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/AsyncEventDispatcher.h" +#include "mozilla/AtomArray.h" +#include "mozilla/Atomics.h" +#include "mozilla/Attributes.h" +#include "mozilla/AutoRestore.h" +#include "mozilla/BackgroundHangMonitor.h" +#include "mozilla/Base64.h" +#include "mozilla/BasePrincipal.h" +#include "mozilla/BasicEvents.h" +#include "mozilla/BloomFilter.h" +#include "mozilla/CORSMode.h" +#include "mozilla/CallState.h" +#include "mozilla/CheckedInt.h" +#include "mozilla/ClearOnShutdown.h" +#include "mozilla/Components.h" +#include "mozilla/ContentBlockingAllowList.h" +#include "mozilla/CycleCollectedJSContext.h" +#include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/ErrorResult.h" +#include "mozilla/EventDispatcher.h" +#include "mozilla/EventListenerManager.h" +#include "mozilla/EventQueue.h" +#include "mozilla/EventStateManager.h" +#include "mozilla/FlushType.h" +#include "mozilla/FOGIPC.h" +#include "mozilla/HTMLEditor.h" +#include "mozilla/HangAnnotations.h" +#include "mozilla/IMEStateManager.h" +#include "mozilla/InputEventOptions.h" +#include "mozilla/InternalMutationEvent.h" +#include "mozilla/Latin1.h" +#include "mozilla/Likely.h" +#include "mozilla/LoadInfo.h" +#include "mozilla/Logging.h" +#include "mozilla/MacroForEach.h" +#include "mozilla/ManualNAC.h" +#include "mozilla/Maybe.h" +#include "mozilla/MediaFeatureChange.h" +#include "mozilla/MouseEvents.h" +#include "mozilla/NotNull.h" +#include "mozilla/NullPrincipal.h" +#include "mozilla/OriginAttributes.h" +#include "mozilla/Preferences.h" +#include "mozilla/PresShell.h" +#include "mozilla/ProfilerRunnable.h" +#include "mozilla/RangeBoundary.h" +#include "mozilla/RefPtr.h" +#include "mozilla/Result.h" +#include "mozilla/ResultExtensions.h" +#include "mozilla/ScrollbarPreferences.h" +#include "mozilla/ShutdownPhase.h" +#include "mozilla/Span.h" +#include "mozilla/StaticAnalysisFunctions.h" +#include "mozilla/StaticPrefs_browser.h" +#include "mozilla/StaticPrefs_dom.h" +#ifdef FUZZING +# include "mozilla/StaticPrefs_fuzzing.h" +#endif +#include "mozilla/StaticPrefs_nglayout.h" +#include "mozilla/StaticPrefs_privacy.h" +#include "mozilla/StaticPrefs_test.h" +#include "mozilla/StaticPrefs_ui.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/TextControlState.h" +#include "mozilla/TextEditor.h" +#include "mozilla/TextEvents.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Unused.h" +#include "mozilla/Variant.h" +#include "mozilla/ViewportUtils.h" +#include "mozilla/dom/AncestorIterator.h" +#include "mozilla/dom/AutoEntryScript.h" +#include "mozilla/dom/AutocompleteInfoBinding.h" +#include "mozilla/dom/AutoSuppressEventHandlingAndSuspend.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/BlobImpl.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" +#include "mozilla/dom/BorrowedAttrInfo.h" +#include "mozilla/dom/BrowserBridgeParent.h" +#include "mozilla/dom/BrowserParent.h" +#include "mozilla/dom/BrowsingContext.h" +#include "mozilla/dom/BrowsingContextGroup.h" +#include "mozilla/dom/CallbackFunction.h" +#include "mozilla/dom/CallbackObject.h" +#include "mozilla/dom/ChromeMessageBroadcaster.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/ContentFrameMessageManager.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/CustomElementRegistry.h" +#include "mozilla/dom/CustomElementRegistryBinding.h" +#include "mozilla/dom/CustomElementTypes.h" +#include "mozilla/dom/DOMArena.h" +#include "mozilla/dom/DOMException.h" +#include "mozilla/dom/DOMExceptionBinding.h" +#include "mozilla/dom/DOMSecurityMonitor.h" +#include "mozilla/dom/DOMTypes.h" +#include "mozilla/dom/DataTransfer.h" +#include "mozilla/dom/DocGroup.h" +#include "mozilla/dom/Document.h" +#include "mozilla/dom/DocumentFragment.h" +#include "mozilla/dom/DocumentInlines.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/ElementBinding.h" +#include "mozilla/dom/ElementInlines.h" +#include "mozilla/dom/Event.h" +#include "mozilla/dom/EventTarget.h" +#include "mozilla/dom/FileBlobImpl.h" +#include "mozilla/dom/FileSystemSecurity.h" +#include "mozilla/dom/FilteredNodeIterator.h" +#include "mozilla/dom/FormData.h" +#include "mozilla/dom/FragmentOrElement.h" +#include "mozilla/dom/FromParser.h" +#include "mozilla/dom/HTMLElement.h" +#include "mozilla/dom/HTMLFormElement.h" +#include "mozilla/dom/HTMLImageElement.h" +#include "mozilla/dom/HTMLInputElement.h" +#include "mozilla/dom/HTMLTextAreaElement.h" +#include "mozilla/dom/IPCBlob.h" +#include "mozilla/dom/IPCBlobUtils.h" +#include "mozilla/dom/MessageBroadcaster.h" +#include "mozilla/dom/MessageListenerManager.h" +#include "mozilla/dom/MessagePort.h" +#include "mozilla/dom/MouseEventBinding.h" +#include "mozilla/dom/NameSpaceConstants.h" +#include "mozilla/dom/NodeBinding.h" +#include "mozilla/dom/NodeInfo.h" +#include "mozilla/dom/PBrowser.h" +#include "mozilla/dom/PContentChild.h" +#include "mozilla/dom/PrototypeList.h" +#include "mozilla/dom/ReferrerPolicyBinding.h" +#include "mozilla/dom/ScriptSettings.h" +#include "mozilla/dom/Selection.h" +#include "mozilla/dom/ShadowRoot.h" +#include "mozilla/dom/Text.h" +#include "mozilla/dom/UserActivation.h" +#include "mozilla/dom/WindowContext.h" +#include "mozilla/dom/WorkerCommon.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerRunnable.h" +#include "mozilla/dom/XULCommandEvent.h" +#include "mozilla/glean/GleanPings.h" +#include "mozilla/fallible.h" +#include "mozilla/gfx/2D.h" +#include "mozilla/gfx/BaseMargin.h" +#include "mozilla/gfx/BasePoint.h" +#include "mozilla/gfx/BaseSize.h" +#include "mozilla/gfx/DataSurfaceHelpers.h" +#include "mozilla/gfx/Point.h" +#include "mozilla/gfx/Rect.h" +#include "mozilla/gfx/Types.h" +#include "mozilla/ipc/ProtocolUtils.h" +#include "mozilla/ipc/SharedMemory.h" +#include "mozilla/net/UrlClassifierCommon.h" +#include "mozilla/Tokenizer.h" +#include "mozilla/widget/IMEData.h" +#include "nsAboutProtocolUtils.h" +#include "nsAlgorithm.h" +#include "nsArrayUtils.h" +#include "nsAtomHashKeys.h" +#include "nsAttrName.h" +#include "nsAttrValue.h" +#include "nsAttrValueInlines.h" +#include "nsBaseHashtable.h" +#include "nsCCUncollectableMarker.h" +#include "nsCOMPtr.h" +#include "nsCRT.h" +#include "nsCRTGlue.h" +#include "nsCanvasFrame.h" +#include "nsCaseTreatment.h" +#include "nsCharSeparatedTokenizer.h" +#include "nsCharTraits.h" +#include "nsCompatibility.h" +#include "nsComponentManagerUtils.h" +#include "nsContainerFrame.h" +#include "nsContentCreatorFunctions.h" +#include "nsContentDLF.h" +#include "nsContentList.h" +#include "nsContentListDeclarations.h" +#include "nsContentPolicyUtils.h" +#include "nsCoord.h" +#include "nsCycleCollectionNoteChild.h" +#include "nsDOMMutationObserver.h" +#include "nsDOMString.h" +#include "nsTHashMap.h" +#include "nsDebug.h" +#include "nsDocShell.h" +#include "nsDocShellCID.h" +#include "nsError.h" +#include "nsFocusManager.h" +#include "nsFrameList.h" +#include "nsFrameLoader.h" +#include "nsFrameLoaderOwner.h" +#include "nsGenericHTMLElement.h" +#include "nsGkAtoms.h" +#include "nsGlobalWindowInner.h" +#include "nsGlobalWindowOuter.h" +#include "nsHTMLDocument.h" +#include "nsHTMLTags.h" +#include "nsHashKeys.h" +#include "nsHtml5StringParser.h" +#include "nsIAboutModule.h" +#include "nsIAnonymousContentCreator.h" +#include "nsIAppShell.h" +#include "nsIArray.h" +#include "nsIAsyncVerifyRedirectCallback.h" +#include "nsIBidiKeyboard.h" +#include "nsIBrowser.h" +#include "nsICacheInfoChannel.h" +#include "nsICategoryManager.h" +#include "nsIChannel.h" +#include "nsIChannelEventSink.h" +#include "nsIClassifiedChannel.h" +#include "nsIConsoleService.h" +#include "nsIContent.h" +#include "nsIContentInlines.h" +#include "nsIContentPolicy.h" +#include "nsIContentSecurityPolicy.h" +#include "nsIContentSink.h" +#include "nsIDOMWindowUtils.h" +#include "nsIDocShell.h" +#include "nsIDocShellTreeItem.h" +#include "nsIDocumentEncoder.h" +#include "nsIDocumentLoaderFactory.h" +#include "nsIDocumentViewer.h" +#include "nsIDragService.h" +#include "nsIDragSession.h" +#include "nsIFile.h" +#include "nsIFocusManager.h" +#include "nsIFormControl.h" +#include "nsIFragmentContentSink.h" +#include "nsIFrame.h" +#include "nsIGlobalObject.h" +#include "nsIHttpChannel.h" +#include "nsIHttpChannelInternal.h" +#include "nsIIOService.h" +#include "nsIImageLoadingContent.h" +#include "nsIInputStream.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsILoadContext.h" +#include "nsILoadGroup.h" +#include "nsILoadInfo.h" +#include "nsIMIMEService.h" +#include "nsIMemoryReporter.h" +#include "nsINetUtil.h" +#include "nsINode.h" +#include "nsIObjectLoadingContent.h" +#include "nsIObserver.h" +#include "nsIObserverService.h" +#include "nsIParserUtils.h" +#include "nsIPermissionManager.h" +#include "nsIPrincipal.h" +#include "nsIProperties.h" +#include "nsIProtocolHandler.h" +#include "nsIRequest.h" +#include "nsIRunnable.h" +#include "nsIScreen.h" +#include "nsIScriptError.h" +#include "nsIScriptGlobalObject.h" +#include "nsIScriptObjectPrincipal.h" +#include "nsIScriptSecurityManager.h" +#include "nsISerialEventTarget.h" +#include "nsIStreamConverter.h" +#include "nsIStreamConverterService.h" +#include "nsIStringBundle.h" +#include "nsISupports.h" +#include "nsISupportsPrimitives.h" +#include "nsISupportsUtils.h" +#include "nsITransferable.h" +#include "nsIURI.h" +#include "nsIURIMutator.h" +#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) +# include "nsIURIWithSpecialOrigin.h" +#endif +#include "nsIUserIdleServiceInternal.h" +#include "nsIWeakReferenceUtils.h" +#include "nsIWebNavigation.h" +#include "nsIWebNavigationInfo.h" +#include "nsIWidget.h" +#include "nsIWindowMediator.h" +#include "nsIXPConnect.h" +#include "nsJSPrincipals.h" +#include "nsJSUtils.h" +#include "nsLayoutUtils.h" +#include "nsLiteralString.h" +#include "nsMargin.h" +#include "nsMimeTypes.h" +#include "nsNameSpaceManager.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" +#include "nsNodeInfoManager.h" +#include "nsPIDOMWindow.h" +#include "nsPIDOMWindowInlines.h" +#include "nsParser.h" +#include "nsParserConstants.h" +#include "nsPoint.h" +#include "nsPointerHashKeys.h" +#include "nsPresContext.h" +#include "nsQueryFrame.h" +#include "nsQueryObject.h" +#include "nsRange.h" +#include "nsRefPtrHashtable.h" +#include "nsSandboxFlags.h" +#include "nsScriptSecurityManager.h" +#include "nsServiceManagerUtils.h" +#include "nsStreamUtils.h" +#include "nsString.h" +#include "nsStringBuffer.h" +#include "nsStringBundle.h" +#include "nsStringFlags.h" +#include "nsStringFwd.h" +#include "nsStringIterator.h" +#include "nsStringStream.h" +#include "nsTArray.h" +#include "nsTLiteralString.h" +#include "nsTPromiseFlatString.h" +#include "nsTStringRepr.h" +#include "nsTextFragment.h" +#include "nsTextNode.h" +#include "nsThreadManager.h" +#include "nsThreadUtils.h" +#include "nsTreeSanitizer.h" +#include "nsUGenCategory.h" +#include "nsURLHelper.h" +#include "nsUnicodeProperties.h" +#include "nsVariant.h" +#include "nsWidgetsCID.h" +#include "nsView.h" +#include "nsViewManager.h" +#include "nsXPCOM.h" +#include "nsXPCOMCID.h" +#include "nsXULAppAPI.h" +#include "nsXULElement.h" +#include "nsXULPopupManager.h" +#include "nscore.h" +#include "prinrval.h" +#include "xpcprivate.h" +#include "xpcpublic.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); + +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; +nsIConsoleService* nsContentUtils::sConsoleService; + +static nsTHashMap, EventNameMapping>* sAtomEventTable; +static nsTHashMap* sStringEventTable; +static nsTArray>* sUserDefinedEvents; +nsIStringBundleService* nsContentUtils::sStringBundleService; + +static StaticRefPtr + sStringBundles[nsContentUtils::PropertiesFile_COUNT]; + +nsIContentPolicy* nsContentUtils::sContentPolicyService; +bool nsContentUtils::sTriedToGetContentPolicy = false; +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::sCommandOrWinText = nullptr; +nsString* nsContentUtils::sAltText = nullptr; +nsString* nsContentUtils::sModifierSeparator = nullptr; + +bool nsContentUtils::sInitialized = false; +#ifndef RELEASE_OR_BETA +bool nsContentUtils::sBypassCSSOMOriginCheck = false; +#endif + +nsCString* nsContentUtils::sJSScriptBytecodeMimeType = nullptr; +nsCString* nsContentUtils::sJSModuleBytecodeMimeType = nullptr; + +nsContentUtils::UserInteractionObserver* + nsContentUtils::sUserInteractionObserver = nullptr; + +nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr; +nsParser* nsContentUtils::sXMLFragmentParser = nullptr; +nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr; +bool nsContentUtils::sFragmentParsingActive = false; + +bool nsContentUtils::sMayHaveFormCheckboxStateChangeListeners = false; +bool nsContentUtils::sMayHaveFormRadioStateChangeListeners = false; + +mozilla::LazyLogModule nsContentUtils::gResistFingerprintingLog( + "nsResistFingerprinting"); +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 AutocompleteCredentialType : uint8_t { +#define AUTOCOMPLETE_CREDENTIAL_TYPE(name_, value_) \ + eAutocompleteCredentialType_##name_, +#include "AutocompleteFieldList.h" +#undef AUTOCOMPLETE_CREDENTIAL_TYPE +}; + +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}}; + +static const nsAttrValue::EnumTable kAutocompleteCredentialTypeTable[] = { +#define AUTOCOMPLETE_CREDENTIAL_TYPE(name_, value_) \ + {value_, eAutocompleteCredentialType_##name_}, +#include "AutocompleteFieldList.h" +#undef AUTOCOMPLETE_CREDENTIAL_TYPE + {nullptr, 0}}; + +namespace { + +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 + +void AutoSuppressEventHandling::SuppressDocument(Document* aDoc) { + // 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. + aDoc->SuppressEventHandling(); +} + +void AutoSuppressEventHandling::UnsuppressDocument(Document* aDoc) { + aDoc->UnsuppressEventHandlingAndFireEvents(true); +} + +AutoSuppressEventHandling::~AutoSuppressEventHandling() { + UnsuppressDocuments(); +} + +void AutoSuppressEventHandlingAndSuspend::SuppressDocument(Document* aDoc) { + AutoSuppressEventHandling::SuppressDocument(aDoc); + if (nsCOMPtr win = aDoc->GetInnerWindow()) { + win->Suspend(); + mWindows.AppendElement(win); + } +} + +AutoSuppressEventHandlingAndSuspend::~AutoSuppressEventHandlingAndSuspend() { + for (const auto& win : mWindows) { + win->Resume(); + } +} + +/** + * 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 constexpr nsLiteralCString kRfpPrefs[] = { + "privacy.resistFingerprinting"_ns, + "privacy.resistFingerprinting.pbmode"_ns, + "privacy.fingerprintingProtection"_ns, + "privacy.fingerprintingProtection.pbmode"_ns, + "privacy.fingerprintingProtection.overrides"_ns, +}; + +static void RecomputeResistFingerprintingAllDocs(const char*, void*) { + AutoTArray, 5> bcGroups; + BrowsingContextGroup::GetAllGroups(bcGroups); + for (auto& bcGroup : bcGroups) { + AutoTArray docGroups; + bcGroup->GetDocGroups(docGroups); + for (auto* docGroup : docGroups) { + for (Document* doc : *docGroup) { + if (doc->RecomputeResistFingerprinting()) { + if (auto* pc = doc->GetPresContext()) { + pc->MediaFeatureValuesChanged( + {MediaFeatureChangeReason::PreferenceChange}, + MediaFeatureChangePropagation::JustThisDocument); + } + } + } + } + } +} + +// static +nsresult nsContentUtils::Init() { + if (sInitialized) { + NS_WARNING("Init() called twice"); + + return NS_OK; + } + + nsHTMLTags::AddRefTable(); + + 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); + + 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 + + Element::InitCCCallbacks(); + + RefPtr rfpService = nsRFPService::GetOrCreate(); + MOZ_ASSERT(rfpService); + + if (XRE_IsParentProcess()) { + AsyncPrecreateStringBundles(); + +#if defined(MOZ_WIDGET_ANDROID) + // On Android, at-shutdown ping submission isn't reliable + // (( because, on Android, we usually get killed, not shut down )). + // To have a chance at submitting the ping, aim for idle after startup. + nsresult rv = NS_DispatchToCurrentThreadQueue( + NS_NewRunnableFunction( + "AndroidUseCounterPingSubmitter", + []() { glean_pings::UseCounters.Submit("idle_startup"_ns); }), + EventQueuePriority::Idle); + // This is mostly best-effort, so if it goes awry, just log. + Unused << NS_WARN_IF(NS_FAILED(rv)); +#endif // defined(MOZ_WIDGET_ANDROID) + + RunOnShutdown( + [&] { glean_pings::UseCounters.Submit("app_shutdown_confirmed"_ns); }, + ShutdownPhase::AppShutdownConfirmed); + } + + RefPtr uio = new UserInteractionObserver(); + uio->Init(); + uio.forget(&sUserInteractionObserver); + + for (const auto& pref : kRfpPrefs) { + Preferences::RegisterCallback(RecomputeResistFingerprintingAllDocs, pref); + } + + sInitialized = true; + + return NS_OK; +} + +bool nsContentUtils::InitJSBytecodeMimeType() { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!sJSScriptBytecodeMimeType); + MOZ_ASSERT(!sJSModuleBytecodeMimeType); + + JS::BuildIdCharVector jsBuildId; + if (!JS::GetScriptTranscodingBuildId(&jsBuildId)) { + return false; + } + + nsDependentCSubstring jsBuildIdStr(jsBuildId.begin(), jsBuildId.length()); + sJSScriptBytecodeMimeType = + new nsCString("javascript/moz-script-bytecode-"_ns + jsBuildIdStr); + sJSModuleBytecodeMimeType = + new nsCString("javascript/moz-module-bytecode-"_ns + jsBuildIdStr); + return true; +} + +void nsContentUtils::GetShiftText(nsAString& text) { + if (!sShiftText) InitializeModifierStrings(); + text.Assign(*sShiftText); +} + +void nsContentUtils::GetControlText(nsAString& text) { + if (!sControlText) InitializeModifierStrings(); + text.Assign(*sControlText); +} + +void nsContentUtils::GetCommandOrWinText(nsAString& text) { + if (!sCommandOrWinText) { + InitializeModifierStrings(); + } + text.Assign(*sCommandOrWinText); +} + +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::components::StringBundle::Service(); + 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 commandOrWinModifier; + 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_COMMAND_OR_WIN", commandOrWinModifier); + 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); + sCommandOrWinText = new nsString(commandOrWinModifier); + 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; + } +} + +bool nsContentUtils::IsExternalProtocol(nsIURI* aURI) { + bool doesNotReturnData = false; + nsresult rv = NS_URIChainHasFlags( + aURI, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA, &doesNotReturnData); + return NS_SUCCEEDED(rv) && doesNotReturnData; +} + +/* static */ +nsAtom* nsContentUtils::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; + } +} + +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}, +#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 nsTHashMap, EventNameMapping>(ArrayLength(eventArray)); + sStringEventTable = new nsTHashMap( + 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->Contains(eventArray[i].mAtom), + "Double-defining event name; fix your EventNameList.h"); + sAtomEventTable->InsertOrUpdate(eventArray[i].mAtom, eventArray[i]); + sStringEventTable->InsertOrUpdate( + 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->InsertOrUpdate(touchEventArray[i].mAtom, + touchEventArray[i]); + sStringEventTable->InsertOrUpdate( + 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; + } + + // The autocomplete attribute value "webauthn" is interpreted as both a + // field name and a credential type. The corresponding IDL-exposed autofill + // value is "webauthn", not "webauthn webauthn". + if (!info.mCredentialType.IsEmpty() && + !(info.mCredentialType.Equals(u"webauthn"_ns) && + info.mCredentialType.Equals(aResult))) { + if (!aResult.IsEmpty()) { + aResult += ' '; + } + aResult += info.mCredentialType; + } + } + + 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 || numTokens > INT32_MAX) { + return eAutocompleteAttrState_Invalid; + } + + uint32_t index = numTokens - 1; + nsString tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); + AutocompleteCategory category; + nsAttrValue enumValue; + nsAutoString credentialTypeStr; + + bool result = enumValue.ParseEnumValue( + tokenString, kAutocompleteCredentialTypeTable, false); + if (result) { + if (!enumValue.Equals(u"webauthn"_ns, eIgnoreCase) || numTokens > 5) { + return eAutocompleteAttrState_Invalid; + } + enumValue.ToString(credentialTypeStr); + ASCIIToLower(credentialTypeStr); + // category is Credential and the indexth token is "webauthn" + if (index == 0) { + aInfo.mFieldName.Assign(credentialTypeStr); + aInfo.mCredentialType.Assign(credentialTypeStr); + return eAutocompleteAttrState_Valid; + } + + --index; + tokenString = nsDependentAtomString(aAttrVal->AtomAt(index)); + + // Only the Normal and Contact categories are allowed with webauthn + // - disallow Credential + if (enumValue.ParseEnumValue(tokenString, kAutocompleteCredentialTypeTable, + false)) { + return eAutocompleteAttrState_Invalid; + } + // - disallow Off and Automatic + if (enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, + false)) { + if (enumValue.Equals(u"off"_ns, eIgnoreCase) || + enumValue.Equals(u"on"_ns, eIgnoreCase)) { + return eAutocompleteAttrState_Invalid; + } + } + + // Proceed to process the remaining tokens as if "webauthn" was not present. + // We need to decrement numTokens to enforce the correct per-category limits + // on the maximum number of tokens. + --numTokens; + } + + bool unsupported = false; + if (!aGrantAllValidValue) { + unsupported = enumValue.ParseEnumValue( + tokenString, kAutocompleteUnsupportedFieldNameTable, false); + if (unsupported) { + return eAutocompleteAttrState_Invalid; + } + } + + nsAutoString fieldNameStr; + result = + enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, false); + + if (result) { + // Off/Automatic/Normal categories. + if (enumValue.Equals(u"off"_ns, eIgnoreCase) || + enumValue.Equals(u"on"_ns, eIgnoreCase)) { + if (numTokens > 1) { + return eAutocompleteAttrState_Invalid; + } + enumValue.ToString(fieldNameStr); + ASCIIToLower(fieldNameStr); + aInfo.mFieldName.Assign(fieldNameStr); + aInfo.mCredentialType.Assign(credentialTypeStr); + aInfo.mCanAutomaticallyPersist = + !enumValue.Equals(u"off"_ns, 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(fieldNameStr); + ASCIIToLower(fieldNameStr); + + aInfo.mFieldName.Assign(fieldNameStr); + aInfo.mCredentialType.Assign(credentialTypeStr); + 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(); + aInfo.mCredentialType.Truncate(); + + return eAutocompleteAttrState_Invalid; +} + +// Parse an integer according to HTML spec +template +int32_t nsContentUtils::ParseHTMLIntegerImpl( + const CharT* aStart, const CharT* aEnd, + ParseHTMLIntegerResultFlags* aResult) { + int result = eParseHTMLInteger_NoFlags; + + const CharT* iter = aStart; + + while (iter != aEnd && nsContentUtils::IsHTMLWhitespace(*iter)) { + result |= eParseHTMLInteger_NonStandard; + ++iter; + } + + if (iter == aEnd) { + 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 != aEnd) { + if (*iter != CharT('0')) { + break; + } + + ++leadingZeros; + foundValue = true; + ++iter; + } + + while (iter != aEnd) { + 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 != aEnd) { + result |= eParseHTMLInteger_DidNotConsumeAllInput; + } + + *aResult = (ParseHTMLIntegerResultFlags)result; + return value.isValid() ? value.value() : 0; +} + +// Parse an integer according to HTML spec +int32_t nsContentUtils::ParseHTMLInteger(const char16_t* aStart, + const char16_t* aEnd, + ParseHTMLIntegerResultFlags* aResult) { + return ParseHTMLIntegerImpl(aStart, aEnd, aResult); +} + +int32_t nsContentUtils::ParseHTMLInteger(const char* aStart, const char* aEnd, + ParseHTMLIntegerResultFlags* aResult) { + return ParseHTMLIntegerImpl(aStart, aEnd, 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) { + // Create MIME type as "text/" + given input + nsAutoString mimeType(u"text/"); + mimeType.Append(aName); + + return IsJavascriptMIMEType(mimeType); +} + +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(); +} + +/** + * A helper function that parses a sandbox attribute (of an