diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc | 295 |
1 files changed, 187 insertions, 108 deletions
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc index 8a5f0a7201d..34643cd55f2 100644 --- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc +++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc @@ -5,7 +5,10 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h" #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.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" @@ -16,38 +19,90 @@ namespace blink { -NGAbstractInlineTextBox::FragmentToNGAbstractInlineTextBoxHashMap* - NGAbstractInlineTextBox::g_abstract_inline_text_box_map_ = nullptr; +namespace { + +// Mapping from NGFragmentItem/NGPaintFragment to NGAbstractInlineTextBox +// TODO(yosin): Once we get rid of |NGPaintFragment|, we should not use +// template class for |NGAbstractInlineTextBoxCache|. +template <typename Fragment> +class NGAbstractInlineTextBoxCache final { + public: + static scoped_refptr<AbstractInlineTextBox> GetOrCreate( + const Fragment& fragment) { + if (!s_instance_) + s_instance_ = new NGAbstractInlineTextBoxCache(); + return s_instance_->GetOrCreateInternal(fragment); + } + + static void WillDestroy(const Fragment* fragment) { + if (!s_instance_) + return; + s_instance_->WillDestroyInternal(fragment); + } + + private: + scoped_refptr<AbstractInlineTextBox> GetOrCreateInternal( + const Fragment& fragment) { + const auto it = map_.find(&fragment); + LayoutText* const layout_text = + ToLayoutText(fragment.GetMutableLayoutObject()); + if (it != map_.end()) { + CHECK(layout_text->HasAbstractInlineTextBox()); + return it->value; + } + scoped_refptr<AbstractInlineTextBox> obj = base::AdoptRef( + new NGAbstractInlineTextBox(LineLayoutText(layout_text), fragment)); + map_.Set(&fragment, obj); + layout_text->SetHasAbstractInlineTextBox(); + return obj; + } + + void WillDestroyInternal(const Fragment* fragment) { + const auto it = map_.find(fragment); + if (it == map_.end()) + return; + it->value->Detach(); + map_.erase(fragment); + } + + static NGAbstractInlineTextBoxCache* s_instance_; + + HashMap<const Fragment*, scoped_refptr<AbstractInlineTextBox>> map_; +}; + +template <typename Fragment> +NGAbstractInlineTextBoxCache<Fragment>* + NGAbstractInlineTextBoxCache<Fragment>::s_instance_ = nullptr; + +} // namespace scoped_refptr<AbstractInlineTextBox> NGAbstractInlineTextBox::GetOrCreate( - const NGPaintFragment& fragment) { - DCHECK(fragment.GetLayoutObject()->IsText()) << fragment.GetLayoutObject(); - if (!g_abstract_inline_text_box_map_) { - g_abstract_inline_text_box_map_ = - new FragmentToNGAbstractInlineTextBoxHashMap(); + const NGInlineCursor& cursor) { + if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) { + return NGAbstractInlineTextBoxCache<NGPaintFragment>::GetOrCreate( + *paint_fragment); } - const auto it = g_abstract_inline_text_box_map_->find(&fragment); - LayoutText* const layout_text = - ToLayoutText(fragment.GetMutableLayoutObject()); - if (it != g_abstract_inline_text_box_map_->end()) { - CHECK(layout_text->HasAbstractInlineTextBox()); - return it->value; + if (const NGFragmentItem* fragment_item = cursor.CurrentItem()) { + return NGAbstractInlineTextBoxCache<NGFragmentItem>::GetOrCreate( + *fragment_item); } - scoped_refptr<AbstractInlineTextBox> obj = base::AdoptRef( - new NGAbstractInlineTextBox(LineLayoutText(layout_text), fragment)); - g_abstract_inline_text_box_map_->Set(&fragment, obj); - layout_text->SetHasAbstractInlineTextBox(); - return obj; + return nullptr; } -void NGAbstractInlineTextBox::WillDestroy(NGPaintFragment* fragment) { - if (!g_abstract_inline_text_box_map_) - return; - const auto it = g_abstract_inline_text_box_map_->find(fragment); - if (it != g_abstract_inline_text_box_map_->end()) { - it->value->Detach(); - g_abstract_inline_text_box_map_->erase(fragment); +void NGAbstractInlineTextBox::WillDestroy(const NGInlineCursor& cursor) { + if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) { + return NGAbstractInlineTextBoxCache<NGPaintFragment>::WillDestroy( + paint_fragment); + } + if (const NGFragmentItem* fragment_item = cursor.CurrentItem()) { + return NGAbstractInlineTextBoxCache<NGFragmentItem>::WillDestroy( + fragment_item); } + NOTREACHED(); +} + +void NGAbstractInlineTextBox::WillDestroy(const NGPaintFragment* fragment) { + NGAbstractInlineTextBoxCache<NGPaintFragment>::WillDestroy(fragment); } NGAbstractInlineTextBox::NGAbstractInlineTextBox( @@ -57,6 +112,13 @@ NGAbstractInlineTextBox::NGAbstractInlineTextBox( DCHECK(fragment_->PhysicalFragment().IsText()) << fragment_; } +NGAbstractInlineTextBox::NGAbstractInlineTextBox( + LineLayoutText line_layout_item, + const NGFragmentItem& fragment_item) + : AbstractInlineTextBox(line_layout_item), fragment_item_(&fragment_item) { + DCHECK(fragment_item_->IsText()) << fragment_item_; +} + NGAbstractInlineTextBox::~NGAbstractInlineTextBox() { DCHECK(!fragment_); } @@ -70,107 +132,128 @@ void NGAbstractInlineTextBox::Detach() { fragment_ = nullptr; } -const NGPhysicalTextFragment& NGAbstractInlineTextBox::PhysicalTextFragment() - const { - return To<NGPhysicalTextFragment>(fragment_->PhysicalFragment()); +NGInlineCursor NGAbstractInlineTextBox::GetCursor() const { + if (!fragment_item_) + return NGInlineCursor(); + NGInlineCursor cursor; + if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) + cursor.MoveTo(*fragment_item_); + else + cursor.MoveTo(*fragment_); + DCHECK(!cursor.Current().GetLayoutObject()->NeedsLayout()); + return cursor; +} + +NGInlineCursor NGAbstractInlineTextBox::GetCursorOnLine() const { + NGInlineCursor current = GetCursor(); + NGInlineCursor line_box = current; + line_box.MoveToContainingLine(); + NGInlineCursor cursor = line_box.CursorForDescendants(); + cursor.MoveTo(current); + return cursor; } -bool NGAbstractInlineTextBox::NeedsLayout() const { - return fragment_->GetLayoutObject()->NeedsLayout(); +String NGAbstractInlineTextBox::GetTextContent() const { + const NGInlineCursor& cursor = GetCursor(); + if (cursor.Current().IsGeneratedTextType()) + return cursor.Current().Text(cursor).ToString(); + if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) { + return To<NGPhysicalTextFragment>(paint_fragment->PhysicalFragment()) + .TextContent(); + } + return cursor.Items().Text(cursor.Current().UsesFirstLineStyle()); } bool NGAbstractInlineTextBox::NeedsTrailingSpace() const { - if (!fragment_->Style().CollapseWhiteSpace()) + const NGInlineCursor& cursor = GetCursor(); + if (!cursor.Current().Style().CollapseWhiteSpace()) return false; - const NGPaintFragment& line_box = *fragment_->ContainerLineBox(); - if (!To<NGPhysicalLineBoxFragment>(line_box.PhysicalFragment()) - .HasSoftWrapToNextLine()) + NGInlineCursor line_box = cursor; + line_box.MoveToContainingLine(); + if (!line_box.HasSoftWrapToNextLine()) return false; - const NGPhysicalTextFragment& text_fragment = PhysicalTextFragment(); - if (text_fragment.EndOffset() >= text_fragment.TextContent().length()) + const String text_content = GetTextContent(); + const unsigned end_offset = cursor.Current().TextEndOffset(); + if (end_offset >= text_content.length()) return false; - if (text_fragment.TextContent()[text_fragment.EndOffset()] != ' ') + if (text_content[end_offset] != ' ') return false; - const NGInlineBreakToken& break_token = *To<NGInlineBreakToken>( - To<NGPhysicalLineBoxFragment>(line_box.PhysicalFragment()).BreakToken()); + const NGInlineBreakToken* break_token = line_box.Current().InlineBreakToken(); + DCHECK(break_token); // TODO(yosin): We should support OOF fragments between |fragment_| and // break token. - if (break_token.TextOffset() != text_fragment.EndOffset() + 1) + if (break_token->TextOffset() != end_offset + 1) return false; // Check a character in text content after |fragment_| comes from same // layout text of |fragment_|. - const NGOffsetMapping* mapping = - NGOffsetMapping::GetFor(fragment_->GetLayoutObject()); + const LayoutObject* const layout_object = cursor.Current().GetLayoutObject(); + const NGOffsetMapping* mapping = NGOffsetMapping::GetFor(layout_object); // TODO(kojii): There's not much we can do for dirty-tree. crbug.com/946004 if (!mapping) return false; const base::span<const NGOffsetMappingUnit> mapping_units = - mapping->GetMappingUnitsForTextContentOffsetRange( - text_fragment.EndOffset(), text_fragment.EndOffset() + 1); + mapping->GetMappingUnitsForTextContentOffsetRange(end_offset, + end_offset + 1); if (mapping_units.begin() == mapping_units.end()) return false; const NGOffsetMappingUnit& mapping_unit = mapping_units.front(); - return mapping_unit.GetLayoutObject() == fragment_->GetLayoutObject(); -} - -const NGPaintFragment* -NGAbstractInlineTextBox::NextTextFragmentForSameLayoutObject() const { - const auto fragments = - NGPaintFragment::InlineFragmentsFor(fragment_->GetLayoutObject()); - const auto it = - std::find_if(fragments.begin(), fragments.end(), - [&](const auto& sibling) { return fragment_ == sibling; }); - DCHECK(it != fragments.end()); - const auto next_it = std::next(it); - return next_it == fragments.end() ? nullptr : *next_it; + return mapping_unit.GetLayoutObject() == layout_object; } scoped_refptr<AbstractInlineTextBox> NGAbstractInlineTextBox::NextInlineTextBox() const { - if (!fragment_) + const NGInlineCursor& cursor = GetCursor(); + if (!cursor) return nullptr; - DCHECK(!NeedsLayout()); - const NGPaintFragment* next_fragment = NextTextFragmentForSameLayoutObject(); - if (!next_fragment) + NGInlineCursor next; + next.MoveTo(*cursor.Current().GetLayoutObject()); + while (next != cursor) + next.MoveToNextForSameLayoutObject(); + next.MoveToNextForSameLayoutObject(); + if (!next) return nullptr; - return GetOrCreate(*next_fragment); + return GetOrCreate(next); } LayoutRect NGAbstractInlineTextBox::LocalBounds() const { - if (!fragment_ || !GetLineLayoutItem()) + const NGInlineCursor& cursor = GetCursor(); + if (!cursor) return LayoutRect(); - return LayoutRect(fragment_->InlineOffsetToContainerBox().ToLayoutPoint(), - fragment_->Size().ToLayoutSize()); + return cursor.Current().RectInContainerBlock().ToLayoutRect(); } unsigned NGAbstractInlineTextBox::Len() const { - if (!fragment_) + const NGInlineCursor& cursor = GetCursor(); + if (!cursor) return 0; if (NeedsTrailingSpace()) - return PhysicalTextFragment().TextLength() + 1; - return PhysicalTextFragment().TextLength(); + return cursor.Current().Text(cursor).length() + 1; + return cursor.Current().Text(cursor).length(); } unsigned NGAbstractInlineTextBox::TextOffsetInContainer(unsigned offset) const { - if (!fragment_) + const NGInlineCursor& cursor = GetCursor(); + if (!cursor) return 0; - return PhysicalTextFragment().StartOffset() + offset; + return cursor.Current().TextStartOffset() + offset; } AbstractInlineTextBox::Direction NGAbstractInlineTextBox::GetDirection() const { - if (!fragment_ || !GetLineLayoutItem()) + const NGInlineCursor& cursor = GetCursor(); + if (!cursor) return kLeftToRight; - const TextDirection text_direction = - PhysicalTextFragment().ResolvedDirection(); + const TextDirection text_direction = cursor.Current().ResolvedDirection(); if (GetLineLayoutItem().Style()->IsHorizontalWritingMode()) return IsLtr(text_direction) ? kLeftToRight : kRightToLeft; return IsLtr(text_direction) ? kTopToBottom : kBottomToTop; } void NGAbstractInlineTextBox::CharacterWidths(Vector<float>& widths) const { - if (!fragment_) + const NGInlineCursor& cursor = GetCursor(); + if (!cursor) return; - if (!PhysicalTextFragment().TextShapeResult()) { + const ShapeResultView* shape_result_view = cursor.Current().TextShapeResult(); + if (!shape_result_view) { // When |fragment_| for BR, we don't have shape result. // "aom-computed-boolean-properties.html" reaches here. widths.resize(Len()); @@ -178,8 +261,8 @@ void NGAbstractInlineTextBox::CharacterWidths(Vector<float>& widths) const { } // TODO(layout-dev): Add support for IndividualCharacterRanges to // ShapeResultView to avoid the copy below. - auto shape_result = - PhysicalTextFragment().TextShapeResult()->CreateShapeResult(); + scoped_refptr<ShapeResult> shape_result = + shape_result_view->CreateShapeResult(); Vector<CharacterRange> ranges; shape_result->IndividualCharacterRanges(&ranges); widths.ReserveCapacity(ranges.size()); @@ -193,10 +276,11 @@ void NGAbstractInlineTextBox::CharacterWidths(Vector<float>& widths) const { } String NGAbstractInlineTextBox::GetText() const { - if (!fragment_ || !GetLineLayoutItem()) - return String(); + const NGInlineCursor& cursor = GetCursor(); + if (!cursor) + return g_empty_string; - String result = PhysicalTextFragment().Text().ToString(); + String result = cursor.Current().Text(cursor).ToString(); // For compatibility with |InlineTextBox|, we should have a space character // for soft line break. @@ -217,56 +301,51 @@ String NGAbstractInlineTextBox::GetText() const { } bool NGAbstractInlineTextBox::IsFirst() const { - if (!fragment_) + const NGInlineCursor& cursor = GetCursor(); + if (!cursor) return true; - DCHECK(!NeedsLayout()); - const auto fragments = - NGPaintFragment::InlineFragmentsFor(fragment_->GetLayoutObject()); - return fragment_ == &fragments.front(); + NGInlineCursor first_fragment; + first_fragment.MoveTo(*cursor.Current().GetLayoutObject()); + return cursor == first_fragment; } bool NGAbstractInlineTextBox::IsLast() const { - if (!fragment_) + const NGInlineCursor& cursor = GetCursor(); + if (!cursor) return true; - DCHECK(!NeedsLayout()); - const auto fragments = - NGPaintFragment::InlineFragmentsFor(fragment_->GetLayoutObject()); - return fragment_ == &fragments.back(); + NGInlineCursor last_fragment; + last_fragment.MoveTo(*cursor.Current().GetLayoutObject()); + last_fragment.MoveToLastForSameLayoutObject(); + return cursor == last_fragment; } scoped_refptr<AbstractInlineTextBox> NGAbstractInlineTextBox::NextOnLine() const { - if (!fragment_) + NGInlineCursor cursor = GetCursorOnLine(); + if (!cursor) return nullptr; - DCHECK(!NeedsLayout()); - DCHECK(fragment_->ContainerLineBox()); - NGPaintFragmentTraversal cursor(*fragment_->ContainerLineBox(), *fragment_); - for (cursor.MoveToNext(); !cursor.IsAtEnd(); cursor.MoveToNext()) { - if (cursor->GetLayoutObject()->IsText()) - return GetOrCreate(*cursor); + for (cursor.MoveToNext(); cursor; cursor.MoveToNext()) { + if (cursor.Current().GetLayoutObject()->IsText()) + return GetOrCreate(cursor); } return nullptr; } scoped_refptr<AbstractInlineTextBox> NGAbstractInlineTextBox::PreviousOnLine() const { - if (!fragment_) + NGInlineCursor cursor = GetCursorOnLine(); + if (!cursor) return nullptr; - DCHECK(!NeedsLayout()); - DCHECK(fragment_->ContainerLineBox()); - NGPaintFragmentTraversal cursor(*fragment_->ContainerLineBox(), *fragment_); - for (cursor.MoveToPrevious(); !cursor.IsAtEnd(); cursor.MoveToPrevious()) { - if (cursor->GetLayoutObject()->IsText()) - return GetOrCreate(*cursor); + for (cursor.MoveToPrevious(); cursor; cursor.MoveToPrevious()) { + if (cursor.Current().GetLayoutObject()->IsText()) + return GetOrCreate(cursor); } return nullptr; } bool NGAbstractInlineTextBox::IsLineBreak() const { - if (!fragment_) - return false; - DCHECK(!NeedsLayout()); - return PhysicalTextFragment().IsLineBreak(); + const NGInlineCursor& cursor = GetCursor(); + return cursor && cursor.Current().IsLineBreak(); } } // namespace blink |