Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsLayoutUtils_h__
#define nsLayoutUtils_h__
#include <limits>
#include <algorithm>
#include "gfxPoint.h"
#include "LayoutConstants.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/ScrollableLayerGuid.h"
#include "mozilla/LayoutStructs.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/RelativeTo.h"
#include "mozilla/Span.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 "nsBoundingMetrics.h"
#include "nsCSSPropertyIDSet.h"
#include "nsFrameList.h"
#include "nsPoint.h"
#include "nsThreadUtils.h"
#include "Units.h"
// 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 nsRegion;
enum nsChangeHint : uint32_t;
class nsFontMetrics;
class nsFontFaceList;
class nsIImageLoadingContent;
class nsBlockFrame;
class nsContainerFrame;
class nsView;
class nsIFrame;
class nsPIDOMWindowOuter;
class imgIRequest;
struct nsStyleFont;
namespace mozilla {
class nsDisplayItem;
class nsDisplayList;
class nsDisplayListBuilder;
enum class nsDisplayListBuilderMode : uint8_t;
class RetainedDisplayListBuilder;
struct AspectRatio;
class ComputedStyle;
class DisplayPortUtils;
class PresShell;
enum class PseudoStyleType : uint8_t;
class EventListenerManager;
enum class LayoutFrameType : uint8_t;
struct IntrinsicSize;
class ReflowOutput;
class WritingMode;
class DisplayItemClip;
class EffectSet;
struct ActiveScrolledRoot;
class ScrollContainerFrame;
enum class ScrollOrigin : uint8_t;
enum class StyleImageOrientation : uint8_t;
enum class StyleSystemFont : uint8_t;
enum class StyleScrollbarWidth : uint8_t;
struct OverflowAreas;
namespace dom {
class CanvasRenderingContext2D;
class DOMRectList;
class Document;
class Element;
class Event;
class HTMLImageElement;
class HTMLCanvasElement;
class HTMLVideoElement;
class ImageBitmap;
class InspectorFontFace;
class OffscreenCanvas;
class Selection;
class VideoFrame;
} // namespace dom
namespace gfx {
struct RectCornerRadii;
enum class ShapedTextFlags : uint16_t;
} // namespace gfx
namespace image {
class ImageIntRegion;
struct Resolution;
} // namespace image
namespace layers {
struct FrameMetrics;
struct ScrollMetadata;
class Image;
class StackingContextHelper;
class Layer;
class WebRenderLayerManager;
} // namespace layers
namespace widget {
enum class TransparencyMode : uint8_t;
}
} // namespace mozilla
// Flags to customize the behavior of nsLayoutUtils::DrawString.
enum class DrawStringFlags {
Default = 0x0,
ForceHorizontal = 0x1 // Forces the text to be drawn horizontally.
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DrawStringFlags)
namespace mozilla {
class RectCallback {
public:
virtual void AddRect(const nsRect& aRect) = 0;
};
} // namespace mozilla
/**
* nsLayoutUtils is a namespace class used for various helper
* functions that are useful in multiple places in layout. The goal
* is not to define multiple copies of the same static helper.
*/
class nsLayoutUtils {
typedef mozilla::AspectRatio AspectRatio;
typedef mozilla::ComputedStyle ComputedStyle;
typedef mozilla::LengthPercentage LengthPercentage;
typedef mozilla::LengthPercentageOrAuto LengthPercentageOrAuto;
typedef mozilla::dom::DOMRectList DOMRectList;
typedef mozilla::layers::StackingContextHelper StackingContextHelper;
typedef mozilla::IntrinsicSize IntrinsicSize;
typedef mozilla::RelativeTo RelativeTo;
typedef mozilla::ScrollOrigin ScrollOrigin;
typedef mozilla::ViewportType ViewportType;
typedef mozilla::gfx::SourceSurface SourceSurface;
typedef mozilla::gfx::sRGBColor sRGBColor;
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::gfx::ExtendMode ExtendMode;
typedef mozilla::gfx::SamplingFilter SamplingFilter;
typedef mozilla::gfx::Float Float;
typedef mozilla::gfx::Point Point;
typedef mozilla::gfx::Rect Rect;
typedef mozilla::gfx::RectDouble RectDouble;
typedef mozilla::gfx::Size Size;
typedef mozilla::gfx::Matrix4x4 Matrix4x4;
typedef mozilla::gfx::Matrix4x4Flagged Matrix4x4Flagged;
typedef mozilla::gfx::MatrixScales MatrixScales;
typedef mozilla::gfx::MatrixScalesDouble MatrixScalesDouble;
typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
typedef mozilla::gfx::StrokeOptions StrokeOptions;
typedef mozilla::image::ImgDrawResult ImgDrawResult;
using nsDisplayItem = mozilla::nsDisplayItem;
using nsDisplayList = mozilla::nsDisplayList;
using nsDisplayListBuilder = mozilla::nsDisplayListBuilder;
using nsDisplayListBuilderMode = mozilla::nsDisplayListBuilderMode;
using RetainedDisplayListBuilder = mozilla::RetainedDisplayListBuilder;
public:
typedef mozilla::layers::FrameMetrics FrameMetrics;
typedef mozilla::layers::ScrollMetadata ScrollMetadata;
typedef mozilla::layers::ScrollableLayerGuid::ViewID ViewID;
typedef mozilla::CSSPoint CSSPoint;
typedef mozilla::CSSSize CSSSize;
typedef mozilla::CSSIntSize CSSIntSize;
typedef mozilla::CSSRect CSSRect;
typedef mozilla::ScreenMargin ScreenMargin;
typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize;
typedef mozilla::LayoutDeviceRect LayoutDeviceRect;
typedef mozilla::PresShell PresShell;
typedef mozilla::StyleGeometryBox StyleGeometryBox;
typedef mozilla::SVGImageContext SVGImageContext;
typedef mozilla::LogicalSize LogicalSize;
/**
* Finds previously assigned ViewID for the given content element, if any.
* Returns whether a ViewID was previously assigned.
*/
static bool FindIDFor(const nsIContent* aContent, ViewID* aOutViewId);
/**
* Finds previously assigned or generates a unique ViewID for the given
* content element.
*/
static ViewID FindOrCreateIDFor(nsIContent* aContent);
/**
* Find content for given ID.
*/
static nsIContent* FindContentFor(ViewID aId);
/**
* Find the scroll container frame for a given content element.
*/
static mozilla::ScrollContainerFrame* FindScrollContainerFrameFor(
nsIContent* aContent);
/**
* Find the scroll container frame for a given ID.
*/
static mozilla::ScrollContainerFrame* FindScrollContainerFrameFor(ViewID aId);
/**
* Helper for FindScrollContainerFrameFor(), also used in DisplayPortUtils.
* Most clients should use FindScrollContainerFrameFor().
*/
static nsIFrame* GetScrollContainerFrameFromContent(nsIContent* aContent);
/**
* Find the ID for a given scroll container frame.
*/
static ViewID FindIDForScrollContainerFrame(
mozilla::ScrollContainerFrame* aScrollContainerFrame);
/**
* Notify the scroll frame with the given scroll id that its scroll offset
* is being sent to APZ as part of a paint-skip transaction.
*
* Normally, this notification happens during painting, after calls to
* ComputeScrollMetadata(). During paint-skipping that code is skipped,
* but it's still important for the scroll frame to be notified for
* correctness of relative scroll updates, so the code that sends the
* empty paint-skip transaction needs to call this.
*/
static void NotifyPaintSkipTransaction(ViewID aScrollId);
/**
* Use heuristics to figure out the child list that
* aChildFrame is currently in.
*/
static mozilla::FrameChildListID GetChildListNameFor(nsIFrame* aChildFrame);
/**
* Returns the ::before pseudo-element for aContent, if any.
*/
static mozilla::dom::Element* GetBeforePseudo(const nsIContent* aContent);
/**
* Returns the frame corresponding to the ::before pseudo-element for
* aContent, if any.
*/
static nsIFrame* GetBeforeFrame(const nsIContent* aContent);
/**
* Returns the ::after pseudo-element for aContent, if any.
*/
static mozilla::dom::Element* GetAfterPseudo(const nsIContent* aContent);
/**
* Returns the frame corresponding to the ::after pseudo-element for aContent,
* if any.
*/
static nsIFrame* GetAfterFrame(const nsIContent* aContent);
/**
* Returns the ::marker pseudo-element for aContent, if any.
*/
static mozilla::dom::Element* GetMarkerPseudo(const nsIContent* aContent);
/**
* Returns the frame corresponding to the ::marker pseudo-element for
* aContent, if any.
*/
static nsIFrame* GetMarkerFrame(const nsIContent* aContent);
#ifdef ACCESSIBILITY
/**
* Set aText to the spoken text for the given ::marker content (aContent)
* if it has a frame, or the empty string otherwise.
*/
static void GetMarkerSpokenText(const nsIContent* aContent, nsAString& aText);
#endif
/**
* Given a frame, search up the frame tree until we find an
* ancestor that (or the frame itself) is of type aFrameType, if any.
*
* @param aFrame the frame to start at
* @param aFrameType the frame type to look for
* @param aStopAt a frame to stop at after we checked it
* @return a frame of the given type or nullptr if no
* such ancestor exists
*/
static nsIFrame* GetClosestFrameOfType(nsIFrame* aFrame,
mozilla::LayoutFrameType aFrameType,
nsIFrame* aStopAt = nullptr);
/**
* Given a frame, search up the frame tree until we find an
* ancestor that (or the frame itself) is a "Page" frame, if any.
*
* @param aFrame the frame to start at
* @return a frame of type mozilla::LayoutFrameType::Page or nullptr if no
* such ancestor exists
*/
static nsIFrame* GetPageFrame(nsIFrame* aFrame);
/**
* Given a frame which is the primary frame for an element,
* return the frame that has the non-pseudoelement ComputedStyle for
* the content.
* This is aPrimaryFrame itself except for tableWrapper frames.
*
* Given a non-null input, this will return null if and only if its
* argument is a table wrapper frame that is mid-destruction (and its
* table frame has been destroyed).
*/
static nsIFrame* GetStyleFrame(nsIFrame* aPrimaryFrame);
static const nsIFrame* GetStyleFrame(const nsIFrame* aPrimaryFrame);
/**
* Given a content node,
* return the frame that has the non-pseudoelement ComputedStyle for
* the content. May return null.
* This is aContent->GetPrimaryFrame() except for tableWrapper frames.
*/
static nsIFrame* GetStyleFrame(const nsIContent* aContent);
/**
* Returns the placeholder size for when the scrollbar is unthemed.
*/
static mozilla::CSSIntCoord UnthemedScrollbarSize(
mozilla::StyleScrollbarWidth);
/**
* The inverse of GetStyleFrame. Returns |aStyleFrame| unless it is an inner
* table frame, in which case the table wrapper frame is returned.
*/
static nsIFrame* GetPrimaryFrameFromStyleFrame(nsIFrame* aStyleFrame);
static const nsIFrame* GetPrimaryFrameFromStyleFrame(
const nsIFrame* aStyleFrame);
/**
* Similar to nsIFrame::IsPrimaryFrame except that this will return true
* for the inner table frame rather than for its wrapper frame.
*/
static bool IsPrimaryStyleFrame(const nsIFrame* aFrame);
/**
* 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, aCommonAncestor);
}
static int32_t CompareTreePosition(nsIFrame* aFrame1, nsIFrame* aFrame2,
nsTArray<nsIFrame*>& aFrame2Ancestors,
nsIFrame* aCommonAncestor = nullptr) {
return DoCompareTreePosition(aFrame1, aFrame2, aFrame2Ancestors,
aCommonAncestor);
}
static nsIFrame* FillAncestors(nsIFrame* aFrame, nsIFrame* aStopAtAncestor,
nsTArray<nsIFrame*>* aAncestors);
static int32_t DoCompareTreePosition(nsIFrame* aFrame1, nsIFrame* aFrame2,
nsIFrame* aCommonAncestor);
static int32_t DoCompareTreePosition(nsIFrame* aFrame1, nsIFrame* aFrame2,
nsTArray<nsIFrame*>& aFrame2Ancestors,
nsIFrame* aCommonAncestor);
/**
* LastContinuationWithChild gets the last continuation in aFrame's chain
* that has a child, or the first continuation if the frame has no children.
*/
static nsContainerFrame* LastContinuationWithChild(nsContainerFrame* aFrame);
/**
* GetLastSibling simply finds the last sibling of aFrame, or returns nullptr
* if aFrame is null.
*/
static nsIFrame* GetLastSibling(nsIFrame* aFrame);
/**
* FindSiblingViewFor locates the child of aParentView that aFrame's
* view should be inserted 'above' (i.e., before in sibling view
* order). This is the first child view of aParentView whose
* corresponding content is before aFrame's content (view siblings
* are in reverse content order).
*/
static nsView* FindSiblingViewFor(nsView* aParentView, nsIFrame* aFrame);
/**
* Get the parent of aFrame. If aFrame is the root frame for a document,
* and the document has a parent document in the same view hierarchy, then
* we try to return the subdocumentframe in the parent document.
* @param aCrossDocOffset [in/out] if non-null, then as we cross documents
* an extra offset may be required and it will be added to aCrossDocOffset.
* Be careful dealing with this extra offset as it is in app units of the
* parent document, which may have a different app units per dev pixel ratio
* than the child document.
* Note that, while this function crosses document boundaries, it (naturally)
* cannot cross process boundaries.
*/
static nsIFrame* GetCrossDocParentFrameInProcess(
const nsIFrame* aFrame, nsPoint* aCrossDocOffset = nullptr);
/**
* Does the same thing as GetCrossDocParentFrameInProcess().
* The purpose of having two functions is to more easily track which call
* sites have been audited to consider out-of-process iframes (bug 1599913).
* Once all call sites have been audited, this function can be removed.
*/
static nsIFrame* GetCrossDocParentFrame(const nsIFrame* aFrame,
nsPoint* aCrossDocOffset = nullptr);
/**
* IsProperAncestorFrame checks whether aAncestorFrame is an ancestor
* of aFrame and not equal to aFrame.
* @param aCommonAncestor nullptr, or a common ancestor of aFrame and
* aAncestorFrame. If non-null, this can bound the search and speed up
* the function
*/
static bool IsProperAncestorFrame(const nsIFrame* aAncestorFrame,
const nsIFrame* aFrame,
const nsIFrame* aCommonAncestor = nullptr);
/**
* Like IsProperAncestorFrame, but looks across document boundaries.
*
* Just like IsAncestorFrameCrossDoc, except that it returns false when
* aFrame == aAncestorFrame.
* TODO: Once after we fixed bug 1715932, this function should be removed.
*/
static bool IsProperAncestorFrameCrossDoc(
const nsIFrame* aAncestorFrame, const nsIFrame* aFrame,
const nsIFrame* aCommonAncestor = nullptr);
/**
* Like IsProperAncestorFrame, but looks across document boundaries.
*
* Just like IsAncestorFrameCrossDoc, except that it returns false when
* aFrame == aAncestorFrame.
*/
static bool IsProperAncestorFrameCrossDocInProcess(
const nsIFrame* aAncestorFrame, const nsIFrame* aFrame,
const nsIFrame* aCommonAncestor = nullptr);
/**
* IsAncestorFrameCrossDoc checks whether aAncestorFrame is an ancestor
* of aFrame or equal to aFrame, looking across document boundaries.
* @param aCommonAncestor nullptr, or a common ancestor of aFrame and
* aAncestorFrame. If non-null, this can bound the search and speed up
* the function.
*
* Just like IsProperAncestorFrameCrossDoc, except that it returns true when
* aFrame == aAncestorFrame.
*
* TODO: Bug 1700245, all call sites of this function will be eventually
* replaced by IsAncestorFrameCrossDocInProcess.
*/
static bool IsAncestorFrameCrossDoc(
const nsIFrame* aAncestorFrame, const nsIFrame* aFrame,
const nsIFrame* aCommonAncestor = nullptr);
/**
* IsAncestorFrameCrossDocInProcess checks whether aAncestorFrame is an
* ancestor of aFrame or equal to aFrame, looking across document boundaries
* in the same process.
* @param aCommonAncestor nullptr, or a common ancestor of aFrame and
* aAncestorFrame. If non-null, this can bound the search and speed up
* the function.
*
* Just like IsProperAncestorFrameCrossDoc, except that it returns true when
* aFrame == aAncestorFrame.
*
* NOTE: This function doesn't return true even if |aAncestorFrame| and
* |aFrame| is in the same process but they are not directly connected, e.g.
* both |aAncestorFrame| and |aFrame| in A domain documents, but there's
* another an iframe document domain B, such as A1 -> B1 ->A2 document tree.
*/
static bool IsAncestorFrameCrossDocInProcess(
const nsIFrame* aAncestorFrame, const nsIFrame* aFrame,
const nsIFrame* aCommonAncestor = nullptr);
static mozilla::SideBits GetSideBitsForFixedPositionContent(
const nsIFrame* aFixedPosFrame);
/**
* Get the scroll id for the root scrollframe of the presshell of the given
* prescontext. Returns NULL_SCROLL_ID if it couldn't be found.
*/
static ViewID ScrollIdForRootScrollFrame(nsPresContext* aPresContext);
/**
* GetScrollContainerFrameFor returns the scroll container frame for a
* scrolled frame.
*/
static mozilla::ScrollContainerFrame* GetScrollContainerFrameFor(
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 scroll container frame or nullptr if not found
*/
static mozilla::ScrollContainerFrame* 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,
};
/**
* GetNearestScrollContainerFrame 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 scroll container frame or nullptr if not found
*/
static mozilla::ScrollContainerFrame* GetNearestScrollContainerFrame(
nsIFrame* aFrame, uint32_t aFlags = 0);
/**
* GetScrolledRect returns the range of allowable scroll offsets
* for aScrolledFrame, assuming the scrollable overflow area is
* aScrolledFrameOverflowArea and the scrollport size is aScrollPortSize.
*/
static nsRect GetScrolledRect(nsIFrame* aScrolledFrame,
const nsRect& aScrolledFrameOverflowArea,
const nsSize& aScrollPortSize,
mozilla::StyleDirection);
/**
* HasPseudoStyle returns true if aContent (whose primary style
* context is aComputedStyle) has the aPseudoElement pseudo-style
* attached to it; returns false otherwise.
*
* @param aContent the content node we're looking at
* @param aComputedStyle aContent's ComputedStyle
* @param aPseudoElement the id of the pseudo style we care about
* @param aPresContext the presentation context
* @return whether aContent has aPseudoElement style attached to it
*/
static bool HasPseudoStyle(nsIContent* aContent,
ComputedStyle* aComputedStyle,
mozilla::PseudoStyleType aPseudoElement,
nsPresContext* aPresContext);
/**
* If this frame is a placeholder for a float, then return the float,
* otherwise return nullptr. aPlaceholder must be a placeholder frame.
*/
static nsIFrame* GetFloatFromPlaceholder(nsIFrame* aPlaceholder);
// Combine aOrigClearType with aNewClearType, but limit the clear types
// to UsedClear::Left, Right, Both.
static mozilla::UsedClear CombineClearType(mozilla::UsedClear aOrigClearType,
mozilla::UsedClear aNewClearType);
/**
* Get the coordinates of a given DOM mouse event, relative to a given
* frame. Works only for DOM events generated by WidgetGUIEvents.
* @param aDOMEvent the event
* @param aFrame the frame to make coordinates relative to
* @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
* for some reason the coordinates for the mouse are not known (e.g.,
* the event is not a GUI event).
*/
static nsPoint GetDOMEventCoordinatesRelativeTo(
mozilla::dom::Event* aDOMEvent, nsIFrame* aFrame);
/**
* Get the coordinates of a given native mouse event, relative to a given
* frame.
* @param aEvent the event
* @param aFrame the frame to make coordinates relative to
* @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
* for some reason the coordinates for the mouse are not known (e.g.,
* the event is not a GUI event).
*/
static nsPoint GetEventCoordinatesRelativeTo(
const mozilla::WidgetEvent* aEvent, RelativeTo aFrame);
/**
* Get the coordinates of a given point relative to an event and a
* given frame.
* @param aEvent the event
* @param aPoint the point to get the coordinates relative to
* @param aFrame the frame to make coordinates relative to
* @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
* for some reason the coordinates for the mouse are not known (e.g.,
* the event is not a GUI event).
*/
static nsPoint GetEventCoordinatesRelativeTo(
const mozilla::WidgetEvent* aEvent,
const mozilla::LayoutDeviceIntPoint& aPoint, RelativeTo aFrame);
/**
* Get the coordinates of a given point relative to a widget and a
* given frame.
* @param aWidget the event src widget
* @param aPoint the point to get the coordinates relative to
* @param aFrame the frame to make coordinates relative to
* @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
* for some reason the coordinates for the mouse are not known (e.g.,
* the event is not a GUI event).
*/
static nsPoint GetEventCoordinatesRelativeTo(
nsIWidget* aWidget, const mozilla::LayoutDeviceIntPoint& aPoint,
RelativeTo aFrame);
/**
* Get the popup frame of a given native mouse event.
* @param aRootPresContext only check popups within aRootPresContext or a
* descendant
* @param aEvent the event.
* @return Null, if there is no popup frame at the point, otherwise,
* returns top-most popup frame at the point.
*/
static nsIFrame* GetPopupFrameForEventCoordinates(
nsPresContext* aRootPresContext, const mozilla::WidgetEvent* aEvent);
/**
* Get the popup frame of a given point relative to a widget.
* @param aRootPresContext only check popups within aRootPresContext or a
* descendant
* @param aEvent the event.
* @return Null, if there is no popup frame at the point, otherwise,
* returns top-most popup frame at the point.
*/
enum class GetPopupFrameForPointFlags : uint8_t {
OnlyReturnFramesWithWidgets = 0x1,
};
static nsIFrame* GetPopupFrameForPoint(
nsPresContext* aRootPresContext, nsIWidget* aWidget,
const mozilla::LayoutDeviceIntPoint& aPoint,
GetPopupFrameForPointFlags aFlags = GetPopupFrameForPointFlags(0));
/**
* Get container and offset if aEvent collapses Selection.
* @param aPresShell The PresShell handling aEvent.
* @param aEvent The event having coordinates where you want to
* collapse Selection.
* @param aContainer Returns the container node at the point.
* Set nullptr if you don't need this.
* @param aOffset Returns offset in the container node at the point.
* Set nullptr if you don't need this.
*/
MOZ_CAN_RUN_SCRIPT
static void GetContainerAndOffsetAtEvent(PresShell* aPresShell,
const mozilla::WidgetEvent* aEvent,
nsIContent** aContainer,
int32_t* aOffset);
/**
* Translate from widget coordinates to the view's coordinates
* @param aPresContext the PresContext for the view
* @param aWidget the widget
* @param aPt the point relative to the widget
* @param aView view to which returned coordinates are relative
* @return the point in the view's coordinates
*/
static nsPoint TranslateWidgetToView(nsPresContext* aPresContext,
nsIWidget* aWidget,
const mozilla::LayoutDeviceIntPoint& aPt,
nsView* aView);
/**
* Translate from view coordinates to the widget's coordinates.
* @param aPresContext the PresContext for the view
* @param aView the view
* @param aPt the point relative to the view
* @param aViewportType whether the point is in visual or layout coordinates
* @param aWidget the widget to which returned coordinates are relative
* @return the point in the view's coordinates
*/
static mozilla::LayoutDeviceIntPoint TranslateViewToWidget(
nsPresContext* aPresContext, nsView* aView, nsPoint aPt,
ViewportType aViewportType, nsIWidget* aWidget);
static mozilla::LayoutDeviceIntPoint WidgetToWidgetOffset(
nsIWidget* aFromWidget, nsIWidget* aToWidget);
enum class FrameForPointOption {
/**
* When set, paint suppression is ignored, so we'll return non-root page
* elements even if paint suppression is stopping them from painting.
*/
IgnorePaintSuppression = 1,
/**
* When set, clipping due to the root scroll frame (and any other viewport-
* related clipping) is ignored.
*/
IgnoreRootScrollFrame,
/**
* When set, return only content in the same document as aFrame.
*/
IgnoreCrossDoc,
/**
* When set, return only content that is actually visible.
*/
OnlyVisible,
};
struct FrameForPointOptions {
using Bits = mozilla::EnumSet<FrameForPointOption>;
Bits mBits;
// If mBits contains OnlyVisible, what is the opacity threshold which we
// consider "opaque enough" to clobber stuff underneath.
float mVisibleThreshold;
FrameForPointOptions(Bits aBits, float aVisibleThreshold)
: mBits(aBits), mVisibleThreshold(aVisibleThreshold) {};
MOZ_IMPLICIT FrameForPointOptions(Bits aBits)
: FrameForPointOptions(aBits, 1.0f) {}
FrameForPointOptions() : FrameForPointOptions(Bits()) {};
};
/**
* Given aFrame, the root frame of a stacking context, find its descendant
* frame under the point aPt that receives a mouse event at that location,
* or nullptr if there is no such frame.
* @param aPt the point, relative to the frame origin, in either visual
* or layout coordinates depending on aRelativeTo.mViewportType
*/
static nsIFrame* GetFrameForPoint(RelativeTo aRelativeTo, nsPoint aPt,
const FrameForPointOptions& = {});
/**
* Given aFrame, the root frame of a stacking context, find all descendant
* frames under the area of a rectangle that receives a mouse event,
* or nullptr if there is no such frame.
* @param aRect the rect, relative to the frame origin, in either visual
* or layout coordinates depending on aRelativeTo.mViewportType
* @param aOutFrames an array to add all the frames found
*/
static nsresult GetFramesForArea(RelativeTo aRelativeTo, const nsRect& aRect,
nsTArray<nsIFrame*>& aOutFrames,
const FrameForPointOptions& = {});
/**
* Transform aRect relative to aFrame up to the coordinate system of
* aAncestor. Computes the bounding-box of the true quadrilateral.
* Pass non-null aPreservesAxisAlignedRectangles and it will be set to true if
* we only need to use a 2d transform that PreservesAxisAlignedRectangles().
* The corner positions of aRect are treated as meaningful even if aRect is
* empty.
*
* |aMatrixCache| allows for optimizations in recomputing the same matrix over
* and over. The argument can be one of the following values:
*
* nullptr (the default) - No optimization; the transform matrix is computed
* on every call to this function.
*
* non-null pointer to an empty Maybe<Matrix4x4> - Upon return, the Maybe is
* filled with the transform matrix that was computed. This can then be passed
* in to subsequent calls with the same source and destination frames to avoid
* recomputing the matrix.
*
* non-null pointer to a non-empty Matrix4x4 - The provided matrix will be
* used as the transform matrix and applied to the rect.
*/
static nsRect TransformFrameRectToAncestor(
const nsIFrame* aFrame, const nsRect& aRect, const nsIFrame* aAncestor,
bool* aPreservesAxisAlignedRectangles = nullptr,
mozilla::Maybe<Matrix4x4Flagged>* aMatrixCache = nullptr,
bool aStopAtStackingContextAndDisplayPortAndOOFFrame = false,
nsIFrame** aOutAncestor = nullptr) {
return TransformFrameRectToAncestor(
aFrame, aRect, RelativeTo{aAncestor}, aPreservesAxisAlignedRectangles,
aMatrixCache, aStopAtStackingContextAndDisplayPortAndOOFFrame,
aOutAncestor);
}
static nsRect TransformFrameRectToAncestor(
const nsIFrame* aFrame, const nsRect& aRect, RelativeTo aAncestor,
bool* aPreservesAxisAlignedRectangles = nullptr,
mozilla::Maybe<Matrix4x4Flagged>* aMatrixCache = nullptr,
bool aStopAtStackingContextAndDisplayPortAndOOFFrame = false,
nsIFrame** aOutAncestor = nullptr);
/**
* Gets the transform for aFrame relative to aAncestor. Pass null for
* aAncestor to go up to the root frame. Including nsIFrame::IN_CSS_UNITS
* flag in aFlags will return CSS pixels, by default it returns device
* pixels.
* More info can be found in nsIFrame::GetTransformMatrix.
*
* Some notes on the possible combinations of |aFrame.mViewportType| and
* |aAncestor.mViewportType|:
*
* | aFrame. | aAncestor. | Notes
* | mViewportType | mViewportType |
* ==========================================================================
* | Layout | Layout | Commonplace, when both source and target
* | | | are inside zoom boundary.
* | | |
* | | | Could also happen in non-e10s setups
* | | | when both source and target are outside
* | | | the zoom boundary and the code is
* | | | oblivious to the existence of a zoom
* | | | boundary.
* ==========================================================================
* | Layout | Visual | Commonplace, used when hit testing visual
* | | | coordinates (e.g. coming from user input
* | | | events). We expected to encounter a
* | | | zoomed content root during traversal and
* | | | apply a layout-to-visual transform.
* ==========================================================================
* | Visual | Layout | Should never happen, will assert.
* ==========================================================================
* | Visual | Visual | In e10s setups, should only happen if
* | | | aFrame and aAncestor are both the
* | | | RCD viewport frame.
* | | |
* | | | In non-e10s setups, could happen with
* | | | different frames if they are both
* | | | outside the zoom boundary.
* ==========================================================================
*/
static Matrix4x4Flagged GetTransformToAncestor(
RelativeTo aFrame, RelativeTo aAncestor, uint32_t aFlags = 0,
nsIFrame** aOutAncestor = nullptr);
/**
* Gets the scale factors of the transform for aFrame relative to the root
* frame if this transform can be drawn 2D, or the identity scale factors
* otherwise.
*/
static MatrixScales GetTransformToAncestorScale(const nsIFrame* aFrame);
/**
* Gets the scale factors of the transform for aFrame relative to the root
* frame if this transform is 2D, or the identity scale factors otherwise.
* If some frame on the path from aFrame to the display root frame may have an
* animated scale, returns the identity scale factors.
*/
static MatrixScales GetTransformToAncestorScaleExcludingAnimated(
nsIFrame* aFrame);
/**
* Gets a scale that includes CSS transforms in this process as well as the
* transform to ancestor scale passed down from our direct ancestor process
* (which includes any enclosing CSS transforms and resolution). Note: this
* does not include any resolution in the current process (this is on purpose
* because that is what the transform to ancestor field on FrameMetrics needs,
* see its definition for explanation as to why). This is the transform to
* ancestor scale to set on FrameMetrics.
*/
static mozilla::ParentLayerToScreenScale2D
GetTransformToAncestorScaleCrossProcessForFrameMetrics(
const nsIFrame* aFrame);
/**
* Find the nearest common ancestor frame for aFrame1 and aFrame2. The
* ancestor frame could be cross-doc.
*/
static const nsIFrame* FindNearestCommonAncestorFrame(
const nsIFrame* aFrame1, const nsIFrame* aFrame2);
/**
* Find the nearest common ancestor frame for aFrame1 and aFrame2, assuming
* that they are within the same block.
*
* Returns null if they are not within the same block.
*/
static const nsIFrame* FindNearestCommonAncestorFrameWithinBlock(
const nsTextFrame* aFrame1, const nsTextFrame* aFrame2);
/**
* Whether author-specified borders / backgrounds disable theming for a given
* appearance value.
*/
static bool AuthorSpecifiedBorderBackgroundDisablesTheming(
mozilla::StyleAppearance);
/**
* Transforms a list of CSSPoints from aFromFrame to aToFrame, taking into
* account all relevant transformations on the frames up to (but excluding)
* their nearest common ancestor.
* If we encounter a transform that we need to invert but which is
* non-invertible, we return NONINVERTIBLE_TRANSFORM. If the frames have
* no common ancestor, we return NO_COMMON_ANCESTOR.
* If this returns TRANSFORM_SUCCEEDED, the points in aPoints are transformed
* in-place, otherwise they are untouched.
*/
enum TransformResult {
TRANSFORM_SUCCEEDED,
NO_COMMON_ANCESTOR,
NONINVERTIBLE_TRANSFORM
};
static TransformResult TransformPoints(RelativeTo aFromFrame,
RelativeTo aToFrame,
uint32_t aPointCount,
CSSPoint* aPoints);
/**
* Same as above function, but transform points in app units and
* handle 1 point per call.
*/
static TransformResult TransformPoint(RelativeTo aFromFrame,
RelativeTo aToFrame, nsPoint& aPoint);
/**
* Transforms a rect from aFromFrame to aToFrame. In app units.
* Returns the bounds of the actual rect if the transform requires rotation
* or anything complex like that.
*/
static TransformResult TransformRect(const nsIFrame* aFromFrame,
const nsIFrame* aToFrame, nsRect& aRect);
/**
* Converts app units to pixels (with optional snapping) and appends as a
* translation to aTransform.
*/
static void PostTranslate(Matrix4x4& aTransform, const nsPoint& aOrigin,
float aAppUnitsPerPixel, bool aRounded);
/*
* Whether the frame should snap to grid. This will end up being passed
* as the aRounded parameter in PostTranslate above. SVG frames should
* not have their translation rounded.
*/
static bool ShouldSnapToGrid(const nsIFrame* aFrame);
/**
* Get the border-box of aElement's primary frame, transformed it to be
* relative to aFrame.
*/
static nsRect GetRectRelativeToFrame(mozilla::dom::Element* aElement,
nsIFrame* aFrame);
/**
* Returns true if aRect with border inflation of size aInflateSize contains
* aPoint.
*/
static bool ContainsPoint(const nsRect& aRect, const nsPoint& aPoint,
nscoord aInflateSize);
/**
* Clamp aRect relative to aFrame to the scroll frames boundary searching from
* aFrame.
*/
static nsRect ClampRectToScrollFrames(nsIFrame* aFrame, const nsRect& aRect);
/**
* 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);
static nsPoint TransformFramePointToRoot(ViewportType aToType,
RelativeTo aFromFrame,
const nsPoint& aPoint);
/**
* Helper function that, given a rectangle and a matrix, returns the smallest
* rectangle containing the image of the source rectangle.
*
* @param aBounds The rectangle to transform.
* @param aMatrix The matrix to transform it with.
* @param aFactor The number of app units per graphics unit.
* @return The smallest rect that contains the image of aBounds.
*/
static nsRect MatrixTransformRect(const nsRect& aBounds,
const Matrix4x4& aMatrix, float aFactor);
static nsRect MatrixTransformRect(const nsRect& aBounds,
const Matrix4x4Flagged& aMatrix,
float aFactor);
/**
* Helper function that, given a point and a matrix, returns the image
* of that point under the matrix transform.
*
* @param aPoint The point to transform.
* @param aMatrix The matrix to transform it with.
* @param aFactor The number of app units per graphics unit.
* @return The image of the point under the transform.
*/
static nsPoint MatrixTransformPoint(const nsPoint& aPoint,
const Matrix4x4& aMatrix, float aFactor);
/**
* Given a graphics rectangle in graphics space, return a rectangle in
* app space that contains the graphics rectangle, rounding out as necessary.
*
* @param aRect The graphics rect to round outward.
* @param aFactor The number of app units per graphics unit.
* @return The smallest rectangle in app space that contains aRect.
*/
template <typename T>
static nsRect RoundGfxRectToAppRect(const T& aRect, const float aFactor);
/**
* Returns a subrectangle of aContainedRect that is entirely inside the
* rounded rect. Complex cases are handled conservatively by returning a
* smaller rect than necessary.
*/
static nsRegion RoundedRectIntersectRect(const nsRect& aRoundedRect,
const nscoord aRadii[8],
const nsRect& aContainedRect);
static nsIntRegion RoundedRectIntersectIntRect(
const nsIntRect& aRoundedRect, const RectCornerRadii& aCornerRadii,
const nsIntRect& aContainedRect);
/**
* Return whether any part of aTestRect is inside of the rounded
* rectangle formed by aBounds and aRadii (which are indexed by the
* enum HalfCorner constants in gfx/2d/Types.h). This is precise.
*/
static bool RoundedRectIntersectsRect(const nsRect& aRoundedRect,
const nscoord aRadii[8],
const nsRect& aTestRect);
enum class PaintFrameFlags : uint32_t {
InTransform = 0x01,
SyncDecodeImages = 0x02,
WidgetLayers = 0x04,
IgnoreSuppression = 0x08,
DocumentRelative = 0x10,
HideCaret = 0x20,
ToWindow = 0x40,
ExistingTransaction = 0x80,
ForWebRender = 0x100,
UseHighQualityScaling = 0x200,
ResetViewportScrolling = 0x400,
};
/**
* Given aFrame, the root frame of a stacking context, paint it and its
* descendants to aRenderingContext.
* @param aRenderingContext a rendering context translated so that (0,0)
* is the origin of aFrame; for best results, (0,0) should transform
* to pixel-aligned coordinates. This can be null, in which case
* aFrame must be a "display root" (root frame for a root document,
* or the root of a popup) with an associated widget and we draw using
* the layer manager for the frame's widget.
* @param aDirtyRegion the region that must be painted, in the coordinates
* of aFrame.
* @param aBackstop paint the dirty area with this color before drawing
* the actual content; pass NS_RGBA(0,0,0,0) to draw no background.
* @param aBuilderMode Passed through to the display-list builder.
* @param aFlags if PAINT_IN_TRANSFORM is set, then we assume
* this is inside a transform or SVG foreignObject. If
* PAINT_SYNC_DECODE_IMAGES is set, we force synchronous decode on all
* images. If PAINT_WIDGET_LAYERS is set, aFrame must be a display root,
* and we will use the frame's widget's layer manager to paint
* even if aRenderingContext is non-null. This is useful if you want
* to force rendering to use the widget's layer manager for testing
* or speed. PAINT_WIDGET_LAYERS must be set if aRenderingContext is null.
* If PAINT_DOCUMENT_RELATIVE is used, the visible region is interpreted
* as being relative to the document (normally it's relative to the CSS
* viewport) and the document is painted as if no scrolling has occured.
* Only considered if PresShell::IgnoringViewportScrolling is true.
* If ResetViewportScrolling is used, then the root scroll frame's scroll
* position is set to 0 during painting, so that position:fixed elements
* are drawn in their initial position.
* PAINT_TO_WINDOW sets painting to window to true on the display list
* builder even if we can't tell that we are painting to the window.
* If PAINT_EXISTING_TRANSACTION is set, then BeginTransaction() has already
* been called on aFrame's widget's layer manager and should not be
* called again.
* If PAINT_COMPRESSED is set, the FrameLayerBuilder should be set to
* compressed mode to avoid short cut optimizations.
*
* So there are three possible behaviours:
* 1) PAINT_WIDGET_LAYERS is set and aRenderingContext is null; we paint
* by calling BeginTransaction on the widget's layer manager.
* 2) PAINT_WIDGET_LAYERS is set and aRenderingContext is non-null; we
* paint by calling BeginTransactionWithTarget on the widget's layer
* manager.
* 3) PAINT_WIDGET_LAYERS is not set and aRenderingContext is non-null;
* we paint by construct a BasicLayerManager and calling
* BeginTransactionWithTarget on it. This is desirable if we're doing
* something like drawWindow in a mode where what gets rendered doesn't
* necessarily correspond to what's visible in the window; we don't
* want to mess up the widget's layer tree.
*/
static void PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
const nsRegion& aDirtyRegion, nscolor aBackstop,
nsDisplayListBuilderMode aBuilderMode,
PaintFrameFlags aFlags = PaintFrameFlags(0));
/**
* Uses a binary search for find where the cursor falls in the line of text
* It also keeps track of the part of the string that has already been
* measured so it doesn't have to keep measuring the same text over and over.
*
* @param "aBaseWidth" contains the width in twips of the portion
* of the text that has already been measured, and aBaseInx contains
* the index of the text that has already been measured.
*
* @param aTextWidth returns (in twips) the length of the text that falls
* before the cursor aIndex contains the index of the text where the cursor
* falls.
*/
static bool BinarySearchForPosition(DrawTarget* aDrawTarget,
nsFontMetrics& aFontMetrics,
const char16_t* aText, int32_t aBaseWidth,
int32_t aBaseInx, int32_t aStartInx,
int32_t aEndInx, int32_t aCursorPos,
int32_t& aIndex, int32_t& aTextWidth);
class BoxCallback {
public:
BoxCallback() = default;
virtual void AddBox(nsIFrame* aFrame) = 0;
bool mIncludeCaptionBoxForTable = true;
// Whether we are in a continuation or ib-split-sibling of the target we're
// measuring. This is useful because if we know we're in the target subtree
// and measuring against it we can avoid finding the common ancestor.
bool mInTargetContinuation = false;
};
/**
* Collect all CSS boxes associated with aFrame and its
* continuations, "drilling down" through table wrapper frames and
* some anonymous blocks since they're not real CSS boxes.
* If aFrame is null, no boxes are returned.
* SVG frames return a single box, themselves.
*/
static void GetAllInFlowBoxes(nsIFrame* aFrame, BoxCallback* aCallback);
/**
* Like GetAllInFlowBoxes, but doesn't include continuations.
*/
static void AddBoxesForFrame(nsIFrame* aFrame, BoxCallback* aCallback);
/**
* Find the first frame descendant of aFrame (including aFrame) which is
* not an anonymous frame that getBoxQuads/getClientRects should ignore.
*/
static nsIFrame* GetFirstNonAnonymousFrame(nsIFrame* aFrame);
struct RectAccumulator : public mozilla::RectCallback {
nsRect mResultRect;
nsRect mFirstRect;
bool mSeenFirstRect;
RectAccumulator();
virtual void AddRect(const nsRect& aRect) override;
};
struct RectListBuilder : public mozilla::RectCallback {
DOMRectList* mRectList;
explicit RectListBuilder(DOMRectList* aList);
virtual void AddRect(const nsRect& aRect) override;
};
static nsIFrame* GetContainingBlockForClientRect(nsIFrame* aFrame);
/**
* 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 'AccountForTransforms', then when converting the boxes
* into aRelativeTo coordinates, transforms (including CSS and SVG transforms)
* are taken into account.
*
* If aFlags includes one of 'UseContentBox', 'UsePaddingBox', 'UseMarginBox',
* or 'UseMarginBoxWithAutoResolvedAsZero', the corresponding type of box is
* used. Otherwise (by default), the border box is used. Note that these "Box"
* flags are meant to be mutually exclusive, though we don't enforce that. If
* multiple "Box" flags are used, we'll gracefully just use the first one in
* the order of the enum.
*/
enum class GetAllInFlowRectsFlag : uint8_t {
AccountForTransforms,
UseContentBox,
UsePaddingBox,
UseMarginBox,
// Similar to UseMarginBox, but the 'auto' margins are resolved as zero.
UseMarginBoxWithAutoResolvedAsZero,
};
using GetAllInFlowRectsFlags = mozilla::EnumSet<GetAllInFlowRectsFlag>;
static void GetAllInFlowRects(nsIFrame* aFrame, const nsIFrame* aRelativeTo,
mozilla::RectCallback* aCallback,
GetAllInFlowRectsFlags aFlags = {});
static void GetAllInFlowRectsAndTexts(
nsIFrame* aFrame, const nsIFrame* aRelativeTo,
mozilla::RectCallback* aCallback,
mozilla::dom::Sequence<nsString>* aTextList,
GetAllInFlowRectsFlags aFlags = {});
/**
* Computes the union of all rects returned by GetAllInFlowRects. If
* the union is empty, returns the first rect.
*
* See GetAllInFlowRects() documentation for the meaning of aRelativeTo and
* aFlags.
*/
static nsRect GetAllInFlowRectsUnion(nsIFrame* aFrame,
const nsIFrame* aRelativeTo,
GetAllInFlowRectsFlags aFlags = {});
enum { EXCLUDE_BLUR_SHADOWS = 0x01 };
/**
* Takes a text-shadow array from the style properties of a given nsIFrame and
* computes the union of those shadows along with the given initial rect.
* If there are no shadows, the initial rect is returned.
*/
static nsRect GetTextShadowRectsUnion(const nsRect& aTextAndDecorationsRect,
nsIFrame* aFrame, uint32_t aFlags = 0);
/**
* Computes the destination rect that a given replaced element should render
* into, based on its CSS 'object-fit' and 'object-position' properties.
*
* @param aConstraintRect The constraint rect that we have at our disposal,
* which would e.g. be exactly filled by the image
* if we had "object-fit: fill".
* @param aIntrinsicSize The replaced content's intrinsic size, as reported
* by nsIFrame::GetIntrinsicSize().
* @param aIntrinsicRatio The replaced content's intrinsic ratio, as reported
* by nsIFrame::GetIntrinsicRatio().
* @param aStylePos The nsStylePosition struct that contains the 'object-fit'
* and 'object-position' values that we should rely on.
* (This should usually be the nsStylePosition for the
* replaced element in question, but not always. For
* example, a <video>'s poster-image has a dedicated
* anonymous element & child-frame, but we should still use
* the <video>'s 'object-fit' and 'object-position' values.)
* @param aAnchorPoint [out] A point that should be pixel-aligned by functions
* like nsLayoutUtils::DrawImage. See documentation
* in nsCSSRendering.h for ComputeObjectAnchorPoint.
* @return The nsRect into which we should render the replaced content (using
* the same coordinate space as the passed-in aConstraintRect).
*/
static nsRect ComputeObjectDestRect(const nsRect& aConstraintRect,
const IntrinsicSize& aIntrinsicSize,
const AspectRatio& aIntrinsicRatio,
const nsStylePosition* aStylePos,
nsPoint* aAnchorPoint = nullptr);
/**
* Get the font metrics corresponding to the frame's style data.
* @param aFrame the frame
* @param aSizeInflation number to multiply font size by
*/
static already_AddRefed<nsFontMetrics> GetFontMetricsForFrame(
const nsIFrame* aFrame, float aSizeInflation);
static already_AddRefed<nsFontMetrics> GetInflatedFontMetricsForFrame(
const nsIFrame* aFrame) {
return GetFontMetricsForFrame(aFrame, FontSizeInflationFor(aFrame));
}
/**
* Get the font metrics corresponding to the given style data.
* @param aComputedStyle the style data
* @param aSizeInflation number to multiply font size by
*/
static already_AddRefed<nsFontMetrics> GetFontMetricsForComputedStyle(
const ComputedStyle* aComputedStyle, nsPresContext* aPresContext,
float aSizeInflation = 1.0f,
uint8_t aVariantWidth = NS_FONT_VARIANT_WIDTH_NORMAL);
/**
* Get the font metrics of emphasis marks corresponding to the given
* style data. The result is same as GetFontMetricsForComputedStyle
* except that the font size is scaled down to 50%.
* @param aComputedStyle the style data
* @param aInflation number to multiple font size by
*/
static already_AddRefed<nsFontMetrics> GetFontMetricsOfEmphasisMarks(
ComputedStyle* aComputedStyle, nsPresContext* aPresContext,
float aInflation) {
return GetFontMetricsForComputedStyle(aComputedStyle, aPresContext,
aInflation * 0.5f);
}
/**
* Find the immediate child of aParent whose frame subtree contains
* aDescendantFrame. Returns null if aDescendantFrame is not a descendant
* of aParent.
*/
static nsIFrame* FindChildContainingDescendant(nsIFrame* aParent,
nsIFrame* aDescendantFrame);
/**
* Find the nearest ancestor that's a block
*/
static nsBlockFrame* FindNearestBlockAncestor(nsIFrame* aFrame);
/**
* Find the nearest ancestor that's not for generated content. Will return
* aFrame if aFrame is not for generated content.
*/
static nsIFrame* GetNonGeneratedAncestor(nsIFrame* aFrame);
/*
* Whether the frame is an nsBlockFrame which is not a wrapper block.
*/
static bool IsNonWrapperBlock(nsIFrame* aFrame);
/**
* If aFrame is an out of flow frame, return its placeholder, otherwise
* return its parent.
*/
static nsIFrame* GetParentOrPlaceholderFor(const nsIFrame* aFrame);
/**
* If aFrame is an out of flow frame, return its placeholder, otherwise
* return its (possibly cross-doc) parent.
*/
static nsIFrame* GetParentOrPlaceholderForCrossDoc(const nsIFrame* aFrame);
/**
* Returns the frame that would act as the parent of aFrame when
* descending through the frame tree in display list building.
* Usually the same as GetParentOrPlaceholderForCrossDoc, except
* that pushed floats are treated as children of their containing
* block.
*/
static nsIFrame* GetDisplayListParent(nsIFrame* aFrame);
/**
* Get a frame's previous continuation, or, if it doesn't have one, its
* previous block-in-inline-split sibling.
*/
static nsIFrame* GetPrevContinuationOrIBSplitSibling(const nsIFrame* aFrame);
/**
* Get a frame's next continuation, or, if it doesn't have one, its
* block-in-inline-split sibling.
*/
static nsIFrame* GetNextContinuationOrIBSplitSibling(const nsIFrame* aFrame);
/**
* Get the first frame in the continuation-plus-ib-split-sibling chain
* containing aFrame.
*/
static nsIFrame* FirstContinuationOrIBSplitSibling(const nsIFrame* aFrame);
/**
* Get the last frame in the continuation-plus-ib-split-sibling chain
* containing aFrame.
*/
static nsIFrame* LastContinuationOrIBSplitSibling(const nsIFrame* aFrame);
/**
* Is FirstContinuationOrIBSplitSibling(aFrame) going to return
* aFrame?
*/
static bool IsFirstContinuationOrIBSplitSibling(const nsIFrame* aFrame);
/**
* Check whether aFrame is a part of the scrollbar or scrollcorner of
* the root content.
* @param aFrame the checking frame.
* @return true if the frame is a part of the scrollbar or scrollcorner of
* the root content.
*/
static bool IsViewportScrollbarFrame(nsIFrame* aFrame);
/**
* Get the contribution of aFrame to its containing block's intrinsic
* size for the given physical axis. This considers the child's intrinsic
* width, its 'width', 'min-width', and 'max-width' properties (or 'height'
* variations if that's what matches aAxis) and its padding, border and margin
* in the corresponding dimension.
* @param aPercentageBasis an optional percentage basis (in aFrame's WM).
* If the basis is indefinite in a given axis, pass a size with
* NS_UNCONSTRAINEDSIZE in that component.
* If you pass Nothing() a percentage basis will be calculated from aFrame's
* ancestors' computed size in the relevant axis, if needed.
* @param aMarginBoxMinSizeClamp make the result fit within this margin-box
* size by reducing the *content size* (flooring at zero). This is used for:
* @param aSizeOverrides optional override values for size properties, which
* this function will use internally instead of the actual property values.
*/
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,
const mozilla::StyleSizeOverrides& aSizeOverrides = {});
/**
* Calls IntrinsicForAxis with aFrame's parent's inline physical axis.
*/
static nscoord IntrinsicForContainer(
gfxContext* aRenderingContext, nsIFrame* aFrame,
mozilla::IntrinsicISizeType aType,
const mozilla::Maybe<LogicalSize>& aPercentageBasis = mozilla::Nothing(),
uint32_t aFlags = 0,
const mozilla::StyleSizeOverrides& aSizeOverrides = {});
/**
* 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:
* 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_ASSERTION(aPercentBasis != NS_UNCONSTRAINEDSIZE || !aCoord.HasPercent(),
"Have unconstrained percentage basis when percentage "
"resolution needed; 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 ComputeCBDependentValue(nscoord aPercentBasis,
const mozilla::StyleInset& aInset) {
if (!aInset.IsLengthPercentage()) {
// Callers are assumed to have handled other cases already.
return 0;
}
return ComputeCBDependentValue(aPercentBasis, aInset.AsLengthPercentage());
}
static nscoord ComputeCBDependentValue(nscoord aPercentBasis,
const mozilla::StyleMargin& aMargin) {
if (!aMargin.IsLengthPercentage()) {
return 0;
}
return ComputeCBDependentValue(aPercentBasis, aMargin.AsLengthPercentage());
}
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);
}
// Wrapper for ComputeBSizeValue that also handles 'stretch':
template <typename SizeOrMaxSize>
static nscoord ComputeBSizeValueHandlingStretch(
nscoord aContainingBlockBSize, nscoord aMargin, nscoord aBorderPadding,
nscoord aContentEdgeToBoxSizingBoxEdge, const SizeOrMaxSize& aSize) {
if (aSize.BehavesLikeStretchOnBlockAxis()) {
// Note: we don't need to worry about accounting for "box-sizing" when
// resolving 'stretch' here. This function unconditionally returns a
// content-box size, and the content-box size of a stretched element is
// the same regardless of whether whether the author is conceptually
// asking us to stretch the content box vs. the border-box.
return ComputeStretchContentBoxBSize(aContainingBlockBSize, aMargin,
aBorderPadding);
}
return ComputeBSizeValue(aContainingBlockBSize,
aContentEdgeToBoxSizingBoxEdge,
aSize.AsLengthPercentage());
}
/**
* Returns the size that an element's box should take on, in order for its
* margin-box to exactly reach a particular larger size (e.g. to fill its
* containing block in a particular axis). The box in question can be either
* the content-box or the border-box, determined by the aBoxSizing param.
*
* This function can be used to resolve the "stretch" size for the child box,
*
* The returned value is floored at 0.
*
* There's a version for ISize and BSize; the only difference is that the
* BSize version has an assertion to be sure that we're not inadvertently
* doing arithmetic with the NS_UNCONSTRAINEDSIZE sentinel value in that
* axis. (This sentinel has special meaning as a block-axis size but not as
* an inline-axis size; hence, the assertion only makes sense for block-axis
* sizes.)
*
* TODO(dholbert): Maybe do minor refactors to use this where we resolve
* 'stretch' alignment in various places, if that feels useful?
*
* @param aSizeToFill
* The size that the child's margin-box should fill, in the axis in
* question -- e.g. the containing block size. Assumed to be a constrained
* size; this function doesn't have any special treatment to handle the
* case where this is unconstrained.
*
* @param aMargin
* The sum of the child box's margins in the axis in question (using zero
* for any margins that should be ignored in computing the 'stretch' size;
* see bug 1932993 for one special case where this should happen).
*
* @param aBorderPadding
* The sum of the child box's border and padding in the axis in question.
*
* @param aBoxSizing
* The StyleBoxSizing enum that represents the box that the caller wants to
* resolve a size for. NOTE: it may or may not be appropriate to actually
* pass the true specified 'box-sizing' value for this param; it depends on
* what box the caller is trying to actually resolve. In many cases, we
* internally work with variables that unconditionally represent a
* content-box size, regardless of the 'box-sizing' value; and for those
* cases, it would be appropriate to unconditionally pass
* StyleBoxSizing::Content to this function, or to just use the
* convenience-wrapper that has "ContentBox" in the function name.
*/
static inline nscoord ComputeStretchBSize(
nscoord aSizeToFill, nscoord aMargin, nscoord aBorderPadding,
mozilla::StyleBoxSizing aBoxSizing) {