diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /layout/base/nsLayoutUtils.h | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'layout/base/nsLayoutUtils.h')
-rw-r--r-- | layout/base/nsLayoutUtils.h | 3110 |
1 files changed, 3110 insertions, 0 deletions
diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h new file mode 100644 index 0000000000..087bdc8ce1 --- /dev/null +++ b/layout/base/nsLayoutUtils.h @@ -0,0 +1,3110 @@ +/* -*- 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/UniquePtr.h" +#include "mozilla/WritingModes.h" +#include "mozilla/layout/FrameChildList.h" +#include "mozilla/layers/ScrollableLayerGuid.h" +#include "mozilla/gfx/2D.h" + +#include "gfxPoint.h" +#include "nsBoundingMetrics.h" +#include "nsCSSPropertyIDSet.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; +class nsDisplayListBuilder; +enum class nsDisplayListBuilderMode : uint8_t; +enum nsChangeHint : uint32_t; +class nsDisplayItem; +class nsDisplayList; +class nsFontMetrics; +class nsFontFaceList; +class nsIImageLoadingContent; +class nsBlockFrame; +class nsContainerFrame; +class nsView; +class nsIFrame; +class nsPIDOMWindowOuter; +class imgIRequest; +struct nsStyleFont; + +namespace mozilla { +struct AspectRatio; +class ComputedStyle; +class DisplayPortUtils; +class PresShell; +enum class PseudoStyleType : uint8_t; +class EventListenerManager; +enum class LayoutFrameType : uint8_t; +struct IntrinsicSize; +struct ContainerLayerParameters; +class ReflowOutput; +class WritingMode; +class DisplayItemClip; +class EffectSet; +struct ActiveScrolledRoot; +enum class ScrollOrigin : uint8_t; +enum class StyleImageOrientation : uint8_t; +struct OverflowAreas; +namespace dom { +class CanvasRenderingContext2D; +class DOMRectList; +class Document; +class Element; +class Event; +class HTMLImageElement; +class HTMLCanvasElement; +class HTMLVideoElement; +class InspectorFontFace; +class OffscreenCanvas; +class Selection; +} // namespace dom +namespace gfx { +struct RectCornerRadii; +enum class ShapedTextFlags : uint16_t; +} // namespace gfx +namespace layers { +struct FrameMetrics; +struct ScrollMetadata; +class Image; +class StackingContextHelper; +class Layer; + +} // 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::Layer Layer; + typedef mozilla::layers::StackingContextHelper StackingContextHelper; + typedef mozilla::ContainerLayerParameters ContainerLayerParameters; + 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::RectCornerRadii RectCornerRadii; + typedef mozilla::gfx::StrokeOptions StrokeOptions; + typedef mozilla::image::ImgDrawResult ImgDrawResult; + + 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::layout::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); + + /** + * 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); + + /** + * 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 aExtraOffset [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. + */ + 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. + */ + static bool IsProperAncestorFrameCrossDoc( + 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. + */ + static bool IsAncestorFrameCrossDoc( + const nsIFrame* aAncestorFrame, const nsIFrame* aFrame, + const nsIFrame* aCommonAncestor = nullptr); + + /** + * Sets the fixed-pos metadata properties on aLayer. + * aAnchorRect is the basic anchor rectangle. If aFixedPosFrame is not a + * viewport frame, then we pick a corner of aAnchorRect to as the anchor point + * for the fixed-pos layer (i.e. the point to remain stable during zooming), + * based on which of the fixed-pos frame's CSS absolute positioning offset + * properties (top, left, right, bottom) are auto. aAnchorRect is in the + * coordinate space of aLayer's container layer (i.e. relative to the + * reference frame of the display item which is building aLayer's container + * layer). + */ + static void SetFixedPositionLayerData( + Layer* aLayer, const nsIFrame* aViewportFrame, const nsRect& aAnchorRect, + const nsIFrame* aFixedPosFrame, nsPresContext* aPresContext, + const ContainerLayerParameters& aContainerParameters); + + static mozilla::SideBits GetSideBitsAndAdjustAnchorForFixedPositionContent( + const nsIFrame* aViewportFrame, const nsIFrame* aFixedPosFrame, + mozilla::LayerPoint* aAnchor, const Rect* aAnchorRect); + 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, + /** + * If the SCROLLABLE_FOLLOW_OOF_TO_PLACEHOLDER flag is set, we navigate + * from out-of-flow frames to their placeholder frame rather than their + * parent frame. + * Note, fixed-pos frames are out-of-flow frames, but + * SCROLLABLE_FIXEDPOS_FINDS_ROOT takes precedence over this. + */ + SCROLLABLE_FOLLOW_OOF_TO_PLACEHOLDER = 0x40 + }; + /** + * 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 aNewBreakType with aOrigBreakType, but limit the break types + // to StyleClear::Left, Right, Both. + static mozilla::StyleClear CombineBreakType( + mozilla::StyleClear aOrigBreakType, mozilla::StyleClear aNewBreakType); + + /** + * 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 aPresContext only check popups within aPresContext 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* aPresContext, const mozilla::WidgetEvent* aEvent); + + /** + * 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 is 2D, or the identity scale factors otherwise. + */ + static gfxSize 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 gfxSize GetTransformToAncestorScaleExcludingAnimated(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); + + /** + * 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(nsIFrame* aFromFrame, + nsIFrame* 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, + NoComposite = 0x100, + Compressed = 0x200, + ForWebRender = 0x400, + UseHighQualityScaling = 0x800, + }; + + /** + * 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. + * 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 nsresult 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() : mIncludeCaptionBoxForTable(true) {} + virtual void AddBox(nsIFrame* aFrame) = 0; + bool mIncludeCaptionBoxForTable; + }; + /** + * 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( + 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(const nsString& aString, + nsFontMetrics& aFontMetrics, + DrawTarget* aDrawTarget) { + return nsLayoutUtils::AppUnitWidthOfString(aString.get(), 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::Maybe<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, + const SamplingFilter aSamplingFilter, const nsRect& aDest, + const nsRect& aDirty, const mozilla::Maybe<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. + */ + static void ComputeSizeForDrawing(imgIContainer* aImage, + 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 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 StackingContextHelper& aSc, + uint32_t aFlags, mozilla::Maybe<SVGImageContext>& aSVGContext); + + /** + * 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( + ComputedStyle* aComputedStyle, nsPresContext* aPresContext, + const nsStyleFont* aStyleFont, const nsStyleText* aStyleText, + nscoord aLetterSpacing); + + /** + * Get orientation flags for textrun construction. + */ + static mozilla::gfx::ShapedTextFlags GetTextRunOrientFlagsForStyle( + ComputedStyle* aComputedStyle); + + /** + * 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 { + /* When creating a new surface, create an image surface */ + SFE_WANT_IMAGE_SURFACE = 1 << 0, + /* 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 << 1, + /* Whether we should skip colorspace/gamma conversion */ + SFE_NO_COLORSPACE_CONVERSION = 1 << 2, + /* Caller handles SFER::mAlphaType = NonPremult */ + SFE_ALLOW_NON_PREMULT = 1 << 3, + /* Whether we should skip getting a surface for vector images and + return a DirectDrawInfo containing an imgIContainer instead. */ + SFE_NO_RASTERIZING_VECTORS = 1 << 4, + /* 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 << 5 + }; + + // 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 SurfaceFromElement( + mozilla::dom::Element* aElement, 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, 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, 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::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 nsDataHashtable<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); + + /** + * 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 Size 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. + * kSelectPopupList and kPopupList are always skipped. + */ + static void UnionChildOverflow( + nsIFrame* aFrame, mozilla::OverflowAreas& aOverflowAreas, + mozilla::layout::FrameChildListIDs aSkipChildLists = + mozilla::layout::FrameChildListIDs()); + + /** + * 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 get touch action behaviour from the frame + */ + static mozilla::StyleTouchAction GetTouchActionFromFrame(nsIFrame* aFrame); + + /** + * 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 the composition size for the root scroll frame of the root + * content document. + * @param aFrame A frame in the root content document (or a descendant of it). + * @param aIsRootContentDocRootScrollFrame Whether aFrame is already the root + * scroll frame of the 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 CalculateRootCompositionSize( + 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 the current APZ Resolution Scale. When Java Pan/Zoom is + * enabled in Fennec it will always return 1.0. + */ + static float GetCurrentAPZResolutionScale(PresShell* aPresShell); + + /** + * 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::LayerManager* 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::LayerManager* 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* aReferenceFrame, + mozilla::layers::LayerManager* aLayerManager, ViewID aScrollParentId, + const nsSize& aScrollPortSize, const mozilla::Maybe<nsRect>& aClipRect, + bool aIsRoot, + const mozilla::Maybe<ContainerLayerParameters>& aContainerParameters); + + /** + * 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::LayerManager* aLayerManager, + const ContainerLayerParameters& aContainerParameters, + 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); + + /** + * Looks in the layer subtree rooted at aLayer for a metrics with scroll id + * aScrollId. Returns true if such is found. + */ + static bool ContainsMetricsWithId(const Layer* aLayer, + const ViewID& aScrollId); + + 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. + */ + static CSSRect GetBoundingContentRect( + const nsIContent* aContent, const nsIScrollableFrame* aRootScrollFrame); + + /** + * Similar to GetBoundingContentRect for nsIFrame. + */ + static CSSRect GetBoundingFrameRect( + nsIFrame* aFrame, const nsIScrollableFrame* aRootScrollFrame); + + /** + * 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); + + // Return the default value to be used for -moz-control-character-visibility, + // from preferences. + static mozilla::StyleControlCharacterVisibility + ControlCharVisibilityDefault(); + + // 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::LookAndFeel::FontID 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::LayerManager* 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) + +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; +}; + +void MaybeSetupTransactionIdAllocator(layers::LayerManager* aManager, + nsPresContext* aPresContext); + +} // 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__ |