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 #include "RenderMultiColumnBlock.h"
28 #include "RenderMultiColumnFlowThread.h"
29 #include "RenderMultiColumnSet.h"
35 RenderMultiColumnBlock::RenderMultiColumnBlock(Node* node)
39 , m_columnWidth(ZERO_LAYOUT_UNIT)
40 , m_columnHeight(ZERO_LAYOUT_UNIT)
44 void RenderMultiColumnBlock::computeColumnCountAndWidth()
46 // Calculate our column width and column count.
47 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
49 m_columnWidth = contentLogicalWidth();
51 ASSERT(!style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth());
53 LayoutUnit availWidth = m_columnWidth;
54 LayoutUnit colGap = columnGap();
55 LayoutUnit colWidth = max<LayoutUnit>(1, LayoutUnit(style()->columnWidth()));
56 int colCount = max<int>(1, style()->columnCount());
58 if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) {
59 m_columnCount = colCount;
60 m_columnWidth = max<LayoutUnit>(0, (availWidth - ((m_columnCount - 1) * colGap)) / m_columnCount);
61 } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) {
62 m_columnCount = max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
63 m_columnWidth = ((availWidth + colGap) / m_columnCount) - colGap;
65 m_columnCount = max<LayoutUnit>(min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
66 m_columnWidth = ((availWidth + colGap) / m_columnCount) - colGap;
70 bool RenderMultiColumnBlock::recomputeLogicalWidth()
72 bool relayoutChildren = RenderBlock::recomputeLogicalWidth();
73 LayoutUnit oldColumnWidth = m_columnWidth;
74 computeColumnCountAndWidth();
75 if (m_columnWidth != oldColumnWidth)
76 relayoutChildren = true;
77 return relayoutChildren;
80 void RenderMultiColumnBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight)
82 // We need to go ahead and set our explicit page height if one exists, so that we can
83 // avoid doing multiple layout passes.
84 computeLogicalHeight();
85 LayoutUnit newContentLogicalHeight = contentLogicalHeight();
86 if (newContentLogicalHeight > ZERO_LAYOUT_UNIT) {
87 pageLogicalHeight = newContentLogicalHeight;
88 hasSpecifiedPageLogicalHeight = true;
90 setLogicalHeight(ZERO_LAYOUT_UNIT);
92 if (columnHeight() != pageLogicalHeight && everHadLayout()) {
93 setColumnHeight(pageLogicalHeight);
94 pageLogicalHeightChanged = true;
97 // Set up our column sets.
101 bool RenderMultiColumnBlock::relayoutForPagination(bool, LayoutUnit, LayoutStateMaintainer&)
107 void RenderMultiColumnBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
110 m_flowThread = new (renderArena()) RenderMultiColumnFlowThread(document());
111 m_flowThread->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK));
112 RenderBlock::addChild(m_flowThread); // Always put the flow thread at the end.
115 // Column sets are siblings of the flow thread. All children designed to be in the columns, however, are part
116 // of the flow thread itself.
117 if (newChild->isRenderMultiColumnSet())
118 RenderBlock::addChild(newChild, beforeChild);
120 m_flowThread->addChild(newChild, beforeChild);
123 void RenderMultiColumnBlock::ensureColumnSets()
125 // This function ensures we have the correct column set information before we get into layout.
126 // For a simple multi-column layout in continuous media, only one column set child is required.
127 // Once a column is nested inside an enclosing pagination context, the number of column sets
128 // required becomes 2n-1, where n is the total number of nested pagination contexts. For example:
130 // Column layout with no enclosing pagination model = 2 * 1 - 1 = 1 column set.
131 // Columns inside pages = 2 * 2 - 1 = 3 column sets (bottom of first page, all the subsequent pages, then the last page).
132 // Columns inside columns inside pages = 2 * 3 - 1 = 5 column sets.
134 // In addition, column spans will force a column set to "split" into before/after sets around the spanning region.
136 // Finally, we will need to deal with columns inside regions. If regions have variable widths, then there will need
137 // to be unique column sets created inside any region whose width is different from its surrounding regions. This is
138 // actually pretty similar to the spanning case, in that we break up the column sets whenever the width varies.
140 // FIXME: For now just make one column set. This matches the old multi-column code.
141 // Right now our goal is just feature parity with the old multi-column code so that we can switch over to the
142 // new code as soon as possible.
143 if (flowThread() && !firstChild()->isRenderMultiColumnSet()) {
144 RenderMultiColumnSet* columnSet = new (renderArena()) RenderMultiColumnSet(document(), flowThread());
145 columnSet->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK));
146 RenderBlock::addChild(columnSet, firstChild());
147 flowThread()->addRegionToThread(columnSet);
151 const char* RenderMultiColumnBlock::renderName() const
154 return "RenderMultiColumnBlock (floating)";
155 if (isOutOfFlowPositioned())
156 return "RenderMultiColumnBlock (positioned)";
157 if (isAnonymousBlock())
158 return "RenderMultiColumnBlock (anonymous)";
160 return "RenderMultiColumnBlock (generated)";
161 if (isRelPositioned())
162 return "RenderMultiColumnBlock (relative positioned)";
163 return "RenderMultiColumnBlock";