/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsColumnSetFrame_h___ #define nsColumnSetFrame_h___ /* rendering object for css3 multi-column layout */ #include "mozilla/Attributes.h" #include "nsContainerFrame.h" #include "nsIFrameInlines.h" // for methods used by IS_TRUE_OVERFLOW_CONTAINER /** * nsColumnSetFrame implements CSS multi-column layout. * @note nsColumnSetFrame keeps true overflow containers in the normal flow * child lists (i.e. the principal and overflow lists). */ class nsColumnSetFrame final : public nsContainerFrame { public: NS_DECL_FRAMEARENA_HELPERS(nsColumnSetFrame) explicit nsColumnSetFrame(ComputedStyle* aStyle); virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) override; #ifdef DEBUG virtual void SetInitialChildList(ChildListID aListID, nsFrameList& aChildList) override; virtual void AppendFrames(ChildListID aListID, nsFrameList& aFrameList) override; virtual void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame, nsFrameList& aFrameList) override; virtual void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override; #endif virtual nscoord GetMinISize(gfxContext *aRenderingContext) override; virtual nscoord GetPrefISize(gfxContext *aRenderingContext) override; /** * Retrieve the available height for content of this frame. The available content * height is the available height for the frame, minus borders and padding. */ virtual nscoord GetAvailableContentBSize(const ReflowInput& aReflowInput); virtual nsContainerFrame* GetContentInsertionFrame() override { nsIFrame* frame = PrincipalChildList().FirstChild(); // if no children return nullptr if (!frame) return nullptr; return frame->GetContentInsertionFrame(); } virtual bool IsFrameOfType(uint32_t aFlags) const override { return nsContainerFrame::IsFrameOfType(aFlags & ~(nsIFrame::eCanContainOverflowContainers)); } virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) override; /** * Similar to nsBlockFrame::DrainOverflowLines. Locate any columns not * handled by our prev-in-flow, and any columns sitting on our own * overflow list, and put them in our primary child list for reflowing. */ void DrainOverflowColumns(); // Return the column-content frame. void AppendDirectlyOwnedAnonBoxes(nsTArray& aResult) override; #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override { return MakeFrameName(NS_LITERAL_STRING("ColumnSet"), aResult); } #endif nsRect CalculateColumnRuleBounds(const nsPoint& aOffset); void CreateBorderRenderers(nsTArray& aBorderRenderers, gfxContext* aCtx, const nsRect& aDirtyRect, const nsPoint& aPt); protected: nscoord mLastBalanceBSize; nsReflowStatus mLastFrameStatus; /** * These are the parameters that control the layout of columns. */ struct ReflowConfig { // The number of columns that we want to balance across. If we're not // balancing, this will be set to INT32_MAX. int32_t mBalanceColCount; // The inline-size of each individual column. nscoord mColISize; // The amount of inline-size that is expected to be left over after all the // columns and column gaps are laid out. nscoord mExpectedISizeLeftOver; // The width (inline-size) of each column gap. nscoord mColGap; // The maximum bSize of any individual column during a reflow iteration. // This parameter is set during each iteration of the binary search for // the best column block-size. nscoord mColMaxBSize; // A boolean controlling whether or not we are balancing. This should be // equivalent to mBalanceColCount == INT32_MAX. bool mIsBalancing; // The last known column block-size that was 'feasible'. A column bSize is // feasible if all child content fits within the specified bSize. nscoord mKnownFeasibleBSize; // The last known block-size that was 'infeasible'. A column bSize is // infeasible if not all child content fits within the specified bSize. nscoord mKnownInfeasibleBSize; // block-size of the column set frame nscoord mComputedBSize; // The block-size "consumed" by previous-in-flows. // The computed block-size should be equal to the block-size of the element // (i.e. the computed block-size itself) plus the consumed block-size. nscoord mConsumedBSize; }; /** * Some data that is better calculated during reflow */ struct ColumnBalanceData { // The maximum "content block-size" of any column nscoord mMaxBSize; // The sum of the "content block-size" for all columns nscoord mSumBSize; // The "content block-size" of the last column nscoord mLastBSize; // The maximum "content block-size" of all columns that overflowed // their available block-size nscoord mMaxOverflowingBSize; // This flag determines whether the last reflow of children exceeded the // computed block-size of the column set frame. If so, we set the bSize to // this maximum allowable bSize, and continue reflow without balancing. bool mHasExcessBSize; void Reset() { mMaxBSize = mSumBSize = mLastBSize = mMaxOverflowingBSize = 0; mHasExcessBSize = false; } }; bool ReflowColumns(ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aReflowStatus, ReflowConfig& aConfig, bool aLastColumnUnbounded, nsCollapsingMargin* aCarriedOutBEndMargin, ColumnBalanceData& aColData); /** * The basic reflow strategy is to call this function repeatedly to * obtain specific parameters that determine the layout of the * columns. This function will compute those parameters from the CSS * style. This function will also be responsible for implementing * the state machine that controls column balancing. */ ReflowConfig ChooseColumnStrategy(const ReflowInput& aReflowInput, bool aForceAuto, nscoord aFeasibleBSize, nscoord aInfeasibleBSize); /** * Perform the binary search for the best balance height for this column set. * * @param aReflowInput The input parameters for the current reflow iteration. * @param aPresContext The presentation context in which the current reflow * iteration is occurring. * @param aConfig The ReflowConfig object associated with this column set * frame, generated by ChooseColumnStrategy(). * @param aColData A data structure used to keep track of data needed between * successive iterations of the balancing process. * @param aDesiredSize The final output size of the column set frame (output * of reflow procedure). * @param aOutMargin The bottom margin of the column set frame that may be * carried out from reflow (and thus collapsed). * @param aUnboundedLastColumn A boolean value indicating that the last column * can be of any height. Used during the first iteration of the * balancing procedure to measure the height of all content in * descendant frames of the column set. * @param aRunWasFeasible An input/output parameter indicating whether or not * the last iteration of the balancing loop was a feasible height to * fit all content from descendant frames. * @param aStatus A final reflow status of the column set frame, passed in as * an output parameter. */ void FindBestBalanceBSize(const ReflowInput& aReflowInput, nsPresContext* aPresContext, ReflowConfig& aConfig, ColumnBalanceData& aColData, ReflowOutput& aDesiredSize, nsCollapsingMargin& aOutMargin, bool& aUnboundedLastColumn, bool& aRunWasFeasible, nsReflowStatus& aStatus); /** * Reflow column children. Returns true iff the content that was reflowed * fit into the mColMaxBSize. */ bool ReflowChildren(ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus, const ReflowConfig& aConfig, bool aLastColumnUnbounded, nsCollapsingMargin* aCarriedOutBEndMargin, ColumnBalanceData& aColData); void ForEachColumnRule(const std::function& aSetLineRect, const nsPoint& aPt); static nscoord ClampUsedColumnWidth(const nsStyleCoord& aColumnWidth); }; #endif // nsColumnSetFrame_h___