Chromium Code Reviews| 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 11 matching lines...) Expand all Loading... | |
| 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/RenderMultiColumnFlowThread.h" | 31 #include "core/rendering/RenderMultiColumnFlowThread.h" |
| 32 #include "core/rendering/RenderMultiColumnSpannerPlaceholder.h" | |
| 32 | 33 |
| 33 using namespace std; | 34 using namespace std; |
| 34 | 35 |
| 35 namespace WebCore { | 36 namespace WebCore { |
| 36 | 37 |
| 37 RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread) | 38 RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread) |
| 38 : RenderRegion(0, flowThread) | 39 : RenderRegion(0, flowThread) |
| 39 , m_columnHeight(0) | 40 , m_columnHeight(0) |
| 40 , m_maxColumnHeight(RenderFlowThread::maxLogicalHeight()) | 41 , m_maxColumnHeight(RenderFlowThread::maxLogicalHeight()) |
| 41 , m_minSpaceShortage(RenderFlowThread::maxLogicalHeight()) | 42 , m_minSpaceShortage(RenderFlowThread::maxLogicalHeight()) |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 63 | 64 |
| 64 RenderMultiColumnSet* RenderMultiColumnSet::previousSiblingMultiColumnSet() cons t | 65 RenderMultiColumnSet* RenderMultiColumnSet::previousSiblingMultiColumnSet() cons t |
| 65 { | 66 { |
| 66 for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling-> previousSibling()) { | 67 for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling-> previousSibling()) { |
| 67 if (sibling->isRenderMultiColumnSet()) | 68 if (sibling->isRenderMultiColumnSet()) |
| 68 return toRenderMultiColumnSet(sibling); | 69 return toRenderMultiColumnSet(sibling); |
| 69 } | 70 } |
| 70 return 0; | 71 return 0; |
| 71 } | 72 } |
| 72 | 73 |
| 74 RenderObject* RenderMultiColumnSet::firstRendererInFlowThread() const | |
| 75 { | |
| 76 if (RenderBox* sibling = RenderMultiColumnFlowThread::previousColumnSetOrSpa nnerSiblingOf(this)) { | |
| 77 // Adjacent sets should not occur. Currently we would have no way of fig uring out what each | |
| 78 // of them contains then. | |
| 79 ASSERT(!sibling->isRenderMultiColumnSet()); | |
| 80 RenderMultiColumnSpannerPlaceholder* placeholder = multiColumnFlowThread ()->findColumnSpannerPlaceholder(sibling); | |
|
rune
2014/07/01 08:41:38
Perhaps add an ASSERT(placeholder) as well?
mstensho (USE GERRIT)
2014/08/26 09:43:58
Is it really necessary? It's gonna crash if it's N
rune
2014/08/27 07:00:01
It adds the information that it's not missing a nu
| |
| 81 return placeholder->nextInPreOrderAfterChildren(); | |
| 82 } | |
| 83 return flowThread()->firstChild(); | |
| 84 } | |
| 85 | |
| 86 RenderObject* RenderMultiColumnSet::lastRendererInFlowThread() const | |
| 87 { | |
| 88 if (RenderBox* sibling = RenderMultiColumnFlowThread::nextColumnSetOrSpanner SiblingOf(this)) { | |
| 89 // Adjacent sets should not occur. Currently we would have no way of fig uring out what each | |
| 90 // of them contains then. | |
| 91 ASSERT(!sibling->isRenderMultiColumnSet()); | |
| 92 RenderMultiColumnSpannerPlaceholder* placeholder = multiColumnFlowThread ()->findColumnSpannerPlaceholder(sibling); | |
| 93 return placeholder->previousInPreOrder(); | |
| 94 } | |
| 95 return flowThread()->lastLeafChild(); | |
| 96 } | |
| 97 | |
| 98 static bool precedesRenderer(RenderObject* renderer, RenderObject* boundary) | |
| 99 { | |
| 100 for (; renderer; renderer = renderer->nextInPreOrder()) { | |
| 101 if (renderer == boundary) | |
| 102 return true; | |
| 103 } | |
| 104 return false; | |
| 105 } | |
| 106 | |
| 107 bool RenderMultiColumnSet::renders(RenderObject* renderer) const | |
| 108 { | |
| 109 if (!previousSiblingMultiColumnSet() && !nextSiblingMultiColumnSet()) { | |
| 110 // There is only one set. This is easy, then. | |
| 111 return renderer->isDescendantOf(m_flowThread); | |
| 112 } | |
| 113 | |
| 114 RenderObject* firstRenderer = firstRendererInFlowThread(); | |
| 115 RenderObject* lastRenderer = lastRendererInFlowThread(); | |
| 116 ASSERT(firstRenderer); | |
| 117 ASSERT(lastRenderer); | |
| 118 | |
| 119 // This is SLOW! But luckily very uncommon. | |
|
rune
2014/07/01 08:41:38
Perhaps note in which cases it happens. Is it when
mstensho (USE GERRIT)
2014/08/26 09:43:58
Done.
rune
2014/08/27 08:17:38
Acknowledged.
| |
| 120 return precedesRenderer(firstRenderer, renderer) && precedesRenderer(rendere r, lastRenderer); | |
|
rune
2014/07/01 08:41:38
Do you need to check both? From where you call ren
mstensho (USE GERRIT)
2014/08/26 09:43:58
Done.
We don't look inside spanners here, so no n
rune
2014/08/27 08:17:38
I see that this code has been transformed in an op
mstensho (USE GERRIT)
2014/08/27 08:24:05
This code is new in this CL and an issue was raise
rune
2014/08/27 08:36:31
It such a long time since I reviewed this as well.
mstensho (USE GERRIT)
2014/08/27 08:47:02
That's what I did in practice. But I lumped it all
rune
2014/08/27 10:22:27
Acknowledged.
| |
| 121 } | |
| 122 | |
| 123 void RenderMultiColumnSet::setLogicalTopInFlowThread(LayoutUnit logicalTop) | |
| 124 { | |
| 125 LayoutRect rect = flowThreadPortionRect(); | |
| 126 if (isHorizontalWritingMode()) | |
| 127 rect.setY(logicalTop); | |
| 128 else | |
| 129 rect.setX(logicalTop); | |
| 130 setFlowThreadPortionRect(rect); | |
| 131 } | |
| 132 | |
| 133 void RenderMultiColumnSet::setLogicalBottomInFlowThread(LayoutUnit logicalBottom ) | |
| 134 { | |
| 135 LayoutRect rect = flowThreadPortionRect(); | |
| 136 if (isHorizontalWritingMode()) | |
| 137 rect.shiftMaxYEdgeTo(logicalBottom); | |
| 138 else | |
| 139 rect.shiftMaxXEdgeTo(logicalBottom); | |
| 140 setFlowThreadPortionRect(rect); | |
| 141 } | |
| 142 | |
| 143 bool RenderMultiColumnSet::heightIsAuto() const | |
| 144 { | |
| 145 RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread(); | |
| 146 if (!flowThread->isRenderPagedFlowThread()) { | |
| 147 if (RenderBox* next = RenderMultiColumnFlowThread::nextColumnSetOrSpanne rSiblingOf(this)) { | |
| 148 if (!next->isRenderMultiColumnSet()) { | |
| 149 // If we're followed by a spanner, we need to balance. | |
| 150 ASSERT(flowThread->findColumnSpannerPlaceholder(next)); | |
| 151 return true; | |
| 152 } | |
| 153 } | |
| 154 if (multiColumnBlockFlow()->style()->columnFill() == ColumnFillBalance) | |
| 155 return true; | |
| 156 } | |
| 157 return !flowThread->columnHeightAvailable(); | |
| 158 } | |
| 159 | |
| 73 LayoutSize RenderMultiColumnSet::flowThreadTranslationAtOffset(LayoutUnit blockO ffset) const | 160 LayoutSize RenderMultiColumnSet::flowThreadTranslationAtOffset(LayoutUnit blockO ffset) const |
| 74 { | 161 { |
| 75 unsigned columnIndex = columnIndexAtOffset(blockOffset); | 162 unsigned columnIndex = columnIndexAtOffset(blockOffset); |
| 76 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); | 163 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); |
| 77 flipForWritingMode(portionRect); | 164 flipForWritingMode(portionRect); |
| 78 LayoutRect columnRect(columnRectAt(columnIndex)); | 165 LayoutRect columnRect(columnRectAt(columnIndex)); |
| 79 flipForWritingMode(columnRect); | 166 flipForWritingMode(columnRect); |
| 80 return contentBoxRect().location() + columnRect.location() - portionRect.loc ation(); | 167 return contentBoxRect().location() + columnRect.location() - portionRect.loc ation(); |
| 81 } | 168 } |
| 82 | 169 |
| 83 LayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) c onst | 170 LayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) c onst |
| 84 { | 171 { |
| 85 // Adjust for the top offset within the content box of the multicol containe r (containing | 172 // Adjust for the top offset within the content box of the multicol containe r (containing |
| 86 // block), unless this is the first set. We know that the top offset for the first set will be | 173 // block), unless this is the first set. We know that the top offset for the first set will be |
| 87 // zero, but if the multicol container has non-zero top border or padding, t he set's top offset | 174 // zero, but if the multicol container has non-zero top border or padding, t he set's top offset |
| 88 // (initially being 0 and relative to the border box) will be negative until it has been laid | 175 // (initially being 0 and relative to the border box) will be negative until it has been laid |
| 89 // out. Had we used this bogus offset, we would calculate the wrong height, and risk performing | 176 // out. Had we used this bogus offset, we would calculate the wrong height, and risk performing |
| 90 // a wasted layout iteration. Of course all other sets (if any) have this pr oblem in the first | 177 // a wasted layout iteration. Of course all other sets (if any) have this pr oblem in the first |
| 91 // layout pass too, but there's really nothing we can do there until the flo w thread has been | 178 // layout pass too, but there's really nothing we can do there until the flo w thread has been |
| 92 // laid out anyway. | 179 // laid out anyway. |
| 93 if (previousSiblingMultiColumnSet()) { | 180 if (RenderMultiColumnFlowThread::previousColumnSetOrSpannerSiblingOf(this)) { |
| 94 RenderBlockFlow* multicolBlock = multiColumnBlockFlow(); | 181 RenderBlockFlow* multicolBlock = multiColumnBlockFlow(); |
| 95 LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderAndPa ddingBefore(); | 182 LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderAndPa ddingBefore(); |
| 96 height -= contentLogicalTop; | 183 height -= contentLogicalTop; |
| 97 } | 184 } |
| 98 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created. | 185 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created. |
| 99 } | 186 } |
| 100 | 187 |
| 101 LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) cons t | 188 LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) cons t |
| 102 { | 189 { |
| 103 unsigned columnIndex = columnIndexAtOffset(offset, AssumeNewColumns); | 190 unsigned columnIndex = columnIndexAtOffset(offset, AssumeNewColumns); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 186 ASSERT(m_minSpaceShortage > 0); // We should never _shrink_ the height! | 273 ASSERT(m_minSpaceShortage > 0); // We should never _shrink_ the height! |
| 187 ASSERT(m_minSpaceShortage != RenderFlowThread::maxLogicalHeight()); // If th is happens, we probably have a bug. | 274 ASSERT(m_minSpaceShortage != RenderFlowThread::maxLogicalHeight()); // If th is happens, we probably have a bug. |
| 188 if (m_minSpaceShortage == RenderFlowThread::maxLogicalHeight()) | 275 if (m_minSpaceShortage == RenderFlowThread::maxLogicalHeight()) |
| 189 return m_columnHeight; // So bail out rather than looping infinitely. | 276 return m_columnHeight; // So bail out rather than looping infinitely. |
| 190 | 277 |
| 191 return m_columnHeight + m_minSpaceShortage; | 278 return m_columnHeight + m_minSpaceShortage; |
| 192 } | 279 } |
| 193 | 280 |
| 194 void RenderMultiColumnSet::addContentRun(LayoutUnit endOffsetFromFirstPage) | 281 void RenderMultiColumnSet::addContentRun(LayoutUnit endOffsetFromFirstPage) |
| 195 { | 282 { |
| 196 if (!multiColumnFlowThread()->heightIsAuto()) | 283 if (!heightIsAuto()) |
| 197 return; | 284 return; |
| 198 if (!m_contentRuns.isEmpty() && endOffsetFromFirstPage <= m_contentRuns.last ().breakOffset()) | 285 if (!m_contentRuns.isEmpty() && endOffsetFromFirstPage <= m_contentRuns.last ().breakOffset()) |
| 199 return; | 286 return; |
| 200 // Append another item as long as we haven't exceeded used column count. Wha t ends up in the | 287 // Append another item as long as we haven't exceeded used column count. Wha t ends up in the |
| 201 // overflow area shouldn't affect column balancing. | 288 // overflow area shouldn't affect column balancing. |
| 202 if (m_contentRuns.size() < usedColumnCount()) | 289 if (m_contentRuns.size() < usedColumnCount()) |
| 203 m_contentRuns.append(ContentRun(endOffsetFromFirstPage)); | 290 m_contentRuns.append(ContentRun(endOffsetFromFirstPage)); |
| 204 } | 291 } |
| 205 | 292 |
| 206 bool RenderMultiColumnSet::recalculateColumnHeight(BalancedHeightCalculation cal culationMode) | 293 bool RenderMultiColumnSet::recalculateColumnHeight(BalancedHeightCalculation cal culationMode) |
| 207 { | 294 { |
| 208 ASSERT(multiColumnFlowThread()->heightIsAuto()); | 295 LayoutUnit oldColumnHeight = m_columnHeight; |
| 209 | 296 |
| 210 LayoutUnit oldColumnHeight = m_columnHeight; | 297 m_maxColumnHeight = calculateMaxColumnHeight(); |
| 211 if (calculationMode == GuessFromFlowThreadPortion) { | 298 |
| 212 // Post-process the content runs and find out where the implicit breaks will occur. | 299 if (heightIsAuto()) { |
| 213 distributeImplicitBreaks(); | 300 if (calculationMode == GuessFromFlowThreadPortion) { |
| 301 // Post-process the content runs and find out where the implicit bre aks will occur. | |
| 302 distributeImplicitBreaks(); | |
| 303 } | |
| 304 LayoutUnit newColumnHeight = calculateColumnHeight(calculationMode); | |
| 305 setAndConstrainColumnHeight(newColumnHeight); | |
| 306 // After having calculated an initial column height, the multicol contai ner typically needs at | |
| 307 // least one more layout pass with a new column height, but if a height was specified, we only | |
| 308 // need to do this if we think that we need less space than specified. C onversely, if we | |
| 309 // determined that the columns need to be as tall as the specified heigh t of the container, we | |
| 310 // have already laid it out correctly, and there's no need for another p ass. | |
| 311 } else { | |
| 312 // The position of the column set may have changed, in which case height available for | |
| 313 // columns may have changed as well. | |
| 314 setAndConstrainColumnHeight(m_columnHeight); | |
| 214 } | 315 } |
| 215 LayoutUnit newColumnHeight = calculateColumnHeight(calculationMode); | |
| 216 setAndConstrainColumnHeight(newColumnHeight); | |
| 217 | |
| 218 // After having calculated an initial column height, the multicol container typically needs at | |
| 219 // least one more layout pass with a new column height, but if a height was specified, we only | |
| 220 // need to do this if we think that we need less space than specified. Conve rsely, if we | |
| 221 // determined that the columns need to be as tall as the specified height of the container, we | |
| 222 // have already laid it out correctly, and there's no need for another pass. | |
| 223 | 316 |
| 224 // We can get rid of the content runs now, if we haven't already done so. Th ey are only needed | 317 // We can get rid of the content runs now, if we haven't already done so. Th ey are only needed |
| 225 // to calculate the initial balanced column height. In fact, we have to get rid of them before | 318 // to calculate the initial balanced column height. In fact, we have to get rid of them before |
| 226 // the next layout pass, since each pass will rebuild this. | 319 // the next layout pass, since each pass will rebuild this. |
| 227 m_contentRuns.clear(); | 320 m_contentRuns.clear(); |
| 228 | 321 |
| 229 if (m_columnHeight == oldColumnHeight) | 322 if (m_columnHeight == oldColumnHeight) |
| 230 return false; // No change. We're done. | 323 return false; // No change. We're done. |
| 231 | 324 |
| 232 m_minSpaceShortage = RenderFlowThread::maxLogicalHeight(); | 325 m_minSpaceShortage = RenderFlowThread::maxLogicalHeight(); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 247 | 340 |
| 248 void RenderMultiColumnSet::resetColumnHeight() | 341 void RenderMultiColumnSet::resetColumnHeight() |
| 249 { | 342 { |
| 250 // Nuke previously stored minimum column height. Contents may have changed f or all we know. | 343 // Nuke previously stored minimum column height. Contents may have changed f or all we know. |
| 251 m_minimumColumnHeight = 0; | 344 m_minimumColumnHeight = 0; |
| 252 | 345 |
| 253 m_maxColumnHeight = calculateMaxColumnHeight(); | 346 m_maxColumnHeight = calculateMaxColumnHeight(); |
| 254 | 347 |
| 255 LayoutUnit oldColumnHeight = pageLogicalHeight(); | 348 LayoutUnit oldColumnHeight = pageLogicalHeight(); |
| 256 | 349 |
| 257 if (multiColumnFlowThread()->heightIsAuto()) | 350 if (heightIsAuto()) |
| 258 m_columnHeight = 0; | 351 m_columnHeight = 0; |
| 259 else | 352 else |
| 260 setAndConstrainColumnHeight(heightAdjustedForSetOffset(multiColumnFlowTh read()->columnHeightAvailable())); | 353 setAndConstrainColumnHeight(heightAdjustedForSetOffset(multiColumnFlowTh read()->columnHeightAvailable())); |
| 261 | 354 |
| 262 if (pageLogicalHeight() != oldColumnHeight) | 355 if (pageLogicalHeight() != oldColumnHeight) |
| 263 setChildNeedsLayout(MarkOnlyThis); | 356 setChildNeedsLayout(MarkOnlyThis); |
| 264 | 357 |
| 265 // Content runs are only needed in the initial layout pass, in order to find an initial column | 358 // Content runs are only needed in the initial layout pass, in order to find an initial column |
| 266 // height, and should have been deleted afterwards. We're about to rebuild t he content runs, so | 359 // height, and should have been deleted afterwards. We're about to rebuild t he content runs, so |
| 267 // the list needs to be empty. | 360 // the list needs to be empty. |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 647 if (!hasOverflowClip()) | 740 if (!hasOverflowClip()) |
| 648 addVisualOverflow(lastRect); | 741 addVisualOverflow(lastRect); |
| 649 } | 742 } |
| 650 | 743 |
| 651 const char* RenderMultiColumnSet::renderName() const | 744 const char* RenderMultiColumnSet::renderName() const |
| 652 { | 745 { |
| 653 return "RenderMultiColumnSet"; | 746 return "RenderMultiColumnSet"; |
| 654 } | 747 } |
| 655 | 748 |
| 656 } | 749 } |
| OLD | NEW |