#include "core/InputTypeNames.h"
#include "core/accessibility/AXImageMapLink.h"
#include "core/accessibility/AXInlineTextBox.h"
-#include "core/accessibility/AXObjectCache.h"
+#include "core/accessibility/AXObjectCacheImpl.h"
#include "core/accessibility/AXSVGRoot.h"
#include "core/accessibility/AXSpinButton.h"
#include "core/accessibility/AXTable.h"
#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderListMarker.h"
#include "core/rendering/RenderMenuList.h"
+#include "core/rendering/RenderPart.h"
#include "core/rendering/RenderTextControlSingleLine.h"
#include "core/rendering/RenderTextFragment.h"
#include "core/rendering/RenderView.h"
-#include "core/rendering/RenderWidget.h"
#include "core/svg/SVGDocumentExtensions.h"
#include "core/svg/SVGSVGElement.h"
#include "core/svg/graphics/SVGImage.h"
ScrollableArea* AXRenderObject::getScrollableAreaIfScrollable() const
{
- // If the parent is a scroll view, then this object isn't really scrollable, the parent ScrollView should handle the scrolling.
+ // If the parent is a FrameView, then this object isn't really scrollable; the parent should handle the scrolling.
if (parentObject() && parentObject()->isAXScrollView())
return 0;
return ImageMapRole;
return LinkRole;
}
- if (cssBox && cssBox->isListItem())
+ if ((cssBox && cssBox->isListItem()) || isHTMLLIElement(node))
return ListItemRole;
if (m_renderer->isListMarker())
return ListMarkerRole;
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::color)
return ColorWellRole;
+ if (type == InputTypeNames::time)
+ return TimeRole;
}
if (isFileUploadButton())
if (node && node->hasTagName(ddTag))
return DescriptionListDetailRole;
+ if (node && node->hasTagName(dlTag))
+ return DescriptionListRole;
+
if (node && node->hasTagName(dtTag))
return DescriptionListTermRole;
if (m_renderer->isHR())
return HorizontalRuleRole;
+ if (isHTMLOutputElement(node))
+ return StatusRole;
+
if (isHTMLParagraphElement(node))
return ParagraphRole;
if (isHTMLDivElement(node))
return DivRole;
+ if (isHTMLMeterElement(node))
+ return MeterRole;
+
if (isHTMLFormElement(node))
return FormRole;
if (node && node->hasTagName(articleTag))
return ArticleRole;
+ if (node && node->hasTagName(blockquoteTag))
+ return BlockquoteRole;
+
if (node && node->hasTagName(mainTag))
return MainRole;
if (node && node->hasTagName(asideTag))
return ComplementaryRole;
+ if (node && node->hasTagName(preTag))
+ return PreRole;
+
if (node && node->hasTagName(sectionTag))
return RegionRole;
if (!renderer)
return false;
// Widgets are the replaced elements that we represent to AX as attachments
- bool isWidget = renderer->isWidget();
- ASSERT(!isWidget || (renderer->isReplaced() && !isImage()));
- return isWidget;
+ bool isRenderPart = renderer->isRenderPart();
+ ASSERT(!isRenderPart || (renderer->isReplaced() && !isImage()));
+ return isRenderPart;
}
bool AXRenderObject::isFileUploadButton() const
if (roleValue() == ListItemRole)
return false;
+ if (roleValue() == BlockquoteRole)
+ return false;
+
if (roleValue() == DialogRole)
return false;
if (roleValue() == DetailsRole)
return false;
+ if (roleValue() == MeterRole)
+ return false;
+
// if this element has aria attributes on it, it should not be ignored.
if (supportsARIAAttributes())
return false;
String AXRenderObject::text() const
{
- if (isPasswordField())
+ if (isPasswordFieldAndShouldHideValue())
return String();
return AXNodeObject::text();
if (!isTextControl())
return -1;
- if (isPasswordField())
+ if (isPasswordFieldAndShouldHideValue())
return -1; // need to return something distinct from 0
return text().length();
}
//
+// Load inline text boxes.
+//
+
+void AXRenderObject::loadInlineTextBoxes()
+{
+ if (!renderer() || !renderer()->isText())
+ return;
+
+ clearChildren();
+ addInlineTextBoxChildren(true);
+}
+
+//
// Properties of interactive elements.
//
if (!m_renderer)
return String();
- if (isPasswordField())
+ if (isPasswordFieldAndShouldHideValue())
return String();
RenderBoxModelObject* cssBox = renderBoxModelObject();
if (m_renderer->isFileUploadControl())
return toRenderFileUploadControl(m_renderer)->fileTextValue();
+ // Handle other HTML input elements that aren't text controls, like date and time
+ // controls, by returning the string value, with the exception of checkboxes
+ // and radio buttons (which would return "on").
+ if (node() && isHTMLInputElement(node())) {
+ HTMLInputElement* input = toHTMLInputElement(node());
+ if (input->type() != InputTypeNames::checkbox && input->type() != InputTypeNames::radio)
+ return input->value();
+ }
+
+ // Handle other HTML input elements that aren't text controls, like date and time
+ // controls, by returning the string value, with the exception of checkboxes
+ // and radio buttons (which would return "on").
+ if (node() && isHTMLInputElement(node())) {
+ HTMLInputElement* input = toHTMLInputElement(node());
+ if (input->type() != InputTypeNames::checkbox && input->type() != InputTypeNames::radio)
+ return input->value();
+ }
+
// FIXME: We might need to implement a value here for more types
// FIXME: It would be better not to advertise a value at all for the types for which we don't implement one;
// this would require subclassing or making accessibilityAttributeNames do something other than return a
WillBeHeapVector<RawPtrWillBeMember<Element> > elements;
elementsFromAttribute(elements, attr);
- AXObjectCache* cache = axObjectCache();
+ AXObjectCacheImpl* cache = axObjectCache();
unsigned count = elements.size();
for (unsigned k = 0; k < count; ++k) {
Element* element = elements[k];
// ARIA live-region features.
//
-const AtomicString& AXRenderObject::ariaLiveRegionStatus() const
+const AtomicString& AXRenderObject::liveRegionStatus() const
{
DEFINE_STATIC_LOCAL(const AtomicString, liveRegionStatusAssertive, ("assertive", AtomicString::ConstructFromLiteral));
DEFINE_STATIC_LOCAL(const AtomicString, liveRegionStatusPolite, ("polite", AtomicString::ConstructFromLiteral));
return liveRegionStatus;
}
-const AtomicString& AXRenderObject::ariaLiveRegionRelevant() const
+const AtomicString& AXRenderObject::liveRegionRelevant() const
{
DEFINE_STATIC_LOCAL(const AtomicString, defaultLiveRegionRelevant, ("additions text", AtomicString::ConstructFromLiteral));
const AtomicString& relevant = getAttribute(aria_relevantAttr);
return relevant;
}
-bool AXRenderObject::ariaLiveRegionAtomic() const
+bool AXRenderObject::liveRegionAtomic() const
{
return elementAttributeValue(aria_atomicAttr);
}
-bool AXRenderObject::ariaLiveRegionBusy() const
+bool AXRenderObject::liveRegionBusy() const
{
return elementAttributeValue(aria_busyAttr);
}
return 0;
Node* node = hitTestResult.innerNode();
- if (node->isInShadowTree())
+
+ // Allow the hit test to return media control buttons.
+ if (node->isInShadowTree() && (!isHTMLInputElement(*node) || !node->isMediaControlElement()))
node = node->shadowHost();
if (isHTMLAreaElement(node))
if (!obj)
return 0;
- AXObject* result = obj->document().axObjectCache()->getOrCreate(obj);
+ AXObject* result = toAXObjectCacheImpl(obj->document().axObjectCache())->getOrCreate(obj);
result->updateChildrenIfNecessary();
// Allow the element to perform any hit-testing it might need to do to reach non-render children.
// High-level accessibility tree access.
//
-AXObject* AXRenderObject::parentObject() const
+AXObject* AXRenderObject::computeParent() const
{
if (!m_renderer)
return 0;
return 0;
}
-AXObject* AXRenderObject::parentObjectIfExists() const
+AXObject* AXRenderObject::computeParentIfExists() const
{
+ if (!m_renderer)
+ return 0;
+
+ if (ariaRoleAttribute() == MenuBarRole)
+ return axObjectCache()->get(m_renderer->parent());
+
+ // menuButton and its corresponding menu are DOM siblings, but Accessibility needs them to be parent/child
+ if (ariaRoleAttribute() == MenuRole) {
+ AXObject* parent = menuButtonForMenu();
+ if (parent)
+ return parent;
+ }
+
+ RenderObject* parentObj = renderParentObject();
+ if (parentObj)
+ return axObjectCache()->get(parentObj);
+
// WebArea's parent should be the scroll view containing it.
if (isWebArea())
return axObjectCache()->get(m_renderer->frame()->view());
- return axObjectCache()->get(renderParentObject());
+ return 0;
}
//
addTextFieldChildren();
addCanvasChildren();
addRemoteSVGChildren();
- addInlineTextBoxChildren();
+ addInlineTextBoxChildren(false);
+
+ for (unsigned i = 0; i < m_children.size(); ++i) {
+ if (!m_children[i].get()->cachedParentObject())
+ m_children[i].get()->setParent(this);
+ }
}
bool AXRenderObject::canHaveChildren() const
if (!m_renderer)
return 0;
- AXObjectCache* cache = axObjectCache();
+ AXObjectCacheImpl* cache = axObjectCache();
RenderObject* currRenderer;
// Search up the render tree for a RenderObject with a DOM node. Defer to an earlier continuation, though.
{
if (!isAttachment())
return 0;
- return toRenderWidget(m_renderer)->widget();
+ return toRenderPart(m_renderer)->widget();
}
//
if (!isTextControl())
return PlainTextRange();
- if (isPasswordField())
+ if (isPasswordFieldAndShouldHideValue())
return PlainTextRange();
AccessibilityRole ariaRole = ariaRoleAttribute();
AXRenderObject* activedescendant = toAXRenderObject(activeDescendant());
if (activedescendant && shouldNotifyActiveDescendant())
- doc.axObjectCache()->postNotification(m_renderer, AXObjectCache::AXActiveDescendantChanged, true);
+ toAXObjectCacheImpl(doc.axObjectCache())->postNotification(m_renderer, AXObjectCacheImpl::AXActiveDescendantChanged, true);
}
void AXRenderObject::handleAriaExpandedChanged()
// Post that the row count changed.
if (containerParent)
- axObjectCache()->postNotification(containerParent, document(), AXObjectCache::AXRowCountChanged, true);
+ axObjectCache()->postNotification(containerParent, document(), AXObjectCacheImpl::AXRowCountChanged, true);
// Post that the specific row either collapsed or expanded.
- if (roleValue() == RowRole || roleValue() == TreeItemRole)
- axObjectCache()->postNotification(this, document(), isExpanded() ? AXObjectCache::AXRowExpanded : AXObjectCache::AXRowCollapsed, true);
+ AccessibilityExpanded expanded = isExpanded();
+ if (!expanded)
+ return;
+
+ if (roleValue() == RowRole || roleValue() == TreeItemRole) {
+ AXObjectCacheImpl::AXNotification notification = AXObjectCacheImpl::AXRowExpanded;
+ if (expanded == ExpandedCollapsed)
+ notification = AXObjectCacheImpl::AXRowCollapsed;
+
+ axObjectCache()->postNotification(this, document(), notification, true);
+ }
}
void AXRenderObject::textChanged()
return TextIterator::rangeLength(range.get());
}
-void AXRenderObject::addInlineTextBoxChildren()
+void AXRenderObject::addInlineTextBoxChildren(bool force)
{
Settings* settings = document()->settings();
- if (!settings || !settings->inlineTextBoxAccessibilityEnabled())
+ if (!force && (!settings || !settings->inlineTextBoxAccessibilityEnabled()))
return;
if (!renderer() || !renderer()->isText())
if (renderer()->needsLayout()) {
// If a RenderText needs layout, its inline text boxes are either
// nonexistent or invalid, so defer until the layout happens and
- // the renderer calls AXObjectCache::inlineTextBoxesUpdated.
+ // the renderer calls AXObjectCacheImpl::inlineTextBoxesUpdated.
return;
}
if (!rendererRoot)
return 0;
- AXObject* rootSVGObject = doc->axObjectCache()->getOrCreate(rendererRoot);
+ AXObject* rootSVGObject = toAXObjectCacheImpl(doc->axObjectCache())->getOrCreate(rendererRoot);
// In order to connect the AX hierarchy from the SVG root element from the loaded resource
// the parent must be set, because there's no other way to get back to who created the image.
if (!map)
return;
- for (HTMLAreaElement* area = Traversal<HTMLAreaElement>::firstWithin(*map); area; area = Traversal<HTMLAreaElement>::next(*area, map)) {
+ for (HTMLAreaElement& area : Traversal<HTMLAreaElement>::descendantsOf(*map)) {
// add an <area> element for this child if it has a link
- if (area->isLink()) {
+ if (area.isLink()) {
AXImageMapLink* areaObject = toAXImageMapLink(axObjectCache()->getOrCreate(ImageMapLinkRole));
- areaObject->setHTMLAreaElement(area);
+ areaObject->setHTMLAreaElement(&area);
areaObject->setHTMLMapElement(map);
areaObject->setParent(this);
if (!areaObject->accessibilityIsIgnored())