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

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: code review 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
« no previous file with comments | « Source/core/layout/MultiColumnFragmentainerGroup.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 LayoutUnit columnHeight = heightIsAuto() ? m_maxColumnHeight : heightAdj ustedForRowOffset(flowThread->columnHeightAvailable());
59 setAndConstrainColumnHeight(columnHeight);
60 } else if (heightIsAuto()) {
49 m_columnHeight = LayoutUnit(); 61 m_columnHeight = LayoutUnit();
50 else 62 } else {
51 setAndConstrainColumnHeight(heightAdjustedForRowOffset(m_columnSet.multi ColumnFlowThread()->columnHeightAvailable())); 63 setAndConstrainColumnHeight(heightAdjustedForRowOffset(flowThread->colum nHeightAvailable()));
64 }
52 65
53 if (m_columnHeight != oldColumnHeight) 66 if (m_columnHeight != oldColumnHeight)
54 m_columnSet.setChildNeedsLayout(MarkOnlyThis); 67 m_columnSet.setChildNeedsLayout(MarkOnlyThis);
55 68
56 // Content runs are only needed in the initial layout pass, in order to find an initial column 69 // 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 70 // height, and should have been deleted afterwards. We're about to rebuild t he content runs, so
58 // the list needs to be empty. 71 // the list needs to be empty.
59 ASSERT(m_contentRuns.isEmpty()); 72 ASSERT(m_contentRuns.isEmpty());
60 } 73 }
61 74
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 125
113 if (m_columnHeight == oldColumnHeight) 126 if (m_columnHeight == oldColumnHeight)
114 return false; // No change. We're done. 127 return false; // No change. We're done.
115 128
116 m_minSpaceShortage = LayoutUnit::max(); 129 m_minSpaceShortage = LayoutUnit::max();
117 return true; // Need another pass. 130 return true; // Need another pass.
118 } 131 }
119 132
120 LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset(LayoutUn it offsetInFlowThread) const 133 LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset(LayoutUn it offsetInFlowThread) const
121 { 134 {
122 LayoutFlowThread* flowThread = m_columnSet.flowThread(); 135 LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( );
123 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread); 136 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread);
124 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); 137 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex));
125 flowThread->flipForWritingMode(portionRect); 138 flowThread->flipForWritingMode(portionRect);
126 LayoutRect columnRect(columnRectAt(columnIndex)); 139 LayoutRect columnRect(columnRectAt(columnIndex));
127 m_columnSet.flipForWritingMode(columnRect); 140 m_columnSet.flipForWritingMode(columnRect);
128 LayoutSize translationRelativeToGroup = columnRect.location() - portionRect. location(); 141 LayoutSize translationRelativeToGroup = columnRect.location() - portionRect. location();
129 return translationRelativeToGroup + offsetFromColumnSet() + m_columnSet.topL eftLocationOffset() - flowThread->topLeftLocationOffset(); 142
143 LayoutSize enclosingTranslation;
144 if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosing FlowThread()) {
145 // Translation that would map points in the coordinate space of the oute rmost flow thread to
146 // visual points in the first column in the first fragmentainer group (r ow) in our multicol
147 // container.
148 LayoutSize enclosingTranslationOrigin = enclosingFlowThread->flowThreadT ranslationAtOffset(flowThread->blockOffsetInEnclosingFlowThread());
149
150 // Translation that would map points in the coordinate space of the oute rmost flow thread to
151 // visual points in the first column in this fragmentainer group.
152 enclosingTranslation = enclosingFlowThread->flowThreadTranslationAtOffse t(blockOffsetInEnclosingFlowThread());
153
154 // What we ultimately return from this method is a translation that maps points in the
155 // coordinate space of our flow thread to a visual point in a certain co lumn in this
156 // fragmentainer group. We had to go all the way up to the outermost flo w thread, since this
157 // fragmentainer group may be in a different outer column than the first outer column that
158 // this multicol container lives in. It's the visual distance between th e first
159 // fragmentainer group and this fragmentainer group that we need to add to the translation.
160 enclosingTranslation -= enclosingTranslationOrigin;
161 }
162
163 return enclosingTranslation + translationRelativeToGroup + offsetFromColumnS et() + m_columnSet.topLeftLocationOffset() - flowThread->topLeftLocationOffset() ;
130 } 164 }
131 165
132 LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(LayoutUnit o ffsetInFlowThread) const 166 LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(LayoutUnit o ffsetInFlowThread) const
133 { 167 {
134 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread, AssumeNewColu mns); 168 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread, AssumeNewColu mns);
135 return logicalTopInFlowThreadAt(columnIndex); 169 return logicalTopInFlowThreadAt(columnIndex);
136 } 170 }
137 171
138 LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(const La youtPoint& visualPoint) const 172 LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(const La youtPoint& visualPoint) const
139 { 173 {
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 height -= contentLogicalTop; 335 height -= contentLogicalTop;
302 } 336 }
303 height -= logicalTop(); 337 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. 338 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created.
305 } 339 }
306 340
307 LayoutUnit MultiColumnFragmentainerGroup::calculateMaxColumnHeight() const 341 LayoutUnit MultiColumnFragmentainerGroup::calculateMaxColumnHeight() const
308 { 342 {
309 LayoutBlockFlow* multicolBlock = m_columnSet.multiColumnBlockFlow(); 343 LayoutBlockFlow* multicolBlock = m_columnSet.multiColumnBlockFlow();
310 const ComputedStyle& multicolStyle = multicolBlock->styleRef(); 344 const ComputedStyle& multicolStyle = multicolBlock->styleRef();
311 LayoutUnit availableHeight = m_columnSet.multiColumnFlowThread()->columnHeig htAvailable(); 345 LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( );
346 LayoutUnit availableHeight = flowThread->columnHeightAvailable();
312 LayoutUnit maxColumnHeight = availableHeight ? availableHeight : LayoutUnit: :max(); 347 LayoutUnit maxColumnHeight = availableHeight ? availableHeight : LayoutUnit: :max();
313 if (!multicolStyle.logicalMaxHeight().isMaxSizeNone()) { 348 if (!multicolStyle.logicalMaxHeight().isMaxSizeNone()) {
314 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight (MaxSize, multicolStyle.logicalMaxHeight(), -1); 349 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight (MaxSize, multicolStyle.logicalMaxHeight(), -1);
315 if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight) 350 if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight)
316 maxColumnHeight = logicalMaxHeight; 351 maxColumnHeight = logicalMaxHeight;
317 } 352 }
318 return heightAdjustedForRowOffset(maxColumnHeight); 353 LayoutUnit maxHeight = heightAdjustedForRowOffset(maxColumnHeight);
354 if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosing FlowThread()) {
355 if (enclosingFlowThread->isPageLogicalHeightKnown()) {
356 // We're nested inside another fragmentation context whose fragmenta iner heights are
357 // known. This constrains the max height.
358 LayoutUnit remainingOuterLogicalHeight = enclosingFlowThread->pageRe mainingLogicalHeightForOffset(blockOffsetInEnclosingFlowThread(), LayoutBlock::A ssociateWithLatterPage);
359 ASSERT(remainingOuterLogicalHeight > 0);
360 if (maxHeight > remainingOuterLogicalHeight)
361 maxHeight = remainingOuterLogicalHeight;
362 }
363 }
364 return maxHeight;
319 } 365 }
320 366
321 void MultiColumnFragmentainerGroup::setAndConstrainColumnHeight(LayoutUnit newHe ight) 367 void MultiColumnFragmentainerGroup::setAndConstrainColumnHeight(LayoutUnit newHe ight)
322 { 368 {
323 m_columnHeight = newHeight; 369 m_columnHeight = newHeight;
324 if (m_columnHeight > m_maxColumnHeight) 370 if (m_columnHeight > m_maxColumnHeight)
325 m_columnHeight = m_maxColumnHeight; 371 m_columnHeight = m_maxColumnHeight;
326 // FIXME: the height may also be affected by the enclosing pagination contex t, if any.
327 } 372 }
328 373
329 unsigned MultiColumnFragmentainerGroup::findRunWithTallestColumns() const 374 unsigned MultiColumnFragmentainerGroup::findRunWithTallestColumns() const
330 { 375 {
331 unsigned indexWithLargestHeight = 0; 376 unsigned indexWithLargestHeight = 0;
332 LayoutUnit largestHeight; 377 LayoutUnit largestHeight;
333 LayoutUnit previousOffset = m_logicalTopInFlowThread; 378 LayoutUnit previousOffset = m_logicalTopInFlowThread;
334 size_t runCount = m_contentRuns.size(); 379 size_t runCount = m_contentRuns.size();
335 ASSERT(runCount); 380 ASSERT(runCount);
336 for (size_t i = 0; i < runCount; i++) { 381 for (size_t i = 0; i < runCount; i++) {
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
462 { 507 {
463 // This function determines the portion of the flow thread that paints for t he column. Along the inline axis, columns are 508 // 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 509 // 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. 510 // gap along interior edges.
466 // 511 //
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 512 // 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. 513 // the last column. This applies only to the true first column and last colu mn across all column sets.
469 // 514 //
470 // FIXME: Eventually we will know overflow on a per-column basis, but we can 't do this until we have a painting 515 // 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. 516 // mode that understands not to paint contents from a previous column in the overflow area of a following column.
472 bool isFirstColumn = !columnIndex; 517 bool isFirstColumnInRow = !columnIndex;
473 bool isLastColumn = columnIndex == actualColumnCount() - 1; 518 bool isLastColumnInRow = columnIndex == actualColumnCount() - 1;
474 bool isLTR = m_columnSet.style()->isLeftToRightDirection(); 519 bool isLTR = m_columnSet.style()->isLeftToRightDirection();
475 bool isLeftmostColumn = isLTR ? isFirstColumn : isLastColumn; 520 bool isLeftmostColumn = isLTR ? isFirstColumnInRow : isLastColumnInRow;
476 bool isRightmostColumn = isLTR ? isLastColumn : isFirstColumn; 521 bool isRightmostColumn = isLTR ? isLastColumnInRow : isFirstColumnInRow;
477 522
478 LayoutRect portionRect = flowThreadPortionRectAt(columnIndex); 523 LayoutRect portionRect = flowThreadPortionRectAt(columnIndex);
524 bool isFirstColumnInMulticolContainer = isFirstColumnInRow && this == &m_col umnSet.firstFragmentainerGroup() && !m_columnSet.previousSiblingMultiColumnSet() ;
525 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 526 // Calculate the overflow rectangle, based on the flow thread's, clipped at column logical
480 // top/bottom unless it's the first/last column. 527 // 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()); 528 LayoutRect overflowRect = m_columnSet.overflowRectForFlowThreadPortion(porti onRect, isFirstColumnInMulticolContainer, isLastColumnInMulticolContainer);
482 529
483 // Avoid overflowing into neighboring columns, by clipping in the middle of adjacent column 530 // Avoid overflowing into neighboring columns, by clipping in the middle of adjacent column
484 // gaps. Also make sure that we avoid rounding errors. 531 // gaps. Also make sure that we avoid rounding errors.
485 LayoutUnit columnGap = m_columnSet.columnGap(); 532 LayoutUnit columnGap = m_columnSet.columnGap();
486 if (m_columnSet.isHorizontalWritingMode()) { 533 if (m_columnSet.isHorizontalWritingMode()) {
487 if (!isLeftmostColumn) 534 if (!isLeftmostColumn)
488 overflowRect.shiftXEdgeTo(portionRect.x() - columnGap / 2); 535 overflowRect.shiftXEdgeTo(portionRect.x() - columnGap / 2);
489 if (!isRightmostColumn) 536 if (!isRightmostColumn)
490 overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap - column Gap / 2); 537 overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap - column Gap / 2);
491 } else { 538 } else {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
586 append(MultiColumnFragmentainerGroup(m_columnSet)); 633 append(MultiColumnFragmentainerGroup(m_columnSet));
587 return last(); 634 return last();
588 } 635 }
589 636
590 void MultiColumnFragmentainerGroupList::deleteExtraGroups() 637 void MultiColumnFragmentainerGroupList::deleteExtraGroups()
591 { 638 {
592 shrink(1); 639 shrink(1);
593 } 640 }
594 641
595 } // namespace blink 642 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/layout/MultiColumnFragmentainerGroup.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698