#include "config.h"
#include "core/accessibility/AXRenderObject.h"
-#include "bindings/v8/ExceptionStatePlaceholder.h"
+#include "bindings/core/v8/ExceptionStatePlaceholder.h"
+#include "core/InputTypeNames.h"
#include "core/accessibility/AXImageMapLink.h"
#include "core/accessibility/AXInlineTextBox.h"
#include "core/accessibility/AXObjectCache.h"
#include "core/editing/VisibleUnits.h"
#include "core/editing/htmlediting.h"
#include "core/frame/LocalFrame.h"
+#include "core/frame/Settings.h"
#include "core/html/HTMLImageElement.h"
#include "core/html/HTMLLabelElement.h"
#include "core/html/HTMLOptionElement.h"
using blink::WebLocalizedString;
-namespace WebCore {
+namespace blink {
using namespace HTMLNames;
-static inline RenderObject* firstChildInContinuation(RenderObject* renderer)
+static inline RenderObject* firstChildInContinuation(const RenderInline& renderer)
{
- RenderObject* r = toRenderInline(renderer)->continuation();
+ RenderBoxModelObject* r = renderer.continuation();
while (r) {
if (r->isRenderBlock())
return r;
- if (RenderObject* child = r->firstChild())
+ if (RenderObject* child = r->slowFirstChild())
return child;
r = toRenderInline(r)->continuation();
}
static inline RenderObject* firstChildConsideringContinuation(RenderObject* renderer)
{
- RenderObject* firstChild = renderer->firstChild();
+ RenderObject* firstChild = renderer->slowFirstChild();
if (!firstChild && isInlineWithContinuation(renderer))
- firstChild = firstChildInContinuation(renderer);
+ firstChild = firstChildInContinuation(toRenderInline(*renderer));
return firstChild;
}
static inline bool lastChildHasContinuation(RenderObject* renderer)
{
- return renderer->lastChild() && isInlineWithContinuation(renderer->lastChild());
+ RenderObject* lastChild = renderer->slowLastChild();
+ return lastChild && isInlineWithContinuation(lastChild);
}
static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
, m_renderer(renderer)
, m_cachedElementRectDirty(true)
{
-#ifndef NDEBUG
+#if ENABLE(ASSERT)
m_renderer->setHasAXObject(true);
#endif
}
return ListMarkerRole;
if (isHTMLButtonElement(node))
return buttonRoleType();
+ if (isHTMLDetailsElement(node))
+ return DetailsRole;
+ if (isHTMLSummaryElement(node)) {
+ if (node->parentElement() && isHTMLDetailsElement(node->parentElement()))
+ return DisclosureTriangleRole;
+ return UnknownRole;
+ }
if (isHTMLLegendElement(node))
return LegendRole;
if (m_renderer->isText())
if (isHTMLInputElement(node)) {
HTMLInputElement& input = toHTMLInputElement(*node);
- if (input.isCheckbox())
+ const AtomicString& type = input.type();
+ if (type == InputTypeNames::checkbox)
return CheckBoxRole;
- if (input.isRadioButton())
+ if (type == InputTypeNames::radio)
return RadioButtonRole;
if (input.isTextButton())
return buttonRoleType();
-
- const AtomicString& type = input.getAttribute(typeAttr);
- if (equalIgnoringCase(type, "color"))
+ if (type == InputTypeNames::color)
return ColorWellRole;
}
if (isEmbeddedObject())
return EmbeddedObjectRole;
+ if (node && node->hasTagName(figcaptionTag))
+ return FigcaptionRole;
+
+ if (node && node->hasTagName(figureTag))
+ return FigureRole;
+
// There should only be one banner/contentInfo per page. If header/footer are being used within an article or section
// then it should not be exposed as whole page's banner/contentInfo
if (node && node->hasTagName(headerTag) && !isDescendantOfElementType(articleTag) && !isDescendantOfElementType(sectionTag))
detachRemoteSVGRoot();
-#ifndef NDEBUG
+#if ENABLE(ASSERT)
if (m_renderer)
m_renderer->setHasAXObject(false);
#endif
bool AXRenderObject::isFileUploadButton() const
{
- if (m_renderer && isHTMLInputElement(m_renderer->node())) {
- HTMLInputElement& input = toHTMLInputElement(*m_renderer->node());
- return input.isFileUpload();
- }
-
- return false;
+ return m_renderer && isHTMLInputElement(m_renderer->node()) && toHTMLInputElement(*m_renderer->node()).type() == InputTypeNames::file;
}
static bool isLinkable(const AXObject& object)
if (isWebArea()) {
Document& document = m_renderer->document();
HTMLElement* body = document.body();
- if (body && body->rendererIsEditable())
+ if (body && body->hasEditableStyle())
return false;
- return !document.rendererIsEditable();
+ return !document.hasEditableStyle();
}
return AXNodeObject::isReadOnly();
bool AXRenderObject::computeAccessibilityIsIgnored() const
{
-#ifndef NDEBUG
+#if ENABLE(ASSERT)
ASSERT(m_initialized);
#endif
if (roleValue() == IgnoredRole)
return true;
- if (roleValue() == PresentationalRole || inheritsPresentationalRole())
+ if ((roleValue() == NoneRole || roleValue() == PresentationalRole) || inheritsPresentationalRole())
return true;
// An ARIA tree can only have tree items and static text as children.
return false;
// Anything that is content editable should not be ignored.
- // However, one cannot just call node->rendererIsEditable() since that will ask if its parents
+ // However, one cannot just call node->hasEditableStyle() since that will ask if its parents
// are also editable. Only the top level content editable region should be exposed.
if (hasContentEditableAttributeSet())
return false;
if (roleValue() == DialogRole)
return false;
+ if (roleValue() == FigcaptionRole)
+ return false;
+
+ if (roleValue() == FigureRole)
+ return false;
+
+ if (roleValue() == DetailsRole)
+ return false;
+
// if this element has aria attributes on it, it should not be ignored.
if (supportsARIAAttributes())
return false;
return true;
if (m_renderer->isRenderBlockFlow() && m_renderer->childrenInline() && !canSetFocusAttribute())
- return !toRenderBlock(m_renderer)->firstLineBox() && !mouseButtonListener();
+ return !toRenderBlockFlow(m_renderer)->firstLineBox() && !mouseButtonListener();
// ignore images seemingly used as spacers
if (isImage()) {
// Don't ignore generic focusable elements like <div tabindex=0>
// unless they're completely empty, with no children.
- if (isGenericFocusableElement() && node->firstChild())
+ if (isGenericFocusableElement() && node->hasChildren())
return false;
if (!ariaAccessibilityDescription().isEmpty())
void AXRenderObject::accessibilityChildrenFromAttribute(QualifiedName attr, AccessibilityChildrenVector& children) const
{
- Vector<Element*> elements;
+ WillBeHeapVector<RawPtrWillBeMember<Element> > elements;
elementsFromAttribute(elements, attr);
AXObjectCache* cache = axObjectCache();
layer->hitTest(request, hitTestResult);
if (!hitTestResult.innerNode())
return 0;
- Node* node = hitTestResult.innerNode()->deprecatedShadowAncestorNode();
+
+ Node* node = hitTestResult.innerNode();
+ if (node->isInShadowTree())
+ node = node->shadowHost();
if (isHTMLAreaElement(node))
return accessibilityImageMapHitTest(toHTMLAreaElement(node), point);
RenderObject* nextSibling = 0;
- RenderInline* inlineContinuation;
- if (m_renderer->isRenderBlock() && (inlineContinuation = toRenderBlock(m_renderer)->inlineElementContinuation())) {
+ RenderInline* inlineContinuation = m_renderer->isRenderBlock() ? toRenderBlock(m_renderer)->inlineElementContinuation() : 0;
+ if (inlineContinuation) {
// Case 1: node is a block and has an inline continuation. Next sibling is the inline continuation's first child.
nextSibling = firstChildConsideringContinuation(inlineContinuation);
} else if (m_renderer->isAnonymousBlock() && lastChildHasContinuation(m_renderer)) {
// Case 2: Anonymous block parent of the start of a continuation - skip all the way to
// after the parent of the end, since everything in between will be linked up via the continuation.
- RenderObject* lastParent = endOfContinuations(m_renderer->lastChild())->parent();
+ RenderObject* lastParent = endOfContinuations(toRenderBlock(m_renderer)->lastChild())->parent();
while (lastChildHasContinuation(lastParent))
- lastParent = endOfContinuations(lastParent->lastChild())->parent();
+ lastParent = endOfContinuations(lastParent->slowLastChild())->parent();
nextSibling = lastParent->nextSibling();
} else if (RenderObject* ns = m_renderer->nextSibling()) {
// Case 3: node has an actual next sibling
addHiddenChildren();
addAttachmentChildren();
+ addPopupChildren();
addImageMapChildren();
addTextFieldChildren();
addCanvasChildren();
if (!m_renderer)
return;
- if (AXObjectCache::inlineTextBoxAccessibility() && roleValue() == StaticTextRole)
+ Settings* settings = document()->settings();
+ if (settings && settings->inlineTextBoxAccessibilityEnabled() && roleValue() == StaticTextRole)
childrenChanged();
// Do this last - AXNodeObject::textChanged posts live region announcements,
if (index <= 0)
return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
- RefPtrWillBeRawPtr<Range> range = Range::create(m_renderer->document());
- range->selectNodeContents(node, IGNORE_EXCEPTION);
- CharacterIterator it(range.get());
+ Position start, end;
+ bool selected = Range::selectNodeContents(node, start, end);
+ if (!selected)
+ return VisiblePosition();
+
+ CharacterIterator it(start, end);
it.advance(index - 1);
- return VisiblePosition(Position(it.range()->endContainer(), it.range()->endOffset(), Position::PositionIsOffsetInAnch\
-or), UPSTREAM);
+ return VisiblePosition(Position(it.endContainer(), it.endOffset(), Position::PositionIsOffsetInAnchor), UPSTREAM);
}
int AXRenderObject::indexForVisiblePosition(const VisiblePosition& pos) const
void AXRenderObject::addInlineTextBoxChildren()
{
- if (!axObjectCache()->inlineTextBoxAccessibility())
+ Settings* settings = document()->settings();
+ if (!settings || !settings->inlineTextBoxAccessibilityEnabled())
return;
if (!renderer() || !renderer()->isText())
if (!focusedElement)
return false;
- Vector<Element*> elements;
+ WillBeHeapVector<RawPtrWillBeMember<Element> > elements;
elementsFromAttribute(elements, aria_controlsAttr);
unsigned count = elements.size();
if (!m_renderer)
return 0;
- RenderObject* parent = m_renderer->parent();
-
- RenderObject* startOfConts = 0;
- RenderObject* firstChild = 0;
- if (m_renderer->isRenderBlock() && (startOfConts = startOfContinuations(m_renderer))) {
+ RenderObject* startOfConts = m_renderer->isRenderBlock() ? startOfContinuations(m_renderer) : 0;
+ if (startOfConts) {
// Case 1: node is a block and is an inline's continuation. Parent
// is the start of the continuation chain.
- parent = startOfConts;
- } else if (parent && parent->isRenderInline() && (startOfConts = startOfContinuations(parent))) {
+ return startOfConts;
+ }
+
+ RenderObject* parent = m_renderer->parent();
+ startOfConts = parent && parent->isRenderInline() ? startOfContinuations(parent) : 0;
+ if (startOfConts) {
// Case 2: node's parent is an inline which is some node's continuation; parent is
// the earliest node in the continuation chain.
- parent = startOfConts;
- } else if (parent && (firstChild = parent->firstChild()) && firstChild->node()) {
+ return startOfConts;
+ }
+
+ RenderObject* firstChild = parent ? parent->slowFirstChild() : 0;
+ if (firstChild && firstChild->node()) {
// Case 3: The first sibling is the beginning of a continuation chain. Find the origin of that continuation.
// Get the node's renderer and follow that continuation chain until the first child is found.
- RenderObject* nodeRenderFirstChild = firstChild->node()->renderer();
- while (nodeRenderFirstChild != firstChild) {
+ for (RenderObject* nodeRenderFirstChild = firstChild->node()->renderer(); nodeRenderFirstChild != firstChild; nodeRenderFirstChild = firstChild->node()->renderer()) {
for (RenderObject* contsTest = nodeRenderFirstChild; contsTest; contsTest = nextContinuation(contsTest)) {
if (contsTest == firstChild) {
parent = nodeRenderFirstChild->parent();
break;
}
}
- if (firstChild == parent->firstChild())
+ RenderObject* newFirstChild = parent->slowFirstChild();
+ if (firstChild == newFirstChild)
break;
- firstChild = parent->firstChild();
+ firstChild = newFirstChild;
if (!firstChild->node())
break;
- nodeRenderFirstChild = firstChild->node()->renderer();
}
}
return parent;
}
-bool AXRenderObject::isDescendantOfElementType(const QualifiedName& tagName) const
+bool AXRenderObject::isDescendantOfElementType(const HTMLQualifiedName& tagName) const
{
for (RenderObject* parent = m_renderer->parent(); parent; parent = parent->parent()) {
if (parent->node() && parent->node()->hasTagName(tagName))
if (!doc || !doc->isSVGDocument())
return 0;
+ Settings* settings = doc->settings();
+ if (settings && !settings->accessibilityEnabled())
+ settings->setAccessibilityEnabled(true);
+
SVGSVGElement* rootElement = doc->accessSVGExtensions().rootElement();
if (!rootElement)
return 0;
m_children.append(axWidget);
}
+void AXRenderObject::addPopupChildren()
+{
+ if (!isHTMLInputElement(node()))
+ return;
+ if (AXObject* axPopup = toHTMLInputElement(node())->popupRootAXObject())
+ m_children.append(axPopup);
+}
+
void AXRenderObject::addRemoteSVGChildren()
{
AXSVGRoot* root = remoteSVGRootElement();
QualifiedName tagName = toElement(elementNode)->tagQName();
if (tagName == ulTag || tagName == olTag || tagName == dlTag)
- return parent->roleValue() == PresentationalRole;
+ return (parent->roleValue() == NoneRole || parent->roleValue() == PresentationalRole);
return false;
}
if (obj->node()) // If we are a continuation, we want to make sure to use the primary renderer.
obj = obj->node()->renderer();
- // absoluteFocusRingQuads will query the hierarchy below this element, which for large webpages can be very slow.
+ // absoluteFocusRingBoundingBox will query the hierarchy below this element, which for large webpages can be very slow.
// For a web area, which will have the most elements of any element, absoluteQuads should be used.
// We should also use absoluteQuads for SVG elements, otherwise transforms won't be applied.
- Vector<FloatQuad> quads;
- if (obj->isText())
+ LayoutRect result;
+ if (obj->isText()) {
+ Vector<FloatQuad> quads;
toRenderText(obj)->absoluteQuads(quads, 0, RenderText::ClipToEllipsis);
- else if (isWebArea() || obj->isSVGRoot())
- obj->absoluteQuads(quads);
- else
- obj->absoluteFocusRingQuads(quads);
-
- LayoutRect result = boundingBoxForQuads(obj, quads);
+ result = boundingBoxForQuads(obj, quads);
+ } else if (isWebArea() || obj->isSVGRoot()) {
+ result = obj->absoluteBoundingBoxRect();
+ } else {
+ result = obj->absoluteFocusRingBoundingBoxRect();
+ }
Document* document = this->document();
if (document && document->isSVGDocument())
offsetBoundingBoxForRemoteSVGElement(result);
+ if (document && document->frame() && document->frame()->pagePopupOwner()) {
+ IntPoint popupOrigin = document->view()->contentsToScreen(IntRect()).location();
+ IntPoint mainOrigin = axObjectCache()->rootObject()->documentFrameView()->contentsToScreen(IntRect()).location();
+ result.moveBy(IntPoint(popupOrigin - mainOrigin));
+ }
// The size of the web area should be the content size, not the clipped size.
if (isWebArea() && obj->frame()->view())
return result;
}
-} // namespace WebCore
+} // namespace blink