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 |