Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp

Issue 1841333002: Various fixes for aria-activedescendant. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updated tests. Stopped firing a focus changed event when the active descendant changes. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698