Home | History | Annotate | Download | only in accessibility
      1 /*
      2 * Copyright (C) 2008 Apple Inc. All rights reserved.
      3 *
      4 * Redistribution and use in source and binary forms, with or without
      5 * modification, are permitted provided that the following conditions
      6 * are met:
      7 *
      8 * 1.  Redistributions of source code must retain the above copyright
      9 *     notice, this list of conditions and the following disclaimer.
     10 * 2.  Redistributions in binary form must reproduce the above copyright
     11 *     notice, this list of conditions and the following disclaimer in the
     12 *     documentation and/or other materials provided with the distribution.
     13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     14 *     its contributors may be used to endorse or promote products derived
     15 *     from this software without specific prior written permission.
     16 *
     17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 */
     28 
     29 #include "config.h"
     30 #include "core/accessibility/AXRenderObject.h"
     31 
     32 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
     33 #include "core/InputTypeNames.h"
     34 #include "core/accessibility/AXImageMapLink.h"
     35 #include "core/accessibility/AXInlineTextBox.h"
     36 #include "core/accessibility/AXObjectCache.h"
     37 #include "core/accessibility/AXSVGRoot.h"
     38 #include "core/accessibility/AXSpinButton.h"
     39 #include "core/accessibility/AXTable.h"
     40 #include "core/dom/ElementTraversal.h"
     41 #include "core/dom/shadow/ShadowRoot.h"
     42 #include "core/editing/FrameSelection.h"
     43 #include "core/editing/RenderedPosition.h"
     44 #include "core/editing/TextIterator.h"
     45 #include "core/editing/VisibleUnits.h"
     46 #include "core/editing/htmlediting.h"
     47 #include "core/frame/LocalFrame.h"
     48 #include "core/frame/Settings.h"
     49 #include "core/html/HTMLImageElement.h"
     50 #include "core/html/HTMLLabelElement.h"
     51 #include "core/html/HTMLOptionElement.h"
     52 #include "core/html/HTMLSelectElement.h"
     53 #include "core/html/HTMLTextAreaElement.h"
     54 #include "core/html/shadow/ShadowElementNames.h"
     55 #include "core/loader/ProgressTracker.h"
     56 #include "core/page/Page.h"
     57 #include "core/rendering/HitTestResult.h"
     58 #include "core/rendering/RenderFieldset.h"
     59 #include "core/rendering/RenderFileUploadControl.h"
     60 #include "core/rendering/RenderHTMLCanvas.h"
     61 #include "core/rendering/RenderImage.h"
     62 #include "core/rendering/RenderInline.h"
     63 #include "core/rendering/RenderLayer.h"
     64 #include "core/rendering/RenderListMarker.h"
     65 #include "core/rendering/RenderMenuList.h"
     66 #include "core/rendering/RenderTextControlSingleLine.h"
     67 #include "core/rendering/RenderTextFragment.h"
     68 #include "core/rendering/RenderView.h"
     69 #include "core/rendering/RenderWidget.h"
     70 #include "core/svg/SVGDocumentExtensions.h"
     71 #include "core/svg/SVGSVGElement.h"
     72 #include "core/svg/graphics/SVGImage.h"
     73 #include "platform/text/PlatformLocale.h"
     74 #include "wtf/StdLibExtras.h"
     75 
     76 using blink::WebLocalizedString;
     77 
     78 namespace blink {
     79 
     80 using namespace HTMLNames;
     81 
     82 static inline RenderObject* firstChildInContinuation(const RenderInline& renderer)
     83 {
     84     RenderBoxModelObject* r = renderer.continuation();
     85 
     86     while (r) {
     87         if (r->isRenderBlock())
     88             return r;
     89         if (RenderObject* child = r->slowFirstChild())
     90             return child;
     91         r = toRenderInline(r)->continuation();
     92     }
     93 
     94     return 0;
     95 }
     96 
     97 static inline bool isInlineWithContinuation(RenderObject* object)
     98 {
     99     if (!object->isBoxModelObject())
    100         return false;
    101 
    102     RenderBoxModelObject* renderer = toRenderBoxModelObject(object);
    103     if (!renderer->isRenderInline())
    104         return false;
    105 
    106     return toRenderInline(renderer)->continuation();
    107 }
    108 
    109 static inline RenderObject* firstChildConsideringContinuation(RenderObject* renderer)
    110 {
    111     RenderObject* firstChild = renderer->slowFirstChild();
    112 
    113     if (!firstChild && isInlineWithContinuation(renderer))
    114         firstChild = firstChildInContinuation(toRenderInline(*renderer));
    115 
    116     return firstChild;
    117 }
    118 
    119 static inline RenderInline* startOfContinuations(RenderObject* r)
    120 {
    121     if (r->isInlineElementContinuation()) {
    122         return toRenderInline(r->node()->renderer());
    123     }
    124 
    125     // Blocks with a previous continuation always have a next continuation
    126     if (r->isRenderBlock() && toRenderBlock(r)->inlineElementContinuation())
    127         return toRenderInline(toRenderBlock(r)->inlineElementContinuation()->node()->renderer());
    128 
    129     return 0;
    130 }
    131 
    132 static inline RenderObject* endOfContinuations(RenderObject* renderer)
    133 {
    134     RenderObject* prev = renderer;
    135     RenderObject* cur = renderer;
    136 
    137     if (!cur->isRenderInline() && !cur->isRenderBlock())
    138         return renderer;
    139 
    140     while (cur) {
    141         prev = cur;
    142         if (cur->isRenderInline()) {
    143             cur = toRenderInline(cur)->inlineElementContinuation();
    144             ASSERT(cur || !toRenderInline(prev)->continuation());
    145         } else {
    146             cur = toRenderBlock(cur)->inlineElementContinuation();
    147         }
    148     }
    149 
    150     return prev;
    151 }
    152 
    153 static inline bool lastChildHasContinuation(RenderObject* renderer)
    154 {
    155     RenderObject* lastChild = renderer->slowLastChild();
    156     return lastChild && isInlineWithContinuation(lastChild);
    157 }
    158 
    159 static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
    160 {
    161     ASSERT(renderer);
    162     if (renderer->isRenderInline() && !renderer->isReplaced())
    163         return toRenderInline(renderer)->continuation();
    164     if (renderer->isRenderBlock())
    165         return toRenderBlock(renderer)->inlineElementContinuation();
    166     return 0;
    167 }
    168 
    169 AXRenderObject::AXRenderObject(RenderObject* renderer)
    170     : AXNodeObject(renderer->node())
    171     , m_renderer(renderer)
    172     , m_cachedElementRectDirty(true)
    173 {
    174 #if ENABLE(ASSERT)
    175     m_renderer->setHasAXObject(true);
    176 #endif
    177 }
    178 
    179 PassRefPtr<AXRenderObject> AXRenderObject::create(RenderObject* renderer)
    180 {
    181     return adoptRef(new AXRenderObject(renderer));
    182 }
    183 
    184 AXRenderObject::~AXRenderObject()
    185 {
    186     ASSERT(isDetached());
    187 }
    188 
    189 LayoutRect AXRenderObject::elementRect() const
    190 {
    191     if (!m_explicitElementRect.isEmpty())
    192         return m_explicitElementRect;
    193     if (!m_renderer)
    194         return LayoutRect();
    195     if (!m_renderer->isBox())
    196         return computeElementRect();
    197 
    198     for (const AXObject* obj = this; obj; obj = obj->parentObject()) {
    199         if (obj->isAXRenderObject())
    200             toAXRenderObject(obj)->checkCachedElementRect();
    201     }
    202     for (const AXObject* obj = this; obj; obj = obj->parentObject()) {
    203         if (obj->isAXRenderObject())
    204             toAXRenderObject(obj)->updateCachedElementRect();
    205     }
    206 
    207     return m_cachedElementRect;
    208 }
    209 
    210 void AXRenderObject::setRenderer(RenderObject* renderer)
    211 {
    212     m_renderer = renderer;
    213     setNode(renderer->node());
    214 }
    215 
    216 RenderBoxModelObject* AXRenderObject::renderBoxModelObject() const
    217 {
    218     if (!m_renderer || !m_renderer->isBoxModelObject())
    219         return 0;
    220     return toRenderBoxModelObject(m_renderer);
    221 }
    222 
    223 Document* AXRenderObject::topDocument() const
    224 {
    225     if (!document())
    226         return 0;
    227     return &document()->topDocument();
    228 }
    229 
    230 bool AXRenderObject::shouldNotifyActiveDescendant() const
    231 {
    232     // We want to notify that the combo box has changed its active descendant,
    233     // but we do not want to change the focus, because focus should remain with the combo box.
    234     if (isComboBox())
    235         return true;
    236 
    237     return shouldFocusActiveDescendant();
    238 }
    239 
    240 ScrollableArea* AXRenderObject::getScrollableAreaIfScrollable() const
    241 {
    242     // If the parent is a scroll view, then this object isn't really scrollable, the parent ScrollView should handle the scrolling.
    243     if (parentObject() && parentObject()->isAXScrollView())
    244         return 0;
    245 
    246     if (!m_renderer || !m_renderer->isBox())
    247         return 0;
    248 
    249     RenderBox* box = toRenderBox(m_renderer);
    250     if (!box->canBeScrolledAndHasScrollableArea())
    251         return 0;
    252 
    253     return box->scrollableArea();
    254 }
    255 
    256 AccessibilityRole AXRenderObject::determineAccessibilityRole()
    257 {
    258     if (!m_renderer)
    259         return UnknownRole;
    260 
    261     m_ariaRole = determineAriaRoleAttribute();
    262 
    263     Node* node = m_renderer->node();
    264     AccessibilityRole ariaRole = ariaRoleAttribute();
    265     if (ariaRole != UnknownRole)
    266         return ariaRole;
    267 
    268     RenderBoxModelObject* cssBox = renderBoxModelObject();
    269 
    270     if (node && node->isLink()) {
    271         if (cssBox && cssBox->isImage())
    272             return ImageMapRole;
    273         return LinkRole;
    274     }
    275     if (cssBox && cssBox->isListItem())
    276         return ListItemRole;
    277     if (m_renderer->isListMarker())
    278         return ListMarkerRole;
    279     if (isHTMLButtonElement(node))
    280         return buttonRoleType();
    281     if (isHTMLDetailsElement(node))
    282         return DetailsRole;
    283     if (isHTMLSummaryElement(node)) {
    284         if (node->parentElement() && isHTMLDetailsElement(node->parentElement()))
    285             return DisclosureTriangleRole;
    286         return UnknownRole;
    287     }
    288     if (isHTMLLegendElement(node))
    289         return LegendRole;
    290     if (m_renderer->isText())
    291         return StaticTextRole;
    292     if (cssBox && cssBox->isImage()) {
    293         if (isHTMLInputElement(node))
    294             return ariaHasPopup() ? PopUpButtonRole : ButtonRole;
    295         if (isSVGImage())
    296             return SVGRootRole;
    297         return ImageRole;
    298     }
    299 
    300     // Note: if JavaScript is disabled, the renderer won't be a RenderHTMLCanvas.
    301     if (isHTMLCanvasElement(node) && m_renderer->isCanvas())
    302         return CanvasRole;
    303 
    304     if (cssBox && cssBox->isRenderView())
    305         return WebAreaRole;
    306 
    307     if (cssBox && cssBox->isTextField())
    308         return TextFieldRole;
    309 
    310     if (cssBox && cssBox->isTextArea())
    311         return TextAreaRole;
    312 
    313     if (isHTMLInputElement(node)) {
    314         HTMLInputElement& input = toHTMLInputElement(*node);
    315         const AtomicString& type = input.type();
    316         if (type == InputTypeNames::checkbox)
    317             return CheckBoxRole;
    318         if (type == InputTypeNames::radio)
    319             return RadioButtonRole;
    320         if (input.isTextButton())
    321             return buttonRoleType();
    322         if (type == InputTypeNames::color)
    323             return ColorWellRole;
    324     }
    325 
    326     if (isFileUploadButton())
    327         return ButtonRole;
    328 
    329     if (cssBox && cssBox->isMenuList())
    330         return PopUpButtonRole;
    331 
    332     if (headingLevel())
    333         return HeadingRole;
    334 
    335     if (m_renderer->isSVGImage())
    336         return ImageRole;
    337     if (m_renderer->isSVGRoot())
    338         return SVGRootRole;
    339 
    340     if (node && node->hasTagName(ddTag))
    341         return DescriptionListDetailRole;
    342 
    343     if (node && node->hasTagName(dtTag))
    344         return DescriptionListTermRole;
    345 
    346     if (node && (node->hasTagName(rpTag) || node->hasTagName(rtTag)))
    347         return AnnotationRole;
    348 
    349     // Table sections should be ignored.
    350     if (m_renderer->isTableSection())
    351         return IgnoredRole;
    352 
    353     if (m_renderer->isHR())
    354         return HorizontalRuleRole;
    355 
    356     if (isHTMLParagraphElement(node))
    357         return ParagraphRole;
    358 
    359     if (isHTMLLabelElement(node))
    360         return LabelRole;
    361 
    362     if (isHTMLDivElement(node))
    363         return DivRole;
    364 
    365     if (isHTMLFormElement(node))
    366         return FormRole;
    367 
    368     if (node && node->hasTagName(articleTag))
    369         return ArticleRole;
    370 
    371     if (node && node->hasTagName(mainTag))
    372         return MainRole;
    373 
    374     if (node && node->hasTagName(navTag))
    375         return NavigationRole;
    376 
    377     if (node && node->hasTagName(asideTag))
    378         return ComplementaryRole;
    379 
    380     if (node && node->hasTagName(sectionTag))
    381         return RegionRole;
    382 
    383     if (node && node->hasTagName(addressTag))
    384         return ContentInfoRole;
    385 
    386     if (node && node->hasTagName(dialogTag))
    387         return DialogRole;
    388 
    389     // The HTML element should not be exposed as an element. That's what the RenderView element does.
    390     if (isHTMLHtmlElement(node))
    391         return IgnoredRole;
    392 
    393     if (node && node->hasTagName(iframeTag))
    394         return IframeRole;
    395 
    396     if (isEmbeddedObject())
    397         return EmbeddedObjectRole;
    398 
    399     if (node && node->hasTagName(figcaptionTag))
    400         return FigcaptionRole;
    401 
    402     if (node && node->hasTagName(figureTag))
    403         return FigureRole;
    404 
    405     // There should only be one banner/contentInfo per page. If header/footer are being used within an article or section
    406     // then it should not be exposed as whole page's banner/contentInfo
    407     if (node && node->hasTagName(headerTag) && !isDescendantOfElementType(articleTag) && !isDescendantOfElementType(sectionTag))
    408         return BannerRole;
    409     if (node && node->hasTagName(footerTag) && !isDescendantOfElementType(articleTag) && !isDescendantOfElementType(sectionTag))
    410         return FooterRole;
    411 
    412     if (isHTMLAnchorElement(node) && isClickable())
    413         return LinkRole;
    414 
    415     if (m_renderer->isRenderBlockFlow())
    416         return GroupRole;
    417 
    418     // If the element does not have role, but it has ARIA attributes, accessibility should fallback to exposing it as a group.
    419     if (supportsARIAAttributes())
    420         return GroupRole;
    421 
    422     return UnknownRole;
    423 }
    424 
    425 void AXRenderObject::init()
    426 {
    427     AXNodeObject::init();
    428 }
    429 
    430 void AXRenderObject::detach()
    431 {
    432     AXNodeObject::detach();
    433 
    434     detachRemoteSVGRoot();
    435 
    436 #if ENABLE(ASSERT)
    437     if (m_renderer)
    438         m_renderer->setHasAXObject(false);
    439 #endif
    440     m_renderer = 0;
    441 }
    442 
    443 //
    444 // Check object role or purpose.
    445 //
    446 
    447 bool AXRenderObject::isAttachment() const
    448 {
    449     RenderBoxModelObject* renderer = renderBoxModelObject();
    450     if (!renderer)
    451         return false;
    452     // Widgets are the replaced elements that we represent to AX as attachments
    453     bool isWidget = renderer->isWidget();
    454     ASSERT(!isWidget || (renderer->isReplaced() && !isImage()));
    455     return isWidget;
    456 }
    457 
    458 bool AXRenderObject::isFileUploadButton() const
    459 {
    460     return m_renderer && isHTMLInputElement(m_renderer->node()) && toHTMLInputElement(*m_renderer->node()).type() == InputTypeNames::file;
    461 }
    462 
    463 static bool isLinkable(const AXObject& object)
    464 {
    465     if (!object.renderer())
    466         return false;
    467 
    468     // See https://wiki.mozilla.org/Accessibility/AT-Windows-API for the elements
    469     // Mozilla considers linkable.
    470     return object.isLink() || object.isImage() || object.renderer()->isText();
    471 }
    472 
    473 bool AXRenderObject::isLinked() const
    474 {
    475     if (!isLinkable(*this))
    476         return false;
    477 
    478     Element* anchor = anchorElement();
    479     if (!isHTMLAnchorElement(anchor))
    480         return false;
    481 
    482     return !toHTMLAnchorElement(*anchor).href().isEmpty();
    483 }
    484 
    485 bool AXRenderObject::isLoaded() const
    486 {
    487     return !m_renderer->document().parser();
    488 }
    489 
    490 bool AXRenderObject::isOffScreen() const
    491 {
    492     ASSERT(m_renderer);
    493     IntRect contentRect = pixelSnappedIntRect(m_renderer->absoluteClippedOverflowRect());
    494     FrameView* view = m_renderer->frame()->view();
    495     IntRect viewRect = view->visibleContentRect();
    496     viewRect.intersect(contentRect);
    497     return viewRect.isEmpty();
    498 }
    499 
    500 bool AXRenderObject::isReadOnly() const
    501 {
    502     ASSERT(m_renderer);
    503 
    504     if (isWebArea()) {
    505         Document& document = m_renderer->document();
    506         HTMLElement* body = document.body();
    507         if (body && body->hasEditableStyle())
    508             return false;
    509 
    510         return !document.hasEditableStyle();
    511     }
    512 
    513     return AXNodeObject::isReadOnly();
    514 }
    515 
    516 bool AXRenderObject::isVisited() const
    517 {
    518     // FIXME: Is it a privacy violation to expose visited information to accessibility APIs?
    519     return m_renderer->style()->isLink() && m_renderer->style()->insideLink() == InsideVisitedLink;
    520 }
    521 
    522 //
    523 // Check object state.
    524 //
    525 
    526 bool AXRenderObject::isFocused() const
    527 {
    528     if (!m_renderer)
    529         return false;
    530 
    531     Document& document = m_renderer->document();
    532     Element* focusedElement = document.focusedElement();
    533     if (!focusedElement)
    534         return false;
    535 
    536     // A web area is represented by the Document node in the DOM tree, which isn't focusable.
    537     // Check instead if the frame's selection controller is focused
    538     if (focusedElement == m_renderer->node()
    539         || (roleValue() == WebAreaRole && document.frame()->selection().isFocusedAndActive()))
    540         return true;
    541 
    542     return false;
    543 }
    544 
    545 bool AXRenderObject::isSelected() const
    546 {
    547     if (!m_renderer)
    548         return false;
    549 
    550     Node* node = m_renderer->node();
    551     if (!node)
    552         return false;
    553 
    554     const AtomicString& ariaSelected = getAttribute(aria_selectedAttr);
    555     if (equalIgnoringCase(ariaSelected, "true"))
    556         return true;
    557 
    558     if (isTabItem() && isTabItemSelected())
    559         return true;
    560 
    561     return false;
    562 }
    563 
    564 //
    565 // Whether objects are ignored, i.e. not included in the tree.
    566 //
    567 
    568 AXObjectInclusion AXRenderObject::defaultObjectInclusion() const
    569 {
    570     // The following cases can apply to any element that's a subclass of AXRenderObject.
    571 
    572     if (!m_renderer)
    573         return IgnoreObject;
    574 
    575     if (m_renderer->style()->visibility() != VISIBLE) {
    576         // aria-hidden is meant to override visibility as the determinant in AX hierarchy inclusion.
    577         if (equalIgnoringCase(getAttribute(aria_hiddenAttr), "false"))
    578             return DefaultBehavior;
    579 
    580         return IgnoreObject;
    581     }
    582 
    583     return AXObject::defaultObjectInclusion();
    584 }
    585 
    586 bool AXRenderObject::computeAccessibilityIsIgnored() const
    587 {
    588 #if ENABLE(ASSERT)
    589     ASSERT(m_initialized);
    590 #endif
    591 
    592     // Check first if any of the common reasons cause this element to be ignored.
    593     // Then process other use cases that need to be applied to all the various roles
    594     // that AXRenderObjects take on.
    595     AXObjectInclusion decision = defaultObjectInclusion();
    596     if (decision == IncludeObject)
    597         return false;
    598     if (decision == IgnoreObject)
    599         return true;
    600 
    601     // If this element is within a parent that cannot have children, it should not be exposed.
    602     if (isDescendantOfBarrenParent())
    603         return true;
    604 
    605     if (roleValue() == IgnoredRole)
    606         return true;
    607 
    608     if ((roleValue() == NoneRole || roleValue() == PresentationalRole) || inheritsPresentationalRole())
    609         return true;
    610 
    611     // An ARIA tree can only have tree items and static text as children.
    612     if (!isAllowedChildOfTree())
    613         return true;
    614 
    615     // TODO: we should refactor this - but right now this is necessary to make
    616     // sure scroll areas stay in the tree.
    617     if (isAttachment())
    618         return false;
    619 
    620     // ignore popup menu items because AppKit does
    621     for (RenderObject* parent = m_renderer->parent(); parent; parent = parent->parent()) {
    622         if (parent->isBoxModelObject() && toRenderBoxModelObject(parent)->isMenuList())
    623             return true;
    624     }
    625 
    626     // find out if this element is inside of a label element.
    627     // if so, it may be ignored because it's the label for a checkbox or radio button
    628     AXObject* controlObject = correspondingControlForLabelElement();
    629     if (controlObject && !controlObject->exposesTitleUIElement() && controlObject->isCheckboxOrRadio())
    630         return true;
    631 
    632     // NOTE: BRs always have text boxes now, so the text box check here can be removed
    633     if (m_renderer->isText()) {
    634         // static text beneath MenuItems and MenuButtons are just reported along with the menu item, so it's ignored on an individual level
    635         AXObject* parent = parentObjectUnignored();
    636         if (parent && (parent->ariaRoleAttribute() == MenuItemRole || parent->ariaRoleAttribute() == MenuButtonRole))
    637             return true;
    638         RenderText* renderText = toRenderText(m_renderer);
    639         if (m_renderer->isBR() || !renderText->firstTextBox())
    640             return true;
    641 
    642         // Don't ignore static text in editable text controls.
    643         for (AXObject* parent = parentObject(); parent; parent = parent->parentObject()) {
    644             if (parent->roleValue() == TextFieldRole || parent->roleValue() == TextAreaRole)
    645                 return false;
    646         }
    647 
    648         // text elements that are just empty whitespace should not be returned
    649         // FIXME(dmazzoni): we probably shouldn't ignore this if the style is 'pre', or similar...
    650         return renderText->text().impl()->containsOnlyWhitespace();
    651     }
    652 
    653     if (isHeading())
    654         return false;
    655 
    656     if (isLandmarkRelated())
    657         return false;
    658 
    659     if (isLink())
    660         return false;
    661 
    662     // all controls are accessible
    663     if (isControl())
    664         return false;
    665 
    666     if (ariaRoleAttribute() != UnknownRole)
    667         return false;
    668 
    669     // don't ignore labels, because they serve as TitleUIElements
    670     Node* node = m_renderer->node();
    671     if (isHTMLLabelElement(node))
    672         return false;
    673 
    674     // Anything that is content editable should not be ignored.
    675     // However, one cannot just call node->hasEditableStyle() since that will ask if its parents
    676     // are also editable. Only the top level content editable region should be exposed.
    677     if (hasContentEditableAttributeSet())
    678         return false;
    679 
    680     // List items play an important role in defining the structure of lists. They should not be ignored.
    681     if (roleValue() == ListItemRole)
    682         return false;
    683 
    684     if (roleValue() == DialogRole)
    685         return false;
    686 
    687     if (roleValue() == FigcaptionRole)
    688         return false;
    689 
    690     if (roleValue() == FigureRole)
    691         return false;
    692 
    693     if (roleValue() == DetailsRole)
    694         return false;
    695 
    696     // if this element has aria attributes on it, it should not be ignored.
    697     if (supportsARIAAttributes())
    698         return false;
    699 
    700     // <span> tags are inline tags and not meant to convey information if they have no other aria
    701     // information on them. If we don't ignore them, they may emit signals expected to come from
    702     // their parent. In addition, because included spans are GroupRole objects, and GroupRole
    703     // objects are often containers with meaningful information, the inclusion of a span can have
    704     // the side effect of causing the immediate parent accessible to be ignored. This is especially
    705     // problematic for platforms which have distinct roles for textual block elements.
    706     if (isHTMLSpanElement(node))
    707         return true;
    708 
    709     if (m_renderer->isRenderBlockFlow() && m_renderer->childrenInline() && !canSetFocusAttribute())
    710         return !toRenderBlockFlow(m_renderer)->firstLineBox() && !mouseButtonListener();
    711 
    712     // ignore images seemingly used as spacers
    713     if (isImage()) {
    714 
    715         // If the image can take focus, it should not be ignored, lest the user not be able to interact with something important.
    716         if (canSetFocusAttribute())
    717             return false;
    718 
    719         if (node && node->isElementNode()) {
    720             Element* elt = toElement(node);
    721             const AtomicString& alt = elt->getAttribute(altAttr);
    722             // don't ignore an image that has an alt tag
    723             if (!alt.string().containsOnlyWhitespace())
    724                 return false;
    725             // informal standard is to ignore images with zero-length alt strings
    726             if (!alt.isNull())
    727                 return true;
    728         }
    729 
    730         if (isNativeImage() && m_renderer->isImage()) {
    731             // check for one-dimensional image
    732             RenderImage* image = toRenderImage(m_renderer);
    733             if (image->height() <= 1 || image->width() <= 1)
    734                 return true;
    735 
    736             // check whether rendered image was stretched from one-dimensional file image
    737             if (image->cachedImage()) {
    738                 LayoutSize imageSize = image->cachedImage()->imageSizeForRenderer(m_renderer, image->view()->zoomFactor());
    739                 return imageSize.height() <= 1 || imageSize.width() <= 1;
    740             }
    741         }
    742         return false;
    743     }
    744 
    745     if (isCanvas()) {
    746         if (canvasHasFallbackContent())
    747             return false;
    748         RenderHTMLCanvas* canvas = toRenderHTMLCanvas(m_renderer);
    749         if (canvas->height() <= 1 || canvas->width() <= 1)
    750             return true;
    751         // Otherwise fall through; use presence of help text, title, or description to decide.
    752     }
    753 
    754     if (isWebArea() || m_renderer->isListMarker())
    755         return false;
    756 
    757     // Using the help text, title or accessibility description (so we
    758     // check if there's some kind of accessible name for the element)
    759     // to decide an element's visibility is not as definitive as
    760     // previous checks, so this should remain as one of the last.
    761     //
    762     // These checks are simplified in the interest of execution speed;
    763     // for example, any element having an alt attribute will make it
    764     // not ignored, rather than just images.
    765     if (!getAttribute(aria_helpAttr).isEmpty() || !getAttribute(aria_describedbyAttr).isEmpty() || !getAttribute(altAttr).isEmpty() || !getAttribute(titleAttr).isEmpty())
    766         return false;
    767 
    768     // Don't ignore generic focusable elements like <div tabindex=0>
    769     // unless they're completely empty, with no children.
    770     if (isGenericFocusableElement() && node->hasChildren())
    771         return false;
    772 
    773     if (!ariaAccessibilityDescription().isEmpty())
    774         return false;
    775 
    776     // By default, objects should be ignored so that the AX hierarchy is not
    777     // filled with unnecessary items.
    778     return true;
    779 }
    780 
    781 //
    782 // Properties of static elements.
    783 //
    784 
    785 const AtomicString& AXRenderObject::accessKey() const
    786 {
    787     Node* node = m_renderer->node();
    788     if (!node)
    789         return nullAtom;
    790     if (!node->isElementNode())
    791         return nullAtom;
    792     return toElement(node)->getAttribute(accesskeyAttr);
    793 }
    794 
    795 AccessibilityOrientation AXRenderObject::orientation() const
    796 {
    797     const AtomicString& ariaOrientation = getAttribute(aria_orientationAttr);
    798     if (equalIgnoringCase(ariaOrientation, "horizontal"))
    799         return AccessibilityOrientationHorizontal;
    800     if (equalIgnoringCase(ariaOrientation, "vertical"))
    801         return AccessibilityOrientationVertical;
    802 
    803     return AXObject::orientation();
    804 }
    805 
    806 String AXRenderObject::text() const
    807 {
    808     if (isPasswordField())
    809         return String();
    810 
    811     return AXNodeObject::text();
    812 }
    813 
    814 int AXRenderObject::textLength() const
    815 {
    816     if (!isTextControl())
    817         return -1;
    818 
    819     if (isPasswordField())
    820         return -1; // need to return something distinct from 0
    821 
    822     return text().length();
    823 }
    824 
    825 KURL AXRenderObject::url() const
    826 {
    827     if (isAnchor() && isHTMLAnchorElement(m_renderer->node())) {
    828         if (HTMLAnchorElement* anchor = toHTMLAnchorElement(anchorElement()))
    829             return anchor->href();
    830     }
    831 
    832     if (isWebArea())
    833         return m_renderer->document().url();
    834 
    835     if (isImage() && isHTMLImageElement(m_renderer->node()))
    836         return toHTMLImageElement(*m_renderer->node()).src();
    837 
    838     if (isInputImage())
    839         return toHTMLInputElement(m_renderer->node())->src();
    840 
    841     return KURL();
    842 }
    843 
    844 //
    845 // Properties of interactive elements.
    846 //
    847 
    848 static String queryString(WebLocalizedString::Name name)
    849 {
    850     return Locale::defaultLocale().queryString(name);
    851 }
    852 
    853 String AXRenderObject::actionVerb() const
    854 {
    855     switch (roleValue()) {
    856     case ButtonRole:
    857     case ToggleButtonRole:
    858         return queryString(WebLocalizedString::AXButtonActionVerb);
    859     case TextFieldRole:
    860     case TextAreaRole:
    861         return queryString(WebLocalizedString::AXTextFieldActionVerb);
    862     case RadioButtonRole:
    863         return queryString(WebLocalizedString::AXRadioButtonActionVerb);
    864     case CheckBoxRole:
    865         return queryString(isChecked() ? WebLocalizedString::AXCheckedCheckBoxActionVerb : WebLocalizedString::AXUncheckedCheckBoxActionVerb);
    866     case LinkRole:
    867         return queryString(WebLocalizedString::AXLinkActionVerb);
    868     default:
    869         return emptyString();
    870     }
    871 }
    872 
    873 String AXRenderObject::stringValue() const
    874 {
    875     if (!m_renderer)
    876         return String();
    877 
    878     if (isPasswordField())
    879         return String();
    880 
    881     RenderBoxModelObject* cssBox = renderBoxModelObject();
    882 
    883     if (ariaRoleAttribute() == StaticTextRole) {
    884         String staticText = text();
    885         if (!staticText.length())
    886             staticText = textUnderElement();
    887         return staticText;
    888     }
    889 
    890     if (m_renderer->isText())
    891         return textUnderElement();
    892 
    893     if (cssBox && cssBox->isMenuList()) {
    894         // RenderMenuList will go straight to the text() of its selected item.
    895         // This has to be overridden in the case where the selected item has an ARIA label.
    896         HTMLSelectElement* selectElement = toHTMLSelectElement(m_renderer->node());
    897         int selectedIndex = selectElement->selectedIndex();
    898         const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement->listItems();
    899         if (selectedIndex >= 0 && static_cast<size_t>(selectedIndex) < listItems.size()) {
    900             const AtomicString& overriddenDescription = listItems[selectedIndex]->fastGetAttribute(aria_labelAttr);
    901             if (!overriddenDescription.isNull())
    902                 return overriddenDescription;
    903         }
    904         return toRenderMenuList(m_renderer)->text();
    905     }
    906 
    907     if (m_renderer->isListMarker())
    908         return toRenderListMarker(m_renderer)->text();
    909 
    910     if (isWebArea()) {
    911         // FIXME: Why would a renderer exist when the Document isn't attached to a frame?
    912         if (m_renderer->frame())
    913             return String();
    914 
    915         ASSERT_NOT_REACHED();
    916     }
    917 
    918     if (isTextControl())
    919         return text();
    920 
    921     if (m_renderer->isFileUploadControl())
    922         return toRenderFileUploadControl(m_renderer)->fileTextValue();
    923 
    924     // FIXME: We might need to implement a value here for more types
    925     // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one;
    926     // this would require subclassing or making accessibilityAttributeNames do something other than return a
    927     // single static array.
    928     return String();
    929 }
    930 
    931 //
    932 // ARIA attributes.
    933 //
    934 
    935 AXObject* AXRenderObject::activeDescendant() const
    936 {
    937     if (!m_renderer)
    938         return 0;
    939 
    940     if (m_renderer->node() && !m_renderer->node()->isElementNode())
    941         return 0;
    942 
    943     Element* element = toElement(m_renderer->node());
    944     if (!element)
    945         return 0;
    946 
    947     const AtomicString& activeDescendantAttrStr = element->getAttribute(aria_activedescendantAttr);
    948     if (activeDescendantAttrStr.isNull() || activeDescendantAttrStr.isEmpty())
    949         return 0;
    950 
    951     Element* target = element->treeScope().getElementById(activeDescendantAttrStr);
    952     if (!target)
    953         return 0;
    954 
    955     AXObject* obj = axObjectCache()->getOrCreate(target);
    956 
    957     // An activedescendant is only useful if it has a renderer, because that's what's needed to post the notification.
    958     if (obj && obj->isAXRenderObject())
    959         return obj;
    960 
    961     return 0;
    962 }
    963 
    964 void AXRenderObject::accessibilityChildrenFromAttribute(QualifiedName attr, AccessibilityChildrenVector& children) const
    965 {
    966     WillBeHeapVector<RawPtrWillBeMember<Element> > elements;
    967     elementsFromAttribute(elements, attr);
    968 
    969     AXObjectCache* cache = axObjectCache();
    970     unsigned count = elements.size();
    971     for (unsigned k = 0; k < count; ++k) {
    972         Element* element = elements[k];
    973         AXObject* child = cache->getOrCreate(element);
    974         if (child)
    975             children.append(child);
    976     }
    977 }
    978 
    979 void AXRenderObject::ariaFlowToElements(AccessibilityChildrenVector& flowTo) const
    980 {
    981     accessibilityChildrenFromAttribute(aria_flowtoAttr, flowTo);
    982 }
    983 
    984 void AXRenderObject::ariaControlsElements(AccessibilityChildrenVector& controls) const
    985 {
    986     accessibilityChildrenFromAttribute(aria_controlsAttr, controls);
    987 }
    988 
    989 void AXRenderObject::ariaDescribedbyElements(AccessibilityChildrenVector& describedby) const
    990 {
    991     accessibilityChildrenFromAttribute(aria_describedbyAttr, describedby);
    992 }
    993 
    994 void AXRenderObject::ariaLabelledbyElements(AccessibilityChildrenVector& labelledby) const
    995 {
    996     accessibilityChildrenFromAttribute(aria_labelledbyAttr, labelledby);
    997 }
    998 
    999 void AXRenderObject::ariaOwnsElements(AccessibilityChildrenVector& owns) const
   1000 {
   1001     accessibilityChildrenFromAttribute(aria_ownsAttr, owns);
   1002 }
   1003 
   1004 bool AXRenderObject::ariaHasPopup() const
   1005 {
   1006     return elementAttributeValue(aria_haspopupAttr);
   1007 }
   1008 
   1009 bool AXRenderObject::ariaRoleHasPresentationalChildren() const
   1010 {
   1011     switch (m_ariaRole) {
   1012     case ButtonRole:
   1013     case SliderRole:
   1014     case ImageRole:
   1015     case ProgressIndicatorRole:
   1016     case SpinButtonRole:
   1017     // case SeparatorRole:
   1018         return true;
   1019     default:
   1020         return false;
   1021     }
   1022 }
   1023 
   1024 bool AXRenderObject::isPresentationalChildOfAriaRole() const
   1025 {
   1026     // Walk the parent chain looking for a parent that has presentational children
   1027     AXObject* parent;
   1028     for (parent = parentObject(); parent && !parent->ariaRoleHasPresentationalChildren(); parent = parent->parentObject())
   1029     { }
   1030 
   1031     return parent;
   1032 }
   1033 
   1034 bool AXRenderObject::shouldFocusActiveDescendant() const
   1035 {
   1036     switch (ariaRoleAttribute()) {
   1037     case ComboBoxRole:
   1038     case GridRole:
   1039     case GroupRole:
   1040     case ListBoxRole:
   1041     case MenuRole:
   1042     case MenuBarRole:
   1043     case OutlineRole:
   1044     case PopUpButtonRole:
   1045     case ProgressIndicatorRole:
   1046     case RadioGroupRole:
   1047     case RowRole:
   1048     case TabListRole:
   1049     case ToolbarRole:
   1050     case TreeRole:
   1051     case TreeGridRole:
   1052         return true;
   1053     default:
   1054         return false;
   1055     }
   1056 }
   1057 
   1058 bool AXRenderObject::supportsARIADragging() const
   1059 {
   1060     const AtomicString& grabbed = getAttribute(aria_grabbedAttr);
   1061     return equalIgnoringCase(grabbed, "true") || equalIgnoringCase(grabbed, "false");
   1062 }
   1063 
   1064 bool AXRenderObject::supportsARIADropping() const
   1065 {
   1066     const AtomicString& dropEffect = getAttribute(aria_dropeffectAttr);
   1067     return !dropEffect.isEmpty();
   1068 }
   1069 
   1070 bool AXRenderObject::supportsARIAFlowTo() const
   1071 {
   1072     return !getAttribute(aria_flowtoAttr).isEmpty();
   1073 }
   1074 
   1075 bool AXRenderObject::supportsARIAOwns() const
   1076 {
   1077     if (!m_renderer)
   1078         return false;
   1079     const AtomicString& ariaOwns = getAttribute(aria_ownsAttr);
   1080 
   1081     return !ariaOwns.isEmpty();
   1082 }
   1083 
   1084 //
   1085 // ARIA live-region features.
   1086 //
   1087 
   1088 const AtomicString& AXRenderObject::ariaLiveRegionStatus() const
   1089 {
   1090     DEFINE_STATIC_LOCAL(const AtomicString, liveRegionStatusAssertive, ("assertive", AtomicString::ConstructFromLiteral));
   1091     DEFINE_STATIC_LOCAL(const AtomicString, liveRegionStatusPolite, ("polite", AtomicString::ConstructFromLiteral));
   1092     DEFINE_STATIC_LOCAL(const AtomicString, liveRegionStatusOff, ("off", AtomicString::ConstructFromLiteral));
   1093 
   1094     const AtomicString& liveRegionStatus = getAttribute(aria_liveAttr);
   1095     // These roles have implicit live region status.
   1096     if (liveRegionStatus.isEmpty()) {
   1097         switch (roleValue()) {
   1098         case AlertDialogRole:
   1099         case AlertRole:
   1100             return liveRegionStatusAssertive;
   1101         case LogRole:
   1102         case StatusRole:
   1103             return liveRegionStatusPolite;
   1104         case TimerRole:
   1105         case MarqueeRole:
   1106             return liveRegionStatusOff;
   1107         default:
   1108             break;
   1109         }
   1110     }
   1111 
   1112     return liveRegionStatus;
   1113 }
   1114 
   1115 const AtomicString& AXRenderObject::ariaLiveRegionRelevant() const
   1116 {
   1117     DEFINE_STATIC_LOCAL(const AtomicString, defaultLiveRegionRelevant, ("additions text", AtomicString::ConstructFromLiteral));
   1118     const AtomicString& relevant = getAttribute(aria_relevantAttr);
   1119 
   1120     // Default aria-relevant = "additions text".
   1121     if (relevant.isEmpty())
   1122         return defaultLiveRegionRelevant;
   1123 
   1124     return relevant;
   1125 }
   1126 
   1127 bool AXRenderObject::ariaLiveRegionAtomic() const
   1128 {
   1129     return elementAttributeValue(aria_atomicAttr);
   1130 }
   1131 
   1132 bool AXRenderObject::ariaLiveRegionBusy() const
   1133 {
   1134     return elementAttributeValue(aria_busyAttr);
   1135 }
   1136 
   1137 //
   1138 // Accessibility Text.
   1139 //
   1140 
   1141 String AXRenderObject::textUnderElement() const
   1142 {
   1143     if (!m_renderer)
   1144         return String();
   1145 
   1146     if (m_renderer->isFileUploadControl())
   1147         return toRenderFileUploadControl(m_renderer)->buttonValue();
   1148 
   1149     if (m_renderer->isText())
   1150         return toRenderText(m_renderer)->plainText();
   1151 
   1152     return AXNodeObject::textUnderElement();
   1153 }
   1154 
   1155 //
   1156 // Accessibility Text - (To be deprecated).
   1157 //
   1158 
   1159 String AXRenderObject::helpText() const
   1160 {
   1161     if (!m_renderer)
   1162         return String();
   1163 
   1164     const AtomicString& ariaHelp = getAttribute(aria_helpAttr);
   1165     if (!ariaHelp.isEmpty())
   1166         return ariaHelp;
   1167 
   1168     String describedBy = ariaDescribedByAttribute();
   1169     if (!describedBy.isEmpty())
   1170         return describedBy;
   1171 
   1172     String description = accessibilityDescription();
   1173     for (RenderObject* curr = m_renderer; curr; curr = curr->parent()) {
   1174         if (curr->node() && curr->node()->isHTMLElement()) {
   1175             const AtomicString& summary = toElement(curr->node())->getAttribute(summaryAttr);
   1176             if (!summary.isEmpty())
   1177                 return summary;
   1178 
   1179             // The title attribute should be used as help text unless it is already being used as descriptive text.
   1180             const AtomicString& title = toElement(curr->node())->getAttribute(titleAttr);
   1181             if (!title.isEmpty() && description != title)
   1182                 return title;
   1183         }
   1184 
   1185         // Only take help text from an ancestor element if its a group or an unknown role. If help was
   1186         // added to those kinds of elements, it is likely it was meant for a child element.
   1187         AXObject* axObj = axObjectCache()->getOrCreate(curr);
   1188         if (axObj) {
   1189             AccessibilityRole role = axObj->roleValue();
   1190             if (role != GroupRole && role != UnknownRole)
   1191                 break;
   1192         }
   1193     }
   1194 
   1195     return String();
   1196 }
   1197 
   1198 //
   1199 // Position and size.
   1200 //
   1201 
   1202 void AXRenderObject::checkCachedElementRect() const
   1203 {
   1204     if (m_cachedElementRectDirty)
   1205         return;
   1206 
   1207     if (!m_renderer)
   1208         return;
   1209 
   1210     if (!m_renderer->isBox())
   1211         return;
   1212 
   1213     bool dirty = false;
   1214     RenderBox* box = toRenderBox(m_renderer);
   1215     if (box->frameRect() != m_cachedFrameRect)
   1216         dirty = true;
   1217 
   1218     if (box->canBeScrolledAndHasScrollableArea()) {
   1219         ScrollableArea* scrollableArea = box->scrollableArea();
   1220         if (scrollableArea && scrollableArea->scrollPosition() != m_cachedScrollPosition)
   1221             dirty = true;
   1222     }
   1223 
   1224     if (dirty)
   1225         markCachedElementRectDirty();
   1226 }
   1227 
   1228 void AXRenderObject::updateCachedElementRect() const
   1229 {
   1230     if (!m_cachedElementRectDirty)
   1231         return;
   1232 
   1233     if (!m_renderer)
   1234         return;
   1235 
   1236     if (!m_renderer->isBox())
   1237         return;
   1238 
   1239     RenderBox* box = toRenderBox(m_renderer);
   1240     m_cachedFrameRect = box->frameRect();
   1241 
   1242     if (box->canBeScrolledAndHasScrollableArea()) {
   1243         ScrollableArea* scrollableArea = box->scrollableArea();
   1244         if (scrollableArea)
   1245             m_cachedScrollPosition = scrollableArea->scrollPosition();
   1246     }
   1247 
   1248     m_cachedElementRect = computeElementRect();
   1249     m_cachedElementRectDirty = false;
   1250 }
   1251 
   1252 void AXRenderObject::markCachedElementRectDirty() const
   1253 {
   1254     if (m_cachedElementRectDirty)
   1255         return;
   1256 
   1257     // Marks children recursively, if this element changed.
   1258     m_cachedElementRectDirty = true;
   1259     for (AXObject* child = firstChild(); child; child = child->nextSibling())
   1260         child->markCachedElementRectDirty();
   1261 }
   1262 
   1263 IntPoint AXRenderObject::clickPoint()
   1264 {
   1265     // Headings are usually much wider than their textual content. If the mid point is used, often it can be wrong.
   1266     if (isHeading() && children().size() == 1)
   1267         return children()[0]->clickPoint();
   1268 
   1269     // use the default position unless this is an editable web area, in which case we use the selection bounds.
   1270     if (!isWebArea() || isReadOnly())
   1271         return AXObject::clickPoint();
   1272 
   1273     IntRect bounds = pixelSnappedIntRect(elementRect());
   1274     return IntPoint(bounds.x() + (bounds.width() / 2), bounds.y() - (bounds.height() / 2));
   1275 }
   1276 
   1277 //
   1278 // Hit testing.
   1279 //
   1280 
   1281 AXObject* AXRenderObject::accessibilityHitTest(const IntPoint& point) const
   1282 {
   1283     if (!m_renderer || !m_renderer->hasLayer())
   1284         return 0;
   1285 
   1286     RenderLayer* layer = toRenderBox(m_renderer)->layer();
   1287 
   1288     HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
   1289     HitTestResult hitTestResult = HitTestResult(point);
   1290     layer->hitTest(request, hitTestResult);
   1291     if (!hitTestResult.innerNode())
   1292         return 0;
   1293 
   1294     Node* node = hitTestResult.innerNode();
   1295     if (node->isInShadowTree())
   1296         node = node->shadowHost();
   1297 
   1298     if (isHTMLAreaElement(node))
   1299         return accessibilityImageMapHitTest(toHTMLAreaElement(node), point);
   1300 
   1301     if (isHTMLOptionElement(node))
   1302         node = toHTMLOptionElement(*node).ownerSelectElement();
   1303 
   1304     RenderObject* obj = node->renderer();
   1305     if (!obj)
   1306         return 0;
   1307 
   1308     AXObject* result = obj->document().axObjectCache()->getOrCreate(obj);
   1309     result->updateChildrenIfNecessary();
   1310 
   1311     // Allow the element to perform any hit-testing it might need to do to reach non-render children.
   1312     result = result->elementAccessibilityHitTest(point);
   1313 
   1314     if (result && result->accessibilityIsIgnored()) {
   1315         // If this element is the label of a control, a hit test should return the control.
   1316         if (result->isAXRenderObject()) {
   1317             AXObject* controlObject = toAXRenderObject(result)->correspondingControlForLabelElement();
   1318             if (controlObject && !controlObject->exposesTitleUIElement())
   1319                 return controlObject;
   1320         }
   1321 
   1322         result = result->parentObjectUnignored();
   1323     }
   1324 
   1325     return result;
   1326 }
   1327 
   1328 AXObject* AXRenderObject::elementAccessibilityHitTest(const IntPoint& point) const
   1329 {
   1330     if (isSVGImage())
   1331         return remoteSVGElementHitTest(point);
   1332 
   1333     return AXObject::elementAccessibilityHitTest(point);
   1334 }
   1335 
   1336 //
   1337 // High-level accessibility tree access.
   1338 //
   1339 
   1340 AXObject* AXRenderObject::parentObject() const
   1341 {
   1342     if (!m_renderer)
   1343         return 0;
   1344 
   1345     if (ariaRoleAttribute() == MenuBarRole)
   1346         return axObjectCache()->getOrCreate(m_renderer->parent());
   1347 
   1348     // menuButton and its corresponding menu are DOM siblings, but Accessibility needs them to be parent/child
   1349     if (ariaRoleAttribute() == MenuRole) {
   1350         AXObject* parent = menuButtonForMenu();
   1351         if (parent)
   1352             return parent;
   1353     }
   1354 
   1355     RenderObject* parentObj = renderParentObject();
   1356     if (parentObj)
   1357         return axObjectCache()->getOrCreate(parentObj);
   1358 
   1359     // WebArea's parent should be the scroll view containing it.
   1360     if (isWebArea())
   1361         return axObjectCache()->getOrCreate(m_renderer->frame()->view());
   1362 
   1363     return 0;
   1364 }
   1365 
   1366 AXObject* AXRenderObject::parentObjectIfExists() const
   1367 {
   1368     // WebArea's parent should be the scroll view containing it.
   1369     if (isWebArea())
   1370         return axObjectCache()->get(m_renderer->frame()->view());
   1371 
   1372     return axObjectCache()->get(renderParentObject());
   1373 }
   1374 
   1375 //
   1376 // Low-level accessibility tree exploration, only for use within the accessibility module.
   1377 //
   1378 
   1379 AXObject* AXRenderObject::firstChild() const
   1380 {
   1381     if (!m_renderer)
   1382         return 0;
   1383 
   1384     RenderObject* firstChild = firstChildConsideringContinuation(m_renderer);
   1385 
   1386     if (!firstChild)
   1387         return 0;
   1388 
   1389     return axObjectCache()->getOrCreate(firstChild);
   1390 }
   1391 
   1392 AXObject* AXRenderObject::nextSibling() const
   1393 {
   1394     if (!m_renderer)
   1395         return 0;
   1396 
   1397     RenderObject* nextSibling = 0;
   1398 
   1399     RenderInline* inlineContinuation = m_renderer->isRenderBlock() ? toRenderBlock(m_renderer)->inlineElementContinuation() : 0;
   1400     if (inlineContinuation) {
   1401         // Case 1: node is a block and has an inline continuation. Next sibling is the inline continuation's first child.
   1402         nextSibling = firstChildConsideringContinuation(inlineContinuation);
   1403     } else if (m_renderer->isAnonymousBlock() && lastChildHasContinuation(m_renderer)) {
   1404         // Case 2: Anonymous block parent of the start of a continuation - skip all the way to
   1405         // after the parent of the end, since everything in between will be linked up via the continuation.
   1406         RenderObject* lastParent = endOfContinuations(toRenderBlock(m_renderer)->lastChild())->parent();
   1407         while (lastChildHasContinuation(lastParent))
   1408             lastParent = endOfContinuations(lastParent->slowLastChild())->parent();
   1409         nextSibling = lastParent->nextSibling();
   1410     } else if (RenderObject* ns = m_renderer->nextSibling()) {
   1411         // Case 3: node has an actual next sibling
   1412         nextSibling = ns;
   1413     } else if (isInlineWithContinuation(m_renderer)) {
   1414         // Case 4: node is an inline with a continuation. Next sibling is the next sibling of the end
   1415         // of the continuation chain.
   1416         nextSibling = endOfContinuations(m_renderer)->nextSibling();
   1417     } else if (isInlineWithContinuation(m_renderer->parent())) {
   1418         // Case 5: node has no next sibling, and its parent is an inline with a continuation.
   1419         RenderObject* continuation = toRenderInline(m_renderer->parent())->continuation();
   1420 
   1421         if (continuation->isRenderBlock()) {
   1422             // Case 5a: continuation is a block - in this case the block itself is the next sibling.
   1423             nextSibling = continuation;
   1424         } else {
   1425             // Case 5b: continuation is an inline - in this case the inline's first child is the next sibling.
   1426             nextSibling = firstChildConsideringContinuation(continuation);
   1427         }
   1428     }
   1429 
   1430     if (!nextSibling)
   1431         return 0;
   1432 
   1433     return axObjectCache()->getOrCreate(nextSibling);
   1434 }
   1435 
   1436 void AXRenderObject::addChildren()
   1437 {
   1438     // If the need to add more children in addition to existing children arises,
   1439     // childrenChanged should have been called, leaving the object with no children.
   1440     ASSERT(!m_haveChildren);
   1441 
   1442     m_haveChildren = true;
   1443 
   1444     if (!canHaveChildren())
   1445         return;
   1446 
   1447     for (RefPtr<AXObject> obj = firstChild(); obj; obj = obj->nextSibling())
   1448         addChild(obj.get());
   1449 
   1450     addHiddenChildren();
   1451     addAttachmentChildren();
   1452     addPopupChildren();
   1453     addImageMapChildren();
   1454     addTextFieldChildren();
   1455     addCanvasChildren();
   1456     addRemoteSVGChildren();
   1457     addInlineTextBoxChildren();
   1458 }
   1459 
   1460 bool AXRenderObject::canHaveChildren() const
   1461 {
   1462     if (!m_renderer)
   1463         return false;
   1464 
   1465     return AXNodeObject::canHaveChildren();
   1466 }
   1467 
   1468 void AXRenderObject::updateChildrenIfNecessary()
   1469 {
   1470     if (needsToUpdateChildren())
   1471         clearChildren();
   1472 
   1473     AXObject::updateChildrenIfNecessary();
   1474 }
   1475 
   1476 void AXRenderObject::clearChildren()
   1477 {
   1478     AXObject::clearChildren();
   1479     m_childrenDirty = false;
   1480 }
   1481 
   1482 AXObject* AXRenderObject::observableObject() const
   1483 {
   1484     // Find the object going up the parent chain that is used in accessibility to monitor certain notifications.
   1485     for (RenderObject* renderer = m_renderer; renderer && renderer->node(); renderer = renderer->parent()) {
   1486         if (renderObjectIsObservable(renderer))
   1487             return axObjectCache()->getOrCreate(renderer);
   1488     }
   1489 
   1490     return 0;
   1491 }
   1492 
   1493 //
   1494 // Properties of the object's owning document or page.
   1495 //
   1496 
   1497 double AXRenderObject::estimatedLoadingProgress() const
   1498 {
   1499     if (!m_renderer)
   1500         return 0;
   1501 
   1502     if (isLoaded())
   1503         return 1.0;
   1504 
   1505     if (LocalFrame* frame = m_renderer->document().frame())
   1506         return frame->loader().progress().estimatedProgress();
   1507     return 0;
   1508 }
   1509 
   1510 //
   1511 // DOM and Render tree access.
   1512 //
   1513 
   1514 Node* AXRenderObject::node() const
   1515 {
   1516     return m_renderer ? m_renderer->node() : 0;
   1517 }
   1518 
   1519 Document* AXRenderObject::document() const
   1520 {
   1521     if (!m_renderer)
   1522         return 0;
   1523     return &m_renderer->document();
   1524 }
   1525 
   1526 FrameView* AXRenderObject::documentFrameView() const
   1527 {
   1528     if (!m_renderer)
   1529         return 0;
   1530 
   1531     // this is the RenderObject's Document's LocalFrame's FrameView
   1532     return m_renderer->document().view();
   1533 }
   1534 
   1535 Element* AXRenderObject::anchorElement() const
   1536 {
   1537     if (!m_renderer)
   1538         return 0;
   1539 
   1540     AXObjectCache* cache = axObjectCache();
   1541     RenderObject* currRenderer;
   1542 
   1543     // Search up the render tree for a RenderObject with a DOM node. Defer to an earlier continuation, though.
   1544     for (currRenderer = m_renderer; currRenderer && !currRenderer->node(); currRenderer = currRenderer->parent()) {
   1545         if (currRenderer->isAnonymousBlock()) {
   1546             RenderObject* continuation = toRenderBlock(currRenderer)->continuation();
   1547             if (continuation)
   1548                 return cache->getOrCreate(continuation)->anchorElement();
   1549         }
   1550     }
   1551 
   1552     // bail if none found
   1553     if (!currRenderer)
   1554         return 0;
   1555 
   1556     // search up the DOM tree for an anchor element
   1557     // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement
   1558     Node* node = currRenderer->node();
   1559     for ( ; node; node = node->parentNode()) {
   1560         if (isHTMLAnchorElement(*node) || (node->renderer() && cache->getOrCreate(node->renderer())->isAnchor()))
   1561             return toElement(node);
   1562     }
   1563 
   1564     return 0;
   1565 }
   1566 
   1567 Widget* AXRenderObject::widgetForAttachmentView() const
   1568 {
   1569     if (!isAttachment())
   1570         return 0;
   1571     return toRenderWidget(m_renderer)->widget();
   1572 }
   1573 
   1574 //
   1575 // Selected text.
   1576 //
   1577 
   1578 AXObject::PlainTextRange AXRenderObject::selectedTextRange() const
   1579 {
   1580     if (!isTextControl())
   1581         return PlainTextRange();
   1582 
   1583     if (isPasswordField())
   1584         return PlainTextRange();
   1585 
   1586     AccessibilityRole ariaRole = ariaRoleAttribute();
   1587     if (isNativeTextControl() && ariaRole == UnknownRole && m_renderer->isTextControl()) {
   1588         HTMLTextFormControlElement* textControl = toRenderTextControl(m_renderer)->textFormControlElement();
   1589         return PlainTextRange(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart());
   1590     }
   1591 
   1592     if (ariaRole == UnknownRole)
   1593         return PlainTextRange();
   1594 
   1595     return ariaSelectedTextRange();
   1596 }
   1597 
   1598 VisibleSelection AXRenderObject::selection() const
   1599 {
   1600     return m_renderer->frame()->selection().selection();
   1601 }
   1602 
   1603 //
   1604 // Modify or take an action on an object.
   1605 //
   1606 
   1607 void AXRenderObject::setSelectedTextRange(const PlainTextRange& range)
   1608 {
   1609     if (isNativeTextControl() && m_renderer->isTextControl()) {
   1610         HTMLTextFormControlElement* textControl = toRenderTextControl(m_renderer)->textFormControlElement();
   1611         textControl->setSelectionRange(range.start, range.start + range.length);
   1612         return;
   1613     }
   1614 
   1615     Document& document = m_renderer->document();
   1616     LocalFrame* frame = document.frame();
   1617     if (!frame)
   1618         return;
   1619     Node* node = m_renderer->node();
   1620     frame->selection().setSelection(VisibleSelection(Position(node, range.start, Position::PositionIsOffsetInAnchor),
   1621         Position(node, range.start + range.length, Position::PositionIsOffsetInAnchor), DOWNSTREAM));
   1622 }
   1623 
   1624 void AXRenderObject::setValue(const String& string)
   1625 {
   1626     if (!node() || !node()->isElementNode())
   1627         return;
   1628     if (!m_renderer || !m_renderer->isBoxModelObject())
   1629         return;
   1630 
   1631     RenderBoxModelObject* renderer = toRenderBoxModelObject(m_renderer);
   1632     if (renderer->isTextField() && isHTMLInputElement(*node()))
   1633         toHTMLInputElement(*node()).setValue(string);
   1634     else if (renderer->isTextArea() && isHTMLTextAreaElement(*node()))
   1635         toHTMLTextAreaElement(*node()).setValue(string);
   1636 }
   1637 
   1638 // FIXME: This function should use an IntSize to avoid the conversion below.
   1639 void AXRenderObject::scrollTo(const IntPoint& point) const
   1640 {
   1641     if (!m_renderer || !m_renderer->isBox())
   1642         return;
   1643 
   1644     RenderBox* box = toRenderBox(m_renderer);
   1645     if (!box->canBeScrolledAndHasScrollableArea())
   1646         return;
   1647 
   1648     box->scrollToOffset(IntSize(point.x(), point.y()));
   1649 }
   1650 
   1651 //
   1652 // Notifications that this object may have changed.
   1653 //
   1654 
   1655 void AXRenderObject::handleActiveDescendantChanged()
   1656 {
   1657     Element* element = toElement(renderer()->node());
   1658     if (!element)
   1659         return;
   1660     Document& doc = renderer()->document();
   1661     if (!doc.frame()->selection().isFocusedAndActive() || doc.focusedElement() != element)
   1662         return;
   1663     AXRenderObject* activedescendant = toAXRenderObject(activeDescendant());
   1664 
   1665     if (activedescendant && shouldNotifyActiveDescendant())
   1666         doc.axObjectCache()->postNotification(m_renderer, AXObjectCache::AXActiveDescendantChanged, true);
   1667 }
   1668 
   1669 void AXRenderObject::handleAriaExpandedChanged()
   1670 {
   1671     // Find if a parent of this object should handle aria-expanded changes.
   1672     AXObject* containerParent = this->parentObject();
   1673     while (containerParent) {
   1674         bool foundParent = false;
   1675 
   1676         switch (containerParent->roleValue()) {
   1677         case TreeRole:
   1678         case TreeGridRole:
   1679         case GridRole:
   1680         case TableRole:
   1681         case BrowserRole:
   1682             foundParent = true;
   1683             break;
   1684         default:
   1685             break;
   1686         }
   1687 
   1688         if (foundParent)
   1689             break;
   1690 
   1691         containerParent = containerParent->parentObject();
   1692     }
   1693 
   1694     // Post that the row count changed.
   1695     if (containerParent)
   1696         axObjectCache()->postNotification(containerParent, document(), AXObjectCache::AXRowCountChanged, true);
   1697 
   1698     // Post that the specific row either collapsed or expanded.
   1699     if (roleValue() == RowRole || roleValue() == TreeItemRole)
   1700         axObjectCache()->postNotification(this, document(), isExpanded() ? AXObjectCache::AXRowExpanded : AXObjectCache::AXRowCollapsed, true);
   1701 }
   1702 
   1703 void AXRenderObject::textChanged()
   1704 {
   1705     if (!m_renderer)
   1706         return;
   1707 
   1708     Settings* settings = document()->settings();
   1709     if (settings && settings->inlineTextBoxAccessibilityEnabled() && roleValue() == StaticTextRole)
   1710         childrenChanged();
   1711 
   1712     // Do this last - AXNodeObject::textChanged posts live region announcements,
   1713     // and we should update the inline text boxes first.
   1714     AXNodeObject::textChanged();
   1715 }
   1716 
   1717 //
   1718 // Text metrics. Most of these should be deprecated, needs major cleanup.
   1719 //
   1720 
   1721 // NOTE: Consider providing this utility method as AX API
   1722 int AXRenderObject::index(const VisiblePosition& position) const
   1723 {
   1724     if (position.isNull() || !isTextControl())
   1725         return -1;
   1726 
   1727     if (renderObjectContainsPosition(m_renderer, position.deepEquivalent()))
   1728         return indexForVisiblePosition(position);
   1729 
   1730     return -1;
   1731 }
   1732 
   1733 VisiblePosition AXRenderObject::visiblePositionForIndex(int index) const
   1734 {
   1735     if (!m_renderer)
   1736         return VisiblePosition();
   1737 
   1738     if (isNativeTextControl() && m_renderer->isTextControl())
   1739         return toRenderTextControl(m_renderer)->textFormControlElement()->visiblePositionForIndex(index);
   1740 
   1741     if (!allowsTextRanges() && !m_renderer->isText())
   1742         return VisiblePosition();
   1743 
   1744     Node* node = m_renderer->node();
   1745     if (!node)
   1746         return VisiblePosition();
   1747 
   1748     if (index <= 0)
   1749         return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
   1750 
   1751     Position start, end;
   1752     bool selected = Range::selectNodeContents(node, start, end);
   1753     if (!selected)
   1754         return VisiblePosition();
   1755 
   1756     CharacterIterator it(start, end);
   1757     it.advance(index - 1);
   1758     return VisiblePosition(Position(it.endContainer(), it.endOffset(), Position::PositionIsOffsetInAnchor), UPSTREAM);
   1759 }
   1760 
   1761 int AXRenderObject::indexForVisiblePosition(const VisiblePosition& pos) const
   1762 {
   1763     if (isNativeTextControl() && m_renderer->isTextControl()) {
   1764         HTMLTextFormControlElement* textControl = toRenderTextControl(m_renderer)->textFormControlElement();
   1765         return textControl->indexForVisiblePosition(pos);
   1766     }
   1767 
   1768     if (!isTextControl())
   1769         return 0;
   1770 
   1771     Node* node = m_renderer->node();
   1772     if (!node)
   1773         return 0;
   1774 
   1775     Position indexPosition = pos.deepEquivalent();
   1776     if (indexPosition.isNull() || highestEditableRoot(indexPosition, HasEditableAXRole) != node)
   1777         return 0;
   1778 
   1779     RefPtrWillBeRawPtr<Range> range = Range::create(m_renderer->document());
   1780     range->setStart(node, 0, IGNORE_EXCEPTION);
   1781     range->setEnd(indexPosition, IGNORE_EXCEPTION);
   1782 
   1783     return TextIterator::rangeLength(range.get());
   1784 }
   1785 
   1786 void AXRenderObject::addInlineTextBoxChildren()
   1787 {
   1788     Settings* settings = document()->settings();
   1789     if (!settings || !settings->inlineTextBoxAccessibilityEnabled())
   1790         return;
   1791 
   1792     if (!renderer() || !renderer()->isText())
   1793         return;
   1794 
   1795     if (renderer()->needsLayout()) {
   1796         // If a RenderText needs layout, its inline text boxes are either
   1797         // nonexistent or invalid, so defer until the layout happens and
   1798         // the renderer calls AXObjectCache::inlineTextBoxesUpdated.
   1799         return;
   1800     }
   1801 
   1802     RenderText* renderText = toRenderText(renderer());
   1803     for (RefPtr<AbstractInlineTextBox> box = renderText->firstAbstractInlineTextBox(); box.get(); box = box->nextInlineTextBox()) {
   1804         AXObject* axObject = axObjectCache()->getOrCreate(box.get());
   1805         if (!axObject->accessibilityIsIgnored())
   1806             m_children.append(axObject);
   1807     }
   1808 }
   1809 
   1810 void AXRenderObject::lineBreaks(Vector<int>& lineBreaks) const
   1811 {
   1812     if (!isTextControl())
   1813         return;
   1814 
   1815     VisiblePosition visiblePos = visiblePositionForIndex(0);
   1816     VisiblePosition savedVisiblePos = visiblePos;
   1817     visiblePos = nextLinePosition(visiblePos, 0);
   1818     while (!visiblePos.isNull() && visiblePos != savedVisiblePos) {
   1819         lineBreaks.append(indexForVisiblePosition(visiblePos));
   1820         savedVisiblePos = visiblePos;
   1821         visiblePos = nextLinePosition(visiblePos, 0);
   1822     }
   1823 }
   1824 
   1825 //
   1826 // Private.
   1827 //
   1828 
   1829 bool AXRenderObject::isAllowedChildOfTree() const
   1830 {
   1831     // Determine if this is in a tree. If so, we apply special behavior to make it work like an AXOutline.
   1832     AXObject* axObj = parentObject();
   1833     bool isInTree = false;
   1834     while (axObj) {
   1835         if (axObj->isTree()) {
   1836             isInTree = true;
   1837             break;
   1838         }
   1839         axObj = axObj->parentObject();
   1840     }
   1841 
   1842     // If the object is in a tree, only tree items should be exposed (and the children of tree items).
   1843     if (isInTree) {
   1844         AccessibilityRole role = roleValue();
   1845         if (role != TreeItemRole && role != StaticTextRole)
   1846             return false;
   1847     }
   1848     return true;
   1849 }
   1850 
   1851 void AXRenderObject::ariaListboxSelectedChildren(AccessibilityChildrenVector& result)
   1852 {
   1853     bool isMulti = isMultiSelectable();
   1854 
   1855     AccessibilityChildrenVector childObjects = children();
   1856     unsigned childrenSize = childObjects.size();
   1857     for (unsigned k = 0; k < childrenSize; ++k) {
   1858         // Every child should have aria-role option, and if so, check for selected attribute/state.
   1859         AXObject* child = childObjects[k].get();
   1860         if (child->isSelected() && child->ariaRoleAttribute() == ListBoxOptionRole) {
   1861             result.append(child);
   1862             if (!isMulti)
   1863                 return;
   1864         }
   1865     }
   1866 }
   1867 
   1868 AXObject::PlainTextRange AXRenderObject::ariaSelectedTextRange() const
   1869 {
   1870     Node* node = m_renderer->node();
   1871     if (!node)
   1872         return PlainTextRange();
   1873 
   1874     VisibleSelection visibleSelection = selection();
   1875     RefPtrWillBeRawPtr<Range> currentSelectionRange = visibleSelection.toNormalizedRange();
   1876     if (!currentSelectionRange || !currentSelectionRange->intersectsNode(node, IGNORE_EXCEPTION))
   1877         return PlainTextRange();
   1878 
   1879     int start = indexForVisiblePosition(visibleSelection.visibleStart());
   1880     int end = indexForVisiblePosition(visibleSelection.visibleEnd());
   1881 
   1882     return PlainTextRange(start, end - start);
   1883 }
   1884 
   1885 bool AXRenderObject::nodeIsTextControl(const Node* node) const
   1886 {
   1887     if (!node)
   1888         return false;
   1889 
   1890     const AXObject* axObjectForNode = axObjectCache()->getOrCreate(const_cast<Node*>(node));
   1891     if (!axObjectForNode)
   1892         return false;
   1893 
   1894     return axObjectForNode->isTextControl();
   1895 }
   1896 
   1897 bool AXRenderObject::isTabItemSelected() const
   1898 {
   1899     if (!isTabItem() || !m_renderer)
   1900         return false;
   1901 
   1902     Node* node = m_renderer->node();
   1903     if (!node || !node->isElementNode())
   1904         return false;
   1905 
   1906     // The ARIA spec says a tab item can also be selected if it is aria-labeled by a tabpanel
   1907     // that has keyboard focus inside of it, or if a tabpanel in its aria-controls list has KB
   1908     // focus inside of it.
   1909     AXObject* focusedElement = focusedUIElement();
   1910     if (!focusedElement)
   1911         return false;
   1912 
   1913     WillBeHeapVector<RawPtrWillBeMember<Element> > elements;
   1914     elementsFromAttribute(elements, aria_controlsAttr);
   1915 
   1916     unsigned count = elements.size();
   1917     for (unsigned k = 0; k < count; ++k) {
   1918         Element* element = elements[k];
   1919         AXObject* tabPanel = axObjectCache()->getOrCreate(element);
   1920 
   1921         // A tab item should only control tab panels.
   1922         if (!tabPanel || tabPanel->roleValue() != TabPanelRole)
   1923             continue;
   1924 
   1925         AXObject* checkFocusElement = focusedElement;
   1926         // Check if the focused element is a descendant of the element controlled by the tab item.
   1927         while (checkFocusElement) {
   1928             if (tabPanel == checkFocusElement)
   1929                 return true;
   1930             checkFocusElement = checkFocusElement->parentObject();
   1931         }
   1932     }
   1933 
   1934     return false;
   1935 }
   1936 
   1937 AXObject* AXRenderObject::accessibilityImageMapHitTest(HTMLAreaElement* area, const IntPoint& point) const
   1938 {
   1939     if (!area)
   1940         return 0;
   1941 
   1942     AXObject* parent = axObjectCache()->getOrCreate(area->imageElement());
   1943     if (!parent)
   1944         return 0;
   1945 
   1946     AXObject::AccessibilityChildrenVector children = parent->children();
   1947     unsigned count = children.size();
   1948     for (unsigned k = 0; k < count; ++k) {
   1949         if (children[k]->elementRect().contains(point))
   1950             return children[k].get();
   1951     }
   1952 
   1953     return 0;
   1954 }
   1955 
   1956 bool AXRenderObject::renderObjectIsObservable(RenderObject* renderer) const
   1957 {
   1958     // AX clients will listen for AXValueChange on a text control.
   1959     if (renderer->isTextControl())
   1960         return true;
   1961 
   1962     // AX clients will listen for AXSelectedChildrenChanged on listboxes.
   1963     Node* node = renderer->node();
   1964     if (nodeHasRole(node, "listbox") || (renderer->isBoxModelObject() && toRenderBoxModelObject(renderer)->isListBox()))
   1965         return true;
   1966 
   1967     // Textboxes should send out notifications.
   1968     if (nodeHasRole(node, "textbox"))
   1969         return true;
   1970 
   1971     return false;
   1972 }
   1973 
   1974 RenderObject* AXRenderObject::renderParentObject() const
   1975 {
   1976     if (!m_renderer)
   1977         return 0;
   1978 
   1979     RenderObject* startOfConts = m_renderer->isRenderBlock() ? startOfContinuations(m_renderer) : 0;
   1980     if (startOfConts) {
   1981         // Case 1: node is a block and is an inline's continuation. Parent
   1982         // is the start of the continuation chain.
   1983         return startOfConts;
   1984     }
   1985 
   1986     RenderObject* parent = m_renderer->parent();
   1987     startOfConts = parent && parent->isRenderInline() ? startOfContinuations(parent) : 0;
   1988     if (startOfConts) {
   1989         // Case 2: node's parent is an inline which is some node's continuation; parent is
   1990         // the earliest node in the continuation chain.
   1991         return startOfConts;
   1992     }
   1993 
   1994     RenderObject* firstChild = parent ? parent->slowFirstChild() : 0;
   1995     if (firstChild && firstChild->node()) {
   1996         // Case 3: The first sibling is the beginning of a continuation chain. Find the origin of that continuation.
   1997         // Get the node's renderer and follow that continuation chain until the first child is found.
   1998         for (RenderObject* nodeRenderFirstChild = firstChild->node()->renderer(); nodeRenderFirstChild != firstChild; nodeRenderFirstChild = firstChild->node()->renderer()) {
   1999             for (RenderObject* contsTest = nodeRenderFirstChild; contsTest; contsTest = nextContinuation(contsTest)) {
   2000                 if (contsTest == firstChild) {
   2001                     parent = nodeRenderFirstChild->parent();
   2002                     break;
   2003                 }
   2004             }
   2005             RenderObject* newFirstChild = parent->slowFirstChild();
   2006             if (firstChild == newFirstChild)
   2007                 break;
   2008             firstChild = newFirstChild;
   2009             if (!firstChild->node())
   2010                 break;
   2011         }
   2012     }
   2013 
   2014     return parent;
   2015 }
   2016 
   2017 bool AXRenderObject::isDescendantOfElementType(const HTMLQualifiedName& tagName) const
   2018 {
   2019     for (RenderObject* parent = m_renderer->parent(); parent; parent = parent->parent()) {
   2020         if (parent->node() && parent->node()->hasTagName(tagName))
   2021             return true;
   2022     }
   2023     return false;
   2024 }
   2025 
   2026 bool AXRenderObject::isSVGImage() const
   2027 {
   2028     return remoteSVGRootElement();
   2029 }
   2030 
   2031 void AXRenderObject::detachRemoteSVGRoot()
   2032 {
   2033     if (AXSVGRoot* root = remoteSVGRootElement())
   2034         root->setParent(0);
   2035 }
   2036 
   2037 AXSVGRoot* AXRenderObject::remoteSVGRootElement() const
   2038 {
   2039     if (!m_renderer || !m_renderer->isRenderImage())
   2040         return 0;
   2041 
   2042     ImageResource* cachedImage = toRenderImage(m_renderer)->cachedImage();
   2043     if (!cachedImage)
   2044         return 0;
   2045 
   2046     Image* image = cachedImage->image();
   2047     if (!image || !image->isSVGImage())
   2048         return 0;
   2049 
   2050     FrameView* frameView = toSVGImage(image)->frameView();
   2051     if (!frameView)
   2052         return 0;
   2053     Document* doc = frameView->frame().document();
   2054     if (!doc || !doc->isSVGDocument())
   2055         return 0;
   2056 
   2057     Settings* settings = doc->settings();
   2058     if (settings && !settings->accessibilityEnabled())
   2059         settings->setAccessibilityEnabled(true);
   2060 
   2061     SVGSVGElement* rootElement = doc->accessSVGExtensions().rootElement();
   2062     if (!rootElement)
   2063         return 0;
   2064     RenderObject* rendererRoot = rootElement->renderer();
   2065     if (!rendererRoot)
   2066         return 0;
   2067 
   2068     AXObject* rootSVGObject = doc->axObjectCache()->getOrCreate(rendererRoot);
   2069 
   2070     // In order to connect the AX hierarchy from the SVG root element from the loaded resource
   2071     // the parent must be set, because there's no other way to get back to who created the image.
   2072     ASSERT(rootSVGObject && rootSVGObject->isAXSVGRoot());
   2073     if (!rootSVGObject->isAXSVGRoot())
   2074         return 0;
   2075 
   2076     return toAXSVGRoot(rootSVGObject);
   2077 }
   2078 
   2079 AXObject* AXRenderObject::remoteSVGElementHitTest(const IntPoint& point) const
   2080 {
   2081     AXObject* remote = remoteSVGRootElement();
   2082     if (!remote)
   2083         return 0;
   2084 
   2085     IntSize offset = point - roundedIntPoint(elementRect().location());
   2086     return remote->accessibilityHitTest(IntPoint(offset));
   2087 }
   2088 
   2089 // The boundingBox for elements within the remote SVG element needs to be offset by its position
   2090 // within the parent page, otherwise they are in relative coordinates only.
   2091 void AXRenderObject::offsetBoundingBoxForRemoteSVGElement(LayoutRect& rect) const
   2092 {
   2093     for (AXObject* parent = parentObject(); parent; parent = parent->parentObject()) {
   2094         if (parent->isAXSVGRoot()) {
   2095             rect.moveBy(parent->parentObject()->elementRect().location());
   2096             break;
   2097         }
   2098     }
   2099 }
   2100 
   2101 // Hidden children are those that are not rendered or visible, but are specifically marked as aria-hidden=false,
   2102 // meaning that they should be exposed to the AX hierarchy.
   2103 void AXRenderObject::addHiddenChildren()
   2104 {
   2105     Node* node = this->node();
   2106     if (!node)
   2107         return;
   2108 
   2109     // First do a quick run through to determine if we have any hidden nodes (most often we will not).
   2110     // If we do have hidden nodes, we need to determine where to insert them so they match DOM order as close as possible.
   2111     bool shouldInsertHiddenNodes = false;
   2112     for (Node* child = node->firstChild(); child; child = child->nextSibling()) {
   2113         if (!child->renderer() && isNodeAriaVisible(child)) {
   2114             shouldInsertHiddenNodes = true;
   2115             break;
   2116         }
   2117     }
   2118 
   2119     if (!shouldInsertHiddenNodes)
   2120         return;
   2121 
   2122     // Iterate through all of the children, including those that may have already been added, and
   2123     // try to insert hidden nodes in the correct place in the DOM order.
   2124     unsigned insertionIndex = 0;
   2125     for (Node* child = node->firstChild(); child; child = child->nextSibling()) {
   2126         if (child->renderer()) {
   2127             // Find out where the last render sibling is located within m_children.
   2128             AXObject* childObject = axObjectCache()->get(child->renderer());
   2129             if (childObject && childObject->accessibilityIsIgnored()) {
   2130                 AccessibilityChildrenVector children = childObject->children();
   2131                 if (children.size())
   2132                     childObject = children.last().get();
   2133                 else
   2134                     childObject = 0;
   2135             }
   2136 
   2137             if (childObject)
   2138                 insertionIndex = m_children.find(childObject) + 1;
   2139             continue;
   2140         }
   2141 
   2142         if (!isNodeAriaVisible(child))
   2143             continue;
   2144 
   2145         unsigned previousSize = m_children.size();
   2146         if (insertionIndex > previousSize)
   2147             insertionIndex = previousSize;
   2148 
   2149         insertChild(axObjectCache()->getOrCreate(child), insertionIndex);
   2150         insertionIndex += (m_children.size() - previousSize);
   2151     }
   2152 }
   2153 
   2154 void AXRenderObject::addTextFieldChildren()
   2155 {
   2156     Node* node = this->node();
   2157     if (!isHTMLInputElement(node))
   2158         return;
   2159 
   2160     HTMLInputElement& input = toHTMLInputElement(*node);
   2161     Element* spinButtonElement = input.userAgentShadowRoot()->getElementById(ShadowElementNames::spinButton());
   2162     if (!spinButtonElement || !spinButtonElement->isSpinButtonElement())
   2163         return;
   2164 
   2165     AXSpinButton* axSpinButton = toAXSpinButton(axObjectCache()->getOrCreate(SpinButtonRole));
   2166     axSpinButton->setSpinButtonElement(toSpinButtonElement(spinButtonElement));
   2167     axSpinButton->setParent(this);
   2168     m_children.append(axSpinButton);
   2169 }
   2170 
   2171 void AXRenderObject::addImageMapChildren()
   2172 {
   2173     RenderBoxModelObject* cssBox = renderBoxModelObject();
   2174     if (!cssBox || !cssBox->isRenderImage())
   2175         return;
   2176 
   2177     HTMLMapElement* map = toRenderImage(cssBox)->imageMap();
   2178     if (!map)
   2179         return;
   2180 
   2181     for (HTMLAreaElement* area = Traversal<HTMLAreaElement>::firstWithin(*map); area; area = Traversal<HTMLAreaElement>::next(*area, map)) {
   2182         // add an <area> element for this child if it has a link
   2183         if (area->isLink()) {
   2184             AXImageMapLink* areaObject = toAXImageMapLink(axObjectCache()->getOrCreate(ImageMapLinkRole));
   2185             areaObject->setHTMLAreaElement(area);
   2186             areaObject->setHTMLMapElement(map);
   2187             areaObject->setParent(this);
   2188             if (!areaObject->accessibilityIsIgnored())
   2189                 m_children.append(areaObject);
   2190             else
   2191                 axObjectCache()->remove(areaObject->axObjectID());
   2192         }
   2193     }
   2194 }
   2195 
   2196 void AXRenderObject::addCanvasChildren()
   2197 {
   2198     if (!isHTMLCanvasElement(node()))
   2199         return;
   2200 
   2201     // If it's a canvas, it won't have rendered children, but it might have accessible fallback content.
   2202     // Clear m_haveChildren because AXNodeObject::addChildren will expect it to be false.
   2203     ASSERT(!m_children.size());
   2204     m_haveChildren = false;
   2205     AXNodeObject::addChildren();
   2206 }
   2207 
   2208 void AXRenderObject::addAttachmentChildren()
   2209 {
   2210     if (!isAttachment())
   2211         return;
   2212 
   2213     // FrameView's need to be inserted into the AX hierarchy when encountered.
   2214     Widget* widget = widgetForAttachmentView();
   2215     if (!widget || !widget->isFrameView())
   2216         return;
   2217 
   2218     AXObject* axWidget = axObjectCache()->getOrCreate(widget);
   2219     if (!axWidget->accessibilityIsIgnored())
   2220         m_children.append(axWidget);
   2221 }
   2222 
   2223 void AXRenderObject::addPopupChildren()
   2224 {
   2225     if (!isHTMLInputElement(node()))
   2226         return;
   2227     if (AXObject* axPopup = toHTMLInputElement(node())->popupRootAXObject())
   2228         m_children.append(axPopup);
   2229 }
   2230 
   2231 void AXRenderObject::addRemoteSVGChildren()
   2232 {
   2233     AXSVGRoot* root = remoteSVGRootElement();
   2234     if (!root)
   2235         return;
   2236 
   2237     root->setParent(this);
   2238 
   2239     if (root->accessibilityIsIgnored()) {
   2240         AccessibilityChildrenVector children = root->children();
   2241         unsigned length = children.size();
   2242         for (unsigned i = 0; i < length; ++i)
   2243             m_children.append(children[i]);
   2244     } else {
   2245         m_children.append(root);
   2246     }
   2247 }
   2248 
   2249 void AXRenderObject::ariaSelectedRows(AccessibilityChildrenVector& result)
   2250 {
   2251     // Get all the rows.
   2252     AccessibilityChildrenVector allRows;
   2253     if (isTree())
   2254         ariaTreeRows(allRows);
   2255     else if (isAXTable() && toAXTable(this)->supportsSelectedRows())
   2256         allRows = toAXTable(this)->rows();
   2257 
   2258     // Determine which rows are selected.
   2259     bool isMulti = isMultiSelectable();
   2260 
   2261     // Prefer active descendant over aria-selected.
   2262     AXObject* activeDesc = activeDescendant();
   2263     if (activeDesc && (activeDesc->isTreeItem() || activeDesc->isTableRow())) {
   2264         result.append(activeDesc);
   2265         if (!isMulti)
   2266             return;
   2267     }
   2268 
   2269     unsigned count = allRows.size();
   2270     for (unsigned k = 0; k < count; ++k) {
   2271         if (allRows[k]->isSelected()) {
   2272             result.append(allRows[k]);
   2273             if (!isMulti)
   2274                 break;
   2275         }
   2276     }
   2277 }
   2278 
   2279 bool AXRenderObject::elementAttributeValue(const QualifiedName& attributeName) const
   2280 {
   2281     if (!m_renderer)
   2282         return false;
   2283 
   2284     return equalIgnoringCase(getAttribute(attributeName), "true");
   2285 }
   2286 
   2287 bool AXRenderObject::inheritsPresentationalRole() const
   2288 {
   2289     // ARIA states if an item can get focus, it should not be presentational.
   2290     if (canSetFocusAttribute())
   2291         return false;
   2292 
   2293     // ARIA spec says that when a parent object is presentational, and it has required child elements,
   2294     // those child elements are also presentational. For example, <li> becomes presentational from <ul>.
   2295     // http://www.w3.org/WAI/PF/aria/complete#presentation
   2296     if (roleValue() != ListItemRole && roleValue() != ListMarkerRole)
   2297         return false;
   2298 
   2299     AXObject* parent = parentObject();
   2300     if (!parent->isAXRenderObject())
   2301         return false;
   2302 
   2303     Node* elementNode = toAXRenderObject(parent)->node();
   2304     if (!elementNode || !elementNode->isElementNode())
   2305         return false;
   2306 
   2307     QualifiedName tagName = toElement(elementNode)->tagQName();
   2308     if (tagName == ulTag || tagName == olTag || tagName == dlTag)
   2309         return (parent->roleValue() == NoneRole || parent->roleValue() == PresentationalRole);
   2310 
   2311     return false;
   2312 }
   2313 
   2314 LayoutRect AXRenderObject::computeElementRect() const
   2315 {
   2316     RenderObject* obj = m_renderer;
   2317 
   2318     if (!obj)
   2319         return LayoutRect();
   2320 
   2321     if (obj->node()) // If we are a continuation, we want to make sure to use the primary renderer.
   2322         obj = obj->node()->renderer();
   2323 
   2324     // absoluteFocusRingBoundingBox will query the hierarchy below this element, which for large webpages can be very slow.
   2325     // For a web area, which will have the most elements of any element, absoluteQuads should be used.
   2326     // We should also use absoluteQuads for SVG elements, otherwise transforms won't be applied.
   2327 
   2328     LayoutRect result;
   2329     if (obj->isText()) {
   2330         Vector<FloatQuad> quads;
   2331         toRenderText(obj)->absoluteQuads(quads, 0, RenderText::ClipToEllipsis);
   2332         result = boundingBoxForQuads(obj, quads);
   2333     } else if (isWebArea() || obj->isSVGRoot()) {
   2334         result = obj->absoluteBoundingBoxRect();
   2335     } else {
   2336         result = obj->absoluteFocusRingBoundingBoxRect();
   2337     }
   2338 
   2339     Document* document = this->document();
   2340     if (document && document->isSVGDocument())
   2341         offsetBoundingBoxForRemoteSVGElement(result);
   2342     if (document && document->frame() && document->frame()->pagePopupOwner()) {
   2343         IntPoint popupOrigin = document->view()->contentsToScreen(IntRect()).location();
   2344         IntPoint mainOrigin = axObjectCache()->rootObject()->documentFrameView()->contentsToScreen(IntRect()).location();
   2345         result.moveBy(IntPoint(popupOrigin - mainOrigin));
   2346     }
   2347 
   2348     // The size of the web area should be the content size, not the clipped size.
   2349     if (isWebArea() && obj->frame()->view())
   2350         result.setSize(obj->frame()->view()->contentsSize());
   2351 
   2352     // Checkboxes and radio buttons include their label as part of their rect.
   2353     if (isCheckboxOrRadio()) {
   2354         HTMLLabelElement* label = labelForElement(toElement(m_renderer->node()));
   2355         if (label && label->renderer()) {
   2356             LayoutRect labelRect = axObjectCache()->getOrCreate(label)->elementRect();
   2357             result.unite(labelRect);
   2358         }
   2359     }
   2360 
   2361     return result;
   2362 }
   2363 
   2364 } // namespace blink
   2365