summaryrefslogtreecommitdiffstats
path: root/layout/generic/nsFlexContainerFrame.h
diff options
context:
space:
mode:
Diffstat (limited to 'layout/generic/nsFlexContainerFrame.h')
-rw-r--r--layout/generic/nsFlexContainerFrame.h327
1 files changed, 327 insertions, 0 deletions
diff --git a/layout/generic/nsFlexContainerFrame.h b/layout/generic/nsFlexContainerFrame.h
new file mode 100644
index 000000000..22b420d85
--- /dev/null
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -0,0 +1,327 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+
+/* This Source Code is subject to the terms of the Mozilla Public License
+ * version 2.0 (the "License"). You can obtain a copy of the License at
+ * http://mozilla.org/MPL/2.0/. */
+
+/* rendering object for CSS "display: flex" and "display: -webkit-box" */
+
+#ifndef nsFlexContainerFrame_h___
+#define nsFlexContainerFrame_h___
+
+#include "nsContainerFrame.h"
+#include "mozilla/UniquePtr.h"
+
+namespace mozilla {
+template <class T> class LinkedList;
+class LogicalPoint;
+} // namespace mozilla
+
+nsContainerFrame* NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
+ nsStyleContext* aContext);
+
+
+/**
+ * This is the rendering object used for laying out elements with
+ * "display: flex" or "display: inline-flex".
+ *
+ * We also use this class for elements with "display: -webkit-box" or
+ * "display: -webkit-inline-box" (but not "-moz-box" / "-moz-inline-box" --
+ * those are rendered with old-school XUL frame classes).
+ *
+ * Note: we represent the -webkit-box family of properties (-webkit-box-orient,
+ * -webkit-box-flex, etc.) as aliases for their -moz equivalents. And for
+ * -webkit-{inline-}box containers, nsFlexContainerFrame will honor those
+ * "legacy" properties for alignment/flexibility/etc. *instead of* honoring the
+ * modern flexbox & alignment properties. For brevity, many comments in
+ * nsFlexContainerFrame.cpp simply refer to these properties using their
+ * "-webkit" versions, since we're mostly expecting to encounter them in that
+ * form. (Technically, the "-moz" versions of these properties *can* influence
+ * layout here as well (since that's what the -webkit versions are aliased to)
+ * -- but only inside of a "display:-webkit-{inline-}box" container.)
+ */
+class nsFlexContainerFrame : public nsContainerFrame {
+public:
+ NS_DECL_FRAMEARENA_HELPERS
+ NS_DECL_QUERYFRAME_TARGET(nsFlexContainerFrame)
+ NS_DECL_QUERYFRAME
+
+ // Factory method:
+ friend nsContainerFrame* NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
+ nsStyleContext* aContext);
+
+ // Forward-decls of helper classes
+ class FlexItem;
+ class FlexLine;
+ class FlexboxAxisTracker;
+ struct StrutInfo;
+
+ // nsIFrame overrides
+ void Init(nsIContent* aContent,
+ nsContainerFrame* aParent,
+ nsIFrame* aPrevInFlow) override;
+
+ virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
+ const nsRect& aDirtyRect,
+ const nsDisplayListSet& aLists) override;
+
+ virtual void Reflow(nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus) override;
+
+ virtual nscoord
+ GetMinISize(nsRenderingContext* aRenderingContext) override;
+ virtual nscoord
+ GetPrefISize(nsRenderingContext* aRenderingContext) override;
+
+ virtual nsIAtom* GetType() const override;
+#ifdef DEBUG_FRAME_DUMP
+ virtual nsresult GetFrameName(nsAString& aResult) const override;
+#endif
+
+ nscoord GetLogicalBaseline(mozilla::WritingMode aWM) const override;
+
+ bool GetVerticalAlignBaseline(mozilla::WritingMode aWM,
+ nscoord* aBaseline) const override
+ {
+ return GetNaturalBaselineBOffset(aWM, BaselineSharingGroup::eFirst, aBaseline);
+ }
+
+ bool GetNaturalBaselineBOffset(mozilla::WritingMode aWM,
+ BaselineSharingGroup aBaselineGroup,
+ nscoord* aBaseline) const override
+ {
+ if (HasAnyStateBits(NS_STATE_FLEX_SYNTHESIZE_BASELINE)) {
+ return false;
+ }
+ *aBaseline = aBaselineGroup == BaselineSharingGroup::eFirst ?
+ mBaselineFromLastReflow : mLastBaselineFromLastReflow;
+ return true;
+ }
+
+ // nsContainerFrame overrides
+ uint16_t CSSAlignmentForAbsPosChild(
+ const ReflowInput& aChildRI,
+ mozilla::LogicalAxis aLogicalAxis) const override;
+
+ // Flexbox-specific public methods
+ bool IsHorizontal();
+
+ /**
+ * Helper function to calculate packing space and initial offset of alignment
+ * subjects in MainAxisPositionTracker() and CrossAxisPositionTracker() for
+ * space-between, space-around, and space-evenly.
+ *
+ * @param aNumThingsToPack Number of alignment subjects.
+ * @param aAlignVal Value for align-self or justify-self.
+ * @param aFirstSubjectOffset Outparam for first subject offset.
+ * @param aNumPackingSpacesRemaining Outparam for number of equal-sized
+ * packing spaces to apply between each
+ * alignment subject.
+ * @param aPackingSpaceRemaining Outparam for total amount of packing
+ * space to be divided up.
+ */
+ static void CalculatePackingSpace(uint32_t aNumThingsToPack,
+ uint8_t aAlignVal,
+ nscoord* aFirstSubjectOffset,
+ uint32_t* aNumPackingSpacesRemaining,
+ nscoord* aPackingSpaceRemaining);
+
+protected:
+ // Protected constructor & destructor
+ explicit nsFlexContainerFrame(nsStyleContext* aContext)
+ : nsContainerFrame(aContext)
+ , mBaselineFromLastReflow(NS_INTRINSIC_WIDTH_UNKNOWN)
+ , mLastBaselineFromLastReflow(NS_INTRINSIC_WIDTH_UNKNOWN)
+ {}
+ virtual ~nsFlexContainerFrame();
+
+ /*
+ * This method does the bulk of the flex layout, implementing the algorithm
+ * described at:
+ * http://dev.w3.org/csswg/css-flexbox/#layout-algorithm
+ * (with a few initialization pieces happening in the caller, Reflow().
+ *
+ * Since this is a helper for Reflow(), this takes all the same parameters
+ * as Reflow(), plus a few more parameters that Reflow() sets up for us.
+ *
+ * (The logic behind the division of work between Reflow and DoFlexLayout is
+ * as follows: DoFlexLayout() begins at the step that we have to jump back
+ * to, if we find any visibility:collapse children, and Reflow() does
+ * everything before that point.)
+ */
+ void DoFlexLayout(nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus,
+ nscoord aContentBoxMainSize,
+ nscoord aAvailableBSizeForContent,
+ nsTArray<StrutInfo>& aStruts,
+ const FlexboxAxisTracker& aAxisTracker);
+
+ /**
+ * Checks whether our child-frame list "mFrames" is sorted, using the given
+ * IsLessThanOrEqual function, and sorts it if it's not already sorted.
+ *
+ * XXXdholbert Once we support pagination, we need to make this function
+ * check our continuations as well (or wrap it in a function that does).
+ *
+ * @return true if we had to sort mFrames, false if it was already sorted.
+ */
+ template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
+ bool SortChildrenIfNeeded();
+
+ // Protected flex-container-specific methods / member-vars
+#ifdef DEBUG
+ void SanityCheckAnonymousFlexItems() const;
+#endif // DEBUG
+
+ /*
+ * Returns a new FlexItem for the given child frame, allocated on the heap.
+ * Guaranteed to return non-null. Caller is responsible for managing the
+ * FlexItem's lifetime.
+ *
+ * Before returning, this method also processes the FlexItem to resolve its
+ * flex basis (including e.g. auto-height) as well as to resolve
+ * "min-height:auto", via ResolveAutoFlexBasisAndMinSize(). (Basically, the
+ * returned FlexItem will be ready to participate in the "Resolve the
+ * Flexible Lengths" step of the Flex Layout Algorithm.)
+ */
+ mozilla::UniquePtr<FlexItem> GenerateFlexItemForChild(nsPresContext* aPresContext,
+ nsIFrame* aChildFrame,
+ const ReflowInput& aParentReflowInput,
+ const FlexboxAxisTracker& aAxisTracker);
+
+ /**
+ * This method performs a "measuring" reflow to get the content height of
+ * aFlexItem.Frame() (treating it as if it had auto-height), & returns the
+ * resulting height.
+ * (Helper for ResolveAutoFlexBasisAndMinSize().)
+ */
+ nscoord MeasureFlexItemContentHeight(nsPresContext* aPresContext,
+ FlexItem& aFlexItem,
+ bool aForceVerticalResizeForMeasuringReflow,
+ const ReflowInput& aParentReflowInput);
+
+ /**
+ * This method resolves an "auto" flex-basis and/or min-main-size value
+ * on aFlexItem, if needed.
+ * (Helper for GenerateFlexItemForChild().)
+ */
+ void ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
+ FlexItem& aFlexItem,
+ const ReflowInput& aItemReflowInput,
+ const FlexboxAxisTracker& aAxisTracker);
+
+ /**
+ * This method:
+ * - Creates FlexItems for all of our child frames (except placeholders).
+ * - Groups those FlexItems into FlexLines.
+ * - Returns those FlexLines in the outparam |aLines|.
+ *
+ * For any child frames which are placeholders, this method will instead just
+ * append that child to the outparam |aPlaceholders| for separate handling.
+ * (Absolutely positioned children of a flex container are *not* flex items.)
+ */
+ void GenerateFlexLines(nsPresContext* aPresContext,
+ const ReflowInput& aReflowInput,
+ nscoord aContentBoxMainSize,
+ nscoord aAvailableBSizeForContent,
+ const nsTArray<StrutInfo>& aStruts,
+ const FlexboxAxisTracker& aAxisTracker,
+ nsTArray<nsIFrame*>& aPlaceholders,
+ mozilla::LinkedList<FlexLine>& aLines);
+
+ nscoord GetMainSizeFromReflowInput(const ReflowInput& aReflowInput,
+ const FlexboxAxisTracker& aAxisTracker);
+
+ nscoord ComputeCrossSize(const ReflowInput& aReflowInput,
+ const FlexboxAxisTracker& aAxisTracker,
+ nscoord aSumLineCrossSizes,
+ nscoord aAvailableBSizeForContent,
+ bool* aIsDefinite,
+ nsReflowStatus& aStatus);
+
+ void SizeItemInCrossAxis(nsPresContext* aPresContext,
+ const FlexboxAxisTracker& aAxisTracker,
+ ReflowInput& aChildReflowInput,
+ FlexItem& aItem);
+
+ /**
+ * Moves the given flex item's frame to the given LogicalPosition (modulo any
+ * relative positioning).
+ *
+ * This can be used in cases where we've already done a "measuring reflow"
+ * for the flex item at the correct size, and hence can skip its final reflow
+ * (but still need to move it to the right final position).
+ *
+ * @param aReflowInput The flex container's reflow state.
+ * @param aItem The flex item whose frame should be moved.
+ * @param aFramePos The position where the flex item's frame should
+ * be placed. (pre-relative positioning)
+ * @param aContainerSize The flex container's size (required by some methods
+ * that we call, to interpret aFramePos correctly).
+ */
+ void MoveFlexItemToFinalPosition(const ReflowInput& aReflowInput,
+ const FlexItem& aItem,
+ mozilla::LogicalPoint& aFramePos,
+ const nsSize& aContainerSize);
+ /**
+ * Helper-function to reflow a child frame, at its final position determined
+ * by flex layout.
+ *
+ * @param aPresContext The presentation context being used in reflow.
+ * @param aAxisTracker A FlexboxAxisTracker with the flex container's axes.
+ * @param aReflowInput The flex container's reflow state.
+ * @param aItem The flex item to be reflowed.
+ * @param aFramePos The position where the flex item's frame should
+ * be placed. (pre-relative positioning)
+ * @param aContainerSize The flex container's size (required by some methods
+ * that we call, to interpret aFramePos correctly).
+ */
+ void ReflowFlexItem(nsPresContext* aPresContext,
+ const FlexboxAxisTracker& aAxisTracker,
+ const ReflowInput& aReflowInput,
+ const FlexItem& aItem,
+ mozilla::LogicalPoint& aFramePos,
+ const nsSize& aContainerSize);
+
+ /**
+ * Helper-function to perform a "dummy reflow" on all our nsPlaceholderFrame
+ * children, at the container's content-box origin.
+ *
+ * This doesn't actually represent the static position of the placeholders'
+ * out-of-flow (OOF) frames -- we can't compute that until we've reflowed the
+ * OOF, because (depending on the CSS Align properties) the static position
+ * may be influenced by the OOF's size. So for now, we just co-opt the
+ * placeholder to store the flex container's logical content-box origin, and
+ * we defer to nsAbsoluteContainingBlock to determine the OOF's actual static
+ * position (using this origin, the OOF's size, and the CSS Align
+ * properties).
+ *
+ * @param aPresContext The presentation context being used in reflow.
+ * @param aReflowInput The flex container's reflow input.
+ * @param aPlaceholders An array of all the flex container's
+ * nsPlaceholderFrame children.
+ * @param aContentBoxOrigin The flex container's logical content-box
+ * origin (in its own coordinate space).
+ * @param aContainerSize The flex container's size (required by some
+ * reflow methods to interpret positions correctly).
+ */
+ void ReflowPlaceholders(nsPresContext* aPresContext,
+ const ReflowInput& aReflowInput,
+ nsTArray<nsIFrame*>& aPlaceholders,
+ const mozilla::LogicalPoint& aContentBoxOrigin,
+ const nsSize& aContainerSize);
+
+ bool mChildrenHaveBeenReordered; // Have we ever had to reorder our kids
+ // to satisfy their 'order' values?
+
+ nscoord mBaselineFromLastReflow;
+ // Note: the last baseline is a distance from our border-box end edge.
+ nscoord mLastBaselineFromLastReflow;
+};
+
+#endif /* nsFlexContainerFrame_h___ */