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 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 flipForWritingMode(flowThreadPoint); | 132 flipForWritingMode(flowThreadPoint); |
133 LayoutUnit blockOffset = isHorizontalWritingMode() ? flowThreadPoint.y() : f
lowThreadPoint.x(); | 133 LayoutUnit blockOffset = isHorizontalWritingMode() ? flowThreadPoint.y() : f
lowThreadPoint.x(); |
134 RenderRegion* renderRegion = regionAtBlockOffset(blockOffset); | 134 RenderRegion* renderRegion = regionAtBlockOffset(blockOffset); |
135 if (!renderRegion) | 135 if (!renderRegion) |
136 return LayoutSize(0, 0); | 136 return LayoutSize(0, 0); |
137 return toRenderMultiColumnSet(renderRegion)->flowThreadTranslationAtOffset(b
lockOffset); | 137 return toRenderMultiColumnSet(renderRegion)->flowThreadTranslationAtOffset(b
lockOffset); |
138 } | 138 } |
139 | 139 |
140 void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLa
youtScope& layoutScope) | 140 void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLa
youtScope& layoutScope) |
141 { | 141 { |
142 // Update the dimensions of our regions before we lay out the flow thread. | 142 if (relayoutChildren) |
143 // FIXME: Eventually this is going to get way more complicated, and we will
be destroying regions | 143 layoutScope.setChildNeedsLayout(this); |
144 // instead of trying to keep them around. | 144 |
145 bool shouldInvalidateRegions = false; | 145 if (!needsLayout()) { |
| 146 // Just before the multicol container (our parent RenderBlockFlow) finis
hes laying out, it |
| 147 // will call recalculateColumnHeights() on us unconditionally, but we on
ly want that method |
| 148 // to do any work if we actually laid out the flow thread. Otherwise, th
e balancing |
| 149 // machinery would kick in needlessly, and trigger additional layout pas
ses. Furthermore, we |
| 150 // actually depend on a proper flowthread layout pass in order to do bal
ancing, since it's |
| 151 // flowthread layout that sets up content runs. |
| 152 m_needsColumnHeightsRecalculation = false; |
| 153 return; |
| 154 } |
| 155 |
146 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col
umnSet = columnSet->nextSiblingMultiColumnSet()) { | 156 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col
umnSet = columnSet->nextSiblingMultiColumnSet()) { |
147 if (relayoutChildren || columnSet->needsLayout()) { | 157 if (!m_inBalancingPass) { |
148 if (!m_inBalancingPass) | 158 // This is the initial layout pass. We need to reset the column heig
ht, because contents |
149 columnSet->prepareForLayout(); | 159 // typically have changed. |
150 shouldInvalidateRegions = true; | 160 columnSet->resetColumnHeight(); |
| 161 |
| 162 columnSet->setComputedColumnWidthAndCount(columnWidth(), columnCount
()); |
151 } | 163 } |
152 } | 164 } |
153 | 165 |
154 if (shouldInvalidateRegions) | 166 invalidateRegions(); |
155 invalidateRegions(); | 167 m_needsColumnHeightsRecalculation = requiresBalancing(); |
156 | 168 layout(); |
157 if (relayoutChildren) | |
158 layoutScope.setChildNeedsLayout(this); | |
159 | |
160 if (requiresBalancing()) { | |
161 // At the end of multicol layout, relayoutForPagination() is called unco
nditionally, but if | |
162 // no children are to be laid out (e.g. fixed width with layout already
being up-to-date), | |
163 // we want to prevent it from doing any work, so that the column balanci
ng machinery doesn't | |
164 // kick in and trigger additional unnecessary layout passes. Actually, i
t's not just a good | |
165 // idea in general to not waste time on balancing content that hasn't be
en re-laid out; we | |
166 // are actually required to guarantee this. The calculation of implicit
breaks needs to be | |
167 // preceded by a proper layout pass, since it's layout that sets up cont
ent runs, and the | |
168 // runs get deleted right after every pass. | |
169 m_needsColumnHeightsRecalculation = shouldInvalidateRegions || needsLayo
ut(); | |
170 } | |
171 | |
172 layoutIfNeeded(); | |
173 } | 169 } |
174 | 170 |
175 bool RenderMultiColumnFlowThread::computeColumnCountAndWidth() | 171 bool RenderMultiColumnFlowThread::computeColumnCountAndWidth() |
176 { | 172 { |
177 RenderBlock* columnBlock = multiColumnBlockFlow(); | 173 RenderBlock* columnBlock = multiColumnBlockFlow(); |
178 LayoutUnit oldColumnWidth = m_columnWidth; | 174 LayoutUnit oldColumnWidth = m_columnWidth; |
179 | 175 |
180 // Calculate our column width and column count. | 176 // Calculate our column width and column count. |
181 m_columnCount = 1; | 177 m_columnCount = 1; |
182 m_columnWidth = columnBlock->contentLogicalWidth(); | 178 m_columnWidth = columnBlock->contentLogicalWidth(); |
(...skipping 15 matching lines...) Expand all Loading... |
198 } else { | 194 } else { |
199 m_columnCount = std::max<LayoutUnit>(std::min<LayoutUnit>(colCount, (ava
ilWidth + colGap) / (colWidth + colGap)), 1); | 195 m_columnCount = std::max<LayoutUnit>(std::min<LayoutUnit>(colCount, (ava
ilWidth + colGap) / (colWidth + colGap)), 1); |
200 m_columnWidth = ((availWidth + colGap) / m_columnCount) - colGap; | 196 m_columnWidth = ((availWidth + colGap) / m_columnCount) - colGap; |
201 } | 197 } |
202 | 198 |
203 return m_columnWidth != oldColumnWidth; | 199 return m_columnWidth != oldColumnWidth; |
204 } | 200 } |
205 | 201 |
206 bool RenderMultiColumnFlowThread::recalculateColumnHeights() | 202 bool RenderMultiColumnFlowThread::recalculateColumnHeights() |
207 { | 203 { |
| 204 // All column sets that needed layout have now been laid out, so we can fina
lly validate them. |
| 205 validateRegions(); |
| 206 |
208 if (!m_needsColumnHeightsRecalculation) | 207 if (!m_needsColumnHeightsRecalculation) |
209 return false; | 208 return false; |
210 | 209 |
211 // Column heights may change here because of balancing. We may have to do mu
ltiple layout | 210 // Column heights may change here because of balancing. We may have to do mu
ltiple layout |
212 // passes, depending on how the contents is fitted to the changed column hei
ghts. In most | 211 // passes, depending on how the contents is fitted to the changed column hei
ghts. In most |
213 // cases, laying out again twice or even just once will suffice. Sometimes w
e need more | 212 // cases, laying out again twice or even just once will suffice. Sometimes w
e need more |
214 // passes than that, though, but the number of retries should not exceed the
number of | 213 // passes than that, though, but the number of retries should not exceed the
number of |
215 // columns, unless we have a bug. | 214 // columns, unless we have a bug. |
216 bool needsRelayout = false; | 215 bool needsRelayout = false; |
217 for (RenderMultiColumnSet* multicolSet = firstMultiColumnSet(); multicolSet;
multicolSet = multicolSet->nextSiblingMultiColumnSet()) { | 216 for (RenderMultiColumnSet* multicolSet = firstMultiColumnSet(); multicolSet;
multicolSet = multicolSet->nextSiblingMultiColumnSet()) { |
218 if (multicolSet->recalculateColumnHeight(!m_inBalancingPass)) { | 217 needsRelayout |= multicolSet->recalculateColumnHeight(m_inBalancingPass
? RenderMultiColumnSet::StretchBySpaceShortage : RenderMultiColumnSet::GuessFrom
FlowThreadPortion); |
| 218 if (needsRelayout) { |
| 219 // Once a column set gets a new column height, that column set and a
ll successive column |
| 220 // sets need to be laid out over again, since their logical top will
be affected by |
| 221 // this, and therefore their column heights may change as well, at l
east if the multicol |
| 222 // height is constrained. |
219 multicolSet->setChildNeedsLayout(MarkOnlyThis); | 223 multicolSet->setChildNeedsLayout(MarkOnlyThis); |
220 needsRelayout = true; | |
221 } | 224 } |
222 } | 225 } |
223 | 226 |
224 if (needsRelayout) | 227 if (needsRelayout) |
225 setChildNeedsLayout(MarkOnlyThis); | 228 setChildNeedsLayout(MarkOnlyThis); |
226 | 229 |
227 m_inBalancingPass = needsRelayout; | 230 m_inBalancingPass = needsRelayout; |
228 return needsRelayout; | 231 return needsRelayout; |
229 } | 232 } |
230 | 233 |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 } | 316 } |
314 | 317 |
315 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const | 318 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const |
316 { | 319 { |
317 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) | 320 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) |
318 return columnSet->computedColumnHeight(); | 321 return columnSet->computedColumnHeight(); |
319 return false; | 322 return false; |
320 } | 323 } |
321 | 324 |
322 } | 325 } |
OLD | NEW |