1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
/* -*- 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"
class nsCSSBorderRenderer;
/**
* 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, nsPresContext* aPresContext);
void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) override;
#ifdef DEBUG
void SetInitialChildList(ChildListID aListID,
nsFrameList&& aChildList) override;
void AppendFrames(ChildListID aListID, nsFrameList&& aFrameList) override;
void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
const nsLineList::iterator* aPrevFrameLine,
nsFrameList&& aFrameList) override;
void RemoveFrame(DestroyContext&, ChildListID, nsIFrame*) override;
#endif
nscoord IntrinsicISize(const mozilla::IntrinsicSizeInput& aInput,
mozilla::IntrinsicISizeType aType) override;
nsContainerFrame* GetContentInsertionFrame() override {
nsIFrame* frame = PrincipalChildList().FirstChild();
// if no children return nullptr
if (!frame) {
return nullptr;
}
return frame->GetContentInsertionFrame();
}
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<OwnedAnonBox>& aResult) override;
#ifdef DEBUG_FRAME_DUMP
nsresult GetFrameName(nsAString& aResult) const override {
return MakeFrameName(u"ColumnSet"_ns, aResult);
}
#endif
void CreateBorderRenderers(nsTArray<nsCSSBorderRenderer>& aBorderRenderers,
gfxContext* aCtx, const nsRect& aDirtyRect,
const nsPoint& aPt);
Maybe<nscoord> GetNaturalBaselineBOffset(
mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup,
BaselineExportContext aExportContext) const override;
protected:
nscoord mLastBalanceBSize;
nsReflowStatus mLastFrameStatus;
/**
* These are the parameters that control the layout of columns.
*/
struct ReflowConfig {
// The optimal number of columns that we want to use. This is computed from
// column-count, column-width, available inline-size, etc.
int32_t mUsedColCount = INT32_MAX;
// The inline-size of each individual column.
nscoord mColISize = NS_UNCONSTRAINEDSIZE;
// The amount of inline-size that is expected to be left over after all the
// columns and column gaps are laid out.
nscoord mExpectedISizeLeftOver = 0;
// The width (inline-size) of each column gap.
nscoord mColGap = NS_UNCONSTRAINEDSIZE;
// The available block-size of each individual column. This parameter is set
// during each iteration of the binary search for the best column
// block-size.
nscoord mColBSize = NS_UNCONSTRAINEDSIZE;
// A boolean controlling whether or not we are balancing.
bool mIsBalancing = false;
// A boolean controlling whether or not we are forced to fill columns
// sequentially.
bool mForceAuto = false;
// A boolean indicates whether or not we are in the last attempt to reflow
// columns. We set it to true at the end of FindBestBalanceBSize().
bool mIsLastBalancingReflow = false;
// 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 = NS_UNCONSTRAINEDSIZE;
// 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 = 0;
};
// Collect various block-size data calculated in ReflowChildren(), which are
// mainly used for column balancing. This is the output of ReflowChildren()
// and ReflowColumns().
struct ColumnBalanceData {
// The maximum "content block-size" of any column
nscoord mMaxBSize = 0;
// The sum of the "content block-size" for all columns
nscoord mSumBSize = 0;
// The "content block-size" of the last column
nscoord mLastBSize = 0;
// The maximum "content block-size" of all columns that overflowed
// their available block-size
nscoord mMaxOverflowingBSize = 0;
// The number of columns (starting from 1 because we have at least one
// column). It can be less than ReflowConfig::mUsedColCount.
int32_t mColCount = 1;
// This flag indicates the content that was reflowed fits into the
// mColMaxBSize in ReflowConfig.
bool mFeasible = false;
};
ColumnBalanceData ReflowColumns(ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus,
const ReflowConfig& aConfig,
bool aUnboundedLastColumn);
/**
* 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) const;
/**
* Perform the binary search for the best balance block-size 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 aUnboundedLastColumn A boolean value indicating that the last column
* can be of any block-size. Used during the first iteration of the
* balancing procedure to measure the block-size of all content in
* descendant frames of the column set.
* @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,
bool aUnboundedLastColumn, nsReflowStatus& aStatus);
void ForEachColumnRule(
const std::function<void(const nsRect& lineRect)>& aSetLineRect,
const nsPoint& aPt) const;
// MinISize() and PrefISize() are helpers to implement IntrinsicISize().
nscoord MinISize(const mozilla::IntrinsicSizeInput& aInput);
nscoord PrefISize(const mozilla::IntrinsicSizeInput& aInput);
};
#endif // nsColumnSetFrame_h___
|