Commit 6cd9f0d1 authored by Xiaocheng Hu's avatar Xiaocheng Hu Committed by Commit Bot

[LayoutNG] Split ng_caret_position.h/cc off ng_caret_rect.h/cc

The current ng_caret_rect.h/cc contains two different parts:
1. Computation of NGCaretPosition
2. Conversion from NGCaretPosition to LocalCaretRect

The two parts are very different that, NGCaretPosition is a building
block of other Layout NG components (e.g., ng_line_utils), while
LocalCaretRect is only passed to legacy.

For better code health, this patch splits them into different files.

Bug: 822575
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_layout_ng
Change-Id: I1dbc1b683d54c2f066cf84c21e7388bb07f8e3f1
Reviewed-on: https://chromium-review.googlesource.com/1014800Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#551249}
parent 841cd74f
...@@ -1911,7 +1911,7 @@ jumbo_source_set("unit_tests") { ...@@ -1911,7 +1911,7 @@ jumbo_source_set("unit_tests") {
"layout/ng/geometry/ng_physical_offset_rect_test.cc", "layout/ng/geometry/ng_physical_offset_rect_test.cc",
"layout/ng/geometry/ng_physical_offset_test.cc", "layout/ng/geometry/ng_physical_offset_test.cc",
"layout/ng/geometry/ng_physical_rect_test.cc", "layout/ng/geometry/ng_physical_rect_test.cc",
"layout/ng/inline/ng_caret_rect_test.cc", "layout/ng/inline/ng_caret_position_test.cc",
"layout/ng/inline/ng_inline_fragment_traversal_test.cc", "layout/ng/inline/ng_inline_fragment_traversal_test.cc",
"layout/ng/inline/ng_inline_items_builder_test.cc", "layout/ng/inline/ng_inline_items_builder_test.cc",
"layout/ng/inline/ng_inline_layout_algorithm_test.cc", "layout/ng/inline/ng_inline_layout_algorithm_test.cc",
......
...@@ -318,6 +318,8 @@ blink_core_sources("layout") { ...@@ -318,6 +318,8 @@ blink_core_sources("layout") {
"ng/inline/ng_baseline.h", "ng/inline/ng_baseline.h",
"ng/inline/ng_bidi_paragraph.cc", "ng/inline/ng_bidi_paragraph.cc",
"ng/inline/ng_bidi_paragraph.h", "ng/inline/ng_bidi_paragraph.h",
"ng/inline/ng_caret_position.cc",
"ng/inline/ng_caret_position.h",
"ng/inline/ng_caret_rect.cc", "ng/inline/ng_caret_rect.cc",
"ng/inline/ng_caret_rect.h", "ng/inline/ng_caret_rect.h",
"ng/inline/ng_inline_box_state.cc", "ng/inline/ng_inline_box_state.cc",
......
// Copyright 2018 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 "third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h"
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.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/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h"
namespace blink {
namespace {
void AssertValidPositionForCaretPositionComputation(
const PositionWithAffinity& position) {
#if DCHECK_IS_ON()
DCHECK(NGOffsetMapping::AcceptsPosition(position.GetPosition()));
const LayoutObject* layout_object = position.AnchorNode()->GetLayoutObject();
DCHECK(layout_object);
DCHECK(layout_object->IsText() || layout_object->IsAtomicInlineLevel());
#endif
}
// The calculation takes the following input:
// - An inline formatting context as a |LayoutBlockFlow|
// - An offset in the |text_content_| string of the above context
// - A TextAffinity
//
// The calculation iterates all inline fragments in the context, and tries to
// compute an NGCaretPosition using the "caret resolution process" below:
//
// The (offset, affinity) pair is compared against each inline fragment to see
// if the corresponding caret should be placed in the fragment, using the
// |TryResolveCaretPositionInXXX()| functions. These functions may return:
// - Failed, indicating that the caret must not be placed in the fragment;
// - Resolved, indicating that the care should be placed in the fragment, and
// no further search is required. The result NGCaretPosition is returned
// together.
// - FoundCandidate, indicating that the caret may be placed in the fragment;
// however, further search may find a better position. The candidate
// NGCaretPosition is also returned together.
enum class ResolutionType { kFailed, kFoundCandidate, kResolved };
struct CaretPositionResolution {
ResolutionType type = ResolutionType::kFailed;
NGCaretPosition caret_position;
};
bool CanResolveCaretPositionBeforeFragment(const NGPaintFragment& fragment,
TextAffinity affinity) {
if (affinity == TextAffinity::kDownstream)
return true;
const NGPaintFragment* current_line_paint = fragment.ContainerLineBox();
const NGPhysicalLineBoxFragment& current_line =
ToNGPhysicalLineBoxFragment(current_line_paint->PhysicalFragment());
// A fragment after line wrap must be the first logical leaf in its line.
if (&fragment.PhysicalFragment() != current_line.FirstLogicalLeaf())
return true;
const NGPaintFragment* last_line_paint =
NGPaintFragmentTraversal::PreviousLineOf(*current_line_paint);
return !last_line_paint ||
!ToNGPhysicalLineBoxFragment(last_line_paint->PhysicalFragment())
.HasSoftWrapToNextLine();
}
bool CanResolveCaretPositionAfterFragment(const NGPaintFragment& fragment,
TextAffinity affinity) {
if (affinity == TextAffinity::kUpstream)
return true;
const NGPaintFragment* current_line_paint = fragment.ContainerLineBox();
const NGPhysicalLineBoxFragment& current_line =
ToNGPhysicalLineBoxFragment(current_line_paint->PhysicalFragment());
// A fragment before line wrap must be the last logical leaf in its line.
if (&fragment.PhysicalFragment() != current_line.LastLogicalLeaf())
return true;
return !current_line.HasSoftWrapToNextLine();
}
CaretPositionResolution TryResolveCaretPositionInTextFragment(
const NGPaintFragment& paint_fragment,
unsigned offset,
TextAffinity affinity) {
DCHECK(paint_fragment.PhysicalFragment().IsText());
const NGPhysicalTextFragment& fragment =
ToNGPhysicalTextFragment(paint_fragment.PhysicalFragment());
if (fragment.IsAnonymousText())
return CaretPositionResolution();
// [StartOffset(), EndOffset()] is the range allowing caret placement.
// For example, "foo" has 4 offsets allowing caret placement.
if (offset < fragment.StartOffset() || offset > fragment.EndOffset()) {
// TODO(xiaochengh): This may introduce false negatives. Investigate.
return CaretPositionResolution();
}
NGCaretPosition candidate = {&paint_fragment,
NGCaretPositionType::kAtTextOffset, offset};
// Offsets in the interior of a fragment can be resolved directly.
if (offset > fragment.StartOffset() && offset < fragment.EndOffset())
return {ResolutionType::kResolved, candidate};
if (offset == fragment.StartOffset() &&
CanResolveCaretPositionBeforeFragment(paint_fragment, affinity)) {
return {ResolutionType::kResolved, candidate};
}
if (offset == fragment.EndOffset() && !fragment.IsLineBreak() &&
CanResolveCaretPositionAfterFragment(paint_fragment, affinity)) {
return {ResolutionType::kResolved, candidate};
}
// We may have a better candidate
return {ResolutionType::kFoundCandidate, candidate};
}
unsigned GetTextOffsetBefore(const NGPhysicalFragment& fragment) {
// TODO(xiaochengh): Design more straightforward way to get text offset of
// atomic inline box.
DCHECK(fragment.IsAtomicInline());
const Node* node = fragment.GetNode();
DCHECK(node);
const Position before_node = Position::BeforeNode(*node);
Optional<unsigned> maybe_offset_before =
NGOffsetMapping::GetFor(before_node)->GetTextContentOffset(before_node);
// We should have offset mapping for atomic inline boxes.
DCHECK(maybe_offset_before.has_value());
return maybe_offset_before.value();
}
CaretPositionResolution TryResolveCaretPositionByBoxFragmentSide(
const NGPaintFragment& fragment,
unsigned offset,
TextAffinity affinity) {
if (!fragment.GetNode()) {
// TODO(xiaochengh): This leads to false negatives for, e.g., RUBY, where an
// anonymous wrapping inline block is created.
return CaretPositionResolution();
}
const unsigned offset_before =
GetTextOffsetBefore(fragment.PhysicalFragment());
const unsigned offset_after = offset_before + 1;
if (offset != offset_before && offset != offset_after)
return CaretPositionResolution();
const NGCaretPositionType position_type =
offset == offset_before ? NGCaretPositionType::kBeforeBox
: NGCaretPositionType::kAfterBox;
NGCaretPosition candidate{&fragment, position_type, WTF::nullopt};
if (offset == offset_before &&
CanResolveCaretPositionBeforeFragment(fragment, affinity)) {
return {ResolutionType::kResolved, candidate};
}
if (offset == offset_after &&
CanResolveCaretPositionAfterFragment(fragment, affinity)) {
return {ResolutionType::kResolved, candidate};
}
return {ResolutionType::kFoundCandidate, candidate};
}
CaretPositionResolution TryResolveCaretPositionWithFragment(
const NGPaintFragment& paint_fragment,
unsigned offset,
TextAffinity affinity) {
const NGPhysicalFragment& fragment = paint_fragment.PhysicalFragment();
if (fragment.IsText()) {
return TryResolveCaretPositionInTextFragment(paint_fragment, offset,
affinity);
}
if (fragment.IsBox() && fragment.IsAtomicInline()) {
return TryResolveCaretPositionByBoxFragmentSide(paint_fragment, offset,
affinity);
}
return CaretPositionResolution();
}
} // namespace
// The main function for compute an NGCaretPosition. See the comments at the top
// of this file for details.
NGCaretPosition ComputeNGCaretPosition(const LayoutBlockFlow& context,
unsigned offset,
TextAffinity affinity) {
const NGPaintFragment* root_fragment = context.PaintFragment();
DCHECK(root_fragment) << "no paint fragment on layout object " << &context;
NGCaretPosition candidate;
for (const auto& child :
NGPaintFragmentTraversal::InlineDescendantsOf(*root_fragment)) {
const CaretPositionResolution resolution =
TryResolveCaretPositionWithFragment(*child.fragment, offset, affinity);
if (resolution.type == ResolutionType::kFailed)
continue;
// TODO(xiaochengh): Handle caret poisition in empty container (e.g. empty
// line box).
if (resolution.type == ResolutionType::kResolved)
return resolution.caret_position;
DCHECK_EQ(ResolutionType::kFoundCandidate, resolution.type);
// TODO(xiaochengh): We are not sure if we can ever find multiple
// candidates. Handle it once reached.
DCHECK(candidate.IsNull());
candidate = resolution.caret_position;
}
return candidate;
}
NGCaretPosition ComputeNGCaretPosition(const PositionWithAffinity& position) {
AssertValidPositionForCaretPositionComputation(position);
const LayoutBlockFlow* context =
NGInlineFormattingContextOf(position.GetPosition());
if (!context)
return NGCaretPosition();
const NGOffsetMapping* mapping = NGOffsetMapping::GetFor(context);
DCHECK(mapping);
const Optional<unsigned> maybe_offset =
mapping->GetTextContentOffset(position.GetPosition());
if (!maybe_offset.has_value()) {
// TODO(xiaochengh): Investigate if we reach here.
NOTREACHED();
return NGCaretPosition();
}
const unsigned offset = maybe_offset.value();
const TextAffinity affinity = position.Affinity();
return ComputeNGCaretPosition(*context, offset, affinity);
}
} // namespace blink
// Copyright 2018 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.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_CARET_POSITION_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_CARET_POSITION_H_
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink {
class NGPaintFragment;
class LayoutBlockFlow;
// An NGCaretPosition indicates a caret position relative to an inline
// NGPaintFragment:
// - When |fragment| is box, |position_type| is either |kBeforeBox| or
// |kAfterBox|, indicating either of the two caret positions by the box sides;
// |text_offset| is |nullopt| in this case.
// - When |fragment| is text, |position_type| is |kAtTextOffset|, and
// |text_offset| is in the text offset range of the fragment.
//
// TODO(xiaochengh): Support "in empty container" caret type
enum class NGCaretPositionType { kBeforeBox, kAfterBox, kAtTextOffset };
struct NGCaretPosition {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
bool IsNull() const { return !fragment; }
const NGPaintFragment* fragment = nullptr; // owned by root LayoutNGMixin
NGCaretPositionType position_type;
Optional<unsigned> text_offset;
};
// Given an inline formatting context, a text offset in the context and a text
// affinity, returns the corresponding NGCaretPosition, or null if not found.
// Note that in many cases, null result indicates that we have reached an
// unexpected case that is not properly handled.
CORE_EXPORT NGCaretPosition ComputeNGCaretPosition(const LayoutBlockFlow&,
unsigned,
TextAffinity);
// Shorthand of the above when the input is a position instead of a
// (context, offset) pair.
NGCaretPosition ComputeNGCaretPosition(const PositionWithAffinity&);
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_CARET_POSITION_H_
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.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/ng/inline/ng_inline_fragment_traversal.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
namespace blink { namespace blink {
class NGCaretRectTest : public NGLayoutTest { class NGCaretPositionTest : public NGLayoutTest {
public: public:
NGCaretRectTest() : NGLayoutTest() {} NGCaretPositionTest() : NGLayoutTest() {}
void SetUp() override { void SetUp() override {
NGLayoutTest::SetUp(); NGLayoutTest::SetUp();
...@@ -69,7 +69,7 @@ class NGCaretRectTest : public NGLayoutTest { ...@@ -69,7 +69,7 @@ class NGCaretRectTest : public NGLayoutTest {
EXPECT_EQ(caret.text_offset, offset_) << caret.text_offset.value_or(-1); \ EXPECT_EQ(caret.text_offset, offset_) << caret.text_offset.value_or(-1); \
} }
TEST_F(NGCaretRectTest, CaretPositionInOneLineOfText) { TEST_F(NGCaretPositionTest, CaretPositionInOneLineOfText) {
SetInlineFormattingContext("t", "foo", 3); SetInlineFormattingContext("t", "foo", 3);
const Node* text = container_->firstChild(); const Node* text = container_->firstChild();
const NGPhysicalFragment* text_fragment = FragmentOf(text); const NGPhysicalFragment* text_fragment = FragmentOf(text);
...@@ -93,7 +93,7 @@ TEST_F(NGCaretRectTest, CaretPositionInOneLineOfText) { ...@@ -93,7 +93,7 @@ TEST_F(NGCaretRectTest, CaretPositionInOneLineOfText) {
kAtTextOffset, Optional<unsigned>(3)); kAtTextOffset, Optional<unsigned>(3));
} }
TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrap) { TEST_F(NGCaretPositionTest, CaretPositionAtSoftLineWrap) {
SetInlineFormattingContext("t", "foobar", 3); SetInlineFormattingContext("t", "foobar", 3);
const Node* text = container_->firstChild(); const Node* text = container_->firstChild();
const auto text_fragments = NGInlineFragmentTraversal::SelfFragmentsOf( const auto text_fragments = NGInlineFragmentTraversal::SelfFragmentsOf(
...@@ -107,7 +107,7 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrap) { ...@@ -107,7 +107,7 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrap) {
kAtTextOffset, Optional<unsigned>(3)); kAtTextOffset, Optional<unsigned>(3));
} }
TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapWithSpace) { TEST_F(NGCaretPositionTest, CaretPositionAtSoftLineWrapWithSpace) {
SetInlineFormattingContext("t", "foo bar", 3); SetInlineFormattingContext("t", "foo bar", 3);
const Node* text = container_->firstChild(); const Node* text = container_->firstChild();
const auto text_fragments = NGInlineFragmentTraversal::SelfFragmentsOf( const auto text_fragments = NGInlineFragmentTraversal::SelfFragmentsOf(
...@@ -128,7 +128,7 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapWithSpace) { ...@@ -128,7 +128,7 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapWithSpace) {
kAtTextOffset, Optional<unsigned>(4)); kAtTextOffset, Optional<unsigned>(4));
} }
TEST_F(NGCaretRectTest, CaretPositionAtForcedLineBreak) { TEST_F(NGCaretPositionTest, CaretPositionAtForcedLineBreak) {
SetInlineFormattingContext("t", "foo<br>bar", 3); SetInlineFormattingContext("t", "foo<br>bar", 3);
const Node* foo = container_->firstChild(); const Node* foo = container_->firstChild();
const Node* br = foo->nextSibling(); const Node* br = foo->nextSibling();
...@@ -149,7 +149,7 @@ TEST_F(NGCaretRectTest, CaretPositionAtForcedLineBreak) { ...@@ -149,7 +149,7 @@ TEST_F(NGCaretRectTest, CaretPositionAtForcedLineBreak) {
kAtTextOffset, Optional<unsigned>(4)); kAtTextOffset, Optional<unsigned>(4));
} }
TEST_F(NGCaretRectTest, CaretPositionAtEmptyLine) { TEST_F(NGCaretPositionTest, CaretPositionAtEmptyLine) {
SetInlineFormattingContext("f", "foo<br><br>bar", 3); SetInlineFormattingContext("f", "foo<br><br>bar", 3);
const Node* foo = container_->firstChild(); const Node* foo = container_->firstChild();
const Node* br1 = foo->nextSibling(); const Node* br1 = foo->nextSibling();
...@@ -162,7 +162,7 @@ TEST_F(NGCaretRectTest, CaretPositionAtEmptyLine) { ...@@ -162,7 +162,7 @@ TEST_F(NGCaretRectTest, CaretPositionAtEmptyLine) {
kAtTextOffset, Optional<unsigned>(4)); kAtTextOffset, Optional<unsigned>(4));
} }
TEST_F(NGCaretRectTest, CaretPositionInOneLineOfImage) { TEST_F(NGCaretPositionTest, CaretPositionInOneLineOfImage) {
SetInlineFormattingContext("t", "<img>", 3); SetInlineFormattingContext("t", "<img>", 3);
const Node* img = container_->firstChild(); const Node* img = container_->firstChild();
const NGPhysicalFragment* img_fragment = FragmentOf(img); const NGPhysicalFragment* img_fragment = FragmentOf(img);
...@@ -180,7 +180,7 @@ TEST_F(NGCaretRectTest, CaretPositionInOneLineOfImage) { ...@@ -180,7 +180,7 @@ TEST_F(NGCaretRectTest, CaretPositionInOneLineOfImage) {
kAfterBox, WTF::nullopt); kAfterBox, WTF::nullopt);
} }
TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenImages) { TEST_F(NGCaretPositionTest, CaretPositionAtSoftLineWrapBetweenImages) {
SetInlineFormattingContext("t", SetInlineFormattingContext("t",
"<img id=img1><img id=img2>" "<img id=img1><img id=img2>"
"<style>img{width: 1em; height: 1em}</style>", "<style>img{width: 1em; height: 1em}</style>",
...@@ -196,7 +196,8 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenImages) { ...@@ -196,7 +196,8 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenImages) {
kAfterBox, WTF::nullopt); kAfterBox, WTF::nullopt);
} }
TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenMultipleTextNodes) { TEST_F(NGCaretPositionTest,
CaretPositionAtSoftLineWrapBetweenMultipleTextNodes) {
SetInlineFormattingContext("t", SetInlineFormattingContext("t",
"<span>A</span>" "<span>A</span>"
"<span>B</span>" "<span>B</span>"
...@@ -221,7 +222,7 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenMultipleTextNodes) { ...@@ -221,7 +222,7 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenMultipleTextNodes) {
fragment_d, kAtTextOffset, Optional<unsigned>(wrap_offset)); fragment_d, kAtTextOffset, Optional<unsigned>(wrap_offset));
} }
TEST_F(NGCaretRectTest, TEST_F(NGCaretPositionTest,
CaretPositionAtSoftLineWrapBetweenMultipleTextNodesRtl) { CaretPositionAtSoftLineWrapBetweenMultipleTextNodesRtl) {
SetInlineFormattingContext("t", SetInlineFormattingContext("t",
"<span>A</span>" "<span>A</span>"
...@@ -247,7 +248,7 @@ TEST_F(NGCaretRectTest, ...@@ -247,7 +248,7 @@ TEST_F(NGCaretRectTest,
fragment_d, kAtTextOffset, Optional<unsigned>(wrap_offset)); fragment_d, kAtTextOffset, Optional<unsigned>(wrap_offset));
} }
TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenDeepTextNodes) { TEST_F(NGCaretPositionTest, CaretPositionAtSoftLineWrapBetweenDeepTextNodes) {
SetInlineFormattingContext( SetInlineFormattingContext(
"t", "t",
"<style>span {border: 1px solid black}</style>" "<style>span {border: 1px solid black}</style>"
......
...@@ -5,17 +5,13 @@ ...@@ -5,17 +5,13 @@
#ifndef NGCaretRect_h #ifndef NGCaretRect_h
#define NGCaretRect_h #define NGCaretRect_h
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/editing/forward.h" #include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink { namespace blink {
// This file provides utility functions for computing caret rect in LayoutNG. // This file provides utility functions for computing caret rect in LayoutNG.
class NGPaintFragment;
class LayoutBlockFlow;
struct LocalCaretRect; struct LocalCaretRect;
// Given a position with affinity, returns the caret rect if the position is // Given a position with affinity, returns the caret rect if the position is
...@@ -24,39 +20,6 @@ struct LocalCaretRect; ...@@ -24,39 +20,6 @@ struct LocalCaretRect;
// formatting context. // formatting context.
CORE_EXPORT LocalCaretRect ComputeNGLocalCaretRect(const PositionWithAffinity&); CORE_EXPORT LocalCaretRect ComputeNGLocalCaretRect(const PositionWithAffinity&);
// An NGCaretPosition indicates a caret position relative to an inline
// NGPaintFragment:
// - When |fragment| is box, |position_type| is either |kBeforeBox| or
// |kAfterBox|, indicating either of the two caret positions by the box sides;
// |text_offset| is |nullopt| in this case.
// - When |fragment| is text, |position_type| is |kAtTextOffset|, and
// |text_offset| is in the text offset range of the fragment.
//
// TODO(xiaochengh): Support "in empty container" caret type
enum class NGCaretPositionType { kBeforeBox, kAfterBox, kAtTextOffset };
struct NGCaretPosition {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
bool IsNull() const { return !fragment; }
const NGPaintFragment* fragment = nullptr; // owned by root LayoutNGMixin
NGCaretPositionType position_type;
Optional<unsigned> text_offset;
};
// Given an inline formatting context, a text offset in the context and a text
// affinity, returns the corresponding NGCaretPosition, or null if not found.
// Note that in many cases, null result indicates that we have reached an
// unexpected case that is not properly handled.
CORE_EXPORT NGCaretPosition ComputeNGCaretPosition(const LayoutBlockFlow&,
unsigned,
TextAffinity);
// Shorthand of the above when the input is a position instead of a
// (context, offset) pair.
NGCaretPosition ComputeNGCaretPosition(const PositionWithAffinity&);
} // namespace blink } // namespace blink
#endif // NGCaretRect_h #endif // NGCaretRect_h
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include "third_party/blink/renderer/core/editing/position_with_affinity.h" #include "third_party/blink/renderer/core/editing/position_with_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/ng/inline/ng_caret_rect.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h" #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
......
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