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

Side by Side Diff: Source/core/layout/MultiColumnFragmentainerGroup.cpp

Issue 883293004: [New Multicolumn] Preparatory work for nested multicol support. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Place the new files in ../layout/ , since that's where they'll end up soon anyway. Created 5 years, 10 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
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6
7 #include "core/layout/MultiColumnFragmentainerGroup.h"
8
9 #include "core/rendering/RenderMultiColumnSet.h"
10
11 namespace blink {
12
13 MultiColumnFragmentainerGroup::MultiColumnFragmentainerGroup(RenderMultiColumnSe t& columnSet)
14 : m_columnSet(columnSet)
15 {
16 }
17
18 bool MultiColumnFragmentainerGroup::isLastGroup() const
19 {
20 return &m_columnSet.lastFragmentainerGroup() == this;
21 }
22
23 LayoutSize MultiColumnFragmentainerGroup::offsetFromColumnSet() const
24 {
25 LayoutSize offset(LayoutUnit(), logicalTop());
26 if (!m_columnSet.flowThread()->isHorizontalWritingMode())
27 return offset.transposedSize();
28 return offset;
29 }
30
31 bool MultiColumnFragmentainerGroup::heightIsAuto() const
32 {
33 // Only the last row may have auto height, and thus be balanced. There are n o good reasons to
34 // balance the preceding rows, and that could potentially lead to an insane number of layout
35 // passes as well.
Julien - ping for review 2015/02/11 07:25:29 Maybe there is some ASSERT we could land to avoid
mstensho (USE GERRIT) 2015/02/11 09:49:54 This very code already makes sure that we only bal
36 return isLastGroup() && m_columnSet.heightIsAuto();
37 }
38
39 void MultiColumnFragmentainerGroup::resetColumnHeight()
40 {
41 // Nuke previously stored minimum column height. Contents may have changed f or all we know.
42 m_minimumColumnHeight = 0;
43
44 m_maxColumnHeight = calculateMaxColumnHeight();
45
46 LayoutUnit oldColumnHeight = m_columnHeight;
47
48 if (heightIsAuto())
49 m_columnHeight = LayoutUnit();
50 else
51 setAndConstrainColumnHeight(heightAdjustedForRowOffset(m_columnSet.multi ColumnFlowThread()->columnHeightAvailable()));
52
53 if (m_columnHeight != oldColumnHeight)
54 m_columnSet.setChildNeedsLayout(MarkOnlyThis);
55
56 // Content runs are only needed in the initial layout pass, in order to find an initial column
57 // height, and should have been deleted afterwards. We're about to rebuild t he content runs, so
58 // the list needs to be empty.
59 ASSERT(m_contentRuns.isEmpty());
60 }
61
62 void MultiColumnFragmentainerGroup::addContentRun(LayoutUnit endOffsetInFlowThre ad)
63 {
64 if (!m_contentRuns.isEmpty() && endOffsetInFlowThread <= m_contentRuns.last( ).breakOffset())
65 return;
66 // Append another item as long as we haven't exceeded used column count. Wha t ends up in the
67 // overflow area shouldn't affect column balancing.
68 if (m_contentRuns.size() < m_columnSet.usedColumnCount())
69 m_contentRuns.append(ContentRun(endOffsetInFlowThread));
70 }
71
72 void MultiColumnFragmentainerGroup::recordSpaceShortage(LayoutUnit spaceShortage )
73 {
74 if (spaceShortage >= m_minSpaceShortage)
75 return;
76
77 // The space shortage is what we use as our stretch amount. We need a positi ve number here in
78 // order to get anywhere.
79 ASSERT(spaceShortage > 0);
80
81 m_minSpaceShortage = spaceShortage;
82 }
83
84 bool MultiColumnFragmentainerGroup::recalculateColumnHeight(BalancedColumnHeight Calculation calculationMode)
85 {
86 LayoutUnit oldColumnHeight = m_columnHeight;
87
88 m_maxColumnHeight = calculateMaxColumnHeight();
89
90 if (heightIsAuto()) {
91 if (calculationMode == GuessFromFlowThreadPortion) {
92 // Post-process the content runs and find out where the implicit bre aks will occur.
93 distributeImplicitBreaks();
94 }
95 LayoutUnit newColumnHeight = calculateColumnHeight(calculationMode);
96 setAndConstrainColumnHeight(newColumnHeight);
97 // After having calculated an initial column height, the multicol contai ner typically needs at
98 // least one more layout pass with a new column height, but if a height was specified, we only
99 // need to do this if we think that we need less space than specified. C onversely, if we
100 // determined that the columns need to be as tall as the specified heigh t of the container, we
101 // have already laid it out correctly, and there's no need for another p ass.
102 } else {
103 // The position of the column set may have changed, in which case height available for
104 // columns may have changed as well.
105 setAndConstrainColumnHeight(m_columnHeight);
106 }
107
108 // We can get rid of the content runs now, if we haven't already done so. Th ey are only needed
109 // to calculate the initial balanced column height. In fact, we have to get rid of them before
110 // the next layout pass, since each pass will rebuild this.
111 m_contentRuns.clear();
112
113 if (m_columnHeight == oldColumnHeight)
114 return false; // No change. We're done.
115
116 m_minSpaceShortage = RenderFlowThread::maxLogicalHeight();
117 return true; // Need another pass.
118 }
119
120 void MultiColumnFragmentainerGroup::expandToEncompassFlowThreadOverflow()
121 {
122 ASSERT(isLastGroup());
123 // Get the offset within the flow thread in its block progression direction. Then get the
124 // flow thread's remaining logical height including its overflow and expand our rect
125 // to encompass that remaining height and overflow. The idea is that we will generate
126 // additional columns and pages to hold that overflow, since people do write bad
127 // content like <body style="height:0px"> in multi-column layouts.
128 RenderMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( );
129 LayoutRect layoutRect = flowThread->layoutOverflowRect();
130 m_logicalBottomInFlowThread = flowThread->isHorizontalWritingMode() ? layout Rect.maxY() : layoutRect.maxX();
131 }
132
133 LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset(LayoutUn it offsetInFlowThread) const
134 {
135 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread);
136 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex));
137 m_columnSet.flipForWritingMode(portionRect);
138 LayoutRect columnRect(columnRectAt(columnIndex));
139 m_columnSet.flipForWritingMode(columnRect);
140 return columnRect.location() - portionRect.location();
141 }
142
143 LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(LayoutUnit o ffsetInFlowThread) const
144 {
145 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread, AssumeNewColu mns);
146 return m_logicalTopInFlowThread + columnIndex * m_columnHeight;
147 }
148
149 void MultiColumnFragmentainerGroup::collectLayerFragments(LayerFragments& fragme nts, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) const
150 {
151 // |layerBoundingBox| is in the flow thread coordinate space, relative to th e top/left edge of
152 // the flow thread, but note that it has been converted with respect to writ ing mode (so that
153 // it's visual/physical in that sense).
154 //
155 // |dirtyRect| is visual, relative to the multicol container.
156 //
157 // Then there's the output from this method - the stuff we put into the list of fragments. The
158 // fragment.paginationOffset point is the actual visual translation required to get from a
159 // location in the flow thread to a location in a given column. The fragment .paginationClip
160 // rectangle, on the other hand, is in flow thread coordinates.
161 //
162 // All other rectangles in this method are sized physically, and the inline direction coordinate
163 // is physical too, but the block direction coordinate is "logical top". Thi s is the same as
164 // e.g. RenderBox::frameRect(). These rectangles also pretend that there's o nly one long column,
165 // i.e. they are for the flow thread.
166
167 RenderMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( );
168 bool isHorizontalWritingMode = m_columnSet.isHorizontalWritingMode();
169
170 // Put the layer bounds into flow thread-local coordinates by flipping it fi rst. Since we're in
171 // a renderer, most rectangles are represented this way.
172 LayoutRect layerBoundsInFlowThread(layerBoundingBox);
173 flowThread->flipForWritingMode(layerBoundsInFlowThread);
174
175 // Now we can compare with the flow thread portions owned by each column. Fi rst let's
176 // see if the rect intersects our flow thread portion at all.
177 LayoutRect clippedRect(layerBoundsInFlowThread);
178 clippedRect.intersect(m_columnSet.RenderRegion::flowThreadPortionOverflowRec t()); // FIXME: clean up this mess.
179 if (clippedRect.isEmpty())
180 return;
181
182 // Now we know we intersect at least one column. Let's figure out the logica l top and logical
183 // bottom of the area we're checking.
184 LayoutUnit layerLogicalTop = isHorizontalWritingMode ? layerBoundsInFlowThre ad.y() : layerBoundsInFlowThread.x();
185 LayoutUnit layerLogicalBottom = (isHorizontalWritingMode ? layerBoundsInFlow Thread.maxY() : layerBoundsInFlowThread.maxX()) - 1;
186
187 // Figure out the start and end columns and only check within that range so that we don't walk the
188 // entire column row.
189 unsigned startColumn = columnIndexAtOffset(layerLogicalTop);
190 unsigned endColumn = columnIndexAtOffset(layerLogicalBottom);
191
192 LayoutUnit colLogicalWidth = m_columnSet.pageLogicalWidth();
193 LayoutUnit colGap = m_columnSet.columnGap();
194 unsigned colCount = actualColumnCount();
195
196 bool progressionIsInline = flowThread->progressionIsInline();
197 bool leftToRight = m_columnSet.style()->isLeftToRightDirection();
198
199 LayoutUnit initialBlockOffset = m_columnSet.logicalTop() + logicalTop() - fl owThread->logicalTop();
200
201 for (unsigned i = startColumn; i <= endColumn; i++) {
202 // Get the portion of the flow thread that corresponds to this column.
203 LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);
204
205 // Now get the overflow rect that corresponds to the column.
206 LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flo wThreadPortion, i, colCount, colGap);
207
208 // In order to create a fragment we must intersect the portion painted b y this column.
209 LayoutRect clippedRect(layerBoundsInFlowThread);
210 clippedRect.intersect(flowThreadOverflowPortion);
211 if (clippedRect.isEmpty())
212 continue;
213
214 // We also need to intersect the dirty rect. We have to apply a translat ion and shift based off
215 // our column index.
216 LayoutPoint translationOffset;
217 LayoutUnit inlineOffset = progressionIsInline ? i * (colLogicalWidth + c olGap) : LayoutUnit();
218 if (!leftToRight)
219 inlineOffset = -inlineOffset;
220 translationOffset.setX(inlineOffset);
221 LayoutUnit blockOffset;
222 if (progressionIsInline) {
223 blockOffset = initialBlockOffset + (isHorizontalWritingMode ? -flowT hreadPortion.y() : -flowThreadPortion.x());
224 } else {
225 // Column gap can apply in the block direction for page fragmentaine rs.
226 // There is currently no spec which calls for column-gap to apply
227 // for page fragmentainers at all, but it's applied here for compati bility
228 // with the old multicolumn implementation.
229 blockOffset = i * colGap;
230 }
231 if (isFlippedBlocksWritingMode(m_columnSet.style()->writingMode()))
232 blockOffset = -blockOffset;
233 translationOffset.setY(blockOffset);
234 if (!isHorizontalWritingMode)
235 translationOffset = translationOffset.transposedPoint();
236
237 // Shift the dirty rect to be in flow thread coordinates with this trans lation applied.
238 LayoutRect translatedDirtyRect(dirtyRect);
239 translatedDirtyRect.moveBy(-translationOffset);
240
241 // See if we intersect the dirty rect.
242 clippedRect = layerBoundingBox;
243 clippedRect.intersect(translatedDirtyRect);
244 if (clippedRect.isEmpty())
245 continue;
246
247 // Something does need to paint in this column. Make a fragment now and supply the physical translation
248 // offset and the clip rect for the column with that offset applied.
249 LayerFragment fragment;
250 fragment.paginationOffset = translationOffset;
251
252 LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion);
253 // Flip it into more a physical (RenderLayer-style) rectangle.
254 flowThread->flipForWritingMode(flippedFlowThreadOverflowPortion);
255 fragment.paginationClip = flippedFlowThreadOverflowPortion;
256 fragments.append(fragment);
257 }
258 }
259
260 LayoutRect MultiColumnFragmentainerGroup::calculateOverflow() const
261 {
262 unsigned columnCount = actualColumnCount();
263 if (!columnCount)
264 return LayoutRect();
265 return columnRectAt(columnCount - 1);
266 }
267
268 unsigned MultiColumnFragmentainerGroup::actualColumnCount() const
269 {
270 // We must always return a value of 1 or greater. Column count = 0 is a mean ingless situation,
271 // and will confuse and cause problems in other parts of the code.
272 if (!m_columnHeight)
273 return 1;
274
275 // Our flow thread portion determines our column count. We have as many colu mns as needed to fit
276 // all the content.
277 LayoutUnit flowThreadPortionHeight = logicalHeightInFlowThread();
278 if (!flowThreadPortionHeight)
279 return 1;
280
281 unsigned count = ceil(flowThreadPortionHeight.toFloat() / m_columnHeight.toF loat());
282 ASSERT(count >= 1);
283 return count;
284 }
285
286 LayoutUnit MultiColumnFragmentainerGroup::heightAdjustedForRowOffset(LayoutUnit height) const
287 {
288 // Adjust for the top offset within the content box of the multicol containe r (containing
289 // block), unless we're in the first set. We know that the top offset for th e first set will be
290 // zero, but if the multicol container has non-zero top border or padding, t he set's top offset
291 // (initially being 0 and relative to the border box) will be negative until it has been laid
292 // out. Had we used this bogus offset, we would calculate the wrong height, and risk performing
293 // a wasted layout iteration. Of course all other sets (if any) have this pr oblem in the first
294 // layout pass too, but there's really nothing we can do there until the flo w thread has been
295 // laid out anyway.
296 if (m_columnSet.previousSiblingMultiColumnSet()) {
297 RenderBlockFlow* multicolBlock = m_columnSet.multiColumnBlockFlow();
298 LayoutUnit contentLogicalTop = m_columnSet.logicalTop() - multicolBlock- >borderAndPaddingBefore();
299 height -= contentLogicalTop;
300 }
301 height -= logicalTop();
302 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created.
303 }
304
305 LayoutUnit MultiColumnFragmentainerGroup::calculateMaxColumnHeight() const
306 {
307 RenderBlockFlow* multicolBlock = m_columnSet.multiColumnBlockFlow();
308 LayoutStyle* multicolStyle = multicolBlock->style();
309 LayoutUnit availableHeight = m_columnSet.multiColumnFlowThread()->columnHeig htAvailable();
310 LayoutUnit maxColumnHeight = availableHeight ? availableHeight : RenderFlowT hread::maxLogicalHeight();
311 if (!multicolStyle->logicalMaxHeight().isMaxSizeNone()) {
312 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight (multicolStyle->logicalMaxHeight(), -1);
313 if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight)
314 maxColumnHeight = logicalMaxHeight;
315 }
316 return heightAdjustedForRowOffset(maxColumnHeight);
317 }
318
319 void MultiColumnFragmentainerGroup::setAndConstrainColumnHeight(LayoutUnit newHe ight)
320 {
321 m_columnHeight = newHeight;
322 if (m_columnHeight > m_maxColumnHeight)
323 m_columnHeight = m_maxColumnHeight;
324 // FIXME: the height may also be affected by the enclosing pagination contex t, if any.
325 }
326
327 unsigned MultiColumnFragmentainerGroup::findRunWithTallestColumns() const
328 {
329 unsigned indexWithLargestHeight = 0;
330 LayoutUnit largestHeight;
331 LayoutUnit previousOffset = m_logicalTopInFlowThread;
332 size_t runCount = m_contentRuns.size();
333 ASSERT(runCount);
334 for (size_t i = 0; i < runCount; i++) {
335 const ContentRun& run = m_contentRuns[i];
336 LayoutUnit height = run.columnLogicalHeight(previousOffset);
337 if (largestHeight < height) {
338 largestHeight = height;
339 indexWithLargestHeight = i;
340 }
341 previousOffset = run.breakOffset();
342 }
343 return indexWithLargestHeight;
344 }
345
346 void MultiColumnFragmentainerGroup::distributeImplicitBreaks()
347 {
348 #if ENABLE(ASSERT)
349 // There should be no implicit breaks assumed at this point.
350 for (unsigned i = 0; i < m_contentRuns.size(); i++)
351 ASSERT(!m_contentRuns[i].assumedImplicitBreaks());
352 #endif // ENABLE(ASSERT)
353
354 // Insert a final content run to encompass all content. This will include ov erflow if this is
355 // the last set.
356 addContentRun(m_logicalBottomInFlowThread);
357 unsigned columnCount = m_contentRuns.size();
358
359 // If there is room for more breaks (to reach the used value of column-count ), imagine that we
360 // insert implicit breaks at suitable locations. At any given time, the cont ent run with the
361 // currently tallest columns will get another implicit break "inserted", whi ch will increase its
362 // column count by one and shrink its columns' height. Repeat until we have the desired total
363 // number of breaks. The largest column height among the runs will then be t he initial column
364 // height for the balancer to use.
365 while (columnCount < m_columnSet.usedColumnCount()) {
366 unsigned index = findRunWithTallestColumns();
367 m_contentRuns[index].assumeAnotherImplicitBreak();
368 columnCount++;
369 }
370 }
371
372 LayoutUnit MultiColumnFragmentainerGroup::calculateColumnHeight(BalancedColumnHe ightCalculation calculationMode) const
373 {
374 if (calculationMode == GuessFromFlowThreadPortion) {
375 // Initial balancing. Start with the lowest imaginable column height. We use the tallest
376 // content run (after having "inserted" implicit breaks), and find its s tart offset (by
377 // looking at the previous run's end offset, or, if there's no previous run, the set's start
378 // offset in the flow thread).
379 unsigned index = findRunWithTallestColumns();
380 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffse t() : m_logicalTopInFlowThread;
381 return std::max<LayoutUnit>(m_contentRuns[index].columnLogicalHeight(sta rtOffset), m_minimumColumnHeight);
382 }
383
384 if (actualColumnCount() <= m_columnSet.usedColumnCount()) {
385 // With the current column height, the content fits without creating ove rflowing columns. We're done.
386 return m_columnHeight;
387 }
388
389 if (m_contentRuns.size() >= m_columnSet.usedColumnCount()) {
390 // Too many forced breaks to allow any implicit breaks. Initial balancin g should already
391 // have set a good height. There's nothing more we should do.
392 return m_columnHeight;
393 }
394
395 // If the initial guessed column height wasn't enough, stretch it now. Stret ch by the lowest
396 // amount of space shortage found during layout.
397
398 ASSERT(m_minSpaceShortage > 0); // We should never _shrink_ the height!
399 ASSERT(m_minSpaceShortage != RenderFlowThread::maxLogicalHeight()); // If th is happens, we probably have a bug.
400 if (m_minSpaceShortage == RenderFlowThread::maxLogicalHeight())
401 return m_columnHeight; // So bail out rather than looping infinitely.
402
403 return m_columnHeight + m_minSpaceShortage;
404 }
405
406 LayoutRect MultiColumnFragmentainerGroup::columnRectAt(unsigned columnIndex) con st
407 {
408 LayoutUnit columnLogicalWidth = m_columnSet.pageLogicalWidth();
409 LayoutUnit columnLogicalHeight = m_columnHeight;
410 LayoutUnit columnLogicalTop;
411 LayoutUnit columnLogicalLeft;
412 LayoutUnit columnGap = m_columnSet.columnGap();
413
414 if (m_columnSet.multiColumnFlowThread()->progressionIsInline()) {
415 if (m_columnSet.style()->isLeftToRightDirection())
416 columnLogicalLeft += columnIndex * (columnLogicalWidth + columnGap);
417 else
418 columnLogicalLeft += m_columnSet.contentLogicalWidth() - columnLogic alWidth - columnIndex * (columnLogicalWidth + columnGap);
419 } else {
420 columnLogicalTop += columnIndex * (columnLogicalHeight + columnGap);
421 }
422
423 LayoutRect columnRect(columnLogicalLeft, columnLogicalTop, columnLogicalWidt h, columnLogicalHeight);
424 if (!m_columnSet.isHorizontalWritingMode())
425 return columnRect.transposedRect();
426 return columnRect;
427 }
428
429 LayoutRect MultiColumnFragmentainerGroup::flowThreadPortionRectAt(unsigned colum nIndex) const
430 {
431 LayoutUnit logicalTop = m_logicalTopInFlowThread + columnIndex * m_columnHei ght;
432 if (m_columnSet.isHorizontalWritingMode())
433 return LayoutRect(LayoutUnit(), logicalTop, m_columnSet.pageLogicalWidth (), m_columnHeight);
434 return LayoutRect(logicalTop, LayoutUnit(), m_columnHeight, m_columnSet.page LogicalWidth());
435 }
436
437 LayoutRect MultiColumnFragmentainerGroup::flowThreadPortionOverflowRect(const La youtRect& portionRect, unsigned columnIndex, unsigned columnCount, LayoutUnit co lumnGap) const
438 {
439 // This function determines the portion of the flow thread that paints for t he column. Along the inline axis, columns are
440 // unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column
441 // gap along interior edges.
442 //
443 // In the block direction, we will not clip overflow out of the top of the f irst column, or out of the bottom of
444 // the last column. This applies only to the true first column and last colu mn across all column sets.
445 //
446 // FIXME: Eventually we will know overflow on a per-column basis, but we can 't do this until we have a painting
447 // mode that understands not to paint contents from a previous column in the overflow area of a following column.
448 // This problem applies to regions and pages as well and is not unique to co lumns.
449 bool isFirstColumn = !columnIndex;
450 bool isLastColumn = columnIndex == columnCount - 1;
451 bool isLTR = m_columnSet.style()->isLeftToRightDirection();
452 bool isLeftmostColumn = isLTR ? isFirstColumn : isLastColumn;
453 bool isRightmostColumn = isLTR ? isLastColumn : isFirstColumn;
454
455 // Calculate the overflow rectangle, based on the flow thread's, clipped at column logical
456 // top/bottom unless it's the first/last column.
457 LayoutRect overflowRect = m_columnSet.overflowRectForFlowThreadPortion(porti onRect, isFirstColumn && m_columnSet.isFirstRegion(), isLastColumn && m_columnSe t.isLastRegion());
458
459 // Avoid overflowing into neighboring columns, by clipping in the middle of adjacent column
460 // gaps. Also make sure that we avoid rounding errors.
461 if (m_columnSet.isHorizontalWritingMode()) {
462 if (!isLeftmostColumn)
463 overflowRect.shiftXEdgeTo(portionRect.x() - columnGap / 2);
464 if (!isRightmostColumn)
465 overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap - column Gap / 2);
466 } else {
467 if (!isLeftmostColumn)
468 overflowRect.shiftYEdgeTo(portionRect.y() - columnGap / 2);
469 if (!isRightmostColumn)
470 overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + columnGap - column Gap / 2);
471 }
472 return overflowRect;
473 }
474
475 unsigned MultiColumnFragmentainerGroup::columnIndexAtOffset(LayoutUnit offsetInF lowThread, ColumnIndexCalculationMode mode) const
476 {
477 // Handle the offset being out of range.
478 if (offsetInFlowThread < m_logicalTopInFlowThread)
479 return 0;
480 // If we're laying out right now, we cannot constrain against some logical b ottom, since it
481 // isn't known yet. Otherwise, just return the last column if we're past the logical bottom.
482 if (mode == ClampToExistingColumns) {
483 if (offsetInFlowThread >= m_logicalBottomInFlowThread)
484 return actualColumnCount() - 1;
485 }
486
487 if (m_columnHeight)
488 return (offsetInFlowThread - m_logicalTopInFlowThread).toFloat() / m_col umnHeight.toFloat();
489 return 0;
490 }
491
492 MultiColumnFragmentainerGroupList::MultiColumnFragmentainerGroupList(RenderMulti ColumnSet& columnSet)
493 : m_columnSet(columnSet)
494 {
495 append(MultiColumnFragmentainerGroup(m_columnSet));
496 }
497
498 MultiColumnFragmentainerGroup& MultiColumnFragmentainerGroupList::addExtraGroup( )
499 {
500 append(MultiColumnFragmentainerGroup(m_columnSet));
501 return last();
502 }
503
504 void MultiColumnFragmentainerGroupList::deleteExtraGroups()
505 {
506 shrink(1);
507 }
508
509 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698