bool AccessibilityObject::allowsTextRanges() const { // Check type for the AccessibilityObject. if (isTextControl() || isWebArea() || isGroup() || isLink() || isHeading() || isListItem() || isTableCell()) return true; // Check roles as the last fallback mechanism. AccessibilityRole role = roleValue(); return role == ParagraphRole || role == LabelRole || role == DivRole || role == FormRole; }
bool AccessibilitySVGElement::inheritsPresentationalRole() const { if (canSetFocusAttribute()) return false; AccessibilityRole role = roleValue(); if (role != AccessibilityRole::SVGTextPath && role != AccessibilityRole::SVGTSpan) return false; for (AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) { if (is<AccessibilityRenderObject>(*parent) && parent->element()->hasTagName(SVGNames::textTag)) return parent->roleValue() == AccessibilityRole::Presentational; } return false; }
AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const { AccessibilityObject* parent = parentObject(); if (!parent) return DefaultBehavior; AccessibilityRole role = roleValue(); if (role == SplitterRole) return IncludeObject; // We expose the slider as a whole but not its value indicator. if (role == SliderThumbRole) return IgnoreObject; // When a list item is made up entirely of children (e.g. paragraphs) // the list item gets ignored. We need it. if (isGroup() && parent->isList()) return IncludeObject; // Entries and password fields have extraneous children which we want to ignore. if (parent->isPasswordField() || parent->isTextControl()) return IgnoreObject; // Include all tables, even layout tables. The AT can decide what to do with each. if (role == CellRole || role == TableRole) return IncludeObject; // The object containing the text should implement AtkText itself. if (role == StaticTextRole) return IgnoreObject; // Include all list items, regardless they have or not inline children if (role == ListItemRole) return IncludeObject; // Bullets/numbers for list items shouldn't be exposed as AtkObjects. if (role == ListMarkerRole) return IgnoreObject; // Never expose an unknown object, since AT's won't know what to // do with them. This is what is done on the Mac as well. if (role == UnknownRole) return IgnoreObject; return DefaultBehavior; }
bool AccessibilitySVGElement::computeAccessibilityIsIgnored() const { // According to the SVG Accessibility API Mappings spec, items should be excluded if: // * They would be excluded according to the Core Accessibility API Mappings. // * They are neither perceivable nor interactive. // * Their first mappable role is presentational, unless they have a global ARIA // attribute (covered by Core AAM) or at least one 'title' or 'desc' child element. // * They have an ancestor with Children Presentational: True (covered by Core AAM) AccessibilityObjectInclusion decision = defaultObjectInclusion(); if (decision == AccessibilityObjectInclusion::IgnoreObject) return true; if (m_renderer->isSVGHiddenContainer()) return true; // The SVG AAM states objects with at least one 'title' or 'desc' element MUST be included. // At this time, the presence of a matching 'lang' attribute is not mentioned in the spec. for (const auto& child : childrenOfType<SVGElement>(*element())) { if ((is<SVGTitleElement>(child) || is<SVGDescElement>(child))) return false; } if (roleValue() == AccessibilityRole::Presentational || inheritsPresentationalRole()) return true; if (ariaRoleAttribute() != AccessibilityRole::Unknown) return false; // The SVG AAM states text elements should also be included, if they have content. if (m_renderer->isSVGText() || m_renderer->isSVGTextPath()) { for (auto& child : childrenOfType<RenderText>(downcast<RenderElement>(*m_renderer))) { if (!child.isAllCollapsibleWhitespace()) return false; } } // SVG shapes should not be included unless there's a concrete reason for inclusion. // https://rawgit.com/w3c/aria/master/svg-aam/svg-aam.html#exclude_elements if (m_renderer->isSVGShape()) return !(hasAttributesRequiredForInclusion() || canSetFocusAttribute() || element()->hasEventListeners()); return AccessibilityRenderObject::computeAccessibilityIsIgnored(); }
AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const { AccessibilityObject* parent = parentObject(); if (!parent) return DefaultBehavior; AccessibilityRole role = roleValue(); if (role == HorizontalRuleRole) return IncludeObject; // We expose the slider as a whole but not its value indicator. if (role == SliderThumbRole) return IgnoreObject; // When a list item is made up entirely of children (e.g. paragraphs) // the list item gets ignored. We need it. if (isGroup() && parent->isList()) return IncludeObject; // Entries and password fields have extraneous children which we want to ignore. if (parent->isPasswordField() || parent->isTextControl()) return IgnoreObject; // Include all tables, even layout tables. The AT can decide what to do with each. if (role == CellRole || role == TableRole) return IncludeObject; // The object containing the text should implement AtkText itself. if (role == StaticTextRole) return IgnoreObject; // Include all list items, regardless they have or not inline children if (role == ListItemRole) return IncludeObject; // Bullets/numbers for list items shouldn't be exposed as AtkObjects. if (role == ListMarkerRole) return IgnoreObject; // Never expose an unknown object, since AT's won't know what to // do with them. This is what is done on the Mac as well. if (role == UnknownRole) return IgnoreObject; // Given a paragraph or div containing a non-nested anonymous block, WebCore // ignores the paragraph or div and includes the block. We want the opposite: // ATs are expecting accessible objects associated with textual elements. They // usually have no need for the anonymous block. And when the wrong objects // get included or ignored, needed accessibility signals do not get emitted. if (role == ParagraphRole || role == DivRole) { // Don't call textUnderElement() here, because it's slow and it can // crash when called while we're in the middle of a subtree being deleted. if (!renderer()->firstChildSlow()) return DefaultBehavior; if (!parent->renderer() || parent->renderer()->isAnonymousBlock()) return DefaultBehavior; for (RenderObject* r = renderer()->firstChildSlow(); r; r = r->nextSibling()) { if (r->isAnonymousBlock()) return IncludeObject; } } // Block spans result in objects of ATK_ROLE_PANEL which are almost always unwanted. // However, if we ignore block spans whose parent is the body, the child controls // will become immediate children of the ATK_ROLE_DOCUMENT_FRAME and any text will // become text within the document frame itself. This ultimately may be what we want // and would largely be consistent with what we see from Gecko. However, ignoring // spans whose parent is the body changes the current behavior we see from WebCore. // Until we have sufficient time to properly analyze these cases, we will defer to // WebCore. We only check that the parent is not aria because we do not expect // anonymous blocks which are aria-related to themselves have an aria role, nor // have we encountered instances where the parent of an anonymous block also lacked // an aria role but the grandparent had one. if (renderer() && renderer()->isAnonymousBlock() && !parent->renderer()->isBody() && parent->ariaRoleAttribute() == UnknownRole) return IgnoreObject; return DefaultBehavior; }