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

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: Added selectable and selected states to ARIA list box options. 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 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 bool AXLayoutObject::isVisited() const 439 bool AXLayoutObject::isVisited() const
450 { 440 {
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
dmazzoni 2016/03/31 05:48:30 We don't actually call isFocused from outside of B
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 || focusedObject->activeDescendant() == 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 if (ariaRoleAttribute() == ListBoxOptionRole && isFocused())
480 return true;
481
491 if (isTabItem() && isTabItemSelected()) 482 if (isTabItem() && isTabItemSelected())
492 return true; 483 return true;
493 484
494 return false; 485 return false;
495 } 486 }
496 487
497 // 488 //
498 // Whether objects are ignored, i.e. not included in the tree. 489 // Whether objects are ignored, i.e. not included in the tree.
499 // 490 //
500 491
(...skipping 654 matching lines...) Expand 10 before | Expand all | Expand 10 after
1155 1146
1156 return AXNodeObject::textAlternative(recursive, inAriaLabelledByTraversal, v isited, nameFrom, relatedObjects, nameSources); 1147 return AXNodeObject::textAlternative(recursive, inAriaLabelledByTraversal, v isited, nameFrom, relatedObjects, nameSources);
1157 } 1148 }
1158 1149
1159 // 1150 //
1160 // ARIA attributes. 1151 // ARIA attributes.
1161 // 1152 //
1162 1153
1163 AXObject* AXLayoutObject::activeDescendant() const 1154 AXObject* AXLayoutObject::activeDescendant() const
1164 { 1155 {
1165 if (!m_layoutObject) 1156 if (!getLayoutObject() || !getNode())
dmazzoni 2016/03/31 05:48:30 Hmmm, is there a reason we need a layoutObject? Ma
1166 return 0; 1157 return nullptr;
1167 1158
1168 if (m_layoutObject->node() && !m_layoutObject->node()->isElementNode()) 1159 if (!getNode()->isElementNode())
1169 return 0; 1160 return nullptr;
1170 1161
1171 Element* element = toElement(m_layoutObject->node()); 1162 Element* element = toElement(getNode());
1172 if (!element) 1163 if (!element)
1173 return 0; 1164 return nullptr;
1174 1165
1175 const AtomicString& activeDescendantAttrStr = element->getAttribute(aria_act ivedescendantAttr); 1166 const AtomicString& activeDescendantAttr = getAttribute(aria_activedescendan tAttr);
1176 if (activeDescendantAttrStr.isNull() || activeDescendantAttrStr.isEmpty()) 1167 if (activeDescendantAttr.isNull() || activeDescendantAttr.isEmpty())
1177 return 0; 1168 return nullptr;
1178 1169
1179 Element* target = element->treeScope().getElementById(activeDescendantAttrSt r); 1170 Element* target = element->treeScope().getElementById(activeDescendantAttr);
1180 if (!target) 1171 if (!target)
1181 return 0; 1172 return nullptr;
1182 1173
1183 AXObject* obj = axObjectCache().getOrCreate(target); 1174 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. 1175 // 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()) 1176 if (obj && obj->isAXLayoutObject())
1187 return obj; 1177 return obj;
1188 1178
1189 return 0; 1179 return nullptr;
1190 } 1180 }
1191 1181
1192 void AXLayoutObject::ariaFlowToElements(AXObjectVector& flowTo) const 1182 void AXLayoutObject::ariaFlowToElements(AXObjectVector& flowTo) const
1193 { 1183 {
1194 accessibilityChildrenFromAttribute(aria_flowtoAttr, flowTo); 1184 accessibilityChildrenFromAttribute(aria_flowtoAttr, flowTo);
1195 } 1185 }
1196 1186
1197 void AXLayoutObject::ariaControlsElements(AXObjectVector& controls) const 1187 void AXLayoutObject::ariaControlsElements(AXObjectVector& controls) const
1198 { 1188 {
1199 accessibilityChildrenFromAttribute(aria_controlsAttr, controls); 1189 accessibilityChildrenFromAttribute(aria_controlsAttr, controls);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1247 // AXMenuListOptions, which are not AXLayoutObjects.) 1237 // AXMenuListOptions, which are not AXLayoutObjects.)
1248 if (parent->isMenuList()) 1238 if (parent->isMenuList())
1249 break; 1239 break;
1250 1240
1251 parent = parent->parentObjectIfExists(); 1241 parent = parent->parentObjectIfExists();
1252 } 1242 }
1253 1243
1254 return parent; 1244 return parent;
1255 } 1245 }
1256 1246
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 1247 bool AXLayoutObject::supportsARIADragging() const
1282 { 1248 {
1283 const AtomicString& grabbed = getAttribute(aria_grabbedAttr); 1249 const AtomicString& grabbed = getAttribute(aria_grabbedAttr);
1284 return equalIgnoringCase(grabbed, "true") || equalIgnoringCase(grabbed, "fal se"); 1250 return equalIgnoringCase(grabbed, "true") || equalIgnoringCase(grabbed, "fal se");
1285 } 1251 }
1286 1252
1287 bool AXLayoutObject::supportsARIADropping() const 1253 bool AXLayoutObject::supportsARIADropping() const
1288 { 1254 {
1289 const AtomicString& dropEffect = getAttribute(aria_dropeffectAttr); 1255 const AtomicString& dropEffect = getAttribute(aria_dropeffectAttr);
1290 return !dropEffect.isEmpty(); 1256 return !dropEffect.isEmpty();
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after
1698 return frame->loader().progress().estimatedProgress(); 1664 return frame->loader().progress().estimatedProgress();
1699 return 0; 1665 return 0;
1700 } 1666 }
1701 1667
1702 // 1668 //
1703 // DOM and layout tree access. 1669 // DOM and layout tree access.
1704 // 1670 //
1705 1671
1706 Node* AXLayoutObject::getNode() const 1672 Node* AXLayoutObject::getNode() const
1707 { 1673 {
1708 return m_layoutObject ? m_layoutObject->node() : 0; 1674 return getLayoutObject() ? getLayoutObject()->node() : nullptr;
1709 } 1675 }
1710 1676
1711 Document* AXLayoutObject::getDocument() const 1677 Document* AXLayoutObject::getDocument() const
1712 { 1678 {
1713 if (!m_layoutObject) 1679 if (!getLayoutObject())
1714 return 0; 1680 return nullptr;
1715 return &m_layoutObject->document(); 1681 return &getLayoutObject()->document();
1716 } 1682 }
1717 1683
1718 FrameView* AXLayoutObject::documentFrameView() const 1684 FrameView* AXLayoutObject::documentFrameView() const
1719 { 1685 {
1720 if (!m_layoutObject) 1686 if (!m_layoutObject)
1721 return 0; 1687 return 0;
1722 1688
1723 // this is the LayoutObject's Document's LocalFrame's FrameView 1689 // this is the LayoutObject's Document's LocalFrame's FrameView
1724 return m_layoutObject->document().view(); 1690 return m_layoutObject->document().view();
1725 } 1691 }
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
2003 else if (layoutObject->isTextArea() && isHTMLTextAreaElement(*getNode())) 1969 else if (layoutObject->isTextArea() && isHTMLTextAreaElement(*getNode()))
2004 toHTMLTextAreaElement(*getNode()).setValue(string, DispatchInputAndChang eEvent); 1970 toHTMLTextAreaElement(*getNode()).setValue(string, DispatchInputAndChang eEvent);
2005 } 1971 }
2006 1972
2007 // 1973 //
2008 // Notifications that this object may have changed. 1974 // Notifications that this object may have changed.
2009 // 1975 //
2010 1976
2011 void AXLayoutObject::handleActiveDescendantChanged() 1977 void AXLayoutObject::handleActiveDescendantChanged()
2012 { 1978 {
2013 Element* element = toElement(getLayoutObject()->node()); 1979 Element* element = toElement(getNode());
2014 if (!element) 1980 if (!element)
2015 return; 1981 return;
2016 Document& doc = getLayoutObject()->document(); 1982 Document& doc = getLayoutObject()->document();
2017 if (!doc.frame()->selection().isFocusedAndActive() || doc.focusedElement() ! = element) 1983 if (!doc.frame()->selection().isFocusedAndActive() || doc.focusedElement() ! = element)
2018 return; 1984 return;
2019 AXLayoutObject* activedescendant = toAXLayoutObject(activeDescendant());
2020 1985
2021 if (activedescendant && shouldNotifyActiveDescendant()) 1986 if (supportsActiveDescendant())
2022 toAXObjectCacheImpl(doc.axObjectCache())->postNotification(m_layoutObjec t, AXObjectCacheImpl::AXActiveDescendantChanged); 1987 toAXObjectCacheImpl(doc.axObjectCache())->postNotification(getLayoutObje ct(), AXObjectCacheImpl::AXActiveDescendantChanged);
2023 } 1988 }
2024 1989
2025 void AXLayoutObject::handleAriaExpandedChanged() 1990 void AXLayoutObject::handleAriaExpandedChanged()
2026 { 1991 {
2027 // Find if a parent of this object should handle aria-expanded changes. 1992 // Find if a parent of this object should handle aria-expanded changes.
2028 AXObject* containerParent = this->parentObject(); 1993 AXObject* containerParent = this->parentObject();
2029 while (containerParent) { 1994 while (containerParent) {
2030 bool foundParent = false; 1995 bool foundParent = false;
2031 1996
2032 switch (containerParent->roleValue()) { 1997 switch (containerParent->roleValue()) {
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
2185 if (treeAncestor) { 2150 if (treeAncestor) {
2186 AccessibilityRole role = roleValue(); 2151 AccessibilityRole role = roleValue();
2187 if (role != TreeItemRole && role != StaticTextRole) 2152 if (role != TreeItemRole && role != StaticTextRole)
2188 return treeAncestor; 2153 return treeAncestor;
2189 } 2154 }
2190 return 0; 2155 return 0;
2191 } 2156 }
2192 2157
2193 bool AXLayoutObject::isTabItemSelected() const 2158 bool AXLayoutObject::isTabItemSelected() const
2194 { 2159 {
2195 if (!isTabItem() || !m_layoutObject) 2160 if (!isTabItem() || !getLayoutObject())
2196 return false; 2161 return false;
2197 2162
2198 Node* node = m_layoutObject->node(); 2163 Node* node = getNode();
2199 if (!node || !node->isElementNode()) 2164 if (!node || !node->isElementNode())
2200 return false; 2165 return false;
2201 2166
2202 // The ARIA spec says a tab item can also be selected if it is aria-labeled by a tabpanel 2167 // 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 2168 // that has keyboard focus inside of it, or if a tabpanel in its aria-contro ls list has KB
2204 // focus inside of it. 2169 // focus inside of it.
2205 AXObject* focusedElement = axObjectCache().focusedObject(); 2170 AXObject* focusedElement = axObjectCache().focusedObject();
2206 if (!focusedElement) 2171 if (!focusedElement)
2207 return false; 2172 return false;
2208 2173
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
2508 if (label && label->layoutObject()) { 2473 if (label && label->layoutObject()) {
2509 LayoutRect labelRect = axObjectCache().getOrCreate(label)->elementRe ct(); 2474 LayoutRect labelRect = axObjectCache().getOrCreate(label)->elementRe ct();
2510 result.unite(labelRect); 2475 result.unite(labelRect);
2511 } 2476 }
2512 } 2477 }
2513 2478
2514 return result; 2479 return result;
2515 } 2480 }
2516 2481
2517 } // namespace blink 2482 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698