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 18 matching lines...) Expand all Loading... |
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/RenderMultiColumnFlowThread.h" | 31 #include "core/rendering/RenderMultiColumnFlowThread.h" |
32 | 32 |
33 using namespace std; | 33 using namespace std; |
34 | 34 |
35 namespace WebCore { | 35 namespace WebCore { |
36 | 36 |
37 RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread) | 37 RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread) |
38 : RenderRegion(0, flowThread) | 38 : RenderRegion(0, flowThread) |
39 , m_computedColumnCount(1) | 39 , m_columnHeight(0) |
40 , m_computedColumnWidth(0) | |
41 , m_computedColumnHeight(0) | |
42 , m_maxColumnHeight(RenderFlowThread::maxLogicalHeight()) | 40 , m_maxColumnHeight(RenderFlowThread::maxLogicalHeight()) |
43 , m_minSpaceShortage(RenderFlowThread::maxLogicalHeight()) | 41 , m_minSpaceShortage(RenderFlowThread::maxLogicalHeight()) |
44 , m_minimumColumnHeight(0) | 42 , m_minimumColumnHeight(0) |
45 { | 43 { |
46 } | 44 } |
47 | 45 |
48 RenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread* fl
owThread, RenderStyle* parentStyle) | 46 RenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread* fl
owThread, RenderStyle* parentStyle) |
49 { | 47 { |
50 Document& document = flowThread->document(); | 48 Document& document = flowThread->document(); |
51 RenderMultiColumnSet* renderer = new RenderMultiColumnSet(flowThread); | 49 RenderMultiColumnSet* renderer = new RenderMultiColumnSet(flowThread); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 RenderBlockFlow* multicolBlock = multiColumnBlockFlow(); | 94 RenderBlockFlow* multicolBlock = multiColumnBlockFlow(); |
97 LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderAndPa
ddingBefore(); | 95 LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderAndPa
ddingBefore(); |
98 height -= contentLogicalTop; | 96 height -= contentLogicalTop; |
99 } | 97 } |
100 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would
probably cause an infinite amount of columns to be created. | 98 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would
probably cause an infinite amount of columns to be created. |
101 } | 99 } |
102 | 100 |
103 LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) cons
t | 101 LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) cons
t |
104 { | 102 { |
105 unsigned columnIndex = columnIndexAtOffset(offset, AssumeNewColumns); | 103 unsigned columnIndex = columnIndexAtOffset(offset, AssumeNewColumns); |
106 return logicalTopInFlowThread() + columnIndex * computedColumnHeight(); | 104 return logicalTopInFlowThread() + columnIndex * pageLogicalHeight(); |
107 } | 105 } |
108 | 106 |
109 void RenderMultiColumnSet::setAndConstrainColumnHeight(LayoutUnit newHeight) | 107 void RenderMultiColumnSet::setAndConstrainColumnHeight(LayoutUnit newHeight) |
110 { | 108 { |
111 m_computedColumnHeight = newHeight; | 109 m_columnHeight = newHeight; |
112 if (m_computedColumnHeight > m_maxColumnHeight) | 110 if (m_columnHeight > m_maxColumnHeight) |
113 m_computedColumnHeight = m_maxColumnHeight; | 111 m_columnHeight = m_maxColumnHeight; |
114 // FIXME: the height may also be affected by the enclosing pagination contex
t, if any. | 112 // FIXME: the height may also be affected by the enclosing pagination contex
t, if any. |
115 } | 113 } |
116 | 114 |
117 unsigned RenderMultiColumnSet::findRunWithTallestColumns() const | 115 unsigned RenderMultiColumnSet::findRunWithTallestColumns() const |
118 { | 116 { |
119 unsigned indexWithLargestHeight = 0; | 117 unsigned indexWithLargestHeight = 0; |
120 LayoutUnit largestHeight; | 118 LayoutUnit largestHeight; |
121 LayoutUnit previousOffset = logicalTopInFlowThread(); | 119 LayoutUnit previousOffset = logicalTopInFlowThread(); |
122 size_t runCount = m_contentRuns.size(); | 120 size_t runCount = m_contentRuns.size(); |
123 ASSERT(runCount); | 121 ASSERT(runCount); |
(...skipping 21 matching lines...) Expand all Loading... |
145 // the last set. | 143 // the last set. |
146 addContentRun(logicalBottomInFlowThread()); | 144 addContentRun(logicalBottomInFlowThread()); |
147 unsigned columnCount = m_contentRuns.size(); | 145 unsigned columnCount = m_contentRuns.size(); |
148 | 146 |
149 // If there is room for more breaks (to reach the used value of column-count
), imagine that we | 147 // If there is room for more breaks (to reach the used value of column-count
), imagine that we |
150 // insert implicit breaks at suitable locations. At any given time, the cont
ent run with the | 148 // insert implicit breaks at suitable locations. At any given time, the cont
ent run with the |
151 // currently tallest columns will get another implicit break "inserted", whi
ch will increase its | 149 // currently tallest columns will get another implicit break "inserted", whi
ch will increase its |
152 // column count by one and shrink its columns' height. Repeat until we have
the desired total | 150 // column count by one and shrink its columns' height. Repeat until we have
the desired total |
153 // number of breaks. The largest column height among the runs will then be t
he initial column | 151 // number of breaks. The largest column height among the runs will then be t
he initial column |
154 // height for the balancer to use. | 152 // height for the balancer to use. |
155 while (columnCount < m_computedColumnCount) { | 153 while (columnCount < usedColumnCount()) { |
156 unsigned index = findRunWithTallestColumns(); | 154 unsigned index = findRunWithTallestColumns(); |
157 m_contentRuns[index].assumeAnotherImplicitBreak(); | 155 m_contentRuns[index].assumeAnotherImplicitBreak(); |
158 columnCount++; | 156 columnCount++; |
159 } | 157 } |
160 } | 158 } |
161 | 159 |
162 LayoutUnit RenderMultiColumnSet::calculateColumnHeight(BalancedHeightCalculation
calculationMode) const | 160 LayoutUnit RenderMultiColumnSet::calculateColumnHeight(BalancedHeightCalculation
calculationMode) const |
163 { | 161 { |
164 if (calculationMode == GuessFromFlowThreadPortion) { | 162 if (calculationMode == GuessFromFlowThreadPortion) { |
165 // Initial balancing. Start with the lowest imaginable column height. We
use the tallest | 163 // Initial balancing. Start with the lowest imaginable column height. We
use the tallest |
166 // content run (after having "inserted" implicit breaks), and find its s
tart offset (by | 164 // content run (after having "inserted" implicit breaks), and find its s
tart offset (by |
167 // looking at the previous run's end offset, or, if there's no previous
run, the set's start | 165 // looking at the previous run's end offset, or, if there's no previous
run, the set's start |
168 // offset in the flow thread). | 166 // offset in the flow thread). |
169 unsigned index = findRunWithTallestColumns(); | 167 unsigned index = findRunWithTallestColumns(); |
170 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffse
t() : logicalTopInFlowThread(); | 168 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffse
t() : logicalTopInFlowThread(); |
171 return std::max<LayoutUnit>(m_contentRuns[index].columnLogicalHeight(sta
rtOffset), m_minimumColumnHeight); | 169 return std::max<LayoutUnit>(m_contentRuns[index].columnLogicalHeight(sta
rtOffset), m_minimumColumnHeight); |
172 } | 170 } |
173 | 171 |
174 if (columnCount() <= computedColumnCount()) { | 172 if (actualColumnCount() <= usedColumnCount()) { |
175 // With the current column height, the content fits without creating ove
rflowing columns. We're done. | 173 // With the current column height, the content fits without creating ove
rflowing columns. We're done. |
176 return m_computedColumnHeight; | 174 return m_columnHeight; |
177 } | 175 } |
178 | 176 |
179 if (m_contentRuns.size() >= computedColumnCount()) { | 177 if (m_contentRuns.size() >= usedColumnCount()) { |
180 // Too many forced breaks to allow any implicit breaks. Initial balancin
g should already | 178 // Too many forced breaks to allow any implicit breaks. Initial balancin
g should already |
181 // have set a good height. There's nothing more we should do. | 179 // have set a good height. There's nothing more we should do. |
182 return m_computedColumnHeight; | 180 return m_columnHeight; |
183 } | 181 } |
184 | 182 |
185 // If the initial guessed column height wasn't enough, stretch it now. Stret
ch by the lowest | 183 // If the initial guessed column height wasn't enough, stretch it now. Stret
ch by the lowest |
186 // amount of space shortage found during layout. | 184 // amount of space shortage found during layout. |
187 | 185 |
188 ASSERT(m_minSpaceShortage > 0); // We should never _shrink_ the height! | 186 ASSERT(m_minSpaceShortage > 0); // We should never _shrink_ the height! |
189 ASSERT(m_minSpaceShortage != RenderFlowThread::maxLogicalHeight()); // If th
is happens, we probably have a bug. | 187 ASSERT(m_minSpaceShortage != RenderFlowThread::maxLogicalHeight()); // If th
is happens, we probably have a bug. |
190 if (m_minSpaceShortage == RenderFlowThread::maxLogicalHeight()) | 188 if (m_minSpaceShortage == RenderFlowThread::maxLogicalHeight()) |
191 return m_computedColumnHeight; // So bail out rather than looping infini
tely. | 189 return m_columnHeight; // So bail out rather than looping infinitely. |
192 | 190 |
193 return m_computedColumnHeight + m_minSpaceShortage; | 191 return m_columnHeight + m_minSpaceShortage; |
194 } | 192 } |
195 | 193 |
196 void RenderMultiColumnSet::addContentRun(LayoutUnit endOffsetFromFirstPage) | 194 void RenderMultiColumnSet::addContentRun(LayoutUnit endOffsetFromFirstPage) |
197 { | 195 { |
198 if (!multiColumnFlowThread()->requiresBalancing()) | 196 if (!multiColumnFlowThread()->requiresBalancing()) |
199 return; | 197 return; |
200 if (!m_contentRuns.isEmpty() && endOffsetFromFirstPage <= m_contentRuns.last
().breakOffset()) | 198 if (!m_contentRuns.isEmpty() && endOffsetFromFirstPage <= m_contentRuns.last
().breakOffset()) |
201 return; | 199 return; |
202 // Append another item as long as we haven't exceeded used column count. Wha
t ends up in the | 200 // Append another item as long as we haven't exceeded used column count. Wha
t ends up in the |
203 // overflow area shouldn't affect column balancing. | 201 // overflow area shouldn't affect column balancing. |
204 if (m_contentRuns.size() < m_computedColumnCount) | 202 if (m_contentRuns.size() < usedColumnCount()) |
205 m_contentRuns.append(ContentRun(endOffsetFromFirstPage)); | 203 m_contentRuns.append(ContentRun(endOffsetFromFirstPage)); |
206 } | 204 } |
207 | 205 |
208 bool RenderMultiColumnSet::recalculateColumnHeight(BalancedHeightCalculation cal
culationMode) | 206 bool RenderMultiColumnSet::recalculateColumnHeight(BalancedHeightCalculation cal
culationMode) |
209 { | 207 { |
210 ASSERT(multiColumnFlowThread()->requiresBalancing()); | 208 ASSERT(multiColumnFlowThread()->requiresBalancing()); |
211 | 209 |
212 LayoutUnit oldColumnHeight = m_computedColumnHeight; | 210 LayoutUnit oldColumnHeight = m_columnHeight; |
213 if (calculationMode == GuessFromFlowThreadPortion) { | 211 if (calculationMode == GuessFromFlowThreadPortion) { |
214 // Post-process the content runs and find out where the implicit breaks
will occur. | 212 // Post-process the content runs and find out where the implicit breaks
will occur. |
215 distributeImplicitBreaks(); | 213 distributeImplicitBreaks(); |
216 } | 214 } |
217 LayoutUnit newColumnHeight = calculateColumnHeight(calculationMode); | 215 LayoutUnit newColumnHeight = calculateColumnHeight(calculationMode); |
218 setAndConstrainColumnHeight(newColumnHeight); | 216 setAndConstrainColumnHeight(newColumnHeight); |
219 | 217 |
220 // After having calculated an initial column height, the multicol container
typically needs at | 218 // After having calculated an initial column height, the multicol container
typically needs at |
221 // least one more layout pass with a new column height, but if a height was
specified, we only | 219 // least one more layout pass with a new column height, but if a height was
specified, we only |
222 // need to do this if we think that we need less space than specified. Conve
rsely, if we | 220 // need to do this if we think that we need less space than specified. Conve
rsely, if we |
223 // determined that the columns need to be as tall as the specified height of
the container, we | 221 // determined that the columns need to be as tall as the specified height of
the container, we |
224 // have already laid it out correctly, and there's no need for another pass. | 222 // have already laid it out correctly, and there's no need for another pass. |
225 | 223 |
226 // We can get rid of the content runs now, if we haven't already done so. Th
ey are only needed | 224 // We can get rid of the content runs now, if we haven't already done so. Th
ey are only needed |
227 // to calculate the initial balanced column height. In fact, we have to get
rid of them before | 225 // to calculate the initial balanced column height. In fact, we have to get
rid of them before |
228 // the next layout pass, since each pass will rebuild this. | 226 // the next layout pass, since each pass will rebuild this. |
229 m_contentRuns.clear(); | 227 m_contentRuns.clear(); |
230 | 228 |
231 if (m_computedColumnHeight == oldColumnHeight) | 229 if (m_columnHeight == oldColumnHeight) |
232 return false; // No change. We're done. | 230 return false; // No change. We're done. |
233 | 231 |
234 m_minSpaceShortage = RenderFlowThread::maxLogicalHeight(); | 232 m_minSpaceShortage = RenderFlowThread::maxLogicalHeight(); |
235 return true; // Need another pass. | 233 return true; // Need another pass. |
236 } | 234 } |
237 | 235 |
238 void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage) | 236 void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage) |
239 { | 237 { |
240 if (spaceShortage >= m_minSpaceShortage) | 238 if (spaceShortage >= m_minSpaceShortage) |
241 return; | 239 return; |
242 | 240 |
243 // The space shortage is what we use as our stretch amount. We need a positi
ve number here in | 241 // The space shortage is what we use as our stretch amount. We need a positi
ve number here in |
244 // order to get anywhere. | 242 // order to get anywhere. |
245 ASSERT(spaceShortage > 0); | 243 ASSERT(spaceShortage > 0); |
246 | 244 |
247 m_minSpaceShortage = spaceShortage; | 245 m_minSpaceShortage = spaceShortage; |
248 } | 246 } |
249 | 247 |
250 void RenderMultiColumnSet::resetColumnHeight() | 248 void RenderMultiColumnSet::resetColumnHeight() |
251 { | 249 { |
252 // Nuke previously stored minimum column height. Contents may have changed f
or all we know. | 250 // Nuke previously stored minimum column height. Contents may have changed f
or all we know. |
253 m_minimumColumnHeight = 0; | 251 m_minimumColumnHeight = 0; |
254 | 252 |
255 m_maxColumnHeight = calculateMaxColumnHeight(); | 253 m_maxColumnHeight = calculateMaxColumnHeight(); |
256 | 254 |
257 LayoutUnit oldColumnHeight = computedColumnHeight(); | 255 LayoutUnit oldColumnHeight = pageLogicalHeight(); |
258 | 256 |
259 if (multiColumnFlowThread()->requiresBalancing()) | 257 if (multiColumnFlowThread()->requiresBalancing()) |
260 m_computedColumnHeight = 0; | 258 m_columnHeight = 0; |
261 else | 259 else |
262 setAndConstrainColumnHeight(heightAdjustedForSetOffset(multiColumnFlowTh
read()->columnHeightAvailable())); | 260 setAndConstrainColumnHeight(heightAdjustedForSetOffset(multiColumnFlowTh
read()->columnHeightAvailable())); |
263 | 261 |
264 if (computedColumnHeight() != oldColumnHeight) | 262 if (pageLogicalHeight() != oldColumnHeight) |
265 setChildNeedsLayout(MarkOnlyThis); | 263 setChildNeedsLayout(MarkOnlyThis); |
266 | 264 |
267 // Content runs are only needed in the initial layout pass, in order to find
an initial column | 265 // Content runs are only needed in the initial layout pass, in order to find
an initial column |
268 // height, and should have been deleted afterwards. We're about to rebuild t
he content runs, so | 266 // height, and should have been deleted afterwards. We're about to rebuild t
he content runs, so |
269 // the list needs to be empty. | 267 // the list needs to be empty. |
270 ASSERT(m_contentRuns.isEmpty()); | 268 ASSERT(m_contentRuns.isEmpty()); |
271 } | 269 } |
272 | 270 |
273 void RenderMultiColumnSet::expandToEncompassFlowThreadContentsIfNeeded() | 271 void RenderMultiColumnSet::expandToEncompassFlowThreadContentsIfNeeded() |
274 { | 272 { |
275 ASSERT(multiColumnFlowThread()->lastMultiColumnSet() == this); | 273 ASSERT(multiColumnFlowThread()->lastMultiColumnSet() == this); |
276 LayoutRect rect(flowThreadPortionRect()); | 274 LayoutRect rect(flowThreadPortionRect()); |
277 | 275 |
278 // Get the offset within the flow thread in its block progression direction.
Then get the | 276 // Get the offset within the flow thread in its block progression direction.
Then get the |
279 // flow thread's remaining logical height including its overflow and expand
our rect | 277 // flow thread's remaining logical height including its overflow and expand
our rect |
280 // to encompass that remaining height and overflow. The idea is that we will
generate | 278 // to encompass that remaining height and overflow. The idea is that we will
generate |
281 // additional columns and pages to hold that overflow, since people do write
bad | 279 // additional columns and pages to hold that overflow, since people do write
bad |
282 // content like <body style="height:0px"> in multi-column layouts. | 280 // content like <body style="height:0px"> in multi-column layouts. |
283 bool isHorizontal = flowThread()->isHorizontalWritingMode(); | 281 bool isHorizontal = flowThread()->isHorizontalWritingMode(); |
284 LayoutUnit logicalTopOffset = isHorizontal ? rect.y() : rect.x(); | 282 LayoutUnit logicalTopOffset = isHorizontal ? rect.y() : rect.x(); |
285 LayoutRect layoutRect = flowThread()->layoutOverflowRect(); | 283 LayoutRect layoutRect = flowThread()->layoutOverflowRect(); |
286 LayoutUnit logicalHeightWithOverflow = (isHorizontal ? layoutRect.maxY() : l
ayoutRect.maxX()) - logicalTopOffset; | 284 LayoutUnit logicalHeightWithOverflow = (isHorizontal ? layoutRect.maxY() : l
ayoutRect.maxX()) - logicalTopOffset; |
287 setFlowThreadPortionRect(LayoutRect(rect.x(), rect.y(), isHorizontal ? rect.
width() : logicalHeightWithOverflow, isHorizontal ? logicalHeightWithOverflow :
rect.height())); | 285 setFlowThreadPortionRect(LayoutRect(rect.x(), rect.y(), isHorizontal ? rect.
width() : logicalHeightWithOverflow, isHorizontal ? logicalHeightWithOverflow :
rect.height())); |
288 } | 286 } |
289 | 287 |
290 void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTo
p, LogicalExtentComputedValues& computedValues) const | 288 void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTo
p, LogicalExtentComputedValues& computedValues) const |
291 { | 289 { |
292 computedValues.m_extent = m_computedColumnHeight; | 290 computedValues.m_extent = m_columnHeight; |
293 computedValues.m_position = logicalTop; | 291 computedValues.m_position = logicalTop; |
294 } | 292 } |
295 | 293 |
296 LayoutUnit RenderMultiColumnSet::calculateMaxColumnHeight() const | 294 LayoutUnit RenderMultiColumnSet::calculateMaxColumnHeight() const |
297 { | 295 { |
298 RenderBlockFlow* multicolBlock = multiColumnBlockFlow(); | 296 RenderBlockFlow* multicolBlock = multiColumnBlockFlow(); |
299 RenderStyle* multicolStyle = multicolBlock->style(); | 297 RenderStyle* multicolStyle = multicolBlock->style(); |
300 LayoutUnit availableHeight = multiColumnFlowThread()->columnHeightAvailable(
); | 298 LayoutUnit availableHeight = multiColumnFlowThread()->columnHeightAvailable(
); |
301 LayoutUnit maxColumnHeight = availableHeight ? availableHeight : RenderFlowT
hread::maxLogicalHeight(); | 299 LayoutUnit maxColumnHeight = availableHeight ? availableHeight : RenderFlowT
hread::maxLogicalHeight(); |
302 if (!multicolStyle->logicalMaxHeight().isUndefined()) { | 300 if (!multicolStyle->logicalMaxHeight().isUndefined()) { |
303 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight
(multicolStyle->logicalMaxHeight(), -1); | 301 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight
(multicolStyle->logicalMaxHeight(), -1); |
304 if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight) | 302 if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight) |
305 maxColumnHeight = logicalMaxHeight; | 303 maxColumnHeight = logicalMaxHeight; |
306 } | 304 } |
307 return heightAdjustedForSetOffset(maxColumnHeight); | 305 return heightAdjustedForSetOffset(maxColumnHeight); |
308 } | 306 } |
309 | 307 |
310 LayoutUnit RenderMultiColumnSet::columnGap() const | 308 LayoutUnit RenderMultiColumnSet::columnGap() const |
311 { | 309 { |
312 RenderBlockFlow* parentBlock = multiColumnBlockFlow(); | 310 RenderBlockFlow* parentBlock = multiColumnBlockFlow(); |
313 if (parentBlock->style()->hasNormalColumnGap()) | 311 if (parentBlock->style()->hasNormalColumnGap()) |
314 return parentBlock->style()->fontDescription().computedPixelSize(); // "
1em" is recommended as the normal gap setting. Matches <p> margins. | 312 return parentBlock->style()->fontDescription().computedPixelSize(); // "
1em" is recommended as the normal gap setting. Matches <p> margins. |
315 return parentBlock->style()->columnGap(); | 313 return parentBlock->style()->columnGap(); |
316 } | 314 } |
317 | 315 |
318 unsigned RenderMultiColumnSet::columnCount() const | 316 unsigned RenderMultiColumnSet::actualColumnCount() const |
319 { | 317 { |
320 // We must always return a value of 1 or greater. Column count = 0 is a mean
ingless situation, | 318 // We must always return a value of 1 or greater. Column count = 0 is a mean
ingless situation, |
321 // and will confuse and cause problems in other parts of the code. | 319 // and will confuse and cause problems in other parts of the code. |
322 if (!computedColumnHeight()) | 320 if (!pageLogicalHeight()) |
323 return 1; | 321 return 1; |
324 | 322 |
325 // Our portion rect determines our column count. We have as many columns as
needed to fit all the content. | 323 // Our portion rect determines our column count. We have as many columns as
needed to fit all the content. |
326 LayoutUnit logicalHeightInColumns = flowThread()->isHorizontalWritingMode()
? flowThreadPortionRect().height() : flowThreadPortionRect().width(); | 324 LayoutUnit logicalHeightInColumns = flowThread()->isHorizontalWritingMode()
? flowThreadPortionRect().height() : flowThreadPortionRect().width(); |
327 if (!logicalHeightInColumns) | 325 if (!logicalHeightInColumns) |
328 return 1; | 326 return 1; |
329 | 327 |
330 unsigned count = ceil(logicalHeightInColumns.toFloat() / computedColumnHeigh
t().toFloat()); | 328 unsigned count = ceil(logicalHeightInColumns.toFloat() / pageLogicalHeight()
.toFloat()); |
331 ASSERT(count >= 1); | 329 ASSERT(count >= 1); |
332 return count; | 330 return count; |
333 } | 331 } |
334 | 332 |
335 LayoutRect RenderMultiColumnSet::columnRectAt(unsigned index) const | 333 LayoutRect RenderMultiColumnSet::columnRectAt(unsigned index) const |
336 { | 334 { |
337 LayoutUnit colLogicalWidth = computedColumnWidth(); | 335 LayoutUnit colLogicalWidth = pageLogicalWidth(); |
338 LayoutUnit colLogicalHeight = computedColumnHeight(); | 336 LayoutUnit colLogicalHeight = pageLogicalHeight(); |
339 LayoutUnit colLogicalTop = borderBefore() + paddingBefore(); | 337 LayoutUnit colLogicalTop = borderBefore() + paddingBefore(); |
340 LayoutUnit colLogicalLeft = borderAndPaddingLogicalLeft(); | 338 LayoutUnit colLogicalLeft = borderAndPaddingLogicalLeft(); |
341 LayoutUnit colGap = columnGap(); | 339 LayoutUnit colGap = columnGap(); |
342 if (style()->isLeftToRightDirection()) | 340 if (style()->isLeftToRightDirection()) |
343 colLogicalLeft += index * (colLogicalWidth + colGap); | 341 colLogicalLeft += index * (colLogicalWidth + colGap); |
344 else | 342 else |
345 colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * (col
LogicalWidth + colGap); | 343 colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * (col
LogicalWidth + colGap); |
346 | 344 |
347 if (isHorizontalWritingMode()) | 345 if (isHorizontalWritingMode()) |
348 return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLog
icalHeight); | 346 return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLog
icalHeight); |
349 return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogica
lWidth); | 347 return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogica
lWidth); |
350 } | 348 } |
351 | 349 |
352 unsigned RenderMultiColumnSet::columnIndexAtOffset(LayoutUnit offset, ColumnInde
xCalculationMode mode) const | 350 unsigned RenderMultiColumnSet::columnIndexAtOffset(LayoutUnit offset, ColumnInde
xCalculationMode mode) const |
353 { | 351 { |
354 LayoutRect portionRect(flowThreadPortionRect()); | 352 LayoutRect portionRect(flowThreadPortionRect()); |
355 | 353 |
356 // Handle the offset being out of range. | 354 // Handle the offset being out of range. |
357 LayoutUnit flowThreadLogicalTop = isHorizontalWritingMode() ? portionRect.y(
) : portionRect.x(); | 355 LayoutUnit flowThreadLogicalTop = isHorizontalWritingMode() ? portionRect.y(
) : portionRect.x(); |
358 if (offset < flowThreadLogicalTop) | 356 if (offset < flowThreadLogicalTop) |
359 return 0; | 357 return 0; |
360 // If we're laying out right now, we cannot constrain against some logical b
ottom, since it | 358 // If we're laying out right now, we cannot constrain against some logical b
ottom, since it |
361 // isn't known yet. Otherwise, just return the last column if we're past the
logical bottom. | 359 // isn't known yet. Otherwise, just return the last column if we're past the
logical bottom. |
362 if (mode == ClampToExistingColumns) { | 360 if (mode == ClampToExistingColumns) { |
363 LayoutUnit flowThreadLogicalBottom = isHorizontalWritingMode() ? portion
Rect.maxY() : portionRect.maxX(); | 361 LayoutUnit flowThreadLogicalBottom = isHorizontalWritingMode() ? portion
Rect.maxY() : portionRect.maxX(); |
364 if (offset >= flowThreadLogicalBottom) | 362 if (offset >= flowThreadLogicalBottom) |
365 return columnCount() - 1; | 363 return actualColumnCount() - 1; |
366 } | 364 } |
367 | 365 |
368 // Just divide by the column height to determine the correct column. | 366 // Just divide by the column height to determine the correct column. |
369 return (offset - flowThreadLogicalTop).toFloat() / computedColumnHeight().to
Float(); | 367 return (offset - flowThreadLogicalTop).toFloat() / pageLogicalHeight().toFlo
at(); |
370 } | 368 } |
371 | 369 |
372 LayoutRect RenderMultiColumnSet::flowThreadPortionRectAt(unsigned index) const | 370 LayoutRect RenderMultiColumnSet::flowThreadPortionRectAt(unsigned index) const |
373 { | 371 { |
374 LayoutRect portionRect = flowThreadPortionRect(); | 372 LayoutRect portionRect = flowThreadPortionRect(); |
375 if (isHorizontalWritingMode()) | 373 if (isHorizontalWritingMode()) |
376 portionRect = LayoutRect(portionRect.x(), portionRect.y() + index * comp
utedColumnHeight(), portionRect.width(), computedColumnHeight()); | 374 portionRect = LayoutRect(portionRect.x(), portionRect.y() + index * page
LogicalHeight(), portionRect.width(), pageLogicalHeight()); |
377 else | 375 else |
378 portionRect = LayoutRect(portionRect.x() + index * computedColumnHeight(
), portionRect.y(), computedColumnHeight(), portionRect.height()); | 376 portionRect = LayoutRect(portionRect.x() + index * pageLogicalHeight(),
portionRect.y(), pageLogicalHeight(), portionRect.height()); |
379 return portionRect; | 377 return portionRect; |
380 } | 378 } |
381 | 379 |
382 LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect&
portionRect, unsigned index, unsigned colCount, LayoutUnit colGap) const | 380 LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect&
portionRect, unsigned index, unsigned colCount, LayoutUnit colGap) const |
383 { | 381 { |
384 // This function determines the portion of the flow thread that paints for t
he column. Along the inline axis, columns are | 382 // This function determines the portion of the flow thread that paints for t
he column. Along the inline axis, columns are |
385 // unclipped at outside edges (i.e., the first and last column in the set),
and they clip to half the column | 383 // unclipped at outside edges (i.e., the first and last column in the set),
and they clip to half the column |
386 // gap along interior edges. | 384 // gap along interior edges. |
387 // | 385 // |
388 // In the block direction, we will not clip overflow out of the top of the f
irst column, or out of the bottom of | 386 // In the block direction, we will not clip overflow out of the top of the f
irst column, or out of the bottom of |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
442 RenderStyle* blockStyle = multiColumnBlockFlow()->style(); | 440 RenderStyle* blockStyle = multiColumnBlockFlow()->style(); |
443 const Color& ruleColor = resolveColor(blockStyle, CSSPropertyWebkitColumnRul
eColor); | 441 const Color& ruleColor = resolveColor(blockStyle, CSSPropertyWebkitColumnRul
eColor); |
444 bool ruleTransparent = blockStyle->columnRuleIsTransparent(); | 442 bool ruleTransparent = blockStyle->columnRuleIsTransparent(); |
445 EBorderStyle ruleStyle = blockStyle->columnRuleStyle(); | 443 EBorderStyle ruleStyle = blockStyle->columnRuleStyle(); |
446 LayoutUnit ruleThickness = blockStyle->columnRuleWidth(); | 444 LayoutUnit ruleThickness = blockStyle->columnRuleWidth(); |
447 LayoutUnit colGap = columnGap(); | 445 LayoutUnit colGap = columnGap(); |
448 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent; | 446 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent; |
449 if (!renderRule) | 447 if (!renderRule) |
450 return; | 448 return; |
451 | 449 |
452 unsigned colCount = columnCount(); | 450 unsigned colCount = actualColumnCount(); |
453 if (colCount <= 1) | 451 if (colCount <= 1) |
454 return; | 452 return; |
455 | 453 |
456 bool antialias = shouldAntialiasLines(paintInfo.context); | 454 bool antialias = shouldAntialiasLines(paintInfo.context); |
457 | 455 |
458 bool leftToRight = style()->isLeftToRightDirection(); | 456 bool leftToRight = style()->isLeftToRightDirection(); |
459 LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogic
alWidth(); | 457 LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogic
alWidth(); |
460 LayoutUnit ruleAdd = borderAndPaddingLogicalLeft(); | 458 LayoutUnit ruleAdd = borderAndPaddingLogicalLeft(); |
461 LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidt
h(); | 459 LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidt
h(); |
462 LayoutUnit inlineDirectionSize = computedColumnWidth(); | 460 LayoutUnit inlineDirectionSize = pageLogicalWidth(); |
463 BoxSide boxSide = isHorizontalWritingMode() | 461 BoxSide boxSide = isHorizontalWritingMode() |
464 ? leftToRight ? BSLeft : BSRight | 462 ? leftToRight ? BSLeft : BSRight |
465 : leftToRight ? BSTop : BSBottom; | 463 : leftToRight ? BSTop : BSBottom; |
466 | 464 |
467 for (unsigned i = 0; i < colCount; i++) { | 465 for (unsigned i = 0; i < colCount; i++) { |
468 // Move to the next position. | 466 // Move to the next position. |
469 if (leftToRight) { | 467 if (leftToRight) { |
470 ruleLogicalLeft += inlineDirectionSize + colGap / 2; | 468 ruleLogicalLeft += inlineDirectionSize + colGap / 2; |
471 currLogicalLeftOffset += inlineDirectionSize + colGap; | 469 currLogicalLeftOffset += inlineDirectionSize + colGap; |
472 } else { | 470 } else { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
504 | 502 |
505 // Now we know we intersect at least one column. Let's figure out the logica
l top and logical | 503 // Now we know we intersect at least one column. Let's figure out the logica
l top and logical |
506 // bottom of the area we're repainting. | 504 // bottom of the area we're repainting. |
507 LayoutUnit repaintLogicalTop = isHorizontalWritingMode() ? flowThreadRepaint
Rect.y() : flowThreadRepaintRect.x(); | 505 LayoutUnit repaintLogicalTop = isHorizontalWritingMode() ? flowThreadRepaint
Rect.y() : flowThreadRepaintRect.x(); |
508 LayoutUnit repaintLogicalBottom = (isHorizontalWritingMode() ? flowThreadRep
aintRect.maxY() : flowThreadRepaintRect.maxX()) - 1; | 506 LayoutUnit repaintLogicalBottom = (isHorizontalWritingMode() ? flowThreadRep
aintRect.maxY() : flowThreadRepaintRect.maxX()) - 1; |
509 | 507 |
510 unsigned startColumn = columnIndexAtOffset(repaintLogicalTop); | 508 unsigned startColumn = columnIndexAtOffset(repaintLogicalTop); |
511 unsigned endColumn = columnIndexAtOffset(repaintLogicalBottom); | 509 unsigned endColumn = columnIndexAtOffset(repaintLogicalBottom); |
512 | 510 |
513 LayoutUnit colGap = columnGap(); | 511 LayoutUnit colGap = columnGap(); |
514 unsigned colCount = columnCount(); | 512 unsigned colCount = actualColumnCount(); |
515 for (unsigned i = startColumn; i <= endColumn; i++) { | 513 for (unsigned i = startColumn; i <= endColumn; i++) { |
516 LayoutRect colRect = columnRectAt(i); | 514 LayoutRect colRect = columnRectAt(i); |
517 | 515 |
518 // Get the portion of the flow thread that corresponds to this column. | 516 // Get the portion of the flow thread that corresponds to this column. |
519 LayoutRect flowThreadPortion = flowThreadPortionRectAt(i); | 517 LayoutRect flowThreadPortion = flowThreadPortionRectAt(i); |
520 | 518 |
521 // Now get the overflow rect that corresponds to the column. | 519 // Now get the overflow rect that corresponds to the column. |
522 LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flo
wThreadPortion, i, colCount, colGap); | 520 LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flo
wThreadPortion, i, colCount, colGap); |
523 | 521 |
524 // Do a repaint for this specific column. | 522 // Do a repaint for this specific column. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
557 // Now we know we intersect at least one column. Let's figure out the logica
l top and logical | 555 // Now we know we intersect at least one column. Let's figure out the logica
l top and logical |
558 // bottom of the area we're checking. | 556 // bottom of the area we're checking. |
559 LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowTh
read.y() : layerBoundsInFlowThread.x(); | 557 LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowTh
read.y() : layerBoundsInFlowThread.x(); |
560 LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFl
owThread.maxY() : layerBoundsInFlowThread.maxX()) - 1; | 558 LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFl
owThread.maxY() : layerBoundsInFlowThread.maxX()) - 1; |
561 | 559 |
562 // Figure out the start and end columns and only check within that range so
that we don't walk the | 560 // Figure out the start and end columns and only check within that range so
that we don't walk the |
563 // entire column set. | 561 // entire column set. |
564 unsigned startColumn = columnIndexAtOffset(layerLogicalTop); | 562 unsigned startColumn = columnIndexAtOffset(layerLogicalTop); |
565 unsigned endColumn = columnIndexAtOffset(layerLogicalBottom); | 563 unsigned endColumn = columnIndexAtOffset(layerLogicalBottom); |
566 | 564 |
567 LayoutUnit colLogicalWidth = computedColumnWidth(); | 565 LayoutUnit colLogicalWidth = pageLogicalWidth(); |
568 LayoutUnit colGap = columnGap(); | 566 LayoutUnit colGap = columnGap(); |
569 unsigned colCount = columnCount(); | 567 unsigned colCount = actualColumnCount(); |
570 | 568 |
571 for (unsigned i = startColumn; i <= endColumn; i++) { | 569 for (unsigned i = startColumn; i <= endColumn; i++) { |
572 // Get the portion of the flow thread that corresponds to this column. | 570 // Get the portion of the flow thread that corresponds to this column. |
573 LayoutRect flowThreadPortion = flowThreadPortionRectAt(i); | 571 LayoutRect flowThreadPortion = flowThreadPortionRectAt(i); |
574 | 572 |
575 // Now get the overflow rect that corresponds to the column. | 573 // Now get the overflow rect that corresponds to the column. |
576 LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flo
wThreadPortion, i, colCount, colGap); | 574 LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flo
wThreadPortion, i, colCount, colGap); |
577 | 575 |
578 // In order to create a fragment we must intersect the portion painted b
y this column. | 576 // In order to create a fragment we must intersect the portion painted b
y this column. |
579 LayoutRect clippedRect(layerBoundsInFlowThread); | 577 LayoutRect clippedRect(layerBoundsInFlowThread); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
615 LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion); | 613 LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion); |
616 // Flip it into more a physical (RenderLayer-style) rectangle. | 614 // Flip it into more a physical (RenderLayer-style) rectangle. |
617 flowThread()->flipForWritingMode(flippedFlowThreadOverflowPortion); | 615 flowThread()->flipForWritingMode(flippedFlowThreadOverflowPortion); |
618 fragment.paginationClip = flippedFlowThreadOverflowPortion; | 616 fragment.paginationClip = flippedFlowThreadOverflowPortion; |
619 fragments.append(fragment); | 617 fragments.append(fragment); |
620 } | 618 } |
621 } | 619 } |
622 | 620 |
623 void RenderMultiColumnSet::addOverflowFromChildren() | 621 void RenderMultiColumnSet::addOverflowFromChildren() |
624 { | 622 { |
625 unsigned colCount = columnCount(); | 623 unsigned colCount = actualColumnCount(); |
626 if (!colCount) | 624 if (!colCount) |
627 return; | 625 return; |
628 | 626 |
629 LayoutRect lastRect = columnRectAt(colCount - 1); | 627 LayoutRect lastRect = columnRectAt(colCount - 1); |
630 addLayoutOverflow(lastRect); | 628 addLayoutOverflow(lastRect); |
631 if (!hasOverflowClip()) | 629 if (!hasOverflowClip()) |
632 addVisualOverflow(lastRect); | 630 addVisualOverflow(lastRect); |
633 } | 631 } |
634 | 632 |
635 const char* RenderMultiColumnSet::renderName() const | 633 const char* RenderMultiColumnSet::renderName() const |
636 { | 634 { |
637 return "RenderMultiColumnSet"; | 635 return "RenderMultiColumnSet"; |
638 } | 636 } |
639 | 637 |
640 } | 638 } |
OLD | NEW |