| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2008 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 return m_cachedElementRect; | 218 return m_cachedElementRect; |
| 219 } | 219 } |
| 220 | 220 |
| 221 LayoutBoxModelObject* AXLayoutObject::getLayoutBoxModelObject() const | 221 LayoutBoxModelObject* AXLayoutObject::getLayoutBoxModelObject() const |
| 222 { | 222 { |
| 223 if (!m_layoutObject || !m_layoutObject->isBoxModelObject()) | 223 if (!m_layoutObject || !m_layoutObject->isBoxModelObject()) |
| 224 return 0; | 224 return 0; |
| 225 return toLayoutBoxModelObject(m_layoutObject); | 225 return toLayoutBoxModelObject(m_layoutObject); |
| 226 } | 226 } |
| 227 | 227 |
| 228 bool AXLayoutObject::shouldNotifyActiveDescendant() const | |
| 229 { | |
| 230 // We want to notify that the combo box has changed its active descendant, | |
| 231 // but we do not want to change the focus, because focus should remain with
the combo box. | |
| 232 if (isComboBox()) | |
| 233 return true; | |
| 234 | |
| 235 return shouldFocusActiveDescendant(); | |
| 236 } | |
| 237 | |
| 238 ScrollableArea* AXLayoutObject::getScrollableAreaIfScrollable() const | 228 ScrollableArea* AXLayoutObject::getScrollableAreaIfScrollable() const |
| 239 { | 229 { |
| 240 if (isWebArea()) | 230 if (isWebArea()) |
| 241 return documentFrameView(); | 231 return documentFrameView(); |
| 242 | 232 |
| 243 if (!m_layoutObject || !m_layoutObject->isBox()) | 233 if (!m_layoutObject || !m_layoutObject->isBox()) |
| 244 return 0; | 234 return 0; |
| 245 | 235 |
| 246 LayoutBox* box = toLayoutBox(m_layoutObject); | 236 LayoutBox* box = toLayoutBox(m_layoutObject); |
| 247 if (!box->canBeScrolledAndHasScrollableArea()) | 237 if (!box->canBeScrolledAndHasScrollableArea()) |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 // FIXME: Is it a privacy violation to expose visited information to accessi
bility APIs? | 441 // FIXME: Is it a privacy violation to expose visited information to accessi
bility APIs? |
| 452 return m_layoutObject->style()->isLink() && m_layoutObject->style()->insideL
ink() == InsideVisitedLink; | 442 return m_layoutObject->style()->isLink() && m_layoutObject->style()->insideL
ink() == InsideVisitedLink; |
| 453 } | 443 } |
| 454 | 444 |
| 455 // | 445 // |
| 456 // Check object state. | 446 // Check object state. |
| 457 // | 447 // |
| 458 | 448 |
| 459 bool AXLayoutObject::isFocused() const | 449 bool AXLayoutObject::isFocused() const |
| 460 { | 450 { |
| 461 if (!m_layoutObject) | 451 if (!getDocument()) |
| 462 return false; | 452 return false; |
| 463 | 453 |
| 464 Document& document = m_layoutObject->document(); | 454 Element* focusedElement = getDocument()->focusedElement(); |
| 465 Element* focusedElement = document.focusedElement(); | |
| 466 if (!focusedElement) | 455 if (!focusedElement) |
| 467 return false; | 456 return false; |
| 457 AXObject* focusedObject = axObjectCache().getOrCreate(focusedElement); |
| 458 if (!focusedObject || !focusedObject->isAXLayoutObject()) |
| 459 return false; |
| 468 | 460 |
| 469 // A web area is represented by the Document node in the DOM tree, which isn
't focusable. | 461 // A web area is represented by the Document node in the DOM tree, which isn
't focusable. |
| 470 // Check instead if the frame's selection controller is focused | 462 // Check instead if the frame's selection controller is focused |
| 471 if (focusedElement == m_layoutObject->node() | 463 if (focusedObject == this |
| 472 || (roleValue() == WebAreaRole && document.frame()->selection().isFocuse
dAndActive())) | 464 || (roleValue() == WebAreaRole && getDocument()->frame()->selection().is
FocusedAndActive())) |
| 473 return true; | 465 return true; |
| 474 | 466 |
| 475 return false; | 467 return false; |
| 476 } | 468 } |
| 477 | 469 |
| 478 bool AXLayoutObject::isSelected() const | 470 bool AXLayoutObject::isSelected() const |
| 479 { | 471 { |
| 480 if (!m_layoutObject) | 472 if (!getLayoutObject() || !getNode()) |
| 481 return false; | |
| 482 | |
| 483 Node* node = m_layoutObject->node(); | |
| 484 if (!node) | |
| 485 return false; | 473 return false; |
| 486 | 474 |
| 487 const AtomicString& ariaSelected = getAttribute(aria_selectedAttr); | 475 const AtomicString& ariaSelected = getAttribute(aria_selectedAttr); |
| 488 if (equalIgnoringCase(ariaSelected, "true")) | 476 if (equalIgnoringCase(ariaSelected, "true")) |
| 489 return true; | 477 return true; |
| 490 | 478 |
| 479 AXObject* focusedObject = axObjectCache().focusedObject(); |
| 480 if (ariaRoleAttribute() == ListBoxOptionRole && focusedObject |
| 481 && focusedObject->activeDescendant() == this) { |
| 482 return true; |
| 483 } |
| 484 |
| 491 if (isTabItem() && isTabItemSelected()) | 485 if (isTabItem() && isTabItemSelected()) |
| 492 return true; | 486 return true; |
| 493 | 487 |
| 494 return false; | 488 return false; |
| 495 } | 489 } |
| 496 | 490 |
| 497 // | 491 // |
| 498 // Whether objects are ignored, i.e. not included in the tree. | 492 // Whether objects are ignored, i.e. not included in the tree. |
| 499 // | 493 // |
| 500 | 494 |
| (...skipping 652 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1153 } | 1147 } |
| 1154 } | 1148 } |
| 1155 | 1149 |
| 1156 return AXNodeObject::textAlternative(recursive, inAriaLabelledByTraversal, v
isited, nameFrom, relatedObjects, nameSources); | 1150 return AXNodeObject::textAlternative(recursive, inAriaLabelledByTraversal, v
isited, nameFrom, relatedObjects, nameSources); |
| 1157 } | 1151 } |
| 1158 | 1152 |
| 1159 // | 1153 // |
| 1160 // ARIA attributes. | 1154 // ARIA attributes. |
| 1161 // | 1155 // |
| 1162 | 1156 |
| 1163 AXObject* AXLayoutObject::activeDescendant() const | |
| 1164 { | |
| 1165 if (!m_layoutObject) | |
| 1166 return 0; | |
| 1167 | |
| 1168 if (m_layoutObject->node() && !m_layoutObject->node()->isElementNode()) | |
| 1169 return 0; | |
| 1170 | |
| 1171 Element* element = toElement(m_layoutObject->node()); | |
| 1172 if (!element) | |
| 1173 return 0; | |
| 1174 | |
| 1175 const AtomicString& activeDescendantAttrStr = element->getAttribute(aria_act
ivedescendantAttr); | |
| 1176 if (activeDescendantAttrStr.isNull() || activeDescendantAttrStr.isEmpty()) | |
| 1177 return 0; | |
| 1178 | |
| 1179 Element* target = element->treeScope().getElementById(activeDescendantAttrSt
r); | |
| 1180 if (!target) | |
| 1181 return 0; | |
| 1182 | |
| 1183 AXObject* obj = axObjectCache().getOrCreate(target); | |
| 1184 | |
| 1185 // An activedescendant is only useful if it has a layoutObject, because that
's what's needed to post the notification. | |
| 1186 if (obj && obj->isAXLayoutObject()) | |
| 1187 return obj; | |
| 1188 | |
| 1189 return 0; | |
| 1190 } | |
| 1191 | |
| 1192 void AXLayoutObject::ariaFlowToElements(AXObjectVector& flowTo) const | 1157 void AXLayoutObject::ariaFlowToElements(AXObjectVector& flowTo) const |
| 1193 { | 1158 { |
| 1194 accessibilityChildrenFromAttribute(aria_flowtoAttr, flowTo); | 1159 accessibilityChildrenFromAttribute(aria_flowtoAttr, flowTo); |
| 1195 } | 1160 } |
| 1196 | 1161 |
| 1197 void AXLayoutObject::ariaControlsElements(AXObjectVector& controls) const | 1162 void AXLayoutObject::ariaControlsElements(AXObjectVector& controls) const |
| 1198 { | 1163 { |
| 1199 accessibilityChildrenFromAttribute(aria_controlsAttr, controls); | 1164 accessibilityChildrenFromAttribute(aria_controlsAttr, controls); |
| 1200 } | 1165 } |
| 1201 | 1166 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1247 // AXMenuListOptions, which are not AXLayoutObjects.) | 1212 // AXMenuListOptions, which are not AXLayoutObjects.) |
| 1248 if (parent->isMenuList()) | 1213 if (parent->isMenuList()) |
| 1249 break; | 1214 break; |
| 1250 | 1215 |
| 1251 parent = parent->parentObjectIfExists(); | 1216 parent = parent->parentObjectIfExists(); |
| 1252 } | 1217 } |
| 1253 | 1218 |
| 1254 return parent; | 1219 return parent; |
| 1255 } | 1220 } |
| 1256 | 1221 |
| 1257 bool AXLayoutObject::shouldFocusActiveDescendant() const | |
| 1258 { | |
| 1259 switch (ariaRoleAttribute()) { | |
| 1260 case ComboBoxRole: | |
| 1261 case GridRole: | |
| 1262 case GroupRole: | |
| 1263 case ListBoxRole: | |
| 1264 case MenuRole: | |
| 1265 case MenuBarRole: | |
| 1266 case OutlineRole: | |
| 1267 case PopUpButtonRole: | |
| 1268 case ProgressIndicatorRole: | |
| 1269 case RadioGroupRole: | |
| 1270 case RowRole: | |
| 1271 case TabListRole: | |
| 1272 case ToolbarRole: | |
| 1273 case TreeRole: | |
| 1274 case TreeGridRole: | |
| 1275 return true; | |
| 1276 default: | |
| 1277 return false; | |
| 1278 } | |
| 1279 } | |
| 1280 | |
| 1281 bool AXLayoutObject::supportsARIADragging() const | 1222 bool AXLayoutObject::supportsARIADragging() const |
| 1282 { | 1223 { |
| 1283 const AtomicString& grabbed = getAttribute(aria_grabbedAttr); | 1224 const AtomicString& grabbed = getAttribute(aria_grabbedAttr); |
| 1284 return equalIgnoringCase(grabbed, "true") || equalIgnoringCase(grabbed, "fal
se"); | 1225 return equalIgnoringCase(grabbed, "true") || equalIgnoringCase(grabbed, "fal
se"); |
| 1285 } | 1226 } |
| 1286 | 1227 |
| 1287 bool AXLayoutObject::supportsARIADropping() const | 1228 bool AXLayoutObject::supportsARIADropping() const |
| 1288 { | 1229 { |
| 1289 const AtomicString& dropEffect = getAttribute(aria_dropeffectAttr); | 1230 const AtomicString& dropEffect = getAttribute(aria_dropeffectAttr); |
| 1290 return !dropEffect.isEmpty(); | 1231 return !dropEffect.isEmpty(); |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1698 return frame->loader().progress().estimatedProgress(); | 1639 return frame->loader().progress().estimatedProgress(); |
| 1699 return 0; | 1640 return 0; |
| 1700 } | 1641 } |
| 1701 | 1642 |
| 1702 // | 1643 // |
| 1703 // DOM and layout tree access. | 1644 // DOM and layout tree access. |
| 1704 // | 1645 // |
| 1705 | 1646 |
| 1706 Node* AXLayoutObject::getNode() const | 1647 Node* AXLayoutObject::getNode() const |
| 1707 { | 1648 { |
| 1708 return m_layoutObject ? m_layoutObject->node() : 0; | 1649 return getLayoutObject() ? getLayoutObject()->node() : nullptr; |
| 1709 } | 1650 } |
| 1710 | 1651 |
| 1711 Document* AXLayoutObject::getDocument() const | 1652 Document* AXLayoutObject::getDocument() const |
| 1712 { | 1653 { |
| 1713 if (!m_layoutObject) | 1654 if (!getLayoutObject()) |
| 1714 return 0; | 1655 return nullptr; |
| 1715 return &m_layoutObject->document(); | 1656 return &getLayoutObject()->document(); |
| 1716 } | 1657 } |
| 1717 | 1658 |
| 1718 FrameView* AXLayoutObject::documentFrameView() const | 1659 FrameView* AXLayoutObject::documentFrameView() const |
| 1719 { | 1660 { |
| 1720 if (!m_layoutObject) | 1661 if (!m_layoutObject) |
| 1721 return 0; | 1662 return 0; |
| 1722 | 1663 |
| 1723 // this is the LayoutObject's Document's LocalFrame's FrameView | 1664 // this is the LayoutObject's Document's LocalFrame's FrameView |
| 1724 return m_layoutObject->document().view(); | 1665 return m_layoutObject->document().view(); |
| 1725 } | 1666 } |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2003 else if (layoutObject->isTextArea() && isHTMLTextAreaElement(*getNode())) | 1944 else if (layoutObject->isTextArea() && isHTMLTextAreaElement(*getNode())) |
| 2004 toHTMLTextAreaElement(*getNode()).setValue(string, DispatchInputAndChang
eEvent); | 1945 toHTMLTextAreaElement(*getNode()).setValue(string, DispatchInputAndChang
eEvent); |
| 2005 } | 1946 } |
| 2006 | 1947 |
| 2007 // | 1948 // |
| 2008 // Notifications that this object may have changed. | 1949 // Notifications that this object may have changed. |
| 2009 // | 1950 // |
| 2010 | 1951 |
| 2011 void AXLayoutObject::handleActiveDescendantChanged() | 1952 void AXLayoutObject::handleActiveDescendantChanged() |
| 2012 { | 1953 { |
| 2013 Element* element = toElement(getLayoutObject()->node()); | 1954 if (!getLayoutObject()) |
| 2014 if (!element) | |
| 2015 return; | 1955 return; |
| 2016 Document& doc = getLayoutObject()->document(); | |
| 2017 if (!doc.frame()->selection().isFocusedAndActive() || doc.focusedElement() !
= element) | |
| 2018 return; | |
| 2019 AXLayoutObject* activedescendant = toAXLayoutObject(activeDescendant()); | |
| 2020 | 1956 |
| 2021 if (activedescendant && shouldNotifyActiveDescendant()) | 1957 AXObject* focusedObject = axObjectCache().focusedObject(); |
| 2022 toAXObjectCacheImpl(doc.axObjectCache())->postNotification(m_layoutObjec
t, AXObjectCacheImpl::AXActiveDescendantChanged); | 1958 if (focusedObject == this && supportsActiveDescendant()) { |
| 1959 axObjectCache().postNotification( |
| 1960 getLayoutObject(), AXObjectCacheImpl::AXActiveDescendantChanged); |
| 1961 } |
| 2023 } | 1962 } |
| 2024 | 1963 |
| 2025 void AXLayoutObject::handleAriaExpandedChanged() | 1964 void AXLayoutObject::handleAriaExpandedChanged() |
| 2026 { | 1965 { |
| 2027 // Find if a parent of this object should handle aria-expanded changes. | 1966 // Find if a parent of this object should handle aria-expanded changes. |
| 2028 AXObject* containerParent = this->parentObject(); | 1967 AXObject* containerParent = this->parentObject(); |
| 2029 while (containerParent) { | 1968 while (containerParent) { |
| 2030 bool foundParent = false; | 1969 bool foundParent = false; |
| 2031 | 1970 |
| 2032 switch (containerParent->roleValue()) { | 1971 switch (containerParent->roleValue()) { |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2185 if (treeAncestor) { | 2124 if (treeAncestor) { |
| 2186 AccessibilityRole role = roleValue(); | 2125 AccessibilityRole role = roleValue(); |
| 2187 if (role != TreeItemRole && role != StaticTextRole) | 2126 if (role != TreeItemRole && role != StaticTextRole) |
| 2188 return treeAncestor; | 2127 return treeAncestor; |
| 2189 } | 2128 } |
| 2190 return 0; | 2129 return 0; |
| 2191 } | 2130 } |
| 2192 | 2131 |
| 2193 bool AXLayoutObject::isTabItemSelected() const | 2132 bool AXLayoutObject::isTabItemSelected() const |
| 2194 { | 2133 { |
| 2195 if (!isTabItem() || !m_layoutObject) | 2134 if (!isTabItem() || !getLayoutObject()) |
| 2196 return false; | 2135 return false; |
| 2197 | 2136 |
| 2198 Node* node = m_layoutObject->node(); | 2137 Node* node = getNode(); |
| 2199 if (!node || !node->isElementNode()) | 2138 if (!node || !node->isElementNode()) |
| 2200 return false; | 2139 return false; |
| 2201 | 2140 |
| 2202 // The ARIA spec says a tab item can also be selected if it is aria-labeled
by a tabpanel | 2141 // The ARIA spec says a tab item can also be selected if it is aria-labeled
by a tabpanel |
| 2203 // that has keyboard focus inside of it, or if a tabpanel in its aria-contro
ls list has KB | 2142 // that has keyboard focus inside of it, or if a tabpanel in its aria-contro
ls list has KB |
| 2204 // focus inside of it. | 2143 // focus inside of it. |
| 2205 AXObject* focusedElement = axObjectCache().focusedObject(); | 2144 AXObject* focusedElement = axObjectCache().focusedObject(); |
| 2206 if (!focusedElement) | 2145 if (!focusedElement) |
| 2207 return false; | 2146 return false; |
| 2208 | 2147 |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2508 if (label && label->layoutObject()) { | 2447 if (label && label->layoutObject()) { |
| 2509 LayoutRect labelRect = axObjectCache().getOrCreate(label)->elementRe
ct(); | 2448 LayoutRect labelRect = axObjectCache().getOrCreate(label)->elementRe
ct(); |
| 2510 result.unite(labelRect); | 2449 result.unite(labelRect); |
| 2511 } | 2450 } |
| 2512 } | 2451 } |
| 2513 | 2452 |
| 2514 return result; | 2453 return result; |
| 2515 } | 2454 } |
| 2516 | 2455 |
| 2517 } // namespace blink | 2456 } // namespace blink |
| OLD | NEW |