Commit 90a52001 authored by mstensho's avatar mstensho Committed by Commit bot

Make column snapping optional when translating to flow thread coordinates.

positionForPoint() wants this, but mapAncestorToLocal() requires that no
special behavior be applied.

While this CL doesn't fix bug 663062, it is a prerequisite for fixing it
without breaking existing tests (MulticolWithAbsPosNotContained in
MapCoordinatesTest unit test).

BUG=663062

Review-Url: https://codereview.chromium.org/2590463002
Cr-Commit-Position: refs/heads/master@{#439758}
parent 83f0c618
...@@ -474,8 +474,9 @@ PositionWithAffinity LayoutMultiColumnSet::positionForPoint( ...@@ -474,8 +474,9 @@ PositionWithAffinity LayoutMultiColumnSet::positionForPoint(
// Convert the visual point to a flow thread point. // Convert the visual point to a flow thread point.
const MultiColumnFragmentainerGroup& row = const MultiColumnFragmentainerGroup& row =
fragmentainerGroupAtVisualPoint(point); fragmentainerGroupAtVisualPoint(point);
LayoutPoint flowThreadPoint = LayoutPoint flowThreadPoint = row.visualPointToFlowThreadPoint(
row.visualPointToFlowThreadPoint(point + row.offsetFromColumnSet()); point + row.offsetFromColumnSet(),
MultiColumnFragmentainerGroup::SnapToColumn);
// Then drill into the flow thread, where we'll find the actual content. // Then drill into the flow thread, where we'll find the actual content.
return flowThread()->positionForPoint(flowThreadPoint); return flowThread()->positionForPoint(flowThreadPoint);
} }
......
...@@ -855,6 +855,36 @@ TEST_P(MapCoordinatesTest, MulticolWithBlock) { ...@@ -855,6 +855,36 @@ TEST_P(MapCoordinatesTest, MulticolWithBlock) {
EXPECT_EQ(FloatPoint(10, 120), mappedPoint); EXPECT_EQ(FloatPoint(10, 120), mappedPoint);
} }
TEST_P(MapCoordinatesTest, MulticolWithBlockAbove) {
setBodyInnerHTML(
"<div id='container' style='columns:3; column-gap:0; "
"column-fill:auto; width:300px; height:200px;'>"
" <div id='target' style='margin-top:-50px; height:100px;'></div>"
"</div>");
LayoutBox* target = toLayoutBox(getLayoutObjectByElementId("target"));
LayoutBox* container = toLayoutBox(getLayoutObjectByElementId("container"));
FloatPoint mappedPoint = mapLocalToAncestor(target, container, FloatPoint());
EXPECT_EQ(FloatPoint(0, -50), mappedPoint);
mappedPoint = mapAncestorToLocal(target, container, mappedPoint);
EXPECT_EQ(FloatPoint(), mappedPoint);
// Walk each ancestor in the chain separately, to verify each step on the way.
LayoutBox* flowThread = target->parentBox();
ASSERT_TRUE(flowThread->isLayoutFlowThread());
mappedPoint = mapLocalToAncestor(target, flowThread, FloatPoint());
EXPECT_EQ(FloatPoint(0, -50), mappedPoint);
mappedPoint = mapAncestorToLocal(target, flowThread, mappedPoint);
EXPECT_EQ(FloatPoint(), mappedPoint);
mappedPoint = mapLocalToAncestor(flowThread, container, FloatPoint(0, -50));
EXPECT_EQ(FloatPoint(0, -50), mappedPoint);
mappedPoint = mapAncestorToLocal(flowThread, container, mappedPoint);
EXPECT_EQ(FloatPoint(0, -50), mappedPoint);
}
TEST_P(MapCoordinatesTest, NestedMulticolWithBlock) { TEST_P(MapCoordinatesTest, NestedMulticolWithBlock) {
setBodyInnerHTML( setBodyInnerHTML(
"<div id='outerMulticol' style='columns:2; column-gap:0; " "<div id='outerMulticol' style='columns:2; column-gap:0; "
......
...@@ -181,36 +181,34 @@ LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset( ...@@ -181,36 +181,34 @@ LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(
} }
LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint( LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(
const LayoutPoint& visualPoint) const { const LayoutPoint& visualPoint,
SnapToColumnPolicy snap) const {
unsigned columnIndex = columnIndexAtVisualPoint(visualPoint); unsigned columnIndex = columnIndexAtVisualPoint(visualPoint);
LayoutRect columnRect = columnRectAt(columnIndex); LayoutRect columnRect = columnRectAt(columnIndex);
LayoutPoint localPoint(visualPoint); LayoutPoint localPoint(visualPoint);
localPoint.moveBy(-columnRect.location()); localPoint.moveBy(-columnRect.location());
// Before converting to a flow thread position, if the block direction
// coordinate is outside the column, snap to the bounds of the column, and
// reset the inline direction coordinate to the start position in the column.
// The effect of this is that if the block position is before the column
// rectangle, we'll get to the beginning of this column, while if the block
// position is after the column rectangle, we'll get to the beginning of the
// next column.
if (!m_columnSet.isHorizontalWritingMode()) { if (!m_columnSet.isHorizontalWritingMode()) {
LayoutUnit columnStart = m_columnSet.style()->isLeftToRightDirection() if (snap == SnapToColumn) {
? LayoutUnit() LayoutUnit columnStart = m_columnSet.style()->isLeftToRightDirection()
: columnRect.height(); ? LayoutUnit()
if (localPoint.x() < 0) : columnRect.height();
localPoint = LayoutPoint(LayoutUnit(), columnStart); if (localPoint.x() < 0)
else if (localPoint.x() > logicalHeight()) localPoint = LayoutPoint(LayoutUnit(), columnStart);
localPoint = LayoutPoint(logicalHeight(), columnStart); else if (localPoint.x() > logicalHeight())
localPoint = LayoutPoint(logicalHeight(), columnStart);
}
return LayoutPoint(localPoint.x() + logicalTopInFlowThreadAt(columnIndex), return LayoutPoint(localPoint.x() + logicalTopInFlowThreadAt(columnIndex),
localPoint.y()); localPoint.y());
} }
LayoutUnit columnStart = m_columnSet.style()->isLeftToRightDirection() if (snap == SnapToColumn) {
? LayoutUnit() LayoutUnit columnStart = m_columnSet.style()->isLeftToRightDirection()
: columnRect.width(); ? LayoutUnit()
if (localPoint.y() < 0) : columnRect.width();
localPoint = LayoutPoint(columnStart, LayoutUnit()); if (localPoint.y() < 0)
else if (localPoint.y() > logicalHeight()) localPoint = LayoutPoint(columnStart, LayoutUnit());
localPoint = LayoutPoint(columnStart, logicalHeight()); else if (localPoint.y() > logicalHeight())
localPoint = LayoutPoint(columnStart, logicalHeight());
}
return LayoutPoint(localPoint.x(), return LayoutPoint(localPoint.x(),
localPoint.y() + logicalTopInFlowThreadAt(columnIndex)); localPoint.y() + logicalTopInFlowThreadAt(columnIndex));
} }
......
...@@ -79,8 +79,21 @@ class MultiColumnFragmentainerGroup { ...@@ -79,8 +79,21 @@ class MultiColumnFragmentainerGroup {
LayoutBox::PageBoundaryRule, LayoutBox::PageBoundaryRule,
CoordinateSpaceConversion) const; CoordinateSpaceConversion) const;
LayoutUnit columnLogicalTopForOffset(LayoutUnit offsetInFlowThread) const; LayoutUnit columnLogicalTopForOffset(LayoutUnit offsetInFlowThread) const;
// If SnapToColumnPolicy is SnapToColumn, visualPointToFlowThreadPoint() won't
// return points that lie outside the bounds of the columns: Before converting
// to a flow thread position, if the block direction coordinate is outside the
// column, snap to the bounds of the column, and reset the inline direction
// coordinate to the start position in the column. The effect of this is that
// if the block position is before the column rectangle, we'll get to the
// beginning of this column, while if the block position is after the column
// rectangle, we'll get to the beginning of the next column. This is behavior
// that positionForPoint() depends on.
enum SnapToColumnPolicy { DontSnapToColumn, SnapToColumn };
LayoutPoint visualPointToFlowThreadPoint( LayoutPoint visualPointToFlowThreadPoint(
const LayoutPoint& visualPoint) const; const LayoutPoint& visualPoint,
SnapToColumnPolicy = DontSnapToColumn) const;
LayoutRect fragmentsBoundingBox( LayoutRect fragmentsBoundingBox(
const LayoutRect& boundingBoxInFlowThread) const; const LayoutRect& boundingBoxInFlowThread) const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment