Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / accessibility / AXObject.cpp
index 1b68e94..7594b3b 100644 (file)
 #include "config.h"
 #include "core/accessibility/AXObject.h"
 
-#include "core/accessibility/AXObjectCache.h"
+#include "core/accessibility/AXObjectCacheImpl.h"
 #include "core/dom/NodeTraversal.h"
 #include "core/editing/VisibleUnits.h"
 #include "core/editing/htmlediting.h"
 #include "core/frame/LocalFrame.h"
+#include "core/frame/Settings.h"
 #include "core/rendering/RenderListItem.h"
 #include "core/rendering/RenderTheme.h"
 #include "core/rendering/RenderView.h"
@@ -76,6 +77,7 @@ static ARIARoleMap* createARIARoleMap()
         { "definition", DefinitionRole },
         { "document", DocumentRole },
         { "rowheader", RowHeaderRole },
+        { "form", FormRole },
         { "group", GroupRole },
         { "heading", HeadingRole },
         { "img", ImageRole },
@@ -91,8 +93,8 @@ static ARIARoleMap* createARIARoleMap()
         { "menu", MenuRole },
         { "menubar", MenuBarRole },
         { "menuitem", MenuItemRole },
-        { "menuitemcheckbox", MenuItemRole },
-        { "menuitemradio", MenuItemRole },
+        { "menuitemcheckbox", MenuItemCheckBoxRole },
+        { "menuitemradio", MenuItemRadioRole },
         { "note", NoteRole },
         { "navigation", NavigationRole },
         { "none", NoneRole },
@@ -134,6 +136,10 @@ AXObject::AXObject()
     , m_role(UnknownRole)
     , m_lastKnownIsIgnoredValue(DefaultBehavior)
     , m_detached(false)
+    , m_parent(0)
+    , m_lastModificationCount(-1)
+    , m_cachedIsIgnored(false)
+    , m_cachedLiveRegionRoot(0)
 {
 }
 
@@ -156,11 +162,11 @@ bool AXObject::isDetached() const
     return m_detached;
 }
 
-AXObjectCache* AXObject::axObjectCache() const
+AXObjectCacheImpl* AXObject::axObjectCache() const
 {
     Document* doc = document();
     if (doc)
-        return doc->axObjectCache();
+        return toAXObjectCacheImpl(doc->axObjectCache());
     return 0;
 }
 
@@ -185,6 +191,7 @@ bool AXObject::isLandmarkRelated() const
     case ComplementaryRole:
     case ContentInfoRole:
     case FooterRole:
+    case FormRole:
     case MainRole:
     case NavigationRole:
     case RegionRole:
@@ -202,12 +209,23 @@ bool AXObject::isMenuRelated() const
     case MenuBarRole:
     case MenuButtonRole:
     case MenuItemRole:
+    case MenuItemCheckBoxRole:
+    case MenuItemRadioRole:
         return true;
     default:
         return false;
     }
 }
 
+bool AXObject::isPasswordFieldAndShouldHideValue() const
+{
+    Settings* settings = document()->settings();
+    if (!settings || settings->accessibilityPasswordValuesEnabled())
+        return false;
+
+    return isPasswordField();
+}
+
 bool AXObject::isTextControl() const
 {
     switch (roleValue()) {
@@ -244,39 +262,26 @@ bool AXObject::isClickable() const
     }
 }
 
-bool AXObject::isExpanded() const
+bool AXObject::accessibilityIsIgnored() const
 {
-    if (equalIgnoringCase(getAttribute(aria_expandedAttr), "true"))
-        return true;
-
-    return false;
+    updateCachedAttributeValuesIfNeeded();
+    return m_cachedIsIgnored;
 }
 
-bool AXObject::accessibilityIsIgnored() const
+void AXObject::updateCachedAttributeValuesIfNeeded() const
 {
-    AXObjectCache* cache = axObjectCache();
+    AXObjectCacheImpl* cache = axObjectCache();
     if (!cache)
-        return true;
-
-    AXComputedObjectAttributeCache* attributeCache = cache->computedObjectAttributeCache();
-    if (attributeCache) {
-        AXObjectInclusion ignored = attributeCache->getIgnored(axObjectID());
-        switch (ignored) {
-        case IgnoreObject:
-            return true;
-        case IncludeObject:
-            return false;
-        case DefaultBehavior:
-            break;
-        }
-    }
-
-    bool result = computeAccessibilityIsIgnored();
+        return;
 
-    if (attributeCache)
-        attributeCache->setIgnored(axObjectID(), result ? IgnoreObject : IncludeObject);
+    if (cache->modificationCount() == m_lastModificationCount)
+        return;
 
-    return result;
+    m_lastModificationCount = cache->modificationCount();
+    m_cachedIsIgnored = computeAccessibilityIsIgnored();
+    m_cachedLiveRegionRoot = isLiveRegion() ?
+        this :
+        (parentObjectIfExists() ? parentObjectIfExists()->liveRegionRoot() : 0);
 }
 
 bool AXObject::accessibilityIsIgnoredByDefault() const
