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(
// Convert the visual point to a flow thread point.
const MultiColumnFragmentainerGroup& row =
fragmentainerGroupAtVisualPoint(point);
LayoutPoint flowThreadPoint =
row.visualPointToFlowThreadPoint(point + row.offsetFromColumnSet());
LayoutPoint flowThreadPoint = row.visualPointToFlowThreadPoint(
point + row.offsetFromColumnSet(),
MultiColumnFragmentainerGroup::SnapToColumn);
// Then drill into the flow thread, where we'll find the actual content.
return flowThread()->positionForPoint(flowThreadPoint);
}
......
......@@ -855,6 +855,36 @@ TEST_P(MapCoordinatesTest, MulticolWithBlock) {
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) {
setBodyInnerHTML(
"<div id='outerMulticol' style='columns:2; column-gap:0; "
......
......@@ -181,36 +181,34 @@ LayoutUnit MultiColumnFragmentainerGroup::columnLogicalTopForOffset(
}
LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(
const LayoutPoint& visualPoint) const {
const LayoutPoint& visualPoint,
SnapToColumnPolicy snap) const {
unsigned columnIndex = columnIndexAtVisualPoint(visualPoint);
LayoutRect columnRect = columnRectAt(columnIndex);
LayoutPoint localPoint(visualPoint);
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()) {
LayoutUnit columnStart = m_columnSet.style()->isLeftToRightDirection()
? LayoutUnit()
: columnRect.height();
if (localPoint.x() < 0)
localPoint = LayoutPoint(LayoutUnit(), columnStart);
else if (localPoint.x() > logicalHeight())
localPoint = LayoutPoint(logicalHeight(), columnStart);
if (snap == SnapToColumn) {
LayoutUnit columnStart = m_columnSet.style()->isLeftToRightDirection()
? LayoutUnit()
: columnRect.height();
if (localPoint.x() < 0)
localPoint = LayoutPoint(LayoutUnit(), columnStart);
else if (localPoint.x() > logicalHeight())
localPoint = LayoutPoint(logicalHeight(), columnStart);
}
return LayoutPoint(localPoint.x() + logicalTopInFlowThreadAt(columnIndex),
localPoint.y());
}
LayoutUnit columnStart = m_columnSet.style()->isLeftToRightDirection()
? LayoutUnit()
: columnRect.width();
if (localPoint.y() < 0)
localPoint = LayoutPoint(columnStart, LayoutUnit());
else if (localPoint.y() > logicalHeight())
localPoint = LayoutPoint(columnStart, logicalHeight());
if (snap == SnapToColumn) {
LayoutUnit columnStart = m_columnSet.style()->isLeftToRightDirection()
? LayoutUnit()
: columnRect.width();
if (localPoint.y() < 0)
localPoint = LayoutPoint(columnStart, LayoutUnit());
else if (localPoint.y() > logicalHeight())
localPoint = LayoutPoint(columnStart, logicalHeight());
}
return LayoutPoint(localPoint.x(),
localPoint.y() + logicalTopInFlowThreadAt(columnIndex));
}
......
......@@ -79,8 +79,21 @@ class MultiColumnFragmentainerGroup {
LayoutBox::PageBoundaryRule,
CoordinateSpaceConversion) 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(
const LayoutPoint& visualPoint) const;
const LayoutPoint& visualPoint,
SnapToColumnPolicy = DontSnapToColumn) const;
LayoutRect fragmentsBoundingBox(
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