OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2012 Apple Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions | |
6 * are met: | |
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. | |
12 * | |
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. | |
24 */ | |
25 | |
26 #include "config.h" | |
27 #include "core/rendering/RenderMultiColumnBlock.h" | |
28 | |
29 #include "core/rendering/RenderMultiColumnFlowThread.h" | |
30 #include "core/rendering/RenderMultiColumnSet.h" | |
31 #include "core/rendering/RenderView.h" | |
32 | |
33 using namespace std; | |
34 | |
35 namespace WebCore { | |
36 | |
37 RenderMultiColumnBlock::RenderMultiColumnBlock(Element* element) | |
38 : RenderBlockFlow(element) | |
39 , m_flowThread(0) | |
40 , m_columnCount(1) | |
41 , m_columnWidth(0) | |
42 , m_columnHeightAvailable(0) | |
43 , m_inBalancingPass(false) | |
44 { | |
45 } | |
46 | |
47 void RenderMultiColumnBlock::styleDidChange(StyleDifference diff, const RenderSt
yle* oldStyle) | |
48 { | |
49 RenderBlock::styleDidChange(diff, oldStyle); | |
50 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBo
x()) | |
51 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BL
OCK)); | |
52 } | |
53 | |
54 void RenderMultiColumnBlock::computeColumnCountAndWidth() | |
55 { | |
56 // Calculate our column width and column count. | |
57 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibli
ng4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744 | |
58 m_columnCount = 1; | |
59 m_columnWidth = contentLogicalWidth(); | |
60 | |
61 ASSERT(!style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth()); | |
62 | |
63 LayoutUnit availWidth = m_columnWidth; | |
64 LayoutUnit colGap = columnGap(); | |
65 LayoutUnit colWidth = max<LayoutUnit>(1, LayoutUnit(style()->columnWidth()))
; | |
66 int colCount = max<int>(1, style()->columnCount()); | |
67 | |
68 if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) { | |
69 m_columnCount = colCount; | |
70 m_columnWidth = max<LayoutUnit>(0, (availWidth - ((m_columnCount - 1) *
colGap)) / m_columnCount); | |
71 } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount())
{ | |
72 m_columnCount = max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + c
olGap)); | |
73 m_columnWidth = ((availWidth + colGap) / m_columnCount) - colGap; | |
74 } else { | |
75 m_columnCount = max<LayoutUnit>(min<LayoutUnit>(colCount, (availWidth +
colGap) / (colWidth + colGap)), 1); | |
76 m_columnWidth = ((availWidth + colGap) / m_columnCount) - colGap; | |
77 } | |
78 } | |
79 | |
80 bool RenderMultiColumnBlock::updateLogicalWidthAndColumnWidth() | |
81 { | |
82 bool relayoutChildren = RenderBlock::updateLogicalWidthAndColumnWidth(); | |
83 LayoutUnit oldColumnWidth = m_columnWidth; | |
84 computeColumnCountAndWidth(); | |
85 if (m_columnWidth != oldColumnWidth) | |
86 relayoutChildren = true; | |
87 return relayoutChildren; | |
88 } | |
89 | |
90 void RenderMultiColumnBlock::checkForPaginationLogicalHeightChange(LayoutUnit& /
*pageLogicalHeight*/, bool& /*pageLogicalHeightChanged*/, bool& /*hasSpecifiedPa
geLogicalHeight*/) | |
91 { | |
92 // We don't actually update any of the variables. We just subclassed to adju
st our column height. | |
93 updateLogicalHeight(); | |
94 m_columnHeightAvailable = max<LayoutUnit>(contentLogicalHeight(), 0); | |
95 setLogicalHeight(0); | |
96 } | |
97 | |
98 bool RenderMultiColumnBlock::relayoutForPagination(bool, LayoutUnit, LayoutState
Maintainer& statePusher) | |
99 { | |
100 if (m_inBalancingPass || !requiresBalancing()) | |
101 return false; | |
102 m_inBalancingPass = true; // Prevent re-entering this method (and recursion
into layout). | |
103 | |
104 bool needsRelayout; | |
105 bool neededRelayout = false; | |
106 bool firstPass = true; | |
107 do { | |
108 // Column heights may change here because of balancing. We may have to d
o multiple layout | |
109 // passes, depending on how the contents is fitted to the changed column
heights. In most | |
110 // cases, laying out again twice or even just once will suffice. Sometim
es we need more | |
111 // passes than that, though, but the number of retries should not exceed
the number of | |
112 // columns, unless we have a bug. | |
113 needsRelayout = false; | |
114 for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBo
x->nextSiblingBox()) { | |
115 if (childBox != m_flowThread && childBox->isRenderMultiColumnSet())
{ | |
116 RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(child
Box); | |
117 if (multicolSet->calculateBalancedHeight(firstPass)) { | |
118 multicolSet->setChildNeedsLayout(MarkOnlyThis); | |
119 needsRelayout = true; | |
120 } | |
121 } | |
122 } | |
123 | |
124 if (needsRelayout) { | |
125 // Layout again. Column balancing resulted in a new height. | |
126 neededRelayout = true; | |
127 m_flowThread->setChildNeedsLayout(MarkOnlyThis); | |
128 setChildNeedsLayout(MarkOnlyThis); | |
129 if (firstPass) | |
130 statePusher.pop(); | |
131 layoutBlock(false); | |
132 } | |
133 firstPass = false; | |
134 } while (needsRelayout); | |
135 m_inBalancingPass = false; | |
136 return neededRelayout; | |
137 } | |
138 | |
139 void RenderMultiColumnBlock::addChild(RenderObject* newChild, RenderObject* befo
reChild) | |
140 { | |
141 if (!m_flowThread) { | |
142 m_flowThread = RenderMultiColumnFlowThread::createAnonymous(&document())
; | |
143 m_flowThread->setStyle(RenderStyle::createAnonymousStyleWithDisplay(styl
e(), BLOCK)); | |
144 RenderBlock::addChild(m_flowThread); | |
145 } | |
146 m_flowThread->addChild(newChild, beforeChild); | |
147 } | |
148 | |
149 RenderObject* RenderMultiColumnBlock::layoutSpecialExcludedChild(bool relayoutCh
ildren, SubtreeLayoutScope& layoutScope) | |
150 { | |
151 if (!m_flowThread) | |
152 return 0; | |
153 | |
154 // Update the dimensions of our regions before we lay out the flow thread. | |
155 // FIXME: Eventually this is going to get way more complicated, and we will
be destroying regions | |
156 // instead of trying to keep them around. | |
157 bool shouldInvalidateRegions = false; | |
158 for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->n
extSiblingBox()) { | |
159 if (childBox == m_flowThread) | |
160 continue; | |
161 | |
162 if (relayoutChildren || childBox->needsLayout()) { | |
163 if (!m_inBalancingPass && childBox->isRenderMultiColumnSet()) | |
164 toRenderMultiColumnSet(childBox)->prepareForLayout(); | |
165 shouldInvalidateRegions = true; | |
166 } | |
167 } | |
168 | |
169 if (shouldInvalidateRegions) | |
170 m_flowThread->invalidateRegions(); | |
171 | |
172 if (relayoutChildren) | |
173 layoutScope.setChildNeedsLayout(m_flowThread); | |
174 | |
175 setLogicalTopForChild(m_flowThread, borderBefore() + paddingBefore()); | |
176 m_flowThread->layoutIfNeeded(); | |
177 determineLogicalLeftPositionForChild(m_flowThread); | |
178 | |
179 return m_flowThread; | |
180 } | |
181 | |
182 const char* RenderMultiColumnBlock::renderName() const | |
183 { | |
184 if (isFloating()) | |
185 return "RenderMultiColumnBlock (floating)"; | |
186 if (isOutOfFlowPositioned()) | |
187 return "RenderMultiColumnBlock (positioned)"; | |
188 if (isAnonymousBlock()) | |
189 return "RenderMultiColumnBlock (anonymous)"; | |
190 // FIXME: Temporary hack while the new generated content system is being imp
lemented. | |
191 if (isPseudoElement()) | |
192 return "RenderMultiColumnBlock (generated)"; | |
193 if (isAnonymous()) | |
194 return "RenderMultiColumnBlock (generated)"; | |
195 if (isRelPositioned()) | |
196 return "RenderMultiColumnBlock (relative positioned)"; | |
197 return "RenderMultiColumnBlock"; | |
198 } | |
199 | |
200 } | |
OLD | NEW |