Commit 92f0dff9 authored by Yoshifumi Inoue's avatar Yoshifumi Inoue Committed by Commit Bot

Paint selection with NGFragmentItem

This patch implements |NGFragmentItem| version of selection painting by using
|NGInlineCursor| to share logic with |NGPaintFragment| version.

Bug: 982194
Change-Id: I44bd0e1b93db611fb03459179dda0bf5d350167d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1832843
Commit-Queue: Yoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Auto-Submit: Yoshifumi Inoue <yosin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#704984}
parent 4540534e
......@@ -1246,8 +1246,8 @@ void FrameSelection::ClearDocumentCachedRange() {
}
LayoutSelectionStatus FrameSelection::ComputeLayoutSelectionStatus(
const NGPaintFragment& text_fragment) const {
return layout_selection_->ComputeSelectionStatus(text_fragment);
const NGInlineCursor& cursor) const {
return layout_selection_->ComputeSelectionStatus(cursor);
}
bool FrameSelection::IsDirectional() const {
......
......@@ -50,7 +50,7 @@ class LocalFrame;
class FrameCaret;
class GranularityStrategy;
class GraphicsContext;
class NGPaintFragment;
class NGInlineCursor;
class Range;
class SelectionEditor;
class LayoutSelection;
......@@ -69,7 +69,7 @@ enum class CaretVisibility;
enum class HandleVisibility { kNotVisible, kVisible };
enum class SelectSoftLineBreak { kNotSelected, kSelected };
// This is return type of ComputeLayoutSelectionStatus(paintfragment).
// This is return type of ComputeLayoutSelectionStatus(cursor).
// This structure represents how the fragment is selected.
// |start|, |end| : Selection start/end offset. This offset is based on
// the text of NGInlineNode of a parent block thus
......@@ -281,7 +281,7 @@ class CORE_EXPORT FrameSelection final
LayoutTextSelectionStatus ComputeLayoutSelectionStatus(
const LayoutText& text) const;
LayoutSelectionStatus ComputeLayoutSelectionStatus(
const NGPaintFragment&) const;
const NGInlineCursor& cursor) const;
void Trace(Visitor*) override;
......
......@@ -33,11 +33,12 @@
#include "third_party/blink/renderer/core/layout/layout_text.h"
#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.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/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
......@@ -118,6 +119,13 @@ enum class SelectionMode {
kBlockCursor,
};
void LayoutSelection::AssertIsValid() const {
const Document& document = frame_selection_->GetDocument();
DCHECK_GE(document.Lifecycle().GetState(), DocumentLifecycle::kLayoutClean);
DCHECK(!document.IsSlotAssignmentOrLegacyDistributionDirty());
DCHECK(!has_pending_selection_);
}
static SelectionMode ComputeSelectionMode(
const FrameSelection& frame_selection) {
const SelectionInDOMTree& selection_in_dom =
......@@ -549,49 +557,11 @@ static SelectionPaintRange* ComputeNewPaintRange(
*paint_range.start_node, start_offset, *paint_range.end_node, end_offset);
}
// ClampOffset modifies |offset| fixed in a range of |text_fragment| start/end
// offsets.
static unsigned ClampOffset(unsigned offset,
const NGPhysicalTextFragment& text_fragment) {
return std::min(std::max(offset, text_fragment.StartOffset()),
text_fragment.EndOffset());
}
// We don't paint a line break the end of inline-block
// because if an inline-block is at the middle of line, we should not paint
// a line break.
// Old layout paints line break if the inline-block is at the end of line, but
// since its complex to determine if the inline-block is at the end of line on NG,
// we just cancels block-end line break painting for any inline-block.
static bool IsLastLineInInlineBlock(const NGPaintFragment& line) {
DCHECK(line.PhysicalFragment().IsLineBox());
NGPaintFragment* parent = line.Parent();
if (!parent->PhysicalFragment().IsAtomicInline())
return false;
return &parent->Children().back() == &line;
}
static bool IsBeforeSoftLineBreak(const NGPaintFragment& fragment) {
if (To<NGPhysicalTextFragment>(fragment.PhysicalFragment()).IsLineBreak())
return false;
// TODO(yoichio): InlineBlock should not be container line box.
// See paint/selection/text-selection-inline-block.html.
const NGPaintFragment* container_line_box = fragment.ContainerLineBox();
DCHECK(container_line_box);
if (IsLastLineInInlineBlock(*container_line_box))
return false;
const auto& physical_line_box =
To<NGPhysicalLineBoxFragment>(container_line_box->PhysicalFragment());
const NGPhysicalFragment* last_leaf = physical_line_box.LastLogicalLeaf();
DCHECK(last_leaf);
if (&fragment.PhysicalFragment() != last_leaf)
return false;
// Even If |fragment| is before linebreak, if its direction differs to line
// direction, we don't paint line break. See
// paint/selection/text-selection-newline-mixed-ltr-rtl.html.
return physical_line_box.BaseDirection() ==
fragment.PhysicalFragment().ResolvedDirection();
unsigned start_offset,
unsigned end_offset) {
DCHECK_LE(start_offset, end_offset);
return std::min(std::max(offset, start_offset), end_offset);
}
static Text* AssociatedTextNode(const LayoutText& text) {
......@@ -613,6 +583,12 @@ static SelectionState GetSelectionStateFor(const LayoutText& layout_text) {
return layout_text.GetSelectionState();
}
static SelectionState GetSelectionStateFor(const NGInlineCursor& cursor) {
DCHECK(cursor.CurrentLayoutObject() &&
cursor.CurrentLayoutObject()->IsText());
return GetSelectionStateFor(ToLayoutText(*cursor.CurrentLayoutObject()));
}
bool LayoutSelection::IsSelected(const LayoutObject& layout_object) {
if (const LayoutText* layout_text = ToLayoutTextOrNull(layout_object))
return GetSelectionStateFor(*layout_text) != SelectionState::kNone;
......@@ -650,10 +626,7 @@ static LayoutTextSelectionStatus ComputeSelectionStatusForNode(
LayoutTextSelectionStatus LayoutSelection::ComputeSelectionStatus(
const LayoutText& layout_text) const {
Document& document = frame_selection_->GetDocument();
DCHECK_GE(document.Lifecycle().GetState(), DocumentLifecycle::kLayoutClean);
DCHECK(!document.IsSlotAssignmentOrLegacyDistributionDirty());
DCHECK(!has_pending_selection_);
AssertIsValid();
const SelectionState selection_state = GetSelectionStateFor(layout_text);
if (selection_state == SelectionState::kNone)
return {0, 0, SelectionIncludeEnd::kNotInclude};
......@@ -683,54 +656,50 @@ LayoutTextSelectionStatus FrameSelection::ComputeLayoutSelectionStatus(
// FrameSelection holds selection offsets in layout block flow at
// LayoutSelection::Commit() if selection starts/ends within Text that
// each LayoutObject::SelectionState indicates.
// These offset can be out of |text_fragment| because SelectionState is of each
// LayoutText and not of each NGPhysicalTextFragment for it.
// These offset can be out of fragment because SelectionState is of each
// LayoutText and not of each fragment for it.
LayoutSelectionStatus LayoutSelection::ComputeSelectionStatus(
const NGPaintFragment& fragment) const {
Document& document = frame_selection_->GetDocument();
DCHECK_GE(document.Lifecycle().GetState(), DocumentLifecycle::kLayoutClean);
DCHECK(!document.IsSlotAssignmentOrLegacyDistributionDirty());
const auto& text_fragment =
To<NGPhysicalTextFragment>(fragment.PhysicalFragment());
const NGInlineCursor& cursor) const {
// We don't paint selection on ellipsis.
if (text_fragment.StyleVariant() == NGStyleVariant::kEllipsis)
if (cursor.IsEllipsis())
return {0, 0, SelectSoftLineBreak::kNotSelected};
// Needs GetSelectionStateFor
DCHECK(text_fragment.GetLayoutObject());
switch (
GetSelectionStateFor(ToLayoutText(*text_fragment.GetLayoutObject()))) {
const unsigned start_offset = cursor.CurrentTextStartOffset();
const unsigned end_offset = cursor.CurrentTextEndOffset();
switch (GetSelectionStateFor(cursor)) {
case SelectionState::kStart: {
const unsigned start_in_block = paint_range_->start_offset.value();
const bool is_continuous = start_in_block <= text_fragment.EndOffset();
return {ClampOffset(start_in_block, text_fragment),
text_fragment.EndOffset(),
(is_continuous && IsBeforeSoftLineBreak(fragment))
const bool is_continuous = start_in_block <= end_offset;
return {ClampOffset(start_in_block, start_offset, end_offset), end_offset,
(is_continuous && cursor.IsBeforeSoftLineBreak())
? SelectSoftLineBreak::kSelected
: SelectSoftLineBreak::kNotSelected};
}
case SelectionState::kEnd: {
const unsigned end_in_block = paint_range_->end_offset.value();
const unsigned end_in_fragment = ClampOffset(end_in_block, text_fragment);
const bool is_continuous = text_fragment.EndOffset() < end_in_block;
return {text_fragment.StartOffset(), end_in_fragment,
(is_continuous && IsBeforeSoftLineBreak(fragment))
const unsigned end_in_fragment =
ClampOffset(end_in_block, start_offset, end_offset);
const bool is_continuous = end_offset < end_in_block;
return {start_offset, end_in_fragment,
(is_continuous && cursor.IsBeforeSoftLineBreak())
? SelectSoftLineBreak::kSelected
: SelectSoftLineBreak::kNotSelected};
}
case SelectionState::kStartAndEnd: {
const unsigned start_in_block = paint_range_->start_offset.value();
const unsigned end_in_block = paint_range_->end_offset.value();
const unsigned end_in_fragment = ClampOffset(end_in_block, text_fragment);
const bool is_continuous = start_in_block <= text_fragment.EndOffset() &&
text_fragment.EndOffset() < end_in_block;
return {ClampOffset(start_in_block, text_fragment), end_in_fragment,
(is_continuous && IsBeforeSoftLineBreak(fragment))
const unsigned end_in_fragment =
ClampOffset(end_in_block, start_offset, end_offset);
const bool is_continuous =
start_in_block <= end_offset && end_offset < end_in_block;
return {ClampOffset(start_in_block, start_offset, end_offset),
end_in_fragment,
(is_continuous && cursor.IsBeforeSoftLineBreak())
? SelectSoftLineBreak::kSelected
: SelectSoftLineBreak::kNotSelected};
}
case SelectionState::kInside: {
return {text_fragment.StartOffset(), text_fragment.EndOffset(),
IsBeforeSoftLineBreak(fragment)
return {start_offset, end_offset,
cursor.IsBeforeSoftLineBreak()
? SelectSoftLineBreak::kSelected
: SelectSoftLineBreak::kNotSelected};
}
......
......@@ -32,7 +32,7 @@ namespace blink {
class IntRect;
class LayoutObject;
class LayoutText;
class NGPaintFragment;
class NGInlineCursor;
class FrameSelection;
struct LayoutSelectionStatus;
struct LayoutTextSelectionStatus;
......@@ -49,7 +49,7 @@ class LayoutSelection final : public GarbageCollected<LayoutSelection> {
void InvalidatePaintForSelection();
LayoutTextSelectionStatus ComputeSelectionStatus(const LayoutText&) const;
LayoutSelectionStatus ComputeSelectionStatus(const NGPaintFragment&) const;
LayoutSelectionStatus ComputeSelectionStatus(const NGInlineCursor&) const;
static bool IsSelected(const LayoutObject&);
void OnDocumentShutdown();
......@@ -57,6 +57,8 @@ class LayoutSelection final : public GarbageCollected<LayoutSelection> {
void Trace(Visitor*);
private:
void AssertIsValid() const;
Member<FrameSelection> frame_selection_;
bool has_pending_selection_ : 1;
......
......@@ -12,9 +12,7 @@
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_text.h"
#include "third_party/blink/renderer/core/layout/layout_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/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
......@@ -40,14 +38,15 @@ class LayoutSelectionTestBase : public EditingTestBase {
std::ostream& ostream,
const LayoutText& layout_text,
SelectionState state) {
const auto fragments = NGPaintFragment::InlineFragmentsFor(&layout_text);
if (fragments.IsInLayoutNGInlineFormattingContext()) {
const unsigned text_start =
To<NGPhysicalTextFragment>(fragments.begin()->PhysicalFragment())
.StartOffset();
for (const NGPaintFragment* fragment : fragments) {
if (layout_text.IsInLayoutNGInlineFormattingContext()) {
NGInlineCursor cursor(*layout_text.RootInlineFormattingContext());
cursor.MoveTo(layout_text);
if (!cursor)
return;
const unsigned text_start = cursor.CurrentTextStartOffset();
for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
const LayoutSelectionStatus status =
selection.ComputeLayoutSelectionStatus(*fragment);
selection.ComputeLayoutSelectionStatus(cursor);
if (state == SelectionState::kNone && status.start == status.end)
continue;
ostream << "(" << status.start - text_start << ","
......@@ -944,32 +943,6 @@ TEST_P(LayoutSelectionTest, InvalidateSlot) {
DumpSelectionInfo());
}
static const NGPaintFragment* FindNGPaintFragmentInternal(
const NGPaintFragment* paint,
const LayoutObject* layout_object) {
if (paint->GetLayoutObject() == layout_object)
return paint;
for (const NGPaintFragment* child : paint->Children()) {
if (const NGPaintFragment* child_fragment =
FindNGPaintFragmentInternal(child, layout_object))
return child_fragment;
}
return nullptr;
}
static const NGPaintFragment& GetNGPaintFragment(
const LayoutObject* layout_object) {
DCHECK(layout_object->IsText());
LayoutBlockFlow* block_flow = layout_object->ContainingNGBlockFlow();
DCHECK(block_flow);
DCHECK(block_flow->IsLayoutNGMixin());
LayoutNGBlockFlow* layout_ng = ToLayoutNGBlockFlow(block_flow);
const NGPaintFragment* paint_fragment =
FindNGPaintFragmentInternal(layout_ng->PaintFragment(), layout_object);
DCHECK(paint_fragment);
return *paint_fragment;
}
class NGLayoutSelectionTest
: public LayoutSelectionTestBase,
private ScopedLayoutNGForTest,
......@@ -979,6 +952,7 @@ class NGLayoutSelectionTest
: ScopedLayoutNGForTest(true),
ScopedPaintUnderInvalidationCheckingForTest(true) {}
protected:
const Text* GetFirstTextNode() {
for (const Node& runner : NodeTraversal::StartsAt(*GetDocument().body())) {
if (auto* text_node = DynamicTo<Text>(runner))
......@@ -990,17 +964,22 @@ class NGLayoutSelectionTest
bool IsFirstTextLineBreak(const std::string& selection_text) {
SetSelectionAndUpdateLayoutSelection(selection_text);
const Text* const first_text = GetFirstTextNode();
const NGPaintFragment& fragment =
GetNGPaintFragment(first_text->GetLayoutObject());
const LayoutText& first_text = *GetFirstTextNode()->GetLayoutObject();
const LayoutSelectionStatus& status =
Selection().ComputeLayoutSelectionStatus(fragment);
ComputeLayoutSelectionStatus(first_text);
return status.line_break == SelectSoftLineBreak::kSelected;
}
LayoutSelectionStatus ComputeLayoutSelectionStatus(const Node& node) {
return Selection().ComputeLayoutSelectionStatus(
GetNGPaintFragment(node.GetLayoutObject()));
return ComputeLayoutSelectionStatus(*node.GetLayoutObject());
}
LayoutSelectionStatus ComputeLayoutSelectionStatus(
const LayoutObject& layout_object) const {
DCHECK(layout_object.IsText());
NGInlineCursor cursor(*layout_object.RootInlineFormattingContext());
cursor.MoveTo(layout_object);
return Selection().ComputeLayoutSelectionStatus(cursor);
}
void SetSelectionAndUpdateLayoutSelection(const std::string& selection_text) {
......@@ -1053,7 +1032,7 @@ TEST_F(NGLayoutSelectionTest, TwoNGBlockFlows) {
LayoutObject* const foo =
GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
EXPECT_EQ(LayoutSelectionStatus(1u, 3u, SelectSoftLineBreak::kSelected),
Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(foo)));
ComputeLayoutSelectionStatus(*foo));
LayoutObject* const bar = GetDocument()
.body()
->firstChild()
......@@ -1061,7 +1040,7 @@ TEST_F(NGLayoutSelectionTest, TwoNGBlockFlows) {
->firstChild()
->GetLayoutObject();
EXPECT_EQ(LayoutSelectionStatus(0u, 2u, SelectSoftLineBreak::kNotSelected),
Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(bar)));
ComputeLayoutSelectionStatus(*bar));
}
// TODO(editing-dev): Once LayoutNG supports editing, we should change this
......@@ -1123,15 +1102,14 @@ TEST_F(NGLayoutSelectionTest, LineBreakBasic) {
EXPECT_FALSE(IsFirstTextLineBreak("<div>f^oo|</div>"));
EXPECT_FALSE(IsFirstTextLineBreak("<div>f^oo<!--|--></div>"));
EXPECT_FALSE(IsFirstTextLineBreak("<div>f^oo</div>|"));
// TODO(yoichio): Fix the test. See LayoutSelection::IsLineBreak.
// EXPECT_FALSE(IsFirstTextLineBreak(
// "<div style='display:inline-block'>f^oo</div>bar|"));
}
TEST_F(NGLayoutSelectionTest, LineBreakInlineBlock) {
LoadAhem();
EXPECT_FALSE(
IsFirstTextLineBreak("<div style='display:inline-block'>^x</div>y|"));
EXPECT_FALSE(
IsFirstTextLineBreak("<div style='display:inline-block'>f^oo</div>bar|"));
}
TEST_F(NGLayoutSelectionTest, LineBreakImage) {
......@@ -1155,9 +1133,8 @@ TEST_F(NGLayoutSelectionTest, BRStatus) {
LayoutObject* const layout_br =
GetDocument().QuerySelector("br")->GetLayoutObject();
CHECK(layout_br->IsBR());
EXPECT_EQ(
LayoutSelectionStatus(3u, 4u, SelectSoftLineBreak::kNotSelected),
Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(layout_br)));
EXPECT_EQ(LayoutSelectionStatus(3u, 4u, SelectSoftLineBreak::kNotSelected),
ComputeLayoutSelectionStatus(*layout_br));
}
// https://crbug.com/907186
......@@ -1166,9 +1143,8 @@ TEST_F(NGLayoutSelectionTest, WBRStatus) {
"<div style=\"width:0\">^foo<wbr>bar|</div>");
const LayoutObject* layout_wbr =
GetDocument().QuerySelector("wbr")->GetLayoutObject();
EXPECT_EQ(
LayoutSelectionStatus(3u, 4u, SelectSoftLineBreak::kSelected),
Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(layout_wbr)));
EXPECT_EQ(LayoutSelectionStatus(3u, 4u, SelectSoftLineBreak::kSelected),
ComputeLayoutSelectionStatus(*layout_wbr));
}
} // namespace blink
......@@ -54,6 +54,7 @@
#include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.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_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
......@@ -2084,20 +2085,19 @@ PhysicalRect LayoutText::LocalSelectionVisualRect() const {
return PhysicalRect();
const FrameSelection& frame_selection = GetFrame()->Selection();
const auto fragments = NGPaintFragment::InlineFragmentsFor(this);
if (fragments.IsInLayoutNGInlineFormattingContext()) {
if (IsInLayoutNGInlineFormattingContext()) {
PhysicalRect rect;
for (const NGPaintFragment* fragment : fragments) {
if (fragment->PhysicalFragment().IsHiddenForPaint())
NGInlineCursor cursor(*RootInlineFormattingContext());
for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject()) {
if (cursor.IsHiddenForPaint())
continue;
const LayoutSelectionStatus status =
frame_selection.ComputeLayoutSelectionStatus(*fragment);
frame_selection.ComputeLayoutSelectionStatus(cursor);
if (status.start == status.end)
continue;
PhysicalRect fragment_rect =
fragment->ComputeLocalSelectionRectForText(status);
fragment_rect.offset += fragment->InlineOffsetToContainerBox();
rect.Unite(fragment_rect);
PhysicalRect item_rect = ComputeLocalSelectionRectForText(cursor, status);
item_rect.offset += cursor.CurrentOffset();
rect.Unite(item_rect);
}
return rect;
}
......
......@@ -18,6 +18,7 @@
namespace blink {
class NGBlockBreakToken;
class NGInlineCursor;
struct LayoutSelectionStatus;
struct NGContainerInkOverflow;
enum class NGOutlineType;
......@@ -184,8 +185,6 @@ class CORE_EXPORT NGPaintFragment : public RefCounted<NGPaintFragment>,
IntRect VisualRect() const override;
IntRect PartialInvalidationVisualRect() const override;
PhysicalRect ComputeLocalSelectionRectForText(
const LayoutSelectionStatus&) const;
PhysicalRect ComputeLocalSelectionRectForReplaced() const;
// Set ShouldDoFullPaintInvalidation flag in the corresponding LayoutObject.
......@@ -429,6 +428,10 @@ extern template class CORE_EXTERN_TEMPLATE_EXPORT
extern template class CORE_EXTERN_TEMPLATE_EXPORT
NGPaintFragment::List<NGPaintFragment::TraverseNextSibling>;
PhysicalRect ComputeLocalSelectionRectForText(
const NGInlineCursor& cursor,
const LayoutSelectionStatus& selection_status);
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_PAINT_FRAGMENT_H_
......@@ -98,19 +98,26 @@ inline std::pair<LayoutUnit, LayoutUnit> GetLineLeftAndRightForOffsets(
// |NGFragmentItem| is done. http://crbug.com/982194
inline LayoutSelectionStatus ComputeLayoutSelectionStatus(
const NGInlineCursor& cursor) {
// TODO(yosin): We should implement |NGInlineCursor| version of
// ComputeLayoutSelectionStatus
return LayoutSelectionStatus(0, 0, SelectSoftLineBreak::kNotSelected);
return cursor.CurrentItem()
->GetLayoutObject()
->GetDocument()
.GetFrame()
->Selection()
.ComputeLayoutSelectionStatus(cursor);
}
inline LayoutSelectionStatus ComputeLayoutSelectionStatus(
const NGTextPainterCursor& cursor) {
// Note:: Because of this function is hot, we should not use |NGInlineCursor|
// on paint fragment which requires traversing ancestors to root.
NGInlineCursor inline_cursor(cursor.RootPaintFragment());
inline_cursor.MoveTo(cursor.PaintFragment());
return cursor.CurrentItem()
->GetLayoutObject()
->GetDocument()
.GetFrame()
->Selection()
.ComputeLayoutSelectionStatus(cursor.PaintFragment());
.ComputeLayoutSelectionStatus(inline_cursor);
}
// TODO(yosin): Remove |ComputeLocalRect| once the transition to
......@@ -305,26 +312,30 @@ void PaintDocumentMarkers(GraphicsContext& context,
} // namespace
const NGPaintFragment& NGTextPainterCursor::RootPaintFragment() const {
if (!root_paint_fragment_)
root_paint_fragment_ = paint_fragment_.Root();
return *root_paint_fragment_;
}
template <typename Cursor>
NGTextFragmentPainter<Cursor>::NGTextFragmentPainter(const Cursor& cursor)
: cursor_(cursor) {}
static PhysicalRect ComputeLocalSelectionRectForText(
const NGTextPainterCursor& cursor,
const LayoutSelectionStatus& selection_status) {
NGInlineCursor inline_cursor(cursor.RootPaintFragment());
inline_cursor.MoveTo(cursor.PaintFragment());
return ComputeLocalSelectionRectForText(inline_cursor, selection_status);
}
// Logic is copied from InlineTextBoxPainter::PaintSelection.
// |selection_start| and |selection_end| should be between
// [text_fragment.StartOffset(), text_fragment.EndOffset()].
// TODO(yosin): We should implement |NGInlineCursor| version of
// |PaintSelection()|
static void PaintSelection(GraphicsContext& context,
const NGInlineCursor& cursor,
Node* node,
const Document& document,
const ComputedStyle& style,
Color text_color,
const PhysicalRect& box_rect,
const LayoutSelectionStatus& selection_status) {}
template <typename Cursor>
static void PaintSelection(GraphicsContext& context,
const NGTextPainterCursor& cursor,
const Cursor& cursor,
Node* node,
const Document& document,
const ComputedStyle& style,
......@@ -334,7 +345,7 @@ static void PaintSelection(GraphicsContext& context,
const Color color =
SelectionBackgroundColor(document, style, node, text_color);
const PhysicalRect selection_rect =
cursor.PaintFragment().ComputeLocalSelectionRectForText(selection_status);
ComputeLocalSelectionRectForText(cursor, selection_status);
PaintRect(context, box_rect.offset, selection_rect, color);
}
......
......@@ -38,10 +38,12 @@ class NGTextPainterCursor {
const NGPaintFragment& PaintFragment() const { return paint_fragment_; }
const NGPhysicalTextFragment* CurrentItem() const { return &text_fragment_; }
const NGPaintFragment& RootPaintFragment() const;
private:
const NGPaintFragment& paint_fragment_;
const NGPhysicalTextFragment& text_fragment_;
mutable const NGPaintFragment* root_paint_fragment_ = nullptr;
};
// Text fragment painter for LayoutNG. Operates on NGPhysicalTextFragments and
......
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