Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: Source/core/rendering/RenderMultiColumnFlowThread.cpp

Issue 584033002: [New Multicolumn] Add support for column-span:all (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * 12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS IN..0TERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 20 * PROFITS; OR BUSINESS IN..0TERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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/RenderMultiColumnFlowThread.h" 27 #include "core/rendering/RenderMultiColumnFlowThread.h"
28 28
29 #include "core/rendering/RenderMultiColumnSet.h" 29 #include "core/rendering/RenderMultiColumnSet.h"
30 #include "core/rendering/RenderMultiColumnSpannerSet.h"
30 31
31 namespace blink { 32 namespace blink {
32 33
33 RenderMultiColumnFlowThread::RenderMultiColumnFlowThread() 34 RenderMultiColumnFlowThread::RenderMultiColumnFlowThread()
34 : m_columnCount(1) 35 : m_lastSetWorkedOn(0)
36 , m_columnCount(1)
35 , m_columnHeightAvailable(0) 37 , m_columnHeightAvailable(0)
36 , m_inBalancingPass(false) 38 , m_inBalancingPass(false)
37 , m_needsColumnHeightsRecalculation(false) 39 , m_needsColumnHeightsRecalculation(false)
38 , m_progressionIsInline(true) 40 , m_progressionIsInline(true)
41 , m_beingEvacuated(false)
39 { 42 {
40 setFlowThreadState(InsideInFlowThread); 43 setFlowThreadState(InsideInFlowThread);
41 } 44 }
42 45
43 RenderMultiColumnFlowThread::~RenderMultiColumnFlowThread() 46 RenderMultiColumnFlowThread::~RenderMultiColumnFlowThread()
44 { 47 {
45 } 48 }
46 49
47 RenderMultiColumnFlowThread* RenderMultiColumnFlowThread::createAnonymous(Docume nt& document, RenderStyle* parentStyle) 50 RenderMultiColumnFlowThread* RenderMultiColumnFlowThread::createAnonymous(Docume nt& document, RenderStyle* parentStyle)
48 { 51 {
(...skipping 14 matching lines...) Expand all
63 66
64 RenderMultiColumnSet* RenderMultiColumnFlowThread::lastMultiColumnSet() const 67 RenderMultiColumnSet* RenderMultiColumnFlowThread::lastMultiColumnSet() const
65 { 68 {
66 for (RenderObject* sibling = multiColumnBlockFlow()->lastChild(); sibling; s ibling = sibling->previousSibling()) { 69 for (RenderObject* sibling = multiColumnBlockFlow()->lastChild(); sibling; s ibling = sibling->previousSibling()) {
67 if (sibling->isRenderMultiColumnSet()) 70 if (sibling->isRenderMultiColumnSet())
68 return toRenderMultiColumnSet(sibling); 71 return toRenderMultiColumnSet(sibling);
69 } 72 }
70 return 0; 73 return 0;
71 } 74 }
72 75
73 void RenderMultiColumnFlowThread::addChild(RenderObject* newChild, RenderObject* beforeChild) 76 RenderMultiColumnSet* RenderMultiColumnFlowThread::findSetRendering(RenderObject * renderer) const
74 { 77 {
75 RenderBlockFlow::addChild(newChild, beforeChild); 78 ASSERT(!containingColumnSpanner(renderer)); // should not be used for spanne rs or content inside them.
76 if (firstMultiColumnSet()) 79 RenderMultiColumnSet* multicolSet = firstMultiColumnSet();
77 return; 80 if (!multicolSet)
81 return 0;
78 82
79 // For now we only create one column set. It's created as soon as the multic ol container gets 83 if (!multicolSet->nextSiblingMultiColumnSet()) {
80 // any content at all. 84 // There is only one set. This is easy, then: if it's in the flow thread , it's part of the set.
81 RenderMultiColumnSet* newSet = RenderMultiColumnSet::createAnonymous(this, m ultiColumnBlockFlow()->style()); 85 return renderer->isDescendantOf(this) ? multicolSet : 0;
86 }
82 87
83 // Need to skip RenderBlockFlow's implementation of addChild(), or we'd get redirected right 88 // This is SLOW! But luckily very uncommon. You need to dynamically insert a spanner into the
84 // back here. 89 // middle of the tree to trigger this.
85 multiColumnBlockFlow()->RenderBlock::addChild(newSet); 90 for (; multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
91 if (multicolSet->isRenderMultiColumnSpannerSet())
92 continue;
93 RenderObject* startRenderer;
94 if (RenderMultiColumnSet* sibling = multicolSet->previousSiblingMultiCol umnSet()) {
95 // Adjacent sets should not occur. Currently we would have no way of figuring out what each
96 // of them contains then.
97 ASSERT(sibling->isRenderMultiColumnSpannerSet());
98 startRenderer = toRenderMultiColumnSpannerSet(sibling)->rendererInFl owThread()->nextInPreOrderAfterChildren(this);
99 } else {
100 startRenderer = firstChild();
101 }
102 ASSERT(startRenderer);
86 103
87 invalidateRegions(); 104 RenderObject* stopRenderer;
105 if (RenderMultiColumnSet* sibling = multicolSet->nextSiblingMultiColumnS et()) {
106 // Adjacent sets should not occur. Currently we would have no way of figuring out what each
107 // of them contains then.
108 ASSERT(sibling->isRenderMultiColumnSpannerSet());
109 stopRenderer = toRenderMultiColumnSpannerSet(sibling)->rendererInFlo wThread();
110 } else {
111 stopRenderer = 0;
112 }
113
114 for (RenderObject* walker = startRenderer; walker != stopRenderer; walke r = walker->nextInPreOrder(this)) {
115 if (walker == renderer)
116 return multicolSet;
117 }
118 }
119
120 return 0;
121 }
122
123 RenderMultiColumnSpannerSet* RenderMultiColumnFlowThread::containingColumnSpanne r(const RenderObject* descendant) const
124 {
125 ASSERT(descendant->isDescendantOf(this));
126
127 // Before we spend time on searching the ancestry, see if there's a quick wa y to determine
128 // whether there might be any spanners at all.
129 RenderMultiColumnSet* firstSet = firstMultiColumnSet();
130 if (!firstSet || (firstSet == lastMultiColumnSet() && !firstSet->isRenderMul tiColumnSpannerSet()))
131 return 0;
132
133 // We have spanners. See if the renderer in question is one or inside of one then.
134 for (const RenderObject* ancestor = descendant; ancestor && ancestor != this ; ancestor = ancestor->parent()) {
135 if (RenderMultiColumnSpannerSet* spanner = m_spannerMap.get(ancestor))
136 return spanner;
137 }
138 return 0;
88 } 139 }
89 140
90 void RenderMultiColumnFlowThread::populate() 141 void RenderMultiColumnFlowThread::populate()
91 { 142 {
92 RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); 143 RenderBlockFlow* multicolContainer = multiColumnBlockFlow();
93 ASSERT(!nextSibling()); 144 ASSERT(!nextSibling());
94 // Reparent children preceding the flow thread into the flow thread. It's mu lticol content 145 // Reparent children preceding the flow thread into the flow thread. It's mu lticol content
95 // now. At this point there's obviously nothing after the flow thread, but r enderers (column 146 // now. At this point there's obviously nothing after the flow thread, but r enderers (column
96 // sets and spanners) will be inserted there as we insert elements into the flow thread. 147 // sets and spanners) will be inserted there as we insert elements into the flow thread.
97 multicolContainer->moveChildrenTo(this, multicolContainer->firstChild(), thi s, true); 148 multicolContainer->moveChildrenTo(this, multicolContainer->firstChild(), thi s, true);
98 } 149 }
99 150
100 void RenderMultiColumnFlowThread::evacuateAndDestroy() 151 void RenderMultiColumnFlowThread::evacuateAndDestroy()
101 { 152 {
102 RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); 153 RenderBlockFlow* multicolContainer = multiColumnBlockFlow();
154 m_beingEvacuated = true;
103 155
104 // Remove all sets. 156 // Remove all sets.
105 while (RenderMultiColumnSet* columnSet = firstMultiColumnSet()) 157 while (RenderMultiColumnSet* columnSet = firstMultiColumnSet())
106 columnSet->destroy(); 158 columnSet->destroy();
107 159
108 ASSERT(!previousSibling()); 160 ASSERT(!previousSibling());
109 ASSERT(!nextSibling()); 161 ASSERT(!nextSibling());
110 162
111 // Finally we can promote all flow thread's children. Before we move them to the flow thread's 163 // Finally we can promote all flow thread's children. Before we move them to the flow thread's
112 // container, we need to unregister the flow thread, so that they aren't jus t re-added again to 164 // container, we need to unregister the flow thread, so that they aren't jus t re-added again to
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 m_needsColumnHeightsRecalculation = false; 212 m_needsColumnHeightsRecalculation = false;
161 return; 213 return;
162 } 214 }
163 215
164 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col umnSet = columnSet->nextSiblingMultiColumnSet()) { 216 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col umnSet = columnSet->nextSiblingMultiColumnSet()) {
165 if (!m_inBalancingPass) { 217 if (!m_inBalancingPass) {
166 // This is the initial layout pass. We need to reset the column heig ht, because contents 218 // This is the initial layout pass. We need to reset the column heig ht, because contents
167 // typically have changed. 219 // typically have changed.
168 columnSet->resetColumnHeight(); 220 columnSet->resetColumnHeight();
169 } 221 }
222 columnSet->resetFlow();
170 } 223 }
171 224
172 invalidateRegions(); 225 invalidateRegions();
173 m_needsColumnHeightsRecalculation = heightIsAuto(); 226 m_needsColumnHeightsRecalculation = true;
174 layout(); 227 layout();
175 } 228 }
176 229
177 bool RenderMultiColumnFlowThread::recalculateColumnHeights() 230 bool RenderMultiColumnFlowThread::recalculateColumnHeights()
178 { 231 {
179 // All column sets that needed layout have now been laid out, so we can fina lly validate them. 232 // All column sets that needed layout have now been laid out, so we can fina lly validate them.
180 validateRegions(); 233 validateRegions();
181 234
182 if (!m_needsColumnHeightsRecalculation) 235 if (!m_needsColumnHeightsRecalculation)
183 return false; 236 return false;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 width = std::max<LayoutUnit>(0, (availableWidth - ((count - 1) * columnG ap)) / count); 274 width = std::max<LayoutUnit>(0, (availableWidth - ((count - 1) * columnG ap)) / count);
222 } else if (!columnStyle->hasAutoColumnWidth() && columnStyle->hasAutoColumnC ount()) { 275 } else if (!columnStyle->hasAutoColumnWidth() && columnStyle->hasAutoColumnC ount()) {
223 count = std::max<LayoutUnit>(1, (availableWidth + columnGap) / (computed ColumnWidth + columnGap)); 276 count = std::max<LayoutUnit>(1, (availableWidth + columnGap) / (computed ColumnWidth + columnGap));
224 width = ((availableWidth + columnGap) / count) - columnGap; 277 width = ((availableWidth + columnGap) / count) - columnGap;
225 } else { 278 } else {
226 count = std::max<LayoutUnit>(std::min<LayoutUnit>(computedColumnCount, ( availableWidth + columnGap) / (computedColumnWidth + columnGap)), 1); 279 count = std::max<LayoutUnit>(std::min<LayoutUnit>(computedColumnCount, ( availableWidth + columnGap) / (computedColumnWidth + columnGap)), 1);
227 width = ((availableWidth + columnGap) / count) - columnGap; 280 width = ((availableWidth + columnGap) / count) - columnGap;
228 } 281 }
229 } 282 }
230 283
284 bool RenderMultiColumnFlowThread::isDescendantValidColumnSpanner(RenderObject* d escendant) const
285 {
286 // We assume that we're inside the flow thread. This function is not to be c alled otherwise.
287 ASSERT(descendant->isDescendantOf(this));
288
289 // First make sure that the renderer itself has the right properties for bec oming a spanner.
290 if (descendant->style()->columnSpan() != ColumnSpanAll || !descendant->isBox () || descendant->isFloatingOrOutOfFlowPositioned())
291 return false;
292
293 RenderBlock* container = descendant->containingBlock();
294 if (!container->isRenderBlockFlow() || container->childrenInline()) {
295 // Needs to be block-level.
296 return false;
297 }
298
299 // This looks like a spanner, but if we're inside something unbreakable, it' s not to be treated as one.
300 for (RenderBox* ancestor = toRenderBox(descendant)->parentBox(); ancestor; a ncestor = ancestor->parentBox()) {
301 if (ancestor->isRenderFlowThread()) {
302 // Don't allow any intervening non-multicol fragmentation contexts. The spec doesn't say
303 // anything about disallowing this, but it's just going to be too co mplicated to
304 // implement (not to mention specify behavior).
305 return ancestor == this;
306 }
307 if (m_spannerMap.get(ancestor))
308 return false; // Nested spanners not allowed.
309 if (ancestor->isUnsplittableForPagination())
310 return false;
311 }
312 ASSERT_NOT_REACHED();
313 return false;
314 }
315
231 const char* RenderMultiColumnFlowThread::renderName() const 316 const char* RenderMultiColumnFlowThread::renderName() const
232 { 317 {
233 return "RenderMultiColumnFlowThread"; 318 return "RenderMultiColumnFlowThread";
234 } 319 }
235 320
236 void RenderMultiColumnFlowThread::addRegionToThread(RenderMultiColumnSet* column Set) 321 void RenderMultiColumnFlowThread::addRegionToThread(RenderMultiColumnSet* column Set)
237 { 322 {
238 if (RenderMultiColumnSet* nextSet = columnSet->nextSiblingMultiColumnSet()) { 323 if (RenderMultiColumnSet* nextSet = columnSet->nextSiblingMultiColumnSet()) {
239 RenderMultiColumnSetList::iterator it = m_multiColumnSetList.find(nextSe t); 324 RenderMultiColumnSetList::iterator it = m_multiColumnSetList.find(nextSe t);
240 ASSERT(it != m_multiColumnSetList.end()); 325 ASSERT(it != m_multiColumnSetList.end());
241 m_multiColumnSetList.insertBefore(it, columnSet); 326 m_multiColumnSetList.insertBefore(it, columnSet);
242 } else { 327 } else {
243 m_multiColumnSetList.add(columnSet); 328 m_multiColumnSetList.add(columnSet);
244 } 329 }
245 columnSet->setIsValid(true); 330 columnSet->setIsValid(true);
246 } 331 }
247 332
248 void RenderMultiColumnFlowThread::willBeRemovedFromTree() 333 void RenderMultiColumnFlowThread::willBeRemovedFromTree()
249 { 334 {
335 m_spannerMap.clear();
250 // Detach all column sets from the flow thread. Cannot destroy them at this point, since they 336 // Detach all column sets from the flow thread. Cannot destroy them at this point, since they
251 // are siblings of this object, and there may be pointers to this object's s ibling somewhere 337 // are siblings of this object, and there may be pointers to this object's s ibling somewhere
252 // further up on the call stack. 338 // further up on the call stack.
253 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col umnSet = columnSet->nextSiblingMultiColumnSet()) 339 for (RenderMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; col umnSet = columnSet->nextSiblingMultiColumnSet())
254 columnSet->detachRegion(); 340 columnSet->detachRegion();
255 multiColumnBlockFlow()->resetMultiColumnFlowThread(); 341 multiColumnBlockFlow()->resetMultiColumnFlowThread();
256 RenderFlowThread::willBeRemovedFromTree(); 342 RenderFlowThread::willBeRemovedFromTree();
257 } 343 }
258 344
345 bool RenderMultiColumnFlowThread::isColumnSpanner(const RenderObject* descendant ) const
346 {
347 ASSERT(descendant->isDescendantOf(this));
348 return m_spannerMap.get(descendant);
349 }
350
351 bool RenderMultiColumnFlowThread::isInsideColumnSpanner(const RenderObject* desc endant) const
352 {
353 ASSERT(descendant->isDescendantOf(this));
354 return containingColumnSpanner(descendant);
355 }
356
357 LayoutUnit RenderMultiColumnFlowThread::enterColumnSpanner(RenderBox* renderer, LayoutUnit logicalTop)
358 {
359 ASSERT(renderer->isDescendantOf(this));
360 RenderMultiColumnSpannerSet* spannerSet = m_spannerMap.get(renderer);
361 ASSERT(spannerSet);
362 spannerSet->setChildNeedsLayout();
Julien - ping for review 2014/09/30 00:39:32 2 mistakes here: - by default setChildNeedsLayout
mstensho (USE GERRIT) 2014/09/30 20:20:28 Done. Uploaded this change separately, as it modi
363 RenderMultiColumnSet* previousSet = spannerSet->previousSiblingMultiColumnSe t();
364 if (!previousSet) {
365 // The first set is entered at the beginning of flow thread layout. If t he first set happens
366 // to be a spanner, we have nothing more to do here.
367 return LayoutUnit();
368 }
369
370 RenderBlock* cb = renderer->containingBlock();
371 LayoutUnit logicalTopInFlowThread = cb->offsetFromLogicalTopOfFirstPage() + logicalTop;
372 LayoutUnit adjustment;
373 if (!previousSet->isRenderMultiColumnSpannerSet() && previousSet->pageLogica lHeight()) {
374 // Pad flow thread offset to a column boundary, so that contents that's supposed to come
375 // after the spanner (or the spanner itself) don't bleed into the column preceding the
376 // spanner.
377 LayoutUnit columnLogicalTopInFlowThread = previousSet->pageLogicalTopFor Offset(logicalTopInFlowThread);
378 if (columnLogicalTopInFlowThread != logicalTopInFlowThread) {
379 adjustment = columnLogicalTopInFlowThread + previousSet->pageLogical Height() - logicalTopInFlowThread;
380 logicalTopInFlowThread += adjustment;
381 }
382 }
383
384 if (!previousSet->isRenderMultiColumnSpannerSet())
385 previousSet->endFlow(logicalTopInFlowThread);
386 spannerSet->beginFlow(logicalTopInFlowThread);
387
388 m_lastSetWorkedOn = spannerSet;
389 return adjustment;
390 }
391
392 void RenderMultiColumnFlowThread::leaveColumnSpanner(RenderBox* renderer, Layout Unit logicalBottom)
393 {
394 ASSERT(m_lastSetWorkedOn == m_spannerMap.get(renderer));
395
396 RenderBlock* cb = renderer->containingBlock();
397 LayoutUnit logicalBottomInFlowThread = cb->offsetFromLogicalTopOfFirstPage() + logicalBottom;
398 m_lastSetWorkedOn->endFlow(logicalBottomInFlowThread);
399 RenderMultiColumnSet* nextSet = m_lastSetWorkedOn->nextSiblingMultiColumnSet ();
400 if (nextSet) {
401 m_lastSetWorkedOn = nextSet;
402 if (!m_lastSetWorkedOn->isRenderMultiColumnSpannerSet())
403 m_lastSetWorkedOn->beginFlow(logicalBottomInFlowThread);
404 }
405 }
406
407 void RenderMultiColumnFlowThread::flowThreadDescendantInserted(RenderObject* des cendant)
408 {
409 ASSERT(!m_beingEvacuated);
410 RenderObject* subtreeRoot = descendant;
411 RenderBlockFlow* multicolContainer = multiColumnBlockFlow();
412 for (; descendant; descendant = descendant->nextInPreOrder(subtreeRoot)) {
Julien - ping for review 2014/09/30 00:39:32 Modifying the passed-in parameter is a bad smell,
mstensho (USE GERRIT) 2014/09/30 20:20:28 Done.
413 RenderObject* nextRenderer = descendant->nextInPreOrderAfterChildren(thi s);
414 RenderMultiColumnSet* insertBeforeSet = 0;
415 if (isDescendantValidColumnSpanner(descendant)) {
416 ASSERT(!containingColumnSpanner(descendant));
417 RenderMultiColumnSet* setToSplit = 0;
418 if (nextRenderer) {
419 if (nextRenderer->isColumnSpanAll()) {
420 insertBeforeSet = m_spannerMap.get(nextRenderer);
421 } else {
422 RenderObject* previousRenderer = descendant->previousInPreOr der(this);
423 if (previousRenderer) {
424 if (RenderMultiColumnSpannerSet* previousSpanner = conta iningColumnSpanner(previousRenderer)) {
425 insertBeforeSet = previousSpanner->nextSiblingMultiC olumnSet();
426 } else {
427 // This is in the middle of an existing column set. Need to split it and put the
428 // spanner between them.
429 setToSplit = findSetRendering(previousRenderer);
430 setToSplit->setNeedsLayoutAndFullPaintInvalidation() ;
431 insertBeforeSet = setToSplit->nextSiblingMultiColumn Set();
432 }
433 } else {
434 insertBeforeSet = firstMultiColumnSet();
435 }
436 }
437 }
438 // Insert the spanner.
439 RenderMultiColumnSpannerSet* newSpanner = RenderMultiColumnSpannerSe t::createAnonymous(this, multicolContainer->style(), toRenderBox(descendant));
440 multicolContainer->RenderBlock::addChild(newSpanner, insertBeforeSet );
441 m_spannerMap.add(descendant, newSpanner);
442 invalidateRegions();
443 if (!setToSplit)
444 continue;
445 } else {
446 if (containingColumnSpanner(descendant))
447 continue;
448 if (nextRenderer) {
449 if (RenderMultiColumnSpannerSet* spanner = containingColumnSpann er(nextRenderer)) {
450 // Inserted right before a spanner. Is there a set for us th ere?
451 RenderMultiColumnSet* previous = spanner->previousSiblingMul tiColumnSet();
452 if (previous && !previous->isRenderMultiColumnSpannerSet())
453 continue;
454 insertBeforeSet = spanner;
455 } else if (lastMultiColumnSet()) {
456 continue;
457 }
458 } else if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) {
459 if (!lastSet->isRenderMultiColumnSpannerSet())
460 continue;
461 }
462 }
463 RenderMultiColumnSet* newSet = RenderMultiColumnSet::createAnonymous(thi s, multicolContainer->style());
464 multicolContainer->RenderBlock::addChild(newSet, insertBeforeSet);
465 invalidateRegions();
466
467 // We cannot handle immediate column set siblings at the moment (and the re's no need for
468 // it, either). There has to be at least one spanner separating them.
469 ASSERT(!newSet->previousSiblingMultiColumnSet() || newSet->previousSibli ngMultiColumnSet()->isRenderMultiColumnSpannerSet());
470 ASSERT(!newSet->nextSiblingMultiColumnSet() || newSet->nextSiblingMultiC olumnSet()->isRenderMultiColumnSpannerSet());
471 }
472 }
473
474 void RenderMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(RenderObject * descendant)
475 {
476 if (m_beingEvacuated)
477 return;
478 RenderMultiColumnSpannerSet* containingSpanner = containingColumnSpanner(des cendant);
479 if (containingSpanner && containingSpanner->rendererInFlowThread() != descen dant)
480 return; // Only removing stuff inside a spanner, and not the spanner its elf. Nothing to see here.
481 RenderObject* next;
482 for (RenderObject* renderer = descendant; renderer; renderer = next) {
483 RenderMultiColumnSpannerSet* spanner = m_spannerMap.get(renderer);
484 if (!spanner) {
485 next = renderer->nextInPreOrder(descendant);
486 continue;
487 }
488 next = renderer->nextInPreOrderAfterChildren(descendant); // It's a span ner. Its children are of no interest to us.
489 if (RenderMultiColumnSet* nextSet = spanner->nextSiblingMultiColumnSet() ) {
490 RenderMultiColumnSet* previousSet = spanner->previousSiblingMultiCol umnSet();
491 if (nextSet && !nextSet->isRenderMultiColumnSpannerSet()
492 && previousSet && !previousSet->isRenderMultiColumnSpannerSet()) {
493 // Need to merge two column sets.
494 nextSet->destroy();
495 previousSet->setNeedsLayout();
496 invalidateRegions();
497 }
498 }
499 m_spannerMap.remove(renderer);
500 spanner->destroy();
501 }
502 if (containingSpanner)
503 return; // Column content has not been removed.
504
505 // Get rid of column sets we no longer need.
506 RenderMultiColumnSpannerSet* adjacentPreviousSpanner = 0;
507 RenderObject* previousRenderer = descendant->previousInPreOrder(this);
508 if (previousRenderer) {
509 adjacentPreviousSpanner = containingColumnSpanner(previousRenderer);
510 if (!adjacentPreviousSpanner)
511 return; // Preceded by column content. Set still needed.
512 }
513 RenderMultiColumnSpannerSet* adjacentNextSpanner = 0;
514 RenderObject* nextRenderer = descendant->nextInPreOrderAfterChildren(this);
515 if (nextRenderer) {
516 adjacentNextSpanner = containingColumnSpanner(nextRenderer);
517 if (!adjacentNextSpanner)
518 return; // Followed by column content. Set still needed.
519 }
520 RenderMultiColumnSet* columnSetToRemove;
521 if (adjacentNextSpanner) {
522 columnSetToRemove = adjacentNextSpanner->previousSiblingMultiColumnSet() ;
523 } else if (adjacentPreviousSpanner) {
524 columnSetToRemove = adjacentPreviousSpanner->nextSiblingMultiColumnSet() ;
525 } else {
526 columnSetToRemove = firstMultiColumnSet();
527 ASSERT(columnSetToRemove);
528 ASSERT(!columnSetToRemove->previousSiblingMultiColumnSet());
529 ASSERT(!columnSetToRemove->nextSiblingMultiColumnSet());
530 }
531 ASSERT(columnSetToRemove);
532 columnSetToRemove->destroy();
533 }
534
535 void RenderMultiColumnFlowThread::flowThreadDescendantStyleDidChange(RenderObjec t* descendant)
536 {
537 ASSERT(descendant->isDescendantOf(this));
538 if (RenderMultiColumnSpannerSet* spanner = m_spannerMap.get(descendant))
539 spanner->updateMarginProperties();
540 }
541
259 void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const 542 void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
260 { 543 {
261 // We simply remain at our intrinsic height. 544 // We simply remain at our intrinsic height.
262 computedValues.m_extent = logicalHeight; 545 computedValues.m_extent = logicalHeight;
263 computedValues.m_position = logicalTop; 546 computedValues.m_position = logicalTop;
264 } 547 }
265 548
266 void RenderMultiColumnFlowThread::updateLogicalWidth() 549 void RenderMultiColumnFlowThread::updateLogicalWidth()
267 { 550 {
268 LayoutUnit columnWidth; 551 LayoutUnit columnWidth;
269 calculateColumnCountAndWidth(columnWidth, m_columnCount); 552 calculateColumnCountAndWidth(columnWidth, m_columnCount);
270 setLogicalWidth(columnWidth); 553 setLogicalWidth(columnWidth);
271 } 554 }
272 555
273 void RenderMultiColumnFlowThread::layout() 556 void RenderMultiColumnFlowThread::layout()
274 { 557 {
558 ASSERT(!m_lastSetWorkedOn);
559 m_lastSetWorkedOn = firstMultiColumnSet();
560 if (m_lastSetWorkedOn)
561 m_lastSetWorkedOn->beginFlow(LayoutUnit());
275 RenderFlowThread::layout(); 562 RenderFlowThread::layout();
276 if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) 563 if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) {
564 lastSet->endFlow(logicalHeight());
277 lastSet->expandToEncompassFlowThreadContentsIfNeeded(); 565 lastSet->expandToEncompassFlowThreadContentsIfNeeded();
566 }
567 m_lastSetWorkedOn = 0;
278 } 568 }
279 569
280 void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spa ceShortage) 570 void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spa ceShortage)
281 { 571 {
282 // Only positive values are interesting (and allowed) here. Zero space short age may be reported 572 // Only positive values are interesting (and allowed) here. Zero space short age may be reported
283 // when we're at the top of a column and the element has zero height. Ignore this, and also 573 // when we're at the top of a column and the element has zero height. Ignore this, and also
284 // ignore any negative values, which may occur when we set an early break in order to honor 574 // ignore any negative values, which may occur when we set an early break in order to honor
285 // widows in the next column. 575 // widows in the next column.
286 if (spaceShortage <= 0) 576 if (spaceShortage <= 0)
287 return; 577 return;
288 578
289 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) 579 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset))
290 multicolSet->recordSpaceShortage(spaceShortage); 580 multicolSet->recordSpaceShortage(spaceShortage);
291 } 581 }
292 582
293 void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay outUnit minHeight) 583 void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay outUnit minHeight)
294 { 584 {
295 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) 585 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset))
296 multicolSet->updateMinimumColumnHeight(minHeight); 586 multicolSet->updateMinimumColumnHeight(minHeight);
297 } 587 }
298 588
299 RenderMultiColumnSet* RenderMultiColumnFlowThread::columnSetAtBlockOffset(Layout Unit /*offset*/) const 589 RenderMultiColumnSet* RenderMultiColumnFlowThread::columnSetAtBlockOffset(Layout Unit offset) const
300 { 590 {
301 // For now there's only one column set, so this is easy: 591 if (m_lastSetWorkedOn) {
302 return firstMultiColumnSet(); 592 // Layout in progress. We are calculating the set heights as we speak, s o the column set range
593 // information is not up-to-date.
594 RenderMultiColumnSet* columnSet = m_lastSetWorkedOn;
595 if (offset < columnSet->logicalTopInFlowThread()) {
596 // In some cases we need to search backwards for a column set we've advanced past. This
597 // happens when a block crosses a column set boundary, and someone w ants to examine or
598 // adjust its top after or during layout. FIXME: If its top acually gets adjusted
599 // (e.g. because of an incorrect initial top position estimate), thi s may be problematic
600 // for column balancing, but returning the correct set here is at le ast better than
601 // nothing.
602 do {
603 if (RenderMultiColumnSet* prev = columnSet->previousSiblingMulti ColumnSet())
604 columnSet = prev;
605 else
606 break;
607 } while (offset < columnSet->logicalTopInFlowThread());
608 }
609 return columnSet;
610 }
611
612 ASSERT(!m_regionsInvalidated);
613 if (offset <= 0)
614 return m_multiColumnSetList.isEmpty() ? 0 : m_multiColumnSetList.first() ;
615
616 MultiColumnSetSearchAdapter adapter(offset);
617 m_multiColumnSetIntervalTree.allOverlapsWithAdapter<MultiColumnSetSearchAdap ter>(adapter);
618
619 // If no set was found, the offset is in the flow thread overflow.
620 if (!adapter.result() && !m_multiColumnSetList.isEmpty())
621 return m_multiColumnSetList.last();
622 return adapter.result();
303 } 623 }
304 624
305 bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render Object* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment) 625 bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render Object* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment)
306 { 626 {
307 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) { 627 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) {
308 multicolSet->addContentRun(offset); 628 multicolSet->addContentRun(offset);
309 if (offsetBreakAdjustment) 629 if (offsetBreakAdjustment)
310 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe mainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit(); 630 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe mainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit();
311 return true; 631 return true;
312 } 632 }
313 return false; 633 return false;
314 } 634 }
315 635
316 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const 636 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const
317 { 637 {
318 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) 638 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet())
319 return columnSet->pageLogicalHeight(); 639 return columnSet->pageLogicalHeight();
320 return false; 640 return false;
321 } 641 }
322 642
323 } 643 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698