summaryrefslogtreecommitdiffstats
path: root/layout/generic/nsFrame.h
diff options
context:
space:
mode:
Diffstat (limited to 'layout/generic/nsFrame.h')
-rw-r--r--layout/generic/nsFrame.h920
1 files changed, 920 insertions, 0 deletions
diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h
new file mode 100644
index 000000000..f996f57d7
--- /dev/null
+++ b/layout/generic/nsFrame.h
@@ -0,0 +1,920 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/* base class of all rendering objects */
+
+#ifndef nsFrame_h___
+#define nsFrame_h___
+
+#include "mozilla/Attributes.h"
+#include "mozilla/EventForwards.h"
+#include "mozilla/Likely.h"
+#include "nsBox.h"
+#include "mozilla/Logging.h"
+
+#include "nsIPresShell.h"
+#include "mozilla/ReflowInput.h"
+#include "nsHTMLParts.h"
+#include "nsISelectionDisplay.h"
+
+/**
+ * nsFrame logging constants. We redefine the nspr
+ * PRLogModuleInfo.level field to be a bitfield. Each bit controls a
+ * specific type of logging. Each logging operation has associated
+ * inline methods defined below.
+ */
+#define NS_FRAME_TRACE_CALLS 0x1
+#define NS_FRAME_TRACE_PUSH_PULL 0x2
+#define NS_FRAME_TRACE_CHILD_REFLOW 0x4
+#define NS_FRAME_TRACE_NEW_FRAMES 0x8
+
+#define NS_FRAME_LOG_TEST(_lm,_bit) (int(((mozilla::LogModule*)_lm)->Level()) & (_bit))
+
+#ifdef DEBUG
+#define NS_FRAME_LOG(_bit,_args) \
+ PR_BEGIN_MACRO \
+ if (NS_FRAME_LOG_TEST(nsFrame::sFrameLogModule,_bit)) { \
+ PR_LogPrint _args; \
+ } \
+ PR_END_MACRO
+#else
+#define NS_FRAME_LOG(_bit,_args)
+#endif
+
+// XXX Need to rework this so that logging is free when it's off
+#ifdef DEBUG
+#define NS_FRAME_TRACE_IN(_method) Trace(_method, true)
+
+#define NS_FRAME_TRACE_OUT(_method) Trace(_method, false)
+
+// XXX remove me
+#define NS_FRAME_TRACE_MSG(_bit,_args) \
+ PR_BEGIN_MACRO \
+ if (NS_FRAME_LOG_TEST(nsFrame::sFrameLogModule,_bit)) { \
+ TraceMsg _args; \
+ } \
+ PR_END_MACRO
+
+#define NS_FRAME_TRACE(_bit,_args) \
+ PR_BEGIN_MACRO \
+ if (NS_FRAME_LOG_TEST(nsFrame::sFrameLogModule,_bit)) { \
+ TraceMsg _args; \
+ } \
+ PR_END_MACRO
+
+#define NS_FRAME_TRACE_REFLOW_IN(_method) Trace(_method, true)
+
+#define NS_FRAME_TRACE_REFLOW_OUT(_method, _status) \
+ Trace(_method, false, _status)
+
+#else
+#define NS_FRAME_TRACE(_bits,_args)
+#define NS_FRAME_TRACE_IN(_method)
+#define NS_FRAME_TRACE_OUT(_method)
+#define NS_FRAME_TRACE_MSG(_bits,_args)
+#define NS_FRAME_TRACE_REFLOW_IN(_method)
+#define NS_FRAME_TRACE_REFLOW_OUT(_method, _status)
+#endif
+
+// Frame allocation boilerplate macros. Every subclass of nsFrame must
+// either use NS_{DECL,IMPL}_FRAMEARENA_HELPERS pair for allocating
+// memory correctly, or use NS_DECL_ABSTRACT_FRAME to declare a frame
+// class abstract and stop it from being instantiated. If a frame class
+// without its own operator new and GetFrameId gets instantiated, the
+// per-frame recycler lists in nsPresArena will not work correctly,
+// with potentially catastrophic consequences (not enough memory is
+// allocated for a frame object).
+
+#define NS_DECL_FRAMEARENA_HELPERS \
+ void* operator new(size_t, nsIPresShell*) MOZ_MUST_OVERRIDE; \
+ virtual nsQueryFrame::FrameIID GetFrameId() override MOZ_MUST_OVERRIDE;
+
+#define NS_IMPL_FRAMEARENA_HELPERS(class) \
+ void* class::operator new(size_t sz, nsIPresShell* aShell) \
+ { return aShell->AllocateFrame(nsQueryFrame::class##_id, sz); } \
+ nsQueryFrame::FrameIID class::GetFrameId() \
+ { return nsQueryFrame::class##_id; }
+
+#define NS_DECL_ABSTRACT_FRAME(class) \
+ void* operator new(size_t, nsIPresShell*) MOZ_MUST_OVERRIDE = delete; \
+ virtual nsQueryFrame::FrameIID GetFrameId() override MOZ_MUST_OVERRIDE = 0;
+
+//----------------------------------------------------------------------
+
+struct nsBoxLayoutMetrics;
+struct nsRect;
+
+/**
+ * Implementation of a simple frame that's not splittable and has no
+ * child frames.
+ *
+ * Sets the NS_FRAME_SYNCHRONIZE_FRAME_AND_VIEW bit, so the default
+ * behavior is to keep the frame and view position and size in sync.
+ */
+class nsFrame : public nsBox
+{
+public:
+ /**
+ * Create a new "empty" frame that maps a given piece of content into a
+ * 0,0 area.
+ */
+ friend nsIFrame* NS_NewEmptyFrame(nsIPresShell* aShell,
+ nsStyleContext* aContext);
+
+private:
+ // Left undefined; nsFrame objects are never allocated from the heap.
+ void* operator new(size_t sz) CPP_THROW_NEW;
+
+protected:
+ // Overridden to prevent the global delete from being called, since
+ // the memory came out of an arena instead of the heap.
+ //
+ // Ideally this would be private and undefined, like the normal
+ // operator new. Unfortunately, the C++ standard requires an
+ // overridden operator delete to be accessible to any subclass that
+ // defines a virtual destructor, so we can only make it protected;
+ // worse, some C++ compilers will synthesize calls to this function
+ // from the "deleting destructors" that they emit in case of
+ // delete-expressions, so it can't even be undefined.
+ void operator delete(void* aPtr, size_t sz);
+
+public:
+
+ // nsQueryFrame
+ NS_DECL_QUERYFRAME
+ void* operator new(size_t, nsIPresShell*) MOZ_MUST_OVERRIDE;
+ virtual nsQueryFrame::FrameIID GetFrameId() MOZ_MUST_OVERRIDE;
+
+ // nsIFrame
+ virtual void Init(nsIContent* aContent,
+ nsContainerFrame* aParent,
+ nsIFrame* aPrevInFlow) override;
+ virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
+ virtual nsStyleContext* GetAdditionalStyleContext(int32_t aIndex) const override;
+ virtual void SetAdditionalStyleContext(int32_t aIndex,
+ nsStyleContext* aStyleContext) override;
+ virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const override;
+ virtual const nsFrameList& GetChildList(ChildListID aListID) const override;
+ virtual void GetChildLists(nsTArray<ChildList>* aLists) const override;
+
+ virtual nsresult HandleEvent(nsPresContext* aPresContext,
+ mozilla::WidgetGUIEvent* aEvent,
+ nsEventStatus* aEventStatus) override;
+ virtual nsresult GetContentForEvent(mozilla::WidgetEvent* aEvent,
+ nsIContent** aContent) override;
+ virtual nsresult GetCursor(const nsPoint& aPoint,
+ nsIFrame::Cursor& aCursor) override;
+
+ virtual nsresult GetPointFromOffset(int32_t inOffset,
+ nsPoint* outPoint) override;
+ virtual nsresult GetCharacterRectsInRange(int32_t aInOffset,
+ int32_t aLength,
+ nsTArray<nsRect>& aOutRect) override;
+
+ virtual nsresult GetChildFrameContainingOffset(int32_t inContentOffset,
+ bool inHint,
+ int32_t* outFrameContentOffset,
+ nsIFrame** outChildFrame) override;
+
+ static nsresult GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
+ nsPeekOffsetStruct *aPos,
+ nsIFrame *aBlockFrame,
+ int32_t aLineStart,
+ int8_t aOutSideLimit
+ );
+
+ virtual nsresult CharacterDataChanged(CharacterDataChangeInfo* aInfo) override;
+ virtual nsresult AttributeChanged(int32_t aNameSpaceID,
+ nsIAtom* aAttribute,
+ int32_t aModType) override;
+ virtual nsSplittableType GetSplittableType() const override;
+ virtual nsIFrame* GetPrevContinuation() const override;
+ virtual void SetPrevContinuation(nsIFrame*) override;
+ virtual nsIFrame* GetNextContinuation() const override;
+ virtual void SetNextContinuation(nsIFrame*) override;
+ virtual nsIFrame* GetPrevInFlowVirtual() const override;
+ virtual void SetPrevInFlow(nsIFrame*) override;
+ virtual nsIFrame* GetNextInFlowVirtual() const override;
+ virtual void SetNextInFlow(nsIFrame*) override;
+ virtual nsIAtom* GetType() const override;
+
+ virtual nsresult IsSelectable(bool* aIsSelectable,
+ mozilla::StyleUserSelect* aSelectStyle) const override;
+
+ virtual nsresult GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon) override;
+
+ virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) override;
+ virtual FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset,
+ bool aRespectClusters = true) override;
+ virtual FrameSearchResult PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
+ int32_t* aOffset, PeekWordState *aState) override;
+ /**
+ * Check whether we should break at a boundary between punctuation and
+ * non-punctuation. Only call it at a punctuation boundary
+ * (i.e. exactly one of the previous and next characters are punctuation).
+ * @param aForward true if we're moving forward in content order
+ * @param aPunctAfter true if the next character is punctuation
+ * @param aWhitespaceAfter true if the next character is whitespace
+ */
+ bool BreakWordBetweenPunctuation(const PeekWordState* aState,
+ bool aForward,
+ bool aPunctAfter, bool aWhitespaceAfter,
+ bool aIsKeyboardSelect);
+
+ virtual nsresult CheckVisibility(nsPresContext* aContext, int32_t aStartIndex, int32_t aEndIndex, bool aRecurse, bool *aFinished, bool *_retval) override;
+
+ virtual nsresult GetOffsets(int32_t &aStart, int32_t &aEnd) const override;
+ virtual void ChildIsDirty(nsIFrame* aChild) override;
+
+#ifdef ACCESSIBILITY
+ virtual mozilla::a11y::AccType AccessibleType() override;
+#endif
+
+ virtual nsStyleContext* GetParentStyleContext(nsIFrame** aProviderFrame) const override {
+ return DoGetParentStyleContext(aProviderFrame);
+ }
+
+ /**
+ * Do the work for getting the parent style context frame so that
+ * other frame's |GetParentStyleContext| methods can call this
+ * method on *another* frame. (This function handles out-of-flow
+ * frames by using the frame manager's placeholder map and it also
+ * handles block-within-inline and generated content wrappers.)
+ *
+ * @param aProviderFrame (out) the frame associated with the returned value
+ * or null 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.
+ */
+ nsStyleContext* DoGetParentStyleContext(nsIFrame** aProviderFrame) const;
+
+ virtual bool IsEmpty() override;
+ virtual bool IsSelfEmpty() override;
+
+ virtual void MarkIntrinsicISizesDirty() override;
+ virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
+ virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override;
+ virtual void AddInlineMinISize(nsRenderingContext *aRenderingContext,
+ InlineMinISizeData *aData) override;
+ virtual void AddInlinePrefISize(nsRenderingContext *aRenderingContext,
+ InlinePrefISizeData *aData) override;
+ virtual IntrinsicISizeOffsetData IntrinsicISizeOffsets() override;
+ virtual mozilla::IntrinsicSize GetIntrinsicSize() override;
+ virtual nsSize GetIntrinsicRatio() override;
+
+ virtual mozilla::LogicalSize
+ ComputeSize(nsRenderingContext* aRenderingContext,
+ mozilla::WritingMode aWM,
+ const mozilla::LogicalSize& aCBSize,
+ nscoord aAvailableISize,
+ const mozilla::LogicalSize& aMargin,
+ const mozilla::LogicalSize& aBorder,
+ const mozilla::LogicalSize& aPadding,
+ ComputeSizeFlags aFlags) override;
+
+ /**
+ * Calculate the used values for 'width' and 'height' for a replaced element.
+ * http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
+ */
+ mozilla::LogicalSize
+ ComputeSizeWithIntrinsicDimensions(
+ nsRenderingContext* aRenderingContext,
+ mozilla::WritingMode aWM,
+ const mozilla::IntrinsicSize& aIntrinsicSize,
+ nsSize aIntrinsicRatio,
+ const mozilla::LogicalSize& aCBSize,
+ const mozilla::LogicalSize& aMargin,
+ const mozilla::LogicalSize& aBorder,
+ const mozilla::LogicalSize& aPadding,
+ ComputeSizeFlags aFlags);
+
+ // Compute tight bounds assuming this frame honours its border, background
+ // and outline, its children's tight bounds, and nothing else.
+ nsRect ComputeSimpleTightBounds(mozilla::gfx::DrawTarget* aDrawTarget) const;
+
+ /**
+ * A helper, used by |nsFrame::ComputeSize| (for frames that need to
+ * override only this part of ComputeSize), that computes the size
+ * that should be returned when 'width', 'height', and
+ * min/max-width/height are all 'auto' or equivalent.
+ *
+ * In general, frames that can accept any computed width/height should
+ * override only ComputeAutoSize, and frames that cannot do so need to
+ * override ComputeSize to enforce their width/height invariants.
+ *
+ * Implementations may optimize by returning a garbage width if
+ * StylePosition()->mWidth.GetUnit() != eStyleUnit_Auto, and
+ * likewise for height, since in such cases the result is guaranteed
+ * to be unused.
+ */
+ virtual mozilla::LogicalSize
+ ComputeAutoSize(nsRenderingContext* aRenderingContext,
+ mozilla::WritingMode aWM,
+ const mozilla::LogicalSize& aCBSize,
+ nscoord aAvailableISize,
+ const mozilla::LogicalSize& aMargin,
+ const mozilla::LogicalSize& aBorder,
+ const mozilla::LogicalSize& aPadding,
+ ComputeSizeFlags aFlags);
+
+ /**
+ * Utility function for ComputeAutoSize implementations. Return
+ * max(GetMinISize(), min(aISizeInCB, GetPrefISize()))
+ */
+ nscoord ShrinkWidthToFit(nsRenderingContext* aRenderingContext,
+ nscoord aISizeInCB,
+ ComputeSizeFlags aFlags);
+
+ /**
+ * Calculates the size of this frame after reflowing (calling Reflow on, and
+ * updating the size and position of) its children, as necessary. The
+ * calculated size is returned to the caller via the ReflowOutput
+ * outparam. (The caller is responsible for setting the actual size and
+ * position of this frame.)
+ *
+ * A frame's children must _all_ be reflowed if the frame is dirty (the
+ * NS_FRAME_IS_DIRTY bit is set on it). Otherwise, individual children
+ * must be reflowed if they are dirty or have the NS_FRAME_HAS_DIRTY_CHILDREN
+ * bit set on them. Otherwise, whether children need to be reflowed depends
+ * on the frame's type (it's up to individual Reflow methods), and on what
+ * has changed. For example, a change in the width of the frame may require
+ * all of its children to be reflowed (even those without dirty bits set on
+ * them), whereas a change in its height might not.
+ * (ReflowInput::ShouldReflowAllKids may be helpful in deciding whether
+ * to reflow all the children, but for some frame types it might result in
+ * over-reflow.)
+ *
+ * Note: if it's only the overflow rect(s) of a frame that need to be
+ * updated, then UpdateOverflow should be called instead of Reflow.
+ */
+ virtual void Reflow(nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus) override;
+ virtual void DidReflow(nsPresContext* aPresContext,
+ const ReflowInput* aReflowInput,
+ nsDidReflowStatus aStatus) override;
+
+ /**
+ * NOTE: aStatus is assumed to be already-initialized. The reflow statuses of
+ * any reflowed absolute children will be merged into aStatus; aside from
+ * that, this method won't modify aStatus.
+ */
+ void ReflowAbsoluteFrames(nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus,
+ bool aConstrainBSize = true);
+ void FinishReflowWithAbsoluteFrames(nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus,
+ bool aConstrainBSize = true);
+
+ /*
+ * If this frame is dirty, marks all absolutely-positioned children of this
+ * frame dirty. If this frame isn't dirty, or if there are no
+ * absolutely-positioned children, does nothing.
+ *
+ * It's necessary to use PushDirtyBitToAbsoluteFrames() when you plan to
+ * reflow this frame's absolutely-positioned children after the dirty bit on
+ * this frame has already been cleared, which prevents ReflowInput from
+ * propagating the dirty bit normally. This situation generally only arises
+ * when a multipass layout algorithm is used.
+ */
+ void PushDirtyBitToAbsoluteFrames();
+
+ virtual bool CanContinueTextRun() const override;
+
+ virtual bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) override;
+
+ virtual void UnionChildOverflow(nsOverflowAreas& aOverflowAreas) override;
+
+ // Selection Methods
+
+ NS_IMETHOD HandlePress(nsPresContext* aPresContext,
+ mozilla::WidgetGUIEvent* aEvent,
+ nsEventStatus* aEventStatus);
+
+ NS_IMETHOD HandleMultiplePress(nsPresContext* aPresContext,
+ mozilla::WidgetGUIEvent* aEvent,
+ nsEventStatus* aEventStatus,
+ bool aControlHeld);
+
+ NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
+ mozilla::WidgetGUIEvent* aEvent,
+ nsEventStatus* aEventStatus);
+
+ NS_IMETHOD HandleRelease(nsPresContext* aPresContext,
+ mozilla::WidgetGUIEvent* aEvent,
+ nsEventStatus* aEventStatus);
+
+ enum { SELECT_ACCUMULATE = 0x01 };
+
+ nsresult PeekBackwardAndForward(nsSelectionAmount aAmountBack,
+ nsSelectionAmount aAmountForward,
+ int32_t aStartPos,
+ bool aJumpLines,
+ uint32_t aSelectFlags);
+
+ nsresult SelectByTypeAtPoint(nsPresContext* aPresContext,
+ const nsPoint& aPoint,
+ nsSelectionAmount aBeginAmountType,
+ nsSelectionAmount aEndAmountType,
+ uint32_t aSelectFlags);
+
+ // Helper for GetContentAndOffsetsFromPoint; calculation of content offsets
+ // in this function assumes there is no child frame that can be targeted.
+ virtual ContentOffsets CalcContentOffsetsFromFramePoint(nsPoint aPoint);
+
+ // Box layout methods
+ virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
+ virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
+ virtual nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState) override;
+ virtual nscoord GetXULFlex() override;
+ virtual nscoord GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState) override;
+
+ // We compute and store the HTML content's overflow area. So don't
+ // try to compute it in the box code.
+ virtual bool ComputesOwnOverflowArea() override { return true; }
+
+ //--------------------------------------------------
+ // Additional methods
+
+ // Helper function that tests if the frame tree is too deep; if it is
+ // it marks the frame as "unflowable", zeroes out the metrics, sets
+ // the reflow status, and returns true. Otherwise, the frame is
+ // unmarked "unflowable" and the metrics and reflow status are not
+ // touched and false is returned.
+ bool IsFrameTreeTooDeep(const ReflowInput& aReflowInput,
+ ReflowOutput& aMetrics,
+ nsReflowStatus& aStatus);
+
+ // Incorporate the child overflow areas into aOverflowAreas.
+ // If the child does not have a overflow, use the child area.
+ void ConsiderChildOverflow(nsOverflowAreas& aOverflowAreas,
+ nsIFrame* aChildFrame);
+
+ /**
+ * @return true if we should avoid a page/column break in this frame.
+ */
+ bool ShouldAvoidBreakInside(const ReflowInput& aReflowInput) const {
+ return !aReflowInput.mFlags.mIsTopOfPage &&
+ NS_STYLE_PAGE_BREAK_AVOID == StyleDisplay()->mBreakInside &&
+ !GetPrevInFlow();
+ }
+
+#ifdef DEBUG
+ /**
+ * Tracing method that writes a method enter/exit routine to the
+ * nspr log using the nsIFrame log module. The tracing is only
+ * done when the NS_FRAME_TRACE_CALLS bit is set in the log module's
+ * level field.
+ */
+ void Trace(const char* aMethod, bool aEnter);
+ void Trace(const char* aMethod, bool aEnter, nsReflowStatus aStatus);
+ void TraceMsg(const char* fmt, ...);
+
+ // Helper function that verifies that each frame in the list has the
+ // NS_FRAME_IS_DIRTY bit set
+ static void VerifyDirtyBitSet(const nsFrameList& aFrameList);
+
+ static void XMLQuote(nsString& aString);
+
+ /**
+ * Dump out the "base classes" regression data. This should dump
+ * out the interior data, not the "frame" XML container. And it
+ * should call the base classes same named method before doing
+ * anything specific in a derived class. This means that derived
+ * classes need not override DumpRegressionData unless they need
+ * some custom behavior that requires changing how the outer "frame"
+ * XML container is dumped.
+ */
+ virtual void DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent);
+
+ // Display Reflow Debugging
+ static void* DisplayReflowEnter(nsPresContext* aPresContext,
+ nsIFrame* aFrame,
+ const ReflowInput& aReflowInput);
+ static void* DisplayLayoutEnter(nsIFrame* aFrame);
+ static void* DisplayIntrinsicISizeEnter(nsIFrame* aFrame,
+ const char* aType);
+ static void* DisplayIntrinsicSizeEnter(nsIFrame* aFrame,
+ const char* aType);
+ static void DisplayReflowExit(nsPresContext* aPresContext,
+ nsIFrame* aFrame,
+ ReflowOutput& aMetrics,
+ uint32_t aStatus,
+ void* aFrameTreeNode);
+ static void DisplayLayoutExit(nsIFrame* aFrame,
+ void* aFrameTreeNode);
+ static void DisplayIntrinsicISizeExit(nsIFrame* aFrame,
+ const char* aType,
+ nscoord aResult,
+ void* aFrameTreeNode);
+ static void DisplayIntrinsicSizeExit(nsIFrame* aFrame,
+ const char* aType,
+ nsSize aResult,
+ void* aFrameTreeNode);
+
+ static void DisplayReflowStartup();
+ static void DisplayReflowShutdown();
+#endif
+
+ /**
+ * Adds display items for standard CSS background if necessary.
+ * Does not check IsVisibleForPainting.
+ * @param aForceBackground draw the background even if the frame
+ * background style appears to have no background --- this is useful
+ * for frames that might receive a propagated background via
+ * nsCSSRendering::FindBackground
+ * @return whether a themed background item was created.
+ */
+ bool DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists,
+ bool aForceBackground);
+ /**
+ * Adds display items for standard CSS borders, background and outline for
+ * for this frame, as necessary. Checks IsVisibleForPainting and won't
+ * display anything if the frame is not visible.
+ * @param aForceBackground draw the background even if the frame
+ * background style appears to have no background --- this is useful
+ * for frames that might receive a propagated background via
+ * nsCSSRendering::FindBackground
+ */
+ void DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists,
+ bool aForceBackground = false);
+ /**
+ * Add a display item for the CSS outline. Does not check visibility.
+ */
+ void DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists);
+ /**
+ * Add a display item for the CSS outline, after calling
+ * IsVisibleForPainting to confirm we are visible.
+ */
+ void DisplayOutline(nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists);
+
+ /**
+ * Adjust the given parent frame to the right style context parent frame for
+ * the child, given the pseudo-type of the prospective child. This handles
+ * things like walking out of table pseudos and so forth.
+ *
+ * @param aProspectiveParent what GetParent() on the child returns.
+ * Must not be null.
+ * @param aChildPseudo the child's pseudo type, if any.
+ */
+ static nsIFrame*
+ CorrectStyleParentFrame(nsIFrame* aProspectiveParent, nsIAtom* aChildPseudo);
+
+protected:
+ // Protected constructor and destructor
+ explicit nsFrame(nsStyleContext* aContext);
+ virtual ~nsFrame();
+
+ /**
+ * To be called by |BuildDisplayLists| of this class or derived classes to add
+ * a translucent overlay if this frame's content is selected.
+ * @param aContentType an nsISelectionDisplay DISPLAY_ constant identifying
+ * which kind of content this is for
+ */
+ void DisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
+ nsDisplayList* aList, uint16_t aContentType = nsISelectionDisplay::DISPLAY_FRAMES);
+
+ int16_t DisplaySelection(nsPresContext* aPresContext, bool isOkToTurnOn = false);
+
+ // Style post processing hook
+ virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override;
+
+public:
+ //given a frame five me the first/last leaf available
+ //XXX Robert O'Callahan wants to move these elsewhere
+ static void GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame);
+ static void GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame);
+
+ // Return the line number of the aFrame, and (optionally) the containing block
+ // frame.
+ // If aScrollLock is true, don't break outside scrollframes when looking for a
+ // containing block frame.
+ static int32_t GetLineNumber(nsIFrame *aFrame,
+ bool aLockScroll,
+ nsIFrame** aContainingBlock = nullptr);
+
+ /**
+ * Returns true if aFrame should apply overflow clipping.
+ */
+ static bool ShouldApplyOverflowClipping(const nsIFrame* aFrame,
+ const nsStyleDisplay* aDisp)
+ {
+ // clip overflow:-moz-hidden-unscrollable, except for nsListControlFrame,
+ // which is an nsHTMLScrollFrame.
+ if (MOZ_UNLIKELY(aDisp->mOverflowX == NS_STYLE_OVERFLOW_CLIP &&
+ aFrame->GetType() != nsGkAtoms::listControlFrame)) {
+ return true;
+ }
+
+ // and overflow:hidden that we should interpret as -moz-hidden-unscrollable
+ if (aDisp->mOverflowX == NS_STYLE_OVERFLOW_HIDDEN &&
+ aDisp->mOverflowY == NS_STYLE_OVERFLOW_HIDDEN) {
+ // REVIEW: these are the frame types that set up clipping.
+ nsIAtom* type = aFrame->GetType();
+ if (type == nsGkAtoms::tableFrame ||
+ type == nsGkAtoms::tableCellFrame ||
+ type == nsGkAtoms::bcTableCellFrame ||
+ type == nsGkAtoms::svgOuterSVGFrame ||
+ type == nsGkAtoms::svgInnerSVGFrame ||
+ type == nsGkAtoms::svgForeignObjectFrame) {
+ return true;
+ }
+ if (aFrame->IsFrameOfType(nsIFrame::eReplacedContainsBlock)) {
+ if (type == nsGkAtoms::textInputFrame) {
+ // It always has an anonymous scroll frame that handles any overflow.
+ return false;
+ }
+ return true;
+ }
+ }
+
+ if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
+ return false;
+ }
+
+ // If we're paginated and a block, and have NS_BLOCK_CLIP_PAGINATED_OVERFLOW
+ // set, then we want to clip our overflow.
+ return
+ (aFrame->GetStateBits() & NS_BLOCK_CLIP_PAGINATED_OVERFLOW) != 0 &&
+ aFrame->PresContext()->IsPaginated() &&
+ aFrame->GetType() == nsGkAtoms::blockFrame;
+ }
+
+ virtual nsILineIterator* GetLineIterator() override;
+
+protected:
+
+ // Test if we are selecting a table object:
+ // Most table/cell selection requires that Ctrl (Cmd on Mac) key is down
+ // during a mouse click or drag. Exception is using Shift+click when
+ // already in "table/cell selection mode" to extend a block selection
+ // Get the parent content node and offset of the frame
+ // of the enclosing cell or table (if not inside a cell)
+ // aTarget tells us what table element to select (currently only cell and table supported)
+ // (enums for this are defined in nsIFrame.h)
+ NS_IMETHOD GetDataForTableSelection(const nsFrameSelection* aFrameSelection,
+ nsIPresShell* aPresShell,
+ mozilla::WidgetMouseEvent* aMouseEvent,
+ nsIContent** aParentContent,
+ int32_t* aContentOffset,
+ int32_t* aTarget);
+
+ // Fills aCursor with the appropriate information from ui
+ static void FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
+ nsIFrame::Cursor& aCursor);
+ NS_IMETHOD DoXULLayout(nsBoxLayoutState& aBoxLayoutState) override;
+
+#ifdef DEBUG_LAYOUT
+ virtual void GetBoxName(nsAutoString& aName) override;
+#endif
+
+ nsBoxLayoutMetrics* BoxMetrics() const;
+
+ // Fire DOM event. If no aContent argument use frame's mContent.
+ void FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent = nullptr);
+
+private:
+ void BoxReflow(nsBoxLayoutState& aState,
+ nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ nsRenderingContext* aRenderingContext,
+ nscoord aX,
+ nscoord aY,
+ nscoord aWidth,
+ nscoord aHeight,
+ bool aMoveFrame = true);
+
+ NS_IMETHODIMP RefreshSizeCache(nsBoxLayoutState& aState);
+
+ // Returns true if this frame has any kind of CSS animations.
+ bool HasCSSAnimations();
+
+ // Returns true if this frame has any kind of CSS transitions.
+ bool HasCSSTransitions();
+
+#ifdef DEBUG_FRAME_DUMP
+public:
+ /**
+ * Get a printable from of the name of the frame type.
+ * XXX This should be eliminated and we use GetType() instead...
+ */
+ virtual nsresult GetFrameName(nsAString& aResult) const override;
+ nsresult MakeFrameName(const nsAString& aKind, nsAString& aResult) const;
+ // Helper function to return the index in parent of the frame's content
+ // object. Returns -1 on error or if the frame doesn't have a content object
+ static int32_t ContentIndexInContainer(const nsIFrame* aFrame);
+#endif
+
+#ifdef DEBUG
+public:
+ /**
+ * Return the state bits that are relevant to regression tests (that
+ * is, those bits which indicate a real difference when they differ
+ */
+ virtual nsFrameState GetDebugStateBits() const override;
+ /**
+ * Called to dump out regression data that describes the layout
+ * of the frame and its children, and so on. The format of the
+ * data is dictated to be XML (using a specific DTD); the
+ * specific kind of data dumped is up to the frame itself, with
+ * the caveat that some base types are defined.
+ * For more information, see XXX.
+ */
+ virtual nsresult DumpRegressionData(nsPresContext* aPresContext,
+ FILE* out, int32_t aIndent) override;
+
+ /**
+ * See if style tree verification is enabled. To enable style tree
+ * verification add "styleverifytree:1" to your MOZ_LOG
+ * environment variable (any non-zero debug level will work). Or,
+ * call SetVerifyStyleTreeEnable with true.
+ */
+ static bool GetVerifyStyleTreeEnable();
+
+ /**
+ * Set the verify-style-tree enable flag.
+ */
+ static void SetVerifyStyleTreeEnable(bool aEnabled);
+
+ static mozilla::LazyLogModule sFrameLogModule;
+
+ // Show frame borders when rendering
+ static void ShowFrameBorders(bool aEnable);
+ static bool GetShowFrameBorders();
+
+ // Show frame border of event target
+ static void ShowEventTargetFrameBorder(bool aEnable);
+ static bool GetShowEventTargetFrameBorder();
+
+#endif
+
+public:
+
+ static void PrintDisplayList(nsDisplayListBuilder* aBuilder,
+ const nsDisplayList& aList,
+ bool aDumpHtml = false)
+ {
+ std::stringstream ss;
+ PrintDisplayList(aBuilder, aList, ss, aDumpHtml);
+ fprintf_stderr(stderr, "%s", ss.str().c_str());
+ }
+ static void PrintDisplayList(nsDisplayListBuilder* aBuilder,
+ const nsDisplayList& aList,
+ std::stringstream& aStream,
+ bool aDumpHtml = false);
+ static void PrintDisplayListSet(nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aList,
+ std::stringstream& aStream,
+ bool aDumpHtml = false);
+
+};
+
+// Start Display Reflow Debugging
+#ifdef DEBUG
+
+ struct DR_cookie {
+ DR_cookie(nsPresContext* aPresContext,
+ nsIFrame* aFrame,
+ const mozilla::ReflowInput& aReflowInput,
+ mozilla::ReflowOutput& aMetrics,
+ nsReflowStatus& aStatus);
+ ~DR_cookie();
+ void Change() const;
+
+ nsPresContext* mPresContext;
+ nsIFrame* mFrame;
+ const mozilla::ReflowInput& mReflowInput;
+ mozilla::ReflowOutput& mMetrics;
+ nsReflowStatus& mStatus;
+ void* mValue;
+ };
+
+ struct DR_layout_cookie {
+ explicit DR_layout_cookie(nsIFrame* aFrame);
+ ~DR_layout_cookie();
+
+ nsIFrame* mFrame;
+ void* mValue;
+ };
+
+ struct DR_intrinsic_width_cookie {
+ DR_intrinsic_width_cookie(nsIFrame* aFrame, const char* aType,
+ nscoord& aResult);
+ ~DR_intrinsic_width_cookie();
+
+ nsIFrame* mFrame;
+ const char* mType;
+ nscoord& mResult;
+ void* mValue;
+ };
+
+ struct DR_intrinsic_size_cookie {
+ DR_intrinsic_size_cookie(nsIFrame* aFrame, const char* aType,
+ nsSize& aResult);
+ ~DR_intrinsic_size_cookie();
+
+ nsIFrame* mFrame;
+ const char* mType;
+ nsSize& mResult;
+ void* mValue;
+ };
+
+ struct DR_init_constraints_cookie {
+ DR_init_constraints_cookie(nsIFrame* aFrame, mozilla::ReflowInput* aState,
+ nscoord aCBWidth, nscoord aCBHeight,
+ const nsMargin* aBorder,
+ const nsMargin* aPadding);
+ ~DR_init_constraints_cookie();
+
+ nsIFrame* mFrame;
+ mozilla::ReflowInput* mState;
+ void* mValue;
+ };
+
+ struct DR_init_offsets_cookie {
+ DR_init_offsets_cookie(nsIFrame* aFrame, mozilla::SizeComputationInput* aState,
+ const mozilla::LogicalSize& aPercentBasis,
+ const nsMargin* aBorder,
+ const nsMargin* aPadding);
+ ~DR_init_offsets_cookie();
+
+ nsIFrame* mFrame;
+ mozilla::SizeComputationInput* mState;
+ void* mValue;
+ };
+
+ struct DR_init_type_cookie {
+ DR_init_type_cookie(nsIFrame* aFrame, mozilla::ReflowInput* aState);
+ ~DR_init_type_cookie();
+
+ nsIFrame* mFrame;
+ mozilla::ReflowInput* mState;
+ void* mValue;
+ };
+
+#define DISPLAY_REFLOW(dr_pres_context, dr_frame, dr_rf_state, dr_rf_metrics, dr_rf_status) \
+ DR_cookie dr_cookie(dr_pres_context, dr_frame, dr_rf_state, dr_rf_metrics, dr_rf_status);
+#define DISPLAY_REFLOW_CHANGE() \
+ dr_cookie.Change();
+#define DISPLAY_LAYOUT(dr_frame) \
+ DR_layout_cookie dr_cookie(dr_frame);
+#define DISPLAY_MIN_WIDTH(dr_frame, dr_result) \
+ DR_intrinsic_width_cookie dr_cookie(dr_frame, "Min", dr_result)
+#define DISPLAY_PREF_WIDTH(dr_frame, dr_result) \
+ DR_intrinsic_width_cookie dr_cookie(dr_frame, "Pref", dr_result)
+#define DISPLAY_PREF_SIZE(dr_frame, dr_result) \
+ DR_intrinsic_size_cookie dr_cookie(dr_frame, "Pref", dr_result)
+#define DISPLAY_MIN_SIZE(dr_frame, dr_result) \
+ DR_intrinsic_size_cookie dr_cookie(dr_frame, "Min", dr_result)
+#define DISPLAY_MAX_SIZE(dr_frame, dr_result) \
+ DR_intrinsic_size_cookie dr_cookie(dr_frame, "Max", dr_result)
+#define DISPLAY_INIT_CONSTRAINTS(dr_frame, dr_state, dr_cbw, dr_cbh, \
+ dr_bdr, dr_pad) \
+ DR_init_constraints_cookie dr_cookie(dr_frame, dr_state, dr_cbw, dr_cbh, \
+ dr_bdr, dr_pad)
+#define DISPLAY_INIT_OFFSETS(dr_frame, dr_state, dr_pb, dr_bdr, dr_pad) \
+ DR_init_offsets_cookie dr_cookie(dr_frame, dr_state, dr_pb, dr_bdr, dr_pad)
+#define DISPLAY_INIT_TYPE(dr_frame, dr_result) \
+ DR_init_type_cookie dr_cookie(dr_frame, dr_result)
+
+#else
+
+#define DISPLAY_REFLOW(dr_pres_context, dr_frame, dr_rf_state, dr_rf_metrics, dr_rf_status)
+#define DISPLAY_REFLOW_CHANGE()
+#define DISPLAY_LAYOUT(dr_frame) PR_BEGIN_MACRO PR_END_MACRO
+#define DISPLAY_MIN_WIDTH(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
+#define DISPLAY_PREF_WIDTH(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
+#define DISPLAY_PREF_SIZE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
+#define DISPLAY_MIN_SIZE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
+#define DISPLAY_MAX_SIZE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
+#define DISPLAY_INIT_CONSTRAINTS(dr_frame, dr_state, dr_cbw, dr_cbh, \
+ dr_bdr, dr_pad) \
+ PR_BEGIN_MACRO PR_END_MACRO
+#define DISPLAY_INIT_OFFSETS(dr_frame, dr_state, dr_pb, dr_bdr, dr_pad) \
+ PR_BEGIN_MACRO PR_END_MACRO
+#define DISPLAY_INIT_TYPE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
+
+#endif
+// End Display Reflow Debugging
+
+// similar to NS_ENSURE_TRUE but with no return value
+#define ENSURE_TRUE(x) \
+ PR_BEGIN_MACRO \
+ if (!(x)) { \
+ NS_WARNING("ENSURE_TRUE(" #x ") failed"); \
+ return; \
+ } \
+ PR_END_MACRO
+#endif /* nsFrame_h___ */