summaryrefslogtreecommitdiffstats
path: root/layout/base/nsLayoutUtils.h
diff options
context:
space:
mode:
Diffstat (limited to 'layout/base/nsLayoutUtils.h')
-rw-r--r--layout/base/nsLayoutUtils.h3226
1 files changed, 3226 insertions, 0 deletions
diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h
new file mode 100644
index 0000000000..ce6d06c109
--- /dev/null
+++ b/layout/base/nsLayoutUtils.h
@@ -0,0 +1,3226 @@
+/* -*- 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 <limits>
+#include <algorithm>
+// 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 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<nsIFrame*>& 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<nsIFrame*>* aAncestors);
+
+ static int32_t DoCompareTreePosition(nsIFrame* aFrame1, nsIFrame* aFrame2,
+ nsTArray<nsIFrame*>& 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<FrameForPointOption>;
+
+ 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<nsIFrame*>& 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<Matrix4x4> - 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<Matrix4x4Flagged>* 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<Matrix4x4Flagged>* 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);
+
+ /**
+ * Return true if a "layer transform" could be computed for aFrame,
+ * and optionally return the computed transform. The returned
+ * transform is what would be set on the layer currently if a layers
+ * transaction were opened at the time this helper is called.
+ */
+ static bool GetLayerTransformForFrame(nsIFrame* aFrame,
+ Matrix4x4Flagged* aTransform);
+
+ /**
+ * 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 <typename T>
+ 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<nsString>* 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 <video>'s poster-image has a dedicated
+ * anonymous element & child-frame, but we should still use
+ * the <video>'s 'object-fit' and 'object-position' values.)
+ * @param aAnchorPoint [out] A point that should be pixel-aligned by functions
+ * like nsLayoutUtils::DrawImage. See documentation
+ * in nsCSSRendering.h for ComputeObjectAnchorPoint.
+ * @return The nsRect into which we should render the replaced content (using
+ * the same coordinate space as the passed-in aConstraintRect).
+ */
+ static nsRect ComputeObjectDestRect(const nsRect& aConstraintRect,
+ const IntrinsicSize& aIntrinsicSize,
+ const AspectRatio& aIntrinsicRatio,
+ const nsStylePosition* aStylePos,
+ nsPoint* aAnchorPoint = nullptr);
+
+ /**
+ * Get the font metrics corresponding to the frame's style data.
+ * @param aFrame the frame
+ * @param aSizeInflation number to multiply font size by
+ */
+ static already_AddRefed<nsFontMetrics> GetFontMetricsForFrame(
+ const nsIFrame* aFrame, float aSizeInflation);
+
+ static already_AddRefed<nsFontMetrics> GetInflatedFontMetricsForFrame(
+ const nsIFrame* aFrame) {
+ return GetFontMetricsForFrame(aFrame, FontSizeInflationFor(aFrame));
+ }
+
+ /**
+ * Get the font metrics corresponding to the given style data.
+ * @param aComputedStyle the style data
+ * @param aSizeInflation number to multiply font size by
+ */
+ static already_AddRefed<nsFontMetrics> GetFontMetricsForComputedStyle(
+ const ComputedStyle* aComputedStyle, nsPresContext* aPresContext,
+ float aSizeInflation = 1.0f,
+ uint8_t aVariantWidth = NS_FONT_VARIANT_WIDTH_NORMAL);
+
+ /**
+ * Get the font metrics of emphasis marks corresponding to the given
+ * style data. The result is same as GetFontMetricsForComputedStyle
+ * except that the font size is scaled down to 50%.
+ * @param aComputedStyle the style data
+ * @param aInflation number to multiple font size by
+ */
+ static already_AddRefed<nsFontMetrics> GetFontMetricsOfEmphasisMarks(
+ ComputedStyle* aComputedStyle, nsPresContext* aPresContext,
+ float aInflation) {
+ return GetFontMetricsForComputedStyle(aComputedStyle, aPresContext,
+ aInflation * 0.5f);
+ }
+
+ /**
+ * Find the immediate child of aParent whose frame subtree contains
+ * aDescendantFrame. Returns null if aDescendantFrame is not a descendant
+ * of aParent.
+ */
+ static nsIFrame* FindChildContainingDescendant(nsIFrame* aParent,
+ nsIFrame* aDescendantFrame);
+
+ /**
+ * Find the nearest ancestor that's a block
+ */
+ static nsBlockFrame* FindNearestBlockAncestor(nsIFrame* aFrame);
+
+ /**
+ * Find the nearest ancestor that's not for generated content. Will return
+ * aFrame if aFrame is not for generated content.
+ */
+ static nsIFrame* GetNonGeneratedAncestor(nsIFrame* aFrame);
+
+ /*
+ * Whether the frame is an nsBlockFrame which is not a wrapper block.
+ */
+ static bool IsNonWrapperBlock(nsIFrame* aFrame);
+
+ /**
+ * If aFrame is an out of flow frame, return its placeholder, otherwise
+ * return its parent.
+ */
+ static nsIFrame* GetParentOrPlaceholderFor(const nsIFrame* aFrame);
+
+ /**
+ * If aFrame is an out of flow frame, return its placeholder, otherwise
+ * return its (possibly cross-doc) parent.
+ */
+ static nsIFrame* GetParentOrPlaceholderForCrossDoc(const nsIFrame* aFrame);
+
+ /**
+ * Returns the frame that would act as the parent of aFrame when
+ * descending through the frame tree in display list building.
+ * Usually the same as GetParentOrPlaceholderForCrossDoc, except
+ * that pushed floats are treated as children of their containing
+ * block.
+ */
+ static nsIFrame* GetDisplayListParent(nsIFrame* aFrame);
+
+ /**
+ * Get a frame's previous continuation, or, if it doesn't have one, its
+ * previous block-in-inline-split sibling.
+ */
+ static nsIFrame* GetPrevContinuationOrIBSplitSibling(const nsIFrame* aFrame);
+
+ /**
+ * Get a frame's next continuation, or, if it doesn't have one, its
+ * block-in-inline-split sibling.
+ */
+ static nsIFrame* GetNextContinuationOrIBSplitSibling(const nsIFrame* aFrame);
+
+ /**
+ * Get the first frame in the continuation-plus-ib-split-sibling chain
+ * containing aFrame.
+ */
+ static nsIFrame* FirstContinuationOrIBSplitSibling(const nsIFrame* aFrame);
+
+ /**
+ * Get the last frame in the continuation-plus-ib-split-sibling chain
+ * containing aFrame.
+ */
+ static nsIFrame* LastContinuationOrIBSplitSibling(const nsIFrame* aFrame);
+
+ /**
+ * Is FirstContinuationOrIBSplitSibling(aFrame) going to return
+ * aFrame?
+ */
+ static bool IsFirstContinuationOrIBSplitSibling(const nsIFrame* aFrame);
+
+ /**
+ * Check whether aFrame is a part of the scrollbar or scrollcorner of
+ * the root content.
+ * @param aFrame the checking frame.
+ * @return true if the frame is a part of the scrollbar or scrollcorner of
+ * the root content.
+ */
+ static bool IsViewportScrollbarFrame(nsIFrame* aFrame);
+
+ /**
+ * Get the contribution of aFrame to its containing block's intrinsic
+ * size for the given physical axis. This considers the child's intrinsic
+ * width, its 'width', 'min-width', and 'max-width' properties (or 'height'
+ * variations if that's what matches aAxis) and its padding, border and margin
+ * in the corresponding dimension.
+ * @param aPercentageBasis an optional percentage basis (in aFrame's WM).
+ * If the basis is indefinite in a given axis, pass a size with
+ * NS_UNCONSTRAINEDSIZE in that component.
+ * If you pass Nothing() a percentage basis will be calculated from aFrame's
+ * ancestors' computed size in the relevant axis, if needed.
+ * @param aMarginBoxMinSizeClamp make the result fit within this margin-box
+ * size by reducing the *content size* (flooring at zero). This is used for:
+ * https://drafts.csswg.org/css-grid/#min-size-auto
+ */
+ enum {
+ IGNORE_PADDING = 0x01,
+ BAIL_IF_REFLOW_NEEDED = 0x02, // returns NS_INTRINSIC_ISIZE_UNKNOWN if so
+ MIN_INTRINSIC_ISIZE = 0x04, // use min-width/height instead of width/height
+ };
+ static nscoord IntrinsicForAxis(
+ mozilla::PhysicalAxis aAxis, gfxContext* aRenderingContext,
+ nsIFrame* aFrame, mozilla::IntrinsicISizeType aType,
+ const mozilla::Maybe<LogicalSize>& aPercentageBasis = mozilla::Nothing(),
+ uint32_t aFlags = 0, nscoord aMarginBoxMinSizeClamp = NS_MAXSIZE);
+ /**
+ * Calls IntrinsicForAxis with aFrame's parent's inline physical axis.
+ */
+ static nscoord IntrinsicForContainer(gfxContext* aRenderingContext,
+ nsIFrame* aFrame,
+ mozilla::IntrinsicISizeType aType,
+ uint32_t aFlags = 0);
+
+ /**
+ * Get the definite size contribution of aFrame for the given physical axis.
+ * This considers the child's 'min-width' property (or 'min-height' if the
+ * given axis is vertical), and its padding, border, and margin in the
+ * corresponding dimension. If the 'min-' property is 'auto' (and 'overflow'
+ * is 'visible') and the corresponding 'width'/'height' is definite it returns
+ * the "specified size" for:
+ * https://drafts.csswg.org/css-grid/#min-size-auto
+ * Note that the "transferred size" is not handled here; use IntrinsicForAxis.
+ * Note that any percentage in 'width'/'height' makes it count as indefinite.
+ * If the 'min-' property is 'auto' and 'overflow' is not 'visible', then it
+ * calculates the result as if the 'min-' computed value is zero.
+ * Otherwise, return NS_UNCONSTRAINEDSIZE.
+ *
+ * @param aPercentageBasis the percentage basis (in aFrame's WM).
+ * Pass NS_UNCONSTRAINEDSIZE if the basis is indefinite in either/both axes.
+ * @note this behavior is specific to Grid/Flexbox (currently) so aFrame
+ * should be a grid/flex item.
+ */
+ static nscoord MinSizeContributionForAxis(mozilla::PhysicalAxis aAxis,
+ gfxContext* aRC, nsIFrame* aFrame,
+ mozilla::IntrinsicISizeType aType,
+ const LogicalSize& aPercentageBasis,
+ uint32_t aFlags = 0);
+
+ /*
+ * Convert LengthPercentage to nscoord when percentages depend on the
+ * containing block size.
+ * @param aPercentBasis The width or height of the containing block
+ * (whichever the client wants to use for resolving percentages).
+ */
+ static nscoord ComputeCBDependentValue(nscoord aPercentBasis,
+ const LengthPercentage& aCoord) {
+ NS_WARNING_ASSERTION(
+ aPercentBasis != NS_UNCONSTRAINEDSIZE,
+ "have unconstrained width or height; this should only result from very "
+ "large sizes, not attempts at intrinsic size calculation");
+ return aCoord.Resolve(aPercentBasis);
+ }
+ static nscoord ComputeCBDependentValue(nscoord aPercentBasis,
+ const LengthPercentageOrAuto& aCoord) {
+ if (aCoord.IsAuto()) {
+ return 0;
+ }
+ return ComputeCBDependentValue(aPercentBasis, aCoord.AsLengthPercentage());
+ }
+
+ static nscoord ComputeBSizeDependentValue(nscoord aContainingBlockBSize,
+ const LengthPercentageOrAuto&);
+
+ static nscoord ComputeBSizeValue(nscoord aContainingBlockBSize,
+ nscoord aContentEdgeToBoxSizingBoxEdge,
+ const LengthPercentage& aCoord) {
+ MOZ_ASSERT(aContainingBlockBSize != nscoord_MAX || !aCoord.HasPercent(),
+ "caller must deal with %% of unconstrained block-size");
+
+ nscoord result = aCoord.Resolve(aContainingBlockBSize);
+ // Clamp calc(), and the subtraction for box-sizing.
+ return std::max(0, result - aContentEdgeToBoxSizingBoxEdge);
+ }
+
+ /**
+ * The "extremum length" values (see ExtremumLength) were originally aimed at
+ * inline-size (or width, as it was before logicalization). For now, we return
+ * true for those here, so that we don't call ComputeBSizeValue with value
+ * types that it doesn't understand. (See bug 1113216.)
+ *
+ * FIXME (bug 567039, bug 527285)
+ * This isn't correct for the 'fill' value or for the 'min-*' or 'max-*'
+ * properties, which need to be handled differently by the callers of
+ * IsAutoBSize().
+ */
+ template <typename SizeOrMaxSize>
+ static bool IsAutoBSize(const SizeOrMaxSize& aCoord, nscoord aCBBSize) {
+ return aCoord.BehavesLikeInitialValueOnBlockAxis() ||
+ (aCBBSize == nscoord_MAX && aCoord.HasPercent());
+ }
+
+ static bool IsPaddingZero(const LengthPercentage& aLength) {
+ // clamp negative calc() to 0
+ return aLength.Resolve(nscoord_MAX) <= 0 && aLength.Resolve(0) <= 0;
+ }
+
+ static bool IsMarginZero(const LengthPercentage& aLength) {
+ return aLength.Resolve(nscoord_MAX) == 0 && aLength.Resolve(0) == 0;
+ }
+
+ static void MarkDescendantsDirty(nsIFrame* aSubtreeRoot);
+
+ static void MarkIntrinsicISizesDirtyIfDependentOnBSize(nsIFrame* aFrame);
+
+ /*
+ * Calculate the used values for 'width' and 'height' when width
+ * and height are 'auto'. The tentWidth and tentHeight arguments should be
+ * the result of applying the rules for computing intrinsic sizes and ratios.
+ * as specified by CSS 2.1 sections 10.3.2 and 10.6.2
+ */
+ static nsSize ComputeAutoSizeWithIntrinsicDimensions(
+ nscoord minWidth, nscoord minHeight, nscoord maxWidth, nscoord maxHeight,
+ nscoord tentWidth, nscoord tentHeight);
+
+ // Implement nsIFrame::GetPrefISize in terms of nsIFrame::AddInlinePrefISize
+ static nscoord PrefISizeFromInline(nsIFrame* aFrame,
+ gfxContext* aRenderingContext);
+
+ // Implement nsIFrame::GetMinISize in terms of nsIFrame::AddInlineMinISize
+ static nscoord MinISizeFromInline(nsIFrame* aFrame,
+ gfxContext* aRenderingContext);
+
+ // Get a suitable foreground color for painting aColor for aFrame.
+ static nscolor DarkenColorIfNeeded(nsIFrame* aFrame, nscolor aColor);
+
+ // Get a suitable foreground color for painting aField for aFrame.
+ // Type of aFrame is made a template parameter because nsIFrame is not
+ // a complete type in the header. Type-safety is not harmed given that
+ // DarkenColorIfNeeded requires an nsIFrame pointer.
+ template <typename Frame, typename T, typename S>
+ static nscolor GetColor(Frame* aFrame, T S::*aField) {
+ nscolor color = aFrame->GetVisitedDependentColor(aField);
+ return DarkenColorIfNeeded(aFrame, color);
+ }
+
+ // Get a baseline y position in app units that is snapped to device pixels.
+ static gfxFloat GetSnappedBaselineY(nsIFrame* aFrame, gfxContext* aContext,
+ nscoord aY, nscoord aAscent);
+ // Ditto for an x position (for vertical text). Note that for vertical-rl
+ // writing mode, the ascent value should be negated by the caller.
+ static gfxFloat GetSnappedBaselineX(nsIFrame* aFrame, gfxContext* aContext,
+ nscoord aX, nscoord aAscent);
+
+ static nscoord AppUnitWidthOfString(char16_t aC, nsFontMetrics& aFontMetrics,
+ DrawTarget* aDrawTarget) {
+ return AppUnitWidthOfString(&aC, 1, aFontMetrics, aDrawTarget);
+ }
+ static nscoord AppUnitWidthOfString(mozilla::Span<const char16_t> aString,
+ nsFontMetrics& aFontMetrics,
+ DrawTarget* aDrawTarget) {
+ return nsLayoutUtils::AppUnitWidthOfString(
+ aString.Elements(), aString.Length(), aFontMetrics, aDrawTarget);
+ }
+ static nscoord AppUnitWidthOfString(const char16_t* aString, uint32_t aLength,
+ nsFontMetrics& aFontMetrics,
+ DrawTarget* aDrawTarget);
+ static nscoord AppUnitWidthOfStringBidi(const nsString& aString,
+ const nsIFrame* aFrame,
+ nsFontMetrics& aFontMetrics,
+ gfxContext& aContext) {
+ return nsLayoutUtils::AppUnitWidthOfStringBidi(
+ aString.get(), aString.Length(), aFrame, aFontMetrics, aContext);
+ }
+ static nscoord AppUnitWidthOfStringBidi(const char16_t* aString,
+ uint32_t aLength,
+ const nsIFrame* aFrame,
+ nsFontMetrics& aFontMetrics,
+ gfxContext& aContext);
+
+ static bool StringWidthIsGreaterThan(const nsString& aString,
+ nsFontMetrics& aFontMetrics,
+ DrawTarget* aDrawTarget, nscoord aWidth);
+
+ static nsBoundingMetrics AppUnitBoundsOfString(const char16_t* aString,
+ uint32_t aLength,
+ nsFontMetrics& aFontMetrics,
+ DrawTarget* aDrawTarget);
+
+ static void DrawString(const nsIFrame* aFrame, nsFontMetrics& aFontMetrics,
+ gfxContext* aContext, const char16_t* aString,
+ int32_t aLength, nsPoint aPoint,
+ ComputedStyle* aComputedStyle = nullptr,
+ DrawStringFlags aFlags = DrawStringFlags::Default);
+
+ static nsPoint GetBackgroundFirstTilePos(const nsPoint& aDest,
+ const nsPoint& aFill,
+ const nsSize& aRepeatSize);
+
+ /**
+ * Supports only LTR or RTL. Bidi (mixed direction) is not supported.
+ */
+ static void DrawUniDirString(const char16_t* aString, uint32_t aLength,
+ const nsPoint& aPoint,
+ nsFontMetrics& aFontMetrics,
+ gfxContext& aContext);
+
+ /**
+ * Helper function for drawing text-shadow. The callback's job
+ * is to draw whatever needs to be blurred onto the given context.
+ */
+ typedef void (*TextShadowCallback)(gfxContext* aCtx, nsPoint aShadowOffset,
+ const nscolor& aShadowColor, void* aData);
+
+ static void PaintTextShadow(const nsIFrame* aFrame, gfxContext* aContext,
+ const nsRect& aTextRect, const nsRect& aDirtyRect,
+ const nscolor& aForegroundColor,
+ TextShadowCallback aCallback,
+ void* aCallbackData);
+
+ /**
+ * Gets the baseline to vertically center text from a font within a
+ * line of specified height.
+ * aIsInverted: true if the text is inverted relative to the block
+ * direction, so that the block-dir "ascent" corresponds to font
+ * descent. (Applies to sideways text in vertical-lr mode.)
+ *
+ * Returns the baseline position relative to the top of the line.
+ */
+ static nscoord GetCenteredFontBaseline(nsFontMetrics* aFontMetrics,
+ nscoord aLineHeight, bool aIsInverted);
+
+ /**
+ * Derive a baseline of |aFrame| (measured from its top border edge)
+ * from its first in-flow line box (not descending into anything with
+ * 'overflow' not 'visible', potentially including aFrame itself).
+ *
+ * Returns true if a baseline was found (and fills in aResult).
+ * Otherwise returns false.
+ */
+ static bool GetFirstLineBaseline(mozilla::WritingMode aWritingMode,
+ const nsIFrame* aFrame, nscoord* aResult);
+
+ /**
+ * Just like GetFirstLineBaseline, except also returns the top and
+ * bottom of the line with the baseline.
+ *
+ * Returns true if a line was found (and fills in aResult).
+ * Otherwise returns false.
+ */
+ struct LinePosition {
+ nscoord mBStart, mBaseline, mBEnd;
+
+ LinePosition operator+(nscoord aOffset) const {
+ LinePosition result;
+ result.mBStart = mBStart + aOffset;
+ result.mBaseline = mBaseline + aOffset;
+ result.mBEnd = mBEnd + aOffset;
+ return result;
+ }
+ };
+ static bool GetFirstLinePosition(mozilla::WritingMode aWritingMode,
+ const nsIFrame* aFrame,
+ LinePosition* aResult);
+
+ /**
+ * Derive a baseline of |aFrame| (measured from its top border edge)
+ * from its last in-flow line box (not descending into anything with
+ * 'overflow' not 'visible', potentially including aFrame itself).
+ *
+ * Returns true if a baseline was found (and fills in aResult).
+ * Otherwise returns false.
+ */
+ static bool GetLastLineBaseline(mozilla::WritingMode aWritingMode,
+ const nsIFrame* aFrame, nscoord* aResult);
+
+ /**
+ * Returns a block-dir coordinate relative to this frame's origin that
+ * represents the logical block-end of the frame or its visible content,
+ * whichever is further from the origin.
+ * Relative positioning is ignored and margins and glyph bounds are not
+ * considered.
+ * This value will be >= mRect.BSize() and <= overflowRect.BEnd() unless
+ * relative positioning is applied.
+ */
+ static nscoord CalculateContentBEnd(mozilla::WritingMode aWritingMode,
+ nsIFrame* aFrame);
+
+ /**
+ * Gets the closest frame (the frame passed in or one of its parents) that
+ * qualifies as a "layer"; used in DOM0 methods that depends upon that
+ * definition. This is the nearest frame that is either positioned or scrolled
+ * (the child of a scroll frame).
+ */
+ static nsIFrame* GetClosestLayer(nsIFrame* aFrame);
+
+ /**
+ * Gets the graphics sampling filter for the frame
+ */
+ static SamplingFilter GetSamplingFilterForFrame(nsIFrame* aFrame);
+
+ static inline void InitDashPattern(StrokeOptions& aStrokeOptions,
+ mozilla::StyleBorderStyle aBorderStyle) {
+ if (aBorderStyle == mozilla::StyleBorderStyle::Dotted) {
+ static Float dot[] = {1.f, 1.f};
+ aStrokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dot);
+ aStrokeOptions.mDashPattern = dot;
+ } else if (aBorderStyle == mozilla::StyleBorderStyle::Dashed) {
+ static Float dash[] = {5.f, 5.f};
+ aStrokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dash);
+ aStrokeOptions.mDashPattern = dash;
+ } else {
+ aStrokeOptions.mDashLength = 0;
+ aStrokeOptions.mDashPattern = nullptr;
+ }
+ }
+
+ /**
+ * Convert an nsRect to a gfxRect.
+ */
+ static gfxRect RectToGfxRect(const nsRect& aRect,
+ int32_t aAppUnitsPerDevPixel);
+
+ static gfxPoint PointToGfxPoint(const nsPoint& aPoint,
+ int32_t aAppUnitsPerPixel) {
+ return gfxPoint(gfxFloat(aPoint.x) / aAppUnitsPerPixel,
+ gfxFloat(aPoint.y) / aAppUnitsPerPixel);
+ }
+
+ /* N.B. The only difference between variants of the Draw*Image
+ * functions below is the type of the aImage argument.
+ */
+
+ /**
+ * Draw a background image. The image's dimensions are as specified in aDest;
+ * the image itself is not consulted to determine a size.
+ * See https://wiki.mozilla.org/Gecko:Image_Snapping_and_Rendering
+ *
+ * @param aContext
+ * The context to draw to, already set up with an appropriate scale and
+ * transform for drawing in app units.
+ * @param aForFrame
+ * The nsIFrame that we're drawing this image for.
+ * @param aImage
+ * The image.
+ * @param aDest
+ * The position and scaled area where one copy of the image should be drawn.
+ * This area represents the image itself in its correct position as defined
+ * with the background-position css property.
+ * @param aFill
+ * The area to be filled with copies of the image.
+ * @param aRepeatSize
+ * The distance between the positions of two subsequent repeats of the image.
+ * Sizes larger than aDest.Size() create gaps between the images.
+ * @param aAnchor
+ * A point in aFill which we will ensure is pixel-aligned in the output.
+ * @param aDirty
+ * Pixels outside this area may be skipped.
+ * @param aImageFlags
+ * Image flags of the imgIContainer::FLAG_* variety.
+ * @param aExtendMode
+ * How to extend the image over the dest rect.
+ */
+ static ImgDrawResult DrawBackgroundImage(
+ gfxContext& aContext, nsIFrame* aForFrame, nsPresContext* aPresContext,
+ imgIContainer* aImage, SamplingFilter aSamplingFilter,
+ const nsRect& aDest, const nsRect& aFill, const nsSize& aRepeatSize,
+ const nsPoint& aAnchor, const nsRect& aDirty, uint32_t aImageFlags,
+ ExtendMode aExtendMode, float aOpacity);
+
+ /**
+ * Draw an image.
+ * See https://wiki.mozilla.org/Gecko:Image_Snapping_and_Rendering
+ * @param aRenderingContext Where to draw the image, set up with an
+ * appropriate scale and transform for drawing in
+ * app units.
+ * @param aComputedStyle The ComputedStyle of the nsIFrame (or
+ * pseudo-element) for which this image is being
+ * drawn.
+ * @param aImage The image.
+ * @param aDest Where one copy of the image should mapped to.
+ * @param aFill The area to be filled with copies of the
+ * image.
+ * @param aAnchor A point in aFill which we will ensure is
+ * pixel-aligned in the output.
+ * @param aDirty Pixels outside this area may be skipped.
+ * @param aImageFlags Image flags of the imgIContainer::FLAG_* variety
+ */
+ static ImgDrawResult DrawImage(gfxContext& aContext,
+ ComputedStyle* aComputedStyle,
+ nsPresContext* aPresContext,
+ imgIContainer* aImage,
+ const SamplingFilter aSamplingFilter,
+ const nsRect& aDest, const nsRect& aFill,
+ const nsPoint& aAnchor, const nsRect& aDirty,
+ uint32_t aImageFlags, float aOpacity = 1.0);
+
+ /**
+ * Draw a whole image without scaling or tiling.
+ *
+ * @param aRenderingContext Where to draw the image, set up with an
+ * appropriate scale and transform for drawing in
+ * app units.
+ * @param aImage The image.
+ * @param aDest The top-left where the image should be drawn.
+ * @param aDirty If non-null, then pixels outside this area may
+ * be skipped.
+ * @param aSVGContext Optionally provides an SVGImageContext.
+ * Callers should pass an SVGImageContext with at
+ * least the viewport size set if aImage may be of
+ * type imgIContainer::TYPE_VECTOR, or pass
+ * Nothing() if it is of type
+ * imgIContainer::TYPE_RASTER (to save cycles
+ * constructing an SVGImageContext, since this
+ * argument will be ignored for raster images).
+ * @param aImageFlags Image flags of the imgIContainer::FLAG_* variety
+ * @param aSourceArea If non-null, this area is extracted from
+ * the image and drawn at aDest. It's
+ * in appunits. For best results it should
+ * be aligned with image pixels.
+ */
+ static ImgDrawResult DrawSingleUnscaledImage(
+ gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage,
+ const SamplingFilter aSamplingFilter, const nsPoint& aDest,
+ const nsRect* aDirty, const mozilla::SVGImageContext& aSVGContext,
+ uint32_t aImageFlags, const nsRect* aSourceArea = nullptr);
+
+ /**
+ * Draw a whole image without tiling.
+ *
+ * @param aRenderingContext Where to draw the image, set up with an
+ * appropriate scale and transform for drawing in
+ * app units.
+ * @param aImage The image.
+ * @param aDest The area that the image should fill.
+ * @param aDirty Pixels outside this area may be skipped.
+ * @param aSVGContext Optionally provides an SVGImageContext.
+ * Callers should pass an SVGImageContext with at
+ * least the viewport size set if aImage may be of
+ * type imgIContainer::TYPE_VECTOR, or pass
+ * Nothing() if it is of type
+ * imgIContainer::TYPE_RASTER (to save cycles
+ * constructing an SVGImageContext, since this
+ * argument will be ignored for raster images).
+ * @param aImageFlags Image flags of the imgIContainer::FLAG_*
+ * variety.
+ * @param aAnchor If non-null, a point which we will ensure
+ * is pixel-aligned in the output.
+ * @param aSourceArea If non-null, this area is extracted from
+ * the image and drawn in aDest. It's
+ * in appunits. For best results it should
+ * be aligned with image pixels.
+ */
+ static ImgDrawResult DrawSingleImage(
+ gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage,
+ SamplingFilter aSamplingFilter, const nsRect& aDest, const nsRect& aDirty,
+ const mozilla::SVGImageContext& aSVGContext, uint32_t aImageFlags,
+ const nsPoint* aAnchorPoint = nullptr,
+ const nsRect* aSourceArea = nullptr);
+
+ /**
+ * Given an imgIContainer, this method attempts to obtain an intrinsic
+ * px-valued height & width for it. If the imgIContainer has a non-pixel
+ * value for either height or width, this method tries to generate a pixel
+ * value for that dimension using the intrinsic ratio (if available). The
+ * intrinsic ratio will be assigned to aIntrinsicRatio; if there's no
+ * intrinsic ratio then (0, 0) will be assigned.
+ *
+ * This method will always set aGotWidth and aGotHeight to indicate whether
+ * we were able to successfully obtain (or compute) a value for each
+ * dimension.
+ *
+ * NOTE: This method is similar to ComputeSizeWithIntrinsicDimensions. The
+ * difference is that this one is simpler and is suited to places where we
+ * have less information about the frame tree.
+ *
+ * @param aResolution The resolution specified by the author for the image, or
+ * its intrinsic resolution.
+ *
+ * This will affect the intrinsic size size of the image
+ * (so e.g., if resolution is 2, and the image is 100x100,
+ * the intrinsic size of the image will be 50x50).
+ */
+ static void ComputeSizeForDrawing(imgIContainer* aImage,
+ const mozilla::image::Resolution&,
+ CSSIntSize& aImageSize,
+ AspectRatio& aIntrinsicRatio,
+ bool& aGotWidth, bool& aGotHeight);
+
+ /**
+ * Given an imgIContainer, this method attempts to obtain an intrinsic
+ * px-valued height & width for it. If the imgIContainer has a non-pixel
+ * value for either height or width, this method tries to generate a pixel
+ * value for that dimension using the intrinsic ratio (if available). If,
+ * after trying all these methods, no value is available for one or both
+ * dimensions, the corresponding dimension of aFallbackSize is used instead.
+ */
+ static CSSIntSize ComputeSizeForDrawingWithFallback(
+ imgIContainer* aImage, const mozilla::image::Resolution&,
+ const nsSize& aFallbackSize);
+
+ /**
+ * Given the image container, frame, and dest rect, determine the best fitting
+ * size to decode the image at, and calculate any necessary SVG parameters.
+ */
+ static mozilla::gfx::IntSize ComputeImageContainerDrawingParameters(
+ imgIContainer* aImage, nsIFrame* aForFrame,
+ const LayoutDeviceRect& aDestRect, const LayoutDeviceRect& aFillRect,
+ const StackingContextHelper& aSc, uint32_t aFlags,
+ mozilla::SVGImageContext& aSVGContext,
+ mozilla::Maybe<mozilla::image::ImageIntRegion>& aRegion);
+
+ /**
+ * Given a source area of an image (in appunits) and a destination area
+ * that we want to map that source area too, computes the area that
+ * would be covered by the whole image. This is useful for passing to
+ * the aDest parameter of DrawImage, when we want to draw a subimage
+ * of an overall image.
+ */
+ static nsRect GetWholeImageDestination(const nsSize& aWholeImageSize,
+ const nsRect& aImageSourceArea,
+ const nsRect& aDestArea);
+
+ /**
+ * Given an image container and an orientation, returns an image container
+ * that contains the same image, reoriented appropriately. May return the
+ * original image container if no changes are needed.
+ *
+ * @param aContainer The image container to apply the orientation to.
+ * @param aOrientation The desired orientation.
+ */
+ static already_AddRefed<imgIContainer> OrientImage(
+ imgIContainer* aContainer,
+ const mozilla::StyleImageOrientation& aOrientation);
+
+ /**
+ * Determine if any corner radius is of nonzero size
+ * @param aCorners the |BorderRadius| object to check
+ * @return true unless all the coordinates are 0%, 0 or null.
+ *
+ * A corner radius with one dimension zero and one nonzero is
+ * treated as a nonzero-radius corner, even though it will end up
+ * being rendered like a zero-radius corner. This is because such
+ * corners are not expected to appear outside of test cases, and it's
+ * simpler to implement the test this way.
+ */
+ static bool HasNonZeroCorner(const mozilla::BorderRadius& aCorners);
+
+ /**
+ * Determine if there is any corner radius on corners adjacent to the
+ * given side.
+ */
+ static bool HasNonZeroCornerOnSide(const mozilla::BorderRadius& aCorners,
+ mozilla::Side aSide);
+
+ /**
+ * Determine if a widget is likely to require transparency or translucency.
+ * @param aBackgroundFrame The frame that the background is set on. For
+ * <window>s, this will be the canvas frame.
+ * @param aCSSRootFrame The frame that holds CSS properties affecting
+ * the widget's transparency. For menupopups,
+ * aBackgroundFrame and aCSSRootFrame will be the
+ * same.
+ * @return a value suitable for passing to SetWindowTranslucency.
+ */
+ static nsTransparencyMode GetFrameTransparency(nsIFrame* aBackgroundFrame,
+ nsIFrame* aCSSRootFrame);
+
+ /**
+ * A frame is a popup if it has its own floating window. Menus, panels
+ * and combobox dropdowns are popups.
+ */
+ static bool IsPopup(const nsIFrame* aFrame);
+
+ /**
+ * Find the nearest "display root". This is the nearest enclosing
+ * popup frame or the root prescontext's root frame.
+ */
+ static nsIFrame* GetDisplayRootFrame(nsIFrame* aFrame);
+ static const nsIFrame* GetDisplayRootFrame(const nsIFrame* aFrame);
+
+ /**
+ * Get the reference frame that would be used when constructing a
+ * display item for this frame. Rather than using their own frame
+ * as a reference frame.)
+ *
+ * This duplicates some of the logic of GetDisplayRootFrame above and
+ * of nsDisplayListBuilder::FindReferenceFrameFor.
+ *
+ * If you have an nsDisplayListBuilder, you should get the reference
+ * frame from it instead of calling this.
+ */
+ static nsIFrame* GetReferenceFrame(nsIFrame* aFrame);
+
+ /**
+ * Get textrun construction flags determined by a given style; in particular
+ * some combination of:
+ * -- TEXT_DISABLE_OPTIONAL_LIGATURES if letter-spacing is in use
+ * -- TEXT_OPTIMIZE_SPEED if the text-rendering CSS property and font size
+ * and prefs indicate we should be optimizing for speed over quality
+ */
+ static mozilla::gfx::ShapedTextFlags GetTextRunFlagsForStyle(
+ const ComputedStyle*, nsPresContext*, const nsStyleFont*,
+ const nsStyleText*, nscoord aLetterSpacing);
+
+ /**
+ * Get orientation flags for textrun construction.
+ */
+ static mozilla::gfx::ShapedTextFlags GetTextRunOrientFlagsForStyle(
+ const ComputedStyle*);
+
+ /**
+ * Takes two rectangles whose origins must be the same, and computes
+ * the difference between their union and their intersection as two
+ * rectangles. (This difference is a superset of the difference
+ * between the two rectangles.)
+ */
+ static void GetRectDifferenceStrips(const nsRect& aR1, const nsRect& aR2,
+ nsRect* aHStrip, nsRect* aVStrip);
+
+ /**
+ * Get a device context that can be used to get up-to-date device
+ * dimensions for the given window. For some reason, this is more
+ * complicated than it ought to be in multi-monitor situations.
+ */
+ static nsDeviceContext* GetDeviceContextForScreenInfo(
+ nsPIDOMWindowOuter* aWindow);
+
+ /**
+ * Some frames with 'position: fixed' (nsStyleDisplay::mPosition ==
+ * StylePositionProperty::Fixed) are not really fixed positioned, since
+ * they're inside an element with -moz-transform. This function says
+ * whether such an element is a real fixed-pos element.
+ */
+ static bool IsReallyFixedPos(const nsIFrame* aFrame);
+
+ /**
+ * This function says whether `aFrame` would really be a fixed positioned
+ * frame if the frame was created with StylePositionProperty::Fixed.
+ *
+ * It is effectively the same as IsReallyFixedPos, but without asserting the
+ * position value. Use it only when you know what you're doing, like when
+ * tearing down the frame tree (where styles may have changed due to
+ * ::first-line reparenting and rule changes at the same time).
+ */
+ static bool MayBeReallyFixedPos(const nsIFrame* aFrame);
+
+ /**
+ * Returns true if |aFrame| is inside position:fixed subtree.
+ */
+ static bool IsInPositionFixedSubtree(const nsIFrame* aFrame);
+
+ /**
+ * Obtain a SourceSurface from the given DOM element, if possible.
+ * This obtains the most natural surface from the element; that
+ * is, the one that can be obtained with the fewest conversions.
+ *
+ * The flags below can modify the behaviour of this function. The
+ * result is returned as a SurfaceFromElementResult struct, also
+ * defined below.
+ *
+ * Currently, this will do:
+ * - HTML Canvas elements: will return the underlying canvas surface
+ * - HTML Video elements: will return the current video frame
+ * - Image elements: will return the image
+ *
+ * The above results are modified by the below flags (copying,
+ * forcing image surface, etc.).
+ */
+
+ enum {
+ /* Whether to extract the first frame (as opposed to the
+ current frame) in the case that the element is an image. */
+ SFE_WANT_FIRST_FRAME_IF_IMAGE = 1 << 0,
+ /* Whether we should skip colorspace/gamma conversion */
+ SFE_NO_COLORSPACE_CONVERSION = 1 << 1,
+ /* Caller handles SFER::mAlphaType = NonPremult */
+ SFE_ALLOW_NON_PREMULT = 1 << 2,
+ /* Whether we should skip getting a surface for vector images and
+ return a DirectDrawInfo containing an imgIContainer instead. */
+ SFE_NO_RASTERIZING_VECTORS = 1 << 3,
+ /* If image type is vector, the return surface size will same as
+ element size, not image's intrinsic size. */
+ SFE_USE_ELEMENT_SIZE_IF_VECTOR = 1 << 4,
+ /* Ensure that the returned surface has a size that matches the
+ * SurfaceFromElementResult::mSize. This is mostly a convenience thing so
+ * that callers who want this don't have to deal with it themselves.
+ * The surface might be different for, e.g., a EXIF-scaled raster image, if
+ * we don't rescale during decode. */
+ SFE_EXACT_SIZE_SURFACE = 1 << 6,
+ };
+
+ // This function can be called on any thread.
+ static mozilla::SurfaceFromElementResult SurfaceFromOffscreenCanvas(
+ mozilla::dom::OffscreenCanvas* aOffscreenCanvas, uint32_t aSurfaceFlags,
+ RefPtr<DrawTarget>& aTarget);
+ static mozilla::SurfaceFromElementResult SurfaceFromOffscreenCanvas(
+ mozilla::dom::OffscreenCanvas* aOffscreenCanvas,
+ uint32_t aSurfaceFlags = 0) {
+ RefPtr<DrawTarget> target = nullptr;
+ return SurfaceFromOffscreenCanvas(aOffscreenCanvas, aSurfaceFlags, target);
+ }
+ static mozilla::SurfaceFromElementResult SurfaceFromImageBitmap(
+ mozilla::dom::ImageBitmap* aImageBitmap, uint32_t aSurfaceFlags);
+
+ static mozilla::SurfaceFromElementResult SurfaceFromElement(
+ mozilla::dom::Element* aElement,
+ const mozilla::Maybe<int32_t>& aResizeWidth,
+ const mozilla::Maybe<int32_t>& aResizeHeight, uint32_t aSurfaceFlags,
+ RefPtr<DrawTarget>& aTarget);
+ static mozilla::SurfaceFromElementResult SurfaceFromElement(
+ mozilla::dom::Element* aElement, uint32_t aSurfaceFlags = 0) {
+ RefPtr<DrawTarget> target = nullptr;
+ return SurfaceFromElement(aElement, mozilla::Nothing(), mozilla::Nothing(),
+ aSurfaceFlags, target);
+ }
+ static mozilla::SurfaceFromElementResult SurfaceFromElement(
+ mozilla::dom::Element* aElement, uint32_t aSurfaceFlags,
+ RefPtr<DrawTarget>& aTarget) {
+ return SurfaceFromElement(aElement, mozilla::Nothing(), mozilla::Nothing(),
+ aSurfaceFlags, aTarget);
+ }
+ static mozilla::SurfaceFromElementResult SurfaceFromElement(
+ mozilla::dom::Element* aElement,
+ const mozilla::Maybe<int32_t>& aResizeWidth,
+ const mozilla::Maybe<int32_t>& aResizeHeight,
+ uint32_t aSurfaceFlags = 0) {
+ RefPtr<DrawTarget> target = nullptr;
+ return SurfaceFromElement(aElement, aResizeWidth, aResizeHeight,
+ aSurfaceFlags, target);
+ }
+
+ // There are a bunch of callers of SurfaceFromElement. Just mark it as
+ MOZ_CAN_RUN_SCRIPT_BOUNDARY
+ static mozilla::SurfaceFromElementResult SurfaceFromElement(
+ nsIImageLoadingContent* aElement,
+ const mozilla::Maybe<int32_t>& aResizeWidth,
+ const mozilla::Maybe<int32_t>& aResizeHeight, uint32_t aSurfaceFlags,
+ RefPtr<DrawTarget>& aTarget);
+ // Need an HTMLImageElement overload, because otherwise the
+ // nsIImageLoadingContent and mozilla::dom::Element overloads are ambiguous
+ // for HTMLImageElement.
+ static mozilla::SurfaceFromElementResult SurfaceFromElement(
+ mozilla::dom::HTMLImageElement* aElement, uint32_t aSurfaceFlags,
+ RefPtr<DrawTarget>& aTarget);
+ static mozilla::SurfaceFromElementResult SurfaceFromElement(
+ mozilla::dom::HTMLCanvasElement* aElement, uint32_t aSurfaceFlags,
+ RefPtr<DrawTarget>& aTarget);
+ static mozilla::SurfaceFromElementResult SurfaceFromElement(
+ mozilla::dom::HTMLCanvasElement* aElement, uint32_t aSurfaceFlags) {
+ RefPtr<DrawTarget> target = nullptr;
+ return SurfaceFromElement(aElement, aSurfaceFlags, target);
+ }
+ static mozilla::SurfaceFromElementResult SurfaceFromElement(
+ mozilla::dom::HTMLVideoElement* aElement, uint32_t aSurfaceFlags,
+ RefPtr<DrawTarget>& aTarget);
+
+ /**
+ * When the document is editable by contenteditable attribute of its root
+ * content or body content.
+ *
+ * Be aware, this returns nullptr if it's in designMode.
+ *
+ * For example:
+ *
+ * <html contenteditable="true"><body></body></html>
+ * returns the <html>.
+ *
+ * <html><body contenteditable="true"></body></html>
+ * <body contenteditable="true"></body>
+ * With these cases, this returns the <body>.
+ * NOTE: The latter case isn't created normally, however, it can be
+ * created by script with XHTML.
+ *
+ * <body><p contenteditable="true"></p></body>
+ * returns nullptr because <body> isn't editable.
+ */
+ static mozilla::dom::Element* GetEditableRootContentByContentEditable(
+ mozilla::dom::Document* aDocument);
+
+ static void AddExtraBackgroundItems(nsDisplayListBuilder* aBuilder,
+ nsDisplayList* aList, nsIFrame* aFrame,
+ const nsRect& aCanvasArea,
+ const nsRegion& aVisibleRegion,
+ nscolor aBackstop);
+
+ /**
+ * Returns true if the passed in prescontext needs the dark grey background
+ * that goes behind the page of a print preview presentation.
+ */
+ static bool NeedsPrintPreviewBackground(nsPresContext* aPresContext);
+
+ /**
+ * Types used by the helpers for InspectorUtils.getUsedFontFaces.
+ * The API returns an array (UsedFontFaceList) that owns the
+ * InspectorFontFace instances, but during range traversal we also
+ * want to maintain a mapping from gfxFontEntry to InspectorFontFace
+ * records, so use a temporary hashtable for that.
+ */
+ typedef nsTArray<mozilla::UniquePtr<mozilla::dom::InspectorFontFace>>
+ UsedFontFaceList;
+ typedef nsTHashMap<nsPtrHashKey<gfxFontEntry>,
+ mozilla::dom::InspectorFontFace*>
+ UsedFontFaceTable;
+
+ /**
+ * Adds all font faces used in the frame tree starting from aFrame
+ * to the list aFontFaceList.
+ * aMaxRanges: maximum number of text ranges to record for each face.
+ */
+ static nsresult GetFontFacesForFrames(nsIFrame* aFrame,
+ UsedFontFaceList& aResult,
+ UsedFontFaceTable& aFontFaces,
+ uint32_t aMaxRanges,
+ bool aSkipCollapsedWhitespace);
+
+ /**
+ * Adds all font faces used within the specified range of text in aFrame,
+ * and optionally its continuations, to the list in aFontFaceList.
+ * Pass 0 and INT32_MAX for aStartOffset and aEndOffset to specify the
+ * entire text is to be considered.
+ * aMaxRanges: maximum number of text ranges to record for each face.
+ */
+ static void GetFontFacesForText(nsIFrame* aFrame, int32_t aStartOffset,
+ int32_t aEndOffset, bool aFollowContinuations,
+ UsedFontFaceList& aResult,
+ UsedFontFaceTable& aFontFaces,
+ uint32_t aMaxRanges,
+ bool aSkipCollapsedWhitespace);
+
+ /**
+ * Walks the frame tree starting at aFrame looking for textRuns.
+ * If |clear| is true, just clears the TEXT_RUN_MEMORY_ACCOUNTED flag
+ * on each textRun found (and |aMallocSizeOf| is not used).
+ * If |clear| is false, adds the storage used for each textRun to the
+ * total, and sets the TEXT_RUN_MEMORY_ACCOUNTED flag to avoid double-
+ * accounting. (Runs with this flag already set will be skipped.)
+ * Expected usage pattern is therefore to call twice:
+ * (void)SizeOfTextRunsForFrames(rootFrame, nullptr, true);
+ * total = SizeOfTextRunsForFrames(rootFrame, mallocSizeOf, false);
+ */
+ static size_t SizeOfTextRunsForFrames(nsIFrame* aFrame,
+ mozilla::MallocSizeOf aMallocSizeOf,
+ bool clear);
+
+ /**
+ * Returns true if |aFrame| has an animation of a property in |aPropertySet|
+ * regardless of whether any property in the set is overridden by an
+ * !important rule.
+ */
+ static bool HasAnimationOfPropertySet(const nsIFrame* aFrame,
+ const nsCSSPropertyIDSet& aPropertySet);
+
+ /**
+ * A variant of the above HasAnimationOfPropertySet that takes an optional
+ * EffectSet parameter as an optimization to save redundant lookups of the
+ * EffectSet.
+ */
+ static bool HasAnimationOfPropertySet(const nsIFrame* aFrame,
+ const nsCSSPropertyIDSet& aPropertySet,
+ mozilla::EffectSet* aEffectSet);
+
+ /**
+ * A variant of the above HasAnimationOfPropertySet. This is especially for
+ * tranform-like properties with motion-path.
+ * For transform-like properties with motion-path, we need to check if
+ * offset-path has effect. If we don't have any animation on offset-path and
+ * offset-path is none, there is no effective motion-path, and so we don't
+ * care other offset-* properties. In this case, this function only checks the
+ * rest of transform-like properties (i.e. transform/translate/rotate/scale).
+ */
+ static bool HasAnimationOfTransformAndMotionPath(const nsIFrame* aFrame);
+
+ /**
+ * Returns true if |aFrame| has an animation of |aProperty| which is
+ * not overridden by !important rules.
+ */
+ static bool HasEffectiveAnimation(const nsIFrame* aFrame,
+ nsCSSPropertyID aProperty);
+
+ /**
+ * Returns true if |aFrame| has an animation where at least one of the
+ * properties in |aPropertySet| is not overridden by !important rules.
+ *
+ * If |aPropertySet| includes transform-like properties (transform, rotate,
+ * etc.) however, this will return false if any of the transform-like
+ * properties is overriden by an !important rule since these properties should
+ * be combined on the compositor.
+ */
+ static bool HasEffectiveAnimation(const nsIFrame* aFrame,
+ const nsCSSPropertyIDSet& aPropertySet);
+
+ /**
+ * Returns all effective animated CSS properties on |aStyleFrame| and its
+ * corresponding primary frame (for content that makes this distinction,
+ * notable display:table content) that can be animated on the compositor.
+ *
+ * Properties that can be animated on the compositor but which are overridden
+ * by !important rules are not returned.
+ *
+ * Unlike HasEffectiveAnimation, however, this does not check the set of
+ * transform-like properties to ensure that if any such properties are
+ * overridden by !important rules, the other transform-like properties are
+ * not run on the compositor (see bug 1534884).
+ */
+ static nsCSSPropertyIDSet GetAnimationPropertiesForCompositor(
+ const nsIFrame* aStyleFrame);
+
+ /**
+ * Checks if off-main-thread animations are enabled.
+ */
+ static bool AreAsyncAnimationsEnabled();
+
+ /**
+ * Checks if retained display lists are enabled.
+ */
+ static bool AreRetainedDisplayListsEnabled();
+
+ static bool DisplayRootHasRetainedDisplayListBuilder(nsIFrame* aFrame);
+
+ static RetainedDisplayListBuilder* GetRetainedDisplayListBuilder(
+ nsIFrame* aFrame);
+
+ /**
+ * Find a suitable scale for a element (aFrame's content) over the course of
+ * any animations and transitions of the CSS transform property on the element
+ * that run on the compositor thread. It will check the maximum and minimum
+ * scale during the animations and transitions and return a suitable value for
+ * performance and quality. Will return scale(1,1) if there are no such
+ * animations. Always returns a positive value.
+ * @param aVisibleSize is the size of the area we want to paint
+ * @param aDisplaySize is the size of the display area of the pres context
+ */
+ static MatrixScales ComputeSuitableScaleForAnimation(
+ const nsIFrame* aFrame, const nsSize& aVisibleSize,
+ const nsSize& aDisplaySize);
+
+ /**
+ * Checks whether we want to use the GPU to scale images when
+ * possible.
+ */
+ static bool GPUImageScalingEnabled();
+
+ /**
+ * Unions the overflow areas of the children of aFrame with aOverflowAreas.
+ * aSkipChildLists specifies any child lists that should be skipped.
+ * FrameChildListID::Popup is always skipped.
+ */
+ static void UnionChildOverflow(
+ nsIFrame* aFrame, mozilla::OverflowAreas& aOverflowAreas,
+ mozilla::FrameChildListIDs aSkipChildLists = {});
+
+ /**
+ * Return the font size inflation *ratio* for a given frame. This is
+ * the factor by which font sizes should be inflated; it is never
+ * smaller than 1.
+ */
+ static float FontSizeInflationFor(const nsIFrame* aFrame);
+
+ /**
+ * Perform the first half of the computation of FontSizeInflationFor
+ * (see above).
+ * This includes determining whether inflation should be performed
+ * within this container and returning 0 if it should not be.
+ *
+ * The result is guaranteed not to vary between line participants
+ * (inlines, text frames) within a line.
+ *
+ * The result should not be used directly since font sizes slightly
+ * above the minimum should always be adjusted as done by
+ * FontSizeInflationInner.
+ */
+ static nscoord InflationMinFontSizeFor(const nsIFrame* aFrame);
+
+ /**
+ * Perform the second half of the computation done by
+ * FontSizeInflationFor (see above).
+ *
+ * aMinFontSize must be the result of one of the
+ * InflationMinFontSizeFor methods above.
+ */
+ static float FontSizeInflationInner(const nsIFrame* aFrame,
+ nscoord aMinFontSize);
+
+ static bool FontSizeInflationEnabled(nsPresContext* aPresContext);
+
+ /**
+ * Returns true if the nglayout.debug.invalidation pref is set to true.
+ */
+ static bool InvalidationDebuggingIsEnabled() {
+ return mozilla::StaticPrefs::nglayout_debug_invalidation() ||
+ getenv("MOZ_DUMP_INVALIDATION") != 0;
+ }
+
+ static void Initialize();
+ static void Shutdown();
+
+ /**
+ * Register an imgIRequest object with a refresh driver.
+ *
+ * @param aPresContext The nsPresContext whose refresh driver we want to
+ * register with.
+ * @param aRequest A pointer to the imgIRequest object which the client wants
+ * to register with the refresh driver.
+ * @param aRequestRegistered A pointer to a boolean value which indicates
+ * whether the given image request is registered. If
+ * *aRequestRegistered is true, then this request will not be
+ * registered again. If the request is registered by this function,
+ * then *aRequestRegistered will be set to true upon the completion of
+ * this function.
+ *
+ */
+ static void RegisterImageRequest(nsPresContext* aPresContext,
+ imgIRequest* aRequest,
+ bool* aRequestRegistered);
+
+ /**
+ * Register an imgIRequest object with a refresh driver, but only if the
+ * request is for an image that is animated.
+ *
+ * @param aPresContext The nsPresContext whose refresh driver we want to
+ * register with.
+ * @param aRequest A pointer to the imgIRequest object which the client wants
+ * to register with the refresh driver.
+ * @param aRequestRegistered A pointer to a boolean value which indicates
+ * whether the given image request is registered. If
+ * *aRequestRegistered is true, then this request will not be
+ * registered again. If the request is registered by this function,
+ * then *aRequestRegistered will be set to true upon the completion of
+ * this function.
+ *
+ */
+ static void RegisterImageRequestIfAnimated(nsPresContext* aPresContext,
+ imgIRequest* aRequest,
+ bool* aRequestRegistered);
+
+ /**
+ * Deregister an imgIRequest object from a refresh driver.
+ *
+ * @param aPresContext The nsPresContext whose refresh driver we want to
+ * deregister from.
+ * @param aRequest A pointer to the imgIRequest object with which the client
+ * previously registered and now wants to deregister from the refresh
+ * driver.
+ * @param aRequestRegistered A pointer to a boolean value which indicates
+ * whether the given image request is registered. If
+ * *aRequestRegistered is false, then this request will not be
+ * deregistered. If the request is deregistered by this function,
+ * then *aRequestRegistered will be set to false upon the completion of
+ * this function.
+ */
+ static void DeregisterImageRequest(nsPresContext* aPresContext,
+ imgIRequest* aRequest,
+ bool* aRequestRegistered);
+
+ /**
+ * Shim to nsCSSFrameConstructor::PostRestyleEvent. Exists so that we
+ * can avoid including nsCSSFrameConstructor.h and all its dependencies
+ * in content files.
+ */
+ static void PostRestyleEvent(mozilla::dom::Element*, mozilla::RestyleHint,
+ nsChangeHint aMinChangeHint);
+
+ /**
+ * Updates a pair of x and y distances if a given point is closer to a given
+ * rectangle than the original distance values. If aPoint is closer to
+ * aRect than aClosestXDistance and aClosestYDistance indicate, then those
+ * two variables are updated with the distance between aPoint and aRect,
+ * and true is returned. If aPoint is not closer, then aClosestXDistance
+ * and aClosestYDistance are left unchanged, and false is returned.
+ *
+ * Distances are measured in the two dimensions separately; a closer x
+ * distance beats a closer y distance.
+ */
+ template <typename PointType, typename RectType, typename CoordType>
+ static bool PointIsCloserToRect(PointType aPoint, const RectType& aRect,
+ CoordType& aClosestXDistance,
+ CoordType& aClosestYDistance);
+ /**
+ * Computes the box shadow rect for the frame, or returns an empty rect if
+ * there are no shadows.
+ *
+ * @param aFrame Frame to compute shadows for.
+ * @param aFrameSize Size of aFrame (in case it hasn't been set yet).
+ */
+ static nsRect GetBoxShadowRectForFrame(nsIFrame* aFrame,
+ const nsSize& aFrameSize);
+
+#ifdef DEBUG
+ /**
+ * Assert that there are no duplicate continuations of the same frame
+ * within aFrameList. Optimize the tests by assuming that all frames
+ * in aFrameList have parent aContainer.
+ */
+ static void AssertNoDuplicateContinuations(nsIFrame* aContainer,
+ const nsFrameList& aFrameList);
+
+ /**
+ * Assert that the frame tree rooted at |aSubtreeRoot| is empty, i.e.,
+ * that it contains no first-in-flows.
+ */
+ static void AssertTreeOnlyEmptyNextInFlows(nsIFrame* aSubtreeRoot);
+#endif
+
+ /**
+ * Helper method to transform |aBounds| from aFrame to aAncestorFrame,
+ * and combine it with |aPreciseTargetDest| if it is axis-aligned, or
+ * combine it with |aImpreciseTargetDest| if not. The transformed rect is
+ * clipped to |aClip|; if |aClip| has rounded corners, that also causes
+ * the imprecise target to be used.
+ */
+ static void TransformToAncestorAndCombineRegions(
+ const nsRegion& aRegion, nsIFrame* aFrame, const nsIFrame* aAncestorFrame,
+ nsRegion* aPreciseTargetDest, nsRegion* aImpreciseTargetDest,
+ mozilla::Maybe<Matrix4x4Flagged>* aMatrixCache,
+ const mozilla::DisplayItemClip* aClip);
+
+ /**
+ * Populate aOutSize with the size of the content viewer corresponding
+ * to the given prescontext. Return true if the size was set, false
+ * otherwise.
+ */
+ enum class SubtractDynamicToolbar { No, Yes };
+ static bool GetContentViewerSize(
+ const nsPresContext* aPresContext, LayoutDeviceIntSize& aOutSize,
+ SubtractDynamicToolbar = SubtractDynamicToolbar::Yes);
+
+ private:
+ static bool UpdateCompositionBoundsForRCDRSF(
+ mozilla::ParentLayerRect& aCompBounds, const nsPresContext* aPresContext);
+
+ public:
+ /**
+ * Calculate the compostion size for a frame. See FrameMetrics.h for
+ * defintion of composition size (or bounds).
+ * Note that for the root content document's root scroll frame (RCD-RSF),
+ * the returned size does not change as the document's resolution changes,
+ * but for all other frames it does. This means that callers that pass in
+ * a frame that may or may not be the RCD-RSF (which is most callers),
+ * are likely to need special-case handling of the RCD-RSF.
+ */
+ static nsSize CalculateCompositionSizeForFrame(
+ nsIFrame* aFrame, bool aSubtractScrollbars = true,
+ const nsSize* aOverrideScrollPortSize = nullptr);
+
+ /**
+ * Calculate a size suitable for bounding the size of the composition bounds
+ * of scroll frames in the current process. This should be at most the
+ * composition size of the cross-process RCD-RSF, but it may be a tighter
+ * bounding size.
+ * @param aFrame A frame in the (in-process) root content document (or a
+ * descendant of it).
+ * @param aIsRootContentDocRootScrollFrame Whether aFrame is the root
+ * scroll frame of the *cross-process* root content document.
+ * In this case we just use aFrame's own composition size.
+ * @param aMetrics A partially populated FrameMetrics for aFrame. Must have at
+ * least mCompositionBounds, mCumulativeResolution, and
+ * mDevPixelsPerCSSPixel set.
+ */
+ static CSSSize CalculateBoundingCompositionSize(
+ const nsIFrame* aFrame, bool aIsRootContentDocRootScrollFrame,
+ const FrameMetrics& aMetrics);
+
+ /**
+ * Calculate the scrollable rect for a frame. See FrameMetrics.h for
+ * defintion of scrollable rect. aScrollableFrame is the scroll frame to
+ * calculate the scrollable rect for. If it's null then we calculate the
+ * scrollable rect as the rect of the root frame.
+ */
+ static nsRect CalculateScrollableRectForFrame(
+ const nsIScrollableFrame* aScrollableFrame, const nsIFrame* aRootFrame);
+
+ /**
+ * Calculate the expanded scrollable rect for a frame. See FrameMetrics.h for
+ * defintion of expanded scrollable rect.
+ */
+ static nsRect CalculateExpandedScrollableRect(nsIFrame* aFrame);
+
+ /**
+ * Returns true if the widget owning the given frame uses asynchronous
+ * scrolling.
+ */
+ static bool UsesAsyncScrolling(nsIFrame* aFrame);
+
+ /**
+ * Returns true if the widget owning the given frame has builtin APZ support
+ * enabled.
+ */
+ static bool AsyncPanZoomEnabled(const nsIFrame* aFrame);
+
+ /**
+ * Returns true if aDocument should be allowed to use resolution
+ * zooming.
+ */
+ static bool AllowZoomingForDocument(const mozilla::dom::Document* aDocument);
+
+ /**
+ * Returns true if we need to disable async scrolling for this particular
+ * element. Note that this does a partial disabling - the displayport still
+ * exists but uses a very small margin, and the compositor doesn't apply the
+ * async transform. However, the content may still be layerized.
+ */
+ static bool ShouldDisableApzForElement(nsIContent* aContent);
+
+ /**
+ * Log a key/value pair as "additional data" (not associated with a paint)
+ * for APZ testing.
+ * While the data is not associated with a paint, the APZTestData object
+ * is still owned by {Client,WebRender}LayerManager, so we need to be passed
+ * something from which we can derive the layer manager.
+ * This function takes a display list builder as the object to derive the
+ * layer manager from, to facilitate logging test data during display list
+ * building, but other overloads that take other objects could be added if
+ * desired.
+ */
+ static void LogAdditionalTestData(nsDisplayListBuilder* aBuilder,
+ const std::string& aKey,
+ const std::string& aValue);
+
+ /**
+ * Log a key/value pair for APZ testing during a paint.
+ * @param aManager The data will be written to the APZTestData associated
+ * with this layer manager.
+ * @param aScrollId Identifies the scroll frame to which the data pertains.
+ * @param aKey The key under which to log the data.
+ * @param aValue The value of the data to be logged.
+ */
+ static void LogTestDataForPaint(
+ mozilla::layers::WebRenderLayerManager* aManager, ViewID aScrollId,
+ const std::string& aKey, const std::string& aValue) {
+ DoLogTestDataForPaint(aManager, aScrollId, aKey, aValue);
+ }
+
+ /**
+ * A convenience overload of LogTestDataForPaint() that accepts any type
+ * as the value, and passes it through mozilla::ToString() to obtain a string
+ * value. The type passed must support streaming to an std::ostream.
+ */
+ template <typename Value>
+ static void LogTestDataForPaint(
+ mozilla::layers::WebRenderLayerManager* aManager, ViewID aScrollId,
+ const std::string& aKey, const Value& aValue) {
+ DoLogTestDataForPaint(aManager, aScrollId, aKey, mozilla::ToString(aValue));
+ }
+
+ /**
+ * Calculate a basic FrameMetrics with enough fields set to perform some
+ * layout calculations. The fields set are dev-to-css ratio, pres shell
+ * resolution, cumulative resolution, zoom, composition size, root
+ * composition size, scroll offset and scrollable rect.
+ *
+ * Note that for the RCD-RSF, the scroll offset returned is the layout
+ * viewport offset; if you need the visual viewport offset, that needs to
+ * be queried independently via PresShell::GetVisualViewportOffset().
+ *
+ * By contrast, ComputeFrameMetrics() computes all the fields, but requires
+ * extra inputs and can only be called during frame layer building.
+ */
+ static FrameMetrics CalculateBasicFrameMetrics(
+ nsIScrollableFrame* aScrollFrame);
+
+ static nsIScrollableFrame* GetAsyncScrollableAncestorFrame(nsIFrame* aTarget);
+
+ static void SetBSizeFromFontMetrics(
+ const nsIFrame* aFrame, mozilla::ReflowOutput& aMetrics,
+ const mozilla::LogicalMargin& aFramePadding, mozilla::WritingMode aLineWM,
+ mozilla::WritingMode aFrameWM);
+
+ static bool HasDocumentLevelListenersForApzAwareEvents(PresShell* aPresShell);
+
+ /**
+ * Returns true if the given scroll origin is "higher priority" than APZ.
+ * In general any content programmatic scrolls (e.g. scrollTo calls) are
+ * higher priority, and take precedence over APZ scrolling. This function
+ * returns true for those, and returns false for other origins like APZ
+ * itself, or scroll position updates from the history restore code.
+ */
+ static bool CanScrollOriginClobberApz(ScrollOrigin aScrollOrigin);
+
+ static ScrollMetadata ComputeScrollMetadata(
+ const nsIFrame* aForFrame, const nsIFrame* aScrollFrame,
+ nsIContent* aContent, const nsIFrame* aItemFrame,
+ const nsPoint& aOffsetToReferenceFrame,
+ mozilla::layers::WebRenderLayerManager* aLayerManager,
+ ViewID aScrollParentId, const nsSize& aScrollPortSize, bool aIsRoot);
+
+ /**
+ * Returns the metadata to put onto the root layer of a layer tree, if one is
+ * needed. The last argument is a callback function to check if the caller
+ * already has a metadata for a given scroll id.
+ */
+ static mozilla::Maybe<ScrollMetadata> GetRootMetadata(
+ nsDisplayListBuilder* aBuilder,
+ mozilla::layers::WebRenderLayerManager* aLayerManager,
+ const std::function<bool(ViewID& aScrollId)>& aCallback);
+
+ /**
+ * If the given scroll frame needs an area excluded from its composition
+ * bounds due to scrollbars, return that area, otherwise return an empty
+ * margin.
+ * There is no need to exclude scrollbars in the following cases:
+ * - If the scroll frame is not the RCD-RSF; in that case, the composition
+ * bounds is calculated based on the scroll port which already excludes
+ * the scrollbar area.
+ * - If the scrollbars are overlay, since then they are drawn on top of the
+ * scrollable content.
+ */
+ static nsMargin ScrollbarAreaToExcludeFromCompositionBoundsFor(
+ const nsIFrame* aScrollFrame);
+
+ static bool ShouldUseNoScriptSheet(mozilla::dom::Document*);
+ static bool ShouldUseNoFramesSheet(mozilla::dom::Document*);
+
+ /**
+ * Get the text content inside the frame. This methods traverse the
+ * frame tree and collect the content from text frames. Note that this
+ * method is similiar to nsContentUtils::GetNodeTextContent, but it at
+ * least differs from that method in the following things:
+ * 1. it skips text content inside nodes like style, script, textarea
+ * which don't generate an in-tree text frame for the text;
+ * 2. it skips elements with display property set to none;
+ * 3. it skips out-of-flow elements;
+ * 4. it includes content inside pseudo elements;
+ * 5. it may include part of text content of a node if a text frame
+ * inside is split to different continuations.
+ */
+ static void GetFrameTextContent(nsIFrame* aFrame, nsAString& aResult);
+
+ /**
+ * Same as GetFrameTextContent but appends the result rather than sets it.
+ */
+ static void AppendFrameTextContent(nsIFrame* aFrame, nsAString& aResult);
+
+ /**
+ * Takes a selection, and returns selection's bounding rect which is relative
+ * to its root frame.
+ *
+ * @param aSel Selection to check
+ */
+ static nsRect GetSelectionBoundingRect(const mozilla::dom::Selection* aSel);
+
+ /**
+ * Calculate the bounding rect of |aContent|, relative to the origin
+ * of the scrolled content of |aRootScrollFrame|.
+ * Where the element is contained inside a scrollable subframe, the
+ * bounding rect is clipped to the bounds of the subframe.
+ * If non-null aOutNearestScrollClip will be filled in with the rect of the
+ * nearest scroll frame (excluding aRootScrollFrame) that is an ancestor of
+ * the frame of aContent, if such exists, in the same coords are the returned
+ * rect. This rect is used to clip the result.
+ */
+ static CSSRect GetBoundingContentRect(
+ const nsIContent* aContent, const nsIScrollableFrame* aRootScrollFrame,
+ mozilla::Maybe<CSSRect>* aOutNearestScrollClip = nullptr);
+
+ /**
+ * Similar to GetBoundingContentRect for nsIFrame.
+ */
+ static CSSRect GetBoundingFrameRect(
+ nsIFrame* aFrame, const nsIScrollableFrame* aRootScrollFrame,
+ mozilla::Maybe<CSSRect>* aOutNearestScrollClip = nullptr);
+
+ /**
+ * Returns the first ancestor who is a float containing block.
+ */
+ static nsBlockFrame* GetFloatContainingBlock(nsIFrame* aFrame);
+
+ /**
+ * Walks up the frame tree from |aForFrame| up to |aTopFrame|, or to the
+ * root of the frame tree if |aTopFrame| is nullptr, and returns true if
+ * a transformed frame is encountered.
+ */
+ static bool IsTransformed(nsIFrame* aForFrame, nsIFrame* aTopFrame = nullptr);
+
+ /**
+ * Walk up from aFrame to the cross-doc root, accumulating all the APZ
+ * callback transforms on the content elements encountered along the way.
+ * Return the accumulated value.
+ * XXX: Note that this does not take into account CSS transforms, nor
+ * differences in structure between the frame tree and the layer tree (which
+ * is probably what we *want* to be computing).
+ */
+ static CSSPoint GetCumulativeApzCallbackTransform(nsIFrame* aFrame);
+
+ /**
+ * Compute a rect to pre-render in cases where we want to render more of
+ * something than what is visible (usually to support async transformation).
+ * @param aFrame the target frame to be pre-rendered
+ * @param aDirtyRect the area that's visible in the coordinate system of
+ * |aFrame|.
+ * @param aOverflow the total size of the thing we're rendering in the
+ * coordinate system of |aFrame|.
+ * @param aPrerenderSize how large of an area we're willing to render in the
+ * coordinate system of the root frame.
+ * @return A rectangle that includes |aDirtyRect|, is clamped to |aOverflow|,
+ * and is no larger than |aPrerenderSize| (unless |aPrerenderSize| is
+ * smaller than |aDirtyRect|, in which case the returned rect will
+ * still include |aDirtyRect| and thus be larger than
+ * |aPrerenderSize|).
+ */
+ static nsRect ComputePartialPrerenderArea(nsIFrame* aFrame,
+ const nsRect& aDirtyRect,
+ const nsRect& aOverflow,
+ const nsSize& aPrerenderSize);
+
+ /*
+ * Checks whether a node is an invisible break.
+ * If not, returns the first frame on the next line if such a next line
+ * exists.
+ *
+ * @return
+ * true if the node is an invisible break. aNextLineFrame is returned null
+ * in this case.
+ *
+ * false if the node causes a visible break or if the node is no break.
+ *
+ * @param aNextLineFrame
+ * assigned to first frame on the next line if such a next line exists, null
+ * otherwise.
+ */
+ static bool IsInvisibleBreak(nsINode* aNode,
+ nsIFrame** aNextLineFrame = nullptr);
+
+ static nsRect ComputeGeometryBox(nsIFrame*, StyleGeometryBox);
+
+ static nsRect ComputeGeometryBox(nsIFrame*,
+ const mozilla::StyleShapeGeometryBox&);
+
+ static nsRect ComputeGeometryBox(nsIFrame*, const mozilla::StyleShapeBox&);
+
+ static nsPoint ComputeOffsetToUserSpace(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame);
+
+ // Callers are responsible to ensure the user-font-set is up-to-date if
+ // aUseUserFontSet is true.
+ static already_AddRefed<nsFontMetrics> GetMetricsFor(
+ nsPresContext* aPresContext, bool aIsVertical,
+ const nsStyleFont* aStyleFont, mozilla::Length aFontSize,
+ bool aUseUserFontSet);
+
+ static void ComputeSystemFont(nsFont* aSystemFont,
+ mozilla::StyleSystemFont aFontID,
+ const nsFont& aDefaultVariableFont,
+ const mozilla::dom::Document* aDocument);
+
+ static uint32_t ParseFontLanguageOverride(const nsAString& aLangTag);
+
+ /**
+ * Returns true if there are any preferences or overrides that indicate a
+ * need to handle <meta name="viewport"> tags.
+ */
+ static bool ShouldHandleMetaViewport(const mozilla::dom::Document*);
+
+ /**
+ * Resolve a CSS <length-percentage> value to a definite size.
+ */
+ template <bool clampNegativeResultToZero>
+ static nscoord ResolveToLength(const LengthPercentage& aLengthPercentage,
+ nscoord aPercentageBasis) {
+ nscoord value = (aPercentageBasis == NS_UNCONSTRAINEDSIZE)
+ ? aLengthPercentage.Resolve(0)
+ : aLengthPercentage.Resolve(aPercentageBasis);
+ return clampNegativeResultToZero ? std::max(0, value) : value;
+ }
+
+ /**
+ * Resolve a column-gap/row-gap to a definite size.
+ * @note This method resolves 'normal' to zero.
+ * Callers who want different behavior should handle 'normal' on their own.
+ */
+ static nscoord ResolveGapToLength(
+ const mozilla::NonNegativeLengthPercentageOrNormal& aGap,
+ nscoord aPercentageBasis) {
+ if (aGap.IsNormal()) {
+ return nscoord(0);
+ }
+ return ResolveToLength<true>(aGap.AsLengthPercentage(), aPercentageBasis);
+ }
+
+ /**
+ * Get the computed style from which the scrollbar style should be
+ * used for the given scrollbar part frame.
+ */
+ static ComputedStyle* StyleForScrollbar(nsIFrame* aScrollbarPart);
+
+ /**
+ * Returns true if |aFrame| is scrolled out of view by a scrollable element in
+ * a cross-process ancestor document.
+ * Note this function only works for frames in out-of-process iframes.
+ **/
+ static bool FrameIsScrolledOutOfViewInCrossProcess(const nsIFrame* aFrame);
+
+ /**
+ * Similar to above FrameIsScrolledOutViewInCrossProcess but returns true even
+ * if |aFrame| is not fully scrolled out of view and its visible area width or
+ * height is smaller than |aMargin|.
+ **/
+ static bool FrameIsMostlyScrolledOutOfViewInCrossProcess(
+ const nsIFrame* aFrame, nscoord aMargin);
+
+ /**
+ * Expand the height of |aSize| to the size of `vh` units.
+ *
+ * With dynamic toolbar(s) the height for `vh` units is greater than the
+ * ICB height, we need to expand it in some places.
+ **/
+ static nsSize ExpandHeightForViewportUnits(nsPresContext* aPresContext,
+ const nsSize& aSize);
+
+ static CSSSize ExpandHeightForDynamicToolbar(
+ const nsPresContext* aPresContext, const CSSSize& aSize);
+ static nsSize ExpandHeightForDynamicToolbar(const nsPresContext* aPresContext,
+ const nsSize& aSize);
+
+ /**
+ * Returns the nsIFrame which clips overflow regions of the given |aFrame|.
+ * Note CSS clip or clip-path isn't accounted for.
+ **/
+ static nsIFrame* GetNearestOverflowClipFrame(nsIFrame* aFrame);
+
+ private:
+ /**
+ * Helper function for LogTestDataForPaint().
+ */
+ static void DoLogTestDataForPaint(
+ mozilla::layers::WebRenderLayerManager* aManager, ViewID aScrollId,
+ const std::string& aKey, const std::string& aValue);
+
+ static bool IsAPZTestLoggingEnabled();
+
+ static void ConstrainToCoordValues(gfxFloat& aStart, gfxFloat& aSize);
+ static void ConstrainToCoordValues(float& aStart, float& aSize);
+};
+
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsLayoutUtils::PaintFrameFlags)
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsLayoutUtils::GetPopupFrameForPointFlags)
+
+template <typename PointType, typename RectType, typename CoordType>
+/* static */ bool nsLayoutUtils::PointIsCloserToRect(
+ PointType aPoint, const RectType& aRect, CoordType& aClosestXDistance,
+ CoordType& aClosestYDistance) {
+ CoordType fromLeft = aPoint.x - aRect.x;
+ CoordType fromRight = aPoint.x - aRect.XMost();
+
+ CoordType xDistance;
+ if (fromLeft >= 0 && fromRight <= 0) {
+ xDistance = 0;
+ } else {
+ xDistance = std::min(abs(fromLeft), abs(fromRight));
+ }
+
+ if (xDistance <= aClosestXDistance) {
+ if (xDistance < aClosestXDistance) {
+ aClosestYDistance = std::numeric_limits<CoordType>::max();
+ }
+
+ CoordType fromTop = aPoint.y - aRect.y;
+ CoordType fromBottom = aPoint.y - aRect.YMost();
+
+ CoordType yDistance;
+ if (fromTop >= 0 && fromBottom <= 0) {
+ yDistance = 0;
+ } else {
+ yDistance = std::min(abs(fromTop), abs(fromBottom));
+ }
+
+ if (yDistance < aClosestYDistance) {
+ aClosestXDistance = xDistance;
+ aClosestYDistance = yDistance;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+template <typename T>
+nsRect nsLayoutUtils::RoundGfxRectToAppRect(const T& aRect,
+ const float aFactor) {
+ // Get a new Rect whose units are app units by scaling by the specified
+ // factor.
+ T scaledRect = aRect;
+ scaledRect.ScaleRoundOut(aFactor);
+
+ // We now need to constrain our results to the max and min values for coords.
+ ConstrainToCoordValues(scaledRect.x, scaledRect.width);
+ ConstrainToCoordValues(scaledRect.y, scaledRect.height);
+
+ if (!aRect.Width()) {
+ scaledRect.SetWidth(0);
+ }
+
+ if (!aRect.Height()) {
+ scaledRect.SetHeight(0);
+ }
+
+ // Now typecast everything back. This is guaranteed to be safe.
+ return nsRect(nscoord(scaledRect.X()), nscoord(scaledRect.Y()),
+ nscoord(scaledRect.Width()), nscoord(scaledRect.Height()));
+}
+
+namespace mozilla {
+
+/**
+ * Converts an nsPoint in app units to a Moz2D Point in pixels (whether those
+ * are device pixels or CSS px depends on what the caller chooses to pass as
+ * aAppUnitsPerPixel).
+ */
+inline gfx::Point NSPointToPoint(const nsPoint& aPoint,
+ int32_t aAppUnitsPerPixel) {
+ return gfx::Point(gfx::Float(aPoint.x) / aAppUnitsPerPixel,
+ gfx::Float(aPoint.y) / aAppUnitsPerPixel);
+}
+
+/**
+ * Converts an nsRect in app units to a Moz2D Rect in pixels (whether those
+ * are device pixels or CSS px depends on what the caller chooses to pass as
+ * aAppUnitsPerPixel).
+ */
+gfx::Rect NSRectToRect(const nsRect& aRect, double aAppUnitsPerPixel);
+
+/**
+ * Converts an nsRect in app units to a Moz2D Rect in pixels (whether those
+ * are device pixels or CSS px depends on what the caller chooses to pass as
+ * aAppUnitsPerPixel).
+ *
+ * The passed DrawTarget is used to additionally snap the returned Rect to
+ * device pixels, if appropriate (as decided and carried out by Moz2D's
+ * MaybeSnapToDevicePixels helper, which this function calls to do any
+ * snapping).
+ */
+gfx::Rect NSRectToSnappedRect(const nsRect& aRect, double aAppUnitsPerPixel,
+ const gfx::DrawTarget& aSnapDT);
+
+/**
+ * Converts, where possible, an nsRect in app units to a Moz2D Rect in pixels
+ * (whether those are device pixels or CSS px depends on what the caller
+ * chooses to pass as aAppUnitsPerPixel).
+ *
+ * If snapping results in a rectangle with zero width or height, the affected
+ * coordinates are left unsnapped
+ */
+gfx::Rect NSRectToNonEmptySnappedRect(const nsRect& aRect,
+ double aAppUnitsPerPixel,
+ const gfx::DrawTarget& aSnapDT);
+
+void StrokeLineWithSnapping(
+ const nsPoint& aP1, const nsPoint& aP2, int32_t aAppUnitsPerDevPixel,
+ gfx::DrawTarget& aDrawTarget, const gfx::Pattern& aPattern,
+ const gfx::StrokeOptions& aStrokeOptions = gfx::StrokeOptions(),
+ const gfx::DrawOptions& aDrawOptions = gfx::DrawOptions());
+
+namespace layout {
+
+/**
+ * An RAII class which will, for the duration of its lifetime,
+ * **if** the frame given is a container for font size inflation,
+ * set the current inflation container on the pres context to null
+ * (and then, in its destructor, restore the old value).
+ */
+class AutoMaybeDisableFontInflation {
+ public:
+ explicit AutoMaybeDisableFontInflation(nsIFrame* aFrame);
+
+ ~AutoMaybeDisableFontInflation();
+
+ private:
+ nsPresContext* mPresContext;
+ bool mOldValue;
+};
+
+} // namespace layout
+} // namespace mozilla
+
+class nsSetAttrRunnable : public mozilla::Runnable {
+ public:
+ nsSetAttrRunnable(mozilla::dom::Element* aElement, nsAtom* aAttrName,
+ const nsAString& aValue);
+ nsSetAttrRunnable(mozilla::dom::Element* aElement, nsAtom* aAttrName,
+ int32_t aValue);
+
+ NS_DECL_NSIRUNNABLE
+
+ RefPtr<mozilla::dom::Element> mElement;
+ RefPtr<nsAtom> mAttrName;
+ nsAutoString mValue;
+};
+
+class nsUnsetAttrRunnable : public mozilla::Runnable {
+ public:
+ nsUnsetAttrRunnable(mozilla::dom::Element* aElement, nsAtom* aAttrName);
+
+ NS_DECL_NSIRUNNABLE
+
+ RefPtr<mozilla::dom::Element> mElement;
+ RefPtr<nsAtom> mAttrName;
+};
+
+// This class allows you to easily set any pointer variable and ensure it's
+// set to nullptr when leaving its scope.
+template <typename T>
+class MOZ_RAII SetAndNullOnExit {
+ public:
+ SetAndNullOnExit(T*& aVariable, T* aValue) {
+ aVariable = aValue;
+ mVariable = &aVariable;
+ }
+ ~SetAndNullOnExit() { *mVariable = nullptr; }
+
+ private:
+ T** mVariable;
+};
+
+#endif // nsLayoutUtils_h__