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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
45 } | 45 } |
46 | 46 |
47 RenderMultiColumnFlowThread* RenderMultiColumnFlowThread::createAnonymous(Docume nt& document, RenderStyle* parentStyle) | 47 RenderMultiColumnFlowThread* RenderMultiColumnFlowThread::createAnonymous(Docume nt& document, RenderStyle* parentStyle) |
48 { | 48 { |
49 RenderMultiColumnFlowThread* renderer = new RenderMultiColumnFlowThread(); | 49 RenderMultiColumnFlowThread* renderer = new RenderMultiColumnFlowThread(); |
50 renderer->setDocumentForAnonymous(&document); | 50 renderer->setDocumentForAnonymous(&document); |
51 renderer->setStyle(RenderStyle::createAnonymousStyleWithDisplay(parentStyle, BLOCK)); | 51 renderer->setStyle(RenderStyle::createAnonymousStyleWithDisplay(parentStyle, BLOCK)); |
52 return renderer; | 52 return renderer; |
53 } | 53 } |
54 | 54 |
55 RenderMultiColumnSet* RenderMultiColumnFlowThread::firstMultiColumnSet() const | |
56 { | |
57 for (RenderObject* sibling = nextSibling(); sibling; sibling = sibling->next Sibling()) { | |
58 if (sibling->isRenderMultiColumnSet()) | |
59 return toRenderMultiColumnSet(sibling); | |
60 } | |
61 return 0; | |
62 } | |
63 | |
64 RenderMultiColumnSet* RenderMultiColumnFlowThread::lastMultiColumnSet() const | |
65 { | |
66 for (RenderObject* sibling = multiColumnBlockFlow()->lastChild(); sibling; s ibling = sibling->previousSibling()) { | |
67 if (sibling->isRenderMultiColumnSet()) | |
68 return toRenderMultiColumnSet(sibling); | |
69 } | |
70 return 0; | |
71 } | |
72 | |
73 void RenderMultiColumnFlowThread::addChild(RenderObject* newChild, RenderObject* beforeChild) | |
74 { | |
75 RenderBlockFlow::addChild(newChild, beforeChild); | |
76 if (firstMultiColumnSet()) | |
77 return; | |
78 | |
79 // For now we only create one column set. It's created as soon as the multic ol container gets | |
80 // any content at all. | |
81 RenderMultiColumnSet* newSet = RenderMultiColumnSet::createAnonymous(this, m ultiColumnBlockFlow()->style()); | |
82 multiColumnBlockFlow()->RenderBlock::addChild(newSet); | |
ojan
2014/04/24 21:38:43
Why do we need the RenderBlock version? Can the mu
mstensho (USE GERRIT)
2014/04/24 22:22:22
Yes, multiColumnBlockFlow() is the one that has a
| |
83 invalidateRegions(); | |
84 } | |
85 | |
55 void RenderMultiColumnFlowThread::populate() | 86 void RenderMultiColumnFlowThread::populate() |
56 { | 87 { |
57 RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); | 88 RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); |
58 ASSERT(!nextSibling()); | 89 ASSERT(!nextSibling()); |
59 // Reparent children preceding the flow thread into the flow thread. It's mu lticol content | 90 // Reparent children preceding the flow thread into the flow thread. It's mu lticol content |
60 // now. At this point there's obviously nothing after the flow thread, but r enderers (column | 91 // now. At this point there's obviously nothing after the flow thread, but r enderers (column |
61 // sets and spanners) will be inserted there as we insert elements into the flow thread. | 92 // sets and spanners) will be inserted there as we insert elements into the flow thread. |
62 multicolContainer->moveChildrenTo(this, multicolContainer->firstChild(), thi s, true); | 93 multicolContainer->moveChildrenTo(this, multicolContainer->firstChild(), thi s, true); |
63 } | 94 } |
64 | 95 |
65 void RenderMultiColumnFlowThread::evacuateAndDestroy() | 96 void RenderMultiColumnFlowThread::evacuateAndDestroy() |
66 { | 97 { |
67 RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); | 98 RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); |
68 | 99 |
69 // Remove all sets. | 100 // Remove all sets. |
70 for (RenderBox* sibling = nextSiblingBox(); sibling;) { | 101 while (RenderMultiColumnSet* columnSet = firstMultiColumnSet()) |
ojan
2014/04/24 21:38:43
How do we have multiple sets? It looks like addChi
mstensho (USE GERRIT)
2014/04/24 22:22:22
For now, only one set. In the (near) future, we ca
ojan
2014/04/24 22:46:59
It's just a bit weird to me to have a while loop t
| |
71 RenderBox* nextSibling = sibling->nextSiblingBox(); | 102 columnSet->destroy(); |
72 if (sibling->isRenderMultiColumnSet()) | |
73 sibling->destroy(); | |
74 sibling = nextSibling; | |
75 } | |
76 | 103 |
77 ASSERT(!previousSibling()); | 104 ASSERT(!previousSibling()); |
78 ASSERT(!nextSibling()); | 105 ASSERT(!nextSibling()); |
79 | 106 |
80 // Finally we can promote all flow thread's children. Before we move them to the flow thread's | 107 // Finally we can promote all flow thread's children. Before we move them to the flow thread's |
81 // container, we need to unregister the flow thread, so that they aren't jus t re-added again to | 108 // container, we need to unregister the flow thread, so that they aren't jus t re-added again to |
82 // the flow thread that we're trying to empty. | 109 // the flow thread that we're trying to empty. |
83 multicolContainer->resetMultiColumnFlowThread(); | 110 multicolContainer->resetMultiColumnFlowThread(); |
84 moveAllChildrenTo(multicolContainer, true); | 111 moveAllChildrenTo(multicolContainer, true); |
85 | 112 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
160 { | 187 { |
161 if (!m_needsRebalancing) | 188 if (!m_needsRebalancing) |
162 return false; | 189 return false; |
163 | 190 |
164 // Column heights may change here because of balancing. We may have to do mu ltiple layout | 191 // Column heights may change here because of balancing. We may have to do mu ltiple layout |
165 // passes, depending on how the contents is fitted to the changed column hei ghts. In most | 192 // passes, depending on how the contents is fitted to the changed column hei ghts. In most |
166 // cases, laying out again twice or even just once will suffice. Sometimes w e need more | 193 // cases, laying out again twice or even just once will suffice. Sometimes w e need more |
167 // passes than that, though, but the number of retries should not exceed the number of | 194 // passes than that, though, but the number of retries should not exceed the number of |
168 // columns, unless we have a bug. | 195 // columns, unless we have a bug. |
169 bool needsRelayout = false; | 196 bool needsRelayout = false; |
170 for (RenderBox* childBox = multiColumnBlockFlow()->firstChildBox(); childBox ; childBox = childBox->nextSiblingBox()) { | 197 for (RenderMultiColumnSet* multicolSet = firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) { |
171 if (childBox != this && childBox->isRenderMultiColumnSet()) { | 198 if (multicolSet->recalculateBalancedHeight(!m_inBalancingPass)) { |
172 RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(childBox) ; | 199 multicolSet->setChildNeedsLayout(MarkOnlyThis); |
173 if (multicolSet->recalculateBalancedHeight(!m_inBalancingPass)) { | 200 needsRelayout = true; |
174 multicolSet->setChildNeedsLayout(MarkOnlyThis); | |
175 needsRelayout = true; | |
176 } | |
177 } | 201 } |
178 } | 202 } |
179 | 203 |
180 if (needsRelayout) | 204 if (needsRelayout) |
181 setChildNeedsLayout(MarkOnlyThis); | 205 setChildNeedsLayout(MarkOnlyThis); |
182 | 206 |
183 m_inBalancingPass = needsRelayout; | 207 m_inBalancingPass = needsRelayout; |
184 return needsRelayout; | 208 return needsRelayout; |
185 } | 209 } |
186 | 210 |
187 const char* RenderMultiColumnFlowThread::renderName() const | 211 const char* RenderMultiColumnFlowThread::renderName() const |
188 { | 212 { |
189 return "RenderMultiColumnFlowThread"; | 213 return "RenderMultiColumnFlowThread"; |
190 } | 214 } |
191 | 215 |
216 void RenderMultiColumnFlowThread::addRegionToThread(RenderRegion* renderRegion) | |
217 { | |
218 RenderMultiColumnSet* columnSet = toRenderMultiColumnSet(renderRegion); | |
219 if (RenderMultiColumnSet* nextSet = columnSet->nextSiblingMultiColumnSet()) { | |
220 RenderRegionList::iterator it = m_regionList.find(nextSet); | |
221 ASSERT(it != m_regionList.end()); | |
222 m_regionList.insertBefore(it, columnSet); | |
223 } else { | |
224 m_regionList.add(columnSet); | |
225 } | |
226 renderRegion->setIsValid(true); | |
227 } | |
228 | |
229 void RenderMultiColumnFlowThread::willBeRemovedFromTree() | |
230 { | |
231 // Detach all column sets from the flow thread. Cannot destroy them at this point, since they | |
232 // are siblings of this object, and there may be pointers to this object's s ibling somewhere | |
233 // further up on the call stack. | |
234 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col umnSet = columnSet->nextSiblingMultiColumnSet()) | |
235 columnSet->detachRegion(); | |
236 multiColumnBlockFlow()->resetMultiColumnFlowThread(); | |
237 RenderFlowThread::willBeRemovedFromTree(); | |
238 } | |
239 | |
192 void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const | 240 void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const |
193 { | 241 { |
194 // We simply remain at our intrinsic height. | 242 // We simply remain at our intrinsic height. |
195 computedValues.m_extent = logicalHeight; | 243 computedValues.m_extent = logicalHeight; |
196 computedValues.m_position = logicalTop; | 244 computedValues.m_position = logicalTop; |
197 } | 245 } |
198 | 246 |
199 LayoutUnit RenderMultiColumnFlowThread::initialLogicalWidth() const | 247 LayoutUnit RenderMultiColumnFlowThread::initialLogicalWidth() const |
200 { | 248 { |
201 return columnWidth(); | 249 return columnWidth(); |
202 } | 250 } |
203 | 251 |
204 void RenderMultiColumnFlowThread::autoGenerateRegionsToBlockOffset(LayoutUnit /* offset*/) | |
205 { | |
206 // This function ensures we have the correct column set information at all t imes. | |
207 // For a simple multi-column layout in continuous media, only one column set child is required. | |
208 // Once a column is nested inside an enclosing pagination context, the numbe r of column sets | |
209 // required becomes 2n-1, where n is the total number of nested pagination c ontexts. For example: | |
210 // | |
211 // Column layout with no enclosing pagination model = 2 * 1 - 1 = 1 column s et. | |
212 // Columns inside pages = 2 * 2 - 1 = 3 column sets (bottom of first page, a ll the subsequent pages, then the last page). | |
213 // Columns inside columns inside pages = 2 * 3 - 1 = 5 column sets. | |
214 // | |
215 // In addition, column spans will force a column set to "split" into before/ after sets around the spanning element. | |
216 // | |
217 // Finally, we will need to deal with columns inside regions. If regions hav e variable widths, then there will need | |
218 // to be unique column sets created inside any region whose width is differe nt from its surrounding regions. This is | |
219 // actually pretty similar to the spanning case, in that we break up the col umn sets whenever the width varies. | |
220 // | |
221 // FIXME: For now just make one column set. This matches the old multi-colum n code. | |
222 // Right now our goal is just feature parity with the old multi-column code so that we can switch over to the | |
223 // new code as soon as possible. | |
224 RenderMultiColumnSet* firstSet = toRenderMultiColumnSet(firstRegion()); | |
225 if (firstSet) | |
226 return; | |
227 | |
228 invalidateRegions(); | |
229 | |
230 RenderBlockFlow* parentBlock = multiColumnBlockFlow(); | |
231 firstSet = RenderMultiColumnSet::createAnonymous(this); | |
232 firstSet->setStyle(RenderStyle::createAnonymousStyleWithDisplay(parentBlock- >style(), BLOCK)); | |
233 parentBlock->RenderBlock::addChild(firstSet); | |
234 | |
235 // Even though we aren't placed yet, we can go ahead and set up our size. At this point we're | |
236 // typically in the middle of laying out the thread, attempting to paginate, and we need to do | |
237 // some rudimentary "layout" of the set now, so that pagination will work. | |
238 firstSet->prepareForLayout(); | |
239 | |
240 validateRegions(); | |
241 } | |
242 | |
243 void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spa ceShortage) | 252 void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spa ceShortage) |
244 { | 253 { |
245 if (RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(regionAtBlock Offset(offset))) | 254 if (RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(regionAtBlock Offset(offset))) |
246 multicolSet->recordSpaceShortage(spaceShortage); | 255 multicolSet->recordSpaceShortage(spaceShortage); |
247 } | 256 } |
248 | 257 |
249 void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay outUnit minHeight) | 258 void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay outUnit minHeight) |
250 { | 259 { |
251 if (RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(regionAtBlock Offset(offset))) | 260 if (RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(regionAtBlock Offset(offset))) |
252 multicolSet->updateMinimumColumnHeight(minHeight); | 261 multicolSet->updateMinimumColumnHeight(minHeight); |
253 } | 262 } |
254 | 263 |
264 RenderRegion* RenderMultiColumnFlowThread::regionAtBlockOffset(LayoutUnit /*offs et*/) | |
265 { | |
266 // For now there's only one column set, so this is easy: | |
267 return firstMultiColumnSet(); | |
268 } | |
269 | |
255 bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render Object* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment) | 270 bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render Object* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment) |
256 { | 271 { |
257 if (RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(regionAtBlock Offset(offset))) { | 272 if (RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(regionAtBlock Offset(offset))) { |
258 multicolSet->addForcedBreak(offset); | 273 multicolSet->addForcedBreak(offset); |
259 if (offsetBreakAdjustment) | 274 if (offsetBreakAdjustment) |
260 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe mainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit(); | 275 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe mainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit(); |
261 return true; | 276 return true; |
262 } | 277 } |
263 return false; | 278 return false; |
264 } | 279 } |
265 | 280 |
266 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const | 281 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const |
267 { | 282 { |
268 for (RenderBox* renderer = parentBox()->lastChildBox(); renderer; renderer = renderer->previousSiblingBox()) { | 283 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) |
269 if (renderer->isRenderMultiColumnSet()) | 284 return columnSet->computedColumnHeight(); |
270 return toRenderMultiColumnSet(renderer)->computedColumnHeight(); | 285 return false; |
271 } | |
272 // A column set hasn't been created yet. Height may already be known if colu mn-fill is 'auto', though. | |
273 return !requiresBalancing(); | |
274 } | 286 } |
275 | 287 |
276 } | 288 } |
OLD | NEW |