Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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 <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <new>
#include <utility>
#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 "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/AutoTimelineMarker.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/Components.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/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/TaskCategory.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/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/FragmentOrElement.h"
#include "mozilla/dom/FromParser.h"
#include "mozilla/dom/HTMLFormElement.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/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/widget/IMEData.h"
#include "nsAboutProtocolUtils.h"
#include "nsAlgorithm.h"
#include "nsArrayUtils.h"
#include "nsAtom.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 "nsIContentViewer.h"
#include "nsIDOMWindowUtils.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocumentEncoder.h"
#include "nsIDocumentLoaderFactory.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 "nsIPluginTag.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 "nsMappedAttributes.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 "nsPluginHost.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;
nsIIOService* nsContentUtils::sIOService;
nsIConsoleService* nsContentUtils::sConsoleService;
nsTHashMap<nsRefPtrHashKey<nsAtom>, EventNameMapping>*
nsContentUtils::sAtomEventTable = nullptr;
nsTHashMap<nsStringHashKey, EventNameMapping>*
nsContentUtils::sStringEventTable = nullptr;
nsTArray<RefPtr<nsAtom>>* nsContentUtils::sUserDefinedEvents = nullptr;
nsIStringBundleService* nsContentUtils::sStringBundleService;
static StaticRefPtr<nsIStringBundle>
sStringBundles[nsContentUtils::PropertiesFile_COUNT];
nsIContentPolicy* nsContentUtils::sContentPolicyService;
bool nsContentUtils::sTriedToGetContentPolicy = false;
StaticRefPtr<nsIBidiKeyboard> nsContentUtils::sBidiKeyboard;
uint32_t nsContentUtils::sScriptBlockerCount = 0;
uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
AutoTArray<nsCOMPtr<nsIRunnable>, 8>* nsContentUtils::sBlockedScriptRunners =
nullptr;
uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0;
nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr;
bool nsContentUtils::sIsHandlingKeyBoardEvent = false;
nsString* nsContentUtils::sShiftText = nullptr;
nsString* nsContentUtils::sControlText = nullptr;
nsString* nsContentUtils::sMetaText = nullptr;
nsString* nsContentUtils::sOSText = nullptr;
nsString* nsContentUtils::sAltText = nullptr;
nsString* nsContentUtils::sModifierSeparator = nullptr;
bool nsContentUtils::sInitialized = false;
#ifndef RELEASE_OR_BETA
bool nsContentUtils::sBypassCSSOMOriginCheck = false;
#endif
nsCString* nsContentUtils::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;
mozilla::LazyLogModule nsContentUtils::gResistFingerprintingLog(
"nsResistFingerprinting");
mozilla::LazyLogModule nsContentUtils::sDOMDumpLog("Dump");
int32_t nsContentUtils::sInnerOrOuterWindowCount = 0;
uint32_t nsContentUtils::sInnerOrOuterWindowSerialCounter = 0;
template Maybe<int32_t> nsContentUtils::ComparePoints(
const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary);
template Maybe<int32_t> nsContentUtils::ComparePoints(
const RangeBoundary& aFirstBoundary,
const RawRangeBoundary& aSecondBoundary);
template Maybe<int32_t> nsContentUtils::ComparePoints(
const RawRangeBoundary& aFirstBoundary,
const RangeBoundary& aSecondBoundary);
template Maybe<int32_t> 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
enum AutocompleteUnsupportedFieldName : uint8_t {
#define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \
eAutocompleteUnsupportedFieldName_##name_,
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME
};
enum AutocompleteNoPersistFieldName : uint8_t {
#define AUTOCOMPLETE_NO_PERSIST_FIELD_NAME(name_, value_) \
eAutocompleteNoPersistFieldName_##name_,
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_NO_PERSIST_FIELD_NAME
};
enum AutocompleteUnsupportFieldContactHint : uint8_t {
#define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \
eAutocompleteUnsupportedFieldContactHint_##name_,
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT
};
enum AutocompleteFieldName : uint8_t {
#define AUTOCOMPLETE_FIELD_NAME(name_, value_) eAutocompleteFieldName_##name_,
#define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \
AUTOCOMPLETE_FIELD_NAME(name_, value_)
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_FIELD_NAME
#undef AUTOCOMPLETE_CONTACT_FIELD_NAME
};
enum AutocompleteFieldHint : uint8_t {
#define AUTOCOMPLETE_FIELD_HINT(name_, value_) eAutocompleteFieldHint_##name_,
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_FIELD_HINT
};
enum AutocompleteFieldContactHint : uint8_t {
#define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \
eAutocompleteFieldContactHint_##name_,
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_FIELD_CONTACT_HINT
};
enum AutocompleteCategory {
#define AUTOCOMPLETE_CATEGORY(name_, value_) eAutocompleteCategory_##name_,
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_CATEGORY
};
static const nsAttrValue::EnumTable kAutocompleteUnsupportedFieldNameTable[] = {
#define AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME(name_, value_) \
{value_, eAutocompleteUnsupportedFieldName_##name_},
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_UNSUPPORTED_FIELD_NAME
{nullptr, 0}};
static const nsAttrValue::EnumTable kAutocompleteNoPersistFieldNameTable[] = {
#define AUTOCOMPLETE_NO_PERSIST_FIELD_NAME(name_, value_) \
{value_, eAutocompleteNoPersistFieldName_##name_},
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_NO_PERSIST_FIELD_NAME
{nullptr, 0}};
static const nsAttrValue::EnumTable
kAutocompleteUnsupportedContactFieldHintTable[] = {
#define AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT(name_, value_) \
{value_, eAutocompleteUnsupportedFieldContactHint_##name_},
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_UNSUPPORTED_FIELD_CONTACT_HINT
{nullptr, 0}};
static const nsAttrValue::EnumTable kAutocompleteFieldNameTable[] = {
#define AUTOCOMPLETE_FIELD_NAME(name_, value_) \
{value_, eAutocompleteFieldName_##name_},
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_FIELD_NAME
{nullptr, 0}};
static const nsAttrValue::EnumTable kAutocompleteContactFieldNameTable[] = {
#define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \
{value_, eAutocompleteFieldName_##name_},
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_CONTACT_FIELD_NAME
{nullptr, 0}};
static const nsAttrValue::EnumTable kAutocompleteFieldHintTable[] = {
#define AUTOCOMPLETE_FIELD_HINT(name_, value_) \
{value_, eAutocompleteFieldHint_##name_},
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_FIELD_HINT
{nullptr, 0}};
static const nsAttrValue::EnumTable kAutocompleteContactFieldHintTable[] = {
#define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \
{value_, eAutocompleteFieldContactHint_##name_},
#include "AutocompleteFieldList.h"
#undef AUTOCOMPLETE_FIELD_CONTACT_HINT
{nullptr, 0}};
namespace {
static PLDHashTable* sEventListenerManagersHash;
// A global hashtable to for keeping the arena alive for cross docGroup node
// adoption.
static nsRefPtrHashtable<nsPtrHashKey<const nsINode>, 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<EventListenerManager> 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<EventListenerManagerMapEntry*>(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<nsPIDOMWindowInner> 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<bool> sUserActive;
private:
~UserInteractionObserver() = default;
};
static constexpr nsLiteralCString kRfpPrefs[] = {
"privacy.resistFingerprinting"_ns,
"privacy.resistFingerprintingLite"_ns,
"privacy.resistFingerprintingLite.overrides"_ns,
"privacy.resistFingerprinting.testGranularityMask"_ns,
};
static void RecomputeResistFingerprintingAllDocs(const char*, void*) {
AutoTArray<RefPtr<BrowsingContextGroup>, 5> bcGroups;
BrowsingContextGroup::GetAllGroups(bcGroups);
for (auto& bcGroup : bcGroups) {
AutoTArray<DocGroup*, 5> docGroups;
bcGroup->GetDocGroups(docGroups);
for (auto* docGroup : docGroups) {
for (Document* doc : *docGroup) {
const bool old = doc->ShouldResistFingerprinting(
RFPTarget::IgnoreTargetAndReturnCachedValue);
doc->RecomputeResistFingerprinting();
if (old != doc->ShouldResistFingerprinting(
RFPTarget::IsAlwaysEnabledForPrecompute)) {
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 =
NullPrincipal::CreateWithoutOriginAttributes();
if (!nullPrincipal) {
return NS_ERROR_FAILURE;
}
nullPrincipal.forget(&sNullSubjectPrincipal);
nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
if (NS_FAILED(rv)) {
// This makes life easier, but we can live without it.
sIOService = nullptr;
}
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<nsCOMPtr<nsIRunnable>, 8>;
#ifndef RELEASE_OR_BETA
sBypassCSSOMOriginCheck = getenv("MOZ_BYPASS_CSSOM_ORIGIN_CHECK");
#endif
Element::InitCCCallbacks();
Unused << nsRFPService::GetOrCreate();
if (XRE_IsParentProcess()) {
AsyncPrecreateStringBundles();
}
RefPtr<UserInteractionObserver> 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::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<nsIStringBundleService> bundleService =
mozilla::components::StringBundle::Service();
nsCOMPtr<nsIStringBundle> bundle;
DebugOnly<nsresult> rv = NS_OK;
if (bundleService) {
rv = bundleService->CreateBundle(
getter_AddRefs(bundle));
}
NS_ASSERTION(
NS_SUCCEEDED(rv) && bundle,
nsAutoString shiftModifier;
nsAutoString metaModifier;
nsAutoString osModifier;
nsAutoString altModifier;
nsAutoString controlModifier;
nsAutoString modifierSeparator;
if (bundle) {
// macs use symbols for each modifier key, so fetch each from the bundle,
// which also covers i18n
bundle->GetStringFromName("VK_SHIFT", shiftModifier);
bundle->GetStringFromName("VK_META", metaModifier);
bundle->GetStringFromName("VK_WIN", osModifier);
bundle->GetStringFromName("VK_ALT", altModifier);
bundle->GetStringFromName("VK_CONTROL", controlModifier);
bundle->GetStringFromName("MODIFIER_SEPARATOR", modifierSeparator);
}
// if any of these don't exist, we get an empty string
sShiftText = new nsString(shiftModifier);
sMetaText = new nsString(metaModifier);
sOSText = new nsString(osModifier);
sAltText = new nsString(altModifier);
sControlText = new nsString(controlModifier);
sModifierSeparator = new nsString(modifierSeparator);
}
mozilla::EventClassID nsContentUtils::GetEventClassIDFromMessage(
EventMessage aEventMessage) {
switch (aEventMessage) {
#define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \
case message_: \
return struct_;
#include "mozilla/EventNameList.h"
#undef MESSAGE_TO_EVENT
default:
MOZ_ASSERT_UNREACHABLE("Invalid event message?");
return eBasicEventClass;
}
}
static nsAtom* GetEventTypeFromMessage(EventMessage aEventMessage) {
switch (aEventMessage) {
#define MESSAGE_TO_EVENT(name_, message_, type_, struct_) \
case message_: \
return nsGkAtoms::on##name_;
#include "mozilla/EventNameList.h"
#undef MESSAGE_TO_EVENT
default:
return nullptr;
}
}
// Because of SVG/SMIL we have several atoms mapped to the same
// id, but we can rely on MESSAGE_TO_EVENT to map id to only one atom.
static bool ShouldAddEventToStringEventTable(const EventNameMapping& aMapping) {
MOZ_ASSERT(aMapping.mAtom);
return GetEventTypeFromMessage(aMapping.mMessage) == aMapping.mAtom;
}
bool nsContentUtils::InitializeEventTable() {
NS_ASSERTION(!sAtomEventTable, "EventTable already initialized!");
NS_ASSERTION(!sStringEventTable, "EventTable already initialized!");
static const EventNameMapping eventArray[] = {
#define EVENT(name_, _message, _type, _class) \
{nsGkAtoms::on##name_, _type, _message, _class, false},
#define WINDOW_ONLY_EVENT EVENT
#define DOCUMENT_ONLY_EVENT EVENT
#define NON_IDL_EVENT EVENT
#include "mozilla/EventNameList.h"
#undef WINDOW_ONLY_EVENT
#undef NON_IDL_EVENT
#undef EVENT
{nullptr}};
sAtomEventTable = new nsTHashMap<nsRefPtrHashKey<nsAtom>, EventNameMapping>(
ArrayLength(eventArray));
sStringEventTable = new nsTHashMap<nsStringHashKey, EventNameMapping>(
ArrayLength(eventArray));
sUserDefinedEvents = new nsTArray<RefPtr<nsAtom>>(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]);
if (ShouldAddEventToStringEventTable(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;
}
}
return state;
}
nsContentUtils::AutocompleteAttrState
nsContentUtils::SerializeAutocompleteAttribute(
const nsAttrValue* aAttr, mozilla::dom::AutocompleteInfo& aInfo,
AutocompleteAttrState aCachedState, bool aGrantAllValidValue) {
if (!aAttr ||
aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) {
return aCachedState;
}
return InternalSerializeAutocompleteAttribute(aAttr, aInfo,
aGrantAllValidValue);
}
/**
* Helper to validate the @autocomplete tokens.
*
* @return {AutocompleteAttrState} The state of the attribute (invalid/valid).
*/
nsContentUtils::AutocompleteAttrState
nsContentUtils::InternalSerializeAutocompleteAttribute(
const nsAttrValue* aAttrVal, mozilla::dom::AutocompleteInfo& aInfo,
bool aGrantAllValidValue) {
// No autocomplete attribute so we are done
if (!aAttrVal) {
return eAutocompleteAttrState_Invalid;
}
uint32_t numTokens = aAttrVal->GetAtomCount();
if (!numTokens) {
return eAutocompleteAttrState_Invalid;
}
uint32_t index = numTokens - 1;
nsString tokenString = nsDependentAtomString(aAttrVal->AtomAt(index));
AutocompleteCategory category;
nsAttrValue enumValue;
bool unsupported = false;
if (!aGrantAllValidValue) {
unsupported = enumValue.ParseEnumValue(
tokenString, kAutocompleteUnsupportedFieldNameTable, false);
if (unsupported) {
return eAutocompleteAttrState_Invalid;
}
}
nsAutoString str;
bool result =
enumValue.ParseEnumValue(tokenString, kAutocompleteFieldNameTable, false);
if (result) {
// Off/Automatic/Normal categories.
if (enumValue.Equals(u"off"_ns, eIgnoreCase) ||
enumValue.Equals(u"on"_ns, eIgnoreCase)) {
if (numTokens > 1) {
return eAutocompleteAttrState_Invalid;
}
enumValue.ToString(str);
ASCIIToLower(str);
aInfo.mFieldName.Assign(str);
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(str);
ASCIIToLower(str);
aInfo.mFieldName.Assign(str);
aInfo.mCanAutomaticallyPersist = !enumValue.ParseEnumValue(
tokenString, kAutocompleteNoPersistFieldNameTable, false);
// We are done if this was the only token.
if (numTokens == 1) {
return eAutocompleteAttrState_Valid;
}
--index;
tokenString = nsDependentAtomString(aAttrVal->AtomAt(index));
if (category == eAutocompleteCategory_CONTACT) {
if (!aGrantAllValidValue) {
unsupported = enumValue.ParseEnumValue(
tokenString, kAutocompleteUnsupportedContactFieldHintTable, false);
if (unsupported) {
return eAutocompleteAttrState_Invalid;
}
}
nsAttrValue contactFieldHint;
result = contactFieldHint.ParseEnumValue(
tokenString, kAutocompleteContactFieldHintTable, false);
if (result) {
nsAutoString contactFieldHintString;
contactFieldHint.ToString(contactFieldHintString);
ASCIIToLower(contactFieldHintString);
aInfo.mContactType.Assign(contactFieldHintString);
if (index == 0) {
return eAutocompleteAttrState_Valid;
}
--index;
tokenString = nsDependentAtomString(aAttrVal->AtomAt(index));
}
}
// Check for billing/shipping tokens
nsAttrValue fieldHint;
if (fieldHint.ParseEnumValue(tokenString, kAutocompleteFieldHintTable,
false)) {
nsString fieldHintString;
fieldHint.ToString(fieldHintString);
ASCIIToLower(fieldHintString);
aInfo.mAddressType.Assign(fieldHintString);
if (index == 0) {
return eAutocompleteAttrState_Valid;
}
--index;
tokenString = nsDependentAtomString(aAttrVal->AtomAt(index));
}
// Check for section-* token
const nsDependentSubstring& section = Substring(tokenString, 0, 8);
if (section.LowerCaseEqualsASCII("section-")) {
ASCIIToLower(tokenString);
aInfo.mSection.Assign(tokenString);
if (index == 0) {
return eAutocompleteAttrState_Valid;
}
}
// Clear the fields as the autocomplete attribute is invalid.
aInfo.mSection.Truncate();
aInfo.mAddressType.Truncate();
aInfo.mContactType.Truncate();
aInfo.mFieldName.Truncate();
return eAutocompleteAttrState_Invalid;
}
// Parse an integer according to HTML spec
template <class CharT>
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<const char*>(chunkEnd),
reinterpret_cast<const char*>(iter),
reinterpret_cast<const char**>(&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 =