From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- layout/base/nsLayoutUtils.h | 3248 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3248 insertions(+) create mode 100644 layout/base/nsLayoutUtils.h (limited to 'layout/base/nsLayoutUtils.h') diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h new file mode 100644 index 0000000000..e331ca11ef --- /dev/null +++ b/layout/base/nsLayoutUtils.h @@ -0,0 +1,3248 @@ +/* -*- 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/. */ + +#ifndef nsLayoutUtils_h__ +#define nsLayoutUtils_h__ + +#include "LayoutConstants.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/LookAndFeel.h" +#include "mozilla/Maybe.h" +#include "mozilla/RelativeTo.h" +#include "mozilla/StaticPrefs_nglayout.h" +#include "mozilla/SurfaceFromElementResult.h" +#include "mozilla/SVGImageContext.h" +#include "mozilla/ToString.h" +#include "mozilla/TypedEnumBits.h" +#include "mozilla/Span.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/WritingModes.h" +#include "mozilla/layers/ScrollableLayerGuid.h" +#include "mozilla/gfx/2D.h" + +#include "gfxPoint.h" +#include "nsBoundingMetrics.h" +#include "nsCSSPropertyIDSet.h" +#include "nsFrameList.h" +#include "nsThreadUtils.h" +#include "Units.h" +#include "mozilla/layers/LayersTypes.h" +#include +#include +// If you're thinking of adding a new include here, please try hard to not. +// This header file gets included just about everywhere and adding headers here +// can dramatically increase avoidable build activity. Try instead: +// - using a forward declaration +// - putting the include in the .cpp file, if it is only needed by the body +// - putting your new functions in some other less-widely-used header + +class gfxContext; +class gfxFontEntry; +class imgIContainer; +class nsFrameList; +class nsPresContext; +class nsIContent; +class nsIPrincipal; +class nsIWidget; +class nsAtom; +class nsIScrollableFrame; +class nsRegion; +enum nsChangeHint : uint32_t; +class nsFontMetrics; +class nsFontFaceList; +class nsIImageLoadingContent; +class nsBlockFrame; +class nsContainerFrame; +class nsView; +class nsIFrame; +class nsPIDOMWindowOuter; +class imgIRequest; +struct nsStyleFont; + +namespace mozilla { +class nsDisplayItem; +class nsDisplayList; +class nsDisplayListBuilder; +enum class nsDisplayListBuilderMode : uint8_t; +class RetainedDisplayListBuilder; +struct AspectRatio; +class ComputedStyle; +class DisplayPortUtils; +class PresShell; +enum class PseudoStyleType : uint8_t; +class EventListenerManager; +enum class LayoutFrameType : uint8_t; +struct IntrinsicSize; +class ReflowOutput; +class WritingMode; +class DisplayItemClip; +class EffectSet; +struct ActiveScrolledRoot; +enum class ScrollOrigin : uint8_t; +enum class StyleImageOrientation : uint8_t; +enum class StyleSystemFont : uint8_t; +enum class StyleScrollbarWidth : uint8_t; +struct OverflowAreas; +namespace dom { +class CanvasRenderingContext2D; +class DOMRectList; +class Document; +class Element; +class Event; +class HTMLImageElement; +class HTMLCanvasElement; +class HTMLVideoElement; +class ImageBitmap; +class InspectorFontFace; +class OffscreenCanvas; +class Selection; +} // namespace dom +namespace gfx { +struct RectCornerRadii; +enum class ShapedTextFlags : uint16_t; +} // namespace gfx +namespace image { +class ImageIntRegion; +struct Resolution; +} // namespace image +namespace layers { +struct FrameMetrics; +struct ScrollMetadata; +class Image; +class StackingContextHelper; +class Layer; +class WebRenderLayerManager; +} // namespace layers +namespace widget { +enum class TransparencyMode : uint8_t; +} +} // namespace mozilla + +// Flags to customize the behavior of nsLayoutUtils::DrawString. +enum class DrawStringFlags { + Default = 0x0, + ForceHorizontal = 0x1 // Forces the text to be drawn horizontally. +}; +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DrawStringFlags) + +namespace mozilla { + +class RectCallback { + public: + virtual void AddRect(const nsRect& aRect) = 0; +}; + +} // namespace mozilla + +/** + * nsLayoutUtils is a namespace class used for various helper + * functions that are useful in multiple places in layout. The goal + * is not to define multiple copies of the same static helper. + */ +class nsLayoutUtils { + typedef mozilla::AspectRatio AspectRatio; + typedef mozilla::ComputedStyle ComputedStyle; + typedef mozilla::LengthPercentage LengthPercentage; + typedef mozilla::LengthPercentageOrAuto LengthPercentageOrAuto; + typedef mozilla::dom::DOMRectList DOMRectList; + typedef mozilla::layers::StackingContextHelper StackingContextHelper; + typedef mozilla::IntrinsicSize IntrinsicSize; + typedef mozilla::RelativeTo RelativeTo; + typedef mozilla::ScrollOrigin ScrollOrigin; + typedef mozilla::ViewportType ViewportType; + typedef mozilla::gfx::SourceSurface SourceSurface; + typedef mozilla::gfx::sRGBColor sRGBColor; + typedef mozilla::gfx::DrawTarget DrawTarget; + typedef mozilla::gfx::ExtendMode ExtendMode; + typedef mozilla::gfx::SamplingFilter SamplingFilter; + typedef mozilla::gfx::Float Float; + typedef mozilla::gfx::Point Point; + typedef mozilla::gfx::Rect Rect; + typedef mozilla::gfx::RectDouble RectDouble; + typedef mozilla::gfx::Size Size; + typedef mozilla::gfx::Matrix4x4 Matrix4x4; + typedef mozilla::gfx::Matrix4x4Flagged Matrix4x4Flagged; + typedef mozilla::gfx::MatrixScales MatrixScales; + typedef mozilla::gfx::MatrixScalesDouble MatrixScalesDouble; + typedef mozilla::gfx::RectCornerRadii RectCornerRadii; + typedef mozilla::gfx::StrokeOptions StrokeOptions; + typedef mozilla::image::ImgDrawResult ImgDrawResult; + + using nsDisplayItem = mozilla::nsDisplayItem; + using nsDisplayList = mozilla::nsDisplayList; + using nsDisplayListBuilder = mozilla::nsDisplayListBuilder; + using nsDisplayListBuilderMode = mozilla::nsDisplayListBuilderMode; + using RetainedDisplayListBuilder = mozilla::RetainedDisplayListBuilder; + + public: + typedef mozilla::layers::FrameMetrics FrameMetrics; + typedef mozilla::layers::ScrollMetadata ScrollMetadata; + typedef mozilla::layers::ScrollableLayerGuid::ViewID ViewID; + typedef mozilla::CSSPoint CSSPoint; + typedef mozilla::CSSSize CSSSize; + typedef mozilla::CSSIntSize CSSIntSize; + typedef mozilla::CSSRect CSSRect; + typedef mozilla::ScreenMargin ScreenMargin; + typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize; + typedef mozilla::LayoutDeviceRect LayoutDeviceRect; + typedef mozilla::PresShell PresShell; + typedef mozilla::StyleGeometryBox StyleGeometryBox; + typedef mozilla::SVGImageContext SVGImageContext; + typedef mozilla::LogicalSize LogicalSize; + + /** + * Finds previously assigned ViewID for the given content element, if any. + * Returns whether a ViewID was previously assigned. + */ + static bool FindIDFor(const nsIContent* aContent, ViewID* aOutViewId); + + /** + * Finds previously assigned or generates a unique ViewID for the given + * content element. + */ + static ViewID FindOrCreateIDFor(nsIContent* aContent); + + /** + * Find content for given ID. + */ + static nsIContent* FindContentFor(ViewID aId); + + /** + * Find the scrollable frame for a given content element. + */ + static nsIScrollableFrame* FindScrollableFrameFor(nsIContent* aContent); + + /** + * Find the scrollable frame for a given ID. + */ + static nsIScrollableFrame* FindScrollableFrameFor(ViewID aId); + + /** + * Helper for FindScrollableFrameFor(), also used in DisplayPortUtils. + * Most clients should use FindScrollableFrameFor(). + */ + static nsIFrame* GetScrollFrameFromContent(nsIContent* aContent); + + /** + * Find the ID for a given scrollable frame. + */ + static ViewID FindIDForScrollableFrame(nsIScrollableFrame* aScrollable); + + /** + * Notify the scroll frame with the given scroll id that its scroll offset + * is being sent to APZ as part of a paint-skip transaction. + * + * Normally, this notification happens during painting, after calls to + * ComputeScrollMetadata(). During paint-skipping that code is skipped, + * but it's still important for the scroll frame to be notified for + * correctness of relative scroll updates, so the code that sends the + * empty paint-skip transaction needs to call this. + */ + static void NotifyPaintSkipTransaction(ViewID aScrollId); + + /** + * Use heuristics to figure out the child list that + * aChildFrame is currently in. + */ + static mozilla::FrameChildListID GetChildListNameFor(nsIFrame* aChildFrame); + + /** + * Returns the ::before pseudo-element for aContent, if any. + */ + static mozilla::dom::Element* GetBeforePseudo(const nsIContent* aContent); + + /** + * Returns the frame corresponding to the ::before pseudo-element for + * aContent, if any. + */ + static nsIFrame* GetBeforeFrame(const nsIContent* aContent); + + /** + * Returns the ::after pseudo-element for aContent, if any. + */ + static mozilla::dom::Element* GetAfterPseudo(const nsIContent* aContent); + + /** + * Returns the frame corresponding to the ::after pseudo-element for aContent, + * if any. + */ + static nsIFrame* GetAfterFrame(const nsIContent* aContent); + + /** + * Returns the ::marker pseudo-element for aContent, if any. + */ + static mozilla::dom::Element* GetMarkerPseudo(const nsIContent* aContent); + + /** + * Returns the frame corresponding to the ::marker pseudo-element for + * aContent, if any. + */ + static nsIFrame* GetMarkerFrame(const nsIContent* aContent); + +#ifdef ACCESSIBILITY + /** + * Set aText to the spoken text for the given ::marker content (aContent) + * if it has a frame, or the empty string otherwise. + */ + static void GetMarkerSpokenText(const nsIContent* aContent, nsAString& aText); +#endif + + /** + * Given a frame, search up the frame tree until we find an + * ancestor that (or the frame itself) is of type aFrameType, if any. + * + * @param aFrame the frame to start at + * @param aFrameType the frame type to look for + * @param aStopAt a frame to stop at after we checked it + * @return a frame of the given type or nullptr if no + * such ancestor exists + */ + static nsIFrame* GetClosestFrameOfType(nsIFrame* aFrame, + mozilla::LayoutFrameType aFrameType, + nsIFrame* aStopAt = nullptr); + + /** + * Given a frame, search up the frame tree until we find an + * ancestor that (or the frame itself) is a "Page" frame, if any. + * + * @param aFrame the frame to start at + * @return a frame of type mozilla::LayoutFrameType::Page or nullptr if no + * such ancestor exists + */ + static nsIFrame* GetPageFrame(nsIFrame* aFrame); + + /** + * Given a frame which is the primary frame for an element, + * return the frame that has the non-pseudoelement ComputedStyle for + * the content. + * This is aPrimaryFrame itself except for tableWrapper frames. + * + * Given a non-null input, this will return null if and only if its + * argument is a table wrapper frame that is mid-destruction (and its + * table frame has been destroyed). + */ + static nsIFrame* GetStyleFrame(nsIFrame* aPrimaryFrame); + static const nsIFrame* GetStyleFrame(const nsIFrame* aPrimaryFrame); + + /** + * Given a content node, + * return the frame that has the non-pseudoelement ComputedStyle for + * the content. May return null. + * This is aContent->GetPrimaryFrame() except for tableWrapper frames. + */ + static nsIFrame* GetStyleFrame(const nsIContent* aContent); + + /** + * Returns the placeholder size for when the scrollbar is unthemed. + */ + static mozilla::CSSIntCoord UnthemedScrollbarSize( + mozilla::StyleScrollbarWidth); + + /** + * The inverse of GetStyleFrame. Returns |aStyleFrame| unless it is an inner + * table frame, in which case the table wrapper frame is returned. + */ + static nsIFrame* GetPrimaryFrameFromStyleFrame(nsIFrame* aStyleFrame); + static const nsIFrame* GetPrimaryFrameFromStyleFrame( + const nsIFrame* aStyleFrame); + + /** + * Similar to nsIFrame::IsPrimaryFrame except that this will return true + * for the inner table frame rather than for its wrapper frame. + */ + static bool IsPrimaryStyleFrame(const nsIFrame* aFrame); + +#ifdef DEBUG + // TODO: remove, see bug 598468. + static bool gPreventAssertInCompareTreePosition; +#endif // DEBUG + + /** + * CompareTreePosition determines whether aContent1 comes before or + * after aContent2 in a preorder traversal of the content tree. + * + * @param aCommonAncestor either null, or a common ancestor of + * aContent1 and aContent2. Actually this is + * only a hint; if it's not an ancestor of + * aContent1 or aContent2, this function will + * still work, but it will be slower than + * normal. + * @return < 0 if aContent1 is before aContent2 + * > 0 if aContent1 is after aContent2, + * 0 otherwise (meaning they're the same, or they're in + * different documents) + */ + static int32_t CompareTreePosition( + nsIContent* aContent1, nsIContent* aContent2, + const nsIContent* aCommonAncestor = nullptr) { + return DoCompareTreePosition(aContent1, aContent2, -1, 1, aCommonAncestor); + } + + /* + * More generic version of |CompareTreePosition|. |aIf1Ancestor| + * gives the value to return when 1 is an ancestor of 2, and likewise + * for |aIf2Ancestor|. Passing (-1, 1) gives preorder traversal + * order, and (1, -1) gives postorder traversal order. + */ + static int32_t DoCompareTreePosition( + nsIContent* aContent1, nsIContent* aContent2, int32_t aIf1Ancestor, + int32_t aIf2Ancestor, const nsIContent* aCommonAncestor = nullptr); + + /** + * CompareTreePosition determines whether aFrame1 comes before or + * after aFrame2 in a preorder traversal of the frame tree, where out + * of flow frames are treated as children of their placeholders. This is + * basically the same ordering as DoCompareTreePosition(nsIContent*) except + * that it handles anonymous content properly and there are subtleties with + * continuations. + * + * @param aCommonAncestor either null, or a common ancestor of + * aContent1 and aContent2. Actually this is + * only a hint; if it's not an ancestor of + * aContent1 or aContent2, this function will + * still work, but it will be slower than + * normal. + * @return < 0 if aContent1 is before aContent2 + * > 0 if aContent1 is after aContent2, + * 0 otherwise (meaning they're the same, or they're in + * different frame trees) + */ + static int32_t CompareTreePosition(nsIFrame* aFrame1, nsIFrame* aFrame2, + nsIFrame* aCommonAncestor = nullptr) { + return DoCompareTreePosition(aFrame1, aFrame2, -1, 1, aCommonAncestor); + } + + static int32_t CompareTreePosition(nsIFrame* aFrame1, nsIFrame* aFrame2, + nsTArray& aFrame2Ancestors, + nsIFrame* aCommonAncestor = nullptr) { + return DoCompareTreePosition(aFrame1, aFrame2, aFrame2Ancestors, -1, 1, + aCommonAncestor); + } + + /* + * More generic version of |CompareTreePosition|. |aIf1Ancestor| + * gives the value to return when 1 is an ancestor of 2, and likewise + * for |aIf2Ancestor|. Passing (-1, 1) gives preorder traversal + * order, and (1, -1) gives postorder traversal order. + */ + static int32_t DoCompareTreePosition(nsIFrame* aFrame1, nsIFrame* aFrame2, + int32_t aIf1Ancestor, + int32_t aIf2Ancestor, + nsIFrame* aCommonAncestor = nullptr); + + static nsIFrame* FillAncestors(nsIFrame* aFrame, nsIFrame* aStopAtAncestor, + nsTArray* aAncestors); + + static int32_t DoCompareTreePosition(nsIFrame* aFrame1, nsIFrame* aFrame2, + nsTArray& aFrame2Ancestors, + int32_t aIf1Ancestor, + int32_t aIf2Ancestor, + nsIFrame* aCommonAncestor); + + /** + * LastContinuationWithChild gets the last continuation in aFrame's chain + * that has a child, or the first continuation if the frame has no children. + */ + static nsContainerFrame* LastContinuationWithChild(nsContainerFrame* aFrame); + + /** + * GetLastSibling simply finds the last sibling of aFrame, or returns nullptr + * if aFrame is null. + */ + static nsIFrame* GetLastSibling(nsIFrame* aFrame); + + /** + * FindSiblingViewFor locates the child of aParentView that aFrame's + * view should be inserted 'above' (i.e., before in sibling view + * order). This is the first child view of aParentView whose + * corresponding content is before aFrame's content (view siblings + * are in reverse content order). + */ + static nsView* FindSiblingViewFor(nsView* aParentView, nsIFrame* aFrame); + + /** + * Get the parent of aFrame. If aFrame is the root frame for a document, + * and the document has a parent document in the same view hierarchy, then + * we try to return the subdocumentframe in the parent document. + * @param aCrossDocOffset [in/out] if non-null, then as we cross documents + * an extra offset may be required and it will be added to aCrossDocOffset. + * Be careful dealing with this extra offset as it is in app units of the + * parent document, which may have a different app units per dev pixel ratio + * than the child document. + * Note that, while this function crosses document boundaries, it (naturally) + * cannot cross process boundaries. + */ + static nsIFrame* GetCrossDocParentFrameInProcess( + const nsIFrame* aFrame, nsPoint* aCrossDocOffset = nullptr); + + /** + * Does the same thing as GetCrossDocParentFrameInProcess(). + * The purpose of having two functions is to more easily track which call + * sites have been audited to consider out-of-process iframes (bug 1599913). + * Once all call sites have been audited, this function can be removed. + */ + static nsIFrame* GetCrossDocParentFrame(const nsIFrame* aFrame, + nsPoint* aCrossDocOffset = nullptr); + + /** + * IsProperAncestorFrame checks whether aAncestorFrame is an ancestor + * of aFrame and not equal to aFrame. + * @param aCommonAncestor nullptr, or a common ancestor of aFrame and + * aAncestorFrame. If non-null, this can bound the search and speed up + * the function + */ + static bool IsProperAncestorFrame(const nsIFrame* aAncestorFrame, + const nsIFrame* aFrame, + const nsIFrame* aCommonAncestor = nullptr); + + /** + * Like IsProperAncestorFrame, but looks across document boundaries. + * + * Just like IsAncestorFrameCrossDoc, except that it returns false when + * aFrame == aAncestorFrame. + * TODO: Once after we fixed bug 1715932, this function should be removed. + */ + static bool IsProperAncestorFrameCrossDoc( + const nsIFrame* aAncestorFrame, const nsIFrame* aFrame, + const nsIFrame* aCommonAncestor = nullptr); + + /** + * Like IsProperAncestorFrame, but looks across document boundaries. + * + * Just like IsAncestorFrameCrossDoc, except that it returns false when + * aFrame == aAncestorFrame. + */ + static bool IsProperAncestorFrameCrossDocInProcess( + const nsIFrame* aAncestorFrame, const nsIFrame* aFrame, + const nsIFrame* aCommonAncestor = nullptr); + + /** + * IsAncestorFrameCrossDoc checks whether aAncestorFrame is an ancestor + * of aFrame or equal to aFrame, looking across document boundaries. + * @param aCommonAncestor nullptr, or a common ancestor of aFrame and + * aAncestorFrame. If non-null, this can bound the search and speed up + * the function. + * + * Just like IsProperAncestorFrameCrossDoc, except that it returns true when + * aFrame == aAncestorFrame. + * + * TODO: Bug 1700245, all call sites of this function will be eventually + * replaced by IsAncestorFrameCrossDocInProcess. + */ + static bool IsAncestorFrameCrossDoc( + const nsIFrame* aAncestorFrame, const nsIFrame* aFrame, + const nsIFrame* aCommonAncestor = nullptr); + + /** + * IsAncestorFrameCrossDocInProcess checks whether aAncestorFrame is an + * ancestor of aFrame or equal to aFrame, looking across document boundaries + * in the same process. + * @param aCommonAncestor nullptr, or a common ancestor of aFrame and + * aAncestorFrame. If non-null, this can bound the search and speed up + * the function. + * + * Just like IsProperAncestorFrameCrossDoc, except that it returns true when + * aFrame == aAncestorFrame. + * + * NOTE: This function doesn't return true even if |aAncestorFrame| and + * |aFrame| is in the same process but they are not directly connected, e.g. + * both |aAncestorFrame| and |aFrame| in A domain documents, but there's + * another an iframe document domain B, such as A1 -> B1 ->A2 document tree. + */ + static bool IsAncestorFrameCrossDocInProcess( + const nsIFrame* aAncestorFrame, const nsIFrame* aFrame, + const nsIFrame* aCommonAncestor = nullptr); + + static mozilla::SideBits GetSideBitsForFixedPositionContent( + const nsIFrame* aFixedPosFrame); + + /** + * Get the scroll id for the root scrollframe of the presshell of the given + * prescontext. Returns NULL_SCROLL_ID if it couldn't be found. + */ + static ViewID ScrollIdForRootScrollFrame(nsPresContext* aPresContext); + + /** + * GetScrollableFrameFor returns the scrollable frame for a scrolled frame + */ + static nsIScrollableFrame* GetScrollableFrameFor( + const nsIFrame* aScrolledFrame); + + /** + * GetNearestScrollableFrameForDirection locates the first ancestor of + * aFrame (or aFrame itself) that is scrollable with overflow:scroll or + * overflow:auto in the given direction and where either the scrollbar for + * that direction is visible or the frame can be scrolled by some + * positive amount in that direction. + * The search extends across document boundaries. + * + * @param aFrame the frame to start with + * @param aDirection Whether it's for horizontal or vertical scrolling. + * @return the nearest scrollable frame or nullptr if not found + */ + static nsIScrollableFrame* GetNearestScrollableFrameForDirection( + nsIFrame* aFrame, mozilla::layers::ScrollDirections aDirections); + + enum { + /** + * If the SCROLLABLE_SAME_DOC flag is set, then we only walk the frame tree + * up to the root frame in the current document. + */ + SCROLLABLE_SAME_DOC = 0x01, + /** + * If the SCROLLABLE_INCLUDE_HIDDEN flag is set then we allow + * overflow:hidden scrollframes to be returned as scrollable frames. + */ + SCROLLABLE_INCLUDE_HIDDEN = 0x02, + /** + * If the SCROLLABLE_ONLY_ASYNC_SCROLLABLE flag is set, then we only + * want to match scrollable frames for which WantAsyncScroll() returns + * true. + */ + SCROLLABLE_ONLY_ASYNC_SCROLLABLE = 0x04, + /** + * If the SCROLLABLE_ALWAYS_MATCH_ROOT flag is set, then we will always + * return the root scrollable frame for the root document (in the current + * process) if we encounter it, whether or not it is async scrollable or + * overflow: hidden. + */ + SCROLLABLE_ALWAYS_MATCH_ROOT = 0x08, + /** + * If the SCROLLABLE_FIXEDPOS_FINDS_ROOT flag is set, then for fixed-pos + * frames return the root scrollable frame for that document. + */ + SCROLLABLE_FIXEDPOS_FINDS_ROOT = 0x10, + /** + * If the SCROLLABLE_STOP_AT_PAGE flag is set, then we stop searching + * for scrollable ancestors when seeing a nsPageFrame. This can be used + * to avoid finding the viewport scroll frame in Print Preview (which + * would be undesirable as a 'position:sticky' container for content). + */ + SCROLLABLE_STOP_AT_PAGE = 0x20, + }; + /** + * GetNearestScrollableFrame locates the first ancestor of aFrame + * (or aFrame itself) that is scrollable with overflow:scroll or + * overflow:auto in some direction. + * + * @param aFrame the frame to start with + * @param aFlags if SCROLLABLE_SAME_DOC is set, do not search across + * document boundaries. If SCROLLABLE_INCLUDE_HIDDEN is set, include + * frames scrollable with overflow:hidden. + * @return the nearest scrollable frame or nullptr if not found + */ + static nsIScrollableFrame* GetNearestScrollableFrame(nsIFrame* aFrame, + uint32_t aFlags = 0); + + /** + * GetScrolledRect returns the range of allowable scroll offsets + * for aScrolledFrame, assuming the scrollable overflow area is + * aScrolledFrameOverflowArea and the scrollport size is aScrollPortSize. + */ + static nsRect GetScrolledRect(nsIFrame* aScrolledFrame, + const nsRect& aScrolledFrameOverflowArea, + const nsSize& aScrollPortSize, + mozilla::StyleDirection); + + /** + * HasPseudoStyle returns true if aContent (whose primary style + * context is aComputedStyle) has the aPseudoElement pseudo-style + * attached to it; returns false otherwise. + * + * @param aContent the content node we're looking at + * @param aComputedStyle aContent's ComputedStyle + * @param aPseudoElement the id of the pseudo style we care about + * @param aPresContext the presentation context + * @return whether aContent has aPseudoElement style attached to it + */ + static bool HasPseudoStyle(nsIContent* aContent, + ComputedStyle* aComputedStyle, + mozilla::PseudoStyleType aPseudoElement, + nsPresContext* aPresContext); + + /** + * If this frame is a placeholder for a float, then return the float, + * otherwise return nullptr. aPlaceholder must be a placeholder frame. + */ + static nsIFrame* GetFloatFromPlaceholder(nsIFrame* aPlaceholder); + + // Combine aOrigClearType with aNewClearType, but limit the clear types + // to StyleClear::Left, Right, Both. + static mozilla::StyleClear CombineClearType( + mozilla::StyleClear aOrigClearType, mozilla::StyleClear aNewClearType); + + /** + * Get the coordinates of a given DOM mouse event, relative to a given + * frame. Works only for DOM events generated by WidgetGUIEvents. + * @param aDOMEvent the event + * @param aFrame the frame to make coordinates relative to + * @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if + * for some reason the coordinates for the mouse are not known (e.g., + * the event is not a GUI event). + */ + static nsPoint GetDOMEventCoordinatesRelativeTo( + mozilla::dom::Event* aDOMEvent, nsIFrame* aFrame); + + /** + * Get the coordinates of a given native mouse event, relative to a given + * frame. + * @param aEvent the event + * @param aFrame the frame to make coordinates relative to + * @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if + * for some reason the coordinates for the mouse are not known (e.g., + * the event is not a GUI event). + */ + static nsPoint GetEventCoordinatesRelativeTo( + const mozilla::WidgetEvent* aEvent, RelativeTo aFrame); + + /** + * Get the coordinates of a given point relative to an event and a + * given frame. + * @param aEvent the event + * @param aPoint the point to get the coordinates relative to + * @param aFrame the frame to make coordinates relative to + * @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if + * for some reason the coordinates for the mouse are not known (e.g., + * the event is not a GUI event). + */ + static nsPoint GetEventCoordinatesRelativeTo( + const mozilla::WidgetEvent* aEvent, + const mozilla::LayoutDeviceIntPoint& aPoint, RelativeTo aFrame); + + /** + * Get the coordinates of a given point relative to a widget and a + * given frame. + * @param aWidget the event src widget + * @param aPoint the point to get the coordinates relative to + * @param aFrame the frame to make coordinates relative to + * @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if + * for some reason the coordinates for the mouse are not known (e.g., + * the event is not a GUI event). + */ + static nsPoint GetEventCoordinatesRelativeTo( + nsIWidget* aWidget, const mozilla::LayoutDeviceIntPoint& aPoint, + RelativeTo aFrame); + + /** + * Get the popup frame of a given native mouse event. + * @param aRootPresContext only check popups within aRootPresContext or a + * descendant + * @param aEvent the event. + * @return Null, if there is no popup frame at the point, otherwise, + * returns top-most popup frame at the point. + */ + static nsIFrame* GetPopupFrameForEventCoordinates( + nsPresContext* aRootPresContext, const mozilla::WidgetEvent* aEvent); + + /** + * Get the popup frame of a given point relative to a widget. + * @param aRootPresContext only check popups within aRootPresContext or a + * descendant + * @param aEvent the event. + * @return Null, if there is no popup frame at the point, otherwise, + * returns top-most popup frame at the point. + */ + enum class GetPopupFrameForPointFlags : uint8_t { + OnlyReturnFramesWithWidgets = 0x1, + }; + static nsIFrame* GetPopupFrameForPoint( + nsPresContext* aRootPresContext, nsIWidget* aWidget, + const mozilla::LayoutDeviceIntPoint& aPoint, + GetPopupFrameForPointFlags aFlags = GetPopupFrameForPointFlags(0)); + + /** + * Get container and offset if aEvent collapses Selection. + * @param aPresShell The PresShell handling aEvent. + * @param aEvent The event having coordinates where you want to + * collapse Selection. + * @param aContainer Returns the container node at the point. + * Set nullptr if you don't need this. + * @param aOffset Returns offset in the container node at the point. + * Set nullptr if you don't need this. + */ + MOZ_CAN_RUN_SCRIPT + static void GetContainerAndOffsetAtEvent(PresShell* aPresShell, + const mozilla::WidgetEvent* aEvent, + nsIContent** aContainer, + int32_t* aOffset); + + /** + * Translate from widget coordinates to the view's coordinates + * @param aPresContext the PresContext for the view + * @param aWidget the widget + * @param aPt the point relative to the widget + * @param aView view to which returned coordinates are relative + * @return the point in the view's coordinates + */ + static nsPoint TranslateWidgetToView(nsPresContext* aPresContext, + nsIWidget* aWidget, + const mozilla::LayoutDeviceIntPoint& aPt, + nsView* aView); + + /** + * Translate from view coordinates to the widget's coordinates. + * @param aPresContext the PresContext for the view + * @param aView the view + * @param aPt the point relative to the view + * @param aViewportType whether the point is in visual or layout coordinates + * @param aWidget the widget to which returned coordinates are relative + * @return the point in the view's coordinates + */ + static mozilla::LayoutDeviceIntPoint TranslateViewToWidget( + nsPresContext* aPresContext, nsView* aView, nsPoint aPt, + ViewportType aViewportType, nsIWidget* aWidget); + + static mozilla::LayoutDeviceIntPoint WidgetToWidgetOffset( + nsIWidget* aFromWidget, nsIWidget* aToWidget); + + enum class FrameForPointOption { + /** + * When set, paint suppression is ignored, so we'll return non-root page + * elements even if paint suppression is stopping them from painting. + */ + IgnorePaintSuppression = 1, + /** + * When set, clipping due to the root scroll frame (and any other viewport- + * related clipping) is ignored. + */ + IgnoreRootScrollFrame, + /** + * When set, return only content in the same document as aFrame. + */ + IgnoreCrossDoc, + /** + * When set, return only content that is actually visible. + */ + OnlyVisible, + }; + + struct FrameForPointOptions { + using Bits = mozilla::EnumSet; + + Bits mBits; + // If mBits contains OnlyVisible, what is the opacity threshold which we + // consider "opaque enough" to clobber stuff underneath. + float mVisibleThreshold; + + FrameForPointOptions(Bits aBits, float aVisibleThreshold) + : mBits(aBits), mVisibleThreshold(aVisibleThreshold){}; + + MOZ_IMPLICIT FrameForPointOptions(Bits aBits) + : FrameForPointOptions(aBits, 1.0f) {} + + FrameForPointOptions() : FrameForPointOptions(Bits()){}; + }; + + /** + * Given aFrame, the root frame of a stacking context, find its descendant + * frame under the point aPt that receives a mouse event at that location, + * or nullptr if there is no such frame. + * @param aPt the point, relative to the frame origin, in either visual + * or layout coordinates depending on aRelativeTo.mViewportType + */ + static nsIFrame* GetFrameForPoint(RelativeTo aRelativeTo, nsPoint aPt, + const FrameForPointOptions& = {}); + + /** + * Given aFrame, the root frame of a stacking context, find all descendant + * frames under the area of a rectangle that receives a mouse event, + * or nullptr if there is no such frame. + * @param aRect the rect, relative to the frame origin, in either visual + * or layout coordinates depending on aRelativeTo.mViewportType + * @param aOutFrames an array to add all the frames found + */ + static nsresult GetFramesForArea(RelativeTo aRelativeTo, const nsRect& aRect, + nsTArray& aOutFrames, + const FrameForPointOptions& = {}); + + /** + * Transform aRect relative to aFrame up to the coordinate system of + * aAncestor. Computes the bounding-box of the true quadrilateral. + * Pass non-null aPreservesAxisAlignedRectangles and it will be set to true if + * we only need to use a 2d transform that PreservesAxisAlignedRectangles(). + * The corner positions of aRect are treated as meaningful even if aRect is + * empty. + * + * |aMatrixCache| allows for optimizations in recomputing the same matrix over + * and over. The argument can be one of the following values: + * + * nullptr (the default) - No optimization; the transform matrix is computed + * on every call to this function. + * + * non-null pointer to an empty Maybe - Upon return, the Maybe is + * filled with the transform matrix that was computed. This can then be passed + * in to subsequent calls with the same source and destination frames to avoid + * recomputing the matrix. + * + * non-null pointer to a non-empty Matrix4x4 - The provided matrix will be + * used as the transform matrix and applied to the rect. + */ + static nsRect TransformFrameRectToAncestor( + const nsIFrame* aFrame, const nsRect& aRect, const nsIFrame* aAncestor, + bool* aPreservesAxisAlignedRectangles = nullptr, + mozilla::Maybe* aMatrixCache = nullptr, + bool aStopAtStackingContextAndDisplayPortAndOOFFrame = false, + nsIFrame** aOutAncestor = nullptr) { + return TransformFrameRectToAncestor( + aFrame, aRect, RelativeTo{aAncestor}, aPreservesAxisAlignedRectangles, + aMatrixCache, aStopAtStackingContextAndDisplayPortAndOOFFrame, + aOutAncestor); + } + static nsRect TransformFrameRectToAncestor( + const nsIFrame* aFrame, const nsRect& aRect, RelativeTo aAncestor, + bool* aPreservesAxisAlignedRectangles = nullptr, + mozilla::Maybe* aMatrixCache = nullptr, + bool aStopAtStackingContextAndDisplayPortAndOOFFrame = false, + nsIFrame** aOutAncestor = nullptr); + + /** + * Gets the transform for aFrame relative to aAncestor. Pass null for + * aAncestor to go up to the root frame. Including nsIFrame::IN_CSS_UNITS + * flag in aFlags will return CSS pixels, by default it returns device + * pixels. + * More info can be found in nsIFrame::GetTransformMatrix. + * + * Some notes on the possible combinations of |aFrame.mViewportType| and + * |aAncestor.mViewportType|: + * + * | aFrame. | aAncestor. | Notes + * | mViewportType | mViewportType | + * ========================================================================== + * | Layout | Layout | Commonplace, when both source and target + * | | | are inside zoom boundary. + * | | | + * | | | Could also happen in non-e10s setups + * | | | when both source and target are outside + * | | | the zoom boundary and the code is + * | | | oblivious to the existence of a zoom + * | | | boundary. + * ========================================================================== + * | Layout | Visual | Commonplace, used when hit testing visual + * | | | coordinates (e.g. coming from user input + * | | | events). We expected to encounter a + * | | | zoomed content root during traversal and + * | | | apply a layout-to-visual transform. + * ========================================================================== + * | Visual | Layout | Should never happen, will assert. + * ========================================================================== + * | Visual | Visual | In e10s setups, should only happen if + * | | | aFrame and aAncestor are both the + * | | | RCD viewport frame. + * | | | + * | | | In non-e10s setups, could happen with + * | | | different frames if they are both + * | | | outside the zoom boundary. + * ========================================================================== + */ + static Matrix4x4Flagged GetTransformToAncestor( + RelativeTo aFrame, RelativeTo aAncestor, uint32_t aFlags = 0, + nsIFrame** aOutAncestor = nullptr); + + /** + * Gets the scale factors of the transform for aFrame relative to the root + * frame if this transform can be drawn 2D, or the identity scale factors + * otherwise. + */ + static MatrixScales GetTransformToAncestorScale(const nsIFrame* aFrame); + + /** + * Gets the scale factors of the transform for aFrame relative to the root + * frame if this transform is 2D, or the identity scale factors otherwise. + * If some frame on the path from aFrame to the display root frame may have an + * animated scale, returns the identity scale factors. + */ + static MatrixScales GetTransformToAncestorScaleExcludingAnimated( + nsIFrame* aFrame); + + /** + * Gets a scale that includes CSS transforms in this process as well as the + * transform to ancestor scale passed down from our direct ancestor process + * (which includes any enclosing CSS transforms and resolution). Note: this + * does not include any resolution in the current process (this is on purpose + * because that is what the transform to ancestor field on FrameMetrics needs, + * see its definition for explanation as to why). This is the transform to + * ancestor scale to set on FrameMetrics. + */ + static mozilla::ParentLayerToScreenScale2D + GetTransformToAncestorScaleCrossProcessForFrameMetrics( + const nsIFrame* aFrame); + + /** + * Find the nearest common ancestor frame for aFrame1 and aFrame2. The + * ancestor frame could be cross-doc. + */ + static const nsIFrame* FindNearestCommonAncestorFrame( + const nsIFrame* aFrame1, const nsIFrame* aFrame2); + + /** + * Find the nearest common ancestor frame for aFrame1 and aFrame2, assuming + * that they are within the same block. + * + * Returns null if they are not within the same block. + */ + static const nsIFrame* FindNearestCommonAncestorFrameWithinBlock( + const nsTextFrame* aFrame1, const nsTextFrame* aFrame2); + + /** + * Whether author-specified borders / backgrounds disable theming for a given + * appearance value. + */ + static bool AuthorSpecifiedBorderBackgroundDisablesTheming( + mozilla::StyleAppearance); + + /** + * Transforms a list of CSSPoints from aFromFrame to aToFrame, taking into + * account all relevant transformations on the frames up to (but excluding) + * their nearest common ancestor. + * If we encounter a transform that we need to invert but which is + * non-invertible, we return NONINVERTIBLE_TRANSFORM. If the frames have + * no common ancestor, we return NO_COMMON_ANCESTOR. + * If this returns TRANSFORM_SUCCEEDED, the points in aPoints are transformed + * in-place, otherwise they are untouched. + */ + enum TransformResult { + TRANSFORM_SUCCEEDED, + NO_COMMON_ANCESTOR, + NONINVERTIBLE_TRANSFORM + }; + static TransformResult TransformPoints(RelativeTo aFromFrame, + RelativeTo aToFrame, + uint32_t aPointCount, + CSSPoint* aPoints); + + /** + * Same as above function, but transform points in app units and + * handle 1 point per call. + */ + static TransformResult TransformPoint(RelativeTo aFromFrame, + RelativeTo aToFrame, nsPoint& aPoint); + + /** + * Transforms a rect from aFromFrame to aToFrame. In app units. + * Returns the bounds of the actual rect if the transform requires rotation + * or anything complex like that. + */ + static TransformResult TransformRect(const nsIFrame* aFromFrame, + const nsIFrame* aToFrame, nsRect& aRect); + + /** + * Converts app units to pixels (with optional snapping) and appends as a + * translation to aTransform. + */ + static void PostTranslate(Matrix4x4& aTransform, const nsPoint& aOrigin, + float aAppUnitsPerPixel, bool aRounded); + + /* + * Whether the frame should snap to grid. This will end up being passed + * as the aRounded parameter in PostTranslate above. SVG frames should + * not have their translation rounded. + */ + static bool ShouldSnapToGrid(const nsIFrame* aFrame); + + /** + * Get the border-box of aElement's primary frame, transformed it to be + * relative to aFrame. + */ + static nsRect GetRectRelativeToFrame(mozilla::dom::Element* aElement, + nsIFrame* aFrame); + + /** + * Returns true if aRect with border inflation of size aInflateSize contains + * aPoint. + */ + static bool ContainsPoint(const nsRect& aRect, const nsPoint& aPoint, + nscoord aInflateSize); + + /** + * Clamp aRect relative to aFrame to the scroll frames boundary searching from + * aFrame. + */ + static nsRect ClampRectToScrollFrames(nsIFrame* aFrame, const nsRect& aRect); + + /** + * Given a point in the global coordinate space, returns that point expressed + * in the coordinate system of aFrame. This effectively inverts all + * transforms between this point and the root frame. + * + * @param aFromType Specifies whether |aPoint| is in layout or visual + * coordinates. + * @param aFrame The frame that acts as the coordinate space container. + * @param aPoint The point, in global layout or visual coordinates (as per + * |aFromType|, to get in the frame-local space. + * @return aPoint, expressed in aFrame's canonical coordinate space. + */ + static nsPoint TransformRootPointToFrame(ViewportType aFromType, + RelativeTo aFrame, + const nsPoint& aPoint) { + return TransformAncestorPointToFrame(aFrame, aPoint, + RelativeTo{nullptr, aFromType}); + } + + /** + * Transform aPoint relative to aAncestor down to the coordinate system of + * aFrame. + */ + static nsPoint TransformAncestorPointToFrame(RelativeTo aFrame, + const nsPoint& aPoint, + RelativeTo aAncestor); + + /** + * Helper function that, given a rectangle and a matrix, returns the smallest + * rectangle containing the image of the source rectangle. + * + * @param aBounds The rectangle to transform. + * @param aMatrix The matrix to transform it with. + * @param aFactor The number of app units per graphics unit. + * @return The smallest rect that contains the image of aBounds. + */ + static nsRect MatrixTransformRect(const nsRect& aBounds, + const Matrix4x4& aMatrix, float aFactor); + static nsRect MatrixTransformRect(const nsRect& aBounds, + const Matrix4x4Flagged& aMatrix, + float aFactor); + + /** + * Helper function that, given a point and a matrix, returns the image + * of that point under the matrix transform. + * + * @param aPoint The point to transform. + * @param aMatrix The matrix to transform it with. + * @param aFactor The number of app units per graphics unit. + * @return The image of the point under the transform. + */ + static nsPoint MatrixTransformPoint(const nsPoint& aPoint, + const Matrix4x4& aMatrix, float aFactor); + + /** + * Given a graphics rectangle in graphics space, return a rectangle in + * app space that contains the graphics rectangle, rounding out as necessary. + * + * @param aRect The graphics rect to round outward. + * @param aFactor The number of app units per graphics unit. + * @return The smallest rectangle in app space that contains aRect. + */ + template + static nsRect RoundGfxRectToAppRect(const T& aRect, const float aFactor); + + /** + * Returns a subrectangle of aContainedRect that is entirely inside the + * rounded rect. Complex cases are handled conservatively by returning a + * smaller rect than necessary. + */ + static nsRegion RoundedRectIntersectRect(const nsRect& aRoundedRect, + const nscoord aRadii[8], + const nsRect& aContainedRect); + static nsIntRegion RoundedRectIntersectIntRect( + const nsIntRect& aRoundedRect, const RectCornerRadii& aCornerRadii, + const nsIntRect& aContainedRect); + + /** + * Return whether any part of aTestRect is inside of the rounded + * rectangle formed by aBounds and aRadii (which are indexed by the + * enum HalfCorner constants in gfx/2d/Types.h). This is precise. + */ + static bool RoundedRectIntersectsRect(const nsRect& aRoundedRect, + const nscoord aRadii[8], + const nsRect& aTestRect); + + enum class PaintFrameFlags : uint32_t { + InTransform = 0x01, + SyncDecodeImages = 0x02, + WidgetLayers = 0x04, + IgnoreSuppression = 0x08, + DocumentRelative = 0x10, + HideCaret = 0x20, + ToWindow = 0x40, + ExistingTransaction = 0x80, + ForWebRender = 0x100, + UseHighQualityScaling = 0x200, + ResetViewportScrolling = 0x400, + }; + + /** + * Given aFrame, the root frame of a stacking context, paint it and its + * descendants to aRenderingContext. + * @param aRenderingContext a rendering context translated so that (0,0) + * is the origin of aFrame; for best results, (0,0) should transform + * to pixel-aligned coordinates. This can be null, in which case + * aFrame must be a "display root" (root frame for a root document, + * or the root of a popup) with an associated widget and we draw using + * the layer manager for the frame's widget. + * @param aDirtyRegion the region that must be painted, in the coordinates + * of aFrame. + * @param aBackstop paint the dirty area with this color before drawing + * the actual content; pass NS_RGBA(0,0,0,0) to draw no background. + * @param aBuilderMode Passed through to the display-list builder. + * @param aFlags if PAINT_IN_TRANSFORM is set, then we assume + * this is inside a transform or SVG foreignObject. If + * PAINT_SYNC_DECODE_IMAGES is set, we force synchronous decode on all + * images. If PAINT_WIDGET_LAYERS is set, aFrame must be a display root, + * and we will use the frame's widget's layer manager to paint + * even if aRenderingContext is non-null. This is useful if you want + * to force rendering to use the widget's layer manager for testing + * or speed. PAINT_WIDGET_LAYERS must be set if aRenderingContext is null. + * If PAINT_DOCUMENT_RELATIVE is used, the visible region is interpreted + * as being relative to the document (normally it's relative to the CSS + * viewport) and the document is painted as if no scrolling has occured. + * Only considered if PresShell::IgnoringViewportScrolling is true. + * If ResetViewportScrolling is used, then the root scroll frame's scroll + * position is set to 0 during painting, so that position:fixed elements + * are drawn in their initial position. + * PAINT_TO_WINDOW sets painting to window to true on the display list + * builder even if we can't tell that we are painting to the window. + * If PAINT_EXISTING_TRANSACTION is set, then BeginTransaction() has already + * been called on aFrame's widget's layer manager and should not be + * called again. + * If PAINT_COMPRESSED is set, the FrameLayerBuilder should be set to + * compressed mode to avoid short cut optimizations. + * + * So there are three possible behaviours: + * 1) PAINT_WIDGET_LAYERS is set and aRenderingContext is null; we paint + * by calling BeginTransaction on the widget's layer manager. + * 2) PAINT_WIDGET_LAYERS is set and aRenderingContext is non-null; we + * paint by calling BeginTransactionWithTarget on the widget's layer + * manager. + * 3) PAINT_WIDGET_LAYERS is not set and aRenderingContext is non-null; + * we paint by construct a BasicLayerManager and calling + * BeginTransactionWithTarget on it. This is desirable if we're doing + * something like drawWindow in a mode where what gets rendered doesn't + * necessarily correspond to what's visible in the window; we don't + * want to mess up the widget's layer tree. + */ + static void PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame, + const nsRegion& aDirtyRegion, nscolor aBackstop, + nsDisplayListBuilderMode aBuilderMode, + PaintFrameFlags aFlags = PaintFrameFlags(0)); + + /** + * Uses a binary search for find where the cursor falls in the line of text + * It also keeps track of the part of the string that has already been + * measured so it doesn't have to keep measuring the same text over and over. + * + * @param "aBaseWidth" contains the width in twips of the portion + * of the text that has already been measured, and aBaseInx contains + * the index of the text that has already been measured. + * + * @param aTextWidth returns (in twips) the length of the text that falls + * before the cursor aIndex contains the index of the text where the cursor + * falls. + */ + static bool BinarySearchForPosition(DrawTarget* aDrawTarget, + nsFontMetrics& aFontMetrics, + const char16_t* aText, int32_t aBaseWidth, + int32_t aBaseInx, int32_t aStartInx, + int32_t aEndInx, int32_t aCursorPos, + int32_t& aIndex, int32_t& aTextWidth); + + class BoxCallback { + public: + BoxCallback() = default; + virtual void AddBox(nsIFrame* aFrame) = 0; + bool mIncludeCaptionBoxForTable = true; + // Whether we are in a continuation or ib-split-sibling of the target we're + // measuring. This is useful because if we know we're in the target subtree + // and measuring against it we can avoid finding the common ancestor. + bool mInTargetContinuation = false; + }; + /** + * Collect all CSS boxes associated with aFrame and its + * continuations, "drilling down" through table wrapper frames and + * some anonymous blocks since they're not real CSS boxes. + * If aFrame is null, no boxes are returned. + * SVG frames return a single box, themselves. + */ + static void GetAllInFlowBoxes(nsIFrame* aFrame, BoxCallback* aCallback); + + /** + * Like GetAllInFlowBoxes, but doesn't include continuations. + */ + static void AddBoxesForFrame(nsIFrame* aFrame, BoxCallback* aCallback); + + /** + * Find the first frame descendant of aFrame (including aFrame) which is + * not an anonymous frame that getBoxQuads/getClientRects should ignore. + */ + static nsIFrame* GetFirstNonAnonymousFrame(nsIFrame* aFrame); + + struct RectAccumulator : public mozilla::RectCallback { + nsRect mResultRect; + nsRect mFirstRect; + bool mSeenFirstRect; + + RectAccumulator(); + + virtual void AddRect(const nsRect& aRect) override; + }; + + struct RectListBuilder : public mozilla::RectCallback { + DOMRectList* mRectList; + + explicit RectListBuilder(DOMRectList* aList); + virtual void AddRect(const nsRect& aRect) override; + }; + + static nsIFrame* GetContainingBlockForClientRect(nsIFrame* aFrame); + + enum { + RECTS_ACCOUNT_FOR_TRANSFORMS = 0x01, + // Two bits for specifying which box type to use. + // With neither bit set (default), use the border box. + RECTS_USE_CONTENT_BOX = 0x02, + RECTS_USE_PADDING_BOX = 0x04, + RECTS_USE_MARGIN_BOX = 0x06, // both bits set + RECTS_WHICH_BOX_MASK = 0x06 // bitmask for these two bits + }; + /** + * Collect all CSS boxes (content, padding, border, or margin) associated + * with aFrame and its continuations, "drilling down" through table wrapper + * frames and some anonymous blocks since they're not real CSS boxes. + * The boxes are positioned relative to aRelativeTo (taking scrolling + * into account) and passed to the callback in frame-tree order. + * If aFrame is null, no boxes are returned. + * For SVG frames, returns one rectangle, the bounding box. + * If aFlags includes RECTS_ACCOUNT_FOR_TRANSFORMS, then when converting + * the boxes into aRelativeTo coordinates, transforms (including CSS + * and SVG transforms) are taken into account. + * If aFlags includes one of RECTS_USE_CONTENT_BOX, RECTS_USE_PADDING_BOX, + * or RECTS_USE_MARGIN_BOX, the corresponding type of box is used. + * Otherwise (by default), the border box is used. + */ + static void GetAllInFlowRects(nsIFrame* aFrame, const nsIFrame* aRelativeTo, + mozilla::RectCallback* aCallback, + uint32_t aFlags = 0); + + static void GetAllInFlowRectsAndTexts( + nsIFrame* aFrame, const nsIFrame* aRelativeTo, + mozilla::RectCallback* aCallback, + mozilla::dom::Sequence* aTextList, uint32_t aFlags = 0); + + /** + * Computes the union of all rects returned by GetAllInFlowRects. If + * the union is empty, returns the first rect. + * If aFlags includes RECTS_ACCOUNT_FOR_TRANSFORMS, then when converting + * the boxes into aRelativeTo coordinates, transforms (including CSS + * and SVG transforms) are taken into account. + * If aFlags includes one of RECTS_USE_CONTENT_BOX, RECTS_USE_PADDING_BOX, + * or RECTS_USE_MARGIN_BOX, the corresponding type of box is used. + * Otherwise (by default), the border box is used. + */ + static nsRect GetAllInFlowRectsUnion(nsIFrame* aFrame, + const nsIFrame* aRelativeTo, + uint32_t aFlags = 0); + + enum { EXCLUDE_BLUR_SHADOWS = 0x01 }; + /** + * Takes a text-shadow array from the style properties of a given nsIFrame and + * computes the union of those shadows along with the given initial rect. + * If there are no shadows, the initial rect is returned. + */ + static nsRect GetTextShadowRectsUnion(const nsRect& aTextAndDecorationsRect, + nsIFrame* aFrame, uint32_t aFlags = 0); + + /** + * Computes the destination rect that a given replaced element should render + * into, based on its CSS 'object-fit' and 'object-position' properties. + * + * @param aConstraintRect The constraint rect that we have at our disposal, + * which would e.g. be exactly filled by the image + * if we had "object-fit: fill". + * @param aIntrinsicSize The replaced content's intrinsic size, as reported + * by nsIFrame::GetIntrinsicSize(). + * @param aIntrinsicRatio The replaced content's intrinsic ratio, as reported + * by nsIFrame::GetIntrinsicRatio(). + * @param aStylePos The nsStylePosition struct that contains the 'object-fit' + * and 'object-position' values that we should rely on. + * (This should usually be the nsStylePosition for the + * replaced element in question, but not always. For + * example, a