Commit 649ccd28 authored by Aaron Leventhal's avatar Aaron Leventhal Committed by Commit Bot

Unify AddChildren() methods

By unifying  AddChildren() methods, the code is easier to follow and
harder to break.

NOTRY=true

Bug: None
Change-Id: I385a73fa5bb72cb4b733a4f42bd9f35727660ec0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2101372
Commit-Queue: Aaron Leventhal <aleventhal@chromium.org>
Reviewed-by: default avatarNektarios Paisios <nektar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#750239}
parent a1577a40
...@@ -1227,25 +1227,6 @@ AXLayoutObject::TextDecorationStyleToAXTextDecorationStyle( ...@@ -1227,25 +1227,6 @@ AXLayoutObject::TextDecorationStyleToAXTextDecorationStyle(
return ax::mojom::TextDecorationStyle::kNone; return ax::mojom::TextDecorationStyle::kNone;
} }
//
// Inline text boxes.
//
void AXLayoutObject::LoadInlineTextBoxes() {
if (!GetLayoutObject())
return;
if (GetLayoutObject()->IsText()) {
ClearChildren();
AddInlineTextBoxChildren(true);
return;
}
for (const auto& child : children_) {
child->LoadInlineTextBoxes();
}
}
static bool ShouldUseLayoutNG(const LayoutObject& layout_object) { static bool ShouldUseLayoutNG(const LayoutObject& layout_object) {
return (layout_object.IsInline() || layout_object.IsLayoutInline() || return (layout_object.IsInline() || layout_object.IsLayoutInline() ||
layout_object.IsText()) && layout_object.IsText()) &&
...@@ -2143,90 +2124,6 @@ AXObject* AXLayoutObject::ComputeParentIfExists() const { ...@@ -2143,90 +2124,6 @@ AXObject* AXLayoutObject::ComputeParentIfExists() const {
return nullptr; return nullptr;
} }
bool AXLayoutObject::ShouldUseDOMTraversal() const {
// TODO(accessibility) Look into having one method of traversal, otherwise
// it's possible for the same object to become a child of 2 different nodes,
// e.g. if it has a different layout parent and DOM parent.
bool is_continuation = layout_object_->IsElementContinuation();
// Avoid calling AXNodeObject logic for continuations.
if (is_continuation)
return false;
Node* node = GetNode();
if (!node)
return false;
// <ruby>: special layout handling
if (IsA<HTMLRubyElement>(*node))
return false;
// <table>: a thead/tfoot in the middle are bumped to the top/bottom in
// the layout representation.
if (IsA<HTMLTableElement>(*node))
return false;
// For now, at least the #docment node needs to use layout traversal, because
// of validation messages, dialog, etc.
// TODO(aleventhal) figure out how to avoid double <dialog> nodes.
Element* element = GetElement();
if (!element)
return false;
// Pseudo elements often have text children that are not
// visited by the LayoutTreeBuilderTraversal class used in DOM traversal.
// Without this condition, list bullets would not have static text children.
if (element->IsPseudoElement())
return false;
return true;
}
void AXLayoutObject::AddChildren() {
if (IsDetached())
return;
if (ShouldUseDOMTraversal()) {
AXNodeObject::AddChildren();
return;
}
// If the need to add more children in addition to existing children arises,
// childrenChanged should have been called, leaving the object with no
// children.
DCHECK(!have_children_);
have_children_ = true;
AXObjectVector owned_children;
ComputeAriaOwnsChildren(owned_children);
for (AXObject* obj = RawFirstChild(); obj; obj = obj->RawNextSibling()) {
if (!AXObjectCache().IsAriaOwned(obj))
AddChild(obj);
}
AddHiddenChildren();
AddPopupChildren();
AddRemoteSVGChildren();
AddTableChildren();
AddInlineTextBoxChildren(false);
AddValidationMessageChild();
AddAccessibleNodeChildren();
for (const auto& owned_child : owned_children)
AddChild(owned_child);
bool is_continuation = layout_object_->IsElementContinuation();
for (const auto& child : children_) {
if (!is_continuation && !child->CachedParentObject()) {
// Never set continuations as a parent object. The first layout object
// in the chain must be used instead.
child->SetParent(this);
}
}
}
bool AXLayoutObject::CanHaveChildren() const { bool AXLayoutObject::CanHaveChildren() const {
if (!layout_object_) if (!layout_object_)
return false; return false;
...@@ -2477,44 +2374,6 @@ void AXLayoutObject::TextChanged() { ...@@ -2477,44 +2374,6 @@ void AXLayoutObject::TextChanged() {
AXNodeObject::TextChanged(); AXNodeObject::TextChanged();
} }
void AXLayoutObject::AddInlineTextBoxChildren(bool force) {
Document* document = GetDocument();
if (!document)
return;
Settings* settings = document->GetSettings();
if (!force &&
(!settings || !settings->GetInlineTextBoxAccessibilityEnabled()))
return;
if (!GetLayoutObject() || !GetLayoutObject()->IsText())
return;
if (GetLayoutObject()->NeedsLayout()) {
// If a LayoutText needs layout, its inline text boxes are either
// nonexistent or invalid, so defer until the layout happens and
// the layoutObject calls AXObjectCacheImpl::inlineTextBoxesUpdated.
return;
}
LayoutText* layout_text = ToLayoutText(GetLayoutObject());
for (scoped_refptr<AbstractInlineTextBox> box =
layout_text->FirstAbstractInlineTextBox();
box.get(); box = box->NextInlineTextBox()) {
AXObject* ax_object = AXObjectCache().GetOrCreate(box.get());
if (ax_object->AccessibilityIsIncludedInTree())
children_.push_back(ax_object);
}
}
void AXLayoutObject::AddValidationMessageChild() {
if (!IsWebArea())
return;
AXObject* ax_object = AXObjectCache().ValidationMessageObjectIfInvalid();
if (ax_object)
children_.push_back(ax_object);
}
AXObject* AXLayoutObject::ErrorMessage() const { AXObject* AXLayoutObject::ErrorMessage() const {
// Check for aria-errormessage. // Check for aria-errormessage.
Element* existing_error_message = Element* existing_error_message =
...@@ -3059,22 +2918,11 @@ AXObject* AXLayoutObject::AccessibilityImageMapHitTest( ...@@ -3059,22 +2918,11 @@ AXObject* AXLayoutObject::AccessibilityImageMapHitTest(
return nullptr; return nullptr;
} }
bool AXLayoutObject::IsSVGImage() const {
return RemoteSVGRootElement();
}
void AXLayoutObject::DetachRemoteSVGRoot() { void AXLayoutObject::DetachRemoteSVGRoot() {
if (AXSVGRoot* root = RemoteSVGRootElement()) if (AXSVGRoot* root = RemoteSVGRootElement())
root->SetParent(nullptr); root->SetParent(nullptr);
} }
AXSVGRoot* AXLayoutObject::RemoteSVGRootElement() const {
// FIXME(dmazzoni): none of this code properly handled multiple references to
// the same remote SVG document. I'm disabling this support until it can be
// fixed properly.
return nullptr;
}
AXObject* AXLayoutObject::RemoteSVGElementHitTest(const IntPoint& point) const { AXObject* AXLayoutObject::RemoteSVGElementHitTest(const IntPoint& point) const {
AXObject* remote = RemoteSVGRootElement(); AXObject* remote = RemoteSVGRootElement();
if (!remote) if (!remote)
...@@ -3100,125 +2948,4 @@ void AXLayoutObject::OffsetBoundingBoxForRemoteSVGElement( ...@@ -3100,125 +2948,4 @@ void AXLayoutObject::OffsetBoundingBoxForRemoteSVGElement(
} }
} }
// Hidden children are those that are not laid out or visible, but are
// specifically marked as aria-hidden=false,
// meaning that they should be exposed to the AX hierarchy.
void AXLayoutObject::AddHiddenChildren() {
Node* node = this->GetNode();
if (!node)
return;
// First do a quick run through to determine if we have any hidden nodes (most
// often we will not). If we do have hidden nodes, we need to determine where
// to insert them so they match DOM order as close as possible.
bool should_insert_hidden_nodes = false;
for (Node& child : NodeTraversal::ChildrenOf(*node)) {
if (!child.GetLayoutObject() && IsNodeAriaVisible(&child)) {
should_insert_hidden_nodes = true;
break;
}
}
if (!should_insert_hidden_nodes)
return;
// Iterate through all of the children, including those that may have already
// been added, and try to insert hidden nodes in the correct place in the DOM
// order.
unsigned insertion_index = 0;
for (Node& child : NodeTraversal::ChildrenOf(*node)) {
if (child.GetLayoutObject()) {
// Find out where the last layout sibling is located within m_children.
if (AXObject* child_object =
AXObjectCache().Get(child.GetLayoutObject())) {
if (!child_object->AccessibilityIsIncludedInTree()) {
const auto& children = child_object->Children();
child_object = children.size() ? children.back().Get() : nullptr;
}
if (child_object)
insertion_index = children_.Find(child_object) + 1;
continue;
}
}
if (!IsNodeAriaVisible(&child))
continue;
unsigned previous_size = children_.size();
if (insertion_index > previous_size)
insertion_index = previous_size;
InsertChild(AXObjectCache().GetOrCreate(&child), insertion_index);
insertion_index += (children_.size() - previous_size);
}
}
void AXLayoutObject::AddImageMapChildren() {
LayoutBoxModelObject* css_box = GetLayoutBoxModelObject();
if (!css_box || !css_box->IsLayoutImage())
return;
HTMLMapElement* map = ToLayoutImage(css_box)->ImageMap();
if (!map)
return;
for (HTMLAreaElement& area :
Traversal<HTMLAreaElement>::DescendantsOf(*map)) {
// add an <area> element for this child if it has a link
AXObject* obj = AXObjectCache().GetOrCreate(&area);
if (obj) {
auto* area_object = To<AXImageMapLink>(obj);
area_object->SetParent(this);
DCHECK_NE(area_object->AXObjectID(), 0U);
if (area_object->AccessibilityIsIncludedInTree())
children_.push_back(area_object);
else
AXObjectCache().Remove(area_object->AXObjectID());
}
}
}
void AXLayoutObject::AddPopupChildren() {
auto* html_input_element = DynamicTo<HTMLInputElement>(GetNode());
if (!html_input_element)
return;
if (AXObject* ax_popup = html_input_element->PopupRootAXObject())
children_.push_back(ax_popup);
}
void AXLayoutObject::AddRemoteSVGChildren() {
AXSVGRoot* root = RemoteSVGRootElement();
if (!root)
return;
root->SetParent(this);
if (!root->AccessibilityIsIncludedInTree()) {
for (const auto& child : root->Children())
children_.push_back(child);
} else {
children_.push_back(root);
}
}
void AXLayoutObject::AddTableChildren() {
if (!IsTableLikeRole())
return;
AXObjectCacheImpl& ax_cache = AXObjectCache();
if (layout_object_->IsTable()) {
LayoutNGTableInterface* table =
ToInterface<LayoutNGTableInterface>(layout_object_);
table->RecalcSectionsIfNeeded();
Node* table_node = table->ToLayoutObject()->GetNode();
if (auto* html_table_element = DynamicTo<HTMLTableElement>(table_node)) {
if (HTMLTableCaptionElement* caption = html_table_element->caption()) {
AXObject* caption_object = ax_cache.GetOrCreate(caption);
if (caption_object && caption_object->AccessibilityIsIncludedInTree())
children_.push_front(caption_object);
}
}
}
}
} // namespace blink } // namespace blink
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
namespace blink { namespace blink {
class AXObjectCacheImpl; class AXObjectCacheImpl;
class AXSVGRoot;
class Element; class Element;
class HTMLAreaElement; class HTMLAreaElement;
class IntPoint; class IntPoint;
...@@ -51,7 +50,6 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { ...@@ -51,7 +50,6 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
// Public, overridden from AXObject. // Public, overridden from AXObject.
LayoutObject* GetLayoutObject() const final { return layout_object_; } LayoutObject* GetLayoutObject() const final { return layout_object_; }
LayoutBoxModelObject* GetLayoutBoxModelObject() const;
ScrollableArea* GetScrollableAreaIfScrollable() const final; ScrollableArea* GetScrollableAreaIfScrollable() const final;
ax::mojom::Role DetermineAccessibilityRole() override; ax::mojom::Role DetermineAccessibilityRole() override;
ax::mojom::Role NativeRoleIgnoringAria() const override; ax::mojom::Role NativeRoleIgnoringAria() const override;
...@@ -63,6 +61,8 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { ...@@ -63,6 +61,8 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
protected: protected:
LayoutObject* layout_object_; LayoutObject* layout_object_;
LayoutBoxModelObject* GetLayoutBoxModelObject() const override;
LayoutObject* LayoutObjectForRelativeBounds() const override { LayoutObject* LayoutObjectForRelativeBounds() const override {
return layout_object_; return layout_object_;
} }
...@@ -120,7 +120,6 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { ...@@ -120,7 +120,6 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
ax::mojom::TextDecorationStyle* text_underline_style) const final; ax::mojom::TextDecorationStyle* text_underline_style) const final;
// Inline text boxes. // Inline text boxes.
void LoadInlineTextBoxes() override;
AXObject* NextOnLine() const override; AXObject* NextOnLine() const override;
AXObject* PreviousOnLine() const override; AXObject* PreviousOnLine() const override;
...@@ -164,11 +163,6 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { ...@@ -164,11 +163,6 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
// accessibility module. // accessibility module.
AXObject* RawFirstChild() const override; AXObject* RawFirstChild() const override;
AXObject* RawNextSibling() const override; AXObject* RawNextSibling() const override;
void AddChildren() override;
void AddInlineTextBoxChildren(bool force) override;
void AddImageMapChildren() override;
void AddHiddenChildren() override;
void AddPopupChildren() override;
bool CanHaveChildren() const override; bool CanHaveChildren() const override;
// Properties of the object's owning document or page. // Properties of the object's owning document or page.
...@@ -214,14 +208,9 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { ...@@ -214,14 +208,9 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
bool IsTabItemSelected() const; bool IsTabItemSelected() const;
AXObject* AccessibilityImageMapHitTest(HTMLAreaElement*, AXObject* AccessibilityImageMapHitTest(HTMLAreaElement*,
const IntPoint&) const; const IntPoint&) const;
bool IsSVGImage() const;
void DetachRemoteSVGRoot(); void DetachRemoteSVGRoot();
AXSVGRoot* RemoteSVGRootElement() const;
AXObject* RemoteSVGElementHitTest(const IntPoint&) const; AXObject* RemoteSVGElementHitTest(const IntPoint&) const;
void OffsetBoundingBoxForRemoteSVGElement(LayoutRect&) const; void OffsetBoundingBoxForRemoteSVGElement(LayoutRect&) const;
void AddRemoteSVGChildren();
void AddTableChildren();
void AddValidationMessageChild();
bool FindAllTableCellsWithRole(ax::mojom::Role, AXObjectVector&) const; bool FindAllTableCellsWithRole(ax::mojom::Role, AXObjectVector&) const;
LayoutRect ComputeElementRect() const; LayoutRect ComputeElementRect() const;
...@@ -231,7 +220,6 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { ...@@ -231,7 +220,6 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
bool IsPlaceholder() const; bool IsPlaceholder() const;
ax::mojom::Dropeffect ParseDropeffect(String& dropeffect) const; ax::mojom::Dropeffect ParseDropeffect(String& dropeffect) const;
bool SelectionShouldFollowFocus() const; bool SelectionShouldFollowFocus() const;
bool ShouldUseDOMTraversal() const;
static ax::mojom::TextDecorationStyle static ax::mojom::TextDecorationStyle
TextDecorationStyleToAXTextDecorationStyle( TextDecorationStyleToAXTextDecorationStyle(
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
namespace blink { namespace blink {
class AXObjectCacheImpl; class AXObjectCacheImpl;
class AXSVGRoot;
class Element; class Element;
class HTMLLabelElement; class HTMLLabelElement;
class Node; class Node;
...@@ -197,10 +198,6 @@ class MODULES_EXPORT AXNodeObject : public AXObject { ...@@ -197,10 +198,6 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
AXObject* RawFirstChild() const override; AXObject* RawFirstChild() const override;
AXObject* RawNextSibling() const override; AXObject* RawNextSibling() const override;
void AddChildren() override; void AddChildren() override;
virtual void AddInlineTextBoxChildren(bool force) {}
virtual void AddImageMapChildren() {}
virtual void AddHiddenChildren() {}
virtual void AddPopupChildren() {}
bool CanHaveChildren() const override; bool CanHaveChildren() const override;
void AddChild(AXObject*); void AddChild(AXObject*);
...@@ -236,6 +233,17 @@ class MODULES_EXPORT AXNodeObject : public AXObject { ...@@ -236,6 +233,17 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
void ComputeAriaOwnsChildren( void ComputeAriaOwnsChildren(
HeapVector<Member<AXObject>>& owned_children) const; HeapVector<Member<AXObject>>& owned_children) const;
// Inline text boxes.
void LoadInlineTextBoxes() override;
// SVG.
bool IsSVGImage() const { return RemoteSVGRootElement(); }
AXSVGRoot* RemoteSVGRootElement() const;
virtual LayoutBoxModelObject* GetLayoutBoxModelObject() const {
return nullptr;
}
FRIEND_TEST_ALL_PREFIXES(AccessibilityTest, SetNeedsToUpdateChildren); FRIEND_TEST_ALL_PREFIXES(AccessibilityTest, SetNeedsToUpdateChildren);
FRIEND_TEST_ALL_PREFIXES(AccessibilityTest, UpdateChildrenIfNecessary); FRIEND_TEST_ALL_PREFIXES(AccessibilityTest, UpdateChildrenIfNecessary);
...@@ -253,6 +261,16 @@ class MODULES_EXPORT AXNodeObject : public AXObject { ...@@ -253,6 +261,16 @@ class MODULES_EXPORT AXNodeObject : public AXObject {
bool IsDescendantOfElementType(HashSet<QualifiedName>& tag_names) const; bool IsDescendantOfElementType(HashSet<QualifiedName>& tag_names) const;
String PlaceholderFromNativeAttribute() const; String PlaceholderFromNativeAttribute() const;
void AddInlineTextBoxChildren(bool force);
void AddImageMapChildren();
void AddHiddenChildren();
void AddPopupChildren();
void AddRemoteSVGChildren();
void AddTableChildren();
void AddValidationMessageChild();
// For some nodes, only LayoutBuilderTraversal visits the necessary children.
bool ShouldUseLayoutBuilderTraversal() const;
DISALLOW_COPY_AND_ASSIGN(AXNodeObject); DISALLOW_COPY_AND_ASSIGN(AXNodeObject);
}; };
......
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