OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2012 Apple Inc. All rights reserved. | 2 * Copyright (C) 2012 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 10 matching lines...) Expand all Loading... |
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 */ | 24 */ |
25 | 25 |
26 #include "config.h" | 26 #include "config.h" |
27 #include "core/rendering/RenderMultiColumnSet.h" | 27 #include "core/rendering/RenderMultiColumnSet.h" |
28 | 28 |
29 #include "core/rendering/PaintInfo.h" | 29 #include "core/rendering/PaintInfo.h" |
30 #include "core/rendering/RenderLayer.h" | 30 #include "core/rendering/RenderLayer.h" |
31 #include "core/rendering/RenderMultiColumnBlock.h" | |
32 #include "core/rendering/RenderMultiColumnFlowThread.h" | 31 #include "core/rendering/RenderMultiColumnFlowThread.h" |
33 | 32 |
34 using namespace std; | 33 using namespace std; |
35 | 34 |
36 namespace WebCore { | 35 namespace WebCore { |
37 | 36 |
38 RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread) | 37 RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread) |
39 : RenderRegionSet(0, flowThread) | 38 : RenderRegionSet(0, flowThread) |
40 , m_computedColumnCount(1) | 39 , m_computedColumnCount(1) |
41 , m_computedColumnWidth(0) | 40 , m_computedColumnWidth(0) |
42 , m_computedColumnHeight(0) | 41 , m_computedColumnHeight(0) |
43 , m_maxColumnHeight(RenderFlowThread::maxLogicalHeight()) | 42 , m_maxColumnHeight(RenderFlowThread::maxLogicalHeight()) |
44 , m_minSpaceShortage(RenderFlowThread::maxLogicalHeight()) | 43 , m_minSpaceShortage(RenderFlowThread::maxLogicalHeight()) |
45 , m_minimumColumnHeight(0) | 44 , m_minimumColumnHeight(0) |
46 { | 45 { |
47 } | 46 } |
48 | 47 |
49 RenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread* fl
owThread) | 48 RenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread* fl
owThread) |
50 { | 49 { |
51 Document& document = flowThread->document(); | 50 Document& document = flowThread->document(); |
52 RenderMultiColumnSet* renderer = new RenderMultiColumnSet(flowThread); | 51 RenderMultiColumnSet* renderer = new RenderMultiColumnSet(flowThread); |
53 renderer->setDocumentForAnonymous(&document); | 52 renderer->setDocumentForAnonymous(&document); |
54 return renderer; | 53 return renderer; |
55 } | 54 } |
56 | 55 |
57 LayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) c
onst | 56 LayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) c
onst |
58 { | 57 { |
59 RenderMultiColumnBlock* multicolBlock = toRenderMultiColumnBlock(parent()); | 58 RenderBlockFlow* multicolBlock = multiColumnBlockFlow(); |
60 LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderBefore()
- multicolBlock->paddingBefore(); | 59 LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderBefore()
- multicolBlock->paddingBefore(); |
61 | 60 |
62 height -= contentLogicalTop; | 61 height -= contentLogicalTop; |
63 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would
probably cause an infinite amount of columns to be created. | 62 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would
probably cause an infinite amount of columns to be created. |
64 } | 63 } |
65 | 64 |
66 LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) cons
t | 65 LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) cons
t |
67 { | 66 { |
68 LayoutUnit portionLogicalTop = (isHorizontalWritingMode() ? flowThreadPortio
nRect().y() : flowThreadPortionRect().x()); | 67 LayoutUnit portionLogicalTop = (isHorizontalWritingMode() ? flowThreadPortio
nRect().y() : flowThreadPortionRect().x()); |
69 unsigned columnIndex = columnIndexAtOffset(offset, AssumeNewColumns); | 68 unsigned columnIndex = columnIndexAtOffset(offset, AssumeNewColumns); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 return m_computedColumnHeight + m_minSpaceShortage; | 154 return m_computedColumnHeight + m_minSpaceShortage; |
156 } | 155 } |
157 | 156 |
158 void RenderMultiColumnSet::clearForcedBreaks() | 157 void RenderMultiColumnSet::clearForcedBreaks() |
159 { | 158 { |
160 m_contentRuns.clear(); | 159 m_contentRuns.clear(); |
161 } | 160 } |
162 | 161 |
163 void RenderMultiColumnSet::addForcedBreak(LayoutUnit offsetFromFirstPage) | 162 void RenderMultiColumnSet::addForcedBreak(LayoutUnit offsetFromFirstPage) |
164 { | 163 { |
165 if (!toRenderMultiColumnBlock(parent())->requiresBalancing()) | 164 if (!multiColumnFlowThread()->requiresBalancing()) |
166 return; | 165 return; |
167 if (!m_contentRuns.isEmpty() && offsetFromFirstPage <= m_contentRuns.last().
breakOffset()) | 166 if (!m_contentRuns.isEmpty() && offsetFromFirstPage <= m_contentRuns.last().
breakOffset()) |
168 return; | 167 return; |
169 // Append another item as long as we haven't exceeded used column count. Wha
t ends up in the | 168 // Append another item as long as we haven't exceeded used column count. Wha
t ends up in the |
170 // overflow area shouldn't affect column balancing. | 169 // overflow area shouldn't affect column balancing. |
171 if (m_contentRuns.size() < m_computedColumnCount) | 170 if (m_contentRuns.size() < m_computedColumnCount) |
172 m_contentRuns.append(ContentRun(offsetFromFirstPage)); | 171 m_contentRuns.append(ContentRun(offsetFromFirstPage)); |
173 } | 172 } |
174 | 173 |
175 bool RenderMultiColumnSet::recalculateBalancedHeight(bool initial) | 174 bool RenderMultiColumnSet::recalculateBalancedHeight(bool initial) |
176 { | 175 { |
177 ASSERT(toRenderMultiColumnBlock(parent())->requiresBalancing()); | 176 ASSERT(multiColumnFlowThread()->requiresBalancing()); |
178 | 177 |
179 LayoutUnit oldColumnHeight = m_computedColumnHeight; | 178 LayoutUnit oldColumnHeight = m_computedColumnHeight; |
180 if (initial) | 179 if (initial) |
181 distributeImplicitBreaks(); | 180 distributeImplicitBreaks(); |
182 LayoutUnit newColumnHeight = calculateBalancedHeight(initial); | 181 LayoutUnit newColumnHeight = calculateBalancedHeight(initial); |
183 setAndConstrainColumnHeight(newColumnHeight); | 182 setAndConstrainColumnHeight(newColumnHeight); |
184 | 183 |
185 // After having calculated an initial column height, the multicol container
typically needs at | 184 // After having calculated an initial column height, the multicol container
typically needs at |
186 // least one more layout pass with a new column height, but if a height was
specified, we only | 185 // least one more layout pass with a new column height, but if a height was
specified, we only |
187 // need to do this if we think that we need less space than specified. Conve
rsely, if we | 186 // need to do this if we think that we need less space than specified. Conve
rsely, if we |
(...skipping 15 matching lines...) Expand all Loading... |
203 | 202 |
204 // The space shortage is what we use as our stretch amount. We need a positi
ve number here in | 203 // The space shortage is what we use as our stretch amount. We need a positi
ve number here in |
205 // order to get anywhere. | 204 // order to get anywhere. |
206 ASSERT(spaceShortage > 0); | 205 ASSERT(spaceShortage > 0); |
207 | 206 |
208 m_minSpaceShortage = spaceShortage; | 207 m_minSpaceShortage = spaceShortage; |
209 } | 208 } |
210 | 209 |
211 void RenderMultiColumnSet::updateLogicalWidth() | 210 void RenderMultiColumnSet::updateLogicalWidth() |
212 { | 211 { |
213 RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent()); | 212 RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread(); |
214 setComputedColumnWidthAndCount(parentBlock->columnWidth(), parentBlock->colu
mnCount()); // FIXME: This will eventually vary if we are contained inside regio
ns. | 213 setComputedColumnWidthAndCount(flowThread->columnWidth(), flowThread->column
Count()); |
215 | 214 |
216 // FIXME: When we add regions support, we'll start it off at the width of th
e multi-column | 215 // FIXME: When we add regions support, we'll start it off at the width of th
e multi-column |
217 // block in that particular region. | 216 // block in that particular region. |
218 setLogicalWidth(parentBox()->contentLogicalWidth()); | 217 setLogicalWidth(parentBox()->contentLogicalWidth()); |
219 | 218 |
220 // If we overflow, increase our logical width. | 219 // If we overflow, increase our logical width. |
221 unsigned colCount = columnCount(); | 220 unsigned colCount = columnCount(); |
222 LayoutUnit colGap = columnGap(); | 221 LayoutUnit colGap = columnGap(); |
223 LayoutUnit minimumContentLogicalWidth = colCount * computedColumnWidth() + (
colCount - 1) * colGap; | 222 LayoutUnit minimumContentLogicalWidth = colCount * computedColumnWidth() + (
colCount - 1) * colGap; |
224 LayoutUnit currentContentLogicalWidth = contentLogicalWidth(); | 223 LayoutUnit currentContentLogicalWidth = contentLogicalWidth(); |
225 LayoutUnit delta = max(LayoutUnit(), minimumContentLogicalWidth - currentCon
tentLogicalWidth); | 224 LayoutUnit delta = max(LayoutUnit(), minimumContentLogicalWidth - currentCon
tentLogicalWidth); |
226 if (!delta) | 225 if (!delta) |
227 return; | 226 return; |
228 | 227 |
229 // Increase our logical width by the delta. | 228 // Increase our logical width by the delta. |
230 setLogicalWidth(logicalWidth() + delta); | 229 setLogicalWidth(logicalWidth() + delta); |
231 } | 230 } |
232 | 231 |
233 void RenderMultiColumnSet::prepareForLayout() | 232 void RenderMultiColumnSet::prepareForLayout() |
234 { | 233 { |
235 RenderMultiColumnBlock* multicolBlock = toRenderMultiColumnBlock(parent()); | 234 RenderBlockFlow* multicolBlock = multiColumnBlockFlow(); |
236 RenderStyle* multicolStyle = multicolBlock->style(); | 235 RenderStyle* multicolStyle = multicolBlock->style(); |
237 | 236 |
238 // Set box logical top. | 237 // Set box logical top. |
239 ASSERT(!previousSiblingBox() || !previousSiblingBox()->isRenderMultiColumnSe
t()); // FIXME: multiple set not implemented; need to examine previous set to ca
lculate the correct logical top. | 238 ASSERT(!previousSiblingBox() || !previousSiblingBox()->isRenderMultiColumnSe
t()); // FIXME: multiple set not implemented; need to examine previous set to ca
lculate the correct logical top. |
240 setLogicalTop(multicolBlock->borderBefore() + multicolBlock->paddingBefore()
); | 239 setLogicalTop(multicolBlock->borderBefore() + multicolBlock->paddingBefore()
); |
241 | 240 |
242 // Set box width. | 241 // Set box width. |
243 updateLogicalWidth(); | 242 updateLogicalWidth(); |
244 | 243 |
245 if (multicolBlock->requiresBalancing()) { | 244 if (multicolBlock->multiColumnFlowThread()->requiresBalancing()) { |
246 // Set maximum column height. We will not stretch beyond this. | 245 // Set maximum column height. We will not stretch beyond this. |
247 m_maxColumnHeight = RenderFlowThread::maxLogicalHeight(); | 246 m_maxColumnHeight = RenderFlowThread::maxLogicalHeight(); |
248 if (!multicolStyle->logicalHeight().isAuto()) { | 247 if (!multicolStyle->logicalHeight().isAuto()) { |
249 m_maxColumnHeight = multicolBlock->computeContentLogicalHeight(multi
colStyle->logicalHeight(), -1); | 248 m_maxColumnHeight = multicolBlock->computeContentLogicalHeight(multi
colStyle->logicalHeight(), -1); |
250 if (m_maxColumnHeight == -1) | 249 if (m_maxColumnHeight == -1) |
251 m_maxColumnHeight = RenderFlowThread::maxLogicalHeight(); | 250 m_maxColumnHeight = RenderFlowThread::maxLogicalHeight(); |
252 } | 251 } |
253 if (!multicolStyle->logicalMaxHeight().isUndefined()) { | 252 if (!multicolStyle->logicalMaxHeight().isUndefined()) { |
254 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHe
ight(multicolStyle->logicalMaxHeight(), -1); | 253 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHe
ight(multicolStyle->logicalMaxHeight(), -1); |
255 if (logicalMaxHeight != -1 && m_maxColumnHeight > logicalMaxHeight) | 254 if (logicalMaxHeight != -1 && m_maxColumnHeight > logicalMaxHeight) |
256 m_maxColumnHeight = logicalMaxHeight; | 255 m_maxColumnHeight = logicalMaxHeight; |
257 } | 256 } |
258 m_maxColumnHeight = heightAdjustedForSetOffset(m_maxColumnHeight); | 257 m_maxColumnHeight = heightAdjustedForSetOffset(m_maxColumnHeight); |
259 m_computedColumnHeight = 0; // Restart balancing. | 258 m_computedColumnHeight = 0; // Restart balancing. |
260 } else { | 259 } else { |
261 setAndConstrainColumnHeight(heightAdjustedForSetOffset(multicolBlock->co
lumnHeightAvailable())); | 260 setAndConstrainColumnHeight(heightAdjustedForSetOffset(multicolBlock->mu
ltiColumnFlowThread()->columnHeightAvailable())); |
262 } | 261 } |
263 | 262 |
264 clearForcedBreaks(); | 263 clearForcedBreaks(); |
265 | 264 |
266 // Nuke previously stored minimum column height. Contents may have changed f
or all we know. | 265 // Nuke previously stored minimum column height. Contents may have changed f
or all we know. |
267 m_minimumColumnHeight = 0; | 266 m_minimumColumnHeight = 0; |
268 } | 267 } |
269 | 268 |
270 void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTo
p, LogicalExtentComputedValues& computedValues) const | 269 void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTo
p, LogicalExtentComputedValues& computedValues) const |
271 { | 270 { |
272 computedValues.m_extent = m_computedColumnHeight; | 271 computedValues.m_extent = m_computedColumnHeight; |
273 computedValues.m_position = logicalTop; | 272 computedValues.m_position = logicalTop; |
274 } | 273 } |
275 | 274 |
276 LayoutUnit RenderMultiColumnSet::columnGap() const | 275 LayoutUnit RenderMultiColumnSet::columnGap() const |
277 { | 276 { |
278 // FIXME: Eventually we will cache the column gap when the widths of columns
start varying, but for now we just | 277 RenderBlockFlow* parentBlock = multiColumnBlockFlow(); |
279 // go to the parent block to get the gap. | |
280 RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent()); | |
281 if (parentBlock->style()->hasNormalColumnGap()) | 278 if (parentBlock->style()->hasNormalColumnGap()) |
282 return parentBlock->style()->fontDescription().computedPixelSize(); // "
1em" is recommended as the normal gap setting. Matches <p> margins. | 279 return parentBlock->style()->fontDescription().computedPixelSize(); // "
1em" is recommended as the normal gap setting. Matches <p> margins. |
283 return parentBlock->style()->columnGap(); | 280 return parentBlock->style()->columnGap(); |
284 } | 281 } |
285 | 282 |
286 unsigned RenderMultiColumnSet::columnCount() const | 283 unsigned RenderMultiColumnSet::columnCount() const |
287 { | 284 { |
288 // We must always return a value of 1 or greater. Column count = 0 is a mean
ingless situation, | 285 // We must always return a value of 1 or greater. Column count = 0 is a mean
ingless situation, |
289 // and will confuse and cause problems in other parts of the code. | 286 // and will confuse and cause problems in other parts of the code. |
290 if (!computedColumnHeight()) | 287 if (!computedColumnHeight()) |
291 return 1; | 288 return 1; |
292 | 289 |
293 // Our portion rect determines our column count. We have as many columns as
needed to fit all the content. | 290 // Our portion rect determines our column count. We have as many columns as
needed to fit all the content. |
294 LayoutUnit logicalHeightInColumns = flowThread()->isHorizontalWritingMode()
? flowThreadPortionRect().height() : flowThreadPortionRect().width(); | 291 LayoutUnit logicalHeightInColumns = flowThread()->isHorizontalWritingMode()
? flowThreadPortionRect().height() : flowThreadPortionRect().width(); |
| 292 if (!logicalHeightInColumns) |
| 293 return 1; |
| 294 |
295 unsigned count = ceil(static_cast<float>(logicalHeightInColumns) / computedC
olumnHeight()); | 295 unsigned count = ceil(static_cast<float>(logicalHeightInColumns) / computedC
olumnHeight()); |
296 ASSERT(count >= 1); | 296 ASSERT(count >= 1); |
297 return count; | 297 return count; |
298 } | 298 } |
299 | 299 |
300 LayoutRect RenderMultiColumnSet::columnRectAt(unsigned index) const | 300 LayoutRect RenderMultiColumnSet::columnRectAt(unsigned index) const |
301 { | 301 { |
302 LayoutUnit colLogicalWidth = computedColumnWidth(); | 302 LayoutUnit colLogicalWidth = computedColumnWidth(); |
303 LayoutUnit colLogicalHeight = computedColumnHeight(); | 303 LayoutUnit colLogicalHeight = computedColumnHeight(); |
304 LayoutUnit colLogicalTop = borderBefore() + paddingBefore(); | 304 LayoutUnit colLogicalTop = borderBefore() + paddingBefore(); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 return; | 397 return; |
398 | 398 |
399 paintColumnRules(paintInfo, paintOffset); | 399 paintColumnRules(paintInfo, paintOffset); |
400 } | 400 } |
401 | 401 |
402 void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPo
int& paintOffset) | 402 void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPo
int& paintOffset) |
403 { | 403 { |
404 if (paintInfo.context->paintingDisabled()) | 404 if (paintInfo.context->paintingDisabled()) |
405 return; | 405 return; |
406 | 406 |
407 RenderStyle* blockStyle = toRenderMultiColumnBlock(parent())->style(); | 407 RenderStyle* blockStyle = multiColumnBlockFlow()->style(); |
408 const Color& ruleColor = resolveColor(blockStyle, CSSPropertyWebkitColumnRul
eColor); | 408 const Color& ruleColor = resolveColor(blockStyle, CSSPropertyWebkitColumnRul
eColor); |
409 bool ruleTransparent = blockStyle->columnRuleIsTransparent(); | 409 bool ruleTransparent = blockStyle->columnRuleIsTransparent(); |
410 EBorderStyle ruleStyle = blockStyle->columnRuleStyle(); | 410 EBorderStyle ruleStyle = blockStyle->columnRuleStyle(); |
411 LayoutUnit ruleThickness = blockStyle->columnRuleWidth(); | 411 LayoutUnit ruleThickness = blockStyle->columnRuleWidth(); |
412 LayoutUnit colGap = columnGap(); | 412 LayoutUnit colGap = columnGap(); |
413 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent; | 413 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent; |
414 if (!renderRule) | 414 if (!renderRule) |
415 return; | 415 return; |
416 | 416 |
417 unsigned colCount = columnCount(); | 417 unsigned colCount = columnCount(); |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
584 fragments.append(fragment); | 584 fragments.append(fragment); |
585 } | 585 } |
586 } | 586 } |
587 | 587 |
588 const char* RenderMultiColumnSet::renderName() const | 588 const char* RenderMultiColumnSet::renderName() const |
589 { | 589 { |
590 return "RenderMultiColumnSet"; | 590 return "RenderMultiColumnSet"; |
591 } | 591 } |
592 | 592 |
593 } | 593 } |
OLD | NEW |