Commit 5c971167 authored by Yoshifumi Inoue's avatar Yoshifumi Inoue Committed by Commit Bot

[LayoutNG] Adapt accessibility module to LayoutNG

This patch adapts accessibility module to LayoutNG by:
 * Make |AbstractInlineTextBox| as an interface like class and implements legacy
 version |LegacyAbstractInlineTextBox| using InlineTextBox and LayoutNG
 version |NGAbstractInlineTextBox| using NGPaintFragment.
 * Make |AXLayoutObject| to handle |LayoutNGListMarker|
   - |LayoutListMarker| has no children.
   - |LayoutNGListMarker| is a container of list marker.
 * Make |AXLayoutObject::ComputeAccessibilityIsIgnored()| to handle LayoutNG
 block flow to check empty block flow.
 * Make |NGPaintFragment::FragmentRange::iterator| to work with |std::next()|
 * Intrdouce LayoutText::GetFirstLetterPart() for ease of getting layout object
  for first-letter part from layout object for remaining part.

Following patch will implements NGAbstractInlineTextBox::CharacterWidths()

The doc,https://bit.ly/2kUEFZy, contains study and change details.

TBR=dmazzoni@chromium.org

Bug: 714962
Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng;luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Iae25e8a7d7e6be0c7478470c690e081084476e85
Reviewed-on: https://chromium-review.googlesource.com/1104082
Commit-Queue: Yoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#569235}
parent cba147cc
......@@ -23,6 +23,11 @@ crbug.com/591099 fast/block/child-not-removed-from-parent-lineboxes-crash.html [
# https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/layout/layout_block.cc?l=1372&rcl=0e081149ecd6a83f6289e3aee5797936008a1e10
crbug.com/591099 fast/block/marquee-width-shrinks-to-fit-in-fixed-size-container.html [ Failure ]
# Whitespace differences only
crbug.com/854889 accessibility/canvas-fallback-content-2.html [ Failure ]
crbug.com/854889 accessibility/css-generated-content.html [ Failure Pass ]
crbug.com/854889 accessibility/css-styles.html [ Failure ]
# Hit test failure due to vertical-rl writing mode
crbug.com/851075 fast/writing-mode/vertical-inline-block-hittest.html [ Failure ]
......@@ -53,46 +58,9 @@ crbug.com/591099 external/wpt/css/css-writing-modes/two-levels-of-orthogonal-flo
crbug.com/591099 fast/dom/inner-text-first-letter.html [ Pass ]
# New failures are appended below by the script.
crbug.com/714962 accessibility/adjacent-continuations-cause-assertion-failure.html [ Failure ]
crbug.com/591099 accessibility/aom-relation-list-properties.html [ Failure ]
crbug.com/591099 accessibility/aria-labelledby-stay-within.html [ Failure ]
crbug.com/591099 accessibility/aria-owns.html [ Failure ]
crbug.com/591099 accessibility/aria-tab-roles.html [ Failure ]
crbug.com/714962 accessibility/aria-tables.html [ Failure ]
crbug.com/714962 accessibility/background-color.html [ Failure ]
crbug.com/714962 accessibility/bounds-calc.html [ Failure ]
crbug.com/591099 accessibility/canvas-fallback-content-2.html [ Timeout ]
crbug.com/714962 accessibility/css-first-letter-children.html [ Failure ]
crbug.com/591099 accessibility/css-generated-content.html [ Failure ]
crbug.com/591099 accessibility/css-styles.html [ Failure ]
crbug.com/591099 accessibility/default-language.html [ Failure ]
crbug.com/591099 accessibility/disabled-controls.html [ Failure ]
crbug.com/714962 accessibility/div-within-anchors-causes-crash.html [ Failure ]
crbug.com/714962 accessibility/dl-role.html [ Failure ]
crbug.com/714962 accessibility/first-letter-text-transform-causes-crash.html [ Failure ]
crbug.com/591099 accessibility/focusable-div.html [ Failure ]
crbug.com/591099 accessibility/focusable-span.html [ Failure ]
crbug.com/714962 accessibility/in-page-link-target.html [ Failure ]
crbug.com/591099 accessibility/inline-text-bidi-bounds-for-range.html [ Failure ]
crbug.com/714962 accessibility/inline-text-bounds-for-range-br.html [ Failure ]
crbug.com/591099 accessibility/inline-text-bounds-for-range.html [ Failure ]
crbug.com/591099 accessibility/inline-text-change-style.html [ Failure ]
crbug.com/591099 accessibility/inline-text-changes.html [ Failure ]
crbug.com/591099 accessibility/inline-text-word-boundaries.html [ Failure ]
crbug.com/591099 accessibility/language-attribute-and-meta-tag.html [ Failure ]
crbug.com/591099 accessibility/language-meta-tag-dynamically-changing.html [ Failure ]
crbug.com/714962 accessibility/legend.html [ Failure ]
crbug.com/591099 accessibility/listitem-presentation-inherited.html [ Failure ]
crbug.com/591099 accessibility/name-calc-aria-owns.html [ Failure ]
crbug.com/591099 accessibility/presentation-owned-elements.html [ Failure ]
crbug.com/591099 accessibility/role-attribute.html [ Failure ]
crbug.com/591099 accessibility/role-change.html [ Failure ]
crbug.com/714962 accessibility/selection-events.html [ Failure ]
crbug.com/714962 accessibility/set-selection-link.html [ Failure ]
crbug.com/591099 accessibility/table-caption.html [ Failure ]
crbug.com/591099 accessibility/table-header-column-row.html [ Failure ]
crbug.com/714962 accessibility/table-with-empty-thead-causes-crash.html [ Failure ]
crbug.com/591099 accessibility/table-with-presentation-role.html [ Failure ]
crbug.com/591099 animations/cross-fade-list-style-image.html [ Failure ]
crbug.com/591099 animations/rotate-transform-equivalent.html [ Failure ]
crbug.com/714962 compositing/background-color/view-blending-base-background.html [ Failure ]
......
......@@ -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/ng_abstract_inline_text_box.cc",
"ng/inline/ng_abstract_inline_text_box.h",
"ng/inline/ng_baseline.cc",
"ng/inline/ng_baseline.h",
"ng/inline/ng_bidi_paragraph.cc",
......
......@@ -4029,14 +4029,7 @@ const LayoutObject* AssociatedLayoutObjectOf(const Node& node,
if (static_cast<unsigned>(offset_in_node) >= threshold)
return layout_object;
}
LayoutObject* first_letter_layout_object =
layout_text_fragment->GetFirstLetterPseudoElement()->GetLayoutObject();
// TODO(yosin): We're not sure when |firstLetterLayoutObject| has
// multiple child layout object.
LayoutObject* child = first_letter_layout_object->SlowFirstChild();
CHECK(child && child->IsText());
DCHECK_EQ(child, first_letter_layout_object->SlowLastChild());
return child;
return layout_text_fragment->GetFirstLetterPart();
}
bool LayoutObject::CanBeSelectionLeaf() const {
......
......@@ -50,6 +50,7 @@
#include "third_party/blink/renderer/core/layout/line/glyph_overflow.h"
#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_rect.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_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"
......@@ -2214,8 +2215,18 @@ void LayoutText::MomentarilyRevealLastTypedCharacter(
}
scoped_refptr<AbstractInlineTextBox> LayoutText::FirstAbstractInlineTextBox() {
return AbstractInlineTextBox::GetOrCreate(LineLayoutText(this),
FirstTextBox());
if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
LayoutObject* const first_letter_part = GetFirstLetterPart();
auto fragments = NGPaintFragment::InlineFragmentsFor(
first_letter_part ? first_letter_part : this);
if (!fragments.IsEmpty() &&
fragments.IsInLayoutNGInlineFormattingContext()) {
return NGAbstractInlineTextBox::GetOrCreate(LineLayoutText(this),
**fragments.begin());
}
}
return LegacyAbstractInlineTextBox::GetOrCreate(LineLayoutText(this),
FirstTextBox());
}
void LayoutText::InvalidateDisplayItemClients(
......
......@@ -94,6 +94,9 @@ class CORE_EXPORT LayoutText : public LayoutObject {
virtual unsigned TextStartOffset() const { return 0; }
String PlainText() const;
// Returns first letter part of |LayoutTextFragment|.
virtual LayoutText* GetFirstLetterPart() { return nullptr; }
InlineTextBox* CreateInlineTextBox(int start, unsigned short length);
void DirtyOrDeleteLineBoxesIfNeeded(bool full_layout);
void DirtyLineBoxes();
......@@ -201,6 +204,9 @@ class CORE_EXPORT LayoutText : public LayoutObject {
const InlineTextBoxList& TextBoxes() const { return text_boxes_; }
// Returns first |InlineTextBox| produces for associated |Node|.
// Note: When |this| is remaining part of ::first-letter, this function
// returns first-letter part of |InlineTextBox| instead of remaining part.
InlineTextBox* FirstTextBox() const { return text_boxes_.First(); }
InlineTextBox* LastTextBox() const { return text_boxes_.Last(); }
......
......@@ -160,6 +160,19 @@ Text* LayoutTextFragment::AssociatedTextNode() const {
return (node && node->IsTextNode()) ? ToText(node) : nullptr;
}
LayoutText* LayoutTextFragment::GetFirstLetterPart() {
if (!is_remaining_text_layout_object_)
return nullptr;
// Node: We assume first letter pseudo element has only one child and it
// is LayoutTextFragment.
LayoutObject* const first_letter_container =
GetFirstLetterPseudoElement()->GetLayoutObject();
LayoutObject* const child = first_letter_container->SlowFirstChild();
CHECK(child->IsText());
DCHECK_EQ(child, first_letter_container->SlowLastChild());
return ToLayoutTextFragment(child);
}
void LayoutTextFragment::UpdateHitTestResult(HitTestResult& result,
const LayoutPoint& point) const {
if (result.InnerNode())
......
......@@ -94,6 +94,7 @@ class CORE_EXPORT LayoutTextFragment final : public LayoutText {
}
Text* AssociatedTextNode() const;
LayoutText* GetFirstLetterPart() override;
protected:
void WillBeDestroyed() override;
......
......@@ -37,35 +37,45 @@
namespace blink {
AbstractInlineTextBox::InlineToAbstractInlineTextBoxHashMap*
AbstractInlineTextBox::g_abstract_inline_text_box_map_ = nullptr;
AbstractInlineTextBox::AbstractInlineTextBox(LineLayoutText line_layout_item)
: line_layout_item_(line_layout_item) {}
scoped_refptr<AbstractInlineTextBox> AbstractInlineTextBox::GetOrCreate(
AbstractInlineTextBox::~AbstractInlineTextBox() {
DCHECK(!line_layout_item_);
}
// ----
LegacyAbstractInlineTextBox::InlineToLegacyAbstractInlineTextBoxHashMap*
LegacyAbstractInlineTextBox::g_abstract_inline_text_box_map_ = nullptr;
scoped_refptr<AbstractInlineTextBox> LegacyAbstractInlineTextBox::GetOrCreate(
LineLayoutText line_layout_text,
InlineTextBox* inline_text_box) {
if (!inline_text_box)
return nullptr;
if (!g_abstract_inline_text_box_map_)
if (!g_abstract_inline_text_box_map_) {
g_abstract_inline_text_box_map_ =
new InlineToAbstractInlineTextBoxHashMap();
new InlineToLegacyAbstractInlineTextBoxHashMap();
}
InlineToAbstractInlineTextBoxHashMap::const_iterator it =
InlineToLegacyAbstractInlineTextBoxHashMap::const_iterator it =
g_abstract_inline_text_box_map_->find(inline_text_box);
if (it != g_abstract_inline_text_box_map_->end())
return it->value;
scoped_refptr<AbstractInlineTextBox> obj = base::AdoptRef(
new AbstractInlineTextBox(line_layout_text, inline_text_box));
new LegacyAbstractInlineTextBox(line_layout_text, inline_text_box));
g_abstract_inline_text_box_map_->Set(inline_text_box, obj);
return obj;
}
void AbstractInlineTextBox::WillDestroy(InlineTextBox* inline_text_box) {
void LegacyAbstractInlineTextBox::WillDestroy(InlineTextBox* inline_text_box) {
if (!g_abstract_inline_text_box_map_)
return;
InlineToAbstractInlineTextBoxHashMap::const_iterator it =
InlineToLegacyAbstractInlineTextBoxHashMap::const_iterator it =
g_abstract_inline_text_box_map_->find(inline_text_box);
if (it != g_abstract_inline_text_box_map_->end()) {
it->value->Detach();
......@@ -73,51 +83,62 @@ void AbstractInlineTextBox::WillDestroy(InlineTextBox* inline_text_box) {
}
}
AbstractInlineTextBox::~AbstractInlineTextBox() {
DCHECK(!line_layout_item_);
LegacyAbstractInlineTextBox::LegacyAbstractInlineTextBox(
LineLayoutText line_layout_item,
InlineTextBox* inline_text_box)
: AbstractInlineTextBox(line_layout_item),
inline_text_box_(inline_text_box) {}
LegacyAbstractInlineTextBox::~LegacyAbstractInlineTextBox() {
DCHECK(!inline_text_box_);
}
void AbstractInlineTextBox::Detach() {
DCHECK(GetLineLayoutItem());
if (Node* node = GetNode()) {
if (AXObjectCache* cache = node->GetDocument().ExistingAXObjectCache())
cache->Remove(this);
}
line_layout_item_ = LineLayoutText(nullptr);
}
void LegacyAbstractInlineTextBox::Detach() {
AbstractInlineTextBox::Detach();
inline_text_box_ = nullptr;
}
scoped_refptr<AbstractInlineTextBox> AbstractInlineTextBox::NextInlineTextBox()
const {
scoped_refptr<AbstractInlineTextBox>
LegacyAbstractInlineTextBox::NextInlineTextBox() const {
DCHECK(!inline_text_box_ ||
!inline_text_box_->GetLineLayoutItem().NeedsLayout());
if (!inline_text_box_)
return nullptr;
return GetOrCreate(line_layout_item_,
return GetOrCreate(GetLineLayoutItem(),
inline_text_box_->NextForSameLayoutObject());
}
LayoutRect AbstractInlineTextBox::LocalBounds() const {
if (!inline_text_box_ || !line_layout_item_)
LayoutRect LegacyAbstractInlineTextBox::LocalBounds() const {
if (!inline_text_box_ || !GetLineLayoutItem())
return LayoutRect();
return inline_text_box_->FrameRect();
}
unsigned AbstractInlineTextBox::Len() const {
unsigned LegacyAbstractInlineTextBox::Len() const {
if (!inline_text_box_)
return 0;
return inline_text_box_->Len();
}
AbstractInlineTextBox::Direction AbstractInlineTextBox::GetDirection() const {
if (!inline_text_box_ || !line_layout_item_)
AbstractInlineTextBox::Direction LegacyAbstractInlineTextBox::GetDirection()
const {
if (!inline_text_box_ || !GetLineLayoutItem())
return kLeftToRight;
if (line_layout_item_.Style()->IsHorizontalWritingMode()) {
if (GetLineLayoutItem().Style()->IsHorizontalWritingMode()) {
return (inline_text_box_->Direction() == TextDirection::kRtl
? kRightToLeft
: kLeftToRight);
......@@ -127,12 +148,12 @@ AbstractInlineTextBox::Direction AbstractInlineTextBox::GetDirection() const {
}
Node* AbstractInlineTextBox::GetNode() const {
if (!line_layout_item_)
if (!GetLineLayoutItem())
return nullptr;
return line_layout_item_.GetNode();
return GetLineLayoutItem().GetNode();
}
void AbstractInlineTextBox::CharacterWidths(Vector<float>& widths) const {
void LegacyAbstractInlineTextBox::CharacterWidths(Vector<float>& widths) const {
if (!inline_text_box_)
return;
......@@ -141,7 +162,7 @@ void AbstractInlineTextBox::CharacterWidths(Vector<float>& widths) const {
void AbstractInlineTextBox::GetWordBoundaries(
Vector<WordBoundaries>& words) const {
if (!inline_text_box_)
if (Len() == 0)
return;
String text = GetText();
......@@ -161,13 +182,13 @@ void AbstractInlineTextBox::GetWordBoundaries(
}
}
String AbstractInlineTextBox::GetText() const {
if (!inline_text_box_ || !line_layout_item_)
String LegacyAbstractInlineTextBox::GetText() const {
if (!inline_text_box_ || !GetLineLayoutItem())
return String();
unsigned start = inline_text_box_->Start();
unsigned len = inline_text_box_->Len();
if (Node* node = line_layout_item_.GetNode()) {
if (Node* node = GetLineLayoutItem().GetNode()) {
if (node->IsTextNode()) {
return PlainText(
EphemeralRange(Position(node, start), Position(node, start + len)),
......@@ -179,7 +200,8 @@ String AbstractInlineTextBox::GetText() const {
TextIteratorBehavior::IgnoresStyleVisibilityBehavior());
}
String result = line_layout_item_.GetText()
String result = GetLineLayoutItem()
.GetText()
.Substring(start, len)
.SimplifyWhiteSpace(WTF::kDoNotStripWhiteSpace);
if (inline_text_box_->NextForSameLayoutObject() &&
......@@ -190,19 +212,20 @@ String AbstractInlineTextBox::GetText() const {
return result;
}
bool AbstractInlineTextBox::IsFirst() const {
bool LegacyAbstractInlineTextBox::IsFirst() const {
DCHECK(!inline_text_box_ ||
!inline_text_box_->GetLineLayoutItem().NeedsLayout());
return !inline_text_box_ || !inline_text_box_->PrevForSameLayoutObject();
}
bool AbstractInlineTextBox::IsLast() const {
bool LegacyAbstractInlineTextBox::IsLast() const {
DCHECK(!inline_text_box_ ||
!inline_text_box_->GetLineLayoutItem().NeedsLayout());
return !inline_text_box_ || !inline_text_box_->NextForSameLayoutObject();
}
scoped_refptr<AbstractInlineTextBox> AbstractInlineTextBox::NextOnLine() const {
scoped_refptr<AbstractInlineTextBox> LegacyAbstractInlineTextBox::NextOnLine()
const {
DCHECK(!inline_text_box_ ||
!inline_text_box_->GetLineLayoutItem().NeedsLayout());
if (!inline_text_box_)
......@@ -216,8 +239,8 @@ scoped_refptr<AbstractInlineTextBox> AbstractInlineTextBox::NextOnLine() const {
return nullptr;
}
scoped_refptr<AbstractInlineTextBox> AbstractInlineTextBox::PreviousOnLine()
const {
scoped_refptr<AbstractInlineTextBox>
LegacyAbstractInlineTextBox::PreviousOnLine() const {
DCHECK(!inline_text_box_ ||
!inline_text_box_->GetLineLayoutItem().NeedsLayout());
if (!inline_text_box_)
......
......@@ -47,19 +47,6 @@ class InlineTextBox;
// get information about InlineTextBoxes without tight coupling.
class CORE_EXPORT AbstractInlineTextBox
: public RefCounted<AbstractInlineTextBox> {
private:
AbstractInlineTextBox(LineLayoutText line_layout_item,
InlineTextBox* inline_text_box)
: line_layout_item_(line_layout_item),
inline_text_box_(inline_text_box) {}
static scoped_refptr<AbstractInlineTextBox> GetOrCreate(LineLayoutText,
InlineTextBox*);
static void WillDestroy(InlineTextBox*);
friend class LayoutText;
friend class InlineTextBox;
public:
struct WordBoundaries {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
......@@ -71,34 +58,71 @@ class CORE_EXPORT AbstractInlineTextBox
enum Direction { kLeftToRight, kRightToLeft, kTopToBottom, kBottomToTop };
~AbstractInlineTextBox();
virtual ~AbstractInlineTextBox();
LineLayoutText GetLineLayoutItem() const { return line_layout_item_; }
scoped_refptr<AbstractInlineTextBox> NextInlineTextBox() const;
LayoutRect LocalBounds() const;
unsigned Len() const;
Direction GetDirection() const;
virtual void Detach();
virtual scoped_refptr<AbstractInlineTextBox> NextInlineTextBox() const = 0;
virtual LayoutRect LocalBounds() const = 0;
virtual unsigned Len() const = 0;
virtual Direction GetDirection() const = 0;
Node* GetNode() const;
void CharacterWidths(Vector<float>&) const;
virtual void CharacterWidths(Vector<float>&) const = 0;
void GetWordBoundaries(Vector<WordBoundaries>&) const;
String GetText() const;
bool IsFirst() const;
bool IsLast() const;
scoped_refptr<AbstractInlineTextBox> NextOnLine() const;
scoped_refptr<AbstractInlineTextBox> PreviousOnLine() const;
virtual String GetText() const = 0;
virtual bool IsFirst() const = 0;
virtual bool IsLast() const = 0;
virtual scoped_refptr<AbstractInlineTextBox> NextOnLine() const = 0;
virtual scoped_refptr<AbstractInlineTextBox> PreviousOnLine() const = 0;
private:
void Detach();
protected:
explicit AbstractInlineTextBox(LineLayoutText line_layout_item);
private:
// Weak ptrs; these are nulled when InlineTextBox::destroy() calls
// AbstractInlineTextBox::willDestroy.
LineLayoutText line_layout_item_;
};
// The implementation of |AbstractInlineTextBox| for legacy layout.
// See also |NGAbstractInlineTextBox| for LayoutNG.
class CORE_EXPORT LegacyAbstractInlineTextBox final
: public AbstractInlineTextBox {
private:
LegacyAbstractInlineTextBox(LineLayoutText line_layout_item,
InlineTextBox* inline_text_box);
static scoped_refptr<AbstractInlineTextBox> GetOrCreate(LineLayoutText,
InlineTextBox*);
static void WillDestroy(InlineTextBox*);
friend class LayoutText;
friend class InlineTextBox;
public:
~LegacyAbstractInlineTextBox() final;
private:
// Implementations of AbstractInlineTextBox member functions.
void Detach() final;
scoped_refptr<AbstractInlineTextBox> NextInlineTextBox() const final;
LayoutRect LocalBounds() const final;
unsigned Len() const final;
Direction GetDirection() const final;
void CharacterWidths(Vector<float>&) const final;
String GetText() const final;
bool IsFirst() const final;
bool IsLast() const final;
scoped_refptr<AbstractInlineTextBox> NextOnLine() const final;
scoped_refptr<AbstractInlineTextBox> PreviousOnLine() const final;
InlineTextBox* inline_text_box_;
typedef HashMap<InlineTextBox*, scoped_refptr<AbstractInlineTextBox>>
InlineToAbstractInlineTextBoxHashMap;
static InlineToAbstractInlineTextBoxHashMap* g_abstract_inline_text_box_map_;
InlineToLegacyAbstractInlineTextBoxHashMap;
static InlineToLegacyAbstractInlineTextBoxHashMap*
g_abstract_inline_text_box_map_;
};
} // namespace blink
......
......@@ -58,7 +58,7 @@ typedef WTF::HashMap<const InlineTextBox*, LayoutRect> InlineTextBoxOverflowMap;
static InlineTextBoxOverflowMap* g_text_boxes_with_overflow;
void InlineTextBox::Destroy() {
AbstractInlineTextBox::WillDestroy(this);
LegacyAbstractInlineTextBox::WillDestroy(this);
if (!KnownToHaveNoOverflow() && g_text_boxes_with_overflow)
g_text_boxes_with_overflow->erase(this);
......
// 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_abstract_inline_text_box.h"
#include "third_party/blink/renderer/core/dom/ax_object_cache.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 {
NGAbstractInlineTextBox::FragmentToNGAbstractInlineTextBoxHashMap*
NGAbstractInlineTextBox::g_abstract_inline_text_box_map_ = nullptr;
scoped_refptr<AbstractInlineTextBox> NGAbstractInlineTextBox::GetOrCreate(
LineLayoutText line_layout_item,
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 auto it = g_abstract_inline_text_box_map_->find(&fragment);
if (it != g_abstract_inline_text_box_map_->end())
return it->value;
scoped_refptr<AbstractInlineTextBox> obj =
base::AdoptRef(new NGAbstractInlineTextBox(line_layout_item, fragment));
g_abstract_inline_text_box_map_->Set(&fragment, obj);
return obj;
}
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);
}
}
NGAbstractInlineTextBox::NGAbstractInlineTextBox(
LineLayoutText line_layout_item,
const NGPaintFragment& fragment)
: AbstractInlineTextBox(line_layout_item), fragment_(&fragment) {
DCHECK(fragment_->PhysicalFragment().IsText()) << fragment_;
}
NGAbstractInlineTextBox::~NGAbstractInlineTextBox() {
DCHECK(!fragment_);
}
void NGAbstractInlineTextBox::Detach() {
if (Node* const node = GetNode()) {
if (AXObjectCache* cache = node->GetDocument().ExistingAXObjectCache())
cache->InlineTextBoxesUpdated(GetLineLayoutItem());
}
AbstractInlineTextBox::Detach();
fragment_ = nullptr;
}
bool NGAbstractInlineTextBox::HasSoftWrapToNextLine() const {
return ToNGPhysicalLineBoxFragment(
fragment_->ContainerLineBox()->PhysicalFragment())
.HasSoftWrapToNextLine();
}
const NGPhysicalTextFragment& NGAbstractInlineTextBox::PhysicalTextFragment()
const {
return ToNGPhysicalTextFragment(fragment_->PhysicalFragment());
}
bool NGAbstractInlineTextBox::NeedsLayout() const {
return fragment_->GetLayoutObject()->NeedsLayout();
}
bool NGAbstractInlineTextBox::NeedsTrailingSpace() const {
if (!HasSoftWrapToNextLine())
return false;
const NGPaintFragment* next_fragment = NextTextFragmentForSameLayoutObject();
if (!next_fragment)
return false;
return ToNGPhysicalTextFragment(next_fragment->PhysicalFragment())
.StartOffset() != PhysicalTextFragment().EndOffset();
}
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;
}
scoped_refptr<AbstractInlineTextBox>
NGAbstractInlineTextBox::NextInlineTextBox() const {
if (!fragment_)
return nullptr;
DCHECK(!NeedsLayout());
const NGPaintFragment* next_fragment = NextTextFragmentForSameLayoutObject();
if (!next_fragment)
return nullptr;
return GetOrCreate(GetLineLayoutItem(), *next_fragment);
}
LayoutRect NGAbstractInlineTextBox::LocalBounds() const {
if (!fragment_ || !GetLineLayoutItem())
return LayoutRect();
return LayoutRect(fragment_->InlineOffsetToContainerBox().ToLayoutPoint(),
fragment_->Size().ToLayoutSize());
}
unsigned NGAbstractInlineTextBox::Len() const {
if (!fragment_)
return 0;
if (NeedsTrailingSpace())
return PhysicalTextFragment().Length() + 1;
return PhysicalTextFragment().Length();
}
AbstractInlineTextBox::Direction NGAbstractInlineTextBox::GetDirection() const {
if (!fragment_ || !GetLineLayoutItem())
return kLeftToRight;
const TextDirection text_direction =
PhysicalTextFragment().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_)
return;
// TODO(layout-dev): We should implement |CharacterWidths()|.
widths.resize(Len());
}
String NGAbstractInlineTextBox::GetText() const {
if (!fragment_ || !GetLineLayoutItem())
return String();
// For compatibility with |InlineTextBox|, we should have a space character
// for soft line break.
// Following tests require this:
// - accessibility/inline-text-change-style.html
// - accessibility/inline-text-changes.html
// - accessibility/inline-text-word-boundaries.html
if (NeedsTrailingSpace())
return PhysicalTextFragment().Text().ToString() + " ";
return PhysicalTextFragment().Text().ToString();
}
bool NGAbstractInlineTextBox::IsFirst() const {
if (!fragment_)
return true;
DCHECK(!NeedsLayout());
const auto fragments =
NGPaintFragment::InlineFragmentsFor(fragment_->GetLayoutObject());
return fragment_ == &fragments.front();
}
bool NGAbstractInlineTextBox::IsLast() const {
if (!fragment_)
return true;
DCHECK(!NeedsLayout());
const auto fragments =
NGPaintFragment::InlineFragmentsFor(fragment_->GetLayoutObject());
return fragment_ == &fragments.back();
}
scoped_refptr<AbstractInlineTextBox> NGAbstractInlineTextBox::NextOnLine()
const {
if (!fragment_)
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(GetLineLayoutItem(), *cursor);
}
return nullptr;
}
scoped_refptr<AbstractInlineTextBox> NGAbstractInlineTextBox::PreviousOnLine()
const {
if (!fragment_)
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(GetLineLayoutItem(), *cursor);
}
return nullptr;
}
} // 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_ABSTRACT_INLINE_TEXT_BOX_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_ABSTRACT_INLINE_TEXT_BOX_H_
#include "third_party/blink/renderer/core/layout/line/abstract_inline_text_box.h"
namespace blink {
class NGPaintFragment;
class NGPhysicalTextFragment;
// The implementation of |AbstractInlineTextBox| for LayoutNG.
// See also |LegacyAbstractInlineTextBox| for legacy layout.
class CORE_EXPORT NGAbstractInlineTextBox final : public AbstractInlineTextBox {
private:
// Returns existing or newly created |NGAbstractInlineTextBox|.
// * |line_layout_item| is |LayoutText| associated to |fragment|. For first
// letter part, it is remaining part of |LayoutTextFragment|.
// * |fragment| should be attached to |NGPhysicalTextFragment|.
static scoped_refptr<AbstractInlineTextBox> GetOrCreate(
LineLayoutText line_layout_item,
const NGPaintFragment& fragment);
static void WillDestroy(NGPaintFragment*);
friend class LayoutText;
friend class NGPaintFragment;
public:
~NGAbstractInlineTextBox() final;
private:
NGAbstractInlineTextBox(LineLayoutText line_layout_item,
const NGPaintFragment& fragment);
bool HasSoftWrapToNextLine() const;
const NGPhysicalTextFragment& PhysicalTextFragment() const;
bool NeedsLayout() const;
bool NeedsTrailingSpace() const;
// Returns next fragment associated to |LayoutText|.
const NGPaintFragment* NextTextFragmentForSameLayoutObject() const;
// Implementations of AbstractInlineTextBox member functions.
void Detach() final;
scoped_refptr<AbstractInlineTextBox> NextInlineTextBox() const final;
LayoutRect LocalBounds() const final;
unsigned Len() const final;
Direction GetDirection() const final;
void CharacterWidths(Vector<float>&) const final;
String GetText() const final;
bool IsFirst() const final;
bool IsLast() const final;
scoped_refptr<AbstractInlineTextBox> NextOnLine() const final;
scoped_refptr<AbstractInlineTextBox> PreviousOnLine() const final;
const NGPaintFragment* fragment_;
using FragmentToNGAbstractInlineTextBoxHashMap =
HashMap<const NGPaintFragment*, scoped_refptr<AbstractInlineTextBox>>;
static FragmentToNGAbstractInlineTextBoxHashMap*
g_abstract_inline_text_box_map_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_ABSTRACT_INLINE_TEXT_BOX_H_
......@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
#include "third_party/blink/renderer/core/layout/layout_text.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
namespace blink {
......@@ -64,4 +65,8 @@ LayoutObject* LayoutNGListMarker::SymbolMarkerLayoutText() const {
return ListItem()->SymbolMarkerLayoutText();
}
String LayoutNGListMarker::TextAlternative() const {
return ToLayoutText(FirstChild())->GetText();
}
} // namespace blink
......@@ -35,6 +35,9 @@ class CORE_EXPORT LayoutNGListMarker final
LayoutObject* SymbolMarkerLayoutText() const;
// Marker text with suffix, e.g. "1. ", for use in accessibility.
String TextAlternative() const;
const char* GetName() const override { return "LayoutNGListMarker"; }
private:
......
......@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_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_abstract_inline_text_box.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_physical_line_box_fragment.h"
......@@ -154,6 +155,10 @@ NGPaintFragment::NGPaintFragment(
DCHECK(physical_fragment_);
}
NGPaintFragment::~NGPaintFragment() {
NGAbstractInlineTextBox::WillDestroy(this);
}
std::unique_ptr<NGPaintFragment> NGPaintFragment::Create(
scoped_refptr<const NGPhysicalFragment> fragment) {
std::unique_ptr<NGPaintFragment> paint_fragment =
......
......@@ -5,6 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_PAINT_FRAGMENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_PAINT_FRAGMENT_H_
#include <iterator>
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
#include "third_party/blink/renderer/core/loader/resource/image_resource_observer.h"
......@@ -36,6 +38,7 @@ class CORE_EXPORT NGPaintFragment : public DisplayItemClient,
public ImageResourceObserver {
public:
NGPaintFragment(scoped_refptr<const NGPhysicalFragment>, NGPaintFragment*);
~NGPaintFragment() override;
static std::unique_ptr<NGPaintFragment> Create(
scoped_refptr<const NGPhysicalFragment>);
......@@ -148,7 +151,8 @@ class CORE_EXPORT NGPaintFragment : public DisplayItemClient,
bool IsEmpty() const { return !first_; }
class iterator {
class iterator final
: public std::iterator<std::forward_iterator_tag, NGPaintFragment*> {
public:
explicit iterator(NGPaintFragment* first) : current_(first) {}
......
......@@ -82,6 +82,8 @@
#include "third_party/blink/renderer/core/layout/layout_text_control.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_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
#include "third_party/blink/renderer/core/loader/progress_tracker.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
......@@ -137,6 +139,10 @@ static inline bool IsInlineWithContinuation(LayoutObject* object) {
static inline LayoutObject* FirstChildConsideringContinuation(
LayoutObject* layout_object) {
if (layout_object->IsLayoutNGListMarker()) {
// We don't care tree structure of list marker.
return nullptr;
}
LayoutObject* first_child = layout_object->SlowFirstChild();
// CSS first-letter pseudo element is handled as continuation. Returning it
......@@ -257,7 +263,7 @@ AccessibilityRole AXLayoutObject::NativeAccessibilityRoleIgnoringAria() const {
if ((css_box && css_box->IsListItem()) || IsHTMLLIElement(node))
return kListItemRole;
if (layout_object_->IsListMarker())
if (layout_object_->IsListMarkerIncludingNG())
return kListMarkerRole;
if (layout_object_->IsBR())
return kLineBreakRole;
......@@ -542,6 +548,15 @@ bool HasAriaAttribute(Element* element) {
return false;
}
static bool HasLineBox(const LayoutBlockFlow& block_flow) {
if (!block_flow.IsLayoutNGMixin())
return block_flow.FirstLineBox();
if (block_flow.HasNGInlineNodeData())
return !block_flow.GetNGInlineNodeData()->items.IsEmpty();
// TODO(layout-dev): We should call this function after layout completion.
return false;
}
bool AXLayoutObject::ComputeAccessibilityIsIgnored(
IgnoredReasons* ignored_reasons) const {
#if DCHECK_IS_ON()
......@@ -750,7 +765,7 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
// to decide.
}
if (IsWebArea() || layout_object_->IsListMarker())
if (IsWebArea() || layout_object_->IsListMarkerIncludingNG())
return false;
// Using the help text, title or accessibility description (so we
......@@ -788,7 +803,7 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
!CanSetFocusAttribute()) {
// If the layout object has any plain text in it, that text will be
// inside a LineBox, so the layout object will have a first LineBox.
bool has_any_text = !!ToLayoutBlockFlow(layout_object_)->FirstLineBox();
bool has_any_text = HasLineBox(ToLayoutBlockFlow(*layout_object_));
// Always include interesting-looking objects.
if (has_any_text || MouseButtonListener())
......@@ -1245,7 +1260,7 @@ static bool ShouldUseLayoutNG(const LayoutObject& layout_object) {
static AXObject* NextOnLineInternalNG(const AXObject& ax_object) {
DCHECK(ax_object.GetLayoutObject());
const LayoutObject& layout_object = *ax_object.GetLayoutObject();
DCHECK(!layout_object.IsListMarker()) << layout_object;
DCHECK(!layout_object.IsListMarkerIncludingNG()) << layout_object;
DCHECK(ShouldUseLayoutNG(layout_object)) << layout_object;
const auto fragments = NGPaintFragment::InlineFragmentsFor(&layout_object);
if (fragments.IsEmpty() || fragments.IsInLayoutNGInlineFormattingContext())
......@@ -1271,7 +1286,7 @@ AXObject* AXLayoutObject::NextOnLine() const {
return nullptr;
AXObject* result = nullptr;
if (GetLayoutObject()->IsListMarker()) {
if (GetLayoutObject()->IsListMarkerIncludingNG()) {
AXObject* next_sibling = RawNextSibling();
if (!next_sibling || !next_sibling->Children().size())
return nullptr;
......@@ -1318,7 +1333,7 @@ AXObject* AXLayoutObject::NextOnLine() const {
static AXObject* PreviousOnLineInlineNG(const AXObject& ax_object) {
DCHECK(ax_object.GetLayoutObject());
const LayoutObject& layout_object = *ax_object.GetLayoutObject();
DCHECK(!layout_object.IsListMarker()) << layout_object;
DCHECK(!layout_object.IsListMarkerIncludingNG()) << layout_object;
DCHECK(ShouldUseLayoutNG(layout_object)) << layout_object;
const auto fragments = NGPaintFragment::InlineFragmentsFor(&layout_object);
if (fragments.IsEmpty() || fragments.IsInLayoutNGInlineFormattingContext())
......@@ -1477,6 +1492,10 @@ String AXLayoutObject::TextAlternative(bool recursive,
} else if (layout_object_->IsListMarker() && !recursive) {
text_alternative = ToLayoutListMarker(layout_object_)->TextAlternative();
found_text_alternative = true;
} else if (layout_object_->IsLayoutNGListMarker() && !recursive) {
text_alternative =
ToLayoutNGListMarker(layout_object_)->TextAlternative();
found_text_alternative = true;
}
if (found_text_alternative) {
......
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