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.h | 3751 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3751 insertions(+) create mode 100644 dom/base/nsContentUtils.h (limited to 'dom/base/nsContentUtils.h') diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h new file mode 100644 index 0000000000..95744fe831 --- /dev/null +++ b/dom/base/nsContentUtils.h @@ -0,0 +1,3751 @@ +/* -*- 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 content utilities. */ + +#ifndef nsContentUtils_h___ +#define nsContentUtils_h___ + +#if defined(XP_WIN) +# include +#endif + +#if defined(SOLARIS) +# include +#endif + +#include +#include +#include +#include +#include +#include "ErrorList.h" +#include "Units.h" +#include "js/Id.h" +#include "js/RegExpFlags.h" +#include "js/RootingAPI.h" +#include "mozilla/AlreadyAddRefed.h" +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/BasicEvents.h" +#include "mozilla/CORSMode.h" +#include "mozilla/CallState.h" +#include "mozilla/Maybe.h" +#include "mozilla/RefPtr.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/FromParser.h" +#include "mozilla/fallible.h" +#include "mozilla/gfx/Point.h" +#include "nsCOMPtr.h" +#include "nsIContentPolicy.h" +#include "nsINode.h" +#include "nsIScriptError.h" +#include "nsIThread.h" +#include "nsLiteralString.h" +#include "nsMargin.h" +#include "nsPIDOMWindow.h" +#include "nsRFPService.h" +#include "nsStringFwd.h" +#include "nsTArray.h" +#include "nsTLiteralString.h" +#include "prtime.h" + +#if defined(XP_WIN) +// Undefine LoadImage to prevent naming conflict with Windows. +# undef LoadImage +#endif + +class JSObject; +class imgICache; +class imgIContainer; +class imgINotificationObserver; +class imgIRequest; +class imgLoader; +class imgRequestProxy; +class nsAtom; +class nsAttrValue; +class nsAutoScriptBlockerSuppressNodeRemoved; +class nsContentList; +class nsCycleCollectionTraversalCallback; +class nsDocShell; +class nsGlobalWindowInner; +class nsHtml5StringParser; +class nsIArray; +class nsIBidiKeyboard; +class nsIChannel; +class nsIConsoleService; +class nsIContent; +class nsIDocShell; +class nsIDocShellTreeItem; +class nsIDocumentLoaderFactory; +class nsIDragSession; +class nsIFile; +class nsIFragmentContentSink; +class nsIFrame; +class nsIHttpChannel; +class nsIIOService; +class nsIImageLoadingContent; +class nsIInterfaceRequestor; +class nsILoadGroup; +class nsILoadInfo; +class nsIObserver; +class nsIPrincipal; +class nsIReferrerInfo; +class nsIRequest; +class nsIRunnable; +class nsIScreen; +class nsIScriptContext; +class nsIScriptSecurityManager; +class nsISerialEventTarget; +class nsIStringBundle; +class nsIStringBundleService; +class nsISupports; +class nsITransferable; +class nsIURI; +class nsIWidget; +class nsIWritableVariant; +class nsIXPConnect; +class nsNodeInfoManager; +class nsParser; +class nsPIWindowRoot; +class nsPresContext; +class nsStringBuffer; +class nsTextFragment; +class nsView; +class nsWrapperCache; + +struct JSContext; +struct nsPoint; + +namespace IPC { +class Message; +class MessageReader; +class MessageWriter; +} // namespace IPC + +namespace JS { +class Value; +class PropertyDescriptor; +} // namespace JS + +namespace mozilla { +class Dispatcher; +class EditorBase; +class ErrorResult; +class EventListenerManager; +class HTMLEditor; +class LazyLogModule; +class LogModule; +class PresShell; +class TextEditor; +class WidgetDragEvent; +class WidgetKeyboardEvent; + +struct InputEventOptions; + +template +class RangeBoundaryBase; + +template +class NotNull; +template +class StaticRefPtr; + +namespace dom { +class IPCImage; +struct AutocompleteInfo; +class BrowserChild; +class BrowserParent; +class BrowsingContext; +class BrowsingContextGroup; +class ContentChild; +class ContentFrameMessageManager; +class ContentParent; +struct CustomElementDefinition; +class CustomElementFormValue; +class CustomElementRegistry; +class DataTransfer; +class Document; +class DocumentFragment; +class DOMArena; +class Element; +class Event; +class EventTarget; +class FragmentOrElement; +class HTMLElement; +class HTMLInputElement; +class IPCTransferable; +class IPCTransferableData; +class IPCTransferableDataImageContainer; +class IPCTransferableDataItem; +struct LifecycleCallbackArgs; +class MessageBroadcaster; +class NodeInfo; +class OwningFileOrUSVStringOrFormData; +class Selection; +enum class ShadowRootMode : uint8_t; +struct StructuredSerializeOptions; +class WorkerPrivate; +enum class ElementCallbackType; +enum class ReferrerPolicy : uint8_t; +} // namespace dom + +namespace ipc { +class BigBuffer; +class IProtocol; +} // namespace ipc + +namespace gfx { +class DataSourceSurface; +enum class SurfaceFormat : int8_t; +} // namespace gfx + +class WindowRenderer; + +} // namespace mozilla + +extern const char kLoadAsData[]; + +// Stolen from nsReadableUtils, but that's OK, since we can declare the same +// name multiple times. +const nsString& EmptyString(); +const nsCString& EmptyCString(); + +enum EventNameType { + EventNameType_None = 0x0000, + EventNameType_HTML = 0x0001, + EventNameType_XUL = 0x0002, + EventNameType_SVGGraphic = 0x0004, // svg graphic elements + EventNameType_SVGSVG = 0x0008, // the svg element + EventNameType_SMIL = 0x0010, // smil elements + EventNameType_HTMLBodyOrFramesetOnly = 0x0020, + EventNameType_HTMLMarqueeOnly = 0x0040, + + EventNameType_HTMLXUL = 0x0003, + EventNameType_All = 0xFFFF +}; + +enum class TreeKind : uint8_t { DOM, Flat }; + +struct EventNameMapping { + // This holds pointers to nsGkAtoms members, and is therefore safe as a + // non-owning reference. + nsAtom* MOZ_NON_OWNING_REF mAtom; + int32_t mType; + mozilla::EventMessage mMessage; + mozilla::EventClassID mEventClassID; +}; + +namespace mozilla { +enum class PreventDefaultResult : uint8_t { No, ByContent, ByChrome }; + +namespace dom { +enum JSONBehavior { UndefinedIsNullStringLiteral, UndefinedIsVoidString }; +} +} // namespace mozilla + +class nsContentUtils { + friend class nsAutoScriptBlockerSuppressNodeRemoved; + using Element = mozilla::dom::Element; + using Document = mozilla::dom::Document; + using Cancelable = mozilla::Cancelable; + using CanBubble = mozilla::CanBubble; + using Composed = mozilla::Composed; + using ChromeOnlyDispatch = mozilla::ChromeOnlyDispatch; + using EventMessage = mozilla::EventMessage; + using TimeDuration = mozilla::TimeDuration; + using Trusted = mozilla::Trusted; + using JSONBehavior = mozilla::dom::JSONBehavior; + using RFPTarget = mozilla::RFPTarget; + + public: + static nsresult Init(); + + static bool IsCallerChrome(); + static bool ThreadsafeIsCallerChrome(); + static bool IsCallerUAWidget(); + static bool IsFuzzingEnabled() +#ifndef FUZZING + { + return false; + } +#else + ; +#endif + static bool IsErrorPage(nsIURI* aURI); + + static bool IsCallerChromeOrFuzzingEnabled(JSContext* aCx, JSObject*) { + return ThreadsafeIsSystemCaller(aCx) || IsFuzzingEnabled(); + } + + static bool IsCallerChromeOrElementTransformGettersEnabled(JSContext* aCx, + JSObject*); + + // The APIs for checking whether the caller is system (in the sense of system + // principal) should only be used when the JSContext is known to accurately + // represent the caller. In practice, that means you should only use them in + // two situations at the moment: + // + // 1) Functions used in WebIDL Func annotations. + // 2) Bindings code or other code called directly from the JS engine. + // + // Use pretty much anywhere else is almost certainly wrong and should be + // replaced with [NeedsCallerType] annotations in bindings. + + // Check whether the caller is system if you know you're on the main thread. + static bool IsSystemCaller(JSContext* aCx); + + // Check whether the caller is system if you might be on a worker or worklet + // thread. + static bool ThreadsafeIsSystemCaller(JSContext* aCx); + + // In the traditional Gecko architecture, both C++ code and untrusted JS code + // needed to rely on the same XPCOM method/getter/setter to get work done. + // This required lots of security checks in the various exposed methods, which + // in turn created difficulty in determining whether the caller was script + // (whose access needed to be checked) and internal C++ platform code (whose + // access did not need to be checked). To address this problem, Gecko had a + // convention whereby the absence of script on the stack was interpretted as + // "System Caller" and always granted unfettered access. + // + // Unfortunately, this created a bunch of footguns. For example, when the + // implementation of a DOM method wanted to perform a privileged + // sub-operation, it needed to "hide" the presence of script on the stack in + // order for that sub-operation to be allowed. Additionally, if script could + // trigger an API entry point to be invoked in some asynchronous way without + // script on the stack, it could potentially perform privilege escalation. + // + // In the modern world, untrusted script should interact with the platform + // exclusively over WebIDL APIs, and platform code has a lot more flexibility + // in deciding whether or not to use XPCOM. This gives us the flexibility to + // do something better. + // + // Going forward, APIs should be designed such that any security checks that + // ask the question "is my caller allowed to do this?" should live in WebIDL + // API entry points, with a separate method provided for internal callers + // that just want to get the job done. + // + // To enforce this and catch bugs, nsContentUtils::SubjectPrincipal will crash + // if it is invoked without script on the stack. To land that transition, it + // was necessary to go through and whitelist a bunch of callers that were + // depending on the old behavior. Those callers should be fixed up, and these + // methods should not be used by new code without review from bholley or bz. + static bool LegacyIsCallerNativeCode() { return !GetCurrentJSContext(); } + static bool LegacyIsCallerChromeOrNativeCode() { + return LegacyIsCallerNativeCode() || IsCallerChrome(); + } + static nsIPrincipal* SubjectPrincipalOrSystemIfNativeCaller() { + if (!GetCurrentJSContext()) { + return GetSystemPrincipal(); + } + return SubjectPrincipal(); + } + + static bool LookupBindingMember( + JSContext* aCx, nsIContent* aContent, JS::Handle aId, + JS::MutableHandle aDesc); + + // Check whether we should avoid leaking distinguishing information to JS/CSS. + // This function can be called both in the main thread and worker threads. + static bool ShouldResistFingerprinting(bool aIsPrivateMode, + RFPTarget aTarget); + static bool ShouldResistFingerprinting(nsIGlobalObject* aGlobalObject, + RFPTarget aTarget); + // Similar to the function above, but always allows CallerType::System + // callers. + static bool ShouldResistFingerprinting(mozilla::dom::CallerType aCallerType, + nsIGlobalObject* aGlobalObject, + RFPTarget aTarget); + static bool ShouldResistFingerprinting(nsIDocShell* aDocShell, + RFPTarget aTarget); + // These functions are the new, nuanced functions + static bool ShouldResistFingerprinting(nsIChannel* aChannel, + RFPTarget aTarget); + // These functions are labeled as dangerous because they will do the wrong + // thing in _most_ cases. They should only be used if you don't have a fully + // constructed LoadInfo or Document. + // A constant string used as justification is required when calling them, + // it should explain why a Document, Channel, LoadInfo, or CookieJarSettings + // does not exist in this context. + // (see below for more on justification strings.) + static bool ShouldResistFingerprinting_dangerous( + nsIURI* aURI, const mozilla::OriginAttributes& aOriginAttributes, + const char* aJustification, RFPTarget aTarget); + static bool ShouldResistFingerprinting_dangerous(nsIPrincipal* aPrincipal, + const char* aJustification, + RFPTarget aTarget); + + /** + * Implement a RFP function that only checks the pref, and does not take + * into account any additional context such as PBM mode or Web Extensions. + * + * It requires an explanation for why the coarse check is being used instead + * of the nuanced check. While there is a gradual cut over of + * ShouldResistFingerprinting calls to a nuanced API, some features still + * require a legacy function. (Additionally, we sometimes use the coarse + * check first, to avoid running additional code to support a nuanced check.) + */ + static bool ShouldResistFingerprinting(const char* aJustification, + RFPTarget aTarget); + + // A helper function to calculate the rounded window size for fingerprinting + // resistance. The rounded size is based on the chrome UI size and available + // screen size. If the inputWidth/Height is greater than the available content + // size, this will report the available content size. Otherwise, it will + // round the size to the nearest upper 200x100. + static void CalcRoundedWindowSizeForResistingFingerprinting( + int32_t aChromeWidth, int32_t aChromeHeight, int32_t aScreenWidth, + int32_t aScreenHeight, int32_t aInputWidth, int32_t aInputHeight, + bool aSetOuterWidth, bool aSetOuterHeight, int32_t* aOutputWidth, + int32_t* aOutputHeight); + + /** + * Returns the parent node of aChild crossing document boundaries, but skips + * any cross-process parent frames and continues with the nearest in-process + * frame in the hierarchy. + * + * Uses the parent node in the composed document. + */ + static nsINode* GetNearestInProcessCrossDocParentNode(nsINode* aChild); + + /** + * Similar to nsINode::IsInclusiveDescendantOf, except will treat an + * HTMLTemplateElement or ShadowRoot as an ancestor of things in the + * corresponding DocumentFragment. See the concept of "host-including + * inclusive ancestor" in the DOM specification. + */ + static bool ContentIsHostIncludingDescendantOf( + const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor); + + /** + * Similar to nsINode::IsInclusiveDescendantOf except it crosses document + * boundaries, this function uses ancestor/descendant relations in the + * composed document (see shadow DOM spec). + */ + static bool ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant, + nsINode* aPossibleAncestor); + + /** + * As with ContentIsCrossDocDescendantOf but crosses shadow boundaries but not + * cross document boundaries. + * + * @see nsINode::GetFlattenedTreeParentNode() + */ + static bool ContentIsFlattenedTreeDescendantOf( + const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor); + + /** + * Same as `ContentIsFlattenedTreeDescendantOf`, but from the flattened tree + * point of view of the style system + * + * @see nsINode::GetFlattenedTreeParentNodeForStyle() + */ + static bool ContentIsFlattenedTreeDescendantOfForStyle( + const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor); + + /** + * Retarget an object A against an object B + * @see https://dom.spec.whatwg.org/#retarget + */ + static nsINode* Retarget(nsINode* aTargetA, nsINode* aTargetB); + + /** + * @see https://wicg.github.io/element-timing/#get-an-element + */ + static Element* GetAnElementForTiming(Element* aTarget, + const Document* aDocument, + nsIGlobalObject* aGlobal); + + /* + * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor. + * + * This method fills the |aArray| with all ancestor nodes of |aNode| + * including |aNode| at the zero index. + * + */ + static nsresult GetInclusiveAncestors(nsINode* aNode, + nsTArray& aArray); + + /* + * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor. + * + * This method fills |aAncestorNodes| with all ancestor nodes of |aNode| + * including |aNode| (QI'd to nsIContent) at the zero index. + * For each ancestor, there is a corresponding element in |aAncestorOffsets| + * which is the ComputeIndexOf the child in relation to its parent. + * + * This method just sucks. + */ + static nsresult GetInclusiveAncestorsAndOffsets( + nsINode* aNode, uint32_t aOffset, nsTArray* aAncestorNodes, + nsTArray>* aAncestorOffsets); + + /** + * Returns the closest common inclusive ancestor + * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) , if any, + * for two nodes. + * + * Returns null if the nodes are disconnected. + */ + static nsINode* GetClosestCommonInclusiveAncestor(nsINode* aNode1, + nsINode* aNode2) { + if (aNode1 == aNode2) { + return aNode1; + } + + return GetCommonAncestorHelper(aNode1, aNode2); + } + + /** + * Returns the common flattened tree ancestor, if any, for two given content + * nodes. + */ + static nsIContent* GetCommonFlattenedTreeAncestor(nsIContent* aContent1, + nsIContent* aContent2) { + if (aContent1 == aContent2) { + return aContent1; + } + + return GetCommonFlattenedTreeAncestorHelper(aContent1, aContent2); + } + + /** + * Returns the common flattened tree ancestor from the point of view of the + * style system, if any, for two given content nodes. + */ + static Element* GetCommonFlattenedTreeAncestorForStyle(Element* aElement1, + Element* aElement2); + + /** + * Returns the common BrowserParent ancestor, if any, for two given + * BrowserParent. + */ + static mozilla::dom::BrowserParent* GetCommonBrowserParentAncestor( + mozilla::dom::BrowserParent* aBrowserParent1, + mozilla::dom::BrowserParent* aBrowserParent2); + + // https://html.spec.whatwg.org/#target-element + // https://html.spec.whatwg.org/#find-a-potential-indicated-element + static Element* GetTargetElement(Document* aDocument, + const nsAString& aAnchorName); + /** + * Returns true if aNode1 is before aNode2 in the same connected + * tree. + * aNode1Index and aNode2Index are in/out arguments. If non-null, and value is + * Some, that value is used instead of calling slow ComputeIndexOf on the + * parent node. If value is Nothing, the value will be set to the return value + * of ComputeIndexOf. + */ + static bool PositionIsBefore(nsINode* aNode1, nsINode* aNode2, + mozilla::Maybe* aNode1Index = nullptr, + mozilla::Maybe* aNode2Index = nullptr); + + struct ComparePointsCache { + mozilla::Maybe ComputeIndexOf(const nsINode* aParent, + const nsINode* aChild) { + if (aParent == mParent && aChild == mChild) { + return mIndex; + } + + mIndex = aParent->ComputeIndexOf(aChild); + mParent = aParent; + mChild = aChild; + return mIndex; + } + + private: + const nsINode* mParent = nullptr; + const nsINode* mChild = nullptr; + mozilla::Maybe mIndex; + }; + + /** + * Utility routine to compare two "points", where a point is a node/offset + * pair. + * Pass a cache object as aParent1Cache if you expect to repeatedly + * call this function with the same value as aParent1. + * + * @return -1 if point1 < point2, + * 1 if point1 > point2, + * 0 if point1 == point2. + * `Nothing` if the two nodes aren't in the same connected subtree. + */ + static mozilla::Maybe ComparePoints( + const nsINode* aParent1, uint32_t aOffset1, const nsINode* aParent2, + uint32_t aOffset2, ComparePointsCache* aParent1Cache = nullptr); + template + static mozilla::Maybe ComparePoints( + const mozilla::RangeBoundaryBase& aFirstBoundary, + const mozilla::RangeBoundaryBase& aSecondBoundary); + + /** + * Utility routine to compare two "points", where a point is a + * node/offset pair + * Returns -1 if point1 < point2, 1, if point1 > point2, + * 0 if error or if point1 == point2. + * NOTE! If the two nodes aren't in the same connected subtree, + * the result is 1, and the optional aDisconnected parameter + * is set to true. + * + * Pass a cache object as aParent1Cache if you expect to repeatedly + * call this function with the same value as aParent1. + */ + static int32_t ComparePoints_Deprecated( + const nsINode* aParent1, uint32_t aOffset1, const nsINode* aParent2, + uint32_t aOffset2, bool* aDisconnected = nullptr, + ComparePointsCache* aParent1Cache = nullptr); + template + static int32_t ComparePoints_Deprecated( + const mozilla::RangeBoundaryBase& aFirstBoundary, + const mozilla::RangeBoundaryBase& aSecondBoundary, + bool* aDisconnected = nullptr); + + /** + * DO NOT USE this method for comparing the points in new code. this method + * emulates same result as `ComparePoints` before bug 1741148. + * When the old `ComparePoints` was called with offset value over `INT32_MAX` + * or `-1` which is used as "not found" by some API, they were treated as-is + * without checking whether the negative value or valid value. Thus, this + * handles the negative offset cases in the special paths to keep the + * traditional behavior. If you want to use this in new code, it means that + * you **should** check the offset values and call `ComparePoints` instead. + */ + static mozilla::Maybe ComparePoints_AllowNegativeOffsets( + const nsINode* aParent1, int64_t aOffset1, const nsINode* aParent2, + int64_t aOffset2) { + if (MOZ_UNLIKELY(aOffset1 < 0 || aOffset2 < 0)) { + // If in same container, just the offset is compared. + if (aParent1 == aParent2) { + const int32_t compOffsets = + aOffset1 == aOffset2 ? 0 : (aOffset1 < aOffset2 ? -1 : 1); + return mozilla::Some(compOffsets); + } + // Otherwise, aOffset1 is referred only when aParent2 is a descendant of + // aParent1. + if (aOffset1 < 0 && aParent2->IsInclusiveDescendantOf(aParent1)) { + return mozilla::Some(-1); + } + // And also aOffset2 is referred only when aParent1 is a descendant of + // aParent2. + if (aOffset2 < 0 && aParent1->IsInclusiveDescendantOf(aParent2)) { + return mozilla::Some(1); + } + // Otherwise, aOffset1 nor aOffset2 is referred so that any value is fine + // if negative. + return ComparePoints( + aParent1, aOffset1 < 0 ? UINT32_MAX : static_cast(aOffset1), + aParent2, + aOffset2 < 0 ? UINT32_MAX : static_cast(aOffset2)); + } + return ComparePoints(aParent1, aOffset1, aParent2, aOffset2); + } + + /** + * Brute-force search of the element subtree rooted at aContent for + * an element with the given id. aId must be nonempty, otherwise + * this method may return nodes even if they have no id! + */ + static Element* MatchElementId(nsIContent* aContent, const nsAString& aId); + + /** + * Similar to above, but to be used if one already has an atom for the ID + */ + static Element* MatchElementId(nsIContent* aContent, const nsAtom* aId); + + /** + * Reverses the document position flags passed in. + * + * @param aDocumentPosition The document position flags to be reversed. + * + * @return The reversed document position flags. + * + * @see Node + */ + static uint16_t ReverseDocumentPosition(uint16_t aDocumentPosition); + + static const nsDependentSubstring TrimCharsInSet(const char* aSet, + const nsAString& aValue); + + template + static const nsDependentSubstring TrimWhitespace(const nsAString& aStr, + bool aTrimTrailing = true); + + /** + * Returns true if aChar is of class Ps, Pi, Po, Pf, or Pe. + */ + static bool IsFirstLetterPunctuation(uint32_t aChar); + + /** + * Returns true if aChar is of class Lu, Ll, Lt, Lm, Lo, Nd, Nl or No + */ + static bool IsAlphanumeric(uint32_t aChar); + /** + * Returns true if aChar is of class L*, N* or S* (for first-letter). + */ + static bool IsAlphanumericOrSymbol(uint32_t aChar); + + /* + * Is the character an HTML whitespace character? + * + * We define whitespace using the list in HTML5 and css3-selectors: + * U+0009, U+000A, U+000C, U+000D, U+0020 + * + * HTML 4.01 also lists U+200B (zero-width space). + */ + static bool IsHTMLWhitespace(char16_t aChar); + + /* + * Returns whether the character is an HTML whitespace (see IsHTMLWhitespace) + * or a nbsp character (U+00A0). + */ + static bool IsHTMLWhitespaceOrNBSP(char16_t aChar); + + /** + * https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements + */ + static bool IsHTMLBlockLevelElement(nsIContent* aContent); + + enum ParseHTMLIntegerResultFlags { + eParseHTMLInteger_NoFlags = 0, + // eParseHTMLInteger_NonStandard is set if the string representation of the + // integer was not the canonical one, but matches at least one of the + // following: + // * had leading whitespaces + // * had '+' sign + // * had leading '0' + // * was '-0' + eParseHTMLInteger_NonStandard = 1 << 0, + eParseHTMLInteger_DidNotConsumeAllInput = 1 << 1, + // Set if one or more error flags were set. + eParseHTMLInteger_Error = 1 << 2, + eParseHTMLInteger_ErrorNoValue = 1 << 3, + eParseHTMLInteger_ErrorOverflow = 1 << 4, + // Use this flag to detect the difference between overflow and underflow + eParseHTMLInteger_Negative = 1 << 5, + }; + static int32_t ParseHTMLInteger(const nsAString& aValue, + ParseHTMLIntegerResultFlags* aResult) { + return ParseHTMLInteger(aValue.BeginReading(), aValue.EndReading(), + aResult); + } + static int32_t ParseHTMLInteger(const char16_t* aStart, const char16_t* aEnd, + ParseHTMLIntegerResultFlags* aResult); + static int32_t ParseHTMLInteger(const nsACString& aValue, + ParseHTMLIntegerResultFlags* aResult) { + return ParseHTMLInteger(aValue.BeginReading(), aValue.EndReading(), + aResult); + } + static int32_t ParseHTMLInteger(const char* aStart, const char* aEnd, + ParseHTMLIntegerResultFlags* aResult); + + private: + template + static int32_t ParseHTMLIntegerImpl(const CharT* aStart, const CharT* aEnd, + ParseHTMLIntegerResultFlags* aResult); + + public: + /** + * Parse a margin string of format 'top, right, bottom, left' into + * an nsIntMargin. + * + * @param aString the string to parse + * @param aResult the resulting integer + * @return whether the value could be parsed + */ + static bool ParseIntMarginValue(const nsAString& aString, + nsIntMargin& aResult); + + /** + * Parse the value of the attribute according to the HTML5 + * spec as of April 16, 2012. + * + * @param aValue the value to parse + * @return 1 to 7, or 0 if the value couldn't be parsed + */ + static int32_t ParseLegacyFontSize(const nsAString& aValue); + + static void Shutdown(); + + /** + * Checks whether two nodes come from the same origin. + */ + static nsresult CheckSameOrigin(const nsINode* aTrustedNode, + const nsINode* unTrustedNode); + + // Check if the (JS) caller can access aNode. + static bool CanCallerAccess(const nsINode* aNode); + + // Check if the (JS) caller can access aWindow. + // aWindow can be either outer or inner window. + static bool CanCallerAccess(nsPIDOMWindowInner* aWindow); + + // Check if the principal is chrome or an addon with the permission. + static bool PrincipalHasPermission(nsIPrincipal& aPrincipal, + const nsAtom* aPerm); + + // Check if the JS caller is chrome or an addon with the permission. + static bool CallerHasPermission(JSContext* aCx, const nsAtom* aPerm); + + /** + * Returns the triggering principal which should be used for the given URL + * attribute value with the given subject principal. + * + * If the attribute value is not an absolute URL, the subject principal will + * be ignored, and the node principal of aContent will be used instead. + * If aContent is non-null, this function will always return a principal. + * Otherewise, it may return null if aSubjectPrincipal is null or is rejected + * based on the attribute value. + * + * @param aContent The content on which the attribute is being set. + * @param aAttrValue The URL value of the attribute. For parsed attribute + * values, such as `srcset`, this function should be called separately + * for each URL value it contains. + * @param aSubjectPrincipal The subject principal of the scripted caller + * responsible for setting the attribute, or null if no scripted caller + * can be determined. + */ + static nsIPrincipal* GetAttrTriggeringPrincipal( + nsIContent* aContent, const nsAString& aAttrValue, + nsIPrincipal* aSubjectPrincipal); + + /** + * Returns true if the given string is guaranteed to be treated as an absolute + * URL, rather than a relative URL. In practice, this means any complete URL + * as supported by nsStandardURL, or any string beginning with a valid scheme + * which is known to the IO service, and has the URI_NORELATIVE flag. + * + * If the URL may be treated as absolute in some cases, but relative in others + * (for instance, "http:foo", which can be either an absolute or relative URL, + * depending on the context), this function returns false. + */ + static bool IsAbsoluteURL(const nsACString& aURL); + + // Check if a node is in the document prolog, i.e. before the document + // element. + static bool InProlog(nsINode* aNode); + + static nsIBidiKeyboard* GetBidiKeyboard(); + + /** + * Get the cache security manager service. Can return null if the layout + * module has been shut down. + */ + static nsIScriptSecurityManager* GetSecurityManager() { + return sSecurityManager; + } + + // Returns the subject principal from the JSContext. May only be called + // from the main thread and assumes an existing compartment. + static nsIPrincipal* SubjectPrincipal(JSContext* aCx); + + // Returns the subject principal. Guaranteed to return non-null. May only + // be called when nsContentUtils is initialized. + static nsIPrincipal* SubjectPrincipal(); + + // Returns the prinipal of the given JS object. This may only be called on + // the main thread for objects from the main thread's JSRuntime. The object + // must not be a cross-compartment wrapper, because CCWs are not associated + // with a single realm. + static nsIPrincipal* ObjectPrincipal(JSObject* aObj); + + static void GenerateStateKey(nsIContent* aContent, Document* aDocument, + nsACString& aKey); + + /** + * Create a new nsIURI from aSpec, using aBaseURI as the base. The + * origin charset of the new nsIURI will be the document charset of + * aDocument. + */ + static nsresult NewURIWithDocumentCharset(nsIURI** aResult, + const nsAString& aSpec, + Document* aDocument, + nsIURI* aBaseURI); + + /** + * Returns true if |aName| is a name with dashes. + */ + static bool IsNameWithDash(nsAtom* aName); + + /** + * Returns true if |aName| is a valid name to be registered via + * customElements.define. + */ + static bool IsCustomElementName(nsAtom* aName, uint32_t aNameSpaceID); + + static nsresult CheckQName(const nsAString& aQualifiedName, + bool aNamespaceAware = true, + const char16_t** aColon = nullptr); + + static nsresult SplitQName(const nsIContent* aNamespaceResolver, + const nsString& aQName, int32_t* aNamespace, + nsAtom** aLocalName); + + static nsresult GetNodeInfoFromQName(const nsAString& aNamespaceURI, + const nsAString& aQualifiedName, + nsNodeInfoManager* aNodeInfoManager, + uint16_t aNodeType, + mozilla::dom::NodeInfo** aNodeInfo); + + static void SplitExpatName(const char16_t* aExpatName, nsAtom** aPrefix, + nsAtom** aTagName, int32_t* aNameSpaceID); + + // Get a permission-manager setting for the given principal and type. + // If the pref doesn't exist or if it isn't ALLOW_ACTION, false is + // returned, otherwise true is returned. Always returns true for the + // system principal, and false for a null principal. + static bool IsSitePermAllow(nsIPrincipal* aPrincipal, + const nsACString& aType); + + // Get a permission-manager setting for the given principal and type. + // If the pref doesn't exist or if it isn't DENY_ACTION, false is + // returned, otherwise true is returned. Always returns false for the + // system principal, and true for a null principal. + static bool IsSitePermDeny(nsIPrincipal* aPrincipal, const nsACString& aType); + + // Get a permission-manager setting for the given principal and type. + // If the pref doesn't exist or if it isn't ALLOW_ACTION, false is + // returned, otherwise true is returned. Always returns true for the + // system principal, and false for a null principal. + // This version checks the permission for an exact host match on + // the principal + static bool IsExactSitePermAllow(nsIPrincipal* aPrincipal, + const nsACString& aType); + + // Get a permission-manager setting for the given principal and type. + // If the pref doesn't exist or if it isn't DENY_ACTION, false is + // returned, otherwise true is returned. Always returns false for the + // system principal, and true for a null principal. + // This version checks the permission for an exact host match on + // the principal + static bool IsExactSitePermDeny(nsIPrincipal* aPrincipal, + const nsACString& aType); + + // Returns true if the pref exists and is not UNKNOWN_ACTION. + static bool HasSitePerm(nsIPrincipal* aPrincipal, const nsACString& aType); + + // Returns true if aDoc1 and aDoc2 have equal NodePrincipal()s. + static bool HaveEqualPrincipals(Document* aDoc1, Document* aDoc2); + + /** + * Regster aObserver as a shutdown observer. A strong reference is held + * to aObserver until UnregisterShutdownObserver is called. + */ + static void RegisterShutdownObserver(nsIObserver* aObserver); + static void UnregisterShutdownObserver(nsIObserver* aObserver); + + /** + * @return true if aContent has an attribute aName in namespace aNameSpaceID, + * and the attribute value is non-empty. + */ + static bool HasNonEmptyAttr(const nsIContent* aContent, int32_t aNameSpaceID, + nsAtom* aName); + + /** + * Method that gets the primary presContext for the node. + * + * @param aContent The content node. + * @return the presContext, or nullptr if the content is not in a document + * (if GetComposedDoc returns nullptr) + */ + static nsPresContext* GetContextForContent(const nsIContent* aContent); + + /** + * Method that gets the pres shell for the node. + * + * @param aContent The content node. + * @return the pres shell, or nullptr if the content is not in a document + * (if GetComposedDoc returns nullptr) + */ + static mozilla::PresShell* GetPresShellForContent(const nsIContent* aContent); + + /** + * Method to do security and content policy checks on the image URI + * + * @param aURI uri of the image to be loaded + * @param aNode, the context the image is loaded in (eg an element) + * @param aLoadingDocument the document we belong to + * @param aLoadingPrincipal the principal doing the load + * @param [aContentPolicyType=nsIContentPolicy::TYPE_INTERNAL_IMAGE] + * (Optional) The CP content type to use + * @param aImageBlockingStatus the nsIContentPolicy blocking status for this + * image. This will be set even if a security check fails for the + * image, to some reasonable REJECT_* value. This out param will only + * be set if it's non-null. + * @return true if the load can proceed, or false if it is blocked. + * Note that aImageBlockingStatus, if set will always be an ACCEPT + * status if true is returned and always be a REJECT_* status if + * false is returned. + */ + static bool CanLoadImage(nsIURI* aURI, nsINode* aNode, + Document* aLoadingDocument, + nsIPrincipal* aLoadingPrincipal); + + /** + * Returns true if objects in aDocument shouldn't initiate image loads. + */ + static bool DocumentInactiveForImageLoads(Document* aDocument); + + /** + * Convert a CORSMode into the corresponding imgILoader flags for + * passing to LoadImage. + * @param aMode CORS mode to convert + * @return a bitfield suitable to bitwise OR with other nsIRequest flags + */ + static int32_t CORSModeToLoadImageFlags(mozilla::CORSMode aMode); + + /** + * Method to start an image load. This does not do any security checks. + * This method will attempt to make aURI immutable; a caller that wants to + * keep a mutable version around should pass in a clone. + * + * @param aURI uri of the image to be loaded + * @param aContext element of document where the result of this request + * will be used. + * @param aLoadingDocument the document we belong to + * @param aLoadingPrincipal the principal doing the load + * @param aReferrerInfo the referrerInfo use on channel creation + * @param aObserver the observer for the image load + * @param aLoadFlags the load flags to use. See nsIRequest + * @param [aContentPolicyType=nsIContentPolicy::TYPE_INTERNAL_IMAGE] + * (Optional) The CP content type to use + * @param aUseUrgentStartForChannel,(Optional) a flag to mark on channel if it + * is triggered by user input events. + * @return the imgIRequest for the image load + */ + static nsresult LoadImage( + nsIURI* aURI, nsINode* aContext, Document* aLoadingDocument, + nsIPrincipal* aLoadingPrincipal, uint64_t aRequestContextID, + nsIReferrerInfo* aReferrerInfo, imgINotificationObserver* aObserver, + int32_t aLoadFlags, const nsAString& initiatorType, + imgRequestProxy** aRequest, + nsContentPolicyType aContentPolicyType = + nsIContentPolicy::TYPE_INTERNAL_IMAGE, + bool aUseUrgentStartForChannel = false, bool aLinkPreload = false, + uint64_t aEarlyHintPreloaderId = 0); + + /** + * Obtain an image loader that respects the given document/channel's privacy + * status. Null document/channel arguments return the public image loader. + */ + static imgLoader* GetImgLoaderForDocument(Document* aDoc); + static imgLoader* GetImgLoaderForChannel(nsIChannel* aChannel, + Document* aContext); + + /** + * Method to get an imgIContainer from an image loading content + * + * @param aContent The image loading content. Must not be null. + * @param aRequest The image request [out] + * @return the imgIContainer corresponding to the first frame of the image + */ + static already_AddRefed GetImageFromContent( + nsIImageLoadingContent* aContent, imgIRequest** aRequest = nullptr); + + /** + * Method that decides whether a content node is draggable + * + * @param aContent The content node to test. + * @return whether it's draggable + */ + static bool ContentIsDraggable(nsIContent* aContent); + + /** + * Method that decides whether a content node is a draggable image + * + * @param aContent The content node to test. + * @return whether it's a draggable image + */ + static bool IsDraggableImage(nsIContent* aContent); + + /** + * Method that decides whether a content node is a draggable link + * + * @param aContent The content node to test. + * @return whether it's a draggable link + */ + static bool IsDraggableLink(const nsIContent* aContent); + + /** + * Convenience method to create a new nodeinfo that differs only by prefix and + * name from aNodeInfo. The new nodeinfo's name is set to aName, and prefix is + * set to null. + */ + static nsresult QNameChanged(mozilla::dom::NodeInfo* aNodeInfo, nsAtom* aName, + mozilla::dom::NodeInfo** aResult); + + /** + * Returns the appropriate event argument names for the specified + * namespace and event name. Added because we need to switch between + * SVG's "evt" and the rest of the world's "event", and because onerror + * on window takes 5 args. + */ + static void GetEventArgNames(int32_t aNameSpaceID, nsAtom* aEventName, + bool aIsForWindow, uint32_t* aArgCount, + const char*** aArgNames); + + /** + * Returns true if this document is in a Private Browsing window. + */ + static bool IsInPrivateBrowsing(const Document* aDoc); + + /** + * Returns true if this loadGroup uses Private Browsing. + */ + static bool IsInPrivateBrowsing(nsILoadGroup* aLoadGroup); + + /** + * Returns whether a node is in the same tree as another one, accounting for + * anonymous roots. + * + * This method is particularly useful for callers who are trying to ensure + * that they are working with a non-anonymous descendant of a given node. If + * aContent is a descendant of aNode, a return value of false from this + * method means that it's an anonymous descendant from aNode's point of view. + * + * Both arguments to this method must be non-null. + */ + static bool IsInSameAnonymousTree(const nsINode* aNode, + const nsINode* aOtherNode); + + /* + * Traverse the parent chain from aElement up to aStop, and return true if + * there's an interactive html content; false otherwise. + * + * Note: This crosses shadow boundaries but not document boundaries. + */ + static bool IsInInteractiveHTMLContent(const Element* aElement, + const Element* aStop); + + /** + * Return the nsIXPConnect service. + */ + static nsIXPConnect* XPConnect() { return sXPConnect; } + + /** + * Report simple error message to the browser console + * @param aErrorText the error message + * @param aCategory Name of the module reporting error + * @param aFromPrivateWindow Whether from private window or not + * @param aFromChromeContext Whether from chrome context or not + * @param [aErrorFlags] See nsIScriptError. + */ + static void LogSimpleConsoleError( + const nsAString& aErrorText, const nsACString& aCategory, + bool aFromPrivateWindow, bool aFromChromeContext, + uint32_t aErrorFlags = nsIScriptError::errorFlag); + + /** + * Report a non-localized error message to the error console. + * @param aErrorText the error message + * @param aErrorFlags See nsIScriptError. + * @param aCategory Name of module reporting error. + * @param aDocument Reference to the document which triggered the message. + * @param [aURI=nullptr] (Optional) URI of resource containing error. + * @param [aSourceLine=u""_ns] (Optional) The text of the line that + contains the error (may be empty). + * @param [aLineNumber=0] (Optional) Line number within resource + containing error. + * @param [aColumnNumber=0] (Optional) Column number within resource + containing error. + If aURI is null, then aDocument->GetDocumentURI() is used. + * @param [aLocationMode] (Optional) Specifies the behavior if + error location information is omitted. + */ + enum MissingErrorLocationMode { + // Don't show location information in the error console. + eOMIT_LOCATION, + // Get location information from the currently executing script. + eUSE_CALLING_LOCATION + }; + static nsresult ReportToConsoleNonLocalized( + const nsAString& aErrorText, uint32_t aErrorFlags, + const nsACString& aCategory, const Document* aDocument, + nsIURI* aURI = nullptr, const nsString& aSourceLine = u""_ns, + uint32_t aLineNumber = 0, uint32_t aColumnNumber = 0, + MissingErrorLocationMode aLocationMode = eUSE_CALLING_LOCATION); + + /** + * Report a non-localized error message to the error console base on the + * innerWindowID. + * @param aErrorText the error message + * @param aErrorFlags See nsIScriptError. + * @param aCategory Name of module reporting error. + * @param [aInnerWindowID] Inner window ID for document which triggered the + * message. + * @param [aURI=nullptr] (Optional) URI of resource containing error. + * @param [aSourceLine=u""_ns] (Optional) The text of the line that + contains the error (may be empty). + * @param [aLineNumber=0] (Optional) Line number within resource + containing error. + * @param [aColumnNumber=1] (Optional) Column number within resource + containing error. + If aURI is null, then aDocument->GetDocumentURI() is used. + * @param [aLocationMode] (Optional) Specifies the behavior if + error location information is omitted. + */ + static nsresult ReportToConsoleByWindowID( + const nsAString& aErrorText, uint32_t aErrorFlags, + const nsACString& aCategory, uint64_t aInnerWindowID, + nsIURI* aURI = nullptr, const nsString& aSourceLine = u""_ns, + uint32_t aLineNumber = 0, uint32_t aColumnNumber = 1, + MissingErrorLocationMode aLocationMode = eUSE_CALLING_LOCATION); + + /** + * Report a localized error message to the error console. + * @param aErrorFlags See nsIScriptError. + * @param aCategory Name of module reporting error. + * @param aDocument Reference to the document which triggered the message. + * @param aFile Properties file containing localized message. + * @param aMessageName Name of localized message. + * @param [aParams=empty-array] (Optional) Parameters to be substituted into + localized message. + * @param [aURI=nullptr] (Optional) URI of resource containing error. + * @param [aSourceLine=u""_ns] (Optional) The text of the line that + contains the error (may be empty). + * @param [aLineNumber=0] (Optional) Line number within resource + containing error. + * @param [aColumnNumber=0] (Optional) Column number within resource + containing error. + If aURI is null, then aDocument->GetDocumentURI() is used. + */ + enum PropertiesFile { + eCSS_PROPERTIES, + eXUL_PROPERTIES, + eLAYOUT_PROPERTIES, + eFORMS_PROPERTIES, + ePRINTING_PROPERTIES, + eDOM_PROPERTIES, + eHTMLPARSER_PROPERTIES, + eSVG_PROPERTIES, + eBRAND_PROPERTIES, + eCOMMON_DIALOG_PROPERTIES, + eMATHML_PROPERTIES, + eSECURITY_PROPERTIES, + eNECKO_PROPERTIES, + eFORMS_PROPERTIES_en_US, + eDOM_PROPERTIES_en_US, + PropertiesFile_COUNT + }; + static nsresult ReportToConsole( + uint32_t aErrorFlags, const nsACString& aCategory, + const Document* aDocument, PropertiesFile aFile, const char* aMessageName, + const nsTArray& aParams = nsTArray(), + nsIURI* aURI = nullptr, const nsString& aSourceLine = u""_ns, + uint32_t aLineNumber = 0, uint32_t aColumnNumber = 0); + + static void ReportEmptyGetElementByIdArg(const Document* aDoc); + + static void LogMessageToConsole(const char* aMsg); + + static bool SpoofLocaleEnglish(); + + /** + * Get the localized string named |aKey| in properties file |aFile|. + */ + static nsresult GetLocalizedString(PropertiesFile aFile, const char* aKey, + nsAString& aResult); + + /** + * Same as GetLocalizedString, except that it might use en-US locale depending + * on SpoofLocaleEnglish() and whether the document is a built-in browser + * page. + */ + static nsresult GetMaybeLocalizedString(PropertiesFile aFile, + const char* aKey, Document* aDocument, + nsAString& aResult); + + /** + * A helper function that parses a sandbox attribute (of an