@@ -404,7 +409,7 @@ bool AXObject::ariaPressedIsPresent() const
 
 bool AXObject::supportsARIAAttributes() const
 {
-    return supportsARIALiveRegion()
+    return isLiveRegion()
         || supportsARIADragging()
         || supportsARIADropping()
         || supportsARIAFlowTo()
@@ -436,12 +441,42 @@ void AXObject::ariaTreeRows(AccessibilityChildrenVector& result)
     }
 }
 
-bool AXObject::supportsARIALiveRegion() const
+bool AXObject::isLiveRegion() const
 {
-    const AtomicString& liveRegion = ariaLiveRegionStatus();
+    const AtomicString& liveRegion = liveRegionStatus();
     return equalIgnoringCase(liveRegion, "polite") || equalIgnoringCase(liveRegion, "assertive");
 }
 
+const AXObject* AXObject::liveRegionRoot() const
+{
+    updateCachedAttributeValuesIfNeeded();
+    return m_cachedLiveRegionRoot;
+}
+
+const AtomicString& AXObject::containerLiveRegionStatus() const
+{
+    updateCachedAttributeValuesIfNeeded();
+    return m_cachedLiveRegionRoot ? m_cachedLiveRegionRoot->liveRegionStatus() : nullAtom;
+}
+
+const AtomicString& AXObject::containerLiveRegionRelevant() const
+{
+    updateCachedAttributeValuesIfNeeded();
+    return m_cachedLiveRegionRoot ? m_cachedLiveRegionRoot->liveRegionRelevant() : nullAtom;
+}
+
+bool AXObject::containerLiveRegionAtomic() const
+{
+    updateCachedAttributeValuesIfNeeded();
+    return m_cachedLiveRegionRoot ? m_cachedLiveRegionRoot->liveRegionAtomic() : false;
+}
+
+bool AXObject::containerLiveRegionBusy() const
+{
+    updateCachedAttributeValuesIfNeeded();
+    return m_cachedLiveRegionRoot ? m_cachedLiveRegionRoot->liveRegionBusy() : false;
+}
+
 void AXObject::markCachedElementRectDirty() const
 {
     for (unsigned i = 0; i < m_children.size(); ++i)
@@ -503,6 +538,28 @@ const AXObject::AccessibilityChildrenVector& AXObject::children()
     return m_children;
 }
 
