Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* code for managing absolutely positioned children of a rendering
* object that is a containing block for them
*/
#ifndef LAYOUT_GENERIC_ABSOLUTE_CONTAINING_BLOCK_H_
#define LAYOUT_GENERIC_ABSOLUTE_CONTAINING_BLOCK_H_
#include "nsFrameList.h"
#include "nsIFrame.h"
class nsContainerFrame;
class nsPresContext;
namespace mozilla {
enum class AbsPosReflowFlag : uint8_t {
// Allow the children in the absolute containing block to fragment. Without
// this flag, the children will be monolithic.
AllowFragmentation,
CBWidthChanged,
CBHeightChanged,
IsGridContainerCB,
};
using AbsPosReflowFlags = EnumSet<AbsPosReflowFlag>;
struct StylePositionArea;
/**
* This class contains the logic for being an absolute containing block. This
* class is used within viewport frames (for frames representing content with
* fixed position) and blocks (for frames representing absolutely positioned
* content), since each set of frames is absolutely positioned with respect to
* its parent.
*
* There is no principal child list, just a named child list which contains
* the absolutely positioned frames (FrameChildListID::Absolute).
*
* All functions include as the first argument the frame that is delegating
* the request.
*/
class AbsoluteContainingBlock {
public:
struct AnchorOffsetInfo {
nsPoint mScrollOffset;
StylePositionArea mResolvedPositionArea;
};
AbsoluteContainingBlock() = default;
const nsFrameList& GetChildList() const { return mAbsoluteFrames; }
const nsFrameList& GetPushedChildList() const {
return mPushedAbsoluteFrames;
}
void SetInitialChildList(nsIFrame* aDelegatingFrame, FrameChildListID aListID,
nsFrameList&& aChildList);
void AppendFrames(nsIFrame* aDelegatingFrame, FrameChildListID aListID,
nsFrameList&& aFrameList);
void InsertFrames(nsIFrame* aDelegatingFrame, FrameChildListID aListID,
nsIFrame* aPrevFrame, nsFrameList&& aFrameList);
void RemoveFrame(FrameDestroyContext&, FrameChildListID, nsIFrame*);
/**
* Return the pushed absolute frames. The caller is responsible for passing
* the ownership of the frames to someone else, or destroying them.
*/
[[nodiscard]] nsFrameList StealPushedChildList();
/**
* Prepare our absolute child list so that it is ready to reflow by moving all
* the pushed absolute frames in aDelegatingFrame's prev-in-flow's absCB, and
* some in our own pushed absolute child list, to our absolute child list.
*
* @return true if we have absolute frames after we return.
*/
bool PrepareAbsoluteFrames(nsContainerFrame* aDelegatingFrame);
/**
* Return true if we have absolute frames.
*
* Note: During reflow, consider calling PrepareAbsoluteFrames() rather than
* this method; it moves absolute frames from other lists to mAbsoluteFrames,
* which may be needed to get the correct result.
*/
bool HasAbsoluteFrames() const { return mAbsoluteFrames.NotEmpty(); }
/**
* Called by the delegating frame after it has done its reflow first. This
* function will reflow any absolutely positioned child frames that need to
* be reflowed, e.g., because the absolutely positioned child frame has
* 'auto' for an offset, or a percentage based width or height.
*
* @param aOverflowAreas, if non-null, is unioned with (in the local
* coordinate space) the overflow areas of the absolutely positioned
* children.
* @param aReflowStatus This function merges in the statuses of the absolutely
* positioned children's reflows.
* @param aContainingBlock Rect representing the area where absolute
* positioned children can be positioned. Generally, this is the padding rect
* of `aDelegatingFrame` (Which would not have a valid mRect set during
* reflow), offset against the `aDelegatingFrame`'s border rect.
* @param aFlags zero or more AbsPosReflowFlags
*/
void Reflow(nsContainerFrame* aDelegatingFrame, nsPresContext* aPresContext,
const ReflowInput& aReflowInput, nsReflowStatus& aReflowStatus,
const nsRect& aContainingBlock, AbsPosReflowFlags aFlags,
OverflowAreas* aOverflowAreas);
using DestroyContext = nsIFrame::DestroyContext;
void DestroyFrames(DestroyContext&);
/**
* Mark our size-dependent absolute frames with NS_FRAME_HAS_DIRTY_CHILDREN
* so that we'll make sure to reflow them.
*/
void MarkSizeDependentFramesDirty();
/**
* Mark all our absolute frames with NS_FRAME_IS_DIRTY.
*/
void MarkAllFramesDirty();
/**
* Rects for abspos frames to position against. Differences are relevant
* for containing blocks that scroll.
*
*/
struct ContainingBlockRects {
nsRect mLocal;
nsRect mScrollable;
};
protected:
/**
* Returns true if the position of aFrame depends on the position of
* its placeholder or if the position or size of aFrame depends on a
* containing block dimension that changed.
*/
bool FrameDependsOnContainer(
nsIFrame* aFrame, bool aCBWidthChanged, bool aCBHeightChanged,
mozilla::AnchorPosResolutionCache* aAnchorPosResolutionCache = nullptr);
/**
* After an abspos child's size is known, this method can be used to
* resolve size-dependent values in the ComputedLogicalOffsets on its
* reflow input.
*
* aCBSize, aKidSize, aMargin, aOffsets, are all expected in the absolute
* containing block's writing-mode.
*
* aOffset is an outparam.
*/
void ResolveSizeDependentOffsets(ReflowInput& aKidReflowInput,
const LogicalSize& aCBSize,
const LogicalSize& aKidSize,
const LogicalMargin& aMargin,
const AnchorOffsetInfo& aAnchorOffsetInfo,
LogicalMargin& aOffsets);
/**
* For frames that have intrinsic block sizes, since we want to use the
* frame's actual instrinsic block-size, we don't compute margins in
* InitAbsoluteConstraints because the block-size isn't computed yet. This
* method computes the margins for them after layout.
*
* aCBSize, aKidSize, aMargin, aOffsets, are all expected in the absolute
* containing block's writing-mode.
*
* aMargin and aOffsets are both outparams (though we only touch aOffsets if
* the position is overconstrained)
*/
void ResolveAutoMarginsAfterLayout(ReflowInput& aKidReflowInput,
const LogicalSize& aCBSize,
const LogicalSize& aKidSize,
LogicalMargin& aMargin,
const LogicalMargin& aOffsets);
void ReflowAbsoluteFrame(
nsContainerFrame* aDelegatingFrame, nsPresContext* aPresContext,
const ReflowInput& aReflowInput,
const ContainingBlockRects& aContainingBlockRects,
AbsPosReflowFlags aFlags, nsIFrame* aKidFrame, nsReflowStatus& aStatus,
OverflowAreas* aOverflowAreas,
const ContainingBlockRects* aFragmentedContainingBlockRects,
AnchorPosResolutionCache* aAnchorPosResolutionCache,
bool aReuseUnfragmentedAnchorPosReferences);
/**
* Mark our absolute frames dirty.
* @param aMarkAllDirty if true, all will be marked with NS_FRAME_IS_DIRTY.
* Otherwise, the size-dependant ones will be marked with
* NS_FRAME_HAS_DIRTY_CHILDREN.
*/
void DoMarkFramesDirty(bool aMarkAllDirty);
/**
* Remove aFrame from one of our frame lists without destroying it.
*/
void StealFrame(nsIFrame* aFrame);
/**
* Move any frame in our pushed absolute list into our absolute child list, if
* it is a first-in-flow, or if its prev-in-flow is not present in our
* absolute child list.
*
* @param aDelegatingFrame the frame that owns us.
*/
void DrainPushedChildList(const nsIFrame* aDelegatingFrame);
// Stores the abspos frames that have been placed in this containing block.
nsFrameList mAbsoluteFrames;
// A temporary frame list used during reflow, storing abspos frames that need
// to be reflowed by the delegating frame's next-in-flow after transferring
// them to its own AbsoluteContainingBlock.
nsFrameList mPushedAbsoluteFrames;
// Suppose D is the distance from an absolute containing block fragment's
// border-box block-start edge to whichever is larger of either (a) its
// border-box block-end edge, or (b) the available space's block-end
// edge.
//
// TODO (TYLin, Bug 2009647): We currently assume (a) cannot be bigger than
// (b), but it can if there is an unfragmentable in-flow element.
//
// This variable stores the sum of the D values for the current absolute
// containing block fragment and for all its previous fragments. It represents
// the offset from the start of the theoretical unfragmented abspos containing
// block to the start of the current fragment. During reflow, we subtract this
// value from abspos frames' unfragmented positions to get their local
// coordinate space position in the current fragment.
nscoord mCumulativeContainingBlockBSize = 0;
#ifdef DEBUG
void SanityCheckChildListsBeforeReflow(
const nsIFrame* aDelegatingFrame) const;
#endif
};
} // namespace mozilla
#endif /* LAYOUT_GENERIC_ABSOLUTE_CONTAINING_BLOCK_H_ */