Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / accessibility / AXRenderObject.cpp
index 99c6da4..2fe5e5a 100644 (file)
@@ -29,7 +29,8 @@
 #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"
@@ -44,6 +45,7 @@
 #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();
     }
@@ -106,10 +108,10 @@ static inline bool isInlineWithContinuation(RenderObject* object)
 
 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;
 }
@@ -150,7 +152,8 @@ static inline RenderObject* endOfContinuations(RenderObject* renderer)
 
 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)
@@ -168,7 +171,7 @@ AXRenderObject::AXRenderObject(RenderObject* renderer)
     , m_renderer(renderer)
     , m_cachedElementRectDirty(true)
 {
-#ifndef NDEBUG
+#if ENABLE(ASSERT)
     m_renderer->setHasAXObject(true);
 #endif
 }
@@ -275,6 +278,13 @@ AccessibilityRole AXRenderObject::determineAccessibilityRole()
         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())
@@ -302,15 +312,14 @@ AccessibilityRole AXRenderObject::determineAccessibilityRole()
 
     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;
     }
 
@@ -387,6 +396,12 @@ AccessibilityRole AXRenderObject::determineAccessibilityRole()
     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))
@@ -418,7 +433,7 @@ void AXRenderObject::detach()
 
     detachRemoteSVGRoot();
 
-#ifndef NDEBUG
+#if ENABLE(ASSERT)
     if (m_renderer)
         m_renderer->setHasAXObject(false);
 #endif
@@ -442,12 +457,7 @@ bool AXRenderObject::isAttachment() const
 
 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)
@@ -494,10 +504,10 @@ bool AXRenderObject::isReadOnly() const
     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();
@@ -575,7 +585,7 @@ AXObjectInclusion AXRenderObject::defaultObjectInclusion() const
 
 bool AXRenderObject::computeAccessibilityIsIgnored() const
 {
-#ifndef NDEBUG
+#if ENABLE(ASSERT)
     ASSERT(m_initialized);
 #endif
 
@@ -595,7 +605,7 @@ bool AXRenderObject::computeAccessibilityIsIgnored() const
     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.
@@ -662,7 +672,7 @@ bool AXRenderObject::computeAccessibilityIsIgnored() const
         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;
@@ -674,6 +684,15 @@ bool AXRenderObject::computeAccessibilityIsIgnored() const
     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;
@@ -688,7 +707,7 @@ bool AXRenderObject::computeAccessibilityIsIgnored() const
         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()) {
@@ -748,7 +767,7 @@ bool AXRenderObject::computeAccessibilityIsIgnored() const
 
     // 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())
@@ -944,7 +963,7 @@ AXObject* AXRenderObject::activeDescendant() const
 
 void AXRenderObject::accessibilityChildrenFromAttribute(QualifiedName attr, AccessibilityChildrenVector& children) const
 {
-    Vector<Element*> elements;
+    WillBeHeapVector<RawPtrWillBeMember<Element> > elements;
     elementsFromAttribute(elements, attr);
 
     AXObjectCache* cache = axObjectCache();
@@ -1271,7 +1290,10 @@ AXObject* AXRenderObject::accessibilityHitTest(const IntPoint& point) const
     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);
@@ -1374,16 +1396,16 @@ AXObject* AXRenderObject::nextSibling() const
 
     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
@@ -1427,6 +1449,7 @@ void AXRenderObject::addChildren()
 
     addHiddenChildren();
     addAttachmentChildren();
+    addPopupChildren();
     addImageMapChildren();
     addTextFieldChildren();
     addCanvasChildren();
@@ -1682,7 +1705,8 @@ void AXRenderObject::textChanged()
     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,
@@ -1724,12 +1748,14 @@ VisiblePosition AXRenderObject::visiblePositionForIndex(int index) const
     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
@@ -1759,7 +1785,8 @@ 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())
@@ -1883,7 +1910,7 @@ bool AXRenderObject::isTabItemSelected() const
     if (!focusedElement)
         return false;
 
-    Vector<Element*> elements;
+    WillBeHeapVector<RawPtrWillBeMember<Element> > elements;
     elementsFromAttribute(elements, aria_controlsAttr);
 
     unsigned count = elements.size();
@@ -1949,42 +1976,45 @@ RenderObject* AXRenderObject::renderParentObject() const
     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))
@@ -2024,6 +2054,10 @@ AXSVGRoot* AXRenderObject::remoteSVGRootElement() const
     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;
@@ -2186,6 +2220,14 @@ void AXRenderObject::addAttachmentChildren()
         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();
@@ -2264,7 +2306,7 @@ bool AXRenderObject::inheritsPresentationalRole() const
 
     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;
 }
@@ -2279,23 +2321,29 @@ LayoutRect AXRenderObject::computeElementRect() const
     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())
@@ -2313,4 +2361,4 @@ LayoutRect AXRenderObject::computeElementRect() const
     return result;
 }
 
-} // namespace WebCore
+} // namespace blink