2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #ifndef LayoutMultiColumnSet_h
28 #define LayoutMultiColumnSet_h
30 #include "core/CoreExport.h"
31 #include "core/layout/LayoutMultiColumnFlowThread.h"
32 #include "core/layout/MultiColumnFragmentainerGroup.h"
33 #include "wtf/Vector.h"
37 // A set of columns in a multicol container. A column set is inserted as an anonymous child of the
38 // actual multicol container (i.e. the layoutObject whose style computes to non-auto column-count and/or
39 // column-width), next to the flow thread. There'll be one column set for each contiguous run of
40 // column content. The only thing that can interrupt a contiguous run of column content is a column
41 // spanner, which means that if there are no spanners, there'll only be one column set.
43 // Since a spanner interrupts an otherwise contiguous run of column content, inserting one may
44 // result in the creation of additional new column sets. A placeholder for the spanning layoutObject has
45 // to be placed in between the column sets that come before and after the spanner, if there's
46 // actually column content both before and after the spanner.
48 // A column set has no children on its own, but is merely used to slice a portion of the tall
49 // "single-column" flow thread into actual columns visually, to convert from flow thread coordinates
50 // to visual ones. It is in charge of both positioning columns correctly relatively to the parent
51 // multicol container, and to calculate the correct translation for each column's contents, and to
52 // paint any rules between them. LayoutMultiColumnSet objects are used for painting, hit testing,
53 // and any other type of operation that requires mapping from flow thread coordinates to visual
56 // Columns are normally laid out in the inline progression direction, but if the multicol container
57 // is inside another fragmentation context (e.g. paged media, or an another multicol container), we
58 // may need to group the columns, so that we get one MultiColumnFragmentainerGroup for each outer
59 // fragmentainer (page / column) that the inner multicol container lives in. Each fragmentainer
60 // group has its own column height, but the column height is uniform within a group.
61 class CORE_EXPORT LayoutMultiColumnSet
: public LayoutBlockFlow
{
63 static LayoutMultiColumnSet
* createAnonymous(LayoutFlowThread
&, const ComputedStyle
& parentStyle
);
65 const MultiColumnFragmentainerGroup
& firstFragmentainerGroup() const { return m_fragmentainerGroups
.first(); }
66 const MultiColumnFragmentainerGroup
& lastFragmentainerGroup() const { return m_fragmentainerGroups
.last(); }
67 MultiColumnFragmentainerGroup
& fragmentainerGroupAtFlowThreadOffset(LayoutUnit flowThreadOffset
)
69 return m_fragmentainerGroups
[fragmentainerGroupIndexAtFlowThreadOffset(flowThreadOffset
)];
71 const MultiColumnFragmentainerGroup
& fragmentainerGroupAtFlowThreadOffset(LayoutUnit flowThreadOffset
) const
73 return m_fragmentainerGroups
[fragmentainerGroupIndexAtFlowThreadOffset(flowThreadOffset
)];
75 const MultiColumnFragmentainerGroup
& fragmentainerGroupAtVisualPoint(const LayoutPoint
&) const;
77 bool isOfType(LayoutObjectType type
) const override
{ return type
== LayoutObjectLayoutMultiColumnSet
|| LayoutBlockFlow::isOfType(type
); }
78 bool canHaveChildren() const final
{ return false; }
80 // Return the width and height of a single column or page in the set.
81 LayoutUnit
pageLogicalWidth() const { return flowThread()->logicalWidth(); }
82 LayoutUnit
pageLogicalHeightForOffset(LayoutUnit
) const;
83 LayoutUnit
pageRemainingLogicalHeightForOffset(LayoutUnit
, PageBoundaryRule
) const;
84 bool isPageLogicalHeightKnown() const;
86 LayoutFlowThread
* flowThread() const { return m_flowThread
; }
88 LayoutBlockFlow
* multiColumnBlockFlow() const { return toLayoutBlockFlow(parent()); }
89 LayoutMultiColumnFlowThread
* multiColumnFlowThread() const { return toLayoutMultiColumnFlowThread(flowThread()); }
91 LayoutMultiColumnSet
* nextSiblingMultiColumnSet() const;
92 LayoutMultiColumnSet
* previousSiblingMultiColumnSet() const;
94 MultiColumnFragmentainerGroup
& appendNewFragmentainerGroup();
96 LayoutUnit
logicalTopInFlowThread() const;
97 LayoutUnit
logicalBottomInFlowThread() const;
98 LayoutUnit
logicalHeightInFlowThread() const { return logicalBottomInFlowThread() - logicalTopInFlowThread(); }
99 LayoutRect
flowThreadPortionRect() const;
100 LayoutRect
flowThreadPortionOverflowRect() const;
101 LayoutRect
overflowRectForFlowThreadPortion(const LayoutRect
& flowThreadPortionRect
, bool isFirstPortion
, bool isLastPortion
) const;
103 // The used CSS value of column-count, i.e. how many columns there are room for without overflowing.
104 unsigned usedColumnCount() const { return multiColumnFlowThread()->columnCount(); }
106 bool heightIsAuto() const;
108 // Find the column that contains the given block offset, and return the translation needed to
109 // get from flow thread coordinates to visual coordinates.
110 LayoutSize
flowThreadTranslationAtOffset(LayoutUnit
) const;
112 LayoutPoint
visualPointToFlowThreadPoint(const LayoutPoint
& visualPoint
) const;
114 void updateMinimumColumnHeight(LayoutUnit offsetInFlowThread
, LayoutUnit height
);
116 // Add a content run, specified by its end position. A content run is appended at every
117 // forced/explicit break and at the end of the column set. The content runs are used to
118 // determine where implicit/soft breaks will occur, in order to calculate an initial column
120 void addContentRun(LayoutUnit endOffsetFromFirstPage
);
122 // (Re-)calculate the column height if it's auto. This is first and foremost needed by sets that
123 // are to balance the column height, but even when it isn't to be balanced, this is necessary if
124 // the multicol container's height is constrained.
125 bool recalculateColumnHeight(BalancedColumnHeightCalculation
);
127 // Record space shortage (the amount of space that would have been enough to prevent some
128 // element from being moved to the next column) at a column break. The smallest amount of space
129 // shortage we find is the amount with which we will stretch the column height, if it turns out
130 // after layout that the columns weren't tall enough.
131 void recordSpaceShortage(LayoutUnit offsetInFlowThread
, LayoutUnit
);
133 // Reset previously calculated column height. Will mark for layout if needed.
134 void resetColumnHeight();
136 // Layout of flow thread content that's to be rendered inside this column set begins. This
137 // happens at the beginning of flow thread layout, and when advancing from a previous column set
138 // or spanner to this one.
139 void beginFlow(LayoutUnit offsetInFlowThread
);
141 // Layout of flow thread content that was to be rendered inside this column set has
142 // finished. This happens at end of flow thread layout, and when advancing to the next column
144 void endFlow(LayoutUnit offsetInFlowThread
);
146 void computeIntrinsicLogicalWidths(LayoutUnit
& minLogicalWidth
, LayoutUnit
& maxLogicalWidth
) const final
;
148 void attachToFlowThread();
149 void detachFromFlowThread();
151 // The top of the page nearest to the specified block offset. All in flowthread coordinates.
152 LayoutUnit
pageLogicalTopForOffset(LayoutUnit offset
) const;
154 LayoutRect
fragmentsBoundingBox(const LayoutRect
& boundingBoxInFlowThread
) const;
156 void collectLayerFragments(DeprecatedPaintLayerFragments
&, const LayoutRect
& layerBoundingBox
, const LayoutRect
& dirtyRect
);
158 LayoutUnit
columnGap() const;
160 // The "CSS actual" value of column-count. This includes overflowing columns, if any.
161 unsigned actualColumnCount() const;
163 const char* name() const override
{ return "LayoutMultiColumnSet"; }
166 LayoutMultiColumnSet(LayoutFlowThread
*);
169 unsigned fragmentainerGroupIndexAtFlowThreadOffset(LayoutUnit
) const;
171 void insertedIntoTree() final
;
172 void willBeRemovedFromTree() final
;
174 bool isSelfCollapsingBlock() const override
{ return false; }
176 void computeLogicalHeight(LayoutUnit logicalHeight
, LayoutUnit logicalTop
, LogicalExtentComputedValues
&) const override
;
177 PositionWithAffinity
positionForPoint(const LayoutPoint
&) override
;
179 void paintObject(const PaintInfo
&, const LayoutPoint
& paintOffset
) override
;
181 void addOverflowFromChildren() override
;
183 MultiColumnFragmentainerGroupList m_fragmentainerGroups
;
184 LayoutFlowThread
* m_flowThread
;
187 DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutMultiColumnSet
, isLayoutMultiColumnSet());
191 #endif // LayoutMultiColumnSet_h