Commit 00921cf0 authored by Xiaocheng Hu's avatar Xiaocheng Hu Committed by Commit Bot

[LayoutNG] Move PositionForPoint() implementation to paint fragments

This patch moves the NG implementation of PositionForPoint() from
physical fragments to paint fragments as a preparation for
implementing NG hit-testing bidi adjustment (*), which requires
traversal among paint fragments.

(*) crrev.com/c/1064480

Bug: 811502
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_layout_tests_layout_ng;master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: I449ac545e5ccefff5c5b6cbe7988b2f3c9280c4a
Reviewed-on: https://chromium-review.googlesource.com/1067699
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Reviewed-by: default avatarEmil A Eklund <eae@chromium.org>
Cr-Commit-Position: refs/heads/master@{#560849}
parent 3d9122e5
...@@ -128,9 +128,4 @@ bool NGPhysicalLineBoxFragment::HasSoftWrapToNextLine() const { ...@@ -128,9 +128,4 @@ bool NGPhysicalLineBoxFragment::HasSoftWrapToNextLine() const {
return !break_token.IsFinished() && !break_token.IsForcedBreak(); return !break_token.IsFinished() && !break_token.IsForcedBreak();
} }
PositionWithAffinity NGPhysicalLineBoxFragment::PositionForPoint(
const NGPhysicalOffset& point) const {
return PositionForPointInInlineLevelBox(point);
}
} // namespace blink } // namespace blink
...@@ -56,8 +56,6 @@ class CORE_EXPORT NGPhysicalLineBoxFragment final ...@@ -56,8 +56,6 @@ class CORE_EXPORT NGPhysicalLineBoxFragment final
// Whether the content soft-wraps to the next line. // Whether the content soft-wraps to the next line.
bool HasSoftWrapToNextLine() const; bool HasSoftWrapToNextLine() const;
PositionWithAffinity PositionForPoint(const NGPhysicalOffset&) const final;
scoped_refptr<NGPhysicalFragment> CloneWithoutOffset() const { scoped_refptr<NGPhysicalFragment> CloneWithoutOffset() const {
Vector<scoped_refptr<NGPhysicalFragment>> children_copy(children_); Vector<scoped_refptr<NGPhysicalFragment>> children_copy(children_);
return base::AdoptRef(new NGPhysicalLineBoxFragment( return base::AdoptRef(new NGPhysicalLineBoxFragment(
......
...@@ -194,17 +194,6 @@ unsigned NGPhysicalTextFragment::TextOffsetForPoint( ...@@ -194,17 +194,6 @@ unsigned NGPhysicalTextFragment::TextOffsetForPoint(
StartOffset(); StartOffset();
} }
PositionWithAffinity NGPhysicalTextFragment::PositionForPoint(
const NGPhysicalOffset& point) const {
if (IsAnonymousText())
return PositionWithAffinity();
const unsigned text_offset = TextOffsetForPoint(point);
const Position position =
NGOffsetMapping::GetFor(GetLayoutObject())->GetFirstPosition(text_offset);
// TODO(xiaochengh): Adjust TextAffinity.
return PositionWithAffinity(position, TextAffinity::kDownstream);
}
UBiDiLevel NGPhysicalTextFragment::BidiLevel() const { UBiDiLevel NGPhysicalTextFragment::BidiLevel() const {
// TODO(xiaochengh): Make the implementation more efficient with, e.g., // TODO(xiaochengh): Make the implementation more efficient with, e.g.,
// binary search and/or LayoutNGText::InlineItems(). // binary search and/or LayoutNGText::InlineItems().
......
...@@ -142,8 +142,6 @@ class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment { ...@@ -142,8 +142,6 @@ class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
// Returns the text offset in the fragment placed closest to the given point. // Returns the text offset in the fragment placed closest to the given point.
unsigned TextOffsetForPoint(const NGPhysicalOffset&) const; unsigned TextOffsetForPoint(const NGPhysicalOffset&) const;
PositionWithAffinity PositionForPoint(const NGPhysicalOffset&) const override;
UBiDiLevel BidiLevel() const override; UBiDiLevel BidiLevel() const override;
TextDirection ResolvedDirection() const override; TextDirection ResolvedDirection() const override;
......
...@@ -286,11 +286,11 @@ PositionWithAffinity LayoutNGMixin<Base>::PositionForPoint( ...@@ -286,11 +286,11 @@ PositionWithAffinity LayoutNGMixin<Base>::PositionForPoint(
if (!Base::ChildrenInline()) if (!Base::ChildrenInline())
return LayoutBlock::PositionForPoint(point); return LayoutBlock::PositionForPoint(point);
if (!CurrentFragment()) if (!PaintFragment())
return Base::CreatePositionWithAffinity(0); return Base::CreatePositionWithAffinity(0);
const PositionWithAffinity ng_position = const PositionWithAffinity ng_position =
CurrentFragment()->PositionForPoint(NGPhysicalOffset(point)); PaintFragment()->PositionForPoint(NGPhysicalOffset(point));
if (ng_position.IsNotNull()) if (ng_position.IsNotNull())
return ng_position; return ng_position;
return Base::CreatePositionWithAffinity(0); return Base::CreatePositionWithAffinity(0);
......
...@@ -199,14 +199,6 @@ NGPhysicalOffsetRect NGPhysicalBoxFragment::VisualRectWithContents() const { ...@@ -199,14 +199,6 @@ NGPhysicalOffsetRect NGPhysicalBoxFragment::VisualRectWithContents() const {
return visual_rect; return visual_rect;
} }
PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
const NGPhysicalOffset& point) const {
if (!IsBlockFlow())
return PositionForPointInInlineLevelBox(point);
return PositionForPointInInlineFormattingContext(point);
}
UBiDiLevel NGPhysicalBoxFragment::BidiLevel() const { UBiDiLevel NGPhysicalBoxFragment::BidiLevel() const {
// TODO(xiaochengh): Make the implementation more efficient. // TODO(xiaochengh): Make the implementation more efficient.
DCHECK(IsInline()); DCHECK(IsInline());
......
...@@ -60,8 +60,6 @@ class CORE_EXPORT NGPhysicalBoxFragment final ...@@ -60,8 +60,6 @@ class CORE_EXPORT NGPhysicalBoxFragment final
void AddSelfOutlineRects(Vector<LayoutRect>*, void AddSelfOutlineRects(Vector<LayoutRect>*,
const LayoutPoint& additional_offset) const; const LayoutPoint& additional_offset) const;
PositionWithAffinity PositionForPoint(const NGPhysicalOffset&) const override;
UBiDiLevel BidiLevel() const override; UBiDiLevel BidiLevel() const override;
scoped_refptr<NGPhysicalFragment> CloneWithoutOffset() const; scoped_refptr<NGPhysicalFragment> CloneWithoutOffset() const;
......
...@@ -4,54 +4,8 @@ ...@@ -4,54 +4,8 @@
#include "third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h"
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
namespace blink { namespace blink {
namespace {
NGLogicalOffset ChildLogicalOffsetInParent(
const NGPhysicalContainerFragment& parent,
const NGPhysicalFragment& child) {
return child.Offset().ConvertToLogical(parent.Style().GetWritingMode(),
parent.Style().Direction(),
parent.Size(), child.Size());
}
NGLogicalSize ChildLogicalSizeInParent(
const NGPhysicalContainerFragment& parent,
const NGPhysicalFragment& child) {
return NGFragment(parent.Style().GetWritingMode(), child).Size();
}
base::Optional<PositionWithAffinity> PositionForPointInChild(
const NGPhysicalFragment& child,
const NGPhysicalOffset& point) {
const NGPhysicalOffset& child_point = point - child.Offset();
// We must fallback to legacy for old layout roots. We also fallback (to
// LayoutNGMixin::PositionForPoint()) for NG block layout, so that we can
// utilize LayoutBlock::PositionForPoint() that resolves the position in block
// layout.
// TODO(xiaochengh): Don't fallback to legacy for NG block layout.
const PositionWithAffinity result =
(child.IsBlockFlow() || child.IsOldLayoutRoot())
? child.GetLayoutObject()->PositionForPoint(
child_point.ToLayoutPoint())
: child.PositionForPoint(child_point);
if (result.IsNotNull())
return result;
return base::nullopt;
}
} // namespace
NGPhysicalContainerFragment::NGPhysicalContainerFragment( NGPhysicalContainerFragment::NGPhysicalContainerFragment(
LayoutObject* layout_object, LayoutObject* layout_object,
const ComputedStyle& style, const ComputedStyle& style,
...@@ -73,154 +27,4 @@ NGPhysicalContainerFragment::NGPhysicalContainerFragment( ...@@ -73,154 +27,4 @@ NGPhysicalContainerFragment::NGPhysicalContainerFragment(
DCHECK(children.IsEmpty()); // Ensure move semantics is used. DCHECK(children.IsEmpty()); // Ensure move semantics is used.
} }
PositionWithAffinity
NGPhysicalContainerFragment::PositionForPointInInlineLevelBox(
const NGPhysicalOffset& point) const {
DCHECK(IsInline() || IsLineBox()) << ToString();
DCHECK(!IsBlockFlow()) << ToString();
const NGLogicalOffset logical_point = point.ConvertToLogical(
Style().GetWritingMode(), Style().Direction(), Size(), NGPhysicalSize());
const LayoutUnit inline_point = logical_point.inline_offset;
// Stores the closest child before |point| in the inline direction. Used if we
// can't find any child |point| falls in to resolve the position.
const NGPhysicalFragment* closest_child_before = nullptr;
LayoutUnit closest_child_before_inline_offset = LayoutUnit::Min();
// Stores the closest child after |point| in the inline direction. Used if we
// can't find any child |point| falls in to resolve the position.
const NGPhysicalFragment* closest_child_after = nullptr;
LayoutUnit closest_child_after_inline_offset = LayoutUnit::Max();
for (const auto& child : children_) {
const LayoutUnit child_inline_min =
ChildLogicalOffsetInParent(*this, *child).inline_offset;
const LayoutUnit child_inline_max =
child_inline_min + ChildLogicalSizeInParent(*this, *child).inline_size;
// Try to resolve if |point| falls in any child in inline direction.
if (inline_point >= child_inline_min && inline_point <= child_inline_max) {
if (auto child_position = PositionForPointInChild(*child, point))
return child_position.value();
continue;
}
if (inline_point < child_inline_min) {
if (child_inline_min < closest_child_after_inline_offset) {
closest_child_after = child.get();
closest_child_after_inline_offset = child_inline_min;
}
}
if (inline_point > child_inline_max) {
if (child_inline_max > closest_child_before_inline_offset) {
closest_child_before = child.get();
closest_child_before_inline_offset = child_inline_max;
}
}
}
if (closest_child_after) {
if (auto child_position =
PositionForPointInChild(*closest_child_after, point))
return child_position.value();
}
if (closest_child_before) {
if (auto child_position =
PositionForPointInChild(*closest_child_before, point))
return child_position.value();
}
return PositionWithAffinity();
}
PositionWithAffinity
NGPhysicalContainerFragment::PositionForPointInInlineFormattingContext(
const NGPhysicalOffset& point) const {
DCHECK(IsBlockFlow()) << ToString();
DCHECK(IsBox()) << ToString();
DCHECK(ToNGPhysicalBoxFragment(this)->ChildrenInline()) << ToString();
const NGLogicalOffset logical_point = point.ConvertToLogical(
Style().GetWritingMode(), Style().Direction(), Size(), NGPhysicalSize());
const LayoutUnit block_point = logical_point.block_offset;
// Stores the closest line box child above |point| in the block direction.
// Used if we can't find any child |point| falls in to resolve the position.
const NGPhysicalLineBoxFragment* closest_line_before = nullptr;
LayoutUnit closest_line_before_block_offset = LayoutUnit::Min();
// Stores the closest line box child below |point| in the block direction.
// Used if we can't find any child |point| falls in to resolve the position.
const NGPhysicalLineBoxFragment* closest_line_after = nullptr;
LayoutUnit closest_line_after_block_offset = LayoutUnit::Max();
for (const auto& child : children_) {
// Try to resolve if |point| falls in a non-line-box child completely.
if (!child->IsLineBox()) {
if (point.left >= child->Offset().left &&
point.left <= child->Offset().left + child->Size().width &&
point.top >= child->Offset().top &&
point.top <= child->Offset().top + child->Size().height) {
if (auto child_position = PositionForPointInChild(*child, point))
return child_position.value();
}
continue;
}
if (!child->IsLineBox() ||
ToNGPhysicalLineBoxFragment(*child).Children().IsEmpty())
continue;
const LayoutUnit line_min =
ChildLogicalOffsetInParent(*this, *child).block_offset;
const LayoutUnit line_max =
line_min + ChildLogicalSizeInParent(*this, *child).block_size;
// Try to resolve if |point| falls in a line box in block direction.
// Hitting on line bottom doesn't count, to match legacy behavior.
// TODO(xiaochengh): Consider floats.
if (block_point >= line_min && block_point < line_max) {
if (auto child_position = PositionForPointInChild(*child, point))
return child_position.value();
continue;
}
if (block_point < line_min) {
if (line_min < closest_line_after_block_offset) {
closest_line_after = ToNGPhysicalLineBoxFragment(child.get());
closest_line_after_block_offset = line_min;
}
}
if (block_point >= line_max) {
if (line_max > closest_line_before_block_offset) {
closest_line_before = ToNGPhysicalLineBoxFragment(child.get());
closest_line_before_block_offset = line_max;
}
}
}
if (closest_line_after) {
if (auto child_position =
PositionForPointInChild(*closest_line_after, point))
return child_position.value();
}
if (closest_line_before) {
if (auto child_position =
PositionForPointInChild(*closest_line_before, point))
return child_position.value();
}
// TODO(xiaochengh): Looking at only the closest lines may not be enough,
// when we have multiple lines full of pseudo elements. Fix it.
// TODO(xiaochengh): Consider floats.
return PositionWithAffinity();
}
} // namespace blink } // namespace blink
...@@ -35,11 +35,6 @@ class CORE_EXPORT NGPhysicalContainerFragment : public NGPhysicalFragment { ...@@ -35,11 +35,6 @@ class CORE_EXPORT NGPhysicalContainerFragment : public NGPhysicalFragment {
const NGPhysicalOffsetRect& contents_visual_rect, const NGPhysicalOffsetRect& contents_visual_rect,
scoped_refptr<NGBreakToken> = nullptr); scoped_refptr<NGBreakToken> = nullptr);
PositionWithAffinity PositionForPointInInlineLevelBox(
const NGPhysicalOffset&) const;
PositionWithAffinity PositionForPointInInlineFormattingContext(
const NGPhysicalOffset&) const;
Vector<scoped_refptr<NGPhysicalFragment>> children_; Vector<scoped_refptr<NGPhysicalFragment>> children_;
NGPhysicalOffsetRect contents_visual_rect_; NGPhysicalOffsetRect contents_visual_rect_;
}; };
......
...@@ -184,9 +184,6 @@ class CORE_EXPORT NGPhysicalFragment ...@@ -184,9 +184,6 @@ class CORE_EXPORT NGPhysicalFragment
bool IsPlaced() const { return is_placed_; } bool IsPlaced() const { return is_placed_; }
virtual PositionWithAffinity PositionForPoint(
const NGPhysicalOffset&) const = 0;
// Returns the bidi level of a text or atomic inline fragment. // Returns the bidi level of a text or atomic inline fragment.
virtual UBiDiLevel BidiLevel() const; virtual UBiDiLevel BidiLevel() const;
......
...@@ -5,12 +5,17 @@ ...@@ -5,12 +5,17 @@
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h" #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h" #include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h" #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h" #include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h" #include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
...@@ -50,6 +55,41 @@ NGPhysicalOffsetRect ExpandedSelectionRectForLineBreakIfNeeded( ...@@ -50,6 +55,41 @@ NGPhysicalOffsetRect ExpandedSelectionRectForLineBreakIfNeeded(
expanded_size); expanded_size);
} }
NGLogicalOffset ChildLogicalOffsetInParent(const NGPaintFragment& child) {
DCHECK(child.Parent());
const NGPaintFragment& parent = *child.Parent();
return child.Offset().ConvertToLogical(parent.Style().GetWritingMode(),
parent.Style().Direction(),
parent.Size(), child.Size());
}
NGLogicalSize ChildLogicalSizeInParent(const NGPaintFragment& child) {
DCHECK(child.Parent());
const NGPaintFragment& parent = *child.Parent();
return NGFragment(parent.Style().GetWritingMode(), child.PhysicalFragment())
.Size();
}
base::Optional<PositionWithAffinity> PositionForPointInChild(
const NGPaintFragment& child,
const NGPhysicalOffset& point) {
const NGPhysicalOffset& child_point = point - child.Offset();
// We must fallback to legacy for old layout roots. We also fallback (to
// LayoutNGMixin::PositionForPoint()) for NG block layout, so that we can
// utilize LayoutBlock::PositionForPoint() that resolves the position in block
// layout.
// TODO(xiaochengh): Don't fallback to legacy for NG block layout.
const bool should_fallback = child.PhysicalFragment().IsBlockFlow() ||
child.PhysicalFragment().IsOldLayoutRoot();
const PositionWithAffinity result =
should_fallback ? child.GetLayoutObject()->PositionForPoint(
child_point.ToLayoutPoint())
: child.PositionForPoint(child_point);
if (result.IsNotNull())
return result;
return base::nullopt;
}
} // namespace } // namespace
NGPaintFragment::NGPaintFragment( NGPaintFragment::NGPaintFragment(
...@@ -296,4 +336,181 @@ NGPhysicalOffsetRect NGPaintFragment::ComputeLocalSelectionRect( ...@@ -296,4 +336,181 @@ NGPhysicalOffsetRect NGPaintFragment::ComputeLocalSelectionRect(
return line_break_extended_rect; return line_break_extended_rect;
} }
PositionWithAffinity NGPaintFragment::PositionForPointInText(
const NGPhysicalOffset& point) const {
DCHECK(PhysicalFragment().IsText());
const NGPhysicalTextFragment& text_fragment =
ToNGPhysicalTextFragment(PhysicalFragment());
if (text_fragment.IsAnonymousText())
return PositionWithAffinity();
const unsigned text_offset = text_fragment.TextOffsetForPoint(point);
const Position position =
NGOffsetMapping::GetFor(GetLayoutObject())->GetFirstPosition(text_offset);
// TODO(xiaochengh): Adjust TextAffinity.
return PositionWithAffinity(position, TextAffinity::kDownstream);
}
PositionWithAffinity NGPaintFragment::PositionForPointInInlineLevelBox(
const NGPhysicalOffset& point) const {
DCHECK(PhysicalFragment().IsInline() || PhysicalFragment().IsLineBox());
DCHECK(!PhysicalFragment().IsBlockFlow());
const NGLogicalOffset logical_point = point.ConvertToLogical(
Style().GetWritingMode(), Style().Direction(), Size(), NGPhysicalSize());
const LayoutUnit inline_point = logical_point.inline_offset;
// Stores the closest child before |point| in the inline direction. Used if we
// can't find any child |point| falls in to resolve the position.
const NGPaintFragment* closest_child_before = nullptr;
LayoutUnit closest_child_before_inline_offset = LayoutUnit::Min();
// Stores the closest child after |point| in the inline direction. Used if we
// can't find any child |point| falls in to resolve the position.
const NGPaintFragment* closest_child_after = nullptr;
LayoutUnit closest_child_after_inline_offset = LayoutUnit::Max();
for (const auto& child : Children()) {
const LayoutUnit child_inline_min =
ChildLogicalOffsetInParent(*child).inline_offset;
const LayoutUnit child_inline_max =
child_inline_min + ChildLogicalSizeInParent(*child).inline_size;
// Try to resolve if |point| falls in any child in inline direction.
if (inline_point >= child_inline_min && inline_point <= child_inline_max) {
if (auto child_position = PositionForPointInChild(*child, point))
return child_position.value();
continue;
}
if (inline_point < child_inline_min) {
if (child_inline_min < closest_child_after_inline_offset) {
closest_child_after = child.get();
closest_child_after_inline_offset = child_inline_min;
}
}
if (inline_point > child_inline_max) {
if (child_inline_max > closest_child_before_inline_offset) {
closest_child_before = child.get();
closest_child_before_inline_offset = child_inline_max;
}
}
}
if (closest_child_after) {
if (auto child_position =
PositionForPointInChild(*closest_child_after, point))
return child_position.value();
}
if (closest_child_before) {
if (auto child_position =
PositionForPointInChild(*closest_child_before, point))
return child_position.value();
}
return PositionWithAffinity();
}
PositionWithAffinity NGPaintFragment::PositionForPointInInlineFormattingContext(
const NGPhysicalOffset& point) const {
DCHECK(PhysicalFragment().IsBlockFlow());
DCHECK(PhysicalFragment().IsBox());
DCHECK(ToNGPhysicalBoxFragment(PhysicalFragment()).ChildrenInline());
const NGLogicalOffset logical_point = point.ConvertToLogical(
Style().GetWritingMode(), Style().Direction(), Size(), NGPhysicalSize());
const LayoutUnit block_point = logical_point.block_offset;
// Stores the closest line box child above |point| in the block direction.
// Used if we can't find any child |point| falls in to resolve the position.
const NGPaintFragment* closest_line_before = nullptr;
LayoutUnit closest_line_before_block_offset = LayoutUnit::Min();
// Stores the closest line box child below |point| in the block direction.
// Used if we can't find any child |point| falls in to resolve the position.
const NGPaintFragment* closest_line_after = nullptr;
LayoutUnit closest_line_after_block_offset = LayoutUnit::Max();
for (const auto& child : Children()) {
// Try to resolve if |point| falls in a non-line-box child completely.
if (!child->PhysicalFragment().IsLineBox()) {
if (point.left >= child->Offset().left &&
point.left <= child->Offset().left + child->Size().width &&
point.top >= child->Offset().top &&
point.top <= child->Offset().top + child->Size().height) {
if (auto child_position = PositionForPointInChild(*child, point))
return child_position.value();
}
continue;
}
if (!child->PhysicalFragment().IsLineBox() || child->Children().IsEmpty())
continue;
const LayoutUnit line_min = ChildLogicalOffsetInParent(*child).block_offset;
const LayoutUnit line_max =
line_min + ChildLogicalSizeInParent(*child).block_size;
// Try to resolve if |point| falls in a line box in block direction.
// Hitting on line bottom doesn't count, to match legacy behavior.
// TODO(xiaochengh): Consider floats.
if (block_point >= line_min && block_point < line_max) {
if (auto child_position = PositionForPointInChild(*child, point))
return child_position.value();
continue;
}
if (block_point < line_min) {
if (line_min < closest_line_after_block_offset) {
closest_line_after = child.get();
closest_line_after_block_offset = line_min;
}
}
if (block_point >= line_max) {
if (line_max > closest_line_before_block_offset) {
closest_line_before = child.get();
closest_line_before_block_offset = line_max;
}
}
}
if (closest_line_after) {
if (auto child_position =
PositionForPointInChild(*closest_line_after, point))
return child_position.value();
}
if (closest_line_before) {
if (auto child_position =
PositionForPointInChild(*closest_line_before, point))
return child_position.value();
}
// TODO(xiaochengh): Looking at only the closest lines may not be enough,
// when we have multiple lines full of pseudo elements. Fix it.
// TODO(xiaochengh): Consider floats.
return PositionWithAffinity();
}
PositionWithAffinity NGPaintFragment::PositionForPoint(
const NGPhysicalOffset& point) const {
if (PhysicalFragment().IsText())
return PositionForPointInText(point);
if (PhysicalFragment().IsBlockFlow()) {
// We current fall back to legacy for block formatting contexts, so we
// should reach here only for inline formatting contexts.
// TODO(xiaochengh): Do not fall back.
DCHECK(ToNGPhysicalBoxFragment(PhysicalFragment()).ChildrenInline());
return PositionForPointInInlineFormattingContext(point);
}
DCHECK(PhysicalFragment().IsInline() || PhysicalFragment().IsLineBox());
return PositionForPointInInlineLevelBox(point);
}
} // namespace blink } // namespace blink
...@@ -110,6 +110,10 @@ class CORE_EXPORT NGPaintFragment : public DisplayItemClient, ...@@ -110,6 +110,10 @@ class CORE_EXPORT NGPaintFragment : public DisplayItemClient,
NGPhysicalOffset Offset() const { return PhysicalFragment().Offset(); } NGPhysicalOffset Offset() const { return PhysicalFragment().Offset(); }
NGPhysicalSize Size() const { return PhysicalFragment().Size(); } NGPhysicalSize Size() const { return PhysicalFragment().Size(); }
// Converts the given point, relative to the fragment itself, into a position
// in DOM tree.
PositionWithAffinity PositionForPoint(const NGPhysicalOffset&) const;
// A range of fragments for |FragmentsFor()|. // A range of fragments for |FragmentsFor()|.
class FragmentRange { class FragmentRange {
public: public:
...@@ -182,6 +186,13 @@ class CORE_EXPORT NGPaintFragment : public DisplayItemClient, ...@@ -182,6 +186,13 @@ class CORE_EXPORT NGPaintFragment : public DisplayItemClient,
HashMap<const LayoutObject*, NGPaintFragment*>* first_fragment_map, HashMap<const LayoutObject*, NGPaintFragment*>* first_fragment_map,
HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map); HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map);
// Helps for PositionForPoint() when |this| falls in different categories.
PositionWithAffinity PositionForPointInText(const NGPhysicalOffset&) const;
PositionWithAffinity PositionForPointInInlineFormattingContext(
const NGPhysicalOffset&) const;
PositionWithAffinity PositionForPointInInlineLevelBox(
const NGPhysicalOffset&) const;
// //
// Following fields are computed in the layout phase. // Following fields are computed in the layout phase.
// //
......
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