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

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

Issue 2339973002: Handle exclusive end offsets when translating from flow thread coordinates. (Closed)
Patch Set: Renamed tests, and fixed typos there. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/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 "core/layout/MultiColumnFragmentainerGroup.h" 5 #include "core/layout/MultiColumnFragmentainerGroup.h"
6 6
7 #include "core/layout/ColumnBalancer.h" 7 #include "core/layout/ColumnBalancer.h"
8 #include "core/layout/FragmentationContext.h" 8 #include "core/layout/FragmentationContext.h"
9 #include "core/layout/LayoutMultiColumnSet.h" 9 #include "core/layout/LayoutMultiColumnSet.h"
10 10
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 // columns may have changed as well. 91 // columns may have changed as well.
92 setAndConstrainColumnHeight(m_columnHeight); 92 setAndConstrainColumnHeight(m_columnHeight);
93 } 93 }
94 94
95 if (m_columnHeight == oldColumnHeight) 95 if (m_columnHeight == oldColumnHeight)
96 return false; // No change. We're done. 96 return false; // No change. We're done.
97 97
98 return true; // Need another pass. 98 return true; // Need another pass.
99 } 99 }
100 100
101 LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset(LayoutUn it offsetInFlowThread, CoordinateSpaceConversion mode) const 101 LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset(LayoutUn it offsetInFlowThread, LayoutBox::PageBoundaryRule rule, CoordinateSpaceConversi on mode) const
102 { 102 {
103 LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( ); 103 LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread( );
104 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread); 104
105 // A column out of range doesn't have a flow thread portion, so we need to c lamp to make sure
106 // that we stay within the actual columns. This means that content in the ov erflow area will be
107 // mapped to the last actual column, instead of being mapped to an imaginary column further
108 // ahead.
109 unsigned columnIndex = offsetInFlowThread >= logicalBottomInFlowThread() ? a ctualColumnCount() - 1 : columnIndexAtOffset(offsetInFlowThread, rule);
eae 2016/09/14 22:08:47 Maybe add a DCHECK(actualColumnCount() > 0) before
mstensho (USE GERRIT) 2016/09/15 06:37:50 There are already other actualColumnCount() - 1 ex
110
105 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); 111 LayoutRect portionRect(flowThreadPortionRectAt(columnIndex));
106 flowThread->flipForWritingMode(portionRect); 112 flowThread->flipForWritingMode(portionRect);
107 LayoutRect columnRect(columnRectAt(columnIndex)); 113 LayoutRect columnRect(columnRectAt(columnIndex));
108 m_columnSet.flipForWritingMode(columnRect); 114 m_columnSet.flipForWritingMode(columnRect);
109 LayoutSize translationRelativeToGroup = columnRect.location() - portionRect. location(); 115 LayoutSize translationRelativeToGroup = columnRect.location() - portionRect. location();
110 LayoutSize translationRelativeToFlowThread = translationRelativeToGroup + of fsetFromColumnSet() + m_columnSet.topLeftLocationOffset() - flowThread->topLeftL ocationOffset(); 116 LayoutSize translationRelativeToFlowThread = translationRelativeToGroup + of fsetFromColumnSet() + m_columnSet.topLeftLocationOffset() - flowThread->topLeftL ocationOffset();
111 if (mode == CoordinateSpaceConversion::Containing) 117 if (mode == CoordinateSpaceConversion::Containing)
112 return translationRelativeToFlowThread; 118 return translationRelativeToFlowThread;
113 119
114 LayoutSize enclosingTranslation; 120 LayoutSize enclosingTranslation;
115 if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosing FlowThread()) { 121 if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosing FlowThread()) {
116 const MultiColumnFragmentainerGroup& firstRow = flowThread->firstMultiCo lumnSet()->firstFragmentainerGroup(); 122 const MultiColumnFragmentainerGroup& firstRow = flowThread->firstMultiCo lumnSet()->firstFragmentainerGroup();
117 // Translation that would map points in the coordinate space of the oute rmost flow thread to 123 // Translation that would map points in the coordinate space of the oute rmost flow thread to
118 // visual points in the first column in the first fragmentainer group (r ow) in our multicol 124 // visual points in the first column in the first fragmentainer group (r ow) in our multicol
119 // container. 125 // container.
120 LayoutSize enclosingTranslationOrigin = enclosingFlowThread->flowThreadT ranslationAtOffset(firstRow.blockOffsetInEnclosingFragmentationContext(), mode); 126 LayoutSize enclosingTranslationOrigin = enclosingFlowThread->flowThreadT ranslationAtOffset(firstRow.blockOffsetInEnclosingFragmentationContext(), Layout Box::AssociateWithLatterPage, mode);
121 127
122 // Translation that would map points in the coordinate space of the oute rmost flow thread to 128 // Translation that would map points in the coordinate space of the oute rmost flow thread to
123 // visual points in the first column in this fragmentainer group. 129 // visual points in the first column in this fragmentainer group.
124 enclosingTranslation = enclosingFlowThread->flowThreadTranslationAtOffse t(blockOffsetInEnclosingFragmentationContext(), mode); 130 enclosingTranslation = enclosingFlowThread->flowThreadTranslationAtOffse t(blockOffsetInEnclosingFragmentationContext(), LayoutBox::AssociateWithLatterPa ge, mode);
125 131
126 // What we ultimately return from this method is a translation that maps points in the 132 // What we ultimately return from this method is a translation that maps points in the
127 // coordinate space of our flow thread to a visual point in a certain co lumn in this 133 // coordinate space of our flow thread to a visual point in a certain co lumn in this
128 // fragmentainer group. We had to go all the way up to the outermost flo w thread, since this 134 // fragmentainer group. We had to go all the way up to the outermost flo w thread, since this
129 // fragmentainer group may be in a different outer column than the first outer column that 135 // fragmentainer group may be in a different outer column than the first outer column that
130 // this multicol container lives in. It's the visual distance between th e first 136 // this multicol container lives in. It's the visual distance between th e first
131 // fragmentainer group and this fragmentainer group that we need to add to the translation. 137 // fragmentainer group and this fragmentainer group that we need to add to the translation.
132 enclosingTranslation -= enclosingTranslationOrigin; 138 enclosingTranslation -= enclosingTranslationOrigin;
133 } 139 }
134 140
135 return enclosingTranslation + translationRelativeToFlowThread; 141 return enclosingTranslation + translationRelativeToFlowThread;
136 } 142 }
137 143
138 LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(LayoutUnit o ffsetInFlowThread) const 144 LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(LayoutUnit o ffsetInFlowThread) const
139 { 145 {
140 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread, AssumeNewColu mns); 146 unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread, LayoutBox::As sociateWithLatterPage);
141 return logicalTopInFlowThreadAt(columnIndex); 147 return logicalTopInFlowThreadAt(columnIndex);
142 } 148 }
143 149
144 LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(const La youtPoint& visualPoint) const 150 LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(const La youtPoint& visualPoint) const
145 { 151 {
146 unsigned columnIndex = columnIndexAtVisualPoint(visualPoint); 152 unsigned columnIndex = columnIndexAtVisualPoint(visualPoint);
147 LayoutRect columnRect = columnRectAt(columnIndex); 153 LayoutRect columnRect = columnRectAt(columnIndex);
148 LayoutPoint localPoint(visualPoint); 154 LayoutPoint localPoint(visualPoint);
149 localPoint.moveBy(-columnRect.location()); 155 localPoint.moveBy(-columnRect.location());
150 // Before converting to a flow thread position, if the block direction coord inate is outside the 156 // Before converting to a flow thread position, if the block direction coord inate is outside the
(...skipping 29 matching lines...) Expand all
180 if (boundingBoxLogicalBottom <= logicalTopInFlowThread() || boundingBoxLogic alTop >= logicalBottomInFlowThread()) 186 if (boundingBoxLogicalBottom <= logicalTopInFlowThread() || boundingBoxLogic alTop >= logicalBottomInFlowThread())
181 return LayoutRect(); // The bounding box doesn't intersect this fragment ainer group. 187 return LayoutRect(); // The bounding box doesn't intersect this fragment ainer group.
182 unsigned startColumn; 188 unsigned startColumn;
183 unsigned endColumn; 189 unsigned endColumn;
184 columnIntervalForBlockRangeInFlowThread(boundingBoxLogicalTop, boundingBoxLo gicalBottom, startColumn, endColumn); 190 columnIntervalForBlockRangeInFlowThread(boundingBoxLogicalTop, boundingBoxLo gicalBottom, startColumn, endColumn);
185 191
186 LayoutRect startColumnFlowThreadOverflowPortion = flowThreadPortionOverflowR ectAt(startColumn); 192 LayoutRect startColumnFlowThreadOverflowPortion = flowThreadPortionOverflowR ectAt(startColumn);
187 flowThread->flipForWritingMode(startColumnFlowThreadOverflowPortion); 193 flowThread->flipForWritingMode(startColumnFlowThreadOverflowPortion);
188 LayoutRect startColumnRect(boundingBoxInFlowThread); 194 LayoutRect startColumnRect(boundingBoxInFlowThread);
189 startColumnRect.intersect(startColumnFlowThreadOverflowPortion); 195 startColumnRect.intersect(startColumnFlowThreadOverflowPortion);
190 startColumnRect.move(flowThreadTranslationAtOffset(logicalTopInFlowThreadAt( startColumn), CoordinateSpaceConversion::Containing)); 196 startColumnRect.move(flowThreadTranslationAtOffset(logicalTopInFlowThreadAt( startColumn), LayoutBox::AssociateWithLatterPage, CoordinateSpaceConversion::Con taining));
191 if (startColumn == endColumn) 197 if (startColumn == endColumn)
192 return startColumnRect; // It all takes place in one column. We're done. 198 return startColumnRect; // It all takes place in one column. We're done.
193 199
194 LayoutRect endColumnFlowThreadOverflowPortion = flowThreadPortionOverflowRec tAt(endColumn); 200 LayoutRect endColumnFlowThreadOverflowPortion = flowThreadPortionOverflowRec tAt(endColumn);
195 flowThread->flipForWritingMode(endColumnFlowThreadOverflowPortion); 201 flowThread->flipForWritingMode(endColumnFlowThreadOverflowPortion);
196 LayoutRect endColumnRect(boundingBoxInFlowThread); 202 LayoutRect endColumnRect(boundingBoxInFlowThread);
197 endColumnRect.intersect(endColumnFlowThreadOverflowPortion); 203 endColumnRect.intersect(endColumnFlowThreadOverflowPortion);
198 endColumnRect.move(flowThreadTranslationAtOffset(logicalTopInFlowThreadAt(en dColumn), CoordinateSpaceConversion::Containing)); 204 endColumnRect.move(flowThreadTranslationAtOffset(logicalTopInFlowThreadAt(en dColumn), LayoutBox::AssociateWithLatterPage, CoordinateSpaceConversion::Contain ing));
199 return unionRect(startColumnRect, endColumnRect); 205 return unionRect(startColumnRect, endColumnRect);
200 } 206 }
201 207
202 LayoutRect MultiColumnFragmentainerGroup::calculateOverflow() const 208 LayoutRect MultiColumnFragmentainerGroup::calculateOverflow() const
203 { 209 {
204 // Note that we just return the bounding rectangle of the column boxes here. We currently don't 210 // Note that we just return the bounding rectangle of the column boxes here. We currently don't
205 // examine overflow caused by the actual content that ends up in each column . 211 // examine overflow caused by the actual content that ends up in each column .
206 LayoutRect overflowRect; 212 LayoutRect overflowRect;
207 if (unsigned columnCount = actualColumnCount()) { 213 if (unsigned columnCount = actualColumnCount()) {
208 overflowRect = columnRectAt(0); 214 overflowRect = columnRectAt(0);
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap - column Gap / 2); 384 overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap - column Gap / 2);
379 } else { 385 } else {
380 if (!isLeftmostColumn) 386 if (!isLeftmostColumn)
381 overflowRect.shiftYEdgeTo(portionRect.y() - columnGap / 2); 387 overflowRect.shiftYEdgeTo(portionRect.y() - columnGap / 2);
382 if (!isRightmostColumn) 388 if (!isRightmostColumn)
383 overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + columnGap - column Gap / 2); 389 overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + columnGap - column Gap / 2);
384 } 390 }
385 return overflowRect; 391 return overflowRect;
386 } 392 }
387 393
388 unsigned MultiColumnFragmentainerGroup::columnIndexAtOffset(LayoutUnit offsetInF lowThread, ColumnIndexCalculationMode mode) const 394 unsigned MultiColumnFragmentainerGroup::columnIndexAtOffset(LayoutUnit offsetInF lowThread, LayoutBox::PageBoundaryRule pageBoundaryRule) const
389 { 395 {
390 // Handle the offset being out of range. 396 // Handle the offset being out of range.
391 if (offsetInFlowThread < m_logicalTopInFlowThread) 397 if (offsetInFlowThread < m_logicalTopInFlowThread)
392 return 0; 398 return 0;
393 // If we're laying out right now, we cannot constrain against some logical b ottom, since it 399
394 // isn't known yet. Otherwise, just return the last column if we're past the logical bottom. 400 if (!m_columnHeight)
395 if (mode == ClampToExistingColumns) { 401 return 0;
396 if (offsetInFlowThread >= m_logicalBottomInFlowThread) 402 unsigned columnIndex = ((offsetInFlowThread - m_logicalTopInFlowThread) / m_ columnHeight).floor();
397 return actualColumnCount() - 1; 403 if (pageBoundaryRule == LayoutBox::AssociateWithFormerPage
404 && columnIndex > 0 && logicalTopInFlowThreadAt(columnIndex) == offsetInF lowThread) {
405 // We are exactly at a column boundary, and we've been told to associate offsets at column
406 // boundaries with the former column, not the latter.
407 columnIndex--;
398 } 408 }
399 409 return columnIndex;
400 if (m_columnHeight)
401 return ((offsetInFlowThread - m_logicalTopInFlowThread) / m_columnHeight ).floor();
402 return 0;
403 } 410 }
404 411
405 unsigned MultiColumnFragmentainerGroup::columnIndexAtVisualPoint(const LayoutPoi nt& visualPoint) const 412 unsigned MultiColumnFragmentainerGroup::columnIndexAtVisualPoint(const LayoutPoi nt& visualPoint) const
406 { 413 {
407 bool isColumnProgressionInline = m_columnSet.multiColumnFlowThread()->progre ssionIsInline(); 414 bool isColumnProgressionInline = m_columnSet.multiColumnFlowThread()->progre ssionIsInline();
408 bool isHorizontalWritingMode = m_columnSet.isHorizontalWritingMode(); 415 bool isHorizontalWritingMode = m_columnSet.isHorizontalWritingMode();
409 LayoutUnit columnLengthInColumnProgressionDirection = isColumnProgressionInl ine ? m_columnSet.pageLogicalWidth() : logicalHeight(); 416 LayoutUnit columnLengthInColumnProgressionDirection = isColumnProgressionInl ine ? m_columnSet.pageLogicalWidth() : logicalHeight();
410 LayoutUnit offsetInColumnProgressionDirection = isHorizontalWritingMode == i sColumnProgressionInline ? visualPoint.x() : visualPoint.y(); 417 LayoutUnit offsetInColumnProgressionDirection = isHorizontalWritingMode == i sColumnProgressionInline ? visualPoint.x() : visualPoint.y();
411 if (!m_columnSet.style()->isLeftToRightDirection() && isColumnProgressionInl ine) 418 if (!m_columnSet.style()->isLeftToRightDirection() && isColumnProgressionInl ine)
412 offsetInColumnProgressionDirection = m_columnSet.logicalWidth() - offset InColumnProgressionDirection; 419 offsetInColumnProgressionDirection = m_columnSet.logicalWidth() - offset InColumnProgressionDirection;
413 LayoutUnit columnGap = m_columnSet.columnGap(); 420 LayoutUnit columnGap = m_columnSet.columnGap();
414 if (columnLengthInColumnProgressionDirection + columnGap <= 0) 421 if (columnLengthInColumnProgressionDirection + columnGap <= 0)
415 return 0; 422 return 0;
416 // Column boundaries are in the middle of the column gap. 423 // Column boundaries are in the middle of the column gap.
417 int index = ((offsetInColumnProgressionDirection + columnGap / 2) / (columnL engthInColumnProgressionDirection + columnGap)).toInt(); 424 int index = ((offsetInColumnProgressionDirection + columnGap / 2) / (columnL engthInColumnProgressionDirection + columnGap)).toInt();
418 if (index < 0) 425 if (index < 0)
419 return 0; 426 return 0;
420 return std::min(unsigned(index), actualColumnCount() - 1); 427 return std::min(unsigned(index), actualColumnCount() - 1);
421 } 428 }
422 429
423 void MultiColumnFragmentainerGroup::columnIntervalForBlockRangeInFlowThread(Layo utUnit logicalTopInFlowThread, LayoutUnit logicalBottomInFlowThread, unsigned& f irstColumn, unsigned& lastColumn) const 430 void MultiColumnFragmentainerGroup::columnIntervalForBlockRangeInFlowThread(Layo utUnit logicalTopInFlowThread, LayoutUnit logicalBottomInFlowThread, unsigned& f irstColumn, unsigned& lastColumn) const
424 { 431 {
432 logicalTopInFlowThread = std::max(logicalTopInFlowThread, this->logicalTopIn FlowThread());
433 logicalBottomInFlowThread = std::min(logicalBottomInFlowThread, this->logica lBottomInFlowThread());
425 ASSERT(logicalTopInFlowThread <= logicalBottomInFlowThread); 434 ASSERT(logicalTopInFlowThread <= logicalBottomInFlowThread);
426 firstColumn = columnIndexAtOffset(logicalTopInFlowThread); 435 firstColumn = columnIndexAtOffset(logicalTopInFlowThread, LayoutBox::Associa teWithLatterPage);
427 lastColumn = columnIndexAtOffset(logicalBottomInFlowThread); 436 lastColumn = columnIndexAtOffset(logicalBottomInFlowThread, LayoutBox::Assoc iateWithFormerPage);
428 // logicalBottomInFlowThread is an exclusive endpoint, so some additional ad justments may be necessary.
429 if (lastColumn > firstColumn && logicalTopInFlowThreadAt(lastColumn) == logi calBottomInFlowThread)
430 lastColumn--;
431 } 437 }
432 438
433 void MultiColumnFragmentainerGroup::columnIntervalForVisualRect(const LayoutRect & rect, unsigned& firstColumn, unsigned& lastColumn) const 439 void MultiColumnFragmentainerGroup::columnIntervalForVisualRect(const LayoutRect & rect, unsigned& firstColumn, unsigned& lastColumn) const
434 { 440 {
435 bool isColumnProgressionInline = m_columnSet.multiColumnFlowThread()->progre ssionIsInline(); 441 bool isColumnProgressionInline = m_columnSet.multiColumnFlowThread()->progre ssionIsInline();
436 bool isFlippedColumnProgression = !m_columnSet.style()->isLeftToRightDirecti on() && isColumnProgressionInline; 442 bool isFlippedColumnProgression = !m_columnSet.style()->isLeftToRightDirecti on() && isColumnProgressionInline;
437 if (m_columnSet.isHorizontalWritingMode() == isColumnProgressionInline) { 443 if (m_columnSet.isHorizontalWritingMode() == isColumnProgressionInline) {
438 if (isFlippedColumnProgression) { 444 if (isFlippedColumnProgression) {
439 firstColumn = columnIndexAtVisualPoint(rect.maxXMinYCorner()); 445 firstColumn = columnIndexAtVisualPoint(rect.maxXMinYCorner());
440 lastColumn = columnIndexAtVisualPoint(rect.minXMinYCorner()); 446 lastColumn = columnIndexAtVisualPoint(rect.minXMinYCorner());
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 append(MultiColumnFragmentainerGroup(m_columnSet)); 480 append(MultiColumnFragmentainerGroup(m_columnSet));
475 return last(); 481 return last();
476 } 482 }
477 483
478 void MultiColumnFragmentainerGroupList::deleteExtraGroups() 484 void MultiColumnFragmentainerGroupList::deleteExtraGroups()
479 { 485 {
480 shrink(1); 486 shrink(1);
481 } 487 }
482 488
483 } // namespace blink 489 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698