summaryrefslogtreecommitdiffstats
path: root/layout/generic/nsColumnSetFrame.h
blob: 20df72a07def215370b258ae7928527e7903ddc3 (plain)
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
/* -*- 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 GetMinISize(gfxContext* aRenderingContext) override;
  nscoord GetPrefISize(gfxContext* aRenderingContext) 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;
};

#endif  // nsColumnSetFrame_h___