#include "core/accessibility/AXNodeObject.h"
#include "core/InputTypeNames.h"
-#include "core/accessibility/AXObjectCache.h"
+#include "core/accessibility/AXObjectCacheImpl.h"
#include "core/dom/NodeTraversal.h"
#include "core/dom/Text.h"
+#include "core/html/HTMLDListElement.h"
#include "core/html/HTMLFieldSetElement.h"
#include "core/html/HTMLFrameElementBase.h"
#include "core/html/HTMLInputElement.h"
Element* idElement = elements[i];
builder.append(accessibleNameForNode(idElement));
- for (Node* n = idElement->firstChild(); n; n = NodeTraversal::next(*n, idElement))
- builder.append(accessibleNameForNode(n));
+ for (Node& n : NodeTraversal::descendantsOf(*idElement))
+ builder.append(accessibleNameForNode(&n));
if (i != size - 1)
builder.append(' ');
setValue(String::number(value));
- axObjectCache()->postNotification(node(), AXObjectCache::AXValueChanged, true);
+ axObjectCache()->postNotification(node(), AXObjectCacheImpl::AXValueChanged, true);
}
bool AXNodeObject::computeAccessibilityIsIgnored() const
if (isHTMLInputElement(*node())) {
HTMLInputElement& input = toHTMLInputElement(*node());
const AtomicString& type = input.type();
- if (type == InputTypeNames::checkbox)
+ if (type == InputTypeNames::button) {
+ if ((node()->parentNode() && isHTMLMenuElement(node()->parentNode())) || (parentObject() && parentObject()->roleValue() == MenuRole))
+ return MenuItemRole;
+ return buttonRoleType();
+ }
+ if (type == InputTypeNames::checkbox) {
+ if ((node()->parentNode() && isHTMLMenuElement(node()->parentNode())) || (parentObject() && parentObject()->roleValue() == MenuRole))
+ return MenuItemCheckBoxRole;
return CheckBoxRole;
- if (type == InputTypeNames::radio)
+ }
+ if (type == InputTypeNames::date)
+ return DateRole;
+ if (type == InputTypeNames::datetime
+ || type == InputTypeNames::datetime_local
+ || type == InputTypeNames::month
+ || type == InputTypeNames::week)
+ return DateTimeRole;
+ if (type == InputTypeNames::radio) {
+ if ((node()->parentNode() && isHTMLMenuElement(node()->parentNode())) || (parentObject() && parentObject()->roleValue() == MenuRole))
+ return MenuItemRadioRole;
return RadioButtonRole;
+ }
if (input.isTextButton())
return buttonRoleType();
if (type == InputTypeNames::range)
return SliderRole;
if (type == InputTypeNames::color)
return ColorWellRole;
+ if (type == InputTypeNames::time)
+ return TimeRole;
return TextFieldRole;
}
if (isHTMLSelectElement(*node())) {
return HeadingRole;
if (isHTMLDivElement(*node()))
return DivRole;
+ if (isHTMLMeterElement(*node()))
+ return MeterRole;
+ if (isHTMLOutputElement(*node()))
+ return StatusRole;
if (isHTMLParagraphElement(*node()))
return ParagraphRole;
if (isHTMLLabelElement(*node()))
return LabelRole;
+ if (isHTMLDListElement(*node()))
+ return DescriptionListRole;
+ if (node()->isElementNode() && node()->hasTagName(blockquoteTag))
+ return BlockquoteRole;
if (node()->isElementNode() && node()->hasTagName(figcaptionTag))
return FigcaptionRole;
if (node()->isElementNode() && node()->hasTagName(figureTag))
if (isHTMLInputElement(*node))
return toHTMLInputElement(*node).shouldAppearChecked();
- // Else, if this is an ARIA checkbox or radio, respect the aria-checked attribute
+ // Else, if this is an ARIA checkbox or radio OR ARIA role menuitemcheckbox
+ // or menuitemradio, respect the aria-checked attribute
AccessibilityRole ariaRole = ariaRoleAttribute();
- if (ariaRole == RadioButtonRole || ariaRole == CheckBoxRole) {
+ if (ariaRole == RadioButtonRole || ariaRole == CheckBoxRole
+ || ariaRole == MenuItemCheckBoxRole || ariaRole == MenuItemRadioRole) {
if (equalIgnoringCase(getAttribute(aria_checkedAttr), "true"))
return true;
return false;
return !toElement(node)->isDisabledFormControl();
}
+AccessibilityExpanded AXNodeObject::isExpanded() const
+{
+ const AtomicString& expanded = getAttribute(aria_expandedAttr);
+ if (equalIgnoringCase(expanded, "true"))
+ return ExpandedExpanded;
+ if (equalIgnoringCase(expanded, "false"))
+ return ExpandedCollapsed;
+
+ return ExpandedUndefined;
+}
+
bool AXNodeObject::isIndeterminate() const
{
Node* node = this->node();
return String();
}
+
+const AtomicString& AXNodeObject::textInputType() const
+{
+ Node* node = this->node();
+ if (!isHTMLInputElement(node))
+ return nullAtom;
+
+ HTMLInputElement& input = toHTMLInputElement(*node);
+ if (input.isTextField())
+ return input.type();
+ return nullAtom;
+}
+
String AXNodeObject::ariaDescribedByAttribute() const
{
WillBeHeapVector<RawPtrWillBeMember<Element> > elements;
return accessibilityDescriptionForElements(elements);
}
-
String AXNodeObject::ariaLabeledByAttribute() const
{
WillBeHeapVector<RawPtrWillBeMember<Element> > elements;
// When building the textUnderElement for an object, determine whether or not
// we should include the inner text of this given descendant object or skip it.
-static bool shouldUseAccessiblityObjectInnerText(AXObject* obj)
+static bool shouldUseAccessibilityObjectInnerText(AXObject* obj)
{
// Consider this hypothetical example:
// <div tabindex=0>
StringBuilder builder;
for (AXObject* child = firstChild(); child; child = child->nextSibling()) {
- if (!shouldUseAccessiblityObjectInnerText(child))
+ if (!shouldUseAccessibilityObjectInnerText(child))
continue;
if (child->isAXNodeObject()) {
case ListBoxOptionRole:
case MenuButtonRole:
case MenuItemRole:
+ case MenuItemCheckBoxRole:
+ case MenuItemRadioRole:
case RadioButtonRole:
case TabRole:
return textUnderElement();
return boundingBox;
}
-AXObject* AXNodeObject::parentObject() const
+AXObject* AXNodeObject::computeParent() const
{
if (!node())
return 0;
return 0;
}
-AXObject* AXNodeObject::parentObjectIfExists() const
+AXObject* AXNodeObject::computeParentIfExists() const
{
- return parentObject();
+ if (!node())
+ return 0;
+
+ Node* parentObj = node()->parentNode();
+ if (parentObj)
+ return axObjectCache()->get(parentObj);
+
+ return 0;
}
AXObject* AXNodeObject::firstChild() const
for (Node* child = m_node->firstChild(); child; child = child->nextSibling())
addChild(axObjectCache()->getOrCreate(child));
+
+ for (unsigned i = 0; i < m_children.size(); ++i)
+ m_children[i].get()->setParent(this);
}
void AXNodeObject::addChild(AXObject* child)
case ToggleButtonRole:
case TabRole:
case MenuItemRole:
+ case MenuItemCheckBoxRole:
+ case MenuItemRadioRole:
case ListItemRole:
return toElement(node);
default:
if (!node)
return 0;
- AXObjectCache* cache = axObjectCache();
+ AXObjectCacheImpl* cache = axObjectCache();
// search up the DOM tree for an anchor element
// NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement
if (!node() && !renderer())
return;
- axObjectCache()->postNotification(this, document(), AXObjectCache::AXChildrenChanged, true);
+ axObjectCache()->postNotification(this, document(), AXObjectCacheImpl::AXChildrenChanged, true);
// Go up the accessibility parent chain, but only if the element already exists. This method is
// called during render layouts, minimal work should be done.
// In other words, they need to be sent even when the screen reader has not accessed this live region since the last update.
// If this element supports ARIA live regions, then notify the AT of changes.
- if (parent->supportsARIALiveRegion())
- axObjectCache()->postNotification(parent, parent->document(), AXObjectCache::AXLiveRegionChanged, true);
+ if (parent->isLiveRegion())
+ axObjectCache()->postNotification(parent, parent->document(), AXObjectCacheImpl::AXLiveRegionChanged, true);
// If this element is an ARIA text box or content editable, post a "value changed" notification on it
// so that it behaves just like a native input element or textarea.
if (isNonNativeTextControl())
- axObjectCache()->postNotification(parent, parent->document(), AXObjectCache::AXValueChanged, true);
+ axObjectCache()->postNotification(parent, parent->document(), AXObjectCacheImpl::AXValueChanged, true);
}
}
// focused (to handle form controls, ARIA text boxes and contentEditable),
// or the web area if the selection is just in the document somewhere.
if (isFocused() || isWebArea())
- axObjectCache()->postNotification(this, document(), AXObjectCache::AXSelectedTextChanged, true);
+ axObjectCache()->postNotification(this, document(), AXObjectCacheImpl::AXSelectedTextChanged, true);
else
AXObject::selectionChanged(); // Calls selectionChanged on parent.
}
{
// If this element supports ARIA live regions, or is part of a region with an ARIA editable role,
// then notify the AT of changes.
- AXObjectCache* cache = axObjectCache();
+ AXObjectCacheImpl* cache = axObjectCache();
for (Node* parentNode = node(); parentNode; parentNode = parentNode->parentNode()) {
AXObject* parent = cache->get(parentNode);
if (!parent)
continue;
- if (parent->supportsARIALiveRegion())
- cache->postNotification(parentNode, AXObjectCache::AXLiveRegionChanged, true);
+ if (parent->isLiveRegion())
+ cache->postNotification(parentNode, AXObjectCacheImpl::AXLiveRegionChanged, true);
// If this element is an ARIA text box or content editable, post a "value changed" notification on it
// so that it behaves just like a native input element or textarea.
if (parent->isNonNativeTextControl())
- cache->postNotification(parentNode, AXObjectCache::AXValueChanged, true);
+ cache->postNotification(parentNode, AXObjectCacheImpl::AXValueChanged, true);
}
}
value += range * (percentChange / 100);
setValue(String::number(value));
- axObjectCache()->postNotification(node(), AXObjectCache::AXValueChanged, true);
+ axObjectCache()->postNotification(node(), AXObjectCacheImpl::AXValueChanged, true);
}
} // namespace blink