1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef MultiColumnFragmentainerGroup_h
6 #define MultiColumnFragmentainerGroup_h
8 #include "core/layout/LayoutMultiColumnFlowThread.h"
9 #include "wtf/Allocator.h"
13 // A group of columns, that are laid out in the inline progression direction, all with the same
16 // When a multicol container is inside another fragmentation context, and said multicol container
17 // lives in multiple outer fragmentainers (pages / columns), we need to put these inner columns into
18 // separate groups, with one group per outer fragmentainer. Such a group of columns is what
19 // comprises a "row of column boxes" in spec lingo.
21 // Column balancing, when enabled, takes place within a column fragmentainer group.
23 // Each fragmentainer group may have its own actual column count (if there are unused columns
24 // because of forced breaks, for example). If there are multiple fragmentainer groups, the actual
25 // column count must not exceed the used column count (the one calculated based on column-count and
26 // column-width from CSS), or they'd overflow the outer fragmentainer in the inline direction. If we
27 // need more columns than what a group has room for, we'll create another group and put them there
28 // (and make them appear in the next outer fragmentainer).
29 class MultiColumnFragmentainerGroup
{
30 ALLOW_ONLY_INLINE_ALLOCATION();
32 MultiColumnFragmentainerGroup(LayoutMultiColumnSet
&);
34 bool isLastGroup() const;
36 // Position within the LayoutMultiColumnSet.
37 LayoutUnit
logicalTop() const { return m_logicalTop
; }
38 void setLogicalTop(LayoutUnit logicalTop
) { m_logicalTop
= logicalTop
; }
40 LayoutUnit
logicalHeight() const { return m_columnHeight
; }
42 LayoutSize
offsetFromColumnSet() const;
44 // Return the block offset from the enclosing flow thread, if nested. In the coordinate space
45 // of the enclosing flow thread.
46 LayoutUnit
blockOffsetInEnclosingFlowThread() const;
48 // The top of our flow thread portion
49 LayoutUnit
logicalTopInFlowThread() const { return m_logicalTopInFlowThread
; }
50 void setLogicalTopInFlowThread(LayoutUnit logicalTopInFlowThread
) { m_logicalTopInFlowThread
= logicalTopInFlowThread
; }
52 // The bottom of our flow thread portion
53 LayoutUnit
logicalBottomInFlowThread() const { return m_logicalBottomInFlowThread
; }
54 void setLogicalBottomInFlowThread(LayoutUnit logicalBottomInFlowThread
) { ASSERT(logicalBottomInFlowThread
>= m_logicalTopInFlowThread
); m_logicalBottomInFlowThread
= logicalBottomInFlowThread
; }
56 // The height of our flow thread portion
57 LayoutUnit
logicalHeightInFlowThread() const { return m_logicalBottomInFlowThread
- m_logicalTopInFlowThread
; }
59 bool heightIsAuto() const;
60 void resetColumnHeight();
61 void addContentRun(LayoutUnit endOffsetInFlowThread
);
62 void updateMinimumColumnHeight(LayoutUnit height
) { m_minimumColumnHeight
= std::max(height
, m_minimumColumnHeight
); }
63 void recordSpaceShortage(LayoutUnit
);
64 bool recalculateColumnHeight(BalancedColumnHeightCalculation calculationMode
);
66 LayoutSize
flowThreadTranslationAtOffset(LayoutUnit offsetInFlowThread
) const;
67 LayoutUnit
columnLogicalTopForOffset(LayoutUnit offsetInFlowThread
) const;
68 LayoutPoint
visualPointToFlowThreadPoint(const LayoutPoint
& visualPoint
) const;
69 LayoutRect
fragmentsBoundingBox(const LayoutRect
& boundingBoxInFlowThread
) const;
71 void collectLayerFragments(DeprecatedPaintLayerFragments
&, const LayoutRect
& layerBoundingBox
, const LayoutRect
& dirtyRect
) const;
72 LayoutRect
calculateOverflow() const;
74 // The "CSS actual" value of column-count. This includes overflowing columns, if any.
75 unsigned actualColumnCount() const;
78 LayoutUnit
heightAdjustedForRowOffset(LayoutUnit height
) const;
79 LayoutUnit
calculateMaxColumnHeight() const;
80 void setAndConstrainColumnHeight(LayoutUnit
);
82 // Return the index of the content run with the currently tallest columns, taking all implicit
83 // breaks assumed so far into account.
84 unsigned findRunWithTallestColumns() const;
86 // Given the current list of content runs, make assumptions about where we need to insert
87 // implicit breaks (if there's room for any at all; depending on the number of explicit breaks),
88 // and store the results. This is needed in order to balance the columns.
89 void distributeImplicitBreaks();
91 LayoutUnit
calculateColumnHeight(BalancedColumnHeightCalculation
) const;
93 LayoutRect
columnRectAt(unsigned columnIndex
) const;
94 LayoutUnit
logicalTopInFlowThreadAt(unsigned columnIndex
) const { return m_logicalTopInFlowThread
+ columnIndex
* m_columnHeight
; }
95 LayoutRect
flowThreadPortionRectAt(unsigned columnIndex
) const;
96 LayoutRect
flowThreadPortionOverflowRectAt(unsigned columnIndex
) const;
98 enum ColumnIndexCalculationMode
{
99 ClampToExistingColumns
, // Stay within the range of already existing columns.
100 AssumeNewColumns
// Allow column indices outside the range of already existing columns.
102 unsigned columnIndexAtOffset(LayoutUnit offsetInFlowThread
, ColumnIndexCalculationMode
= ClampToExistingColumns
) const;
104 // Return the column that the specified visual point belongs to. Only the coordinate on the
105 // column progression axis is relevant. Every point belongs to a column, even if said point is
106 // not inside any of the columns.
107 unsigned columnIndexAtVisualPoint(const LayoutPoint
& visualPoint
) const;
109 // Get the first and the last column intersecting the specified block range.
110 // Note that |logicalBottomInFlowThread| is an exclusive endpoint.
111 void columnIntervalForBlockRangeInFlowThread(LayoutUnit logicalTopInFlowThread
, LayoutUnit logicalBottomInFlowThread
, unsigned& firstColumn
, unsigned& lastColumn
) const;
113 // Get the first and the last column intersecting the specified visual rectangle.
114 void columnIntervalForVisualRect(const LayoutRect
&, unsigned& firstColumn
, unsigned& lastColumn
) const;
116 LayoutMultiColumnSet
& m_columnSet
;
118 LayoutUnit m_logicalTop
;
119 LayoutUnit m_logicalTopInFlowThread
;
120 LayoutUnit m_logicalBottomInFlowThread
;
122 LayoutUnit m_columnHeight
;
124 // The following variables are used when balancing the column set.
125 LayoutUnit m_maxColumnHeight
; // Maximum column height allowed.
126 LayoutUnit m_minSpaceShortage
; // The smallest amout of space shortage that caused a column break.
127 LayoutUnit m_minimumColumnHeight
;
129 // A run of content without explicit (forced) breaks; i.e. a flow thread portion between two
130 // explicit breaks, between flow thread start and an explicit break, between an explicit break
131 // and flow thread end, or, in cases when there are no explicit breaks at all: between flow
132 // thread portion start and flow thread portion end. We need to know where the explicit breaks
133 // are, in order to figure out where the implicit breaks will end up, so that we get the columns
134 // properly balanced. A content run starts out as representing one single column, and will
135 // represent one additional column for each implicit break "inserted" there.
138 ContentRun(LayoutUnit breakOffset
)
139 : m_breakOffset(breakOffset
)
140 , m_assumedImplicitBreaks(0) { }
142 unsigned assumedImplicitBreaks() const { return m_assumedImplicitBreaks
; }
143 void assumeAnotherImplicitBreak() { m_assumedImplicitBreaks
++; }
144 LayoutUnit
breakOffset() const { return m_breakOffset
; }
146 // Return the column height that this content run would require, considering the implicit
147 // breaks assumed so far.
148 LayoutUnit
columnLogicalHeight(LayoutUnit startOffset
) const { return ceilf((m_breakOffset
- startOffset
).toFloat() / float(m_assumedImplicitBreaks
+ 1)); }
151 LayoutUnit m_breakOffset
; // Flow thread offset where this run ends.
152 unsigned m_assumedImplicitBreaks
; // Number of implicit breaks in this run assumed so far.
154 Vector
<ContentRun
, 1> m_contentRuns
;
157 // List of all fragmentainer groups within a column set. There will always be at least one
158 // group. Deleting the one group is not allowed (or possible). There will be more than one group if
159 // the owning column set lives in multiple outer fragmentainers (e.g. multicol inside paged media).
160 class CORE_EXPORT MultiColumnFragmentainerGroupList
{
161 DISALLOW_ALLOCATION();
163 MultiColumnFragmentainerGroupList(LayoutMultiColumnSet
&);
164 ~MultiColumnFragmentainerGroupList();
166 // Add an additional fragmentainer group to the end of the list, and return it.
167 MultiColumnFragmentainerGroup
& addExtraGroup();
169 // Remove all fragmentainer groups but the first one.
170 void deleteExtraGroups();
172 MultiColumnFragmentainerGroup
& first() { return m_groups
.first(); }
173 const MultiColumnFragmentainerGroup
& first() const { return m_groups
.first(); }
174 MultiColumnFragmentainerGroup
& last() { return m_groups
.last(); }
175 const MultiColumnFragmentainerGroup
& last() const { return m_groups
.last(); }
177 typedef Vector
<MultiColumnFragmentainerGroup
, 1>::iterator iterator
;
178 typedef Vector
<MultiColumnFragmentainerGroup
, 1>::const_iterator const_iterator
;
180 iterator
begin() { return m_groups
.begin(); }
181 const_iterator
begin() const { return m_groups
.begin(); }
182 iterator
end() { return m_groups
.end(); }
183 const_iterator
end() const { return m_groups
.end(); }
185 size_t size() const { return m_groups
.size(); }
186 MultiColumnFragmentainerGroup
& operator[](size_t i
) { return m_groups
.at(i
); }
187 const MultiColumnFragmentainerGroup
& operator[](size_t i
) const { return m_groups
.at(i
); }
189 void append(const MultiColumnFragmentainerGroup
& group
) { m_groups
.append(group
); }
190 void shrink(size_t size
) { m_groups
.shrink(size
); }
193 LayoutMultiColumnSet
& m_columnSet
;
195 Vector
<MultiColumnFragmentainerGroup
, 1> m_groups
;
200 #endif // MultiColumnFragmentainerGroup_h