Index: third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp |
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp |
index 97baaabca2d756ceb2d1776496e7c67f0d518d3c..58932b0e1db3c1992a61a5eb95b5df9d767b9e3f 100644 |
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp |
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp |
@@ -31,6 +31,7 @@ |
#include "core/layout/LayoutBlockFlow.h" |
#include "core/dom/AXObjectCache.h" |
+#include "core/editing/Editor.h" |
#include "core/frame/FrameView.h" |
#include "core/frame/LocalFrame.h" |
#include "core/frame/Settings.h" |
@@ -3180,6 +3181,106 @@ bool LayoutBlockFlow::recalcInlineChildrenOverflowAfterStyleChange() |
return childrenOverflowChanged; |
} |
+PositionWithAffinity LayoutBlockFlow::positionForPoint(const LayoutPoint& point) |
+{ |
+ if (isAtomicInlineLevel()) { |
+ PositionWithAffinity position = positionForPointIfOutsideAtomicInlineLevel(point); |
+ if (!position.isNull()) |
+ return position; |
+ } |
+ if (!childrenInline()) |
+ return LayoutBlock::positionForPoint(point); |
+ |
+ LayoutPoint pointInContents = point; |
+ offsetForContents(pointInContents); |
+ LayoutPoint pointInLogicalContents(pointInContents); |
+ if (!isHorizontalWritingMode()) |
+ pointInLogicalContents = pointInLogicalContents.transposedPoint(); |
+ |
+ if (!firstRootBox()) |
+ return createPositionWithAffinity(0); |
+ |
+ bool linesAreFlipped = style()->isFlippedLinesWritingMode(); |
+ bool blocksAreFlipped = style()->isFlippedBlocksWritingMode(); |
+ |
+ // look for the closest line box in the root box which is at the passed-in y coordinate |
+ InlineBox* closestBox = nullptr; |
+ RootInlineBox* firstRootBoxWithChildren = nullptr; |
+ RootInlineBox* lastRootBoxWithChildren = nullptr; |
+ for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) { |
+ if (!root->firstLeafChild()) |
+ continue; |
+ if (!firstRootBoxWithChildren) |
+ firstRootBoxWithChildren = root; |
+ |
+ if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading() |
+ || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading()))) |
+ break; |
+ |
+ lastRootBoxWithChildren = root; |
+ |
+ // check if this root line box is located at this y coordinate |
+ if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) { |
+ if (linesAreFlipped) { |
+ RootInlineBox* nextRootBoxWithChildren = root->nextRootBox(); |
+ while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild()) |
+ nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox(); |
+ |
+ if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading() |
+ || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading()))) |
+ continue; |
+ } |
+ closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x()); |
+ if (closestBox) |
+ break; |
+ } |
+ } |
+ |
+ bool moveCaretToBoundary = document().frame()->editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom(); |
+ |
+ if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) { |
+ // y coordinate is below last root line box, pretend we hit it |
+ closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x()); |
+ } |
+ |
+ if (closestBox) { |
+ if (moveCaretToBoundary) { |
+ LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop()); |
+ if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop |
+ || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) { |
+ InlineBox* box = firstRootBoxWithChildren->firstLeafChild(); |
+ if (box->isLineBreak()) { |
+ if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak()) |
+ box = newBox; |
+ } |
+ // y coordinate is above first root line box, so return the start of the first |
+ return PositionWithAffinity(positionForBox(box, true)); |
+ } |
+ } |
+ |
+ // pass the box a top position that is inside it |
+ LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine()); |
+ if (!isHorizontalWritingMode()) |
+ point = point.transposedPoint(); |
+ if (closestBox->getLineLayoutItem().isAtomicInlineLevel()) |
+ return positionForPointRespectingEditingBoundaries(LineLayoutBox(closestBox->getLineLayoutItem()), point); |
+ return closestBox->getLineLayoutItem().positionForPoint(point); |
+ } |
+ |
+ if (lastRootBoxWithChildren) { |
+ // We hit this case for Mac behavior when the Y coordinate is below the last box. |
+ ASSERT(moveCaretToBoundary); |
+ InlineBox* logicallyLastBox; |
+ if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox)) |
+ return PositionWithAffinity(positionForBox(logicallyLastBox, false)); |
+ } |
+ |
+ // Can't reach this. We have a root line box, but it has no kids. |
+ // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text |
+ // seems to hit this code path. |
+ return createPositionWithAffinity(0); |
+} |
+ |
#ifndef NDEBUG |
void LayoutBlockFlow::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const LayoutObject* obj) const |