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
76using blink::WebLocalizedString;
77
78namespace blink {
79
80using namespace HTMLNames;
81
82static 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
97static 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
109static 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
119static 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
132static 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
153static inline bool lastChildHasContinuation(RenderObject* renderer)
154{
155    RenderObject* lastChild = renderer->slowLastChild();
156    return lastChild && isInlineWithContinuation(lastChild);
157}
158
159static 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
169AXRenderObject::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
179PassRefPtr<AXRenderObject> AXRenderObject::create(RenderObject* renderer)
180{
181    return adoptRef(new AXRenderObject(renderer));
182}
183
184AXRenderObject::~AXRenderObject()
185{
186    ASSERT(isDetached());
187}
188
189LayoutRect 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
210void AXRenderObject::setRenderer(RenderObject* renderer)
211{
212    m_renderer = renderer;
213    setNode(renderer->node());
214}
215
216RenderBoxModelObject* AXRenderObject::renderBoxModelObject() const
217{
218    if (!m_renderer || !m_renderer->isBoxModelObject())
219        return 0;
220    return toRenderBoxModelObject(m_renderer);
221}
222
223Document* AXRenderObject::topDocument() const
224{
225    if (!document())
226        return 0;
227    return &document()->topDocument();
228}
229
230bool 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
240ScrollableArea* 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
256AccessibilityRole 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
425void AXRenderObject::init()
426{
427    AXNodeObject::init();
428}
429
430void 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
447bool 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
458bool AXRenderObject::isFileUploadButton() const
459{
460    return m_renderer && isHTMLInputElement(m_renderer->node()) && toHTMLInputElement(*m_renderer->node()).type() == InputTypeNames::file;
461}
462
463static 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
473bool 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
485bool AXRenderObject::isLoaded() const
486{
487    return !m_renderer->document().parser();
488}
489
490bool 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
500bool 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
516bool 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
526bool 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
545bool 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
568AXObjectInclusion 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
586bool 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
785const 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
795AccessibilityOrientation 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
806String AXRenderObject::text() const
807{
808    if (isPasswordField())
809        return String();
810
811    return AXNodeObject::text();
812}
813
814int 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
825KURL 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
848static String queryString(WebLocalizedString::Name name)
849{
850    return Locale::defaultLocale().queryString(name);
851}
852
853String 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
873String 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
935AXObject* 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
964void 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
979void AXRenderObject::ariaFlowToElements(AccessibilityChildrenVector& flowTo) const
980{
981    accessibilityChildrenFromAttribute(aria_flowtoAttr, flowTo);
982}
983
984void AXRenderObject::ariaControlsElements(AccessibilityChildrenVector& controls) const
985{
986    accessibilityChildrenFromAttribute(aria_controlsAttr, controls);
987}
988
989void AXRenderObject::ariaDescribedbyElements(AccessibilityChildrenVector& describedby) const
990{
991    accessibilityChildrenFromAttribute(aria_describedbyAttr, describedby);
992}
993
994void AXRenderObject::ariaLabelledbyElements(AccessibilityChildrenVector& labelledby) const
995{
996    accessibilityChildrenFromAttribute(aria_labelledbyAttr, labelledby);
997}
998
999void AXRenderObject::ariaOwnsElements(AccessibilityChildrenVector& owns) const
1000{
1001    accessibilityChildrenFromAttribute(aria_ownsAttr, owns);
1002}
1003
1004bool AXRenderObject::ariaHasPopup() const
1005{
1006    return elementAttributeValue(aria_haspopupAttr);
1007}
1008
1009bool 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
1024bool 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
1034bool 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
1058bool AXRenderObject::supportsARIADragging() const
1059{
1060    const AtomicString& grabbed = getAttribute(aria_grabbedAttr);
1061    return equalIgnoringCase(grabbed, "true") || equalIgnoringCase(grabbed, "false");
1062}
1063
1064bool AXRenderObject::supportsARIADropping() const
1065{
1066    const AtomicString& dropEffect = getAttribute(aria_dropeffectAttr);
1067    return !dropEffect.isEmpty();
1068}
1069
1070bool AXRenderObject::supportsARIAFlowTo() const
1071{
1072    return !getAttribute(aria_flowtoAttr).isEmpty();
1073}
1074
1075bool 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
1088const 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
1115const 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
1127bool AXRenderObject::ariaLiveRegionAtomic() const
1128{
1129    return elementAttributeValue(aria_atomicAttr);
1130}
1131
1132bool AXRenderObject::ariaLiveRegionBusy() const
1133{
1134    return elementAttributeValue(aria_busyAttr);
1135}
1136
1137//
1138// Accessibility Text.
1139//
1140
1141String 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
1159String 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
1202void 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
1228void 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
1252void 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
1263IntPoint 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
1281AXObject* 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
1328AXObject* 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
1340AXObject* 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
1366AXObject* 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
1379AXObject* 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
1392AXObject* 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
1436void 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
1460bool AXRenderObject::canHaveChildren() const
1461{
1462    if (!m_renderer)
1463        return false;
1464
1465    return AXNodeObject::canHaveChildren();
1466}
1467
1468void AXRenderObject::updateChildrenIfNecessary()
1469{
1470    if (needsToUpdateChildren())
1471        clearChildren();
1472
1473    AXObject::updateChildrenIfNecessary();
1474}
1475
1476void AXRenderObject::clearChildren()
1477{
1478    AXObject::clearChildren();
1479    m_childrenDirty = false;
1480}
1481
1482AXObject* 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
1497double 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
1514Node* AXRenderObject::node() const
1515{
1516    return m_renderer ? m_renderer->node() : 0;
1517}
1518
1519Document* AXRenderObject::document() const
1520{
1521    if (!m_renderer)
1522        return 0;
1523    return &m_renderer->document();
1524}
1525
1526FrameView* 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
1535Element* 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
1567Widget* AXRenderObject::widgetForAttachmentView() const
1568{
1569    if (!isAttachment())
1570        return 0;
1571    return toRenderWidget(m_renderer)->widget();
1572}
1573
1574//
1575// Selected text.
1576//
1577
1578AXObject::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
1598VisibleSelection 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
1607void 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
1624void 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.
1639void 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
1655void 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
1669void 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
1703void 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
1722int 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
1733VisiblePosition 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
1761int 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
1786void 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
1810void 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
1829bool 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
1851void 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
1868AXObject::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
1885bool 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
1897bool 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
1937AXObject* 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
1956bool 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
1974RenderObject* 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
2017bool 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
2026bool AXRenderObject::isSVGImage() const
2027{
2028    return remoteSVGRootElement();
2029}
2030
2031void AXRenderObject::detachRemoteSVGRoot()
2032{
2033    if (AXSVGRoot* root = remoteSVGRootElement())
2034        root->setParent(0);
2035}
2036
2037AXSVGRoot* 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
2079AXObject* 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.
2091void 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.
2103void 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
2154void 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
2171void 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
2196void 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
2208void 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
2223void AXRenderObject::addPopupChildren()
2224{
2225    if (!isHTMLInputElement(node()))
2226        return;
2227    if (AXObject* axPopup = toHTMLInputElement(node())->popupRootAXObject())
2228        m_children.append(axPopup);
2229}
2230
2231void 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
2249void 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
2279bool AXRenderObject::elementAttributeValue(const QualifiedName& attributeName) const
2280{
2281    if (!m_renderer)
2282        return false;
2283
2284    return equalIgnoringCase(getAttribute(attributeName), "true");
2285}
2286
2287bool 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
2314LayoutRect 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