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

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: Fix ref in test. Tables don't do subpixel, and that made a difference on Windows and Mac. Created 6 years, 2 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, SubtreeLayoutScope& layoutScope)
358 {
359 ASSERT(renderer->isDescendantOf(this));
360 RenderMultiColumnSpannerSet* spannerSet = m_spannerMap.get(renderer);
361 ASSERT(spannerSet);
362
363 // FIXME: it's really only necessary to mark the spanner set for layout when the height of
364 // |renderer| changes.
365 spannerSet->setChildNeedsLayout(MarkOnlyThis, &layoutScope);
366
367 RenderMultiColumnSet* previousSet = spannerSet->previousSiblingMultiColumnSe t();
368 if (!previousSet) {
369 // The first set is entered at the beginning of flow thread layout. If t he first set happens
370 // to be a spanner, we have nothing more to do here.
371 return LayoutUnit();
372 }
373
374 RenderBlock* cb = renderer->containingBlock();
375 LayoutUnit logicalTopInFlowThread = cb->offsetFromLogicalTopOfFirstPage() + logicalTop;
376 LayoutUnit adjustment;
377 if (!previousSet->isRenderMultiColumnSpannerSet() && previousSet->pageLogica lHeight()) {
378 // Pad flow thread offset to a column boundary, so that contents that's supposed to come
379 // after the spanner (or the spanner itself) don't bleed into the column preceding the
380 // spanner.
381 LayoutUnit columnLogicalTopInFlowThread = previousSet->pageLogicalTopFor Offset(logicalTopInFlowThread);
382 if (columnLogicalTopInFlowThread != logicalTopInFlowThread) {
383 adjustment = columnLogicalTopInFlowThread + previousSet->pageLogical Height() - logicalTopInFlowThread;
384 logicalTopInFlowThread += adjustment;
385 }
386 }
387
388 if (!previousSet->isRenderMultiColumnSpannerSet())
389 previousSet->endFlow(logicalTopInFlowThread);
390 spannerSet->beginFlow(logicalTopInFlowThread);
391
392 m_lastSetWorkedOn = spannerSet;
393 return adjustment;
394 }
395
396 void RenderMultiColumnFlowThread::leaveColumnSpanner(RenderBox* renderer, Layout Unit logicalBottom)
397 {
398 ASSERT(m_lastSetWorkedOn == m_spannerMap.get(renderer));
399
400 RenderBlock* cb = renderer->containingBlock();
401 LayoutUnit logicalBottomInFlowThread = cb->offsetFromLogicalTopOfFirstPage() + logicalBottom;
402 m_lastSetWorkedOn->endFlow(logicalBottomInFlowThread);
403 RenderMultiColumnSet* nextSet = m_lastSetWorkedOn->nextSiblingMultiColumnSet ();
404 if (nextSet) {
405 m_lastSetWorkedOn = nextSet;
406 if (!m_lastSetWorkedOn->isRenderMultiColumnSpannerSet())
407 m_lastSetWorkedOn->beginFlow(logicalBottomInFlowThread);
408 }
409 }
410
411 void RenderMultiColumnFlowThread::flowThreadDescendantInserted(RenderObject* des cendant)
412 {
413 ASSERT(!m_beingEvacuated);
414 RenderBlockFlow* multicolContainer = multiColumnBlockFlow();
415 for (RenderObject* renderer = descendant; renderer; renderer = renderer->nex tInPreOrder(descendant)) {
416 RenderObject* nextRenderer = renderer->nextInPreOrderAfterChildren(this) ;
417 RenderMultiColumnSet* insertBeforeSet = 0;
418 if (isDescendantValidColumnSpanner(renderer)) {
419 ASSERT(!containingColumnSpanner(renderer));
420 RenderMultiColumnSet* setToSplit = 0;
421 if (nextRenderer) {
422 if (nextRenderer->isColumnSpanAll()) {
423 insertBeforeSet = m_spannerMap.get(nextRenderer);
424 } else {
425 RenderObject* previousRenderer = renderer->previousInPreOrde r(this);
426 if (previousRenderer) {
427 if (RenderMultiColumnSpannerSet* previousSpanner = conta iningColumnSpanner(previousRenderer)) {
428 insertBeforeSet = previousSpanner->nextSiblingMultiC olumnSet();
429 } else {
430 // This is in the middle of an existing column set. Need to split it and put the
431 // spanner between them.
432 setToSplit = findSetRendering(previousRenderer);
433 setToSplit->setNeedsLayoutAndFullPaintInvalidation() ;
434 insertBeforeSet = setToSplit->nextSiblingMultiColumn Set();
435 }
436 } else {
437 insertBeforeSet = firstMultiColumnSet();
438 }
439 }
440 }
441 // Insert the spanner.
442 RenderMultiColumnSpannerSet* newSpanner = RenderMultiColumnSpannerSe t::createAnonymous(this, multicolContainer->style(), toRenderBox(renderer));
443 multicolContainer->RenderBlock::addChild(newSpanner, insertBeforeSet );
444 m_spannerMap.add(renderer, newSpanner);
445 invalidateRegions();
446 if (!setToSplit)
447 continue;
448 } else {
449 if (containingColumnSpanner(renderer))
450 continue;
451 if (nextRenderer) {
452 if (RenderMultiColumnSpannerSet* spanner = containingColumnSpann er(nextRenderer)) {
453 // Inserted right before a spanner. Is there a set for us th ere?
454 RenderMultiColumnSet* previous = spanner->previousSiblingMul tiColumnSet();
455 if (previous && !previous->isRenderMultiColumnSpannerSet())
456 continue;
457 insertBeforeSet = spanner;
458 } else if (lastMultiColumnSet()) {
459 continue;
460 }
461 } else if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) {
462 if (!lastSet->isRenderMultiColumnSpannerSet())
463 continue;
464 }
465 }
466 RenderMultiColumnSet* newSet = RenderMultiColumnSet::createAnonymous(thi s, multicolContainer->style());
467 multicolContainer->RenderBlock::addChild(newSet, insertBeforeSet);
468 invalidateRegions();
469
470 // We cannot handle immediate column set siblings at the moment (and the re's no need for
471 // it, either). There has to be at least one spanner separating them.
472 ASSERT(!newSet->previousSiblingMultiColumnSet() || newSet->previousSibli ngMultiColumnSet()->isRenderMultiColumnSpannerSet());
473 ASSERT(!newSet->nextSiblingMultiColumnSet() || newSet->nextSiblingMultiC olumnSet()->isRenderMultiColumnSpannerSet());
474 }
475 }
476
477 void RenderMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(RenderObject * descendant)
478 {
479 if (m_beingEvacuated)
480 return;
481 RenderMultiColumnSpannerSet* containingSpanner = containingColumnSpanner(des cendant);
482 if (containingSpanner && containingSpanner->rendererInFlowThread() != descen dant)
483 return; // Only removing stuff inside a spanner, and not the spanner its elf. Nothing to see here.
484 RenderObject* next;
485 for (RenderObject* renderer = descendant; renderer; renderer = next) {
486 RenderMultiColumnSpannerSet* spanner = m_spannerMap.get(renderer);
487 if (!spanner) {
488 next = renderer->nextInPreOrder(descendant);
489 continue;
490 }
491 next = renderer->nextInPreOrderAfterChildren(descendant); // It's a span ner. Its children are of no interest to us.
492 if (RenderMultiColumnSet* nextSet = spanner->nextSiblingMultiColumnSet() ) {
493 RenderMultiColumnSet* previousSet = spanner->previousSiblingMultiCol umnSet();
494 if (nextSet && !nextSet->isRenderMultiColumnSpannerSet()
495 && previousSet && !previousSet->isRenderMultiColumnSpannerSet()) {
496 // Need to merge two column sets.
497 nextSet->destroy();
498 previousSet->setNeedsLayout();
499 invalidateRegions();
500 }
501 }
502 m_spannerMap.remove(renderer);
503 spanner->destroy();
504 }
505 if (containingSpanner)
506 return; // Column content has not been removed.
507
508 // Get rid of column sets we no longer need.
509 RenderMultiColumnSpannerSet* adjacentPreviousSpanner = 0;
510 RenderObject* previousRenderer = descendant->previousInPreOrder(this);
511 if (previousRenderer) {
512 adjacentPreviousSpanner = containingColumnSpanner(previousRenderer);
513 if (!adjacentPreviousSpanner)
514 return; // Preceded by column content. Set still needed.
515 }
516 RenderMultiColumnSpannerSet* adjacentNextSpanner = 0;
517 RenderObject* nextRenderer = descendant->nextInPreOrderAfterChildren(this);
518 if (nextRenderer) {
519 adjacentNextSpanner = containingColumnSpanner(nextRenderer);
520 if (!adjacentNextSpanner)
521 return; // Followed by column content. Set still needed.
522 }
523 RenderMultiColumnSet* columnSetToRemove;
524 if (adjacentNextSpanner) {
525 columnSetToRemove = adjacentNextSpanner->previousSiblingMultiColumnSet() ;
526 } else if (adjacentPreviousSpanner) {
527 columnSetToRemove = adjacentPreviousSpanner->nextSiblingMultiColumnSet() ;
528 } else {
529 columnSetToRemove = firstMultiColumnSet();
530 ASSERT(columnSetToRemove);
531 ASSERT(!columnSetToRemove->previousSiblingMultiColumnSet());
532 ASSERT(!columnSetToRemove->nextSiblingMultiColumnSet());
533 }
534 ASSERT(columnSetToRemove);
535 columnSetToRemove->destroy();
536 }
537
538 void RenderMultiColumnFlowThread::flowThreadDescendantStyleDidChange(RenderObjec t* descendant)
539 {
540 ASSERT(descendant->isDescendantOf(this));
541 if (RenderMultiColumnSpannerSet* spanner = m_spannerMap.get(descendant))
542 spanner->updateMarginProperties();
543 }
544
259 void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const 545 void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
260 { 546 {
261 // We simply remain at our intrinsic height. 547 // We simply remain at our intrinsic height.
262 computedValues.m_extent = logicalHeight; 548 computedValues.m_extent = logicalHeight;
263 computedValues.m_position = logicalTop; 549 computedValues.m_position = logicalTop;
264 } 550 }
265 551
266 void RenderMultiColumnFlowThread::updateLogicalWidth() 552 void RenderMultiColumnFlowThread::updateLogicalWidth()
267 { 553 {
268 LayoutUnit columnWidth; 554 LayoutUnit columnWidth;
269 calculateColumnCountAndWidth(columnWidth, m_columnCount); 555 calculateColumnCountAndWidth(columnWidth, m_columnCount);
270 setLogicalWidth(columnWidth); 556 setLogicalWidth(columnWidth);
271 } 557 }
272 558
273 void RenderMultiColumnFlowThread::layout() 559 void RenderMultiColumnFlowThread::layout()
274 { 560 {
561 ASSERT(!m_lastSetWorkedOn);
562 m_lastSetWorkedOn = firstMultiColumnSet();
563 if (m_lastSetWorkedOn)
564 m_lastSetWorkedOn->beginFlow(LayoutUnit());
275 RenderFlowThread::layout(); 565 RenderFlowThread::layout();
276 if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) 566 if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) {
567 lastSet->endFlow(logicalHeight());
277 lastSet->expandToEncompassFlowThreadContentsIfNeeded(); 568 lastSet->expandToEncompassFlowThreadContentsIfNeeded();
569 }
570 m_lastSetWorkedOn = 0;
278 } 571 }
279 572
280 void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spa ceShortage) 573 void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spa ceShortage)
281 { 574 {
282 // Only positive values are interesting (and allowed) here. Zero space short age may be reported 575 // 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 576 // 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 577 // ignore any negative values, which may occur when we set an early break in order to honor
285 // widows in the next column. 578 // widows in the next column.
286 if (spaceShortage <= 0) 579 if (spaceShortage <= 0)
287 return; 580 return;
288 581
289 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) 582 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset))
290 multicolSet->recordSpaceShortage(spaceShortage); 583 multicolSet->recordSpaceShortage(spaceShortage);
291 } 584 }
292 585
293 void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay outUnit minHeight) 586 void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay outUnit minHeight)
294 { 587 {
295 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) 588 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset))
296 multicolSet->updateMinimumColumnHeight(minHeight); 589 multicolSet->updateMinimumColumnHeight(minHeight);
297 } 590 }
298 591
299 RenderMultiColumnSet* RenderMultiColumnFlowThread::columnSetAtBlockOffset(Layout Unit /*offset*/) const 592 RenderMultiColumnSet* RenderMultiColumnFlowThread::columnSetAtBlockOffset(Layout Unit offset) const
300 { 593 {
301 // For now there's only one column set, so this is easy: 594 if (m_lastSetWorkedOn) {
302 return firstMultiColumnSet(); 595 // Layout in progress. We are calculating the set heights as we speak, s o the column set range
596 // information is not up-to-date.
597 RenderMultiColumnSet* columnSet = m_lastSetWorkedOn;
598 if (offset < columnSet->logicalTopInFlowThread()) {
599 // In some cases we need to search backwards for a column set we've advanced past. This
600 // happens when a block crosses a column set boundary, and someone w ants to examine or
601 // adjust its top after or during layout. FIXME: If its top acually gets adjusted
602 // (e.g. because of an incorrect initial top position estimate), thi s may be problematic
603 // for column balancing, but returning the correct set here is at le ast better than
604 // nothing.
605 do {
606 if (RenderMultiColumnSet* prev = columnSet->previousSiblingMulti ColumnSet())
607 columnSet = prev;
608 else
609 break;
610 } while (offset < columnSet->logicalTopInFlowThread());
611 }
612 return columnSet;
613 }
614
615 ASSERT(!m_regionsInvalidated);
616 if (offset <= 0)
617 return m_multiColumnSetList.isEmpty() ? 0 : m_multiColumnSetList.first() ;
618
619 MultiColumnSetSearchAdapter adapter(offset);
620 m_multiColumnSetIntervalTree.allOverlapsWithAdapter<MultiColumnSetSearchAdap ter>(adapter);
621
622 // If no set was found, the offset is in the flow thread overflow.
623 if (!adapter.result() && !m_multiColumnSetList.isEmpty())
624 return m_multiColumnSetList.last();
625 return adapter.result();
303 } 626 }
304 627
305 bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render Object* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment) 628 bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render Object* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment)
306 { 629 {
307 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) { 630 if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) {
308 multicolSet->addContentRun(offset); 631 multicolSet->addContentRun(offset);
309 if (offsetBreakAdjustment) 632 if (offsetBreakAdjustment)
310 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe mainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit(); 633 *offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRe mainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit();
311 return true; 634 return true;
312 } 635 }
313 return false; 636 return false;
314 } 637 }
315 638
316 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const 639 bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const
317 { 640 {
318 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet()) 641 if (RenderMultiColumnSet* columnSet = lastMultiColumnSet())
319 return columnSet->pageLogicalHeight(); 642 return columnSet->pageLogicalHeight();
320 return false; 643 return false;
321 } 644 }
322 645
323 } 646 }
OLDNEW
« no previous file with comments | « Source/core/rendering/RenderMultiColumnFlowThread.h ('k') | Source/core/rendering/RenderMultiColumnSet.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698