| 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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 m_computedColumnHeight = newHeight; | 94 m_computedColumnHeight = newHeight; |
| 95 if (m_computedColumnHeight > m_maxColumnHeight) | 95 if (m_computedColumnHeight > m_maxColumnHeight) |
| 96 m_computedColumnHeight = m_maxColumnHeight; | 96 m_computedColumnHeight = m_maxColumnHeight; |
| 97 // FIXME: the height may also be affected by the enclosing pagination contex
t, if any. | 97 // FIXME: the height may also be affected by the enclosing pagination contex
t, if any. |
| 98 } | 98 } |
| 99 | 99 |
| 100 unsigned RenderMultiColumnSet::findRunWithTallestColumns() const | 100 unsigned RenderMultiColumnSet::findRunWithTallestColumns() const |
| 101 { | 101 { |
| 102 unsigned indexWithLargestHeight = 0; | 102 unsigned indexWithLargestHeight = 0; |
| 103 LayoutUnit largestHeight; | 103 LayoutUnit largestHeight; |
| 104 LayoutUnit previousOffset; | 104 LayoutUnit previousOffset = logicalTopInFlowThread(); |
| 105 size_t runCount = m_contentRuns.size(); | 105 size_t runCount = m_contentRuns.size(); |
| 106 ASSERT(runCount); | 106 ASSERT(runCount); |
| 107 for (size_t i = 0; i < runCount; i++) { | 107 for (size_t i = 0; i < runCount; i++) { |
| 108 const ContentRun& run = m_contentRuns[i]; | 108 const ContentRun& run = m_contentRuns[i]; |
| 109 LayoutUnit height = run.columnLogicalHeight(previousOffset); | 109 LayoutUnit height = run.columnLogicalHeight(previousOffset); |
| 110 if (largestHeight < height) { | 110 if (largestHeight < height) { |
| 111 largestHeight = height; | 111 largestHeight = height; |
| 112 indexWithLargestHeight = i; | 112 indexWithLargestHeight = i; |
| 113 } | 113 } |
| 114 previousOffset = run.breakOffset(); | 114 previousOffset = run.breakOffset(); |
| 115 } | 115 } |
| 116 return indexWithLargestHeight; | 116 return indexWithLargestHeight; |
| 117 } | 117 } |
| 118 | 118 |
| 119 void RenderMultiColumnSet::distributeImplicitBreaks() | 119 void RenderMultiColumnSet::distributeImplicitBreaks() |
| 120 { | 120 { |
| 121 #ifndef NDEBUG | 121 #ifndef NDEBUG |
| 122 // There should be no implicit breaks assumed at this point. | 122 // There should be no implicit breaks assumed at this point. |
| 123 for (unsigned i = 0; i < forcedBreaksCount(); i++) | 123 for (unsigned i = 0; i < m_contentRuns.size(); i++) |
| 124 ASSERT(!m_contentRuns[i].assumedImplicitBreaks()); | 124 ASSERT(!m_contentRuns[i].assumedImplicitBreaks()); |
| 125 #endif // NDEBUG | 125 #endif // NDEBUG |
| 126 | 126 |
| 127 // Insert a final content run to encompass all content. This will include ov
erflow if this is | 127 // Insert a final content run to encompass all content. This will include ov
erflow if this is |
| 128 // the last set. | 128 // the last set. |
| 129 addForcedBreak(logicalBottomInFlowThread()); | 129 addContentRun(logicalBottomInFlowThread()); |
| 130 unsigned breakCount = forcedBreaksCount(); | 130 unsigned columnCount = m_contentRuns.size(); |
| 131 | 131 |
| 132 // If there is room for more breaks (to reach the used value of column-count
), imagine that we | 132 // If there is room for more breaks (to reach the used value of column-count
), imagine that we |
| 133 // insert implicit breaks at suitable locations. At any given time, the cont
ent run with the | 133 // insert implicit breaks at suitable locations. At any given time, the cont
ent run with the |
| 134 // currently tallest columns will get another implicit break "inserted", whi
ch will increase its | 134 // currently tallest columns will get another implicit break "inserted", whi
ch will increase its |
| 135 // column count by one and shrink its columns' height. Repeat until we have
the desired total | 135 // column count by one and shrink its columns' height. Repeat until we have
the desired total |
| 136 // number of breaks. The largest column height among the runs will then be t
he initial column | 136 // number of breaks. The largest column height among the runs will then be t
he initial column |
| 137 // height for the balancer to use. | 137 // height for the balancer to use. |
| 138 while (breakCount < m_computedColumnCount) { | 138 while (columnCount < m_computedColumnCount) { |
| 139 unsigned index = findRunWithTallestColumns(); | 139 unsigned index = findRunWithTallestColumns(); |
| 140 m_contentRuns[index].assumeAnotherImplicitBreak(); | 140 m_contentRuns[index].assumeAnotherImplicitBreak(); |
| 141 breakCount++; | 141 columnCount++; |
| 142 } | 142 } |
| 143 } | 143 } |
| 144 | 144 |
| 145 LayoutUnit RenderMultiColumnSet::calculateColumnHeight(bool initial) const | 145 LayoutUnit RenderMultiColumnSet::calculateColumnHeight(bool initial) const |
| 146 { | 146 { |
| 147 if (initial) { | 147 if (initial) { |
| 148 // Start with the lowest imaginable column height. | 148 // Start with the lowest imaginable column height. We use the tallest co
ntent run (after |
| 149 // having "inserted" implicit breaks), and find its start offset (by loo
king at the previous |
| 150 // run's end offset, or, if there's no previous run, the set's start off
set in the flow |
| 151 // thread). |
| 149 unsigned index = findRunWithTallestColumns(); | 152 unsigned index = findRunWithTallestColumns(); |
| 150 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffse
t() : LayoutUnit(); | 153 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffse
t() : logicalTopInFlowThread(); |
| 151 return std::max<LayoutUnit>(m_contentRuns[index].columnLogicalHeight(sta
rtOffset), m_minimumColumnHeight); | 154 return std::max<LayoutUnit>(m_contentRuns[index].columnLogicalHeight(sta
rtOffset), m_minimumColumnHeight); |
| 152 } | 155 } |
| 153 | 156 |
| 154 if (columnCount() <= computedColumnCount()) { | 157 if (columnCount() <= computedColumnCount()) { |
| 155 // With the current column height, the content fits without creating ove
rflowing columns. We're done. | 158 // With the current column height, the content fits without creating ove
rflowing columns. We're done. |
| 156 return m_computedColumnHeight; | 159 return m_computedColumnHeight; |
| 157 } | 160 } |
| 158 | 161 |
| 159 if (forcedBreaksCount() >= computedColumnCount()) { | 162 if (m_contentRuns.size() >= computedColumnCount()) { |
| 160 // Too many forced breaks to allow any implicit breaks. Initial balancin
g should already | 163 // Too many forced breaks to allow any implicit breaks. Initial balancin
g should already |
| 161 // have set a good height. There's nothing more we should do. | 164 // have set a good height. There's nothing more we should do. |
| 162 return m_computedColumnHeight; | 165 return m_computedColumnHeight; |
| 163 } | 166 } |
| 164 | 167 |
| 165 // If the initial guessed column height wasn't enough, stretch it now. Stret
ch by the lowest | 168 // If the initial guessed column height wasn't enough, stretch it now. Stret
ch by the lowest |
| 166 // amount of space shortage found during layout. | 169 // amount of space shortage found during layout. |
| 167 | 170 |
| 168 ASSERT(m_minSpaceShortage > 0); // We should never _shrink_ the height! | 171 ASSERT(m_minSpaceShortage > 0); // We should never _shrink_ the height! |
| 169 ASSERT(m_minSpaceShortage != RenderFlowThread::maxLogicalHeight()); // If th
is happens, we probably have a bug. | 172 ASSERT(m_minSpaceShortage != RenderFlowThread::maxLogicalHeight()); // If th
is happens, we probably have a bug. |
| 170 if (m_minSpaceShortage == RenderFlowThread::maxLogicalHeight()) | 173 if (m_minSpaceShortage == RenderFlowThread::maxLogicalHeight()) |
| 171 return m_computedColumnHeight; // So bail out rather than looping infini
tely. | 174 return m_computedColumnHeight; // So bail out rather than looping infini
tely. |
| 172 | 175 |
| 173 return m_computedColumnHeight + m_minSpaceShortage; | 176 return m_computedColumnHeight + m_minSpaceShortage; |
| 174 } | 177 } |
| 175 | 178 |
| 176 void RenderMultiColumnSet::clearForcedBreaks() | 179 void RenderMultiColumnSet::addContentRun(LayoutUnit endOffsetFromFirstPage) |
| 177 { | |
| 178 m_contentRuns.clear(); | |
| 179 } | |
| 180 | |
| 181 void RenderMultiColumnSet::addForcedBreak(LayoutUnit offsetFromFirstPage) | |
| 182 { | 180 { |
| 183 if (!multiColumnFlowThread()->requiresBalancing()) | 181 if (!multiColumnFlowThread()->requiresBalancing()) |
| 184 return; | 182 return; |
| 185 if (!m_contentRuns.isEmpty() && offsetFromFirstPage <= m_contentRuns.last().
breakOffset()) | 183 if (!m_contentRuns.isEmpty() && endOffsetFromFirstPage <= m_contentRuns.last
().breakOffset()) |
| 186 return; | 184 return; |
| 187 // Append another item as long as we haven't exceeded used column count. Wha
t ends up in the | 185 // Append another item as long as we haven't exceeded used column count. Wha
t ends up in the |
| 188 // overflow area shouldn't affect column balancing. | 186 // overflow area shouldn't affect column balancing. |
| 189 if (m_contentRuns.size() < m_computedColumnCount) | 187 if (m_contentRuns.size() < m_computedColumnCount) |
| 190 m_contentRuns.append(ContentRun(offsetFromFirstPage)); | 188 m_contentRuns.append(ContentRun(endOffsetFromFirstPage)); |
| 191 } | 189 } |
| 192 | 190 |
| 193 bool RenderMultiColumnSet::recalculateColumnHeight(bool initial) | 191 bool RenderMultiColumnSet::recalculateColumnHeight(bool initial) |
| 194 { | 192 { |
| 195 ASSERT(multiColumnFlowThread()->requiresBalancing()); | 193 ASSERT(multiColumnFlowThread()->requiresBalancing()); |
| 196 | 194 |
| 197 LayoutUnit oldColumnHeight = m_computedColumnHeight; | 195 LayoutUnit oldColumnHeight = m_computedColumnHeight; |
| 198 if (initial) | 196 if (initial) { |
| 197 // Post-process the content runs and find out where the implicit breaks
will occur. |
| 199 distributeImplicitBreaks(); | 198 distributeImplicitBreaks(); |
| 199 } |
| 200 LayoutUnit newColumnHeight = calculateColumnHeight(initial); | 200 LayoutUnit newColumnHeight = calculateColumnHeight(initial); |
| 201 setAndConstrainColumnHeight(newColumnHeight); | 201 setAndConstrainColumnHeight(newColumnHeight); |
| 202 | 202 |
| 203 // After having calculated an initial column height, the multicol container
typically needs at | 203 // After having calculated an initial column height, the multicol container
typically needs at |
| 204 // least one more layout pass with a new column height, but if a height was
specified, we only | 204 // least one more layout pass with a new column height, but if a height was
specified, we only |
| 205 // need to do this if we think that we need less space than specified. Conve
rsely, if we | 205 // need to do this if we think that we need less space than specified. Conve
rsely, if we |
| 206 // determined that the columns need to be as tall as the specified height of
the container, we | 206 // determined that the columns need to be as tall as the specified height of
the container, we |
| 207 // have already laid it out correctly, and there's no need for another pass. | 207 // have already laid it out correctly, and there's no need for another pass. |
| 208 | 208 |
| 209 if (m_computedColumnHeight == oldColumnHeight) | 209 if (m_computedColumnHeight == oldColumnHeight) |
| 210 return false; // No change. We're done. | 210 return false; // No change. We're done. |
| 211 | 211 |
| 212 m_minSpaceShortage = RenderFlowThread::maxLogicalHeight(); | 212 m_minSpaceShortage = RenderFlowThread::maxLogicalHeight(); |
| 213 clearForcedBreaks(); | 213 m_contentRuns.clear(); |
| 214 return true; // Need another pass. | 214 return true; // Need another pass. |
| 215 } | 215 } |
| 216 | 216 |
| 217 void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage) | 217 void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage) |
| 218 { | 218 { |
| 219 if (spaceShortage >= m_minSpaceShortage) | 219 if (spaceShortage >= m_minSpaceShortage) |
| 220 return; | 220 return; |
| 221 | 221 |
| 222 // The space shortage is what we use as our stretch amount. We need a positi
ve number here in | 222 // The space shortage is what we use as our stretch amount. We need a positi
ve number here in |
| 223 // order to get anywhere. | 223 // order to get anywhere. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHe
ight(multicolStyle->logicalMaxHeight(), -1); | 272 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHe
ight(multicolStyle->logicalMaxHeight(), -1); |
| 273 if (logicalMaxHeight != -1 && m_maxColumnHeight > logicalMaxHeight) | 273 if (logicalMaxHeight != -1 && m_maxColumnHeight > logicalMaxHeight) |
| 274 m_maxColumnHeight = logicalMaxHeight; | 274 m_maxColumnHeight = logicalMaxHeight; |
| 275 } | 275 } |
| 276 m_maxColumnHeight = heightAdjustedForSetOffset(m_maxColumnHeight); | 276 m_maxColumnHeight = heightAdjustedForSetOffset(m_maxColumnHeight); |
| 277 m_computedColumnHeight = 0; // Restart balancing. | 277 m_computedColumnHeight = 0; // Restart balancing. |
| 278 } else { | 278 } else { |
| 279 setAndConstrainColumnHeight(heightAdjustedForSetOffset(multiColumnFlowTh
read()->columnHeightAvailable())); | 279 setAndConstrainColumnHeight(heightAdjustedForSetOffset(multiColumnFlowTh
read()->columnHeightAvailable())); |
| 280 } | 280 } |
| 281 | 281 |
| 282 clearForcedBreaks(); | 282 m_contentRuns.clear(); |
| 283 | 283 |
| 284 // Nuke previously stored minimum column height. Contents may have changed f
or all we know. | 284 // Nuke previously stored minimum column height. Contents may have changed f
or all we know. |
| 285 m_minimumColumnHeight = 0; | 285 m_minimumColumnHeight = 0; |
| 286 } | 286 } |
| 287 | 287 |
| 288 void RenderMultiColumnSet::expandToEncompassFlowThreadContentsIfNeeded() | 288 void RenderMultiColumnSet::expandToEncompassFlowThreadContentsIfNeeded() |
| 289 { | 289 { |
| 290 ASSERT(multiColumnFlowThread()->lastMultiColumnSet() == this); | 290 ASSERT(multiColumnFlowThread()->lastMultiColumnSet() == this); |
| 291 LayoutRect rect(flowThreadPortionRect()); | 291 LayoutRect rect(flowThreadPortionRect()); |
| 292 | 292 |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 620 fragments.append(fragment); | 620 fragments.append(fragment); |
| 621 } | 621 } |
| 622 } | 622 } |
| 623 | 623 |
| 624 const char* RenderMultiColumnSet::renderName() const | 624 const char* RenderMultiColumnSet::renderName() const |
| 625 { | 625 { |
| 626 return "RenderMultiColumnSet"; | 626 return "RenderMultiColumnSet"; |
| 627 } | 627 } |
| 628 | 628 |
| 629 } | 629 } |
| OLD | NEW |