Commit e0104ef4 authored by Yoshifumi Inoue's avatar Yoshifumi Inoue Committed by Commit Bot

Introduce LayoutNGTextFragment to have NGInlineItem

This patch introduces |LayoutNGTextFragment| to make layout text objects in
NG layout tree to have |NGInlineItem| for utilizing it in Element#innerText
to handle |Text| nodes with ::first-letter.

Before this patch |Text| node applied ::first-letter is represented with two
|LayoutTextFragment| objects for first-letter part and remaining part. After
this patch, they are represented to |LayoutNGTextFragment| with |NGInlineItem|.

[1] http://crrev.com/c/1309562 Make Element#innterText to utilize NGInlineItem
instead of NGPaintFragment

Bug: 873957
Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng
Change-Id: I4cd6b43fdc4caf0d92b1030cfbb75f37d4fe67b8
Reviewed-on: https://chromium-review.googlesource.com/c/1309391Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Commit-Queue: Yoshifumi Inoue <yosin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#604861}
parent c43609fd
......@@ -311,12 +311,13 @@ void FirstLetterPseudoElement::AttachFirstLetterTextLayoutObjects(LayoutText* fi
LayoutTextFragment* remaining_text;
if (first_letter_text->GetNode()) {
remaining_text =
new LayoutTextFragment(first_letter_text->GetNode(), old_text.Impl(),
length, remaining_length);
remaining_text = LayoutTextFragment::Create(
*first_letter_text->Style(), first_letter_text->GetNode(),
old_text.Impl(), length, remaining_length);
} else {
remaining_text = LayoutTextFragment::CreateAnonymous(
*this, old_text.Impl(), length, remaining_length);
*first_letter_text->Style(), *this, old_text.Impl(), length,
remaining_length);
}
remaining_text->SetFirstLetterPseudoElement(this);
......@@ -332,10 +333,11 @@ void FirstLetterPseudoElement::AttachFirstLetterTextLayoutObjects(LayoutText* fi
GetLayoutObject()->Parent()->AddChild(remaining_text, next_sibling);
// Construct text fragment for the first letter.
LayoutTextFragment* letter =
LayoutTextFragment::CreateAnonymous(*this, old_text.Impl(), 0, length);
ComputedStyle* const letter_style = MutableComputedStyle();
LayoutTextFragment* letter = LayoutTextFragment::CreateAnonymous(
*letter_style, *this, old_text.Impl(), 0, length);
letter->SetFirstLetterPseudoElement(this);
letter->SetStyle(MutableComputedStyle());
letter->SetStyle(letter_style);
GetLayoutObject()->AddChild(letter);
first_letter_text->Destroy();
......
......@@ -323,6 +323,8 @@ blink_core_sources("layout") {
"ng/geometry/ng_static_position.cc",
"ng/geometry/ng_static_position.h",
"ng/inline/empty_offset_mapping_builder.h",
"ng/inline/layout_ng_text.h",
"ng/inline/layout_ng_text_fragment.h",
"ng/inline/ng_abstract_inline_text_box.cc",
"ng/inline/ng_abstract_inline_text_box.h",
"ng/inline/ng_baseline.cc",
......@@ -345,6 +347,7 @@ blink_core_sources("layout") {
"ng/inline/ng_inline_item.h",
"ng/inline/ng_inline_item_result.cc",
"ng/inline/ng_inline_item_result.h",
"ng/inline/ng_inline_items.h",
"ng/inline/ng_inline_items_builder.cc",
"ng/inline/ng_inline_items_builder.h",
"ng/inline/ng_inline_layout_algorithm.cc",
......
......@@ -31,7 +31,6 @@
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h"
#include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
namespace blink {
......@@ -45,8 +44,8 @@ namespace {
void InvalidateInlineItems(LayoutObject* object) {
if (object->IsInLayoutNGInlineFormattingContext())
object->SetFirstInlineFragment(nullptr);
if (object->IsLayoutNGText()) {
ToLayoutNGText(object)->InvalidateInlineItems();
if (object->IsText()) {
ToLayoutText(object)->InvalidateInlineItems();
} else if (object->IsLayoutInline()) {
// When moving without |notify_layout_object|, only top-level objects are
// moved. Ensure to invalidate all LayoutNGText in this inline formatting
......
......@@ -269,8 +269,8 @@ void LayoutQuote::UpdateText() {
fragment->SetStyle(MutableStyle());
fragment->SetContentString(text_.Impl());
} else {
fragment =
LayoutTextFragment::CreateAnonymous(*owning_pseudo_, text_.Impl());
fragment = LayoutTextFragment::CreateAnonymous(*Style(), *owning_pseudo_,
text_.Impl());
fragment->SetStyle(MutableStyle());
AddChild(fragment);
}
......
......@@ -2432,4 +2432,25 @@ LayoutRect LayoutText::DebugRect() const {
return rect;
}
void LayoutText::AddInlineItem(NGInlineItem* item) {
DCHECK_EQ(this, item->GetLayoutObject());
NGInlineItems* items = GetNGInlineItems();
if (!items)
return;
valid_ng_items_ = true;
items->Add(item);
}
void LayoutText::ClearInlineItems() {
valid_ng_items_ = false;
if (NGInlineItems* items = GetNGInlineItems())
items->Clear();
}
const Vector<NGInlineItem*>& LayoutText::InlineItems() const {
DCHECK(valid_ng_items_);
DCHECK(!GetNGInlineItems()->Items().IsEmpty());
return GetNGInlineItems()->Items();
}
} // namespace blink
......@@ -37,6 +37,8 @@ namespace blink {
class AbstractInlineTextBox;
class InlineTextBox;
class NGInlineItem;
class NGInlineItems;
class NGOffsetMapping;
enum class OnlyWhitespaceOrNbsp : unsigned { kUnknown = 0, kNo = 1, kYes = 2 };
......@@ -312,7 +314,17 @@ class CORE_EXPORT LayoutText : public LayoutObject {
unsigned* start,
unsigned* end) const;
void AddInlineItem(NGInlineItem* item);
void ClearInlineItems();
bool HasValidInlineItems() const { return valid_ng_items_; }
const Vector<NGInlineItem*>& InlineItems() const;
// Inline items depends on context. It needs to be invalidated not only when
// it was inserted/changed but also it was moved.
void InvalidateInlineItems() { valid_ng_items_ = false; }
protected:
virtual const NGInlineItems* GetNGInlineItems() const { return nullptr; }
virtual NGInlineItems* GetNGInlineItems() { return nullptr; }
void WillBeDestroyed() override;
void StyleWillChange(StyleDifference, const ComputedStyle&) final {}
......
......@@ -28,6 +28,7 @@
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
namespace blink {
......@@ -43,19 +44,28 @@ LayoutTextFragment::LayoutTextFragment(Node* node,
content_string_(str),
first_letter_pseudo_element_(nullptr) {}
LayoutTextFragment::LayoutTextFragment(Node* node, StringImpl* str)
: LayoutTextFragment(node, str, 0, str ? str->length() : 0) {}
LayoutTextFragment::~LayoutTextFragment() {
DCHECK(!first_letter_pseudo_element_);
}
LayoutTextFragment* LayoutTextFragment::CreateAnonymous(PseudoElement& pseudo,
StringImpl* text,
unsigned start,
unsigned length) {
LayoutTextFragment* LayoutTextFragment::Create(const ComputedStyle& style,
Node* node,
StringImpl* str,
int start_offset,
int length) {
if (RuntimeEnabledFeatures::LayoutNGEnabled() && !style.ForceLegacyLayout())
return new LayoutNGTextFragment(node, str, start_offset, length);
return new LayoutTextFragment(node, str, start_offset, length);
}
LayoutTextFragment* LayoutTextFragment::CreateAnonymous(
const ComputedStyle& style,
PseudoElement& pseudo,
StringImpl* text,
unsigned start,
unsigned length) {
LayoutTextFragment* fragment =
new LayoutTextFragment(nullptr, text, start, length);
LayoutTextFragment::Create(style, nullptr, text, start, length);
fragment->SetDocumentForAnonymous(&pseudo.GetDocument());
if (length)
pseudo.GetDocument().View()->IncrementVisuallyNonEmptyCharacterCount(
......@@ -63,9 +73,11 @@ LayoutTextFragment* LayoutTextFragment::CreateAnonymous(PseudoElement& pseudo,
return fragment;
}
LayoutTextFragment* LayoutTextFragment::CreateAnonymous(PseudoElement& pseudo,
StringImpl* text) {
return CreateAnonymous(pseudo, text, 0, text ? text->length() : 0);
LayoutTextFragment* LayoutTextFragment::CreateAnonymous(
const ComputedStyle& style,
PseudoElement& pseudo,
StringImpl* text) {
return CreateAnonymous(style, pseudo, text, 0, text ? text->length() : 0);
}
void LayoutTextFragment::WillBeDestroyed() {
......
......@@ -37,14 +37,21 @@ class FirstLetterPseudoElement;
// We cache offsets so that text transformations can be applied in such a way
// that we can recover the original unaltered string from our corresponding DOM
// node.
class CORE_EXPORT LayoutTextFragment final : public LayoutText {
class CORE_EXPORT LayoutTextFragment : public LayoutText {
public:
LayoutTextFragment(Node*, StringImpl*, int start_offset, int length);
LayoutTextFragment(Node*, StringImpl*);
~LayoutTextFragment() override;
static LayoutTextFragment* CreateAnonymous(PseudoElement&, StringImpl*);
static LayoutTextFragment* CreateAnonymous(PseudoElement&,
// |style| is used for checking |ForceLegacyLayout()|.
static LayoutTextFragment* Create(const ComputedStyle& style,
Node*,
StringImpl*,
int start_offset,
int length);
static LayoutTextFragment* CreateAnonymous(const ComputedStyle& style,
PseudoElement&,
StringImpl*);
static LayoutTextFragment* CreateAnonymous(const ComputedStyle& style,
PseudoElement&,
StringImpl*,
unsigned start,
unsigned length);
......@@ -99,6 +106,7 @@ class CORE_EXPORT LayoutTextFragment final : public LayoutText {
LayoutText* GetFirstLetterPart() const override;
protected:
LayoutTextFragment(Node*, StringImpl*, int start_offset, int length);
void WillBeDestroyed() override;
private:
......
......@@ -6,18 +6,13 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_LAYOUT_NG_TEXT_H_
#include "third_party/blink/renderer/core/layout/layout_text.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_items.h"
namespace blink {
class NGInlineItem;
// This overrides the default LayoutText to reference LayoutNGInlineItems
// instead of InlineTextBoxes.
//
// ***** INLINE ITEMS OWNERSHIP *****
// NGInlineItems in items_ are not owned by LayoutText but are pointers into the
// LayoutNGBlockFlow's items_. Should not be accessed outside of layout.
class CORE_EXPORT LayoutNGText : public LayoutText {
public:
LayoutNGText(Node* node, scoped_refptr<StringImpl> text)
......@@ -28,26 +23,6 @@ class CORE_EXPORT LayoutNGText : public LayoutText {
}
bool IsLayoutNGObject() const override { return true; }
bool HasValidLayout() const { return valid_ng_items_; }
const Vector<NGInlineItem*>& InlineItems() const {
DCHECK(valid_ng_items_);
return inline_items_;
}
// Inline items depends on context. It needs to be invalidated not only when
// it was inserted/changed but also it was moved.
void InvalidateInlineItems() { valid_ng_items_ = false; }
void ClearInlineItems() {
inline_items_.clear();
valid_ng_items_ = false;
}
void AddInlineItem(NGInlineItem* item) {
inline_items_.push_back(item);
valid_ng_items_ = true;
}
protected:
void InsertedIntoTree() override {
valid_ng_items_ = false;
......@@ -55,7 +30,10 @@ class CORE_EXPORT LayoutNGText : public LayoutText {
}
private:
Vector<NGInlineItem*> inline_items_;
const NGInlineItems* GetNGInlineItems() const final { return &inline_items_; }
NGInlineItems* GetNGInlineItems() final { return &inline_items_; }
NGInlineItems inline_items_;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGText, IsLayoutNGText());
......
// 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_LAYOUT_NG_TEXT_FRAGMENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_LAYOUT_NG_TEXT_FRAGMENT_H_
#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_items.h"
namespace blink {
// This overrides the default LayoutText to reference LayoutNGInlineItems
// instead of InlineTextBoxes.
//
class CORE_EXPORT LayoutNGTextFragment final : public LayoutTextFragment {
public:
LayoutNGTextFragment(Node* node,
StringImpl* text,
int start_offset,
int length)
: LayoutTextFragment(node, text, start_offset, length) {}
bool IsLayoutNGObject() const final { return true; }
private:
const NGInlineItems* GetNGInlineItems() const final { return &inline_items_; }
NGInlineItems* GetNGInlineItems() final { return &inline_items_; }
void InsertedIntoTree() final {
valid_ng_items_ = false;
LayoutText::InsertedIntoTree();
}
NGInlineItems inline_items_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_LAYOUT_NG_TEXT_FRAGMENT_H_
// 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_INLINE_ITEMS_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_ITEMS_H_
#include "base/macros.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
class NGInlineItem;
// A collection of |NGInlineItem| associated to |LayoutNGText|.
//
// ***** INLINE ITEMS OWNERSHIP *****
// NGInlineItems in items_ are not owned by LayoutText but are pointers into the
// LayoutNGBlockFlow's items_. Should not be accessed outside of layout.
class NGInlineItems final {
public:
NGInlineItems() = default;
void Add(NGInlineItem* item) { items_.push_back(item); }
void Clear() { items_.clear(); }
const Vector<NGInlineItem*>& Items() const { return items_; }
private:
Vector<NGInlineItem*> items_;
DISALLOW_COPY_AND_ASSIGN(NGInlineItems);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_ITEMS_H_
......@@ -247,8 +247,8 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::
template <typename OffsetMappingBuilder>
bool NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::Append(
const String& original_string,
LayoutNGText* layout_text,
const Vector<NGInlineItem*>& items) {
LayoutText* layout_text) {
const Vector<NGInlineItem*>& items = layout_text->InlineItems();
// Don't reuse existing items if they might be affected by whitespace
// collapsing.
// TODO(layout-dev): This could likely be optimized further.
......@@ -348,10 +348,8 @@ bool NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::Append(
}
template <>
bool NGInlineItemsBuilderTemplate<NGOffsetMappingBuilder>::Append(
const String&,
LayoutNGText*,
const Vector<NGInlineItem*>&) {
bool NGInlineItemsBuilderTemplate<NGOffsetMappingBuilder>::Append(const String&,
LayoutText*) {
NOTREACHED();
return false;
}
......
......@@ -18,7 +18,6 @@
namespace blink {
class ComputedStyle;
class LayoutNGText;
class LayoutObject;
class LayoutText;
......@@ -59,7 +58,7 @@ class NGInlineItemsBuilderTemplate {
// Returns whether the existing items could be reused.
// NOTE: The state of the builder remains unchanged if the append operation
// fails (i.e. if it returns false).
bool Append(const String&, LayoutNGText*, const Vector<NGInlineItem*>&);
bool Append(const String&, LayoutText*);
// Append a string.
// When appending, spaces are collapsed according to CSS Text, The white space
......@@ -185,8 +184,7 @@ class NGInlineItemsBuilderTemplate {
template <>
CORE_EXPORT bool NGInlineItemsBuilderTemplate<NGOffsetMappingBuilder>::Append(
const String&,
LayoutNGText*,
const Vector<NGInlineItem*>&);
LayoutText*);
extern template class CORE_EXTERN_TEMPLATE_EXPORT
NGInlineItemsBuilderTemplate<EmptyOffsetMappingBuilder>;
......
......@@ -97,17 +97,14 @@ class NGInlineItemsBuilderTest : public NGLayoutTest {
for (Input& input : inputs) {
// Collect items for this LayoutObject.
DCHECK(input.layout_text);
Vector<NGInlineItem*> previous_items;
for (auto& item : items_) {
if (item.GetLayoutObject() == input.layout_text)
previous_items.push_back(&item);
input.layout_text->AddInlineItem(&item);
}
// Try to re-use previous items, or Append if it was not re-usable.
bool reused =
!previous_items.IsEmpty() &&
reuse_builder.Append(text_, ToLayoutNGText(input.layout_text),
previous_items);
bool reused = input.layout_text->HasValidInlineItems() &&
reuse_builder.Append(text_, input.layout_text);
if (!reused) {
reuse_builder.Append(input.text, input.layout_text->Style(),
input.layout_text);
......
......@@ -75,8 +75,8 @@ void ClearNeedsLayout(LayoutObject* object) {
// Reset previous items if they cannot be reused to prevent stale items
// for subsequent layouts. Items that can be reused have already been
// added to the builder.
if (object->IsLayoutNGText())
ToLayoutNGText(object)->ClearInlineItems();
if (object->IsText())
ToLayoutText(object)->ClearInlineItems();
}
// The function is templated to indicate the purpose of collected inlines:
......@@ -109,11 +109,8 @@ void CollectInlinesInternal(
// if the last ended with space and this starts with space, do not allow
// reuse. builder->MightCollapseWithPreceding(*previous_text)
bool item_reused = false;
if (node->IsLayoutNGText() && ToLayoutNGText(node)->HasValidLayout() &&
previous_text) {
item_reused = builder->Append(*previous_text, ToLayoutNGText(node),
ToLayoutNGText(node)->InlineItems());
}
if (previous_text && layout_text->HasValidInlineItems())
item_reused = builder->Append(*previous_text, layout_text);
// If not create a new item as needed.
if (!item_reused) {
......@@ -642,8 +639,8 @@ void NGInlineNode::AssociateItemsWithInlines(NGInlineNodeData* data) {
LayoutObject* last_object = nullptr;
for (auto& item : data->items) {
LayoutObject* object = item.GetLayoutObject();
if (object && object->IsLayoutNGText()) {
LayoutNGText* layout_text = ToLayoutNGText(object);
if (object && object->IsText()) {
LayoutText* layout_text = ToLayoutText(object);
if (object != last_object)
layout_text->ClearInlineItems();
layout_text->AddInlineItem(&item);
......
......@@ -90,7 +90,7 @@ LayoutObject* TextContentData::CreateLayoutObject(
PseudoElement& pseudo,
ComputedStyle& pseudo_style) const {
LayoutObject* layout_object =
LayoutTextFragment::CreateAnonymous(pseudo, text_.Impl());
LayoutTextFragment::CreateAnonymous(pseudo_style, pseudo, text_.Impl());
layout_object->SetPseudoStyle(&pseudo_style);
return layout_object;
}
......
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