summaryrefslogtreecommitdiffstats
path: root/layout/generic/nsIFrame.h
diff options
context:
space:
mode:
Diffstat (limited to 'layout/generic/nsIFrame.h')
-rw-r--r--layout/generic/nsIFrame.h4021
1 files changed, 4021 insertions, 0 deletions
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
new file mode 100644
index 000000000..50eb958e0
--- /dev/null
+++ b/layout/generic/nsIFrame.h
@@ -0,0 +1,4021 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* 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/. */
+
+/* interface for all rendering objects */
+
+#ifndef nsIFrame_h___
+#define nsIFrame_h___
+
+#ifndef MOZILLA_INTERNAL_API
+#error This header/class should only be used within Mozilla code. It should not be used by extensions.
+#endif
+
+#define MAX_REFLOW_DEPTH 200
+
+/* nsIFrame is in the process of being deCOMtaminated, i.e., this file is eventually
+ going to be eliminated, and all callers will use nsFrame instead. At the moment
+ we're midway through this process, so you will see inlined functions and member
+ variables in this file. -dwh */
+
+#include <algorithm>
+#include <stdio.h>
+
+#include "CaretAssociationHint.h"
+#include "FramePropertyTable.h"
+#include "mozilla/layout/FrameChildList.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/WritingModes.h"
+#include "nsDirection.h"
+#include "nsFrameList.h"
+#include "nsFrameState.h"
+#include "mozilla/ReflowOutput.h"
+#include "nsITheme.h"
+#include "nsLayoutUtils.h"
+#include "nsQueryFrame.h"
+#include "nsStringGlue.h"
+#include "nsStyleContext.h"
+#include "nsStyleStruct.h"
+#include "Visibility.h"
+
+#ifdef ACCESSIBILITY
+#include "mozilla/a11y/AccTypes.h"
+#endif
+
+/**
+ * New rules of reflow:
+ * 1. you get a WillReflow() followed by a Reflow() followed by a DidReflow() in order
+ * (no separate pass over the tree)
+ * 2. it's the parent frame's responsibility to size/position the child's view (not
+ * the child frame's responsibility as it is today) during reflow (and before
+ * sending the DidReflow() notification)
+ * 3. positioning of child frames (and their views) is done on the way down the tree,
+ * and sizing of child frames (and their views) on the way back up
+ * 4. if you move a frame (outside of the reflow process, or after reflowing it),
+ * then you must make sure that its view (or its child frame's views) are re-positioned
+ * as well. It's reasonable to not position the view until after all reflowing the
+ * entire line, for example, but the frame should still be positioned and sized (and
+ * the view sized) during the reflow (i.e., before sending the DidReflow() notification)
+ * 5. the view system handles moving of widgets, i.e., it's not our problem
+ */
+
+class nsIAtom;
+class nsPresContext;
+class nsIPresShell;
+class nsRenderingContext;
+class nsView;
+class nsIWidget;
+class nsISelectionController;
+class nsBoxLayoutState;
+class nsBoxLayout;
+class nsILineIterator;
+class nsDisplayListBuilder;
+class nsDisplayListSet;
+class nsDisplayList;
+class gfxSkipChars;
+class gfxSkipCharsIterator;
+class gfxContext;
+class nsLineList_iterator;
+class nsAbsoluteContainingBlock;
+class nsIContent;
+class nsContainerFrame;
+
+struct nsPeekOffsetStruct;
+struct nsPoint;
+struct nsRect;
+struct nsSize;
+struct nsMargin;
+struct CharacterDataChangeInfo;
+
+namespace mozilla {
+
+enum class CSSPseudoElementType : uint8_t;
+class EventStates;
+struct ReflowInput;
+class ReflowOutput;
+
+namespace layers {
+class Layer;
+} // namespace layers
+
+namespace gfx {
+class Matrix;
+} // namespace gfx
+} // namespace mozilla
+
+/**
+ * Indication of how the frame can be split. This is used when doing runaround
+ * of floats, and when pulling up child frames from a next-in-flow.
+ *
+ * The choices are splittable, not splittable at all, and splittable in
+ * a non-rectangular fashion. This last type only applies to block-level
+ * elements, and indicates whether splitting can be used when doing runaround.
+ * If you can split across page boundaries, but you expect each continuing
+ * frame to be the same width then return frSplittable and not
+ * frSplittableNonRectangular.
+ *
+ * @see #GetSplittableType()
+ */
+typedef uint32_t nsSplittableType;
+
+#define NS_FRAME_NOT_SPLITTABLE 0 // Note: not a bit!
+#define NS_FRAME_SPLITTABLE 0x1
+#define NS_FRAME_SPLITTABLE_NON_RECTANGULAR 0x3
+
+#define NS_FRAME_IS_SPLITTABLE(type)\
+ (0 != ((type) & NS_FRAME_SPLITTABLE))
+
+#define NS_FRAME_IS_NOT_SPLITTABLE(type)\
+ (0 == ((type) & NS_FRAME_SPLITTABLE))
+
+#define NS_INTRINSIC_WIDTH_UNKNOWN nscoord_MIN
+
+//----------------------------------------------------------------------
+
+#define NS_SUBTREE_DIRTY(_frame) \
+ (((_frame)->GetStateBits() & \
+ (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0)
+
+/**
+ * Constant used to indicate an unconstrained size.
+ *
+ * @see #Reflow()
+ */
+#define NS_UNCONSTRAINEDSIZE NS_MAXSIZE
+
+#define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE
+#define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE
+// +1 is to avoid clamped huge margin values being processed as auto margins
+#define NS_AUTOMARGIN (NS_UNCONSTRAINEDSIZE + 1)
+#define NS_AUTOOFFSET NS_UNCONSTRAINEDSIZE
+// NOTE: there are assumptions all over that these have the same value, namely NS_UNCONSTRAINEDSIZE
+// if any are changed to be a value other than NS_UNCONSTRAINEDSIZE
+// at least update AdjustComputedHeight/Width and test ad nauseum
+
+// 1 million CSS pixels less than our max app unit measure.
+// For reflowing with an "infinite" available inline space per [css-sizing].
+// (reflowing with an NS_UNCONSTRAINEDSIZE available inline size isn't allowed
+// and leads to assertions)
+#define INFINITE_ISIZE_COORD nscoord(NS_MAXSIZE - (1000000*60))
+
+//----------------------------------------------------------------------
+
+enum nsSelectionAmount {
+ eSelectCharacter = 0, // a single Unicode character;
+ // do not use this (prefer Cluster) unless you
+ // are really sure it's what you want
+ eSelectCluster = 1, // a grapheme cluster: this is usually the right
+ // choice for movement or selection by "character"
+ // as perceived by the user
+ eSelectWord = 2,
+ eSelectWordNoSpace = 3, // select a "word" without selecting the following
+ // space, no matter what the default platform
+ // behavior is
+ eSelectLine = 4, // previous drawn line in flow.
+ // NOTE that selection code depends on the ordering of the above values,
+ // allowing simple <= tests to check categories of caret movement.
+ // Don't rearrange without checking the usage in nsSelection.cpp!
+
+ eSelectBeginLine = 5,
+ eSelectEndLine = 6,
+ eSelectNoAmount = 7, // just bounce back current offset.
+ eSelectParagraph = 8 // select a "paragraph"
+};
+
+enum nsSpread {
+ eSpreadNone = 0,
+ eSpreadAcross = 1,
+ eSpreadDown = 2
+};
+
+// Carried out margin flags
+#define NS_CARRIED_TOP_MARGIN_IS_AUTO 0x1
+#define NS_CARRIED_BOTTOM_MARGIN_IS_AUTO 0x2
+
+//----------------------------------------------------------------------
+
+/**
+ * Reflow status returned by the reflow methods. There are three
+ * completion statuses, represented by two bit flags.
+ *
+ * NS_FRAME_COMPLETE means the frame is fully complete.
+ *
+ * NS_FRAME_NOT_COMPLETE bit flag means the frame does not map all its
+ * content, and that the parent frame should create a continuing frame.
+ * If this bit isn't set it means the frame does map all its content.
+ * This bit is mutually exclusive with NS_FRAME_OVERFLOW_INCOMPLETE.
+ *
+ * NS_FRAME_OVERFLOW_INCOMPLETE bit flag means that the frame has
+ * overflow that is not complete, but its own box is complete.
+ * (This happens when content overflows a fixed-height box.)
+ * The reflower should place and size the frame and continue its reflow,
+ * but needs to create an overflow container as a continuation for this
+ * frame. See nsContainerFrame.h for more information.
+ * This bit is mutually exclusive with NS_FRAME_NOT_COMPLETE.
+ *
+ * Please use the SET macro for handling
+ * NS_FRAME_NOT_COMPLETE and NS_FRAME_OVERFLOW_INCOMPLETE.
+ *
+ * NS_FRAME_REFLOW_NEXTINFLOW bit flag means that the next-in-flow is
+ * dirty, and also needs to be reflowed. This status only makes sense
+ * for a frame that is not complete, i.e. you wouldn't set both
+ * NS_FRAME_COMPLETE and NS_FRAME_REFLOW_NEXTINFLOW.
+ *
+ * The low 8 bits of the nsReflowStatus are reserved for future extensions;
+ * the remaining 24 bits are zero (and available for extensions; however
+ * API's that accept/return nsReflowStatus must not receive/return any
+ * extension bits).
+ *
+ * @see #Reflow()
+ */
+typedef uint32_t nsReflowStatus;
+
+#define NS_FRAME_COMPLETE 0 // Note: not a bit!
+#define NS_FRAME_NOT_COMPLETE 0x1
+#define NS_FRAME_REFLOW_NEXTINFLOW 0x2
+#define NS_FRAME_OVERFLOW_INCOMPLETE 0x4
+
+#define NS_FRAME_IS_COMPLETE(status) \
+ (0 == ((status) & NS_FRAME_NOT_COMPLETE))
+
+#define NS_FRAME_IS_NOT_COMPLETE(status) \
+ (0 != ((status) & NS_FRAME_NOT_COMPLETE))
+
+#define NS_FRAME_OVERFLOW_IS_INCOMPLETE(status) \
+ (0 != ((status) & NS_FRAME_OVERFLOW_INCOMPLETE))
+
+#define NS_FRAME_IS_FULLY_COMPLETE(status) \
+ (NS_FRAME_IS_COMPLETE(status) && !NS_FRAME_OVERFLOW_IS_INCOMPLETE(status))
+
+// These macros set or switch incomplete statuses without touching the
+// NS_FRAME_REFLOW_NEXTINFLOW bit.
+#define NS_FRAME_SET_INCOMPLETE(status) \
+ status = (status & ~NS_FRAME_OVERFLOW_INCOMPLETE) | NS_FRAME_NOT_COMPLETE
+
+#define NS_FRAME_SET_OVERFLOW_INCOMPLETE(status) \
+ status = (status & ~NS_FRAME_NOT_COMPLETE) | NS_FRAME_OVERFLOW_INCOMPLETE
+
+// This bit is set, when a break is requested. This bit is orthogonal
+// to the nsIFrame::nsReflowStatus completion bits.
+#define NS_INLINE_BREAK 0x0100
+
+// When a break is requested, this bit when set indicates that the
+// break should occur after the frame just reflowed; when the bit is
+// clear the break should occur before the frame just reflowed.
+#define NS_INLINE_BREAK_BEFORE 0x0000
+#define NS_INLINE_BREAK_AFTER 0x0200
+
+// The type of break requested can be found in these bits.
+#define NS_INLINE_BREAK_TYPE_MASK 0xF000
+
+// Set when a break was induced by completion of a first-letter
+#define NS_INLINE_BREAK_FIRST_LETTER_COMPLETE 0x10000
+
+//----------------------------------------
+// Macros that use those bits
+
+#define NS_INLINE_IS_BREAK(_status) \
+ (0 != ((_status) & NS_INLINE_BREAK))
+
+#define NS_INLINE_IS_BREAK_AFTER(_status) \
+ (0 != ((_status) & NS_INLINE_BREAK_AFTER))
+
+#define NS_INLINE_IS_BREAK_BEFORE(_status) \
+ (NS_INLINE_BREAK == ((_status) & (NS_INLINE_BREAK|NS_INLINE_BREAK_AFTER)))
+
+#define NS_INLINE_GET_BREAK_TYPE(_status) \
+ (static_cast<StyleClear>(((_status) >> 12) & 0xF))
+
+#define NS_INLINE_MAKE_BREAK_TYPE(_type) (static_cast<int>(_type) << 12)
+
+// Construct a line-break-before status. Note that there is no
+// completion status for a line-break before because we *know* that
+// the frame will be reflowed later and hence its current completion
+// status doesn't matter.
+#define NS_INLINE_LINE_BREAK_BEFORE() \
+ (NS_INLINE_BREAK | NS_INLINE_BREAK_BEFORE | \
+ NS_INLINE_MAKE_BREAK_TYPE(StyleClear::Line))
+
+// Take a completion status and add to it the desire to have a
+// line-break after. For this macro we do need the completion status
+// because the user of the status will need to know whether to
+// continue the frame or not.
+#define NS_INLINE_LINE_BREAK_AFTER(_completionStatus) \
+ ((_completionStatus) | NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER | \
+ NS_INLINE_MAKE_BREAK_TYPE(StyleClear::Line))
+
+// A frame is "truncated" if the part of the frame before the first
+// possible break point was unable to fit in the available vertical
+// space. Therefore, the entire frame should be moved to the next page.
+// A frame that begins at the top of the page must never be "truncated".
+// Doing so would likely cause an infinite loop.
+#define NS_FRAME_TRUNCATED 0x0010
+#define NS_FRAME_IS_TRUNCATED(status) \
+ (0 != ((status) & NS_FRAME_TRUNCATED))
+#define NS_FRAME_SET_TRUNCATION(status, aReflowInput, aMetrics) \
+ aReflowInput.SetTruncated(aMetrics, &status);
+
+// Merge the incompleteness, truncation and NS_FRAME_REFLOW_NEXTINFLOW
+// status from aSecondary into aPrimary.
+void NS_MergeReflowStatusInto(nsReflowStatus* aPrimary,
+ nsReflowStatus aSecondary);
+
+//----------------------------------------------------------------------
+
+/**
+ * DidReflow status values.
+ */
+enum class nsDidReflowStatus : uint32_t {
+ NOT_FINISHED,
+ FINISHED
+};
+
+/**
+ * When there is no scrollable overflow rect, the visual overflow rect
+ * may be stored as four 1-byte deltas each strictly LESS THAN 0xff, for
+ * the four edges of the rectangle, or the four bytes may be read as a
+ * single 32-bit "overflow-rect type" value including at least one 0xff
+ * byte as an indicator that the value does NOT represent four deltas.
+ * If all four deltas are zero, this means that no overflow rect has
+ * actually been set (this is the initial state of newly-created frames).
+ */
+#define NS_FRAME_OVERFLOW_DELTA_MAX 0xfe // max delta we can store
+
+#define NS_FRAME_OVERFLOW_NONE 0x00000000 // there are no overflow rects;
+ // code relies on this being
+ // the all-zero value
+
+#define NS_FRAME_OVERFLOW_LARGE 0x000000ff // overflow is stored as a
+ // separate rect property
+
+/**
+ * nsBidiLevel is the type of the level values in our Unicode Bidi
+ * implementation.
+ * It holds an embedding level and indicates the visual direction
+ * by its bit 0 (even/odd value).<p>
+ *
+ * <li><code>aParaLevel</code> can be set to the
+ * pseudo-level values <code>NSBIDI_DEFAULT_LTR</code>
+ * and <code>NSBIDI_DEFAULT_RTL</code>.</li></ul>
+ *
+ * @see nsBidi::SetPara
+ *
+ * <p>The related constants are not real, valid level values.
+ * <code>NSBIDI_DEFAULT_XXX</code> can be used to specify
+ * a default for the paragraph level for
+ * when the <code>SetPara</code> function
+ * shall determine it but there is no
+ * strongly typed character in the input.<p>
+ *
+ * Note that the value for <code>NSBIDI_DEFAULT_LTR</code> is even
+ * and the one for <code>NSBIDI_DEFAULT_RTL</code> is odd,
+ * just like with normal LTR and RTL level values -
+ * these special values are designed that way. Also, the implementation
+ * assumes that NSBIDI_MAX_EXPLICIT_LEVEL is odd.
+ *
+ * @see NSBIDI_DEFAULT_LTR
+ * @see NSBIDI_DEFAULT_RTL
+ * @see NSBIDI_LEVEL_OVERRIDE
+ * @see NSBIDI_MAX_EXPLICIT_LEVEL
+ */
+typedef uint8_t nsBidiLevel;
+
+/** Paragraph level setting.
+ * If there is no strong character, then set the paragraph level to 0 (left-to-right).
+ */
+#define NSBIDI_DEFAULT_LTR 0xfe
+
+/** Paragraph level setting.
+ * If there is no strong character, then set the paragraph level to 1 (right-to-left).
+ */
+#define NSBIDI_DEFAULT_RTL 0xff
+
+/**
+ * Maximum explicit embedding level.
+ * (The maximum resolved level can be up to <code>NSBIDI_MAX_EXPLICIT_LEVEL+1</code>).
+ *
+ */
+#define NSBIDI_MAX_EXPLICIT_LEVEL 125
+
+/** Bit flag for level input.
+ * Overrides directional properties.
+ */
+#define NSBIDI_LEVEL_OVERRIDE 0x80
+
+/**
+ * <code>nsBidiDirection</code> values indicate the text direction.
+ */
+enum nsBidiDirection {
+ /** All left-to-right text This is a 0 value. */
+ NSBIDI_LTR,
+ /** All right-to-left text This is a 1 value. */
+ NSBIDI_RTL,
+ /** Mixed-directional text. */
+ NSBIDI_MIXED
+};
+
+namespace mozilla {
+
+// https://drafts.csswg.org/css-align-3/#baseline-sharing-group
+enum BaselineSharingGroup
+{
+ // NOTE Used as an array index so must be 0 and 1.
+ eFirst = 0,
+ eLast = 1,
+};
+
+// Loosely: https://drafts.csswg.org/css-align-3/#shared-alignment-context
+enum class AlignmentContext
+{
+ eInline,
+ eTable,
+ eFlexbox,
+ eGrid,
+};
+
+/*
+ * For replaced elements only. Gets the intrinsic dimensions of this element.
+ * The dimensions may only be one of the following two types:
+ *
+ * eStyleUnit_Coord - a length in app units
+ * eStyleUnit_None - the element has no intrinsic size in this dimension
+ */
+struct IntrinsicSize {
+ nsStyleCoord width, height;
+
+ IntrinsicSize()
+ : width(eStyleUnit_None), height(eStyleUnit_None)
+ {}
+ IntrinsicSize(const IntrinsicSize& rhs)
+ : width(rhs.width), height(rhs.height)
+ {}
+ IntrinsicSize& operator=(const IntrinsicSize& rhs) {
+ width = rhs.width; height = rhs.height; return *this;
+ }
+ bool operator==(const IntrinsicSize& rhs) {
+ return width == rhs.width && height == rhs.height;
+ }
+ bool operator!=(const IntrinsicSize& rhs) {
+ return !(*this == rhs);
+ }
+};
+
+// Pseudo bidi embedding level indicating nonexistence.
+static const nsBidiLevel kBidiLevelNone = 0xff;
+
+struct FrameBidiData
+{
+ nsBidiLevel baseLevel;
+ nsBidiLevel embeddingLevel;
+ // The embedding level of virtual bidi formatting character before
+ // this frame if any. kBidiLevelNone is used to indicate nonexistence
+ // or unnecessity of such virtual character.
+ nsBidiLevel precedingControl;
+};
+
+} // namespace mozilla
+
+/// Generic destructor for frame properties. Calls delete.
+template<typename T>
+static void DeleteValue(T* aPropertyValue)
+{
+ delete aPropertyValue;
+}
+
+/// Generic destructor for frame properties. Calls Release().
+template<typename T>
+static void ReleaseValue(T* aPropertyValue)
+{
+ aPropertyValue->Release();
+}
+
+//----------------------------------------------------------------------
+
+/**
+ * A frame in the layout model. This interface is supported by all frame
+ * objects.
+ *
+ * Frames can have multiple child lists: the default child list
+ * (referred to as the <i>principal</i> child list, and additional named
+ * child lists. There is an ordering of frames within a child list, but
+ * there is no order defined between frames in different child lists of
+ * the same parent frame.
+ *
+ * Frames are NOT reference counted. Use the Destroy() member function
+ * to destroy a frame. The lifetime of the frame hierarchy is bounded by the
+ * lifetime of the presentation shell which owns the frames.
+ *
+ * nsIFrame is a private Gecko interface. If you are not Gecko then you
+ * should not use it. If you're not in layout, then you won't be able to
+ * link to many of the functions defined here. Too bad.
+ *
+ * If you're not in layout but you must call functions in here, at least
+ * restrict yourself to calling virtual methods, which won't hurt you as badly.
+ */
+class nsIFrame : public nsQueryFrame
+{
+public:
+ using AlignmentContext = mozilla::AlignmentContext;
+ using BaselineSharingGroup = mozilla::BaselineSharingGroup;
+ template <typename T> using Maybe = mozilla::Maybe<T>;
+ using Nothing = mozilla::Nothing;
+ using OnNonvisible = mozilla::OnNonvisible;
+ template<typename T=void>
+ using PropertyDescriptor = const mozilla::FramePropertyDescriptor<T>*;
+ using ReflowInput = mozilla::ReflowInput;
+ using ReflowOutput = mozilla::ReflowOutput;
+ using Visibility = mozilla::Visibility;
+
+ typedef mozilla::FrameProperties FrameProperties;
+ typedef mozilla::layers::Layer Layer;
+ typedef mozilla::layout::FrameChildList ChildList;
+ typedef mozilla::layout::FrameChildListID ChildListID;
+ typedef mozilla::layout::FrameChildListIDs ChildListIDs;
+ typedef mozilla::layout::FrameChildListIterator ChildListIterator;
+ typedef mozilla::layout::FrameChildListArrayIterator ChildListArrayIterator;
+ typedef mozilla::gfx::DrawTarget DrawTarget;
+ typedef mozilla::gfx::Matrix Matrix;
+ typedef mozilla::gfx::Matrix4x4 Matrix4x4;
+ typedef mozilla::Sides Sides;
+ typedef mozilla::LogicalSides LogicalSides;
+
+ NS_DECL_QUERYFRAME_TARGET(nsIFrame)
+
+ nsPresContext* PresContext() const {
+ return StyleContext()->PresContext();
+ }
+
+ /**
+ * Called to initialize the frame. This is called immediately after creating
+ * the frame.
+ *
+ * If the frame is a continuing frame, then aPrevInFlow indicates the previous
+ * frame (the frame that was split).
+ *
+ * If you want a view associated with your frame, you should create the view
+ * after Init() has returned.
+ *
+ * @param aContent the content object associated with the frame
+ * @param aParent the parent frame
+ * @param aPrevInFlow the prev-in-flow frame
+ */
+ virtual void Init(nsIContent* aContent,
+ nsContainerFrame* aParent,
+ nsIFrame* aPrevInFlow) = 0;
+
+ /**
+ * Destroys this frame and each of its child frames (recursively calls
+ * Destroy() for each child). If this frame is a first-continuation, this
+ * also removes the frame from the primary frame map and clears undisplayed
+ * content for its content node.
+ * If the frame is a placeholder, it also ensures the out-of-flow frame's
+ * removal and destruction.
+ */
+ void Destroy() { DestroyFrom(this); }
+
+ /** Flags for PeekOffsetCharacter, PeekOffsetNoAmount, PeekOffsetWord return values.
+ */
+ enum FrameSearchResult {
+ // Peek found a appropriate offset within frame.
+ FOUND = 0x00,
+ // try next frame for offset.
+ CONTINUE = 0x1,
+ // offset not found because the frame was empty of text.
+ CONTINUE_EMPTY = 0x2 | CONTINUE,
+ // offset not found because the frame didn't contain any text that could be selected.
+ CONTINUE_UNSELECTABLE = 0x4 | CONTINUE,
+ };
+
+protected:
+ /**
+ * Return true if the frame is part of a Selection.
+ * Helper method to implement the public IsSelected() API.
+ */
+ virtual bool IsFrameSelected() const;
+
+ /**
+ * Implements Destroy(). Do not call this directly except from within a
+ * DestroyFrom() implementation.
+ *
+ * @note This will always be called, so it is not necessary to override
+ * Destroy() in subclasses of nsFrame, just DestroyFrom().
+ *
+ * @param aDestructRoot is the root of the subtree being destroyed
+ */
+ virtual void DestroyFrom(nsIFrame* aDestructRoot) = 0;
+ friend class nsFrameList; // needed to pass aDestructRoot through to children
+ friend class nsLineBox; // needed to pass aDestructRoot through to children
+ friend class nsContainerFrame; // needed to pass aDestructRoot through to children
+ friend class nsFrame; // need to assign mParent
+public:
+
+ /**
+ * Get the content object associated with this frame. Does not add a reference.
+ */
+ nsIContent* GetContent() const { return mContent; }
+
+ /**
+ * Get the frame that should be the parent for the frames of child elements
+ * May return nullptr during reflow
+ */
+ virtual nsContainerFrame* GetContentInsertionFrame() { return nullptr; }
+
+ /**
+ * Move any frames on our overflow list to the end of our principal list.
+ * @return true if there were any overflow frames
+ */
+ virtual bool DrainSelfOverflowList() { return false; }
+
+ /**
+ * Get the frame that should be scrolled if the content associated
+ * with this frame is targeted for scrolling. For frames implementing
+ * nsIScrollableFrame this will return the frame itself. For frames
+ * like nsTextControlFrame that contain a scrollframe, will return
+ * that scrollframe.
+ */
+ virtual nsIScrollableFrame* GetScrollTargetFrame() { return nullptr; }
+
+ /**
+ * Get the offsets of the frame. most will be 0,0
+ *
+ */
+ virtual nsresult GetOffsets(int32_t &start, int32_t &end) const = 0;
+
+ /**
+ * Reset the offsets when splitting frames during Bidi reordering
+ *
+ */
+ virtual void AdjustOffsetsForBidi(int32_t aStart, int32_t aEnd) {}
+
+ /**
+ * Get the style context associated with this frame.
+ */
+ nsStyleContext* StyleContext() const { return mStyleContext; }
+ void SetStyleContext(nsStyleContext* aContext)
+ {
+ if (aContext != mStyleContext) {
+ nsStyleContext* oldStyleContext = mStyleContext;
+ mStyleContext = aContext;
+ aContext->AddRef();
+#ifdef DEBUG
+ aContext->FrameAddRef();
+#endif
+ DidSetStyleContext(oldStyleContext);
+#ifdef DEBUG
+ oldStyleContext->FrameRelease();
+#endif
+ oldStyleContext->Release();
+ }
+ }
+
+ /**
+ * SetStyleContextWithoutNotification is for changes to the style
+ * context that should suppress style change processing, in other
+ * words, those that aren't really changes. This generally means only
+ * changes that happen during frame construction.
+ */
+ void SetStyleContextWithoutNotification(nsStyleContext* aContext)
+ {
+ if (aContext != mStyleContext) {
+#ifdef DEBUG
+ mStyleContext->FrameRelease();
+#endif
+ mStyleContext->Release();
+ mStyleContext = aContext;
+ aContext->AddRef();
+#ifdef DEBUG
+ aContext->FrameAddRef();
+#endif
+ }
+ }
+
+ // Style post processing hook
+ // Attention: the old style context is the one we're forgetting,
+ // and hence possibly completely bogus for GetStyle* purposes.
+ // Use PeekStyleData instead.
+ virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) = 0;
+
+ /**
+ * Define typesafe getter functions for each style struct by
+ * preprocessing the list of style structs. These functions are the
+ * preferred way to get style data. The macro creates functions like:
+ * const nsStyleBorder* StyleBorder();
+ * const nsStyleColor* StyleColor();
+ *
+ * Callers outside of libxul should use nsIDOMWindow::GetComputedStyle()
+ * instead of these accessors.
+ */
+ #define STYLE_STRUCT(name_, checkdata_cb_) \
+ const nsStyle##name_ * Style##name_ () const { \
+ NS_ASSERTION(mStyleContext, "No style context found!"); \
+ return mStyleContext->Style##name_ (); \
+ }
+ #include "nsStyleStructList.h"
+ #undef STYLE_STRUCT
+
+ /** Also forward GetVisitedDependentColor to the style context */
+ nscolor GetVisitedDependentColor(nsCSSPropertyID aProperty)
+ { return mStyleContext->GetVisitedDependentColor(aProperty); }
+
+ /**
+ * These methods are to access any additional style contexts that
+ * the frame may be holding. These are contexts that are children
+ * of the frame's primary context and are NOT used as style contexts
+ * for any child frames. These contexts also MUST NOT have any child
+ * contexts whatsoever. If you need to insert style contexts into the
+ * style tree, then you should create pseudo element frames to own them
+ * The indicies must be consecutive and implementations MUST return an
+ * NS_ERROR_INVALID_ARG if asked for an index that is out of range.
+ */
+ virtual nsStyleContext* GetAdditionalStyleContext(int32_t aIndex) const = 0;
+
+ virtual void SetAdditionalStyleContext(int32_t aIndex,
+ nsStyleContext* aStyleContext) = 0;
+
+ /**
+ * Accessor functions for geometric parent.
+ */
+ nsContainerFrame* GetParent() const { return mParent; }
+ /**
+ * Set this frame's parent to aParent.
+ * If the frame may have moved into or out of a scrollframe's
+ * frame subtree, StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary
+ * must also be called.
+ */
+ void SetParent(nsContainerFrame* aParent);
+
+ /**
+ * The frame's writing-mode, used for logical layout computations.
+ */
+ virtual mozilla::WritingMode GetWritingMode() const {
+ return mozilla::WritingMode(StyleContext());
+ }
+
+ /**
+ * Get the writing mode of this frame, but if it is styled with
+ * unicode-bidi: plaintext, reset the direction to the resolved paragraph
+ * level of the given subframe (typically the first frame on the line),
+ * not this frame's writing mode, because the container frame could be split
+ * by hard line breaks into multiple paragraphs with different base direction.
+ */
+ mozilla::WritingMode GetWritingMode(nsIFrame* aSubFrame) const;
+
+ /**
+ * Bounding rect of the frame. The values are in app units, and the origin is
+ * relative to the upper-left of the geometric parent. The size includes the
+ * content area, borders, and padding.
+ *
+ * Note: moving or sizing the frame does not affect the view's size or
+ * position.
+ */
+ nsRect GetRect() const { return mRect; }
+ nsPoint GetPosition() const { return mRect.TopLeft(); }
+ nsSize GetSize() const { return mRect.Size(); }
+ nsRect GetRectRelativeToSelf() const {
+ return nsRect(nsPoint(0, 0), mRect.Size());
+ }
+ /**
+ * Dimensions and position in logical coordinates in the frame's writing mode
+ * or another writing mode
+ */
+ mozilla::LogicalRect GetLogicalRect(const nsSize& aContainerSize) const {
+ return GetLogicalRect(GetWritingMode(), aContainerSize);
+ }
+ mozilla::LogicalPoint GetLogicalPosition(const nsSize& aContainerSize) const {
+ return GetLogicalPosition(GetWritingMode(), aContainerSize);
+ }
+ mozilla::LogicalSize GetLogicalSize() const {
+ return GetLogicalSize(GetWritingMode());
+ }
+ mozilla::LogicalRect GetLogicalRect(mozilla::WritingMode aWritingMode,
+ const nsSize& aContainerSize) const {
+ return mozilla::LogicalRect(aWritingMode, GetRect(), aContainerSize);
+ }
+ mozilla::LogicalPoint GetLogicalPosition(mozilla::WritingMode aWritingMode,
+ const nsSize& aContainerSize) const {
+ return GetLogicalRect(aWritingMode, aContainerSize).Origin(aWritingMode);
+ }
+ mozilla::LogicalSize GetLogicalSize(mozilla::WritingMode aWritingMode) const {
+ return mozilla::LogicalSize(aWritingMode, GetSize());
+ }
+ nscoord IStart(const nsSize& aContainerSize) const {
+ return IStart(GetWritingMode(), aContainerSize);
+ }
+ nscoord IStart(mozilla::WritingMode aWritingMode,
+ const nsSize& aContainerSize) const {
+ return GetLogicalPosition(aWritingMode, aContainerSize).I(aWritingMode);
+ }
+ nscoord BStart(const nsSize& aContainerSize) const {
+ return BStart(GetWritingMode(), aContainerSize);
+ }
+ nscoord BStart(mozilla::WritingMode aWritingMode,
+ const nsSize& aContainerSize) const {
+ return GetLogicalPosition(aWritingMode, aContainerSize).B(aWritingMode);
+ }
+ nscoord ISize() const { return ISize(GetWritingMode()); }
+ nscoord ISize(mozilla::WritingMode aWritingMode) const {
+ return GetLogicalSize(aWritingMode).ISize(aWritingMode);
+ }
+ nscoord BSize() const { return BSize(GetWritingMode()); }
+ nscoord BSize(mozilla::WritingMode aWritingMode) const {
+ return GetLogicalSize(aWritingMode).BSize(aWritingMode);
+ }
+ nscoord ContentBSize() const { return ContentBSize(GetWritingMode()); }
+ nscoord ContentBSize(mozilla::WritingMode aWritingMode) const {
+ auto bp = GetLogicalUsedBorderAndPadding(aWritingMode);
+ bp.ApplySkipSides(GetLogicalSkipSides());
+ return std::max(0, BSize(aWritingMode) - bp.BStartEnd(aWritingMode));
+ }
+
+ /**
+ * When we change the size of the frame's border-box rect, we may need to
+ * reset the overflow rect if it was previously stored as deltas.
+ * (If it is currently a "large" overflow and could be re-packed as deltas,
+ * we don't bother as the cost of the allocation has already been paid.)
+ */
+ void SetRect(const nsRect& aRect) {
+ if (mOverflow.mType != NS_FRAME_OVERFLOW_LARGE &&
+ mOverflow.mType != NS_FRAME_OVERFLOW_NONE) {
+ nsOverflowAreas overflow = GetOverflowAreas();
+ mRect = aRect;
+ SetOverflowAreas(overflow);
+ } else {
+ mRect = aRect;
+ }
+ }
+ /**
+ * Set this frame's rect from a logical rect in its own writing direction
+ */
+ void SetRect(const mozilla::LogicalRect& aRect,
+ const nsSize& aContainerSize) {
+ SetRect(GetWritingMode(), aRect, aContainerSize);
+ }
+ /**
+ * Set this frame's rect from a logical rect in a different writing direction
+ * (GetPhysicalRect will assert if the writing mode doesn't match)
+ */
+ void SetRect(mozilla::WritingMode aWritingMode,
+ const mozilla::LogicalRect& aRect,
+ const nsSize& aContainerSize) {
+ SetRect(aRect.GetPhysicalRect(aWritingMode, aContainerSize));
+ }
+
+ /**
+ * Set this frame's size from a logical size in its own writing direction.
+ * This leaves the frame's logical position unchanged, which means its
+ * physical position may change (for right-to-left modes).
+ */
+ void SetSize(const mozilla::LogicalSize& aSize) {
+ SetSize(GetWritingMode(), aSize);
+ }
+ /*
+ * Set this frame's size from a logical size in a different writing direction.
+ * This leaves the frame's logical position in the given mode unchanged,
+ * which means its physical position may change (for right-to-left modes).
+ */
+ void SetSize(mozilla::WritingMode aWritingMode,
+ const mozilla::LogicalSize& aSize)
+ {
+ if ((!aWritingMode.IsVertical() && !aWritingMode.IsBidiLTR()) ||
+ aWritingMode.IsVerticalRL()) {
+ nscoord oldWidth = mRect.width;
+ SetSize(aSize.GetPhysicalSize(aWritingMode));
+ mRect.x -= mRect.width - oldWidth;
+ } else {
+ SetSize(aSize.GetPhysicalSize(aWritingMode));
+ }
+ }
+
+ /**
+ * Set this frame's physical size. This leaves the frame's physical position
+ * (topLeft) unchanged.
+ */
+ void SetSize(const nsSize& aSize) {
+ SetRect(nsRect(mRect.TopLeft(), aSize));
+ }
+
+ void SetPosition(const nsPoint& aPt) { mRect.MoveTo(aPt); }
+ void SetPosition(mozilla::WritingMode aWritingMode,
+ const mozilla::LogicalPoint& aPt,
+ const nsSize& aContainerSize) {
+ // We subtract mRect.Size() from the container size to account for
+ // the fact that logical origins in RTL coordinate systems are at
+ // the top right of the frame instead of the top left.
+ mRect.MoveTo(aPt.GetPhysicalPoint(aWritingMode,
+ aContainerSize - mRect.Size()));
+ }
+
+ /**
+ * Move the frame, accounting for relative positioning. Use this when
+ * adjusting the frame's position by a known amount, to properly update its
+ * saved normal position (see GetNormalPosition below).
+ *
+ * This must be used only when moving a frame *after*
+ * ReflowInput::ApplyRelativePositioning is called. When moving
+ * a frame during the reflow process prior to calling
+ * ReflowInput::ApplyRelativePositioning, the position should
+ * simply be adjusted directly (e.g., using SetPosition()).
+ */
+ void MovePositionBy(const nsPoint& aTranslation);
+
+ /**
+ * As above, using a logical-point delta in a given writing mode.
+ */
+ void MovePositionBy(mozilla::WritingMode aWritingMode,
+ const mozilla::LogicalPoint& aTranslation)
+ {
+ // The LogicalPoint represents a vector rather than a point within a
+ // rectangular coordinate space, so we use a null containerSize when
+ // converting logical to physical.
+ const nsSize nullContainerSize;
+ MovePositionBy(aTranslation.GetPhysicalPoint(aWritingMode,
+ nullContainerSize));
+ }
+
+ /**
+ * Return frame's rect without relative positioning
+ */
+ nsRect GetNormalRect() const;
+
+ /**
+ * Return frame's position without relative positioning
+ */
+ nsPoint GetNormalPosition() const;
+ mozilla::LogicalPoint
+ GetLogicalNormalPosition(mozilla::WritingMode aWritingMode,
+ const nsSize& aContainerSize) const
+ {
+ // Subtract the size of this frame from the container size to get
+ // the correct position in rtl frames where the origin is on the
+ // right instead of the left
+ return mozilla::LogicalPoint(aWritingMode,
+ GetNormalPosition(),
+ aContainerSize - mRect.Size());
+ }
+
+ virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild)
+ { return aChild->GetPosition(); }
+
+ nsPoint GetPositionIgnoringScrolling();
+
+ typedef AutoTArray<nsIContent*, 2> ContentArray;
+ static void DestroyContentArray(ContentArray* aArray);
+
+#define NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, dtor) \
+ static const mozilla::FramePropertyDescriptor<type>* prop() { \
+ /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */ \
+ static const auto descriptor = \
+ mozilla::FramePropertyDescriptor<type>::NewWithDestructor<dtor>(); \
+ return &descriptor; \
+ }
+
+// Don't use this unless you really know what you're doing!
+#define NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(prop, type, dtor) \
+ static const mozilla::FramePropertyDescriptor<type>* prop() { \
+ /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */ \
+ static const auto descriptor = mozilla:: \
+ FramePropertyDescriptor<type>::NewWithDestructorWithFrame<dtor>(); \
+ return &descriptor; \
+ }
+
+#define NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(prop, type) \
+ static const mozilla::FramePropertyDescriptor<type>* prop() { \
+ /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */ \
+ static const auto descriptor = \
+ mozilla::FramePropertyDescriptor<type>::NewWithoutDestructor(); \
+ return &descriptor; \
+ }
+
+#define NS_DECLARE_FRAME_PROPERTY_DELETABLE(prop, type) \
+ NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, DeleteValue)
+
+#define NS_DECLARE_FRAME_PROPERTY_RELEASABLE(prop, type) \
+ NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, ReleaseValue)
+
+#define NS_DECLARE_FRAME_PROPERTY_WITH_DTOR_NEVER_CALLED(prop, type) \
+ static void AssertOnDestroyingProperty##prop(type*) { \
+ MOZ_ASSERT_UNREACHABLE("Frame property " #prop " should never " \
+ "be destroyed by the FramePropertyTable"); \
+ } \
+ NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, \
+ AssertOnDestroyingProperty##prop)
+
+#define NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(prop, type) \
+ NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(prop, mozilla::SmallValueHolder<type>)
+
+ NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitSibling, nsIFrame)
+ NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitPrevSibling, nsIFrame)
+
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(NormalPositionProperty, nsPoint)
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(ComputedOffsetProperty, nsMargin)
+
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutlineInnerRectProperty, nsRect)
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(PreEffectsBBoxProperty, nsRect)
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(PreTransformOverflowAreasProperty,
+ nsOverflowAreas)
+
+ // The initial overflow area passed to FinishAndStoreOverflow. This is only set
+ // on frames that Preserve3D() or HasPerspective() or IsTransformed(), and
+ // when at least one of the overflow areas differs from the frame bound rect.
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(InitialOverflowProperty, nsOverflowAreas)
+
+#ifdef DEBUG
+ // InitialOverflowPropertyDebug is added to the frame to indicate that either
+ // the InitialOverflowProperty has been stored or the InitialOverflowProperty
+ // has been suppressed due to being set to the default value (frame bounds)
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(DebugInitialOverflowPropertyApplied, bool)
+#endif
+
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(UsedMarginProperty, nsMargin)
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(UsedPaddingProperty, nsMargin)
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(UsedBorderProperty, nsMargin)
+
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(LineBaselineOffset, nscoord)
+
+ // Temporary override for a flex item's main-size property (either width
+ // or height), imposed by its flex container.
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(FlexItemMainSizeOverride, nscoord)
+
+ NS_DECLARE_FRAME_PROPERTY_RELEASABLE(CachedBackgroundImageDT, DrawTarget)
+
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(InvalidationRect, nsRect)
+
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(RefusedAsyncAnimationProperty, bool)
+
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(FragStretchBSizeProperty, nscoord)
+
+ // The block-axis margin-box size associated with eBClampMarginBoxMinSize.
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BClampMarginBoxMinSizeProperty, nscoord)
+
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(IBaselinePadProperty, nscoord)
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BBaselinePadProperty, nscoord)
+
+ NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(GenConProperty, ContentArray,
+ DestroyContentArray)
+
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BidiDataProperty, mozilla::FrameBidiData)
+
+ mozilla::FrameBidiData GetBidiData()
+ {
+ return Properties().Get(BidiDataProperty());
+ }
+
+ nsBidiLevel GetBaseLevel()
+ {
+ return GetBidiData().baseLevel;
+ }
+
+ nsBidiLevel GetEmbeddingLevel()
+ {
+ return GetBidiData().embeddingLevel;
+ }
+
+ nsTArray<nsIContent*>* GetGenConPseudos() {
+ return Properties().Get(GenConProperty());
+ }
+
+ /**
+ * Return the distance between the border edge of the frame and the
+ * margin edge of the frame. Like GetRect(), returns the dimensions
+ * as of the most recent reflow.
+ *
+ * This doesn't include any margin collapsing that may have occurred.
+ *
+ * It also treats 'auto' margins as zero, and treats any margins that
+ * should have been turned into 'auto' because of overconstraint as
+ * having their original values.
+ */
+ virtual nsMargin GetUsedMargin() const;
+ virtual mozilla::LogicalMargin
+ GetLogicalUsedMargin(mozilla::WritingMode aWritingMode) const {
+ return mozilla::LogicalMargin(aWritingMode, GetUsedMargin());
+ }
+
+ /**
+ * Return the distance between the border edge of the frame (which is
+ * its rect) and the padding edge of the frame. Like GetRect(), returns
+ * the dimensions as of the most recent reflow.
+ *
+ * Note that this differs from StyleBorder()->GetComputedBorder() in
+ * that this describes a region of the frame's box, and
+ * StyleBorder()->GetComputedBorder() describes a border. They differ
+ * for tables (particularly border-collapse tables) and themed
+ * elements.
+ */
+ virtual nsMargin GetUsedBorder() const;
+ virtual mozilla::LogicalMargin
+ GetLogicalUsedBorder(mozilla::WritingMode aWritingMode) const {
+ return mozilla::LogicalMargin(aWritingMode, GetUsedBorder());
+ }
+
+ /**
+ * Return the distance between the padding edge of the frame and the
+ * content edge of the frame. Like GetRect(), returns the dimensions
+ * as of the most recent reflow.
+ */
+ virtual nsMargin GetUsedPadding() const;
+ virtual mozilla::LogicalMargin
+ GetLogicalUsedPadding(mozilla::WritingMode aWritingMode) const {
+ return mozilla::LogicalMargin(aWritingMode, GetUsedPadding());
+ }
+
+ nsMargin GetUsedBorderAndPadding() const {
+ return GetUsedBorder() + GetUsedPadding();
+ }
+ mozilla::LogicalMargin
+ GetLogicalUsedBorderAndPadding(mozilla::WritingMode aWritingMode) const {
+ return mozilla::LogicalMargin(aWritingMode, GetUsedBorderAndPadding());
+ }
+
+ /**
+ * Like the frame's rect (see |GetRect|), which is the border rect,
+ * other rectangles of the frame, in app units, relative to the parent.
+ */
+ nsRect GetPaddingRect() const;
+ nsRect GetPaddingRectRelativeToSelf() const;
+ nsRect GetContentRect() const;
+ nsRect GetContentRectRelativeToSelf() const;
+ nsRect GetMarginRectRelativeToSelf() const;
+
+ /**
+ * The area to paint box-shadows around. The default is the border rect.
+ * (nsFieldSetFrame overrides this).
+ */
+ virtual nsRect VisualBorderRectRelativeToSelf() const {
+ return nsRect(0, 0, mRect.width, mRect.height);
+ }
+
+ /**
+ * Get the size, in app units, of the border radii. It returns FALSE iff all
+ * returned radii == 0 (so no border radii), TRUE otherwise.
+ * For the aRadii indexes, use the NS_CORNER_* constants in nsStyleConsts.h
+ * If a side is skipped via aSkipSides, its corners are forced to 0.
+ *
+ * All corner radii are then adjusted so they do not require more
+ * space than aBorderArea, according to the algorithm in css3-background.
+ *
+ * aFrameSize is used as the basis for percentage widths and heights.
+ * aBorderArea is used for the adjustment of radii that might be too
+ * large.
+ * FIXME: In the long run, we can probably get away with only one of
+ * these, especially if we change the way we handle outline-radius (by
+ * removing it and inflating the border radius)
+ *
+ * Return whether any radii are nonzero.
+ */
+ static bool ComputeBorderRadii(const nsStyleCorners& aBorderRadius,
+ const nsSize& aFrameSize,
+ const nsSize& aBorderArea,
+ Sides aSkipSides,
+ nscoord aRadii[8]);
+
+ /*
+ * Given a set of border radii for one box (e.g., border box), convert
+ * it to the equivalent set of radii for another box (e.g., in to
+ * padding box, out to outline box) by reducing radii or increasing
+ * nonzero radii as appropriate.
+ *
+ * Indices into aRadii are the NS_CORNER_* constants in nsStyleConsts.h
+ *
+ * Note that InsetBorderRadii is lossy, since it can turn nonzero
+ * radii into zero, and OutsetBorderRadii does not inflate zero radii.
+ * Therefore, callers should always inset or outset directly from the
+ * original value coming from style.
+ */
+ static void InsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets);
+ static void OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets);
+
+ /**
+ * Fill in border radii for this frame. Return whether any are nonzero.
+ * Indices into aRadii are the NS_CORNER_* constants in nsStyleConsts.h
+ * aSkipSides is a union of SIDE_BIT_LEFT/RIGHT/TOP/BOTTOM bits that says
+ * which side(s) to skip.
+ */
+ virtual bool GetBorderRadii(const nsSize& aFrameSize,
+ const nsSize& aBorderArea,
+ Sides aSkipSides,
+ nscoord aRadii[8]) const;
+ bool GetBorderRadii(nscoord aRadii[8]) const;
+
+ bool GetPaddingBoxBorderRadii(nscoord aRadii[8]) const;
+ bool GetContentBoxBorderRadii(nscoord aRadii[8]) const;
+
+ /**
+ * XXX: this method will likely be replaced by GetVerticalAlignBaseline
+ * Get the position of the frame's baseline, relative to the top of
+ * the frame (its top border edge). Only valid when Reflow is not
+ * needed.
+ * @note You should only call this on frames with a WM that's parallel to aWM.
+ * @param aWM the writing-mode of the alignment context, with the ltr/rtl
+ * direction tweak done by nsIFrame::GetWritingMode(nsIFrame*) in inline
+ * contexts (see that method).
+ */
+ virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWM) const = 0;
+
+ /**
+ * Synthesize a first(last) inline-axis baseline from our margin-box.
+ * An alphabetical baseline is at the start(end) edge and a central baseline
+ * is at the center of our block-axis margin-box (aWM tells which to use).
+ * https://drafts.csswg.org/css-align-3/#synthesize-baselines
+ * @note You should only call this on frames with a WM that's parallel to aWM.
+ * @param aWM the writing-mode of the alignment context
+ * @return an offset from our border-box block-axis start(end) edge for
+ * a first(last) baseline respectively
+ * (implemented in nsIFrameInlines.h)
+ */
+ inline nscoord SynthesizeBaselineBOffsetFromMarginBox(
+ mozilla::WritingMode aWM,
+ BaselineSharingGroup aGroup) const;
+
+ /**
+ * Synthesize a first(last) inline-axis baseline from our border-box.
+ * An alphabetical baseline is at the start(end) edge and a central baseline
+ * is at the center of our block-axis border-box (aWM tells which to use).
+ * https://drafts.csswg.org/css-align-3/#synthesize-baselines
+ * @note The returned value is only valid when reflow is not needed.
+ * @note You should only call this on frames with a WM that's parallel to aWM.
+ * @param aWM the writing-mode of the alignment context
+ * @return an offset from our border-box block-axis start(end) edge for
+ * a first(last) baseline respectively
+ * (implemented in nsIFrameInlines.h)
+ */
+ inline nscoord SynthesizeBaselineBOffsetFromBorderBox(
+ mozilla::WritingMode aWM,
+ BaselineSharingGroup aGroup) const;
+
+ /**
+ * Return the position of the frame's inline-axis baseline, or synthesize one
+ * for the given alignment context. The returned baseline is the distance from
+ * the block-axis border-box start(end) edge for aBaselineGroup eFirst(eLast).
+ * @note The returned value is only valid when reflow is not needed.
+ * @note You should only call this on frames with a WM that's parallel to aWM.
+ * @param aWM the writing-mode of the alignment context
+ * @param aBaselineOffset out-param, only valid if the method returns true
+ * (implemented in nsIFrameInlines.h)
+ */
+ inline nscoord BaselineBOffset(mozilla::WritingMode aWM,
+ BaselineSharingGroup aBaselineGroup,
+ AlignmentContext aAlignmentContext) const;
+
+ /**
+ * XXX: this method is taking over the role that GetLogicalBaseline has.
+ * Return true if the frame has a CSS2 'vertical-align' baseline.
+ * If it has, then the returned baseline is the distance from the block-
+ * axis border-box start edge.
+ * @note This method should only be used in AlignmentContext::eInline contexts.
+ * @note The returned value is only valid when reflow is not needed.
+ * @note You should only call this on frames with a WM that's parallel to aWM.
+ * @param aWM the writing-mode of the alignment context
+ * @param aBaseline the baseline offset, only valid if the method returns true
+ */
+ virtual bool GetVerticalAlignBaseline(mozilla::WritingMode aWM,
+ nscoord* aBaseline) const {
+ return false;
+ }
+
+ /**
+ * Return true if the frame has a first(last) inline-axis natural baseline per
+ * CSS Box Alignment. If so, then the returned baseline is the distance from
+ * the block-axis border-box start(end) edge for aBaselineGroup eFirst(eLast).
+ * https://drafts.csswg.org/css-align-3/#natural-baseline
+ * @note The returned value is only valid when reflow is not needed.
+ * @note You should only call this on frames with a WM that's parallel to aWM.
+ * @param aWM the writing-mode of the alignment context
+ * @param aBaseline the baseline offset, only valid if the method returns true
+ */
+ virtual bool GetNaturalBaselineBOffset(mozilla::WritingMode aWM,
+ BaselineSharingGroup aBaselineGroup,
+ nscoord* aBaseline) const {
+ return false;
+ }
+
+ /**
+ * Get the position of the baseline on which the caret needs to be placed,
+ * relative to the top of the frame. This is mostly needed for frames
+ * which return a baseline from GetBaseline which is not useful for
+ * caret positioning.
+ */
+ virtual nscoord GetCaretBaseline() const {
+ return GetLogicalBaseline(GetWritingMode());
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // The public visibility API.
+ ///////////////////////////////////////////////////////////////////////////////
+
+ /// @return true if we're tracking visibility for this frame.
+ bool TrackingVisibility() const
+ {
+ return bool(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED);
+ }
+
+ /// @return the visibility state of this frame. See the Visibility enum
+ /// for the possible return values and their meanings.
+ Visibility GetVisibility() const;
+
+ /// Update the visibility state of this frame synchronously.
+ /// XXX(seth): Avoid using this method; we should be relying on the refresh
+ /// driver for visibility updates. This method, which replaces
+ /// nsLayoutUtils::UpdateApproximateFrameVisibility(), exists purely as a
+ /// temporary measure to avoid changing behavior during the transition from
+ /// the old image visibility code.
+ void UpdateVisibilitySynchronously();
+
+ // A frame property which stores the visibility state of this frame. Right
+ // now that consists of an approximate visibility counter represented as a
+ // uint32_t. When the visibility of this frame is not being tracked, this
+ // property is absent.
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(VisibilityStateProperty, uint32_t);
+
+protected:
+
+ /**
+ * Subclasses can call this method to enable visibility tracking for this frame.
+ *
+ * If visibility tracking was previously disabled, this will schedule an
+ * update an asynchronous update of visibility.
+ */
+ void EnableVisibilityTracking();
+
+ /**
+ * Subclasses can call this method to disable visibility tracking for this frame.
+ *
+ * Note that if visibility tracking was previously enabled, disabling visibility
+ * tracking will cause a synchronous call to OnVisibilityChange().
+ */
+ void DisableVisibilityTracking();
+
+ /**
+ * Called when a frame transitions between visibility states (for example,
+ * from nonvisible to visible, or from visible to nonvisible).
+ *
+ * @param aNewVisibility The new visibility state.
+ * @param aNonvisibleAction A requested action if the frame has become
+ * nonvisible. If Nothing(), no action is
+ * requested. If DISCARD_IMAGES is specified, the
+ * frame is requested to ask any images it's
+ * associated with to discard their surfaces if
+ * possible.
+ *
+ * Subclasses which override this method should call their parent class's
+ * implementation.
+ */
+ virtual void OnVisibilityChange(Visibility aNewVisibility,
+ Maybe<OnNonvisible> aNonvisibleAction = Nothing());
+
+public:
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // Internal implementation for the approximate frame visibility API.
+ ///////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * We track the approximate visibility of frames using a counter; if it's
+ * non-zero, then the frame is considered visible. Using a counter allows us
+ * to account for situations where the frame may be visible in more than one
+ * place (for example, via -moz-element), and it simplifies the
+ * implementation of our approximate visibility tracking algorithms.
+ *
+ * @param aNonvisibleAction A requested action if the frame has become
+ * nonvisible. If Nothing(), no action is
+ * requested. If DISCARD_IMAGES is specified, the
+ * frame is requested to ask any images it's
+ * associated with to discard their surfaces if
+ * possible.
+ */
+ void DecApproximateVisibleCount(Maybe<OnNonvisible> aNonvisibleAction = Nothing());
+ void IncApproximateVisibleCount();
+
+
+ /**
+ * Get the specified child list.
+ *
+ * @param aListID identifies the requested child list.
+ * @return the child list. If the requested list is unsupported by this
+ * frame type, an empty list will be returned.
+ */
+ virtual const nsFrameList& GetChildList(ChildListID aListID) const = 0;
+ const nsFrameList& PrincipalChildList() const { return GetChildList(kPrincipalList); }
+ virtual void GetChildLists(nsTArray<ChildList>* aLists) const = 0;
+
+ /**
+ * Gets the child lists for this frame, including
+ * ones belong to a child document.
+ */
+ void GetCrossDocChildLists(nsTArray<ChildList>* aLists);
+
+ // The individual concrete child lists.
+ static const ChildListID kPrincipalList = mozilla::layout::kPrincipalList;
+ static const ChildListID kAbsoluteList = mozilla::layout::kAbsoluteList;
+ static const ChildListID kBulletList = mozilla::layout::kBulletList;
+ static const ChildListID kCaptionList = mozilla::layout::kCaptionList;
+ static const ChildListID kColGroupList = mozilla::layout::kColGroupList;
+ static const ChildListID kExcessOverflowContainersList = mozilla::layout::kExcessOverflowContainersList;
+ static const ChildListID kFixedList = mozilla::layout::kFixedList;
+ static const ChildListID kFloatList = mozilla::layout::kFloatList;
+ static const ChildListID kOverflowContainersList = mozilla::layout::kOverflowContainersList;
+ static const ChildListID kOverflowList = mozilla::layout::kOverflowList;
+ static const ChildListID kOverflowOutOfFlowList = mozilla::layout::kOverflowOutOfFlowList;
+ static const ChildListID kPopupList = mozilla::layout::kPopupList;
+ static const ChildListID kPushedFloatsList = mozilla::layout::kPushedFloatsList;
+ static const ChildListID kSelectPopupList = mozilla::layout::kSelectPopupList;
+ static const ChildListID kBackdropList = mozilla::layout::kBackdropList;
+ // A special alias for kPrincipalList that do not request reflow.
+ static const ChildListID kNoReflowPrincipalList = mozilla::layout::kNoReflowPrincipalList;
+
+ /**
+ * Child frames are linked together in a doubly-linked list
+ */
+ nsIFrame* GetNextSibling() const { return mNextSibling; }
+ void SetNextSibling(nsIFrame* aNextSibling) {
+ NS_ASSERTION(this != aNextSibling, "Creating a circular frame list, this is very bad.");
+ if (mNextSibling && mNextSibling->GetPrevSibling() == this) {
+ mNextSibling->mPrevSibling = nullptr;
+ }
+ mNextSibling = aNextSibling;
+ if (mNextSibling) {
+ mNextSibling->mPrevSibling = this;
+ }
+ }
+
+ nsIFrame* GetPrevSibling() const { return mPrevSibling; }
+
+ /**
+ * Builds the display lists for the content represented by this frame
+ * and its descendants. The background+borders of this element must
+ * be added first, before any other content.
+ *
+ * This should only be called by methods in nsFrame. Instead of calling this
+ * directly, call either BuildDisplayListForStackingContext or
+ * BuildDisplayListForChild.
+ *
+ * See nsDisplayList.h for more information about display lists.
+ *
+ * @param aDirtyRect content outside this rectangle can be ignored; the
+ * rectangle is in frame coordinates
+ */
+ virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
+ const nsRect& aDirtyRect,
+ const nsDisplayListSet& aLists) {}
+ /**
+ * Displays the caret onto the given display list builder. The caret is
+ * painted on top of the rest of the display list items.
+ *
+ * @param aDirtyRect is the dirty rectangle that we're repainting.
+ */
+ void DisplayCaret(nsDisplayListBuilder* aBuilder,
+ const nsRect& aDirtyRect,
+ nsDisplayList* aList);
+
+ /**
+ * Get the preferred caret color at the offset.
+ *
+ * @param aOffset is offset of the content.
+ */
+ virtual nscolor GetCaretColorAt(int32_t aOffset);
+
+
+ bool IsThemed(nsITheme::Transparency* aTransparencyState = nullptr) const {
+ return IsThemed(StyleDisplay(), aTransparencyState);
+ }
+ bool IsThemed(const nsStyleDisplay* aDisp,
+ nsITheme::Transparency* aTransparencyState = nullptr) const {
+ nsIFrame* mutable_this = const_cast<nsIFrame*>(this);
+ if (!aDisp->mAppearance)
+ return false;
+ nsPresContext* pc = PresContext();
+ nsITheme *theme = pc->GetTheme();
+ if(!theme ||
+ !theme->ThemeSupportsWidget(pc, mutable_this, aDisp->mAppearance))
+ return false;
+ if (aTransparencyState) {
+ *aTransparencyState =
+ theme->GetWidgetTransparency(mutable_this, aDisp->mAppearance);
+ }
+ return true;
+ }
+
+ /**
+ * Builds a display list for the content represented by this frame,
+ * treating this frame as the root of a stacking context.
+ * @param aDirtyRect content outside this rectangle can be ignored; the
+ * rectangle is in frame coordinates
+ */
+ void BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
+ const nsRect& aDirtyRect,
+ nsDisplayList* aList);
+
+ enum {
+ DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT = 0x01,
+ DISPLAY_CHILD_FORCE_STACKING_CONTEXT = 0x02,
+ DISPLAY_CHILD_INLINE = 0x04
+ };
+ /**
+ * Adjusts aDirtyRect for the child's offset, checks that the dirty rect
+ * actually intersects the child (or its descendants), calls BuildDisplayList
+ * on the child if necessary, and puts things in the right lists if the child
+ * is positioned.
+ *
+ * @param aFlags combination of DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT,
+ * DISPLAY_CHILD_FORCE_STACKING_CONTEXT and DISPLAY_CHILD_INLINE
+ */
+ void BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aChild,
+ const nsRect& aDirtyRect,
+ const nsDisplayListSet& aLists,
+ uint32_t aFlags = 0);
+
+ /**
+ * Does this frame need a view?
+ */
+ virtual bool NeedsView() { return false; }
+
+ bool RefusedAsyncAnimation() const
+ {
+ return Properties().Get(RefusedAsyncAnimationProperty());
+ }
+
+ /**
+ * Returns true if this frame is transformed (e.g. has CSS or SVG transforms)
+ * or if its parent is an SVG frame that has children-only transforms (e.g.
+ * an SVG viewBox attribute) or if its transform-style is preserve-3d or
+ * the frame has transform animations.
+ */
+ bool IsTransformed() const;
+
+ /**
+ * Returns true if the frame is translucent or the frame has opacity
+ * animations for the purposes of creating a stacking context.
+ */
+ bool HasOpacity() const
+ {
+ return HasOpacityInternal(1.0f);
+ }
+ /**
+ * Returns true if the frame is translucent for display purposes.
+ */
+ bool HasVisualOpacity() const
+ {
+ // Treat an opacity value of 0.99 and above as opaque. This is an
+ // optimization aimed at Web content which use opacity:0.99 as a hint for
+ // creating a stacking context only.
+ return HasOpacityInternal(0.99f);
+ }
+
+ /**
+ * Return true if this frame might be using a transform getter.
+ */
+ virtual bool HasTransformGetter() const { return false; }
+
+ /**
+ * Returns true if this frame is an SVG frame that has SVG transforms applied
+ * to it, or if its parent frame is an SVG frame that has children-only
+ * transforms (e.g. an SVG viewBox attribute).
+ * If aOwnTransforms is non-null and the frame has its own SVG transforms,
+ * aOwnTransforms will be set to these transforms. If aFromParentTransforms
+ * is non-null and the frame has an SVG parent with children-only transforms,
+ * then aFromParentTransforms will be set to these transforms.
+ */
+ virtual bool IsSVGTransformed(Matrix *aOwnTransforms = nullptr,
+ Matrix *aFromParentTransforms = nullptr) const;
+
+ /**
+ * Returns whether this frame will attempt to extend the 3d transforms of its
+ * children. This requires transform-style: preserve-3d, as well as no clipping
+ * or svg effects.
+ */
+ bool Extend3DContext() const;
+
+ /**
+ * Returns whether this frame has a parent that Extend3DContext() and has
+ * its own transform (or hidden backface) to be combined with the parent's
+ * transform.
+ */
+ bool Combines3DTransformWithAncestors() const;
+
+ /**
+ * Returns whether this frame has a hidden backface and has a parent that
+ * Extend3DContext(). This is useful because in some cases the hidden
+ * backface can safely be ignored if it could not be visible anyway.
+ */
+ bool In3DContextAndBackfaceIsHidden() const;
+
+ bool IsPreserve3DLeaf() const {
+ return Combines3DTransformWithAncestors() && !Extend3DContext();
+ }
+
+ bool HasPerspective() const;
+
+ bool ChildrenHavePerspective() const;
+
+ /**
+ * Includes the overflow area of all descendants that participate in the current
+ * 3d context into aOverflowAreas.
+ */
+ void ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas);
+
+ void RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame);
+
+ /**
+ * Returns the number of ancestors between this and the root of our frame tree
+ */
+ uint32_t GetDepthInFrameTree() const;
+
+ /**
+ * Event handling of GUI events.
+ *
+ * @param aEvent event structure describing the type of event and rge widget
+ * where the event originated
+ * The |point| member of this is in the coordinate system of the
+ * view returned by GetOffsetFromView.
+ * @param aEventStatus a return value indicating whether the event was handled
+ * and whether default processing should be done
+ *
+ * XXX From a frame's perspective it's unclear what the effect of the event status
+ * is. Does it cause the event to continue propagating through the frame hierarchy
+ * or is it just returned to the widgets?
+ *
+ * @see WidgetGUIEvent
+ * @see nsEventStatus
+ */
+ virtual nsresult HandleEvent(nsPresContext* aPresContext,
+ mozilla::WidgetGUIEvent* aEvent,
+ nsEventStatus* aEventStatus) = 0;
+
+ virtual nsresult GetContentForEvent(mozilla::WidgetEvent* aEvent,
+ nsIContent** aContent) = 0;
+
+ // This structure keeps track of the content node and offsets associated with
+ // a point; there is a primary and a secondary offset associated with any
+ // point. The primary and secondary offsets differ when the point is over a
+ // non-text object. The primary offset is the expected position of the
+ // cursor calculated from a point; the secondary offset, when it is different,
+ // indicates that the point is in the boundaries of some selectable object.
+ // Note that the primary offset can be after the secondary offset; for places
+ // that need the beginning and end of the object, the StartOffset and
+ // EndOffset helpers can be used.
+ struct MOZ_STACK_CLASS ContentOffsets
+ {
+ ContentOffsets() : offset(0)
+ , secondaryOffset(0)
+ , associate(mozilla::CARET_ASSOCIATE_BEFORE) {}
+ bool IsNull() { return !content; }
+ // Helpers for places that need the ends of the offsets and expect them in
+ // numerical order, as opposed to wanting the primary and secondary offsets
+ int32_t StartOffset() { return std::min(offset, secondaryOffset); }
+ int32_t EndOffset() { return std::max(offset, secondaryOffset); }
+
+ nsCOMPtr<nsIContent> content;
+ int32_t offset;
+ int32_t secondaryOffset;
+ // This value indicates whether the associated content is before or after
+ // the offset; the most visible use is to allow the caret to know which line
+ // to display on.
+ mozilla::CaretAssociationHint associate;
+ };
+ enum {
+ IGNORE_SELECTION_STYLE = 0x01,
+ // Treat visibility:hidden frames as non-selectable
+ SKIP_HIDDEN = 0x02
+ };
+ /**
+ * This function calculates the content offsets for selection relative to
+ * a point. Note that this should generally only be callled on the event
+ * frame associated with an event because this function does not account
+ * for frame lists other than the primary one.
+ * @param aPoint point relative to this frame
+ */
+ ContentOffsets GetContentOffsetsFromPoint(nsPoint aPoint,
+ uint32_t aFlags = 0);
+
+ virtual ContentOffsets GetContentOffsetsFromPointExternal(nsPoint aPoint,
+ uint32_t aFlags = 0)
+ { return GetContentOffsetsFromPoint(aPoint, aFlags); }
+
+ /**
+ * Ensure that aImage gets notifed when the underlying image request loads
+ * or animates.
+ */
+ void AssociateImage(const nsStyleImage& aImage, nsPresContext* aPresContext);
+
+ /**
+ * This structure holds information about a cursor. mContainer represents a
+ * loaded image that should be preferred. If it is not possible to use it, or
+ * if it is null, mCursor should be used.
+ */
+ struct MOZ_STACK_CLASS Cursor {
+ nsCOMPtr<imgIContainer> mContainer;
+ int32_t mCursor;
+ bool mHaveHotspot;
+ bool mLoading;
+ float mHotspotX, mHotspotY;
+ };
+ /**
+ * Get the cursor for a given frame.
+ */
+ virtual nsresult GetCursor(const nsPoint& aPoint,
+ Cursor& aCursor) = 0;
+
+ /**
+ * Get a point (in the frame's coordinate space) given an offset into
+ * the content. This point should be on the baseline of text with
+ * the correct horizontal offset
+ */
+ virtual nsresult GetPointFromOffset(int32_t inOffset,
+ nsPoint* outPoint) = 0;
+
+ /**
+ * Get a list of character rects in a given range.
+ * This is similar version of GetPointFromOffset.
+ */
+ virtual nsresult GetCharacterRectsInRange(int32_t aInOffset,
+ int32_t aLength,
+ nsTArray<nsRect>& aRects) = 0;
+
+ /**
+ * Get the child frame of this frame which contains the given
+ * content offset. outChildFrame may be this frame, or nullptr on return.
+ * outContentOffset returns the content offset relative to the start
+ * of the returned node. You can also pass a hint which tells the method
+ * to stick to the end of the first found frame or the beginning of the
+ * next in case the offset falls on a boundary.
+ */
+ virtual nsresult GetChildFrameContainingOffset(int32_t inContentOffset,
+ bool inHint,//false stick left
+ int32_t* outFrameContentOffset,
+ nsIFrame** outChildFrame) = 0;
+
+ /**
+ * Get the current frame-state value for this frame. aResult is
+ * filled in with the state bits.
+ */
+ nsFrameState GetStateBits() const { return mState; }
+
+ /**
+ * Update the current frame-state value for this frame.
+ */
+ void AddStateBits(nsFrameState aBits) { mState |= aBits; }
+ void RemoveStateBits(nsFrameState aBits) { mState &= ~aBits; }
+
+ /**
+ * Checks if the current frame-state includes all of the listed bits
+ */
+ bool HasAllStateBits(nsFrameState aBits) const
+ {
+ return (mState & aBits) == aBits;
+ }
+
+ /**
+ * Checks if the current frame-state includes any of the listed bits
+ */
+ bool HasAnyStateBits(nsFrameState aBits) const
+ {
+ return mState & aBits;
+ }
+
+ /**
+ * This call is invoked on the primary frame for a character data content
+ * node, when it is changed in the content tree.
+ */
+ virtual nsresult CharacterDataChanged(CharacterDataChangeInfo* aInfo) = 0;
+
+ /**
+ * This call is invoked when the value of a content objects's attribute
+ * is changed.
+ * The first frame that maps that content is asked to deal
+ * with the change by doing whatever is appropriate.
+ *
+ * @param aNameSpaceID the namespace of the attribute
+ * @param aAttribute the atom name of the attribute
+ * @param aModType Whether or not the attribute was added, changed, or removed.
+ * The constants are defined in nsIDOMMutationEvent.h.
+ */
+ virtual nsresult AttributeChanged(int32_t aNameSpaceID,
+ nsIAtom* aAttribute,
+ int32_t aModType) = 0;
+
+ /**
+ * When the content states of a content object change, this method is invoked
+ * on the primary frame of that content object.
+ *
+ * @param aStates the changed states
+ */
+ virtual void ContentStatesChanged(mozilla::EventStates aStates);
+
+ /**
+ * Return how your frame can be split.
+ */
+ virtual nsSplittableType GetSplittableType() const = 0;
+
+ /**
+ * Continuation member functions
+ */
+ virtual nsIFrame* GetPrevContinuation() const = 0;
+ virtual void SetPrevContinuation(nsIFrame*) = 0;
+ virtual nsIFrame* GetNextContinuation() const = 0;
+ virtual void SetNextContinuation(nsIFrame*) = 0;
+ virtual nsIFrame* FirstContinuation() const {
+ return const_cast<nsIFrame*>(this);
+ }
+ virtual nsIFrame* LastContinuation() const {
+ return const_cast<nsIFrame*>(this);
+ }
+
+ /**
+ * GetTailContinuation gets the last non-overflow-container continuation
+ * in the continuation chain, i.e. where the next sibling element
+ * should attach).
+ */
+ nsIFrame* GetTailContinuation();
+
+ /**
+ * Flow member functions
+ */
+ virtual nsIFrame* GetPrevInFlowVirtual() const = 0;
+ nsIFrame* GetPrevInFlow() const { return GetPrevInFlowVirtual(); }
+ virtual void SetPrevInFlow(nsIFrame*) = 0;
+
+ virtual nsIFrame* GetNextInFlowVirtual() const = 0;
+ nsIFrame* GetNextInFlow() const { return GetNextInFlowVirtual(); }
+ virtual void SetNextInFlow(nsIFrame*) = 0;
+
+ /**
+ * Return the first frame in our current flow.
+ */
+ virtual nsIFrame* FirstInFlow() const {
+ return const_cast<nsIFrame*>(this);
+ }
+
+ /**
+ * Return the last frame in our current flow.
+ */
+ virtual nsIFrame* LastInFlow() const {
+ return const_cast<nsIFrame*>(this);
+ }
+
+ /**
+ * Note: "width" in the names and comments on the following methods
+ * means inline-size, which could be height in vertical layout
+ */
+
+ /**
+ * Mark any stored intrinsic width information as dirty (requiring
+ * re-calculation). Note that this should generally not be called
+ * directly; nsPresShell::FrameNeedsReflow will call it instead.
+ */
+ virtual void MarkIntrinsicISizesDirty() = 0;
+
+ /**
+ * Get the min-content intrinsic inline size of the frame. This must be
+ * less than or equal to the max-content intrinsic inline size.
+ *
+ * This is *not* affected by the CSS 'min-width', 'width', and
+ * 'max-width' properties on this frame, but it is affected by the
+ * values of those properties on this frame's descendants. (It may be
+ * called during computation of the values of those properties, so it
+ * cannot depend on any values in the nsStylePosition for this frame.)
+ *
+ * The value returned should **NOT** include the space required for
+ * padding and border.
+ *
+ * Note that many frames will cache the result of this function call
+ * unless MarkIntrinsicISizesDirty is called.
+ *
+ * It is not acceptable for a frame to mark itself dirty when this
+ * method is called.
+ *
+ * This method must not return a negative value.
+ */
+ virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) = 0;
+
+ /**
+ * Get the max-content intrinsic inline size of the frame. This must be
+ * greater than or equal to the min-content intrinsic inline size.
+ *
+ * Otherwise, all the comments for |GetMinISize| above apply.
+ */
+ virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) = 0;
+
+ /**
+ * |InlineIntrinsicISize| represents the intrinsic width information
+ * in inline layout. Code that determines the intrinsic width of a
+ * region of inline layout accumulates the result into this structure.
+ * This pattern is needed because we need to maintain state
+ * information about whitespace (for both collapsing and trimming).
+ */
+ struct InlineIntrinsicISizeData {
+ InlineIntrinsicISizeData()
+ : mLine(nullptr)
+ , mLineContainer(nullptr)
+ , mPrevLines(0)
+ , mCurrentLine(0)
+ , mTrailingWhitespace(0)
+ , mSkipWhitespace(true)
+ {}
+
+ // The line. This may be null if the inlines are not associated with
+ // a block or if we just don't know the line.
+ const nsLineList_iterator* mLine;
+
+ // The line container. Private, to ensure we always use SetLineContainer
+ // to update it (so that we have a chance to store the mLineContainerWM).
+ //
+ // Note that nsContainerFrame::DoInlineIntrinsicISize will clear the
+ // |mLine| and |mLineContainer| fields when following a next-in-flow link,
+ // so we must not assume these can always be dereferenced.
+ private:
+ nsIFrame* mLineContainer;
+
+ // Setter and getter for the lineContainer field:
+ public:
+ void SetLineContainer(nsIFrame* aLineContainer)
+ {
+ mLineContainer = aLineContainer;
+ if (mLineContainer) {
+ mLineContainerWM = mLineContainer->GetWritingMode();
+ }
+ }
+ nsIFrame* LineContainer() const { return mLineContainer; }
+
+ // The maximum intrinsic width for all previous lines.
+ nscoord mPrevLines;
+
+ // The maximum intrinsic width for the current line. At a line
+ // break (mandatory for preferred width; allowed for minimum width),
+ // the caller should call |Break()|.
+ nscoord mCurrentLine;
+
+ // This contains the width of the trimmable whitespace at the end of
+ // |mCurrentLine|; it is zero if there is no such whitespace.
+ nscoord mTrailingWhitespace;
+
+ // True if initial collapsable whitespace should be skipped. This
+ // should be true at the beginning of a block, after hard breaks
+ // and when the last text ended with whitespace.
+ bool mSkipWhitespace;
+
+ // Writing mode of the line container (stored here so that we don't
+ // lose track of it if the mLineContainer field is reset).
+ mozilla::WritingMode mLineContainerWM;
+
+ // Floats encountered in the lines.
+ class FloatInfo {
+ public:
+ FloatInfo(const nsIFrame* aFrame, nscoord aWidth)
+ : mFrame(aFrame), mWidth(aWidth)
+ { }
+ const nsIFrame* Frame() const { return mFrame; }
+ nscoord Width() const { return mWidth; }
+
+ private:
+ const nsIFrame* mFrame;
+ nscoord mWidth;
+ };
+
+ nsTArray<FloatInfo> mFloats;
+ };
+
+ struct InlineMinISizeData : public InlineIntrinsicISizeData {
+ InlineMinISizeData()
+ : mAtStartOfLine(true)
+ {}
+
+ // The default implementation for nsIFrame::AddInlineMinISize.
+ void DefaultAddInlineMinISize(nsIFrame* aFrame,
+ nscoord aISize,
+ bool aAllowBreak = true);
+
+ // We need to distinguish forced and optional breaks for cases where the
+ // current line total is negative. When it is, we need to ignore
+ // optional breaks to prevent min-width from ending up bigger than
+ // pref-width.
+ void ForceBreak();
+
+ // If the break here is actually taken, aHyphenWidth must be added to the
+ // width of the current line.
+ void OptionallyBreak(nscoord aHyphenWidth = 0);
+
+ // Whether we're currently at the start of the line. If we are, we
+ // can't break (for example, between the text-indent and the first
+ // word).
+ bool mAtStartOfLine;
+ };
+
+ struct InlinePrefISizeData : public InlineIntrinsicISizeData {
+ void ForceBreak();
+
+ // The default implementation for nsIFrame::AddInlinePrefISize.
+ void DefaultAddInlinePrefISize(nscoord aISize);
+ };
+
+ /**
+ * Add the intrinsic minimum width of a frame in a way suitable for
+ * use in inline layout to an |InlineIntrinsicISizeData| object that
+ * represents the intrinsic width information of all the previous
+ * frames in the inline layout region.
+ *
+ * All *allowed* breakpoints within the frame determine what counts as
+ * a line for the |InlineIntrinsicISizeData|. This means that
+ * |aData->mTrailingWhitespace| will always be zero (unlike for
+ * AddInlinePrefISize).
+ *
+ * All the comments for |GetMinISize| apply, except that this function
+ * is responsible for adding padding, border, and margin and for
+ * considering the effects of 'width', 'min-width', and 'max-width'.
+ *
+ * This may be called on any frame. Frames that do not participate in
+ * line breaking can inherit the default implementation on nsFrame,
+ * which calls |GetMinISize|.
+ */
+ virtual void
+ AddInlineMinISize(nsRenderingContext *aRenderingContext,
+ InlineMinISizeData *aData) = 0;
+
+ /**
+ * Add the intrinsic preferred width of a frame in a way suitable for
+ * use in inline layout to an |InlineIntrinsicISizeData| object that
+ * represents the intrinsic width information of all the previous
+ * frames in the inline layout region.
+ *
+ * All the comments for |AddInlineMinISize| and |GetPrefISize| apply,
+ * except that this fills in an |InlineIntrinsicISizeData| structure
+ * based on using all *mandatory* breakpoints within the frame.
+ */
+ virtual void
+ AddInlinePrefISize(nsRenderingContext *aRenderingContext,
+ InlinePrefISizeData *aData) = 0;
+
+ /**
+ * Return the horizontal components of padding, border, and margin
+ * that contribute to the intrinsic width that applies to the parent.
+ */
+ struct IntrinsicISizeOffsetData {
+ nscoord hPadding, hBorder, hMargin;
+ float hPctPadding, hPctMargin;
+
+ IntrinsicISizeOffsetData()
+ : hPadding(0), hBorder(0), hMargin(0)
+ , hPctPadding(0.0f), hPctMargin(0.0f)
+ {}
+ };
+ virtual IntrinsicISizeOffsetData IntrinsicISizeOffsets() = 0;
+
+ /**
+ * Return the bsize components of padding, border, and margin
+ * that contribute to the intrinsic width that applies to the parent.
+ */
+ IntrinsicISizeOffsetData IntrinsicBSizeOffsets();
+
+ virtual mozilla::IntrinsicSize GetIntrinsicSize() = 0;
+
+ /**
+ * Get the intrinsic ratio of this element, or nsSize(0,0) if it has
+ * no intrinsic ratio. The intrinsic ratio is the ratio of the
+ * height/width of a box with an intrinsic size or the intrinsic
+ * aspect ratio of a scalable vector image without an intrinsic size.
+ *
+ * Either one of the sides may be zero, indicating a zero or infinite
+ * ratio.
+ */
+ virtual nsSize GetIntrinsicRatio() = 0;
+
+ /**
+ * Bit-flags to pass to ComputeSize in |aFlags| parameter.
+ */
+ enum ComputeSizeFlags {
+ eDefault = 0,
+ /**
+ * Set if the frame is in a context where non-replaced blocks should
+ * shrink-wrap (e.g., it's floating, absolutely positioned, or
+ * inline-block).
+ */
+ eShrinkWrap = 1 << 0,
+ /**
+ * Set if we'd like to compute our 'auto' bsize, regardless of our actual
+ * corresponding computed value. (e.g. to get an intrinsic height for flex
+ * items with "min-height: auto" to use during flexbox layout.)
+ */
+ eUseAutoBSize = 1 << 1,
+ /**
+ * Indicates that we should clamp the margin-box min-size to the given CB
+ * size. This is used for implementing the grid area clamping here:
+ * https://drafts.csswg.org/css-grid/#min-size-auto
+ */
+ eIClampMarginBoxMinSize = 1 << 2, // clamp in our inline axis
+ eBClampMarginBoxMinSize = 1 << 3, // clamp in our block axis
+ };
+
+ /**
+ * Compute the size that a frame will occupy. Called while
+ * constructing the ReflowInput to be used to Reflow the frame,
+ * in order to fill its mComputedWidth and mComputedHeight member
+ * variables.
+ *
+ * The |height| member of the return value may be
+ * NS_UNCONSTRAINEDSIZE, but the |width| member must not be.
+ *
+ * Note that the reason that border and padding need to be passed
+ * separately is so that the 'box-sizing' property can be handled.
+ * Thus aMargin includes absolute positioning offsets as well.
+ *
+ * @param aWritingMode The writing mode to use for the returned size
+ * (need not match this frame's writing mode).
+ * This is also the writing mode of the passed-in
+ * LogicalSize parameters.
+ * @param aCBSize The size of the element's containing block. (Well,
+ * the |height| component isn't really.)
+ * @param aAvailableWidth The available width for 'auto' widths.
+ * This is usually the same as aCBSize.width,
+ * but differs in cases such as block
+ * formatting context roots next to floats, or
+ * in some cases of float reflow in quirks
+ * mode.
+ * @param aMargin The sum of the vertical / horizontal margins
+ * ***AND*** absolute positioning offsets (top, right,
+ * bottom, left) of the frame, including actual values
+ * resulting from percentages and from the
+ * "hypothetical box" for absolute positioning, but
+ * not including actual values resulting from 'auto'
+ * margins or ignored 'auto' values in absolute
+ * positioning.
+ * @param aBorder The sum of the vertical / horizontal border widths
+ * of the frame.
+ * @param aPadding The sum of the vertical / horizontal margins of
+ * the frame, including actual values resulting from
+ * percentages.
+ * @param aFlags Flags to further customize behavior (definitions above).
+ */
+ virtual mozilla::LogicalSize
+ ComputeSize(nsRenderingContext *aRenderingContext,
+ mozilla::WritingMode aWritingMode,
+ const mozilla::LogicalSize& aCBSize,
+ nscoord aAvailableISize,
+ const mozilla::LogicalSize& aMargin,
+ const mozilla::LogicalSize& aBorder,
+ const mozilla::LogicalSize& aPadding,
+ ComputeSizeFlags aFlags) = 0;
+
+ /**
+ * Compute a tight bounding rectangle for the frame. This is a rectangle
+ * that encloses the pixels that are actually drawn. We're allowed to be
+ * conservative and currently we don't try very hard. The rectangle is
+ * in appunits and relative to the origin of this frame.
+ *
+ * This probably only needs to include frame bounds, glyph bounds, and
+ * text decorations, but today it sometimes includes other things that
+ * contribute to visual overflow.
+ *
+ * @param aDrawTarget a draw target that can be used if we need
+ * to do measurement
+ */
+ virtual nsRect ComputeTightBounds(DrawTarget* aDrawTarget) const;
+
+ /**
+ * This function is similar to GetPrefISize and ComputeTightBounds: it
+ * computes the left and right coordinates of a preferred tight bounding
+ * rectangle for the frame. This is a rectangle that would enclose the pixels
+ * that are drawn if we lay out the element without taking any optional line
+ * breaks. The rectangle is in appunits and relative to the origin of this
+ * frame. Currently, this function is only implemented for nsBlockFrame and
+ * nsTextFrame and is used to determine intrinsic widths of MathML token
+ * elements.
+
+ * @param aContext a rendering context that can be used if we need
+ * to do measurement
+ * @param aX computed left coordinate of the tight bounding rectangle
+ * @param aXMost computed intrinsic width of the tight bounding rectangle
+ *
+ */
+ virtual nsresult GetPrefWidthTightBounds(nsRenderingContext* aContext,
+ nscoord* aX,
+ nscoord* aXMost);
+
+ /**
+ * The frame is given an available size and asked for its desired
+ * size. This is the frame's opportunity to reflow its children.
+ *
+ * If the frame has the NS_FRAME_IS_DIRTY bit set then it is
+ * responsible for completely reflowing itself and all of its
+ * descendants.
+ *
+ * Otherwise, if the frame has the NS_FRAME_HAS_DIRTY_CHILDREN bit
+ * set, then it is responsible for reflowing at least those
+ * children that have NS_FRAME_HAS_DIRTY_CHILDREN or NS_FRAME_IS_DIRTY
+ * set.
+ *
+ * If a difference in available size from the previous reflow causes
+ * the frame's size to change, it should reflow descendants as needed.
+ *
+ * @param aReflowOutput <i>out</i> parameter where you should return the
+ * desired size and ascent/descent info. You should include any
+ * space you want for border/padding in the desired size you return.
+ *
+ * It's okay to return a desired size that exceeds the avail
+ * size if that's the smallest you can be, i.e. it's your
+ * minimum size.
+ *
+ * For an incremental reflow you are responsible for invalidating
+ * any area within your frame that needs repainting (including
+ * borders). If your new desired size is different than your current
+ * size, then your parent frame is responsible for making sure that
+ * the difference between the two rects is repainted
+ *
+ * @param aReflowInput information about your reflow including the reason
+ * for the reflow and the available space in which to lay out. Each
+ * dimension of the available space can either be constrained or
+ * unconstrained (a value of NS_UNCONSTRAINEDSIZE).
+ *
+ * Note that the available space can be negative. In this case you
+ * still must return an accurate desired size. If you're a container
+ * you must <b>always</b> reflow at least one frame regardless of the
+ * available space
+ *
+ * @param aStatus a return value indicating whether the frame is complete
+ * and whether the next-in-flow is dirty and needs to be reflowed
+ */
+ virtual void Reflow(nsPresContext* aPresContext,
+ ReflowOutput& aReflowOutput,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus) = 0;
+
+ /**
+ * Post-reflow hook. After a frame is reflowed this method will be called
+ * informing the frame that this reflow process is complete, and telling the
+ * frame the status returned by the Reflow member function.
+ *
+ * This call may be invoked many times, while NS_FRAME_IN_REFLOW is set, before
+ * it is finally called once with a NS_FRAME_REFLOW_COMPLETE value. When called
+ * with a NS_FRAME_REFLOW_COMPLETE value the NS_FRAME_IN_REFLOW bit in the
+ * frame state will be cleared.
+ *
+ * XXX This doesn't make sense. If the frame is reflowed but not complete, then
+ * the status should be NS_FRAME_NOT_COMPLETE and not NS_FRAME_COMPLETE
+ * XXX Don't we want the semantics to dictate that we only call this once for
+ * a given reflow?
+ */
+ virtual void DidReflow(nsPresContext* aPresContext,
+ const ReflowInput* aReflowInput,
+ nsDidReflowStatus aStatus) = 0;
+
+ /**
+ * Updates the overflow areas of the frame. This can be called if an
+ * overflow area of the frame's children has changed without reflowing.
+ * @return true if either of the overflow areas for this frame have changed.
+ */
+ bool UpdateOverflow();
+
+ /**
+ * Computes any overflow area created by the frame itself (outside of the
+ * frame bounds) and includes it into aOverflowAreas.
+ *
+ * Returns false if updating overflow isn't supported for this frame.
+ * If the frame requires a reflow instead, then it is responsible
+ * for scheduling one.
+ */
+ virtual bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) = 0;
+
+ /**
+ * Computes any overflow area created by children of this frame and
+ * includes it into aOverflowAreas.
+ */
+ virtual void UnionChildOverflow(nsOverflowAreas& aOverflowAreas) = 0;
+
+ /**
+ * Helper method used by block reflow to identify runs of text so
+ * that proper word-breaking can be done.
+ *
+ * @return
+ * true if we can continue a "text run" through the frame. A
+ * text run is text that should be treated contiguously for line
+ * and word breaking.
+ */
+ virtual bool CanContinueTextRun() const = 0;
+
+ /**
+ * Computes an approximation of the rendered text of the frame and its
+ * continuations. Returns nothing for non-text frames.
+ * The appended text will often not contain all the whitespace from source,
+ * depending on CSS white-space processing.
+ * if aEndOffset goes past end, use the text up to the string's end.
+ * Call this on the primary frame for a text node.
+ * aStartOffset and aEndOffset can be content offsets or offsets in the
+ * rendered text, depending on aOffsetType.
+ * Returns a string, as well as offsets identifying the start of the text
+ * within the rendered text for the whole node, and within the text content
+ * of the node.
+ */
+ struct RenderedText {
+ nsAutoString mString;
+ uint32_t mOffsetWithinNodeRenderedText;
+ int32_t mOffsetWithinNodeText;
+ RenderedText() : mOffsetWithinNodeRenderedText(0),
+ mOffsetWithinNodeText(0) {}
+ };
+ enum class TextOffsetType {
+ // Passed-in start and end offsets are within the content text.
+ OFFSETS_IN_CONTENT_TEXT,
+ // Passed-in start and end offsets are within the rendered text.
+ OFFSETS_IN_RENDERED_TEXT
+ };
+ enum class TrailingWhitespace {
+ TRIM_TRAILING_WHITESPACE,
+ // Spaces preceding a caret at the end of a line should not be trimmed
+ DONT_TRIM_TRAILING_WHITESPACE
+ };
+ virtual RenderedText GetRenderedText(uint32_t aStartOffset = 0,
+ uint32_t aEndOffset = UINT32_MAX,
+ TextOffsetType aOffsetType =
+ TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
+ TrailingWhitespace aTrimTrailingWhitespace =
+ TrailingWhitespace::TRIM_TRAILING_WHITESPACE)
+ { return RenderedText(); }
+
+ /**
+ * Returns true if the frame contains any non-collapsed characters.
+ * This method is only available for text frames, and it will return false
+ * for all other frame types.
+ */
+ virtual bool HasAnyNoncollapsedCharacters()
+ { return false; }
+
+ /**
+ * Accessor functions to get/set the associated view object
+ *
+ * GetView returns non-null if and only if |HasView| returns true.
+ */
+ bool HasView() const { return !!(mState & NS_FRAME_HAS_VIEW); }
+ nsView* GetView() const;
+ nsresult SetView(nsView* aView);
+
+ /**
+ * Find the closest view (on |this| or an ancestor).
+ * If aOffset is non-null, it will be set to the offset of |this|
+ * from the returned view.
+ */
+ nsView* GetClosestView(nsPoint* aOffset = nullptr) const;
+
+ /**
+ * Find the closest ancestor (excluding |this| !) that has a view
+ */
+ nsIFrame* GetAncestorWithView() const;
+
+ /**
+ * Get the offset between the coordinate systems of |this| and aOther.
+ * Adding the return value to a point in the coordinate system of |this|
+ * will transform the point to the coordinate system of aOther.
+ *
+ * aOther must be non-null.
+ *
+ * This function is fastest when aOther is an ancestor of |this|.
+ *
+ * This function _DOES NOT_ work across document boundaries.
+ * Use this function only when |this| and aOther are in the same document.
+ *
+ * NOTE: this actually returns the offset from aOther to |this|, but
+ * that offset is added to transform _coordinates_ from |this| to
+ * aOther.
+ */
+ nsPoint GetOffsetTo(const nsIFrame* aOther) const;
+
+ /**
+ * Get the offset between the coordinate systems of |this| and aOther
+ * expressed in appunits per dev pixel of |this|' document. Adding the return
+ * value to a point that is relative to the origin of |this| will make the
+ * point relative to the origin of aOther but in the appunits per dev pixel
+ * ratio of |this|.
+ *
+ * aOther must be non-null.
+ *
+ * This function is fastest when aOther is an ancestor of |this|.
+ *
+ * This function works across document boundaries.
+ *
+ * Because this function may cross document boundaries that have different
+ * app units per dev pixel ratios it needs to be used very carefully.
+ *
+ * NOTE: this actually returns the offset from aOther to |this|, but
+ * that offset is added to transform _coordinates_ from |this| to
+ * aOther.
+ */
+ nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther) const;
+
+ /**
+ * Like GetOffsetToCrossDoc, but the caller can specify which appunits
+ * to return the result in.
+ */
+ nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther, const int32_t aAPD) const;
+
+ /**
+ * Get the screen rect of the frame in pixels.
+ * @return the pixel rect of the frame in screen coordinates.
+ */
+ nsIntRect GetScreenRect() const;
+
+ /**
+ * Get the screen rect of the frame in app units.
+ * @return the app unit rect of the frame in screen coordinates.
+ */
+ nsRect GetScreenRectInAppUnits() const;
+
+ /**
+ * Returns the offset from this frame to the closest geometric parent that
+ * has a view. Also returns the containing view or null in case of error
+ */
+ void GetOffsetFromView(nsPoint& aOffset, nsView** aView) const;
+
+ /**
+ * Returns the nearest widget containing this frame. If this frame has a
+ * view and the view has a widget, then this frame's widget is
+ * returned, otherwise this frame's geometric parent is checked
+ * recursively upwards.
+ */
+ nsIWidget* GetNearestWidget() const;
+
+ /**
+ * Same as GetNearestWidget() above but uses an outparam to return the offset
+ * of this frame to the returned widget expressed in appunits of |this| (the
+ * widget might be in a different document with a different zoom).
+ */
+ nsIWidget* GetNearestWidget(nsPoint& aOffset) const;
+
+ /**
+ * Get the "type" of the frame. May return nullptr.
+ *
+ * @see nsGkAtoms
+ */
+ virtual nsIAtom* GetType() const = 0;
+
+ /**
+ * Returns a transformation matrix that converts points in this frame's
+ * coordinate space to points in some ancestor frame's coordinate space.
+ * The frame decides which ancestor it will use as a reference point.
+ * If this frame has no ancestor, aOutAncestor will be set to null.
+ *
+ * @param aStopAtAncestor don't look further than aStopAtAncestor. If null,
+ * all ancestors (including across documents) will be traversed.
+ * @param aOutAncestor [out] The ancestor frame the frame has chosen. If
+ * this frame has no ancestor, *aOutAncestor will be set to null. If
+ * this frame is not a root frame, then *aOutAncestor will be in the same
+ * document as this frame. If this frame IsTransformed(), then *aOutAncestor
+ * will be the parent frame (if not preserve-3d) or the nearest non-transformed
+ * ancestor (if preserve-3d).
+ * @return A Matrix4x4 that converts points in this frame's coordinate space
+ * into points in aOutAncestor's coordinate space.
+ */
+ Matrix4x4 GetTransformMatrix(const nsIFrame* aStopAtAncestor,
+ nsIFrame **aOutAncestor);
+
+ /**
+ * Bit-flags to pass to IsFrameOfType()
+ */
+ enum {
+ eMathML = 1 << 0,
+ eSVG = 1 << 1,
+ eSVGForeignObject = 1 << 2,
+ eSVGContainer = 1 << 3,
+ eSVGGeometry = 1 << 4,
+ eSVGPaintServer = 1 << 5,
+ eBidiInlineContainer = 1 << 6,
+ // the frame is for a replaced element, such as an image
+ eReplaced = 1 << 7,
+ // Frame that contains a block but looks like a replaced element
+ // from the outside
+ eReplacedContainsBlock = 1 << 8,
+ // A frame that participates in inline reflow, i.e., one that
+ // requires ReflowInput::mLineLayout.
+ eLineParticipant = 1 << 9,
+ eXULBox = 1 << 10,
+ eCanContainOverflowContainers = 1 << 11,
+ eBlockFrame = 1 << 12,
+ eTablePart = 1 << 13,
+ // If this bit is set, the frame doesn't allow ignorable whitespace as
+ // children. For example, the whitespace between <table>\n<tr>\n<td>
+ // will be excluded during the construction of children.
+ eExcludesIgnorableWhitespace = 1 << 14,
+ eSupportsCSSTransforms = 1 << 15,
+
+ // A replaced element that has replaced-element sizing
+ // characteristics (i.e., like images or iframes), as opposed to
+ // inline-block sizing characteristics (like form controls).
+ eReplacedSizing = 1 << 16,
+
+ // These are to allow nsFrame::Init to assert that IsFrameOfType
+ // implementations all call the base class method. They are only
+ // meaningful in DEBUG builds.
+ eDEBUGAllFrames = 1 << 30,
+ eDEBUGNoFrames = 1 << 31
+ };
+
+ /**
+ * API for doing a quick check if a frame is of a given
+ * type. Returns true if the frame matches ALL flags passed in.
+ *
+ * Implementations should always override with inline virtual
+ * functions that call the base class's IsFrameOfType method.
+ */
+ virtual bool IsFrameOfType(uint32_t aFlags) const
+ {
+#ifdef DEBUG
+ return !(aFlags & ~(nsIFrame::eDEBUGAllFrames | nsIFrame::eSupportsCSSTransforms));
+#else
+ return !(aFlags & ~nsIFrame::eSupportsCSSTransforms);
+#endif
+ }
+
+ /**
+ * Returns true if the frame is a block wrapper.
+ */
+ bool IsBlockWrapper() const;
+
+ /**
+ * Get this frame's CSS containing block.
+ *
+ * The algorithm is defined in
+ * http://www.w3.org/TR/CSS2/visudet.html#containing-block-details.
+ *
+ * NOTE: This is guaranteed to return a non-null pointer when invoked on any
+ * frame other than the root frame.
+ *
+ * Requires SKIP_SCROLLED_FRAME to get behaviour matching the spec, otherwise
+ * it can return anonymous inner scrolled frames. Bug 1204044 is filed for
+ * investigating whether any of the callers actually require the default
+ * behaviour.
+ */
+ enum {
+ // If the containing block is an anonymous scrolled frame, then skip over
+ // this and return the outer scroll frame.
+ SKIP_SCROLLED_FRAME = 0x01
+ };
+ nsIFrame* GetContainingBlock(uint32_t aFlags = 0) const;
+
+ /**
+ * Is this frame a containing block for floating elements?
+ * Note that very few frames are, so default to false.
+ */
+ virtual bool IsFloatContainingBlock() const { return false; }
+
+ /**
+ * Is this a leaf frame? Frames that want the frame constructor to be able
+ * to construct kids for them should return false, all others should return
+ * true. Note that returning true here does not mean that the frame _can't_
+ * have kids. It could still have kids created via
+ * nsIAnonymousContentCreator. Returning true indicates that "normal"
+ * (non-anonymous, XBL-bound, CSS generated content, etc) children should not
+ * be constructed.
+ */
+ virtual bool IsLeaf() const;
+
+ /**
+ * Marks all display items created by this frame as needing a repaint,
+ * and calls SchedulePaint() if requested and one is not already pending.
+ *
+ * This includes all display items created by this frame, including
+ * container types.
+ *
+ * @param aDisplayItemKey If specified, only issues an invalidate
+ * if this frame painted a display item of that type during the
+ * previous paint. SVG rendering observers are always notified.
+ */
+ virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0);
+
+ /**
+ * Same as InvalidateFrame(), but only mark a fixed rect as needing
+ * repainting.
+ *
+ * @param aRect The rect to invalidate, relative to the TopLeft of the
+ * frame's border box.
+ * @param aDisplayItemKey If specified, only issues an invalidate
+ * if this frame painted a display item of that type during the
+ * previous paint. SVG rendering observers are always notified.
+ */
+ virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0);
+
+ /**
+ * Calls InvalidateFrame() on all frames descendant frames (including
+ * this one).
+ *
+ * This function doesn't walk through placeholder frames to invalidate
+ * the out-of-flow frames.
+ *
+ * @param aDisplayItemKey If specified, only issues an invalidate
+ * if this frame painted a display item of that type during the
+ * previous paint. SVG rendering observers are always notified.
+ */
+ void InvalidateFrameSubtree(uint32_t aDisplayItemKey = 0);
+
+ /**
+ * Called when a frame is about to be removed and needs to be invalidated.
+ * Normally does nothing since DLBI handles removed frames.
+ */
+ virtual void InvalidateFrameForRemoval() {}
+
+ /**
+ * When HasUserData(frame->LayerIsPrerenderedDataKey()), then the
+ * entire overflow area of this frame has been rendered in its
+ * layer(s).
+ */
+ static void* LayerIsPrerenderedDataKey() {
+ return &sLayerIsPrerenderedDataKey;
+ }
+ static uint8_t sLayerIsPrerenderedDataKey;
+
+ /**
+ * Try to update this frame's transform without invalidating any
+ * content. Return true iff successful. If unsuccessful, the
+ * caller is responsible for scheduling an invalidating paint.
+ *
+ * If the result is true, aLayerResult will be filled in with the
+ * transform layer for the frame.
+ */
+ bool TryUpdateTransformOnly(Layer** aLayerResult);
+
+ /**
+ * Checks if a frame has had InvalidateFrame() called on it since the
+ * last paint.
+ *
+ * If true, then the invalid rect is returned in aRect, with an
+ * empty rect meaning all pixels drawn by this frame should be
+ * invalidated.
+ * If false, aRect is left unchanged.
+ */
+ bool IsInvalid(nsRect& aRect);
+
+ /**
+ * Check if any frame within the frame subtree (including this frame)
+ * returns true for IsInvalid().
+ */
+ bool HasInvalidFrameInSubtree()
+ {
+ return HasAnyStateBits(NS_FRAME_NEEDS_PAINT | NS_FRAME_DESCENDANT_NEEDS_PAINT);
+ }
+
+ /**
+ * Removes the invalid state from the current frame and all
+ * descendant frames.
+ */
+ void ClearInvalidationStateBits();
+
+ /**
+ * Ensures that the refresh driver is running, and schedules a view
+ * manager flush on the next tick.
+ *
+ * The view manager flush will update the layer tree, repaint any
+ * invalid areas in the layer tree and schedule a layer tree
+ * composite operation to display the layer tree.
+ *
+ * In general it is not necessary for frames to call this when they change.
+ * For example, changes that result in a reflow will have this called for
+ * them by PresContext::DoReflow when the reflow begins. Style changes that
+ * do not trigger a reflow should have this called for them by
+ * DoApplyRenderingChangeToTree.
+ *
+ * @param aType PAINT_COMPOSITE_ONLY : No changes have been made
+ * that require a layer tree update, so only schedule a layer
+ * tree composite.
+ * PAINT_DELAYED_COMPRESS : Schedule a paint to be executed after a delay, and
+ * put FrameLayerBuilder in 'compressed' mode that avoids short cut optimizations.
+ */
+ enum PaintType {
+ PAINT_DEFAULT = 0,
+ PAINT_COMPOSITE_ONLY,
+ PAINT_DELAYED_COMPRESS
+ };
+ void SchedulePaint(PaintType aType = PAINT_DEFAULT);
+
+ /**
+ * Checks if the layer tree includes a dedicated layer for this
+ * frame/display item key pair, and invalidates at least aDamageRect
+ * area within that layer.
+ *
+ * If no layer is found, calls InvalidateFrame() instead.
+ *
+ * @param aDamageRect Area of the layer to invalidate.
+ * @param aFrameDamageRect If no layer is found, the area of the frame to
+ * invalidate. If null, the entire frame will be
+ * invalidated.
+ * @param aDisplayItemKey Display item type.
+ * @param aFlags UPDATE_IS_ASYNC : Will skip the invalidation
+ * if the found layer is being composited by a remote
+ * compositor.
+ * @return Layer, if found, nullptr otherwise.
+ */
+ enum {
+ UPDATE_IS_ASYNC = 1 << 0
+ };
+ Layer* InvalidateLayer(uint32_t aDisplayItemKey,
+ const nsIntRect* aDamageRect = nullptr,
+ const nsRect* aFrameDamageRect = nullptr,
+ uint32_t aFlags = 0);
+
+ /**
+ * Returns a rect that encompasses everything that might be painted by
+ * this frame. This includes this frame, all its descendant frames, this
+ * frame's outline, and descendant frames' outline, but does not include
+ * areas clipped out by the CSS "overflow" and "clip" properties.
+ *
+ * HasOverflowRects() (below) will return true when this overflow
+ * rect has been explicitly set, even if it matches mRect.
+ * XXX Note: because of a space optimization using the formula above,
+ * during reflow this function does not give accurate data if
+ * FinishAndStoreOverflow has been called but mRect hasn't yet been
+ * updated yet. FIXME: This actually isn't true, but it should be.
+ *
+ * The visual overflow rect should NEVER be used for things that
+ * affect layout. The scrollable overflow rect is permitted to affect
+ * layout.
+ *
+ * @return the rect relative to this frame's origin, but after
+ * CSS transforms have been applied (i.e. not really this frame's coordinate
+ * system, and may not contain the frame's border-box, e.g. if there
+ * is a CSS transform scaling it down)
+ */
+ nsRect GetVisualOverflowRect() const {
+ return GetOverflowRect(eVisualOverflow);
+ }
+
+ /**
+ * Returns a rect that encompasses the area of this frame that the
+ * user should be able to scroll to reach. This is similar to
+ * GetVisualOverflowRect, but does not include outline or shadows, and
+ * may in the future include more margins than visual overflow does.
+ * It does not include areas clipped out by the CSS "overflow" and
+ * "clip" properties.
+ *
+ * HasOverflowRects() (below) will return true when this overflow
+ * rect has been explicitly set, even if it matches mRect.
+ * XXX Note: because of a space optimization using the formula above,
+ * during reflow this function does not give accurate data if
+ * FinishAndStoreOverflow has been called but mRect hasn't yet been
+ * updated yet.
+ *
+ * @return the rect relative to this frame's origin, but after
+ * CSS transforms have been applied (i.e. not really this frame's coordinate
+ * system, and may not contain the frame's border-box, e.g. if there
+ * is a CSS transform scaling it down)
+ */
+ nsRect GetScrollableOverflowRect() const {
+ return GetOverflowRect(eScrollableOverflow);
+ }
+
+ nsRect GetOverflowRect(nsOverflowType aType) const;
+
+ nsOverflowAreas GetOverflowAreas() const;
+
+ /**
+ * Same as GetOverflowAreas, except in this frame's coordinate
+ * system (before transforms are applied).
+ *
+ * @return the overflow areas relative to this frame, before any CSS transforms have
+ * been applied, i.e. in this frame's coordinate system
+ */
+ nsOverflowAreas GetOverflowAreasRelativeToSelf() const;
+
+ /**
+ * Same as GetScrollableOverflowRect, except relative to the parent
+ * frame.
+ *
+ * @return the rect relative to the parent frame, in the parent frame's
+ * coordinate system
+ */
+ nsRect GetScrollableOverflowRectRelativeToParent() const;
+
+ /**
+ * Same as GetScrollableOverflowRect, except in this frame's coordinate
+ * system (before transforms are applied).
+ *
+ * @return the rect relative to this frame, before any CSS transforms have
+ * been applied, i.e. in this frame's coordinate system
+ */
+ nsRect GetScrollableOverflowRectRelativeToSelf() const;
+
+ /**
+ * Like GetVisualOverflowRect, except in this frame's
+ * coordinate system (before transforms are applied).
+ *
+ * @return the rect relative to this frame, before any CSS transforms have
+ * been applied, i.e. in this frame's coordinate system
+ */
+ nsRect GetVisualOverflowRectRelativeToSelf() const;
+
+ /**
+ * Same as GetVisualOverflowRect, except relative to the parent
+ * frame.
+ *
+ * @return the rect relative to the parent frame, in the parent frame's
+ * coordinate system
+ */
+ nsRect GetVisualOverflowRectRelativeToParent() const;
+
+ /**
+ * Returns this frame's visual overflow rect as it would be before taking
+ * account of SVG effects or transforms. The rect returned is relative to
+ * this frame.
+ */
+ nsRect GetPreEffectsVisualOverflowRect() const;
+
+ /**
+ * Store the overflow area in the frame's mOverflow.mVisualDeltas
+ * fields or as a frame property in the frame manager so that it can
+ * be retrieved later without reflowing the frame. Returns true if either of
+ * the overflow areas changed.
+ */
+ bool FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
+ nsSize aNewSize, nsSize* aOldSize = nullptr);
+
+ bool FinishAndStoreOverflow(ReflowOutput* aMetrics) {
+ return FinishAndStoreOverflow(aMetrics->mOverflowAreas,
+ nsSize(aMetrics->Width(), aMetrics->Height()));
+ }
+
+ /**
+ * Returns whether the frame has an overflow rect that is different from
+ * its border-box.
+ */
+ bool HasOverflowAreas() const {
+ return mOverflow.mType != NS_FRAME_OVERFLOW_NONE;
+ }
+
+ /**
+ * Removes any stored overflow rects (visual and scrollable) from the frame.
+ * Returns true if the overflow changed.
+ */
+ bool ClearOverflowRects();
+
+ /**
+ * Determine whether borders, padding, margins etc should NOT be applied
+ * on certain sides of the frame.
+ * @see mozilla::Sides in gfx/2d/BaseMargin.h
+ * @see mozilla::LogicalSides in layout/generic/WritingModes.h
+ *
+ * @note (See also bug 743402, comment 11) GetSkipSides() checks to see
+ * if this frame has a previous or next continuation to determine
+ * if a side should be skipped.
+ * Unfortunately, this only works after reflow has been completed. In
+ * lieu of this, during reflow, an ReflowInput parameter can be
+ * passed in, indicating that it should be used to determine if sides
+ * should be skipped during reflow.
+ */
+ Sides GetSkipSides(const ReflowInput* aReflowInput = nullptr) const;
+ virtual LogicalSides
+ GetLogicalSkipSides(const ReflowInput* aReflowInput = nullptr) const {
+ return LogicalSides();
+ }
+
+ /**
+ * @returns true if this frame is selected.
+ */
+ bool IsSelected() const;
+
+ /**
+ * called to discover where this frame, or a parent frame has user-select style
+ * applied, which affects that way that it is selected.
+ *
+ * @param aIsSelectable out param. Set to true if the frame can be selected
+ * (i.e. is not affected by user-select: none)
+ * @param aSelectStyle out param. Returns the type of selection style found
+ * (using values defined in nsStyleConsts.h).
+ */
+ virtual nsresult IsSelectable(bool* aIsSelectable,
+ mozilla::StyleUserSelect* aSelectStyle) const = 0;
+
+ /**
+ * Called to retrieve the SelectionController associated with the frame.
+ * @param aSelCon will contain the selection controller associated with
+ * the frame.
+ */
+ virtual nsresult GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon) = 0;
+
+ /**
+ * Call to get nsFrameSelection for this frame.
+ */
+ already_AddRefed<nsFrameSelection> GetFrameSelection();
+
+ /**
+ * GetConstFrameSelection returns an object which methods are safe to use for
+ * example in nsIFrame code.
+ */
+ const nsFrameSelection* GetConstFrameSelection() const;
+
+ /**
+ * called to find the previous/next character, word, or line returns the actual
+ * nsIFrame and the frame offset. THIS DOES NOT CHANGE SELECTION STATE
+ * uses frame's begin selection state to start. if no selection on this frame will
+ * return NS_ERROR_FAILURE
+ * @param aPOS is defined in nsFrameSelection
+ */
+ virtual nsresult PeekOffset(nsPeekOffsetStruct *aPos);
+
+ /**
+ * called to find the previous/next non-anonymous selectable leaf frame.
+ * @param aDirection [in] the direction to move in (eDirPrevious or eDirNext)
+ * @param aVisual [in] whether bidi caret behavior is visual (true) or logical (false)
+ * @param aJumpLines [in] whether to allow jumping across line boundaries
+ * @param aScrollViewStop [in] whether to stop when reaching a scroll frame boundary
+ * @param aOutFrame [out] the previous/next selectable leaf frame
+ * @param aOutOffset [out] 0 indicates that we arrived at the beginning of the output frame;
+ * -1 indicates that we arrived at its end.
+ * @param aOutJumpedLine [out] whether this frame and the returned frame are on different lines
+ * @param aOutMovedOverNonSelectableText [out] whether we jumped over a non-selectable
+ * frame during the search
+ */
+ nsresult GetFrameFromDirection(nsDirection aDirection, bool aVisual,
+ bool aJumpLines, bool aScrollViewStop,
+ nsIFrame** aOutFrame, int32_t* aOutOffset,
+ bool* aOutJumpedLine, bool* aOutMovedOverNonSelectableText);
+
+ /**
+ * called to see if the children of the frame are visible from indexstart to index end.
+ * this does not change any state. returns true only if the indexes are valid and any of
+ * the children are visible. for textframes this index is the character index.
+ * if aStart = aEnd result will be false
+ * @param aStart start index of first child from 0-N (number of children)
+ * @param aEnd end index of last child from 0-N
+ * @param aRecurse should this frame talk to siblings to get to the contents other children?
+ * @param aFinished did this frame have the aEndIndex? or is there more work to do
+ * @param _retval return value true or false. false = range is not rendered.
+ */
+ virtual nsresult CheckVisibility(nsPresContext* aContext, int32_t aStartIndex, int32_t aEndIndex, bool aRecurse, bool *aFinished, bool *_retval)=0;
+
+ /**
+ * Called to tell a frame that one of its child frames is dirty (i.e.,
+ * has the NS_FRAME_IS_DIRTY *or* NS_FRAME_HAS_DIRTY_CHILDREN bit
+ * set). This should always set the NS_FRAME_HAS_DIRTY_CHILDREN on
+ * the frame, and may do other work.
+ */
+ virtual void ChildIsDirty(nsIFrame* aChild) = 0;
+
+ /**
+ * Called to retrieve this frame's accessible.
+ * If this frame implements Accessibility return a valid accessible
+ * If not return NS_ERROR_NOT_IMPLEMENTED.
+ * Note: Accessible must be refcountable. Do not implement directly on your frame
+ * Use a mediatior of some kind.
+ */
+#ifdef ACCESSIBILITY
+ virtual mozilla::a11y::AccType AccessibleType() = 0;
+#endif
+
+ /**
+ * Get the frame whose style context should be the parent of this
+ * frame's style context (i.e., provide the parent style context).
+ * This frame must either be an ancestor of this frame or a child. If
+ * this returns a child frame, then the child frame must be sure to
+ * return a grandparent or higher! Furthermore, if a child frame is
+ * returned it must have the same GetContent() as this frame.
+ *
+ * @param aProviderFrame (out) the frame associated with the returned value
+ * or nullptr if the style context is for display:contents content.
+ * @return The style context that should be the parent of this frame's
+ * style context. Null is permitted, and means that this frame's
+ * style context should be the root of the style context tree.
+ */
+ virtual nsStyleContext* GetParentStyleContext(nsIFrame** aProviderFrame) const = 0;
+
+ /**
+ * Determines whether a frame is visible for painting;
+ * taking into account whether it is painting a selection or printing.
+ */
+ bool IsVisibleForPainting(nsDisplayListBuilder* aBuilder);
+ /**
+ * Determines whether a frame is visible for painting or collapsed;
+ * taking into account whether it is painting a selection or printing,
+ */
+ bool IsVisibleOrCollapsedForPainting(nsDisplayListBuilder* aBuilder);
+ /**
+ * As above, but slower because we have to recompute some stuff that
+ * aBuilder already has.
+ */
+ bool IsVisibleForPainting();
+ /**
+ * Check whether this frame is visible in the current selection. Returns
+ * true if there is no current selection.
+ */
+ bool IsVisibleInSelection(nsDisplayListBuilder* aBuilder);
+
+ /**
+ * Overridable function to determine whether this frame should be considered
+ * "in" the given non-null aSelection for visibility purposes.
+ */
+ virtual bool IsVisibleInSelection(nsISelection* aSelection);
+
+ /**
+ * Determines whether this frame is a pseudo stacking context, looking
+ * only as style --- i.e., assuming that it's in-flow and not a replaced
+ * element and not an SVG element.
+ * XXX maybe check IsTransformed()?
+ */
+ bool IsPseudoStackingContextFromStyle();
+
+ virtual bool HonorPrintBackgroundSettings() { return true; }
+
+ /**
+ * Determine whether the frame is logically empty, which is roughly
+ * whether the layout would be the same whether or not the frame is
+ * present. Placeholder frames should return true. Block frames
+ * should be considered empty whenever margins collapse through them,
+ * even though those margins are relevant. Text frames containing
+ * only whitespace that does not contribute to the height of the line
+ * should return true.
+ */
+ virtual bool IsEmpty() = 0;
+ /**
+ * Return the same as IsEmpty(). This may only be called after the frame
+ * has been reflowed and before any further style or content changes.
+ */
+ virtual bool CachedIsEmpty();
+ /**
+ * Determine whether the frame is logically empty, assuming that all
+ * its children are empty.
+ */
+ virtual bool IsSelfEmpty() = 0;
+
+ /**
+ * IsGeneratedContentFrame returns whether a frame corresponds to
+ * generated content
+ *
+ * @return whether the frame correspods to generated content
+ */
+ bool IsGeneratedContentFrame() const {
+ return (mState & NS_FRAME_GENERATED_CONTENT) != 0;
+ }
+
+ /**
+ * IsPseudoFrame returns whether a frame is a pseudo frame (eg an
+ * anonymous table-row frame created for a CSS table-cell without an
+ * enclosing table-row.
+ *
+ * @param aParentContent the content node corresponding to the parent frame
+ * @return whether the frame is a pseudo frame
+ */
+ bool IsPseudoFrame(const nsIContent* aParentContent) {
+ return mContent == aParentContent;
+ }
+
+ FrameProperties Properties() const {
+ return FrameProperties(PresContext()->PropertyTable(), this);
+ }
+
+ /**
+ * Return true if and only if this frame obeys visibility:hidden.
+ * if it does not, then nsContainerFrame will hide its view even though
+ * this means children can't be made visible again.
+ */
+ virtual bool SupportsVisibilityHidden() { return true; }
+
+ /**
+ * Returns the clip rect set via the 'clip' property, if the 'clip' property
+ * applies to this frame; otherwise returns Nothing(). The 'clip' property
+ * applies to HTML frames if they are absolutely positioned. The 'clip'
+ * property applies to SVG frames regardless of the value of the 'position'
+ * property.
+ *
+ * The coordinates of the returned rectangle are relative to this frame's
+ * origin.
+ */
+ Maybe<nsRect> GetClipPropClipRect(const nsStyleDisplay* aDisp,
+ const nsStyleEffects* aEffects,
+ const nsSize& aSize) const;
+
+ /**
+ * Check if this frame is focusable and in the current tab order.
+ * Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
+ * For example, only the selected radio button in a group is in the
+ * tab order, unless the radio group has no selection in which case
+ * all of the visible, non-disabled radio buttons in the group are
+ * in the tab order. On the other hand, all of the visible, non-disabled
+ * radio buttons are always focusable via clicking or script.
+ * Also, depending on the pref accessibility.tabfocus some widgets may be
+ * focusable but removed from the tab order. This is the default on
+ * Mac OS X, where fewer items are focusable.
+ * @param [in, optional] aTabIndex the computed tab index
+ * < 0 if not tabbable
+ * == 0 if in normal tab order
+ * > 0 can be tabbed to in the order specified by this value
+ * @param [in, optional] aWithMouse, is this focus query for mouse clicking
+ * @return whether the frame is focusable via mouse, kbd or script.
+ */
+ virtual bool IsFocusable(int32_t *aTabIndex = nullptr, bool aWithMouse = false);
+
+ // BOX LAYOUT METHODS
+ // These methods have been migrated from nsIBox and are in the process of
+ // being refactored. DO NOT USE OUTSIDE OF XUL.
+ bool IsXULBoxFrame() const
+ {
+ return IsFrameOfType(nsIFrame::eXULBox);
+ }
+
+ enum Halignment {
+ hAlign_Left,
+ hAlign_Right,
+ hAlign_Center
+ };
+
+ enum Valignment {
+ vAlign_Top,
+ vAlign_Middle,
+ vAlign_BaseLine,
+ vAlign_Bottom
+ };
+
+ /**
+ * This calculates the minimum size required for a box based on its state
+ * @param[in] aBoxLayoutState The desired state to calculate for
+ * @return The minimum size
+ */
+ virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) = 0;
+
+ /**
+ * This calculates the preferred size of a box based on its state
+ * @param[in] aBoxLayoutState The desired state to calculate for
+ * @return The preferred size
+ */
+ virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) = 0;
+
+ /**
+ * This calculates the maximum size for a box based on its state
+ * @param[in] aBoxLayoutState The desired state to calculate for
+ * @return The maximum size
+ */
+ virtual nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState) = 0;
+
+ /**
+ * This returns the minimum size for the scroll area if this frame is
+ * being scrolled. Usually it's (0,0).
+ */
+ virtual nsSize GetXULMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState) = 0;
+
+ // Implemented in nsBox, used in nsBoxFrame
+ uint32_t GetXULOrdinal();
+
+ virtual nscoord GetXULFlex() = 0;
+ virtual nscoord GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState) = 0;
+ virtual bool IsXULCollapsed() = 0;
+ // This does not alter the overflow area. If the caller is changing
+ // the box size, the caller is responsible for updating the overflow
+ // area. It's enough to just call XULLayout or SyncLayout on the
+ // box. You can pass true to aRemoveOverflowArea as a
+ // convenience.
+ virtual void SetXULBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect,
+ bool aRemoveOverflowAreas = false) = 0;
+ nsresult XULLayout(nsBoxLayoutState& aBoxLayoutState);
+ // Box methods. Note that these do NOT just get the CSS border, padding,
+ // etc. They also talk to nsITheme.
+ virtual nsresult GetXULBorderAndPadding(nsMargin& aBorderAndPadding);
+ virtual nsresult GetXULBorder(nsMargin& aBorder)=0;
+ virtual nsresult GetXULPadding(nsMargin& aBorderAndPadding)=0;
+ virtual nsresult GetXULMargin(nsMargin& aMargin)=0;
+ virtual void SetXULLayoutManager(nsBoxLayout* aLayout) { }
+ virtual nsBoxLayout* GetXULLayoutManager() { return nullptr; }
+ nsresult GetXULClientRect(nsRect& aContentRect);
+
+ virtual uint32_t GetXULLayoutFlags()
+ { return 0; }
+
+ // For nsSprocketLayout
+ virtual Valignment GetXULVAlign() const = 0;
+ virtual Halignment GetXULHAlign() const = 0;
+
+ bool IsXULHorizontal() const { return (mState & NS_STATE_IS_HORIZONTAL) != 0; }
+ bool IsXULNormalDirection() const { return (mState & NS_STATE_IS_DIRECTION_NORMAL) != 0; }
+
+ nsresult XULRedraw(nsBoxLayoutState& aState);
+ virtual nsresult XULRelayoutChildAtOrdinal(nsIFrame* aChild)=0;
+
+#ifdef DEBUG_LAYOUT
+ virtual nsresult SetXULDebug(nsBoxLayoutState& aState, bool aDebug)=0;
+ virtual nsresult GetXULDebug(bool& aDebug)=0;
+
+ virtual nsresult XULDumpBox(FILE* out)=0;
+#endif
+
+ static bool AddXULPrefSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth, bool& aHeightSet);
+ static bool AddXULMinSize(nsBoxLayoutState& aState, nsIFrame* aBox,
+ nsSize& aSize, bool& aWidth, bool& aHeightSet);
+ static bool AddXULMaxSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth, bool& aHeightSet);
+ static bool AddXULFlex(nsIFrame* aBox, nscoord& aFlex);
+
+ // END OF BOX LAYOUT METHODS
+ // The above methods have been migrated from nsIBox and are in the process of
+ // being refactored. DO NOT USE OUTSIDE OF XUL.
+
+ /**
+ * @return true if this text frame ends with a newline character. It
+ * should return false if this is not a text frame.
+ */
+ virtual bool HasSignificantTerminalNewline() const;
+
+ struct CaretPosition {
+ CaretPosition();
+ ~CaretPosition();
+
+ nsCOMPtr<nsIContent> mResultContent;
+ int32_t mContentOffset;
+ };
+
+ /**
+ * gets the first or last possible caret position within the frame
+ *
+ * @param [in] aStart
+ * true for getting the first possible caret position
+ * false for getting the last possible caret position
+ * @return The caret position in a CaretPosition.
+ * the returned value is a 'best effort' in case errors
+ * are encountered rummaging through the frame.
+ */
+ CaretPosition GetExtremeCaretPosition(bool aStart);
+
+ /**
+ * Get a line iterator for this frame, if supported.
+ *
+ * @return nullptr if no line iterator is supported.
+ * @note dispose the line iterator using nsILineIterator::DisposeLineIterator
+ */
+ virtual nsILineIterator* GetLineIterator() = 0;
+
+ /**
+ * If this frame is a next-in-flow, and its prev-in-flow has something on its
+ * overflow list, pull those frames into the child list of this one.
+ */
+ virtual void PullOverflowsFromPrevInFlow() {}
+
+ /**
+ * Clear the list of child PresShells generated during the last paint
+ * so that we can begin generating a new one.
+ */
+ void ClearPresShellsFromLastPaint() {
+ PaintedPresShellList()->Clear();
+ }
+
+ /**
+ * Flag a child PresShell as painted so that it will get its paint count
+ * incremented during empty transactions.
+ */
+ void AddPaintedPresShell(nsIPresShell* shell) {
+ PaintedPresShellList()->AppendElement(do_GetWeakReference(shell));
+ }
+
+ /**
+ * Increment the paint count of all child PresShells that were painted during
+ * the last repaint.
+ */
+ void UpdatePaintCountForPaintedPresShells() {
+ for (nsWeakPtr& item : *PaintedPresShellList()) {
+ nsCOMPtr<nsIPresShell> shell = do_QueryReferent(item);
+ if (shell) {
+ shell->IncrementPaintCount();
+ }
+ }
+ }
+
+ /**
+ * @return true if we painted @aShell during the last repaint.
+ */
+ bool DidPaintPresShell(nsIPresShell* aShell)
+ {
+ for (nsWeakPtr& item : *PaintedPresShellList()) {
+ nsCOMPtr<nsIPresShell> shell = do_QueryReferent(item);
+ if (shell == aShell) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Accessors for the absolute containing block.
+ */
+ bool IsAbsoluteContainer() const { return !!(mState & NS_FRAME_HAS_ABSPOS_CHILDREN); }
+ bool HasAbsolutelyPositionedChildren() const;
+ nsAbsoluteContainingBlock* GetAbsoluteContainingBlock() const;
+ void MarkAsAbsoluteContainingBlock();
+ void MarkAsNotAbsoluteContainingBlock();
+ // Child frame types override this function to select their own child list name
+ virtual mozilla::layout::FrameChildListID GetAbsoluteListID() const { return kAbsoluteList; }
+
+ // Checks if we (or any of our descendents) have NS_FRAME_PAINTED_THEBES set, and
+ // clears this bit if so.
+ bool CheckAndClearPaintedState();
+
+ // CSS visibility just doesn't cut it because it doesn't inherit through
+ // documents. Also if this frame is in a hidden card of a deck then it isn't
+ // visible either and that isn't expressed using CSS visibility. Also if it
+ // is in a hidden view (there are a few cases left and they are hopefully
+ // going away soon).
+ // If the VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY flag is passed then we
+ // ignore the chrome/content boundary, otherwise we stop looking when we
+ // reach it.
+ enum {
+ VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY = 0x01
+ };
+ bool IsVisibleConsideringAncestors(uint32_t aFlags = 0) const;
+
+ struct FrameWithDistance
+ {
+ nsIFrame* mFrame;
+ nscoord mXDistance;
+ nscoord mYDistance;
+ };
+
+ /**
+ * Finds a frame that is closer to a specified point than a current
+ * distance. Distance is measured as for text selection -- a closer x
+ * distance beats a closer y distance.
+ *
+ * Normally, this function will only check the distance between this
+ * frame's rectangle and the specified point. SVGTextFrame overrides
+ * this so that it can manage all of its descendant frames and take
+ * into account any SVG text layout.
+ *
+ * If aPoint is closer to this frame's rectangle than aCurrentBestFrame
+ * indicates, then aCurrentBestFrame is updated with the distance between
+ * aPoint and this frame's rectangle, and with a pointer to this frame.
+ * If aPoint is not closer, then aCurrentBestFrame is left unchanged.
+ *
+ * @param aPoint The point to check for its distance to this frame.
+ * @param aCurrentBestFrame Pointer to a struct that will be updated with
+ * a pointer to this frame and its distance to aPoint, if this frame
+ * is indeed closer than the current distance in aCurrentBestFrame.
+ */
+ virtual void FindCloserFrameForSelection(nsPoint aPoint,
+ FrameWithDistance* aCurrentBestFrame);
+
+ /**
+ * Is this a flex item? (i.e. a non-abs-pos child of a flex container)
+ */
+ inline bool IsFlexItem() const;
+ /**
+ * Is this a flex or grid item? (i.e. a non-abs-pos child of a flex/grid container)
+ */
+ inline bool IsFlexOrGridItem() const;
+ inline bool IsFlexOrGridContainer() const;
+
+ /**
+ * @return true if this frame is used as a table caption.
+ */
+ inline bool IsTableCaption() const;
+
+ inline bool IsBlockInside() const;
+ inline bool IsBlockOutside() const;
+ inline bool IsInlineOutside() const;
+ inline mozilla::StyleDisplay GetDisplay() const;
+ inline bool IsFloating() const;
+ inline bool IsAbsPosContainingBlock() const;
+ inline bool IsFixedPosContainingBlock() const;
+ inline bool IsRelativelyPositioned() const;
+ inline bool IsAbsolutelyPositioned() const;
+
+ /**
+ * Returns the vertical-align value to be used for layout, if it is one
+ * of the enumerated values. If this is an SVG text frame, it returns a value
+ * that corresponds to the value of dominant-baseline. If the
+ * vertical-align property has length or percentage value, this returns
+ * eInvalidVerticalAlign.
+ */
+ uint8_t VerticalAlignEnum() const;
+ enum { eInvalidVerticalAlign = 0xFF };
+
+ bool IsSVGText() const { return mState & NS_FRAME_IS_SVG_TEXT; }
+
+ void CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder, nsDisplayList* aList);
+
+ /**
+ * Adds the NS_FRAME_IN_POPUP state bit to aFrame, and
+ * all descendant frames (including cross-doc ones).
+ */
+ static void AddInPopupStateBitToDescendants(nsIFrame* aFrame);
+ /**
+ * Removes the NS_FRAME_IN_POPUP state bit from aFrame and
+ * all descendant frames (including cross-doc ones), unless
+ * the frame is a popup itself.
+ */
+ static void RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame);
+
+ /**
+ * Sorts the given nsFrameList, so that for every two adjacent frames in the
+ * list, the former is less than or equal to the latter, according to the
+ * templated IsLessThanOrEqual method.
+ *
+ * Note: this method uses a stable merge-sort algorithm.
+ */
+ template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
+ static void SortFrameList(nsFrameList& aFrameList);
+
+ /**
+ * Returns true if the given frame list is already sorted, according to the
+ * templated IsLessThanOrEqual function.
+ */
+ template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
+ static bool IsFrameListSorted(nsFrameList& aFrameList);
+
+ /**
+ * Return true if aFrame is in an {ib} split and is NOT one of the
+ * continuations of the first inline in it.
+ */
+ bool FrameIsNonFirstInIBSplit() const {
+ return (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
+ FirstContinuation()->Properties().Get(nsIFrame::IBSplitPrevSibling());
+ }
+
+ /**
+ * Return true if aFrame is in an {ib} split and is NOT one of the
+ * continuations of the last inline in it.
+ */
+ bool FrameIsNonLastInIBSplit() const {
+ return (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
+ FirstContinuation()->Properties().Get(nsIFrame::IBSplitSibling());
+ }
+
+ /**
+ * Return whether this is a frame whose width is used when computing
+ * the font size inflation of its descendants.
+ */
+ bool IsContainerForFontSizeInflation() const {
+ return GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER;
+ }
+
+ /**
+ * Return whether this frame keeps track of overflow areas. (Frames for
+ * non-display SVG elements -- e.g. <clipPath> -- do not maintain overflow
+ * areas, because they're never painted.)
+ */
+ bool FrameMaintainsOverflow() const {
+ return !HasAllStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
+ }
+
+ /**
+ * Returns the content node within the anonymous content that this frame
+ * generated and which corresponds to the specified pseudo-element type,
+ * or nullptr if there is no such anonymous content.
+ */
+ virtual mozilla::dom::Element*
+ GetPseudoElement(mozilla::CSSPseudoElementType aType);
+
+ bool BackfaceIsHidden() const {
+ return StyleDisplay()->BackfaceIsHidden();
+ }
+
+ /**
+ * Returns true if the frame is scrolled out of view.
+ */
+ bool IsScrolledOutOfView();
+
+ /**
+ * If this returns true, the frame it's called on should get the
+ * NS_FRAME_HAS_DIRTY_CHILDREN bit set on it by the caller; either directly
+ * if it's already in reflow, or via calling FrameNeedsReflow() to schedule a
+ * reflow.
+ */
+ virtual bool RenumberFrameAndDescendants(int32_t* aOrdinal,
+ int32_t aDepth,
+ int32_t aIncrement,
+ bool aForCounting) { return false; }
+
+ /**
+ * Helper function - computes the content-box inline size for aCoord.
+ */
+ nscoord ComputeISizeValue(nsRenderingContext* aRenderingContext,
+ nscoord aContainingBlockISize,
+ nscoord aContentEdgeToBoxSizing,
+ nscoord aBoxSizingToMarginEdge,
+ const nsStyleCoord& aCoord,
+ ComputeSizeFlags aFlags = eDefault);
+protected:
+ // Members
+ nsRect mRect;
+ nsIContent* mContent;
+ nsStyleContext* mStyleContext;
+private:
+ nsContainerFrame* mParent;
+ nsIFrame* mNextSibling; // doubly-linked list of frames
+ nsIFrame* mPrevSibling; // Do not touch outside SetNextSibling!
+
+ void MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect);
+
+ static void DestroyPaintedPresShellList(nsTArray<nsWeakPtr>* list) {
+ list->Clear();
+ delete list;
+ }
+
+ // Stores weak references to all the PresShells that were painted during
+ // the last paint event so that we can increment their paint count during
+ // empty transactions
+ NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(PaintedPresShellsProperty,
+ nsTArray<nsWeakPtr>,
+ DestroyPaintedPresShellList)
+
+ nsTArray<nsWeakPtr>* PaintedPresShellList() {
+ nsTArray<nsWeakPtr>* list = Properties().Get(PaintedPresShellsProperty());
+
+ if (!list) {
+ list = new nsTArray<nsWeakPtr>();
+ Properties().Set(PaintedPresShellsProperty(), list);
+ }
+
+ return list;
+ }
+
+protected:
+ void MarkInReflow() {
+#ifdef DEBUG_dbaron_off
+ // bug 81268
+ NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW), "frame is already in reflow");
+#endif
+ mState |= NS_FRAME_IN_REFLOW;
+ }
+
+ nsFrameState mState;
+
+ // When there is an overflow area only slightly larger than mRect,
+ // we store a set of four 1-byte deltas from the edges of mRect
+ // rather than allocating a whole separate rectangle property.
+ // Note that these are unsigned values, all measured "outwards"
+ // from the edges of mRect, so /mLeft/ and /mTop/ are reversed from
+ // our normal coordinate system.
+ // If mOverflow.mType == NS_FRAME_OVERFLOW_LARGE, then the
+ // delta values are not meaningful and the overflow area is stored
+ // as a separate rect property.
+ struct VisualDeltas {
+ uint8_t mLeft;
+ uint8_t mTop;
+ uint8_t mRight;
+ uint8_t mBottom;
+ bool operator==(const VisualDeltas& aOther) const
+ {
+ return mLeft == aOther.mLeft && mTop == aOther.mTop &&
+ mRight == aOther.mRight && mBottom == aOther.mBottom;
+ }
+ bool operator!=(const VisualDeltas& aOther) const
+ {
+ return !(*this == aOther);
+ }
+ };
+ union {
+ uint32_t mType;
+ VisualDeltas mVisualDeltas;
+ } mOverflow;
+
+ // Helpers
+ /**
+ * Can we stop inside this frame when we're skipping non-rendered whitespace?
+ * @param aForward [in] Are we moving forward (or backward) in content order.
+ * @param aOffset [in/out] At what offset into the frame to start looking.
+ * on output - what offset was reached (whether or not we found a place to stop).
+ * @return STOP: An appropriate offset was found within this frame,
+ * and is given by aOffset.
+ * CONTINUE: Not found within this frame, need to try the next frame.
+ * see enum FrameSearchResult for more details.
+ */
+ virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) = 0;
+
+ /**
+ * Search the frame for the next character
+ * @param aForward [in] Are we moving forward (or backward) in content order.
+ * @param aOffset [in/out] At what offset into the frame to start looking.
+ * on output - what offset was reached (whether or not we found a place to stop).
+ * @param aRespectClusters [in] Whether to restrict result to valid cursor locations
+ * (between grapheme clusters) - default TRUE maintains "normal" behavior,
+ * FALSE is used for selection by "code unit" (instead of "character")
+ * @return STOP: An appropriate offset was found within this frame,
+ * and is given by aOffset.
+ * CONTINUE: Not found within this frame, need to try the next frame.
+ * see enum FrameSearchResult for more details.
+ */
+ virtual FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset,
+ bool aRespectClusters = true) = 0;
+
+ /**
+ * Search the frame for the next word boundary
+ * @param aForward [in] Are we moving forward (or backward) in content order.
+ * @param aWordSelectEatSpace [in] true: look for non-whitespace following
+ * whitespace (in the direction of movement).
+ * false: look for whitespace following non-whitespace (in the
+ * direction of movement).
+ * @param aIsKeyboardSelect [in] Was the action initiated by a keyboard operation?
+ * If true, punctuation immediately following a word is considered part
+ * of that word. Otherwise, a sequence of punctuation is always considered
+ * as a word on its own.
+ * @param aOffset [in/out] At what offset into the frame to start looking.
+ * on output - what offset was reached (whether or not we found a place to stop).
+ * @param aState [in/out] the state that is carried from frame to frame
+ * @return true: An appropriate offset was found within this frame,
+ * and is given by aOffset.
+ * false: Not found within this frame, need to try the next frame.
+ */
+ struct PeekWordState {
+ // true when we're still at the start of the search, i.e., we can't return
+ // this point as a valid offset!
+ bool mAtStart;
+ // true when we've encountered at least one character of the pre-boundary type
+ // (whitespace if aWordSelectEatSpace is true, non-whitespace otherwise)
+ bool mSawBeforeType;
+ // true when the last character encountered was punctuation
+ bool mLastCharWasPunctuation;
+ // true when the last character encountered was whitespace
+ bool mLastCharWasWhitespace;
+ // true when we've seen non-punctuation since the last whitespace
+ bool mSeenNonPunctuationSinceWhitespace;
+ // text that's *before* the current frame when aForward is true, *after*
+ // the current frame when aForward is false. Only includes the text
+ // on the current line.
+ nsAutoString mContext;
+
+ PeekWordState() : mAtStart(true), mSawBeforeType(false),
+ mLastCharWasPunctuation(false), mLastCharWasWhitespace(false),
+ mSeenNonPunctuationSinceWhitespace(false) {}
+ void SetSawBeforeType() { mSawBeforeType = true; }
+ void Update(bool aAfterPunctuation, bool aAfterWhitespace) {
+ mLastCharWasPunctuation = aAfterPunctuation;
+ mLastCharWasWhitespace = aAfterWhitespace;
+ if (aAfterWhitespace) {
+ mSeenNonPunctuationSinceWhitespace = false;
+ } else if (!aAfterPunctuation) {
+ mSeenNonPunctuationSinceWhitespace = true;
+ }
+ mAtStart = false;
+ }
+ };
+ virtual FrameSearchResult PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
+ int32_t* aOffset, PeekWordState* aState) = 0;
+
+ /**
+ * Search for the first paragraph boundary before or after the given position
+ * @param aPos See description in nsFrameSelection.h. The following fields are
+ * used by this method:
+ * Input: mDirection
+ * Output: mResultContent, mContentOffset
+ */
+ nsresult PeekOffsetParagraph(nsPeekOffsetStruct *aPos);
+
+private:
+ nsOverflowAreas* GetOverflowAreasProperty();
+ nsRect GetVisualOverflowFromDeltas() const {
+ MOZ_ASSERT(mOverflow.mType != NS_FRAME_OVERFLOW_LARGE,
+ "should not be called when overflow is in a property");
+ // Calculate the rect using deltas from the frame's border rect.
+ // Note that the mOverflow.mDeltas fields are unsigned, but we will often
+ // need to return negative values for the left and top, so take care
+ // to cast away the unsigned-ness.
+ return nsRect(-(int32_t)mOverflow.mVisualDeltas.mLeft,
+ -(int32_t)mOverflow.mVisualDeltas.mTop,
+ mRect.width + mOverflow.mVisualDeltas.mRight +
+ mOverflow.mVisualDeltas.mLeft,
+ mRect.height + mOverflow.mVisualDeltas.mBottom +
+ mOverflow.mVisualDeltas.mTop);
+ }
+ /**
+ * Returns true if any overflow changed.
+ */
+ bool SetOverflowAreas(const nsOverflowAreas& aOverflowAreas);
+
+ // Helper-functions for SortFrameList():
+ template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
+ static nsIFrame* SortedMerge(nsIFrame *aLeft, nsIFrame *aRight);
+
+ template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
+ static nsIFrame* MergeSort(nsIFrame *aSource);
+
+ bool HasOpacityInternal(float aThreshold) const;
+
+#ifdef DEBUG_FRAME_DUMP
+public:
+ static void IndentBy(FILE* out, int32_t aIndent) {
+ while (--aIndent >= 0) fputs(" ", out);
+ }
+ void ListTag(FILE* out) const {
+ ListTag(out, this);
+ }
+ static void ListTag(FILE* out, const nsIFrame* aFrame) {
+ nsAutoCString t;
+ ListTag(t, aFrame);
+ fputs(t.get(), out);
+ }
+ static void ListTag(FILE* out, const nsFrameList& aFrameList) {
+ for (nsIFrame* frame : aFrameList) {
+ ListTag(out, frame);
+ }
+ }
+ void ListTag(nsACString& aTo) const;
+ nsAutoCString ListTag() const {
+ nsAutoCString tag;
+ ListTag(tag);
+ return tag;
+ }
+ static void ListTag(nsACString& aTo, const nsIFrame* aFrame);
+ void ListGeneric(nsACString& aTo, const char* aPrefix = "", uint32_t aFlags = 0) const;
+ enum {
+ TRAVERSE_SUBDOCUMENT_FRAMES = 0x01
+ };
+ virtual void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const;
+ /**
+ * lists the frames beginning from the root frame
+ * - calls root frame's List(...)
+ */
+ static void RootFrameList(nsPresContext* aPresContext,
+ FILE* out = stderr, const char* aPrefix = "");
+ virtual void DumpFrameTree() const;
+ void DumpFrameTreeLimited() const;
+
+ virtual nsresult GetFrameName(nsAString& aResult) const = 0;
+#endif
+
+#ifdef DEBUG
+public:
+ virtual nsFrameState GetDebugStateBits() const = 0;
+ virtual nsresult DumpRegressionData(nsPresContext* aPresContext,
+ FILE* out, int32_t aIndent) = 0;
+#endif
+};
+
+//----------------------------------------------------------------------
+
+/**
+ * nsWeakFrame can be used to keep a reference to a nsIFrame in a safe way.
+ * Whenever an nsIFrame object is deleted, the nsWeakFrames pointing
+ * to it will be cleared.
+ *
+ * Create nsWeakFrame object when it is sure that nsIFrame object
+ * is alive and after some operations which may destroy the nsIFrame
+ * (for example any DOM modifications) use IsAlive() or GetFrame() methods to
+ * check whether it is safe to continue to use the nsIFrame object.
+ *
+ * @note The usage of this class should be kept to a minimum.
+ */
+
+class nsWeakFrame {
+public:
+ nsWeakFrame() : mPrev(nullptr), mFrame(nullptr) { }
+
+ nsWeakFrame(const nsWeakFrame& aOther) : mPrev(nullptr), mFrame(nullptr)
+ {
+ Init(aOther.GetFrame());
+ }
+
+ MOZ_IMPLICIT nsWeakFrame(nsIFrame* aFrame) : mPrev(nullptr), mFrame(nullptr)
+ {
+ Init(aFrame);
+ }
+
+ nsWeakFrame& operator=(nsWeakFrame& aOther) {
+ Init(aOther.GetFrame());
+ return *this;
+ }
+
+ nsWeakFrame& operator=(nsIFrame* aFrame) {
+ Init(aFrame);
+ return *this;
+ }
+
+ nsIFrame* operator->()
+ {
+ return mFrame;
+ }
+
+ operator nsIFrame*()
+ {
+ return mFrame;
+ }
+
+ void Clear(nsIPresShell* aShell) {
+ if (aShell) {
+ aShell->RemoveWeakFrame(this);
+ }
+ mFrame = nullptr;
+ mPrev = nullptr;
+ }
+
+ bool IsAlive() { return !!mFrame; }
+
+ nsIFrame* GetFrame() const { return mFrame; }
+
+ nsWeakFrame* GetPreviousWeakFrame() { return mPrev; }
+
+ void SetPreviousWeakFrame(nsWeakFrame* aPrev) { mPrev = aPrev; }
+
+ ~nsWeakFrame()
+ {
+ Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
+ }
+private:
+ void Init(nsIFrame* aFrame);
+
+ nsWeakFrame* mPrev;
+ nsIFrame* mFrame;
+};
+
+inline bool
+nsFrameList::ContinueRemoveFrame(nsIFrame* aFrame)
+{
+ MOZ_ASSERT(!aFrame->GetPrevSibling() || !aFrame->GetNextSibling(),
+ "Forgot to call StartRemoveFrame?");
+ if (aFrame == mLastChild) {
+ MOZ_ASSERT(!aFrame->GetNextSibling(), "broken frame list");
+ nsIFrame* prevSibling = aFrame->GetPrevSibling();
+ if (!prevSibling) {
+ MOZ_ASSERT(aFrame == mFirstChild, "broken frame list");
+ mFirstChild = mLastChild = nullptr;
+ return true;
+ }
+ MOZ_ASSERT(prevSibling->GetNextSibling() == aFrame, "Broken frame linkage");
+ prevSibling->SetNextSibling(nullptr);
+ mLastChild = prevSibling;
+ return true;
+ }
+ if (aFrame == mFirstChild) {
+ MOZ_ASSERT(!aFrame->GetPrevSibling(), "broken frame list");
+ mFirstChild = aFrame->GetNextSibling();
+ aFrame->SetNextSibling(nullptr);
+ MOZ_ASSERT(mFirstChild, "broken frame list");
+ return true;
+ }
+ return false;
+}
+
+inline bool
+nsFrameList::StartRemoveFrame(nsIFrame* aFrame)
+{
+ if (aFrame->GetPrevSibling() && aFrame->GetNextSibling()) {
+ UnhookFrameFromSiblings(aFrame);
+ return true;
+ }
+ return ContinueRemoveFrame(aFrame);
+}
+
+inline void
+nsFrameList::Enumerator::Next()
+{
+ NS_ASSERTION(!AtEnd(), "Should have checked AtEnd()!");
+ mFrame = mFrame->GetNextSibling();
+}
+
+inline
+nsFrameList::FrameLinkEnumerator::
+FrameLinkEnumerator(const nsFrameList& aList, nsIFrame* aPrevFrame)
+ : Enumerator(aList)
+{
+ mPrev = aPrevFrame;
+ mFrame = aPrevFrame ? aPrevFrame->GetNextSibling() : aList.FirstChild();
+}
+
+inline void
+nsFrameList::FrameLinkEnumerator::Next()
+{
+ mPrev = mFrame;
+ Enumerator::Next();
+}
+
+// Operators of nsFrameList::Iterator
+// ---------------------------------------------------
+
+inline nsFrameList::Iterator&
+nsFrameList::Iterator::operator++()
+{
+ mCurrent = mCurrent->GetNextSibling();
+ return *this;
+}
+
+inline nsFrameList::Iterator&
+nsFrameList::Iterator::operator--()
+{
+ if (!mCurrent) {
+ mCurrent = mList.LastChild();
+ } else {
+ mCurrent = mCurrent->GetPrevSibling();
+ }
+ return *this;
+}
+
+// Helper-functions for nsIFrame::SortFrameList()
+// ---------------------------------------------------
+
+template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
+/* static */ nsIFrame*
+nsIFrame::SortedMerge(nsIFrame *aLeft, nsIFrame *aRight)
+{
+ NS_PRECONDITION(aLeft && aRight, "SortedMerge must have non-empty lists");
+
+ nsIFrame *result;
+ // Unroll first iteration to avoid null-check 'result' inside the loop.
+ if (IsLessThanOrEqual(aLeft, aRight)) {
+ result = aLeft;
+ aLeft = aLeft->GetNextSibling();
+ if (!aLeft) {
+ result->SetNextSibling(aRight);
+ return result;
+ }
+ }
+ else {
+ result = aRight;
+ aRight = aRight->GetNextSibling();
+ if (!aRight) {
+ result->SetNextSibling(aLeft);
+ return result;
+ }
+ }
+
+ nsIFrame *last = result;
+ for (;;) {
+ if (IsLessThanOrEqual(aLeft, aRight)) {
+ last->SetNextSibling(aLeft);
+ last = aLeft;
+ aLeft = aLeft->GetNextSibling();
+ if (!aLeft) {
+ last->SetNextSibling(aRight);
+ return result;
+ }
+ }
+ else {
+ last->SetNextSibling(aRight);
+ last = aRight;
+ aRight = aRight->GetNextSibling();
+ if (!aRight) {
+ last->SetNextSibling(aLeft);
+ return result;
+ }
+ }
+ }
+}
+
+template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
+/* static */ nsIFrame*
+nsIFrame::MergeSort(nsIFrame *aSource)
+{
+ NS_PRECONDITION(aSource, "MergeSort null arg");
+
+ nsIFrame *sorted[32] = { nullptr };
+ nsIFrame **fill = &sorted[0];
+ nsIFrame **left;
+ nsIFrame *rest = aSource;
+
+ do {
+ nsIFrame *current = rest;
+ rest = rest->GetNextSibling();
+ current->SetNextSibling(nullptr);
+
+ // Merge it with sorted[0] if present; then merge the result with sorted[1] etc.
+ // sorted[0] is a list of length 1 (or nullptr).
+ // sorted[1] is a list of length 2 (or nullptr).
+ // sorted[2] is a list of length 4 (or nullptr). etc.
+ for (left = &sorted[0]; left != fill && *left; ++left) {
+ current = SortedMerge<IsLessThanOrEqual>(*left, current);
+ *left = nullptr;
+ }
+
+ // Fill the empty slot that we couldn't merge with the last result.
+ *left = current;
+
+ if (left == fill)
+ ++fill;
+ } while (rest);
+
+ // Collect and merge the results.
+ nsIFrame *result = nullptr;
+ for (left = &sorted[0]; left != fill; ++left) {
+ if (*left) {
+ result = result ? SortedMerge<IsLessThanOrEqual>(*left, result) : *left;
+ }
+ }
+ return result;
+}
+
+template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
+/* static */ void
+nsIFrame::SortFrameList(nsFrameList& aFrameList)
+{
+ nsIFrame* head = MergeSort<IsLessThanOrEqual>(aFrameList.FirstChild());
+ aFrameList = nsFrameList(head, nsLayoutUtils::GetLastSibling(head));
+ MOZ_ASSERT(IsFrameListSorted<IsLessThanOrEqual>(aFrameList),
+ "After we sort a frame list, it should be in sorted order...");
+}
+
+template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
+/* static */ bool
+nsIFrame::IsFrameListSorted(nsFrameList& aFrameList)
+{
+ if (aFrameList.IsEmpty()) {
+ // empty lists are trivially sorted.
+ return true;
+ }
+
+ // We'll walk through the list with two iterators, one trailing behind the
+ // other. The list is sorted IFF trailingIter <= iter, across the whole list.
+ nsFrameList::Enumerator trailingIter(aFrameList);
+ nsFrameList::Enumerator iter(aFrameList);
+ iter.Next(); // Skip |iter| past first frame. (List is nonempty, so we can.)
+
+ // Now, advance the iterators in parallel, comparing each adjacent pair.
+ while (!iter.AtEnd()) {
+ MOZ_ASSERT(!trailingIter.AtEnd(), "trailing iter shouldn't finish first");
+ if (!IsLessThanOrEqual(trailingIter.get(), iter.get())) {
+ return false;
+ }
+ trailingIter.Next();
+ iter.Next();
+ }
+
+ // We made it to the end without returning early, so the list is sorted.
+ return true;
+}
+
+#endif /* nsIFrame_h___ */