+AXObject* AXObject::parentObject() const
+{
+    if (m_detached)
+        return 0;
+
+    if (m_parent)
+        return m_parent;
+
+    return computeParent();
+}
+
+AXObject* AXObject::parentObjectIfExists() const
+{
+    if (m_detached)
+        return 0;
+
+    if (m_parent)
+        return m_parent;
+
+    return computeParentIfExists();
+}
+
 AXObject* AXObject::parentObjectUnignored() const
 {
     AXObject* parent;
@@ -517,7 +574,7 @@ AXObject* AXObject::firstAccessibleObjectFromNode(const Node* node)
     if (!node)
         return 0;
 
-    AXObjectCache* cache = node->document().axObjectCache();
+    AXObjectCacheImpl* cache = toAXObjectCacheImpl(node->document().axObjectCache());
     AXObject* accessibleObject = cache->getOrCreate(node->renderer());
     while (accessibleObject && accessibleObject->accessibilityIsIgnored()) {
         node = NodeTraversal::next(*node);
@@ -542,7 +599,7 @@ void AXObject::updateChildrenIfNecessary()
 
 void AXObject::clearChildren()
 {
-    // Some objects have weak pointers to their parents and those associations need to be detached.
+    // Detach all weak pointers from objects to their parents.
     size_t length = m_children.size();
     for (size_t i = 0; i < length; i++)
         m_children[i]->detachFromParent();
@@ -561,7 +618,7 @@ AXObject* AXObject::focusedUIElement() const
     if (!page)
         return 0;
 
-    return AXObjectCache::focusedUIElementForPage(page);
+    return AXObjectCacheImpl::focusedUIElementForPage(page);
 }
 
 Document* AXObject::document() const
@@ -652,23 +709,47 @@ void AXObject::scrollToMakeVisible() const
 // logic is the same. The goal is to compute the best scroll offset
 // in order to make an object visible within a viewport.
 //
+// If the object is already fully visible, returns the same scroll
+// offset.
+//
 // In case the whole object cannot fit, you can specify a
 // subfocus - a smaller region within the object that should
 // be prioritized. If the whole object can fit, the subfocus is
 // ignored.
 //
-// Example: the viewport is scrolled to the right just enough
-// that the object is in view.
+// If possible, the object and subfocus are centered within the
+// viewport.
+//
+// Example 1: the object is already visible, so nothing happens.
+//   +----------Viewport---------+
+//                 +---Object---+
+//                 +--SubFocus--+
+//
+// Example 2: the object is not fully visible, so it's centered
+// within the viewport.
 //   Before:
 //   +----------Viewport---------+
 //                         +---Object---+
 //                         +--SubFocus--+
 //
 //   After:
-//          +----------Viewport---------+
+//                 +----------Viewport---------+
 //                         +---Object---+
 //                         +--SubFocus--+
 //
+// Example 3: the object is larger than the viewport, so the
+// viewport moves to show as much of the object as possible,
+// while also trying to center the subfocus.
+//   Before:
+//   +----------Viewport---------+
+//     +---------------Object--------------+
+//                         +-SubFocus-+
+//
+//   After:
+//             +----------Viewport---------+
+//     +---------------Object--------------+
+//                         +-SubFocus-+
+//
 // When constraints cannot be fully satisfied, the min
 // (left/top) position takes precedence over the max (right/bottom).
 //
@@ -679,10 +760,17 @@ static int computeBestScrollOffset(int currentScrollOffset, int subfocusMin, int
 {
     int viewportSize = viewportMax - viewportMin;
 
-    // If the focus size is larger than the viewport size, shrink it in the
-    // direction of subfocus.
+    // If the object size is larger than the viewport size, consider
+    // only a portion that's as large as the viewport, centering on
+    // the subfocus as much as possible.
     if (objectMax - objectMin > viewportSize) {
-        // Subfocus must be within focus:
+        // Since it's impossible to fit the whole object in the
+        // viewport, exit now if the subfocus is already within the viewport.
+        if (subfocusMin - currentScrollOffset >= viewportMin
+            && subfocusMax - currentScrollOffset <= viewportMax)
+            return currentScrollOffset;
+
+        // Subfocus must be within focus.
         subfocusMin = std::max(subfocusMin, objectMin);
         subfocusMax = std::min(subfocusMax, objectMax);
 
@@ -690,12 +778,12 @@ static int computeBestScrollOffset(int currentScrollOffset, int subfocusMin, int
         if (subfocusMax - subfocusMin > viewportSize)
             subfocusMax = subfocusMin + viewportSize;
 
-        if (subfocusMin + viewportSize > objectMax) {
-            objectMin = objectMax - viewportSize;
-        } else {
-            objectMin = subfocusMin;
-            objectMax = subfocusMin + viewportSize;
-        }
+        // Compute the size of an object centered on the subfocus, the size of the viewport.
+        int centeredObjectMin = (subfocusMin + subfocusMax - viewportSize) / 2;
+        int centeredObjectMax = centeredObjectMin + viewportSize;
+
+        objectMin = std::max(objectMin, centeredObjectMin);
+        objectMax = std::min(objectMax, centeredObjectMax);
     }
 
     // Exit now if the focus is already within the viewport.
@@ -703,18 +791,8 @@ static int computeBestScrollOffset(int currentScrollOffset, int subfocusMin, int
         && objectMax - currentScrollOffset <= viewportMax)
         return currentScrollOffset;
 
-    // Scroll left if we're too far to the right.
-    if (objectMax - currentScrollOffset > viewportMax)
-        return objectMax - viewportMax;
-
-    // Scroll right if we're too far to the left.
-    if (objectMin - currentScrollOffset < viewportMin)
-        return objectMin - viewportMin;
-
-    ASSERT_NOT_REACHED();
-
-    // This shouldn't happen.
-    return currentScrollOffset;
+    // Center the object in the viewport.
+    return (objectMin + objectMax - viewportMin - viewportMax) / 2;
 }
 
 void AXObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const
@@ -748,9 +826,16 @@ void AXObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const
 
     scrollParent->scrollTo(IntPoint(desiredX, desiredY));
 
+    // Convert the subfocus into the coordinates of the scroll parent.
+    IntRect newSubfocus = subfocus;
+    IntRect newElementRect = pixelSnappedIntRect(elementRect());
+    IntRect scrollParentRect = pixelSnappedIntRect(scrollParent->elementRect());
+    newSubfocus.move(newElementRect.x(), newElementRect.y());
+    newSubfocus.move(-scrollParentRect.x(), -scrollParentRect.y());
+
     // Recursively make sure the scroll parent itself is visible.
     if (scrollParent->parentObject())
-        scrollParent->scrollToMakeVisible();
+        scrollParent->scrollToMakeVisibleWithSubFocus(newSubfocus);
 }
 
 void AXObject::scrollToGlobalPoint(const IntPoint& globalPoint) const