nsColumnSetFrame.h (8175B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef nsColumnSetFrame_h___ 8 #define nsColumnSetFrame_h___ 9 10 /* rendering object for css3 multi-column layout */ 11 12 #include "nsContainerFrame.h" 13 14 class nsCSSBorderRenderer; 15 16 /** 17 * nsColumnSetFrame implements CSS multi-column layout. 18 * @note nsColumnSetFrame keeps true overflow containers in the normal flow 19 * child lists (i.e. the principal and overflow lists). 20 */ 21 class nsColumnSetFrame final : public nsContainerFrame { 22 public: 23 NS_DECL_FRAMEARENA_HELPERS(nsColumnSetFrame) 24 25 explicit nsColumnSetFrame(ComputedStyle* aStyle, nsPresContext* aPresContext); 26 27 void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, 28 const ReflowInput& aReflowInput, 29 nsReflowStatus& aStatus) override; 30 31 #ifdef DEBUG 32 void SetInitialChildList(ChildListID aListID, 33 nsFrameList&& aChildList) override; 34 void AppendFrames(ChildListID aListID, nsFrameList&& aFrameList) override; 35 void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame, 36 const nsLineList::iterator* aPrevFrameLine, 37 nsFrameList&& aFrameList) override; 38 void RemoveFrame(DestroyContext&, ChildListID, nsIFrame*) override; 39 #endif 40 41 nscoord IntrinsicISize(const mozilla::IntrinsicSizeInput& aInput, 42 mozilla::IntrinsicISizeType aType) override; 43 44 nsContainerFrame* GetContentInsertionFrame() override { 45 nsIFrame* frame = PrincipalChildList().FirstChild(); 46 47 // if no children return nullptr 48 if (!frame) { 49 return nullptr; 50 } 51 52 return frame->GetContentInsertionFrame(); 53 } 54 55 void BuildDisplayList(nsDisplayListBuilder* aBuilder, 56 const nsDisplayListSet& aLists) override; 57 58 /** 59 * Similar to nsBlockFrame::DrainOverflowLines. Locate any columns not 60 * handled by our prev-in-flow, and any columns sitting on our own 61 * overflow list, and put them in our primary child list for reflowing. 62 */ 63 void DrainOverflowColumns(); 64 65 // Return the column-content frame. 66 void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override; 67 68 #ifdef DEBUG_FRAME_DUMP 69 nsresult GetFrameName(nsAString& aResult) const override { 70 return MakeFrameName(u"ColumnSet"_ns, aResult); 71 } 72 #endif 73 74 void CreateBorderRenderers(nsTArray<nsCSSBorderRenderer>& aBorderRenderers, 75 gfxContext* aCtx, const nsRect& aDirtyRect, 76 const nsPoint& aPt); 77 78 Maybe<nscoord> GetNaturalBaselineBOffset( 79 mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, 80 BaselineExportContext aExportContext) const override; 81 82 protected: 83 nscoord mLastBalanceBSize; 84 nsReflowStatus mLastFrameStatus; 85 86 /** 87 * These are the parameters that control the layout of columns. 88 */ 89 struct ReflowConfig { 90 // The optimal number of columns that we want to use. This is computed from 91 // column-count, column-width, available inline-size, etc. 92 int32_t mUsedColCount = INT32_MAX; 93 94 // The inline-size of each individual column. 95 nscoord mColISize = NS_UNCONSTRAINEDSIZE; 96 97 // The amount of inline-size that is expected to be left over after all the 98 // columns and column gaps are laid out. 99 nscoord mExpectedISizeLeftOver = 0; 100 101 // The width (inline-size) of each column gap. 102 nscoord mColGap = NS_UNCONSTRAINEDSIZE; 103 104 // The available block-size of each individual column. This parameter is set 105 // during each iteration of the binary search for the best column 106 // block-size. 107 nscoord mColBSize = NS_UNCONSTRAINEDSIZE; 108 109 // A boolean controlling whether or not we are balancing. 110 bool mIsBalancing = false; 111 112 // A boolean controlling whether or not we are forced to fill columns 113 // sequentially. 114 bool mForceAuto = false; 115 116 // A boolean indicates whether or not we are in the last attempt to reflow 117 // columns. We set it to true at the end of FindBestBalanceBSize(). 118 bool mIsLastBalancingReflow = false; 119 120 // The last known column block-size that was 'feasible'. A column bSize is 121 // feasible if all child content fits within the specified bSize. 122 nscoord mKnownFeasibleBSize = NS_UNCONSTRAINEDSIZE; 123 124 // The last known block-size that was 'infeasible'. A column bSize is 125 // infeasible if not all child content fits within the specified bSize. 126 nscoord mKnownInfeasibleBSize = 0; 127 }; 128 129 // Collect various block-size data calculated in ReflowChildren(), which are 130 // mainly used for column balancing. This is the output of ReflowChildren() 131 // and ReflowColumns(). 132 struct ColumnBalanceData { 133 // The maximum "content block-size" of any column 134 nscoord mMaxBSize = 0; 135 136 // The sum of the "content block-size" for all columns 137 nscoord mSumBSize = 0; 138 139 // The "content block-size" of the last column 140 nscoord mLastBSize = 0; 141 142 // The maximum "content block-size" of all columns that overflowed 143 // their available block-size 144 nscoord mMaxOverflowingBSize = 0; 145 146 // The number of columns (starting from 1 because we have at least one 147 // column). It can be less than ReflowConfig::mUsedColCount. 148 int32_t mColCount = 1; 149 150 // This flag indicates the content that was reflowed fits into the 151 // mColMaxBSize in ReflowConfig. 152 bool mFeasible = false; 153 }; 154 155 ColumnBalanceData ReflowColumns(ReflowOutput& aDesiredSize, 156 const ReflowInput& aReflowInput, 157 nsReflowStatus& aStatus, 158 const ReflowConfig& aConfig, 159 bool aUnboundedLastColumn); 160 161 /** 162 * The basic reflow strategy is to call this function repeatedly to 163 * obtain specific parameters that determine the layout of the 164 * columns. This function will compute those parameters from the CSS 165 * style. This function will also be responsible for implementing 166 * the state machine that controls column balancing. 167 */ 168 ReflowConfig ChooseColumnStrategy(const ReflowInput& aReflowInput, 169 bool aForceAuto) const; 170 171 /** 172 * Perform the binary search for the best balance block-size for this column 173 * set. 174 * 175 * @param aReflowInput The input parameters for the current reflow iteration. 176 * @param aPresContext The presentation context in which the current reflow 177 * iteration is occurring. 178 * @param aConfig The ReflowConfig object associated with this column set 179 * frame, generated by ChooseColumnStrategy(). 180 * @param aColData A data structure used to keep track of data needed between 181 * successive iterations of the balancing process. 182 * @param aDesiredSize The final output size of the column set frame (output 183 * of reflow procedure). 184 * @param aUnboundedLastColumn A boolean value indicating that the last column 185 * can be of any block-size. Used during the first iteration of the 186 * balancing procedure to measure the block-size of all content in 187 * descendant frames of the column set. 188 * @param aStatus A final reflow status of the column set frame, passed in as 189 * an output parameter. 190 */ 191 void FindBestBalanceBSize(const ReflowInput& aReflowInput, 192 nsPresContext* aPresContext, ReflowConfig& aConfig, 193 ColumnBalanceData aColData, 194 ReflowOutput& aDesiredSize, 195 bool aUnboundedLastColumn, nsReflowStatus& aStatus); 196 197 void ForEachColumnRule( 198 const std::function<void(const nsRect& lineRect)>& aSetLineRect, 199 const nsPoint& aPt) const; 200 201 // MinISize() and PrefISize() are helpers to implement IntrinsicISize(). 202 nscoord MinISize(const mozilla::IntrinsicSizeInput& aInput); 203 nscoord PrefISize(const mozilla::IntrinsicSizeInput& aInput); 204 }; 205 206 #endif // nsColumnSetFrame_h___