Index: third_party/WebKit/Source/core/layout/FragmentainerIterator.cpp |
diff --git a/third_party/WebKit/Source/core/layout/FragmentainerIterator.cpp b/third_party/WebKit/Source/core/layout/FragmentainerIterator.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e7c13ea161b85452edd09e09699de83cc08d91b5 |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/layout/FragmentainerIterator.cpp |
@@ -0,0 +1,133 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "core/layout/FragmentainerIterator.h" |
+ |
+#include "core/layout/LayoutMultiColumnSet.h" |
+ |
+namespace blink { |
+ |
+FragmentainerIterator::FragmentainerIterator(const LayoutFlowThread& flowThread, const LayoutRect& physicalBoundingBoxInFlowThread, const LayoutRect& clipRectInMulticolContainer) |
+ : m_flowThread(flowThread) |
+ , m_clipRectInMulticolContainer(clipRectInMulticolContainer) |
+ , m_currentFragmentainerGroupIndex(0) |
+{ |
+ // Put the bounds into flow thread-local coordinates by flipping it first. This is how |
+ // rectangles typically are represented in layout, i.e. with the block direction coordinate |
+ // flipped, if writing mode is vertical-rl. |
+ LayoutRect boundsInFlowThread = physicalBoundingBoxInFlowThread; |
+ m_flowThread.flipForWritingMode(boundsInFlowThread); |
+ |
+ if (m_flowThread.isHorizontalWritingMode()) { |
+ m_logicalTopInFlowThread = boundsInFlowThread.y(); |
+ m_logicalBottomInFlowThread = boundsInFlowThread.maxY(); |
+ } else { |
+ m_logicalTopInFlowThread = boundsInFlowThread.x(); |
+ m_logicalBottomInFlowThread = boundsInFlowThread.maxX(); |
+ } |
+ |
+ // Jump to the first interesting column set. |
+ m_currentColumnSet = flowThread.columnSetAtBlockOffset(m_logicalTopInFlowThread); |
+ if (!m_currentColumnSet || m_currentColumnSet->logicalTopInFlowThread() >= m_logicalBottomInFlowThread) { |
+ setAtEnd(); |
+ return; |
+ } |
+ // Then find the first interesting fragmentainer group. |
+ m_currentFragmentainerGroupIndex = m_currentColumnSet->fragmentainerGroupIndexAtFlowThreadOffset(m_logicalTopInFlowThread); |
+ |
+ // Now find the first and last fragmentainer we're interested in. We'll also clip against |
+ // the clip rect here. In case the clip rect doesn't intersect with any of the |
+ // fragmentainers, we have to move on to the next fragmentainer group, and see if we find |
+ // something there. |
+ if (!setFragmentainersOfInterest()) { |
+ moveToNextFragmentainerGroup(); |
+ if (atEnd()) |
+ return; |
+ } |
+ |
+ updateOutput(); |
+} |
+ |
+void FragmentainerIterator::advance() |
+{ |
+ DCHECK(!atEnd()); |
+ |
+ if (m_currentFragmentainerIndex < m_endFragmentainerIndex) { |
+ m_currentFragmentainerIndex++; |
+ } else { |
+ // That was the last fragmentainer to visit in this fragmentainer group. Advance to the |
+ // next group. |
+ moveToNextFragmentainerGroup(); |
+ if (atEnd()) |
+ return; |
+ } |
+ updateOutput(); |
+} |
+ |
+const MultiColumnFragmentainerGroup& FragmentainerIterator::currentGroup() const |
+{ |
+ DCHECK(!atEnd()); |
+ return m_currentColumnSet->fragmentainerGroups()[m_currentFragmentainerGroupIndex]; |
+} |
+ |
+void FragmentainerIterator::moveToNextFragmentainerGroup() |
+{ |
+ do { |
+ m_currentFragmentainerGroupIndex++; |
+ if (m_currentFragmentainerGroupIndex >= m_currentColumnSet->fragmentainerGroups().size()) { |
+ // That was the last fragmentainer group in this set. Advance to the next set. |
+ m_currentColumnSet = m_currentColumnSet->nextSiblingMultiColumnSet(); |
+ m_currentFragmentainerGroupIndex = 0; |
+ if (!m_currentColumnSet || m_currentColumnSet->logicalTopInFlowThread() >= m_logicalBottomInFlowThread) { |
+ setAtEnd(); |
+ return; // No more sets or next set out of range. We're done. |
+ } |
+ } |
+ if (currentGroup().logicalTopInFlowThread() >= m_logicalBottomInFlowThread) { |
+ setAtEnd(); // This fragmentainer group doesn't intersect with the range we're interested in. We're done. |
+ return; |
+ } |
+ } while (!setFragmentainersOfInterest()); |
+} |
+ |
+bool FragmentainerIterator::setFragmentainersOfInterest() |
+{ |
+ const MultiColumnFragmentainerGroup& group = currentGroup(); |
+ |
+ // Figure out the start and end fragmentainers for the block range we're interested in. We |
+ // might not have to walk the entire fragmentainer group. |
+ group.columnIntervalForBlockRangeInFlowThread(m_logicalTopInFlowThread, m_logicalBottomInFlowThread, m_currentFragmentainerIndex, m_endFragmentainerIndex); |
+ |
+ // Now intersect with the fragmentainers that actually intersect with the clip rect, to narrow |
+ // it down even further. |
+ unsigned firstFragmentainerInClipRect, lastFragmentainerInClipRect; |
+ group.columnIntervalForVisualRect(m_clipRectInMulticolContainer, firstFragmentainerInClipRect, lastFragmentainerInClipRect); |
+ // If the two fragmentainer intervals are disjoint, there's nothing of interest in this |
+ // fragmentainer group. |
+ if (firstFragmentainerInClipRect > m_endFragmentainerIndex || lastFragmentainerInClipRect < m_currentFragmentainerIndex) |
+ return false; |
+ if (m_currentFragmentainerIndex < firstFragmentainerInClipRect) |
+ m_currentFragmentainerIndex = firstFragmentainerInClipRect; |
+ if (m_endFragmentainerIndex > lastFragmentainerInClipRect) |
+ m_endFragmentainerIndex = lastFragmentainerInClipRect; |
+ DCHECK(m_endFragmentainerIndex >= m_currentFragmentainerIndex); |
+ return true; |
+} |
+ |
+void FragmentainerIterator::updateOutput() |
+{ |
+ const MultiColumnFragmentainerGroup& group = currentGroup(); |
+ |
+ // Set the physical translation offset. |
+ LayoutUnit fragmentainerLogicalTopInFlowThread = group.logicalTopInFlowThread() + m_currentFragmentainerIndex * group.logicalHeight(); |
+ m_paginationOffset = group.flowThreadTranslationAtOffset(fragmentainerLogicalTopInFlowThread, CoordinateSpaceConversion::Visual); |
+ |
+ // Set the overflow clip rect that corresponds to the fragmentainer. |
+ m_clipRectInFlowThread = group.flowThreadPortionOverflowRectAt(m_currentFragmentainerIndex); |
+ |
+ // Flip it into a physical rectangle. |
+ m_flowThread.flipForWritingMode(m_clipRectInFlowThread); |
+} |
+ |
+} // namespace blink |