18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
22fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * Copyright (C) 2008, 2009, 2011 Apple Inc. All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1.  Redistributions of source code must retain the above copyright
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     notice, this list of conditions and the following disclaimer.
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2.  Redistributions in binary form must reproduce the above copyright
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     notice, this list of conditions and the following disclaimer in the
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     documentation and/or other materials provided with the distribution.
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     its contributors may be used to endorse or promote products derived
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     from this software without specific prior written permission.
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "AccessibilityObject.h"
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "AXObjectCache.h"
33643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#include "AccessibilityRenderObject.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FloatRect.h"
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FocusController.h"
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Frame.h"
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FrameLoader.h"
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "LocalizedStrings.h"
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "NodeList.h"
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "NotImplemented.h"
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Page.h"
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderImage.h"
43231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "RenderListItem.h"
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderListMarker.h"
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderMenuList.h"
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderTextControl.h"
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderTheme.h"
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderView.h"
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderWidget.h"
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SelectionController.h"
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "TextIterator.h"
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "htmlediting.h"
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "visible_units.h"
54635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <wtf/StdLibExtras.h>
552daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include <wtf/text/StringBuilder.h>
562daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include <wtf/text/StringConcatenate.h>
572fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include <wtf/unicode/CharacterNames.h>
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace std;
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace HTMLNames;
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectAccessibilityObject::AccessibilityObject()
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    : m_id(0)
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_haveChildren(false)
680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    , m_role(UnknownRole)
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#if PLATFORM(GTK)
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_wrapper(0)
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectAccessibilityObject::~AccessibilityObject()
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(isDetached());
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid AccessibilityObject::detach()
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#if HAVE(ACCESSIBILITY)
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    setWrapper(0);
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectAccessibilityObject* AccessibilityObject::parentObjectUnignored() const
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    AccessibilityObject* parent;
90643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject()) {
91643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
92643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return parent;
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
96231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockAccessibilityObject* AccessibilityObject::firstAccessibleObjectFromNode(const Node* node)
97231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
98231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    ASSERT(AXObjectCache::accessibilityEnabled());
99231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
100231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!node)
101231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return 0;
102231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
103231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    Document* document = node->document();
104231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!document)
105231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return 0;
106231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
107231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    AXObjectCache* cache = document->axObjectCache();
108231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
109231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    AccessibilityObject* accessibleObject = cache->getOrCreate(node->renderer());
110231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    while (accessibleObject && accessibleObject->accessibilityIsIgnored()) {
111231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        node = node->traverseNextNode();
112231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
113231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        while (node && !node->renderer())
114231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            node = node->traverseNextSibling();
115231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
116231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (!node)
117231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return 0;
118231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
119231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        accessibleObject = cache->getOrCreate(node->renderer());
120231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
121231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
122231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return accessibleObject;
123231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
124231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool AccessibilityObject::isARIAInput(AccessibilityRole ariaRole)
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return ariaRole == RadioButtonRole || ariaRole == CheckBoxRole || ariaRole == TextFieldRole;
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool AccessibilityObject::isARIAControl(AccessibilityRole ariaRole)
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return isARIAInput(ariaRole) || ariaRole == TextAreaRole || ariaRole == ButtonRole
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    || ariaRole == ComboBoxRole || ariaRole == SliderRole;
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectIntPoint AccessibilityObject::clickPoint() const
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    IntRect rect = elementRect();
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return IntPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2);
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool AccessibilityObject::press() const
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Element* actionElem = actionElement();
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!actionElem)
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (Frame* f = actionElem->document()->frame())
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        f->loader()->resetMultipleFormSubmissionProtection();
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    actionElem->accessKeyAction(true);
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochString AccessibilityObject::language() const
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
155967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    const AtomicString& lang = getAttribute(langAttr);
156967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (!lang.isEmpty())
157967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        return lang;
158967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
1590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    AccessibilityObject* parent = parentObject();
1600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // as a last resort, fall back to the content language specified in the meta tag
1620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!parent) {
1630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Document* doc = document();
1640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (doc)
1650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return doc->contentLanguage();
166967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        return nullAtom;
1670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
1680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return parent->language();
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePositionRange AccessibilityObject::visiblePositionRangeForUnorderedPositions(const VisiblePosition& visiblePos1, const VisiblePosition& visiblePos2) const
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos1.isNull() || visiblePos2.isNull())
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePositionRange();
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition startPos;
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition endPos;
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool alreadyInOrder;
1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // upstream is ordered before downstream for the same position
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos1 == visiblePos2 && visiblePos2.affinity() == UPSTREAM)
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        alreadyInOrder = false;
1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // use selection order to see if the positions are in order
1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
1878f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        alreadyInOrder = VisibleSelection(visiblePos1, visiblePos2).isBaseFirst();
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (alreadyInOrder) {
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startPos = visiblePos1;
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        endPos = visiblePos2;
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startPos = visiblePos2;
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        endPos = visiblePos1;
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePositionRange(startPos, endPos);
1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePositionRange AccessibilityObject::positionOfLeftWord(const VisiblePosition& visiblePos) const
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition startPosition = startOfWord(visiblePos, LeftWordIfOnBoundary);
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition endPosition = endOfWord(startPosition);
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePositionRange(startPosition, endPosition);
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePositionRange AccessibilityObject::positionOfRightWord(const VisiblePosition& visiblePos) const
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition startPosition = startOfWord(visiblePos, RightWordIfOnBoundary);
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition endPosition = endOfWord(startPosition);
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePositionRange(startPosition, endPosition);
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic VisiblePosition updateAXLineStartForVisiblePosition(const VisiblePosition& visiblePosition)
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // A line in the accessibility sense should include floating objects, such as aligned image, as part of a line.
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // So let's update the position to include that.
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition tempPosition;
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition startPosition = visiblePosition;
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position p;
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RenderObject* renderer;
2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (true) {
2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        tempPosition = startPosition.previous();
2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (tempPosition.isNull())
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        p = tempPosition.deepEquivalent();
22781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (!p.deprecatedNode())
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
22981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        renderer = p.deprecatedNode()->renderer();
2305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (!renderer || (renderer->isRenderBlock() && !p.deprecatedEditingOffset()))
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        InlineBox* box;
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int ignoredCaretOffset;
2348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        p.getInlineBoxAndOffset(tempPosition.affinity(), box, ignoredCaretOffset);
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (box)
2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startPosition = tempPosition;
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return startPosition;
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePositionRange AccessibilityObject::leftLineVisiblePositionRange(const VisiblePosition& visiblePos) const
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePositionRange();
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // make a caret selection for the position before marker position (to make sure
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // we move off of a line start)
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition prevVisiblePos = visiblePos.previous();
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (prevVisiblePos.isNull())
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePositionRange();
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition startPosition = startOfLine(prevVisiblePos);
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // keep searching for a valid line start position.  Unless the VisiblePosition is at the very beginning, there should
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // always be a valid line range.  However, startOfLine will return null for position next to a floating object,
2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // since floating object doesn't really belong to any line.
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // This check will reposition the marker before the floating object, to ensure we get a line start.
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (startPosition.isNull()) {
2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            prevVisiblePos = prevVisiblePos.previous();
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            startPosition = startOfLine(prevVisiblePos);
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startPosition = updateAXLineStartForVisiblePosition(startPosition);
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition endPosition = endOfLine(prevVisiblePos);
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePositionRange(startPosition, endPosition);
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePositionRange AccessibilityObject::rightLineVisiblePositionRange(const VisiblePosition& visiblePos) const
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePositionRange();
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // make sure we move off of a line end
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition nextVisiblePos = visiblePos.next();
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (nextVisiblePos.isNull())
2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePositionRange();
2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition startPosition = startOfLine(nextVisiblePos);
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // fetch for a valid line start position
285643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (startPosition.isNull()) {
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startPosition = visiblePos;
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        nextVisiblePos = nextVisiblePos.next();
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else
2898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startPosition = updateAXLineStartForVisiblePosition(startPosition);
2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition endPosition = endOfLine(nextVisiblePos);
2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Unless the VisiblePosition is at the very end, there should always be a valid line range.  However, endOfLine will
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // return null for position by a floating object, since floating object doesn't really belong to any line.
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // This check will reposition the marker after the floating object, to ensure we get a line end.
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        nextVisiblePos = nextVisiblePos.next();
2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        endPosition = endOfLine(nextVisiblePos);
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePositionRange(startPosition, endPosition);
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePositionRange AccessibilityObject::sentenceForPosition(const VisiblePosition& visiblePos) const
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Related? <rdar://problem/3927736> Text selection broken in 8A336
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition startPosition = startOfSentence(visiblePos);
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition endPosition = endOfSentence(startPosition);
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePositionRange(startPosition, endPosition);
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePositionRange AccessibilityObject::paragraphForPosition(const VisiblePosition& visiblePos) const
3158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition startPosition = startOfParagraph(visiblePos);
3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition endPosition = endOfParagraph(startPosition);
3188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePositionRange(startPosition, endPosition);
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic VisiblePosition startOfStyleRange(const VisiblePosition visiblePos)
3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
32381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    RenderObject* renderer = visiblePos.deepEquivalent().deprecatedNode()->renderer();
3248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RenderObject* startRenderer = renderer;
3258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RenderStyle* style = renderer->style();
3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // traverse backward by renderer to look for style change
3288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (RenderObject* r = renderer->previousInPreOrder(); r; r = r->previousInPreOrder()) {
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // skip non-leaf nodes
3308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (r->firstChild())
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            continue;
3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // stop at style change
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (r->style() != style)
3358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // remember match
3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startRenderer = r;
3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
34181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return firstPositionInOrBeforeNode(startRenderer->node());
3428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3448f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qianstatic VisiblePosition endOfStyleRange(const VisiblePosition& visiblePos)
3458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
34681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    RenderObject* renderer = visiblePos.deepEquivalent().deprecatedNode()->renderer();
3478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RenderObject* endRenderer = renderer;
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RenderStyle* style = renderer->style();
3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // traverse forward by renderer to look for style change
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (RenderObject* r = renderer->nextInPreOrder(); r; r = r->nextInPreOrder()) {
3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // skip non-leaf nodes
3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (r->firstChild())
3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            continue;
3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // stop at style change
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (r->style() != style)
3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // remember match
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        endRenderer = r;
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
36481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return lastPositionInOrAfterNode(endRenderer->node());
3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePositionRange AccessibilityObject::styleRangeForPosition(const VisiblePosition& visiblePos) const
3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePositionRange();
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePositionRange(startOfStyleRange(visiblePos), endOfStyleRange(visiblePos));
3738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// NOTE: Consider providing this utility method as AX API
3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePositionRange AccessibilityObject::visiblePositionRangeForRange(const PlainTextRange& range) const
3778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
37868513a70bcd92384395513322f1b801e7bf9c729Steve Block    unsigned textLength = getLengthForTextRange();
379db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    if (range.start + range.length > textLength)
3808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePositionRange();
3818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition startPosition = visiblePositionForIndex(range.start);
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    startPosition.setAffinity(DOWNSTREAM);
3848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition endPosition = visiblePositionForIndex(range.start + range.length);
3858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePositionRange(startPosition, endPosition);
3868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic bool replacedNodeNeedsCharacter(Node* replacedNode)
3898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // we should always be given a rendered node and a replaced node, but be safe
3918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // replaced nodes are either attachments (widgets) or images
392643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode())
3938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // create an AX object, but skip it if it is not supposed to be seen
3968f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    AccessibilityObject* object = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer());
3978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (object->accessibilityIsIgnored())
3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
3998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
403231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// Finds a RenderListItem parent give a node.
404967717af5423377c967781471ee106e2bb4e11c8Ben Murdochstatic RenderListItem* renderListItemContainerForNode(Node* node)
405231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
4066b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    for (; node; node = node->parentNode()) {
407dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch        RenderBoxModelObject* renderer = node->renderBoxModelObject();
408dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch        if (renderer && renderer->isListItem())
409dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch            return toRenderListItem(renderer);
410231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
411231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return 0;
412231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
413231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
414231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// Returns the text associated with a list marker if this node is contained within a list item.
415231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockString AccessibilityObject::listMarkerTextForNodeAndPosition(Node* node, const VisiblePosition& visiblePositionStart) const
416231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
417231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // If the range does not contain the start of the line, the list marker text should not be included.
418231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!isStartOfLine(visiblePositionStart))
419231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return String();
420231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
421231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    RenderListItem* listItem = renderListItemContainerForNode(node);
422231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!listItem)
423231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return String();
424231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
425231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // If this is in a list item, we need to manually add the text for the list marker
426231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // because a RenderListMarker does not have a Node equivalent and thus does not appear
427231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // when iterating text.
428231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    const String& markerText = listItem->markerText();
429231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (markerText.isEmpty())
430231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return String();
431231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
432231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Append text, plus the period that follows the text.
433231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // FIXME: Not all list marker styles are followed by a period, but this
434231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // sounds much better when there is a synthesized pause because of a period.
4352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return makeString(markerText, ". ");
436231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
437231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
4388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
4398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePositionRange.isNull())
4418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return String();
4428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    StringBuilder builder;
4448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
4458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
4468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
447643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if (it.length()) {
448231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // Add a textual representation for list marker text
449231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            String listMarkerText = listMarkerTextForNodeAndPosition(it.node(), visiblePositionRange.start);
450231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            if (!listMarkerText.isEmpty())
4512daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                builder.append(listMarkerText);
4522daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
4532daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            builder.append(it.characters(), it.length());
4548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
4558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // locate the node and starting offset for this replaced range
4568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            int exception = 0;
4578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            Node* node = it.range()->startContainer(exception);
4588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ASSERT(node == it.range()->endContainer(exception));
4598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            int offset = it.range()->startOffset(exception);
4608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
461643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            if (replacedNodeNeedsCharacter(node->childNode(offset)))
4622daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                builder.append(objectReplacementCharacter);
4638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4662daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return builder.toString();
4678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectint AccessibilityObject::lengthForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
4708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: Multi-byte support
4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePositionRange.isNull())
4738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return -1;
4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int length = 0;
4768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
4778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
4788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
479643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if (it.length())
4808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            length += it.length();
481643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        else {
4828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // locate the node and starting offset for this replaced range
4838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            int exception = 0;
4848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            Node* node = it.range()->startContainer(exception);
4858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ASSERT(node == it.range()->endContainer(exception));
4868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            int offset = it.range()->startOffset(exception);
4878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (replacedNodeNeedsCharacter(node->childNode(offset)))
4898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                length++;
4908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return length;
4948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition AccessibilityObject::nextWordEnd(const VisiblePosition& visiblePos) const
4978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
4998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
5008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // make sure we move off of a word end
5028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition nextVisiblePos = visiblePos.next();
5038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (nextVisiblePos.isNull())
5048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
5058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return endOfWord(nextVisiblePos, LeftWordIfOnBoundary);
5078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition AccessibilityObject::previousWordStart(const VisiblePosition& visiblePos) const
5108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
5128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
5138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // make sure we move off of a word start
5158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition prevVisiblePos = visiblePos.previous();
5168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (prevVisiblePos.isNull())
5178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
5188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return startOfWord(prevVisiblePos, RightWordIfOnBoundary);
5208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition AccessibilityObject::nextLineEndPosition(const VisiblePosition& visiblePos) const
5238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
5258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
5268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // to make sure we move off of a line end
5288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition nextVisiblePos = visiblePos.next();
5298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (nextVisiblePos.isNull())
5308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
5318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition endPosition = endOfLine(nextVisiblePos);
5338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // as long as the position hasn't reached the end of the doc,  keep searching for a valid line end position
5358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // There are cases like when the position is next to a floating object that'll return null for end of line. This code will avoid returning null.
5368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
5378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        nextVisiblePos = nextVisiblePos.next();
5388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        endPosition = endOfLine(nextVisiblePos);
5398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return endPosition;
5428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition AccessibilityObject::previousLineStartPosition(const VisiblePosition& visiblePos) const
5458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
5478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
5488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // make sure we move off of a line start
5508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition prevVisiblePos = visiblePos.previous();
5518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (prevVisiblePos.isNull())
5528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
5538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition startPosition = startOfLine(prevVisiblePos);
5558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // as long as the position hasn't reached the beginning of the doc,  keep searching for a valid line start position
5578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // There are cases like when the position is next to a floating object that'll return null for start of line. This code will avoid returning null.
5588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (startPosition.isNull()) {
5598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
5608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            prevVisiblePos = prevVisiblePos.previous();
5618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            startPosition = startOfLine(prevVisiblePos);
5628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
5638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else
5648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startPosition = updateAXLineStartForVisiblePosition(startPosition);
5658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return startPosition;
5678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition AccessibilityObject::nextSentenceEndPosition(const VisiblePosition& visiblePos) const
5708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
5728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Related? <rdar://problem/3927736> Text selection broken in 8A336
5738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
5748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
5758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // make sure we move off of a sentence end
5778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition nextVisiblePos = visiblePos.next();
5788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (nextVisiblePos.isNull())
5798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
5808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // an empty line is considered a sentence. If it's skipped, then the sentence parser will not
5828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // see this empty line.  Instead, return the end position of the empty line.
5838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition endPosition;
584635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
585635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    String lineString = plainText(makeRange(startOfLine(nextVisiblePos), endOfLine(nextVisiblePos)).get());
5868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (lineString.isEmpty())
5878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        endPosition = nextVisiblePos;
5888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
5898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        endPosition = endOfSentence(nextVisiblePos);
5908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return endPosition;
5928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition AccessibilityObject::previousSentenceStartPosition(const VisiblePosition& visiblePos) const
5958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
5978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Related? <rdar://problem/3927736> Text selection broken in 8A336
5988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
5998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
6008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // make sure we move off of a sentence start
6028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition previousVisiblePos = visiblePos.previous();
6038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (previousVisiblePos.isNull())
6048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
6058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // treat empty line as a separate sentence.
6078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition startPosition;
608635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
6098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    String lineString = plainText(makeRange(startOfLine(previousVisiblePos), endOfLine(previousVisiblePos)).get());
6108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (lineString.isEmpty())
6118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startPosition = previousVisiblePos;
6128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
6138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startPosition = startOfSentence(previousVisiblePos);
6148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return startPosition;
6168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition AccessibilityObject::nextParagraphEndPosition(const VisiblePosition& visiblePos) const
6198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
6218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
6228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // make sure we move off of a paragraph end
6248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition nextPos = visiblePos.next();
6258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (nextPos.isNull())
6268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
6278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return endOfParagraph(nextPos);
6298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition AccessibilityObject::previousParagraphStartPosition(const VisiblePosition& visiblePos) const
6328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
6348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
6358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // make sure we move off of a paragraph start
6378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition previousPos = visiblePos.previous();
6388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (previousPos.isNull())
6398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
6408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return startOfParagraph(previousPos);
6428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectAccessibilityObject* AccessibilityObject::accessibilityObjectForPosition(const VisiblePosition& visiblePos) const
6458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
6478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
6488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
64981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    RenderObject* obj = visiblePos.deepEquivalent().deprecatedNode()->renderer();
6508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!obj)
6518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
6528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6538f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    return obj->document()->axObjectCache()->getOrCreate(obj);
6548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectint AccessibilityObject::lineForPosition(const VisiblePosition& visiblePos) const
6578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (visiblePos.isNull())
6598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
6608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned lineCount = 0;
6628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition currentVisiblePos = visiblePos;
6638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition savedVisiblePos;
6648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // move up until we get to the top
6668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: This only takes us to the top of the rootEditableElement, not the top of the
6678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // top document.
6688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (currentVisiblePos.isNotNull() && !(inSameLine(currentVisiblePos, savedVisiblePos))) {
6698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ++lineCount;
6708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        savedVisiblePos = currentVisiblePos;
6718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        VisiblePosition prevVisiblePos = previousLinePosition(currentVisiblePos, 0);
6728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        currentVisiblePos = prevVisiblePos;
6738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return lineCount - 1;
6768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// NOTE: Consider providing this utility method as AX API
6798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectPlainTextRange AccessibilityObject::plainTextRangeForVisiblePositionRange(const VisiblePositionRange& positionRange) const
6808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int index1 = index(positionRange.start);
6828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int index2 = index(positionRange.end);
6838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (index1 < 0 || index2 < 0 || index1 > index2)
6848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return PlainTextRange();
6858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return PlainTextRange(index1, index2 - index1);
6878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// The composed character range in the text associated with this accessibility object that
6908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// is specified by the given screen coordinates. This parameterized attribute returns the
6918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// complete range of characters (including surrogate pairs of multi-byte glyphs) at the given
6928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// screen coordinates.
6938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// NOTE: This varies from AppKit when the point is below the last line. AppKit returns an
6948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// an error in that case. We return textControl->text().length(), 1. Does this matter?
6958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectPlainTextRange AccessibilityObject::doAXRangeForPosition(const IntPoint& point) const
6968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int i = index(visiblePositionForPoint(point));
6988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (i < 0)
6998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return PlainTextRange();
7008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return PlainTextRange(i, 1);
7028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Given a character index, the range of text associated with this accessibility object
7058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// over which the style in effect at that character index applies.
7068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectPlainTextRange AccessibilityObject::doAXStyleRangeForIndex(unsigned index) const
7078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePositionRange range = styleRangeForPosition(visiblePositionForIndex(index, false));
7098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return plainTextRangeForVisiblePositionRange(range);
7108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Given an indexed character, the line number of the text associated with this accessibility
7138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// object that contains the character.
7148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectunsigned AccessibilityObject::doAXLineForIndex(unsigned index)
7158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return lineForPosition(visiblePositionForIndex(index, false));
7178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7192fc2651226baac27029e38c9d6ef883fa32084dbSteve BlockDocument* AccessibilityObject::document() const
7202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
7212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    FrameView* frameView = documentFrameView();
7222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (!frameView)
7232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return 0;
7242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return frameView->frame()->document();
7262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
7278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectFrameView* AccessibilityObject::documentFrameView() const
7298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const AccessibilityObject* object = this;
7318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (object && !object->isAccessibilityRenderObject())
7328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        object = object->parentObject();
7338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!object)
7358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
7368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return object->documentFrameView();
7388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
739cad810f21b803229eb11403f9209855525a25d57Steve Block
740cad810f21b803229eb11403f9209855525a25d57Steve Blockvoid AccessibilityObject::updateChildrenIfNecessary()
741cad810f21b803229eb11403f9209855525a25d57Steve Block{
742cad810f21b803229eb11403f9209855525a25d57Steve Block    if (!hasChildren())
743cad810f21b803229eb11403f9209855525a25d57Steve Block        addChildren();
744cad810f21b803229eb11403f9209855525a25d57Steve Block}
7458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid AccessibilityObject::clearChildren()
7478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_children.clear();
749dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_haveChildren = false;
7508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochAccessibilityObject* AccessibilityObject::anchorElementForNode(Node* node)
7538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    RenderObject* obj = node->renderer();
7550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!obj)
7560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return 0;
7578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    RefPtr<AccessibilityObject> axObj = obj->document()->axObjectCache()->getOrCreate(obj);
7590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Element* anchor = axObj->anchorElement();
7600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!anchor)
7610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return 0;
7620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    RenderObject* anchorRenderer = anchor->renderer();
7640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!anchorRenderer)
7650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return 0;
7660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
7670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return anchorRenderer->document()->axObjectCache()->getOrCreate(anchorRenderer);
7688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
770643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid AccessibilityObject::ariaTreeRows(AccessibilityChildrenVector& result)
771643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
772643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    AccessibilityChildrenVector axChildren = children();
773643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    unsigned count = axChildren.size();
774643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    for (unsigned k = 0; k < count; ++k) {
775643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        AccessibilityObject* obj = axChildren[k].get();
776643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
777643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        // Add tree items as the rows.
778643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if (obj->roleValue() == TreeItemRole)
779643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            result.append(obj);
780643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
781643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        // Now see if this item also has rows hiding inside of it.
782643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        obj->ariaTreeRows(result);
783643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
784643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
785643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
786643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid AccessibilityObject::ariaTreeItemContent(AccessibilityChildrenVector& result)
787643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
788643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // The ARIA tree item content are the item that are not other tree items or their containing groups.
789643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    AccessibilityChildrenVector axChildren = children();
790643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    unsigned count = axChildren.size();
791643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    for (unsigned k = 0; k < count; ++k) {
792643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        AccessibilityObject* obj = axChildren[k].get();
793643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        AccessibilityRole role = obj->roleValue();
794643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if (role == TreeItemRole || role == GroupRole)
795643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            continue;
796643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
797643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        result.append(obj);
798643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
799643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
800643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
801643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid AccessibilityObject::ariaTreeItemDisclosedRows(AccessibilityChildrenVector& result)
802643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
803643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    AccessibilityChildrenVector axChildren = children();
804643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    unsigned count = axChildren.size();
805643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    for (unsigned k = 0; k < count; ++k) {
806643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        AccessibilityObject* obj = axChildren[k].get();
807643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
808643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        // Add tree items as the rows.
809643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if (obj->roleValue() == TreeItemRole)
810643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            result.append(obj);
811643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        // If it's not a tree item, then descend into the group to find more tree items.
812643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        else
813643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            obj->ariaTreeRows(result);
814643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
815643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
816643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
8178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectconst String& AccessibilityObject::actionVerb() const
8188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: Need to add verbs for select elements.
820635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const String, buttonAction, (AXButtonActionVerb()));
821635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const String, textFieldAction, (AXTextFieldActionVerb()));
822635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const String, radioButtonAction, (AXRadioButtonActionVerb()));
823635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const String, checkedCheckBoxAction, (AXCheckedCheckBoxActionVerb()));
824635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const String, uncheckedCheckBoxAction, (AXUncheckedCheckBoxActionVerb()));
825635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const String, linkAction, (AXLinkActionVerb()));
826d0825bca7fe65beaee391d30da42e937db621564Steve Block    DEFINE_STATIC_LOCAL(const String, menuListAction, (AXMenuListActionVerb()));
827d0825bca7fe65beaee391d30da42e937db621564Steve Block    DEFINE_STATIC_LOCAL(const String, menuListPopupAction, (AXMenuListPopupActionVerb()));
828635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(const String, noAction, ());
8298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    switch (roleValue()) {
831643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    case ButtonRole:
832643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return buttonAction;
833643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    case TextFieldRole:
834643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    case TextAreaRole:
835643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return textFieldAction;
836643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    case RadioButtonRole:
837643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return radioButtonAction;
838643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    case CheckBoxRole:
839643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
840643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    case LinkRole:
841643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    case WebCoreLinkRole:
842643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return linkAction;
843d0825bca7fe65beaee391d30da42e937db621564Steve Block    case PopUpButtonRole:
844d0825bca7fe65beaee391d30da42e937db621564Steve Block        return menuListAction;
845d0825bca7fe65beaee391d30da42e937db621564Steve Block    case MenuListPopupRole:
846d0825bca7fe65beaee391d30da42e937db621564Steve Block        return menuListPopupAction;
847643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    default:
848643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return noAction;
8498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
851f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
852f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochbool AccessibilityObject::ariaIsMultiline() const
853f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch{
854f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    return equalIgnoringCase(getAttribute(aria_multilineAttr), "true");
855f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch}
856f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
857f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochconst AtomicString& AccessibilityObject::invalidStatus() const
858f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch{
859f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    DEFINE_STATIC_LOCAL(const AtomicString, invalidStatusFalse, ("false"));
860f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
861f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    // aria-invalid can return false (default), grammer, spelling, or true.
862f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    const AtomicString& ariaInvalid = getAttribute(aria_invalidAttr);
863f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
864f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    // If empty or not present, it should return false.
865f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (ariaInvalid.isEmpty())
866f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        return invalidStatusFalse;
867f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
868f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    return ariaInvalid;
869f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch}
8700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
871967717af5423377c967781471ee106e2bb4e11c8Ben Murdochconst AtomicString& AccessibilityObject::getAttribute(const QualifiedName& attribute) const
872dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
873967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    Node* elementNode = node();
874967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (!elementNode)
875dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return nullAtom;
876dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
877967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (!elementNode->isElementNode())
878dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return nullAtom;
879dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
880967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    Element* element = static_cast<Element*>(elementNode);
881f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    return element->fastGetAttribute(attribute);
882dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
883dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
8840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// Lacking concrete evidence of orientation, horizontal means width > height. vertical is height > width;
8850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochAccessibilityOrientation AccessibilityObject::orientation() const
886635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
8870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    IntRect bounds = elementRect();
8880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (bounds.size().width() > bounds.size().height())
8890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return AccessibilityOrientationHorizontal;
8900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (bounds.size().height() > bounds.size().width())
8910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return AccessibilityOrientationVertical;
8920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
8930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // A tie goes to horizontal.
8940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return AccessibilityOrientationHorizontal;
895643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
896643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
897643ca7872b450ea4efacab6188849e5aac2ba161Steve Blocktypedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap;
898643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
899643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockstruct RoleEntry {
900643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    String ariaRole;
901643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    AccessibilityRole webcoreRole;
902643ca7872b450ea4efacab6188849e5aac2ba161Steve Block};
903643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
904643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockstatic ARIARoleMap* createARIARoleMap()
905643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
906643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    const RoleEntry roles[] = {
907643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "alert", ApplicationAlertRole },
908643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "alertdialog", ApplicationAlertDialogRole },
909643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "application", LandmarkApplicationRole },
910643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "article", DocumentArticleRole },
911643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "banner", LandmarkBannerRole },
912643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "button", ButtonRole },
913643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "checkbox", CheckBoxRole },
914643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "complementary", LandmarkComplementaryRole },
915643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "contentinfo", LandmarkContentInfoRole },
916643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "dialog", ApplicationDialogRole },
917643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "directory", DirectoryRole },
918643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "grid", TableRole },
919643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "gridcell", CellRole },
920643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "columnheader", ColumnHeaderRole },
921643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "combobox", ComboBoxRole },
922643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "definition", DefinitionListDefinitionRole },
923643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "document", DocumentRole },
924643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "rowheader", RowHeaderRole },
925643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "group", GroupRole },
926643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "heading", HeadingRole },
927643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "img", ImageRole },
928643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "link", WebCoreLinkRole },
929643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "list", ListRole },
93006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        { "listitem", ListItemRole },
931643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "listbox", ListBoxRole },
932643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "log", ApplicationLogRole },
933643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        // "option" isn't here because it may map to different roles depending on the parent element's role
934643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "main", LandmarkMainRole },
935643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "marquee", ApplicationMarqueeRole },
936643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "math", DocumentMathRole },
937643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "menu", MenuRole },
938f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        { "menubar", MenuBarRole },
939643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        // "menuitem" isn't here because it may map to different roles depending on the parent element's role
940643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "menuitemcheckbox", MenuItemRole },
941643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "menuitemradio", MenuItemRole },
942643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "note", DocumentNoteRole },
943643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "navigation", LandmarkNavigationRole },
944643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "option", ListBoxOptionRole },
94506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        { "presentation", PresentationalRole },
946643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "progressbar", ProgressIndicatorRole },
947643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "radio", RadioButtonRole },
948643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "radiogroup", RadioGroupRole },
949643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "region", DocumentRegionRole },
950643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "row", RowRole },
951643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "range", SliderRole },
952643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "scrollbar", ScrollBarRole },
953643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "search", LandmarkSearchRole },
954643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "separator", SplitterRole },
955643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "slider", SliderRole },
956643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "spinbutton", ProgressIndicatorRole },
957643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "status", ApplicationStatusRole },
958643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "tab", TabRole },
959643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "tablist", TabListRole },
960643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "tabpanel", TabPanelRole },
961643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "text", StaticTextRole },
962643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "textbox", TextAreaRole },
963643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "timer", ApplicationTimerRole },
964643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "toolbar", ToolbarRole },
965643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "tooltip", UserInterfaceTooltipRole },
966643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "tree", TreeRole },
967d0825bca7fe65beaee391d30da42e937db621564Steve Block        { "treegrid", TreeGridRole },
968643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        { "treeitem", TreeItemRole }
969643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    };
970643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    ARIARoleMap* roleMap = new ARIARoleMap;
9714576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang
9724576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    for (size_t i = 0; i < WTF_ARRAY_LENGTH(roles); ++i)
973643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        roleMap->set(roles[i].ariaRole, roles[i].webcoreRole);
974643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return roleMap;
975643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
976643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
977643ca7872b450ea4efacab6188849e5aac2ba161Steve BlockAccessibilityRole AccessibilityObject::ariaRoleToWebCoreRole(const String& value)
978643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
979643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    ASSERT(!value.isEmpty());
980643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    static const ARIARoleMap* roleMap = createARIARoleMap();
981643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return roleMap->get(value);
982635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
983d0825bca7fe65beaee391d30da42e937db621564Steve Block
984dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdochconst AtomicString& AccessibilityObject::placeholderValue() const
985dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch{
986dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch    const AtomicString& placeholder = getAttribute(placeholderAttr);
987dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch    if (!placeholder.isEmpty())
988dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch        return placeholder;
989dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch
990dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch    return nullAtom;
991dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch}
992dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch
993d0825bca7fe65beaee391d30da42e937db621564Steve Blockbool AccessibilityObject::isInsideARIALiveRegion() const
994d0825bca7fe65beaee391d30da42e937db621564Steve Block{
995d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (supportsARIALiveRegion())
996d0825bca7fe65beaee391d30da42e937db621564Steve Block        return true;
997d0825bca7fe65beaee391d30da42e937db621564Steve Block
998d0825bca7fe65beaee391d30da42e937db621564Steve Block    for (AccessibilityObject* axParent = parentObject(); axParent; axParent = axParent->parentObject()) {
999d0825bca7fe65beaee391d30da42e937db621564Steve Block        if (axParent->supportsARIALiveRegion())
1000d0825bca7fe65beaee391d30da42e937db621564Steve Block            return true;
1001d0825bca7fe65beaee391d30da42e937db621564Steve Block    }
1002d0825bca7fe65beaee391d30da42e937db621564Steve Block
1003d0825bca7fe65beaee391d30da42e937db621564Steve Block    return false;
1004d0825bca7fe65beaee391d30da42e937db621564Steve Block}
1005d0825bca7fe65beaee391d30da42e937db621564Steve Block
1006dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockbool AccessibilityObject::supportsARIAAttributes() const
1007dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
1008dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return supportsARIALiveRegion() || supportsARIADragging() || supportsARIADropping() || supportsARIAFlowTo() || supportsARIAOwns();
1009dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
1010dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
1011d0825bca7fe65beaee391d30da42e937db621564Steve Blockbool AccessibilityObject::supportsARIALiveRegion() const
1012d0825bca7fe65beaee391d30da42e937db621564Steve Block{
1013d0825bca7fe65beaee391d30da42e937db621564Steve Block    const AtomicString& liveRegion = ariaLiveRegionStatus();
1014d0825bca7fe65beaee391d30da42e937db621564Steve Block    return equalIgnoringCase(liveRegion, "polite") || equalIgnoringCase(liveRegion, "assertive");
1015d0825bca7fe65beaee391d30da42e937db621564Steve Block}
1016cad810f21b803229eb11403f9209855525a25d57Steve Block
1017cad810f21b803229eb11403f9209855525a25d57Steve BlockAccessibilityObject* AccessibilityObject::elementAccessibilityHitTest(const IntPoint& point) const
1018cad810f21b803229eb11403f9209855525a25d57Steve Block{
1019cad810f21b803229eb11403f9209855525a25d57Steve Block    // Send the hit test back into the sub-frame if necessary.
1020cad810f21b803229eb11403f9209855525a25d57Steve Block    if (isAttachment()) {
1021cad810f21b803229eb11403f9209855525a25d57Steve Block        Widget* widget = widgetForAttachmentView();
1022ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        // Normalize the point for the widget's bounds.
1023cad810f21b803229eb11403f9209855525a25d57Steve Block        if (widget && widget->isFrameView())
1024ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch            return axObjectCache()->getOrCreate(widget)->accessibilityHitTest(IntPoint(point - widget->frameRect().location()));
1025cad810f21b803229eb11403f9209855525a25d57Steve Block    }
1026cad810f21b803229eb11403f9209855525a25d57Steve Block
1027cad810f21b803229eb11403f9209855525a25d57Steve Block    return const_cast<AccessibilityObject*>(this);
1028cad810f21b803229eb11403f9209855525a25d57Steve Block}
1029cad810f21b803229eb11403f9209855525a25d57Steve Block
1030cad810f21b803229eb11403f9209855525a25d57Steve BlockAXObjectCache* AccessibilityObject::axObjectCache() const
1031cad810f21b803229eb11403f9209855525a25d57Steve Block{
1032cad810f21b803229eb11403f9209855525a25d57Steve Block    Document* doc = document();
1033cad810f21b803229eb11403f9209855525a25d57Steve Block    if (doc)
1034cad810f21b803229eb11403f9209855525a25d57Steve Block        return doc->axObjectCache();
1035cad810f21b803229eb11403f9209855525a25d57Steve Block    return 0;
1036cad810f21b803229eb11403f9209855525a25d57Steve Block}
1037cad810f21b803229eb11403f9209855525a25d57Steve Block
1038cad810f21b803229eb11403f9209855525a25d57Steve BlockAccessibilityObject* AccessibilityObject::focusedUIElement() const
1039cad810f21b803229eb11403f9209855525a25d57Steve Block{
1040cad810f21b803229eb11403f9209855525a25d57Steve Block    Document* doc = document();
1041cad810f21b803229eb11403f9209855525a25d57Steve Block    if (!doc)
1042cad810f21b803229eb11403f9209855525a25d57Steve Block        return 0;
1043cad810f21b803229eb11403f9209855525a25d57Steve Block
1044cad810f21b803229eb11403f9209855525a25d57Steve Block    Page* page = doc->page();
1045cad810f21b803229eb11403f9209855525a25d57Steve Block    if (!page)
1046cad810f21b803229eb11403f9209855525a25d57Steve Block        return 0;
1047cad810f21b803229eb11403f9209855525a25d57Steve Block
1048cad810f21b803229eb11403f9209855525a25d57Steve Block    return AXObjectCache::focusedUIElementForPage(page);
1049cad810f21b803229eb11403f9209855525a25d57Steve Block}
1050cad810f21b803229eb11403f9209855525a25d57Steve Block
10512fc2651226baac27029e38c9d6ef883fa32084dbSteve BlockAccessibilitySortDirection AccessibilityObject::sortDirection() const
10522fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
10532fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    const AtomicString& sortAttribute = getAttribute(aria_sortAttr);
10542fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (equalIgnoringCase(sortAttribute, "ascending"))
10552fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return SortDirectionAscending;
10562fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (equalIgnoringCase(sortAttribute, "descending"))
10572fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return SortDirectionDescending;
10582fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
10592fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return SortDirectionNone;
10602fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
10612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
1062cad810f21b803229eb11403f9209855525a25d57Steve Blockbool AccessibilityObject::supportsARIAExpanded() const
1063cad810f21b803229eb11403f9209855525a25d57Steve Block{
1064cad810f21b803229eb11403f9209855525a25d57Steve Block    return !getAttribute(aria_expandedAttr).isEmpty();
1065cad810f21b803229eb11403f9209855525a25d57Steve Block}
1066cad810f21b803229eb11403f9209855525a25d57Steve Block
1067cad810f21b803229eb11403f9209855525a25d57Steve Blockbool AccessibilityObject::isExpanded() const
1068cad810f21b803229eb11403f9209855525a25d57Steve Block{
1069cad810f21b803229eb11403f9209855525a25d57Steve Block    if (equalIgnoringCase(getAttribute(aria_expandedAttr), "true"))
1070cad810f21b803229eb11403f9209855525a25d57Steve Block        return true;
1071cad810f21b803229eb11403f9209855525a25d57Steve Block
1072cad810f21b803229eb11403f9209855525a25d57Steve Block    return false;
1073cad810f21b803229eb11403f9209855525a25d57Steve Block}
1074967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
10750617145a89917ae7735fe1c9538688ab9a577df5Kristian MonsenAccessibilityButtonState AccessibilityObject::checkboxOrRadioValue() const
1076967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
1077967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    // If this is a real checkbox or radio button, AccessibilityRenderObject will handle.
1078967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    // If it's an ARIA checkbox or radio, the aria-checked attribute should be used.
1079d0825bca7fe65beaee391d30da42e937db621564Steve Block
10800617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    const AtomicString& result = getAttribute(aria_checkedAttr);
10810617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    if (equalIgnoringCase(result, "true"))
10820617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        return ButtonStateOn;
10830617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    if (equalIgnoringCase(result, "mixed"))
10840617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        return ButtonStateMixed;
1085967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
10860617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    return ButtonStateOff;
1087967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
1088635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
10898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} // namespace WebCore
1090