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

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

Issue 1292163002: Initial support for nested multicol layout. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 4 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "config.h" 5 #include "config.h"
6 6
7 #include "core/layout/MultiColumnFragmentainerGroup.h" 7 #include "core/layout/MultiColumnFragmentainerGroup.h"
8 8
9 #include "core/layout/LayoutMultiColumnSet.h" 9 #include "core/layout/LayoutMultiColumnSet.h"
10 10
(...skipping 10 matching lines...) Expand all
21 } 21 }
22 22
23 LayoutSize MultiColumnFragmentainerGroup::offsetFromColumnSet() const 23 LayoutSize MultiColumnFragmentainerGroup::offsetFromColumnSet() const
24 { 24 {
25 LayoutSize offset(LayoutUnit(), logicalTop()); 25 LayoutSize offset(LayoutUnit(), logicalTop());
26 if (!m_columnSet.flowThread()->isHorizontalWritingMode()) 26 if (!m_columnSet.flowThread()->isHorizontalWritingMode())
27 return offset.transposedSize(); 27 return offset.transposedSize();
28 return offset; 28 return offset;
29 } 29 }
30 30
31 LayoutUnit MultiColumnFragmentainerGroup::blockOffsetInEnclosingFlowThread() con st
32 {
33 return logicalTop() + m_columnSet.logicalTop() + m_columnSet.multiColumnFlow Thread()->blockOffsetInEnclosingFlowThread();
34 }
35
31 bool MultiColumnFragmentainerGroup::heightIsAuto() const 36 bool MultiColumnFragmentainerGroup::heightIsAuto() const
32 { 37 {
33 // Only the last row may have auto height, and thus be balanced. There are n o good reasons to 38 // 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 39 // balance the preceding rows, and that could potentially lead to an insane number of layout
35 // passes as well. 40 // passes as well.
36 return isLastGroup() && m_columnSet.heightIsAuto(); 41 return isLastGroup() && m_columnSet.heightIsAuto();
37 } 42 }
38 43
39 void MultiColumnFragmentainerGroup::resetColumnHeight() 44 void MultiColumnFragmentainerGroup::resetColumnHeight()
40 { 45 {
41 // Nuke previously stored minimum column height. Contents may have changed f or all we know. 46 // Nuke previously stored minimum column height. Contents may have changed f or all we know.
42 m_minimumColumnHeight = 0; 47 m_minimumColumnHeight = 0;
43 48
44 m_maxColumnHeight = calculateMaxColumnHeight(); 49 m_maxColumnHeight = calculateMaxColumnHeight();
45 50
46 LayoutUnit oldColumnHeight = m_columnHeight; 51 LayoutUnit oldColumnHeight = m_columnHeight;
47 52
48 if (heightIsAuto()) 53 LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( );
54 LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosingFlow Thread();
55 if (enclosingFlowThread && enclosingFlowThread->isPageLogicalHeightKnown()) {
56 // TODO(mstensho): Do this better. If height is auto here, we shouldn't set a
57 // height, or forced breaks and pagination struts might mess up column b alancing.
58 ASSERT(m_maxColumnHeight != LayoutUnit::max());
leviw_travelin_and_unemployed 2015/08/15 00:04:43 Why this ASSERT? What situation are you testing fo
mstensho (USE GERRIT) 2015/08/17 07:43:09 I wanted to make sure that calculateMaxColumnHeigh
59 LayoutUnit columnHeight = heightIsAuto() ? m_maxColumnHeight : heightAdj ustedForRowOffset(flowThread->columnHeightAvailable());
60 setAndConstrainColumnHeight(columnHeight);
61 } else if (heightIsAuto()) {
49 m_columnHeight = LayoutUnit(); 62 m_columnHeight = LayoutUnit();
50 else 63 } else {
51 setAndConstrainColumnHeight(heightAdjustedForRowOffset(m_columnSet.multi ColumnFlowThread()->columnHeightAvailable())); 64 setAndConstrainColumnHeight(heightAdjustedForRowOffset(flowThread->colum nHeightAvailable()));
65 }
52 66
53 if (m_columnHeight != oldColumnHeight) 67 if (m_columnHeight != oldColumnHeight)
54 m_columnSet.setChildNeedsLayout(MarkOnlyThis); 68 m_columnSet.setChildNeedsLayout(MarkOnlyThis);
55 69
56 // Content runs are only needed in the initial layout pass, in order to find an initial column 70 // 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 71 // height, and should have been deleted afterwards. We're about to rebuild t he content runs, so
58 // the list needs to be empty. 72 // the list needs to be empty.
59 ASSERT(m_contentRuns.isEmpty()); 73 ASSERT(m_contentRuns.isEmpty());
60 } 74 }
61 75
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 126
113 if (m_columnHeight == oldColumnHeight) 127 if (m_columnHeight == oldColumnHeight)
114 return false; // No change. We're done. 128 return false; // No change. We're done.
115 129
116 m_minSpaceShortage = LayoutUnit::max(); 130 m_minSpaceShortage = LayoutUnit::max();
117 return true; // Need another pass. 131 return true; // Need another pass.
118 } 132 }
119 133
120 LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset(LayoutUn it offsetInFlowThread) const 134 LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset(LayoutUn it offsetInFlowThread) const
121 { 135 {
122 LayoutFlowThread* flowThread = m_columnSet.flowThread(); 136 LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( );
123 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread); 137 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread);
124 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); 138 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex));
125 flowThread->flipForWritingMode(portionRect); 139 flowThread->flipForWritingMode(portionRect);
126 LayoutRect columnRect(columnRectAt(columnIndex)); 140 LayoutRect columnRect(columnRectAt(columnIndex));
127 m_columnSet.flipForWritingMode(columnRect); 141 m_columnSet.flipForWritingMode(columnRect);
128 LayoutSize translationRelativeToGroup = columnRect.location() - portionRect. location(); 142 LayoutSize translationRelativeToGroup = columnRect.location() - portionRect. location();
129 return translationRelativeToGroup + offsetFromColumnSet() + m_columnSet.topL eftLocationOffset() - flowThread->topLeftLocationOffset(); 143
144 LayoutSize enclosingTranslation;
145 if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosing FlowThread()) {
146 // Translation that would map points in the coordinate space of the oute rmost flow thread to
147 // visual points in the first column in the first fragmentainer group (r ow) in our multicol
148 // container.
149 LayoutSize enclosingTranslationOrigin = enclosingFlowThread->flowThreadT ranslationAtOffset(flowThread->blockOffsetInEnclosingFlowThread());
150
151 // Translation that would map points in the coordinate space of the oute rmost flow thread to
152 // visual points in the first column in this fragmentainer group.
153 enclosingTranslation = enclosingFlowThread->flowThreadTranslationAtOffse t(blockOffsetInEnclosingFlowThread());
154
155 // What we ultimately return from this method is a translation that maps points in the
156 // coordinate space of our flow thread to a visual point in a certain co lumn in this
157 // fragmentainer group. We had to go all the way up to the outermost flo w thread, since this
158 // fragmentainer group may be in a different outer column than the first outer column that
159 // this multicol container lives in. It's the visual distance between th e first
160 // fragmentainer group and this fragmentainer group that we need to add to the translation.
161 enclosingTranslation -= enclosingTranslationOrigin;
162 }
163
164 return enclosingTranslation + translationRelativeToGroup + offsetFromColumnS et() + m_columnSet.topLeftLocationOffset() - flowThread->topLeftLocationOffset() ;
130 } 165 }
131 166
132 LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(LayoutUnit o ffsetInFlowThread) const 167 LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(LayoutUnit o ffsetInFlowThread) const
133 { 168 {
134 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread, AssumeNewColu mns); 169 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread, AssumeNewColu mns);
135 return logicalTopInFlowThreadAt(columnIndex); 170 return logicalTopInFlowThreadAt(columnIndex);
136 } 171 }
137 172
138 LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(const La youtPoint& visualPoint) const 173 LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(const La youtPoint& visualPoint) const
139 { 174 {
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 height -= contentLogicalTop; 336 height -= contentLogicalTop;
302 } 337 }
303 height -= logicalTop(); 338 height -= logicalTop();
304 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created. 339 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created.
305 } 340 }
306 341
307 LayoutUnit MultiColumnFragmentainerGroup::calculateMaxColumnHeight() const 342 LayoutUnit MultiColumnFragmentainerGroup::calculateMaxColumnHeight() const
308 { 343 {
309 LayoutBlockFlow* multicolBlock = m_columnSet.multiColumnBlockFlow(); 344 LayoutBlockFlow* multicolBlock = m_columnSet.multiColumnBlockFlow();
310 const ComputedStyle& multicolStyle = multicolBlock->styleRef(); 345 const ComputedStyle& multicolStyle = multicolBlock->styleRef();
311 LayoutUnit availableHeight = m_columnSet.multiColumnFlowThread()->columnHeig htAvailable(); 346 LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( );
347 LayoutUnit availableHeight = flowThread->columnHeightAvailable();
312 LayoutUnit maxColumnHeight = availableHeight ? availableHeight : LayoutUnit: :max(); 348 LayoutUnit maxColumnHeight = availableHeight ? availableHeight : LayoutUnit: :max();
313 if (!multicolStyle.logicalMaxHeight().isMaxSizeNone()) { 349 if (!multicolStyle.logicalMaxHeight().isMaxSizeNone()) {
314 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight (MaxSize, multicolStyle.logicalMaxHeight(), -1); 350 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight (MaxSize, multicolStyle.logicalMaxHeight(), -1);
315 if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight) 351 if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight)
316 maxColumnHeight = logicalMaxHeight; 352 maxColumnHeight = logicalMaxHeight;
317 } 353 }
318 return heightAdjustedForRowOffset(maxColumnHeight); 354 LayoutUnit maxHeight = heightAdjustedForRowOffset(maxColumnHeight);
355 if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosing FlowThread()) {
356 if (enclosingFlowThread->isPageLogicalHeightKnown()) {
357 // We're nested inside another fragmentation context whose fragmenta iner heights are
358 // known. This constrains the max height.
359 LayoutUnit remainingOuterLogicalHeight = enclosingFlowThread->pageRe mainingLogicalHeightForOffset(blockOffsetInEnclosingFlowThread(), LayoutBlock::A ssociateWithLatterPage);
360 ASSERT(remainingOuterLogicalHeight > 0);
361 if (maxHeight > remainingOuterLogicalHeight)
362 maxHeight = remainingOuterLogicalHeight;
363 }
364 }
365 return maxHeight;
319 } 366 }
320 367
321 void MultiColumnFragmentainerGroup::setAndConstrainColumnHeight(LayoutUnit newHe ight) 368 void MultiColumnFragmentainerGroup::setAndConstrainColumnHeight(LayoutUnit newHe ight)
322 { 369 {
323 m_columnHeight = newHeight; 370 m_columnHeight = newHeight;
324 if (m_columnHeight > m_maxColumnHeight) 371 if (m_columnHeight > m_maxColumnHeight)
325 m_columnHeight = m_maxColumnHeight; 372 m_columnHeight = m_maxColumnHeight;
326 // FIXME: the height may also be affected by the enclosing pagination contex t, if any.
327 } 373 }
328 374
329 unsigned MultiColumnFragmentainerGroup::findRunWithTallestColumns() const 375 unsigned MultiColumnFragmentainerGroup::findRunWithTallestColumns() const
330 { 376 {
331 unsigned indexWithLargestHeight = 0; 377 unsigned indexWithLargestHeight = 0;
332 LayoutUnit largestHeight; 378 LayoutUnit largestHeight;
333 LayoutUnit previousOffset = m_logicalTopInFlowThread; 379 LayoutUnit previousOffset = m_logicalTopInFlowThread;
334 size_t runCount = m_contentRuns.size(); 380 size_t runCount = m_contentRuns.size();
335 ASSERT(runCount); 381 ASSERT(runCount);
336 for (size_t i = 0; i < runCount; i++) { 382 for (size_t i = 0; i < runCount; i++) {
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
462 { 508 {
463 // This function determines the portion of the flow thread that paints for t he column. Along the inline axis, columns are 509 // This function determines the portion of the flow thread that paints for t he column. Along the inline axis, columns are
464 // unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column 510 // unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column
465 // gap along interior edges. 511 // gap along interior edges.
466 // 512 //
467 // In the block direction, we will not clip overflow out of the top of the f irst column, or out of the bottom of 513 // In the block direction, we will not clip overflow out of the top of the f irst column, or out of the bottom of
468 // the last column. This applies only to the true first column and last colu mn across all column sets. 514 // the last column. This applies only to the true first column and last colu mn across all column sets.
469 // 515 //
470 // FIXME: Eventually we will know overflow on a per-column basis, but we can 't do this until we have a painting 516 // FIXME: Eventually we will know overflow on a per-column basis, but we can 't do this until we have a painting
471 // mode that understands not to paint contents from a previous column in the overflow area of a following column. 517 // mode that understands not to paint contents from a previous column in the overflow area of a following column.
472 bool isFirstColumn = !columnIndex; 518 bool isFirstColumnInRow = !columnIndex;
473 bool isLastColumn = columnIndex == actualColumnCount() - 1; 519 bool isLastColumnInRow = columnIndex == actualColumnCount() - 1;
474 bool isLTR = m_columnSet.style()->isLeftToRightDirection(); 520 bool isLTR = m_columnSet.style()->isLeftToRightDirection();
475 bool isLeftmostColumn = isLTR ? isFirstColumn : isLastColumn; 521 bool isLeftmostColumn = isLTR ? isFirstColumnInRow : isLastColumnInRow;
476 bool isRightmostColumn = isLTR ? isLastColumn : isFirstColumn; 522 bool isRightmostColumn = isLTR ? isLastColumnInRow : isFirstColumnInRow;
477 523
478 LayoutRect portionRect = flowThreadPortionRectAt(columnIndex); 524 LayoutRect portionRect = flowThreadPortionRectAt(columnIndex);
525 bool isFirstColumnInMulticolContainer = isFirstColumnInRow && this == &m_col umnSet.firstFragmentainerGroup() && !m_columnSet.previousSiblingMultiColumnSet() ;
526 bool isLastColumnInMulticolContainer = isLastColumnInRow && this == &m_colum nSet.lastFragmentainerGroup() && !m_columnSet.nextSiblingMultiColumnSet();
479 // Calculate the overflow rectangle, based on the flow thread's, clipped at column logical 527 // Calculate the overflow rectangle, based on the flow thread's, clipped at column logical
480 // top/bottom unless it's the first/last column. 528 // top/bottom unless it's the first/last column.
481 LayoutRect overflowRect = m_columnSet.overflowRectForFlowThreadPortion(porti onRect, isFirstColumn && !m_columnSet.previousSiblingMultiColumnSet(), isLastCol umn && !m_columnSet.nextSiblingMultiColumnSet()); 529 LayoutRect overflowRect = m_columnSet.overflowRectForFlowThreadPortion(porti onRect, isFirstColumnInMulticolContainer, isLastColumnInMulticolContainer);
482 530
483 // Avoid overflowing into neighboring columns, by clipping in the middle of adjacent column 531 // Avoid overflowing into neighboring columns, by clipping in the middle of adjacent column
484 // gaps. Also make sure that we avoid rounding errors. 532 // gaps. Also make sure that we avoid rounding errors.
485 LayoutUnit columnGap = m_columnSet.columnGap(); 533 LayoutUnit columnGap = m_columnSet.columnGap();
486 if (m_columnSet.isHorizontalWritingMode()) { 534 if (m_columnSet.isHorizontalWritingMode()) {
487 if (!isLeftmostColumn) 535 if (!isLeftmostColumn)
488 overflowRect.shiftXEdgeTo(portionRect.x() - columnGap / 2); 536 overflowRect.shiftXEdgeTo(portionRect.x() - columnGap / 2);
489 if (!isRightmostColumn) 537 if (!isRightmostColumn)
490 overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap - column Gap / 2); 538 overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap - column Gap / 2);
491 } else { 539 } else {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
586 append(MultiColumnFragmentainerGroup(m_columnSet)); 634 append(MultiColumnFragmentainerGroup(m_columnSet));
587 return last(); 635 return last();
588 } 636 }
589 637
590 void MultiColumnFragmentainerGroupList::deleteExtraGroups() 638 void MultiColumnFragmentainerGroupList::deleteExtraGroups()
591 { 639 {
592 shrink(1); 640 shrink(1);
593 } 641 }
594 642
595 } // namespace blink 643 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698