Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "modules/accessibility/InspectorAccessibilityAgent.h" | 5 #include "modules/accessibility/InspectorAccessibilityAgent.h" |
| 6 | 6 |
| 7 #include "core/HTMLNames.h" | 7 #include "core/HTMLNames.h" |
| 8 #include "core/dom/AXObjectCache.h" | 8 #include "core/dom/AXObjectCache.h" |
| 9 #include "core/dom/DOMNodeIds.h" | 9 #include "core/dom/DOMNodeIds.h" |
| 10 #include "core/dom/Element.h" | 10 #include "core/dom/Element.h" |
| 11 #include "core/dom/Node.h" | |
| 12 #include "core/dom/NodeList.h" | |
| 11 #include "core/inspector/IdentifiersFactory.h" | 13 #include "core/inspector/IdentifiersFactory.h" |
| 12 #include "core/inspector/InspectorDOMAgent.h" | 14 #include "core/inspector/InspectorDOMAgent.h" |
| 13 #include "core/inspector/InspectorStyleSheet.h" | 15 #include "core/inspector/InspectorStyleSheet.h" |
| 14 #include "core/page/Page.h" | 16 #include "core/page/Page.h" |
| 15 #include "modules/accessibility/AXObject.h" | 17 #include "modules/accessibility/AXObject.h" |
| 16 #include "modules/accessibility/AXObjectCacheImpl.h" | 18 #include "modules/accessibility/AXObjectCacheImpl.h" |
| 17 #include "modules/accessibility/InspectorTypeBuilderHelper.h" | 19 #include "modules/accessibility/InspectorTypeBuilderHelper.h" |
| 18 #include <memory> | 20 #include <memory> |
| 19 | 21 |
| 20 namespace blink { | 22 namespace blink { |
| 21 | 23 |
| 22 using protocol::Accessibility::AXGlobalStates; | 24 using protocol::Accessibility::AXGlobalStates; |
| 23 using protocol::Accessibility::AXLiveRegionAttributes; | 25 using protocol::Accessibility::AXLiveRegionAttributes; |
| 24 using protocol::Accessibility::AXNode; | 26 using protocol::Accessibility::AXNode; |
| 25 using protocol::Accessibility::AXNodeId; | 27 using protocol::Accessibility::AXNodeId; |
| 26 using protocol::Accessibility::AXProperty; | 28 using protocol::Accessibility::AXProperty; |
| 27 using protocol::Accessibility::AXValueSource; | 29 using protocol::Accessibility::AXValueSource; |
| 28 using protocol::Accessibility::AXValueType; | 30 using protocol::Accessibility::AXValueType; |
| 29 using protocol::Accessibility::AXRelatedNode; | 31 using protocol::Accessibility::AXRelatedNode; |
| 30 using protocol::Accessibility::AXRelationshipAttributes; | 32 using protocol::Accessibility::AXRelationshipAttributes; |
| 31 using protocol::Accessibility::AXValue; | 33 using protocol::Accessibility::AXValue; |
| 32 using protocol::Accessibility::AXWidgetAttributes; | 34 using protocol::Accessibility::AXWidgetAttributes; |
| 33 using protocol::Accessibility::AXWidgetStates; | 35 using protocol::Accessibility::AXWidgetStates; |
| 34 | 36 |
| 35 using namespace HTMLNames; | 37 using namespace HTMLNames; |
| 36 | 38 |
| 37 namespace { | 39 namespace { |
| 38 | 40 |
| 39 void fillCoreProperties(AXObject* axObject, AXNode* nodeObject) { | 41 void fillLiveRegionProperties(AXObject& axObject, |
| 40 // Description (secondary to the accessible name). | 42 protocol::Array<AXProperty>& properties) { |
| 41 AXNameFrom nameFrom; | 43 if (!axObject.liveRegionRoot()) |
| 42 AXObject::AXObjectVector nameObjects; | 44 return; |
| 43 axObject->name(nameFrom, &nameObjects); | |
| 44 AXDescriptionFrom descriptionFrom; | |
| 45 AXObject::AXObjectVector descriptionObjects; | |
| 46 String description = | |
| 47 axObject->description(nameFrom, descriptionFrom, &descriptionObjects); | |
| 48 if (!description.isEmpty()) | |
| 49 nodeObject->setDescription( | |
| 50 createValue(description, AXValueTypeEnum::ComputedString)); | |
| 51 | 45 |
| 52 // Value. | 46 properties.addItem( |
| 53 if (axObject->supportsRangeValue()) { | 47 createProperty(AXLiveRegionAttributesEnum::Live, |
| 54 nodeObject->setValue(createValue(axObject->valueForRange())); | 48 createValue(axObject.containerLiveRegionStatus(), |
| 55 } else { | 49 AXValueTypeEnum::Token))); |
| 56 String stringValue = axObject->stringValue(); | 50 properties.addItem( |
| 57 if (!stringValue.isEmpty()) | 51 createProperty(AXLiveRegionAttributesEnum::Atomic, |
| 58 nodeObject->setValue(createValue(stringValue)); | 52 createBooleanValue(axObject.containerLiveRegionAtomic()))); |
| 53 properties.addItem( | |
| 54 createProperty(AXLiveRegionAttributesEnum::Relevant, | |
| 55 createValue(axObject.containerLiveRegionRelevant(), | |
| 56 AXValueTypeEnum::TokenList))); | |
| 57 properties.addItem( | |
| 58 createProperty(AXLiveRegionAttributesEnum::Busy, | |
| 59 createBooleanValue(axObject.containerLiveRegionBusy()))); | |
| 60 | |
| 61 if (!axObject.isLiveRegion()) { | |
| 62 properties.addItem(createProperty( | |
| 63 AXLiveRegionAttributesEnum::Root, | |
| 64 createRelatedNodeListValue(*(axObject.liveRegionRoot())))); | |
| 59 } | 65 } |
| 60 } | 66 } |
| 61 | 67 |
| 62 void fillLiveRegionProperties(AXObject* axObject, | 68 void fillGlobalStates(AXObject& axObject, |
| 63 protocol::Array<AXProperty>* properties) { | 69 protocol::Array<AXProperty>& properties) { |
| 64 if (!axObject->liveRegionRoot()) | 70 if (!axObject.isEnabled()) |
| 65 return; | 71 properties.addItem( |
| 66 | |
| 67 properties->addItem( | |
| 68 createProperty(AXLiveRegionAttributesEnum::Live, | |
| 69 createValue(axObject->containerLiveRegionStatus(), | |
| 70 AXValueTypeEnum::Token))); | |
| 71 properties->addItem(createProperty( | |
| 72 AXLiveRegionAttributesEnum::Atomic, | |
| 73 createBooleanValue(axObject->containerLiveRegionAtomic()))); | |
| 74 properties->addItem( | |
| 75 createProperty(AXLiveRegionAttributesEnum::Relevant, | |
| 76 createValue(axObject->containerLiveRegionRelevant(), | |
| 77 AXValueTypeEnum::TokenList))); | |
| 78 properties->addItem( | |
| 79 createProperty(AXLiveRegionAttributesEnum::Busy, | |
| 80 createBooleanValue(axObject->containerLiveRegionBusy()))); | |
| 81 | |
| 82 if (!axObject->isLiveRegion()) | |
| 83 properties->addItem( | |
| 84 createProperty(AXLiveRegionAttributesEnum::Root, | |
| 85 createRelatedNodeListValue(axObject->liveRegionRoot()))); | |
| 86 } | |
| 87 | |
| 88 void fillGlobalStates(AXObject* axObject, | |
| 89 protocol::Array<AXProperty>* properties) { | |
| 90 if (!axObject->isEnabled()) | |
| 91 properties->addItem( | |
| 92 createProperty(AXGlobalStatesEnum::Disabled, createBooleanValue(true))); | 72 createProperty(AXGlobalStatesEnum::Disabled, createBooleanValue(true))); |
| 93 | 73 |
| 94 if (const AXObject* hiddenRoot = axObject->ariaHiddenRoot()) { | 74 if (const AXObject* hiddenRoot = axObject.ariaHiddenRoot()) { |
| 95 properties->addItem( | 75 properties.addItem( |
| 96 createProperty(AXGlobalStatesEnum::Hidden, createBooleanValue(true))); | 76 createProperty(AXGlobalStatesEnum::Hidden, createBooleanValue(true))); |
| 97 properties->addItem(createProperty(AXGlobalStatesEnum::HiddenRoot, | 77 properties.addItem(createProperty(AXGlobalStatesEnum::HiddenRoot, |
| 98 createRelatedNodeListValue(hiddenRoot))); | 78 createRelatedNodeListValue(*hiddenRoot))); |
| 99 } | 79 } |
| 100 | 80 |
| 101 InvalidState invalidState = axObject->getInvalidState(); | 81 InvalidState invalidState = axObject.getInvalidState(); |
| 102 switch (invalidState) { | 82 switch (invalidState) { |
| 103 case InvalidStateUndefined: | 83 case InvalidStateUndefined: |
| 104 break; | 84 break; |
| 105 case InvalidStateFalse: | 85 case InvalidStateFalse: |
| 106 properties->addItem( | 86 properties.addItem( |
| 107 createProperty(AXGlobalStatesEnum::Invalid, | 87 createProperty(AXGlobalStatesEnum::Invalid, |
| 108 createValue("false", AXValueTypeEnum::Token))); | 88 createValue("false", AXValueTypeEnum::Token))); |
| 109 break; | 89 break; |
| 110 case InvalidStateTrue: | 90 case InvalidStateTrue: |
| 111 properties->addItem( | 91 properties.addItem( |
| 112 createProperty(AXGlobalStatesEnum::Invalid, | 92 createProperty(AXGlobalStatesEnum::Invalid, |
| 113 createValue("true", AXValueTypeEnum::Token))); | 93 createValue("true", AXValueTypeEnum::Token))); |
| 114 break; | 94 break; |
| 115 case InvalidStateSpelling: | 95 case InvalidStateSpelling: |
| 116 properties->addItem( | 96 properties.addItem( |
| 117 createProperty(AXGlobalStatesEnum::Invalid, | 97 createProperty(AXGlobalStatesEnum::Invalid, |
| 118 createValue("spelling", AXValueTypeEnum::Token))); | 98 createValue("spelling", AXValueTypeEnum::Token))); |
| 119 break; | 99 break; |
| 120 case InvalidStateGrammar: | 100 case InvalidStateGrammar: |
| 121 properties->addItem( | 101 properties.addItem( |
| 122 createProperty(AXGlobalStatesEnum::Invalid, | 102 createProperty(AXGlobalStatesEnum::Invalid, |
| 123 createValue("grammar", AXValueTypeEnum::Token))); | 103 createValue("grammar", AXValueTypeEnum::Token))); |
| 124 break; | 104 break; |
| 125 default: | 105 default: |
| 126 // TODO(aboxhall): expose invalid: <nothing> and source: aria-invalid as | 106 // TODO(aboxhall): expose invalid: <nothing> and source: aria-invalid as |
| 127 // invalid value | 107 // invalid value |
| 128 properties->addItem(createProperty( | 108 properties.addItem(createProperty( |
| 129 AXGlobalStatesEnum::Invalid, | 109 AXGlobalStatesEnum::Invalid, |
| 130 createValue(axObject->ariaInvalidValue(), AXValueTypeEnum::String))); | 110 createValue(axObject.ariaInvalidValue(), AXValueTypeEnum::String))); |
| 131 break; | 111 break; |
| 132 } | 112 } |
| 133 } | 113 } |
| 134 | 114 |
| 135 bool roleAllowsMultiselectable(AccessibilityRole role) { | 115 bool roleAllowsMultiselectable(AccessibilityRole role) { |
| 136 return role == GridRole || role == ListBoxRole || role == TabListRole || | 116 return role == GridRole || role == ListBoxRole || role == TabListRole || |
| 137 role == TreeGridRole || role == TreeRole; | 117 role == TreeGridRole || role == TreeRole; |
| 138 } | 118 } |
| 139 | 119 |
| 140 bool roleAllowsOrientation(AccessibilityRole role) { | 120 bool roleAllowsOrientation(AccessibilityRole role) { |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 166 role == SwitchRole; | 146 role == SwitchRole; |
| 167 } | 147 } |
| 168 | 148 |
| 169 bool roleAllowsSelected(AccessibilityRole role) { | 149 bool roleAllowsSelected(AccessibilityRole role) { |
| 170 return role == CellRole || role == ListBoxOptionRole || role == RowRole || | 150 return role == CellRole || role == ListBoxOptionRole || role == RowRole || |
| 171 role == TabRole || role == ColumnHeaderRole || | 151 role == TabRole || role == ColumnHeaderRole || |
| 172 role == MenuItemRadioRole || role == RadioButtonRole || | 152 role == MenuItemRadioRole || role == RadioButtonRole || |
| 173 role == RowHeaderRole || role == TreeItemRole; | 153 role == RowHeaderRole || role == TreeItemRole; |
| 174 } | 154 } |
| 175 | 155 |
| 176 void fillWidgetProperties(AXObject* axObject, | 156 void fillWidgetProperties(AXObject& axObject, |
|
dmazzoni
2016/10/19 16:33:49
You could land a quick change to replace pointers
aboxhall
2016/10/19 23:49:05
Done.
| |
| 177 protocol::Array<AXProperty>* properties) { | 157 protocol::Array<AXProperty>& properties) { |
| 178 AccessibilityRole role = axObject->roleValue(); | 158 AccessibilityRole role = axObject.roleValue(); |
| 179 String autocomplete = axObject->ariaAutoComplete(); | 159 String autocomplete = axObject.ariaAutoComplete(); |
| 180 if (!autocomplete.isEmpty()) | 160 if (!autocomplete.isEmpty()) |
| 181 properties->addItem( | 161 properties.addItem( |
| 182 createProperty(AXWidgetAttributesEnum::Autocomplete, | 162 createProperty(AXWidgetAttributesEnum::Autocomplete, |
| 183 createValue(autocomplete, AXValueTypeEnum::Token))); | 163 createValue(autocomplete, AXValueTypeEnum::Token))); |
| 184 | 164 |
| 185 if (axObject->hasAttribute(HTMLNames::aria_haspopupAttr)) { | 165 if (axObject.hasAttribute(HTMLNames::aria_haspopupAttr)) { |
| 186 bool hasPopup = axObject->ariaHasPopup(); | 166 bool hasPopup = axObject.ariaHasPopup(); |
| 187 properties->addItem(createProperty(AXWidgetAttributesEnum::Haspopup, | 167 properties.addItem(createProperty(AXWidgetAttributesEnum::Haspopup, |
| 188 createBooleanValue(hasPopup))); | 168 createBooleanValue(hasPopup))); |
| 189 } | 169 } |
| 190 | 170 |
| 191 int headingLevel = axObject->headingLevel(); | 171 int headingLevel = axObject.headingLevel(); |
| 192 if (headingLevel > 0) | 172 if (headingLevel > 0) { |
|
dmazzoni
2016/10/19 16:33:49
Did this come from "git cl format" or some other a
aboxhall
2016/10/19 23:49:05
Done.
| |
| 193 properties->addItem(createProperty(AXWidgetAttributesEnum::Level, | 173 properties.addItem(createProperty(AXWidgetAttributesEnum::Level, |
| 194 createValue(headingLevel))); | 174 createValue(headingLevel))); |
| 195 int hierarchicalLevel = axObject->hierarchicalLevel(); | 175 } |
| 176 int hierarchicalLevel = axObject.hierarchicalLevel(); | |
| 196 if (hierarchicalLevel > 0 || | 177 if (hierarchicalLevel > 0 || |
| 197 axObject->hasAttribute(HTMLNames::aria_levelAttr)) | 178 axObject.hasAttribute(HTMLNames::aria_levelAttr)) { |
| 198 properties->addItem(createProperty(AXWidgetAttributesEnum::Level, | 179 properties.addItem(createProperty(AXWidgetAttributesEnum::Level, |
| 199 createValue(hierarchicalLevel))); | 180 createValue(hierarchicalLevel))); |
| 181 } | |
| 200 | 182 |
| 201 if (roleAllowsMultiselectable(role)) { | 183 if (roleAllowsMultiselectable(role)) { |
| 202 bool multiselectable = axObject->isMultiSelectable(); | 184 bool multiselectable = axObject.isMultiSelectable(); |
| 203 properties->addItem(createProperty(AXWidgetAttributesEnum::Multiselectable, | 185 properties.addItem(createProperty(AXWidgetAttributesEnum::Multiselectable, |
| 204 createBooleanValue(multiselectable))); | 186 createBooleanValue(multiselectable))); |
| 205 } | 187 } |
| 206 | 188 |
| 207 if (roleAllowsOrientation(role)) { | 189 if (roleAllowsOrientation(role)) { |
| 208 AccessibilityOrientation orientation = axObject->orientation(); | 190 AccessibilityOrientation orientation = axObject.orientation(); |
| 209 switch (orientation) { | 191 switch (orientation) { |
| 210 case AccessibilityOrientationVertical: | 192 case AccessibilityOrientationVertical: |
| 211 properties->addItem( | 193 properties.addItem( |
| 212 createProperty(AXWidgetAttributesEnum::Orientation, | 194 createProperty(AXWidgetAttributesEnum::Orientation, |
| 213 createValue("vertical", AXValueTypeEnum::Token))); | 195 createValue("vertical", AXValueTypeEnum::Token))); |
| 214 break; | 196 break; |
| 215 case AccessibilityOrientationHorizontal: | 197 case AccessibilityOrientationHorizontal: |
| 216 properties->addItem( | 198 properties.addItem( |
| 217 createProperty(AXWidgetAttributesEnum::Orientation, | 199 createProperty(AXWidgetAttributesEnum::Orientation, |
| 218 createValue("horizontal", AXValueTypeEnum::Token))); | 200 createValue("horizontal", AXValueTypeEnum::Token))); |
| 219 break; | 201 break; |
| 220 case AccessibilityOrientationUndefined: | 202 case AccessibilityOrientationUndefined: |
| 221 break; | 203 break; |
| 222 } | 204 } |
| 223 } | 205 } |
| 224 | 206 |
| 225 if (role == TextFieldRole) | 207 if (role == TextFieldRole) { |
| 226 properties->addItem( | 208 properties.addItem( |
| 227 createProperty(AXWidgetAttributesEnum::Multiline, | 209 createProperty(AXWidgetAttributesEnum::Multiline, |
| 228 createBooleanValue(axObject->isMultiline()))); | 210 createBooleanValue(axObject.isMultiline()))); |
| 211 } | |
| 229 | 212 |
| 230 if (roleAllowsReadonly(role)) { | 213 if (roleAllowsReadonly(role)) { |
| 231 properties->addItem( | 214 properties.addItem( |
| 232 createProperty(AXWidgetAttributesEnum::Readonly, | 215 createProperty(AXWidgetAttributesEnum::Readonly, |
| 233 createBooleanValue(axObject->isReadOnly()))); | 216 createBooleanValue(axObject.isReadOnly()))); |
| 234 } | 217 } |
| 235 | 218 |
| 236 if (roleAllowsRequired(role)) { | 219 if (roleAllowsRequired(role)) { |
| 237 properties->addItem( | 220 properties.addItem( |
| 238 createProperty(AXWidgetAttributesEnum::Required, | 221 createProperty(AXWidgetAttributesEnum::Required, |
| 239 createBooleanValue(axObject->isRequired()))); | 222 createBooleanValue(axObject.isRequired()))); |
| 240 } | 223 } |
| 241 | 224 |
| 242 if (roleAllowsSort(role)) { | 225 if (roleAllowsSort(role)) { |
| 243 // TODO(aboxhall): sort | 226 // TODO(aboxhall): sort |
| 244 } | 227 } |
| 245 | 228 |
| 246 if (axObject->isRange()) { | 229 if (axObject.isRange()) { |
| 247 properties->addItem( | 230 properties.addItem( |
| 248 createProperty(AXWidgetAttributesEnum::Valuemin, | 231 createProperty(AXWidgetAttributesEnum::Valuemin, |
| 249 createValue(axObject->minValueForRange()))); | 232 createValue(axObject.minValueForRange()))); |
| 250 properties->addItem( | 233 properties.addItem( |
| 251 createProperty(AXWidgetAttributesEnum::Valuemax, | 234 createProperty(AXWidgetAttributesEnum::Valuemax, |
| 252 createValue(axObject->maxValueForRange()))); | 235 createValue(axObject.maxValueForRange()))); |
| 253 properties->addItem( | 236 properties.addItem( |
| 254 createProperty(AXWidgetAttributesEnum::Valuetext, | 237 createProperty(AXWidgetAttributesEnum::Valuetext, |
| 255 createValue(axObject->valueDescription()))); | 238 createValue(axObject.valueDescription()))); |
| 256 } | 239 } |
| 257 } | 240 } |
| 258 | 241 |
| 259 void fillWidgetStates(AXObject* axObject, | 242 void fillWidgetStates(AXObject& axObject, |
| 260 protocol::Array<AXProperty>* properties) { | 243 protocol::Array<AXProperty>& properties) { |
| 261 AccessibilityRole role = axObject->roleValue(); | 244 AccessibilityRole role = axObject.roleValue(); |
| 262 if (roleAllowsChecked(role)) { | 245 if (roleAllowsChecked(role)) { |
| 263 AccessibilityButtonState checked = axObject->checkboxOrRadioValue(); | 246 AccessibilityButtonState checked = axObject.checkboxOrRadioValue(); |
| 264 switch (checked) { | 247 switch (checked) { |
| 265 case ButtonStateOff: | 248 case ButtonStateOff: |
| 266 properties->addItem( | 249 properties.addItem( |
| 267 createProperty(AXWidgetStatesEnum::Checked, | 250 createProperty(AXWidgetStatesEnum::Checked, |
| 268 createValue("false", AXValueTypeEnum::Tristate))); | 251 createValue("false", AXValueTypeEnum::Tristate))); |
| 269 break; | 252 break; |
| 270 case ButtonStateOn: | 253 case ButtonStateOn: |
| 271 properties->addItem( | 254 properties.addItem( |
| 272 createProperty(AXWidgetStatesEnum::Checked, | 255 createProperty(AXWidgetStatesEnum::Checked, |
| 273 createValue("true", AXValueTypeEnum::Tristate))); | 256 createValue("true", AXValueTypeEnum::Tristate))); |
| 274 break; | 257 break; |
| 275 case ButtonStateMixed: | 258 case ButtonStateMixed: |
| 276 properties->addItem( | 259 properties.addItem( |
| 277 createProperty(AXWidgetStatesEnum::Checked, | 260 createProperty(AXWidgetStatesEnum::Checked, |
| 278 createValue("mixed", AXValueTypeEnum::Tristate))); | 261 createValue("mixed", AXValueTypeEnum::Tristate))); |
| 279 break; | 262 break; |
| 280 } | 263 } |
| 281 } | 264 } |
| 282 | 265 |
| 283 AccessibilityExpanded expanded = axObject->isExpanded(); | 266 AccessibilityExpanded expanded = axObject.isExpanded(); |
| 284 switch (expanded) { | 267 switch (expanded) { |
| 285 case ExpandedUndefined: | 268 case ExpandedUndefined: |
| 286 break; | 269 break; |
| 287 case ExpandedCollapsed: | 270 case ExpandedCollapsed: |
| 288 properties->addItem(createProperty( | 271 properties.addItem(createProperty( |
| 289 AXWidgetStatesEnum::Expanded, | 272 AXWidgetStatesEnum::Expanded, |
| 290 createBooleanValue(false, AXValueTypeEnum::BooleanOrUndefined))); | 273 createBooleanValue(false, AXValueTypeEnum::BooleanOrUndefined))); |
| 291 break; | 274 break; |
| 292 case ExpandedExpanded: | 275 case ExpandedExpanded: |
| 293 properties->addItem(createProperty( | 276 properties.addItem(createProperty( |
| 294 AXWidgetStatesEnum::Expanded, | 277 AXWidgetStatesEnum::Expanded, |
| 295 createBooleanValue(true, AXValueTypeEnum::BooleanOrUndefined))); | 278 createBooleanValue(true, AXValueTypeEnum::BooleanOrUndefined))); |
| 296 break; | 279 break; |
| 297 } | 280 } |
| 298 | 281 |
| 299 if (role == ToggleButtonRole) { | 282 if (role == ToggleButtonRole) { |
| 300 if (!axObject->isPressed()) { | 283 if (!axObject.isPressed()) { |
| 301 properties->addItem( | 284 properties.addItem( |
| 302 createProperty(AXWidgetStatesEnum::Pressed, | 285 createProperty(AXWidgetStatesEnum::Pressed, |
| 303 createValue("false", AXValueTypeEnum::Tristate))); | 286 createValue("false", AXValueTypeEnum::Tristate))); |
| 304 } else { | 287 } else { |
| 305 const AtomicString& pressedAttr = | 288 const AtomicString& pressedAttr = |
| 306 axObject->getAttribute(HTMLNames::aria_pressedAttr); | 289 axObject.getAttribute(HTMLNames::aria_pressedAttr); |
| 307 if (equalIgnoringCase(pressedAttr, "mixed")) | 290 if (equalIgnoringCase(pressedAttr, "mixed")) |
| 308 properties->addItem( | 291 properties.addItem( |
| 309 createProperty(AXWidgetStatesEnum::Pressed, | 292 createProperty(AXWidgetStatesEnum::Pressed, |
| 310 createValue("mixed", AXValueTypeEnum::Tristate))); | 293 createValue("mixed", AXValueTypeEnum::Tristate))); |
| 311 else | 294 else |
| 312 properties->addItem( | 295 properties.addItem( |
| 313 createProperty(AXWidgetStatesEnum::Pressed, | 296 createProperty(AXWidgetStatesEnum::Pressed, |
| 314 createValue("true", AXValueTypeEnum::Tristate))); | 297 createValue("true", AXValueTypeEnum::Tristate))); |
| 315 } | 298 } |
| 316 } | 299 } |
| 317 | 300 |
| 318 if (roleAllowsSelected(role)) { | 301 if (roleAllowsSelected(role)) { |
| 319 properties->addItem( | 302 properties.addItem( |
| 320 createProperty(AXWidgetStatesEnum::Selected, | 303 createProperty(AXWidgetStatesEnum::Selected, |
| 321 createBooleanValue(axObject->isSelected()))); | 304 createBooleanValue(axObject.isSelected()))); |
| 322 } | 305 } |
| 323 } | 306 } |
| 324 | 307 |
| 325 std::unique_ptr<AXProperty> createRelatedNodeListProperty( | 308 std::unique_ptr<AXProperty> createRelatedNodeListProperty( |
| 326 const String& key, | 309 const String& key, |
| 327 AXRelatedObjectVector& nodes) { | 310 AXRelatedObjectVector& nodes) { |
| 328 std::unique_ptr<AXValue> nodeListValue = | 311 std::unique_ptr<AXValue> nodeListValue = |
| 329 createRelatedNodeListValue(nodes, AXValueTypeEnum::NodeList); | 312 createRelatedNodeListValue(nodes, AXValueTypeEnum::NodeList); |
| 330 return createProperty(key, std::move(nodeListValue)); | 313 return createProperty(key, std::move(nodeListValue)); |
| 331 } | 314 } |
| 332 | 315 |
| 333 std::unique_ptr<AXProperty> createRelatedNodeListProperty( | 316 std::unique_ptr<AXProperty> createRelatedNodeListProperty( |
| 334 const String& key, | 317 const String& key, |
| 335 AXObject::AXObjectVector& nodes, | 318 AXObject::AXObjectVector& nodes, |
| 336 const QualifiedName& attr, | 319 const QualifiedName& attr, |
| 337 AXObject* axObject) { | 320 AXObject& axObject) { |
| 338 std::unique_ptr<AXValue> nodeListValue = createRelatedNodeListValue(nodes); | 321 std::unique_ptr<AXValue> nodeListValue = createRelatedNodeListValue(nodes); |
| 339 const AtomicString& attrValue = axObject->getAttribute(attr); | 322 const AtomicString& attrValue = axObject.getAttribute(attr); |
| 340 nodeListValue->setValue(protocol::StringValue::create(attrValue)); | 323 nodeListValue->setValue(protocol::StringValue::create(attrValue)); |
| 341 return createProperty(key, std::move(nodeListValue)); | 324 return createProperty(key, std::move(nodeListValue)); |
| 342 } | 325 } |
| 343 | 326 |
| 344 void fillRelationships(AXObject* axObject, | 327 void fillRelationships(AXObject& axObject, |
| 345 protocol::Array<AXProperty>* properties) { | 328 protocol::Array<AXProperty>& properties) { |
| 346 if (AXObject* activeDescendant = axObject->activeDescendant()) { | 329 if (AXObject* activeDescendant = axObject.activeDescendant()) { |
| 347 properties->addItem( | 330 properties.addItem( |
| 348 createProperty(AXRelationshipAttributesEnum::Activedescendant, | 331 createProperty(AXRelationshipAttributesEnum::Activedescendant, |
| 349 createRelatedNodeListValue(activeDescendant))); | 332 createRelatedNodeListValue(*activeDescendant))); |
| 350 } | 333 } |
| 351 | 334 |
| 352 AXObject::AXObjectVector results; | 335 AXObject::AXObjectVector results; |
| 353 axObject->ariaFlowToElements(results); | 336 axObject.ariaFlowToElements(results); |
| 354 if (!results.isEmpty()) | 337 if (!results.isEmpty()) |
| 355 properties->addItem( | 338 properties.addItem( |
| 356 createRelatedNodeListProperty(AXRelationshipAttributesEnum::Flowto, | 339 createRelatedNodeListProperty(AXRelationshipAttributesEnum::Flowto, |
| 357 results, aria_flowtoAttr, axObject)); | 340 results, aria_flowtoAttr, axObject)); |
| 358 results.clear(); | 341 results.clear(); |
| 359 | 342 |
| 360 axObject->ariaControlsElements(results); | 343 axObject.ariaControlsElements(results); |
| 361 if (!results.isEmpty()) | 344 if (!results.isEmpty()) |
| 362 properties->addItem( | 345 properties.addItem( |
| 363 createRelatedNodeListProperty(AXRelationshipAttributesEnum::Controls, | 346 createRelatedNodeListProperty(AXRelationshipAttributesEnum::Controls, |
| 364 results, aria_controlsAttr, axObject)); | 347 results, aria_controlsAttr, axObject)); |
| 365 results.clear(); | 348 results.clear(); |
| 366 | 349 |
| 367 axObject->ariaDescribedbyElements(results); | 350 axObject.ariaDescribedbyElements(results); |
| 368 if (!results.isEmpty()) | 351 if (!results.isEmpty()) |
| 369 properties->addItem( | 352 properties.addItem( |
| 370 createRelatedNodeListProperty(AXRelationshipAttributesEnum::Describedby, | 353 createRelatedNodeListProperty(AXRelationshipAttributesEnum::Describedby, |
| 371 results, aria_describedbyAttr, axObject)); | 354 results, aria_describedbyAttr, axObject)); |
| 372 results.clear(); | 355 results.clear(); |
| 373 | 356 |
| 374 axObject->ariaOwnsElements(results); | 357 axObject.ariaOwnsElements(results); |
| 375 if (!results.isEmpty()) | 358 if (!results.isEmpty()) |
| 376 properties->addItem(createRelatedNodeListProperty( | 359 properties.addItem(createRelatedNodeListProperty( |
| 377 AXRelationshipAttributesEnum::Owns, results, aria_ownsAttr, axObject)); | 360 AXRelationshipAttributesEnum::Owns, results, aria_ownsAttr, axObject)); |
| 378 results.clear(); | 361 results.clear(); |
| 379 } | 362 } |
| 380 | 363 |
| 381 std::unique_ptr<AXValue> createRoleNameValue(AccessibilityRole role) { | 364 std::unique_ptr<AXValue> createRoleNameValue(AccessibilityRole role) { |
| 382 AtomicString roleName = AXObject::roleName(role); | 365 AtomicString roleName = AXObject::roleName(role); |
| 383 std::unique_ptr<AXValue> roleNameValue; | 366 std::unique_ptr<AXValue> roleNameValue; |
| 384 if (!roleName.isNull()) { | 367 if (!roleName.isNull()) { |
| 385 roleNameValue = createValue(roleName, AXValueTypeEnum::Role); | 368 roleNameValue = createValue(roleName, AXValueTypeEnum::Role); |
| 386 } else { | 369 } else { |
| 387 roleNameValue = createValue(AXObject::internalRoleName(role), | 370 roleNameValue = createValue(AXObject::internalRoleName(role), |
| 388 AXValueTypeEnum::InternalRole); | 371 AXValueTypeEnum::InternalRole); |
| 389 } | 372 } |
| 390 return roleNameValue; | 373 return roleNameValue; |
| 391 } | 374 } |
| 392 | 375 |
| 393 std::unique_ptr<AXNode> buildObjectForIgnoredNode(Node* node, | 376 bool isAncestorOf(AXObject* possibleAncestor, AXObject* descendant) { |
| 394 const AXObject* axObject) { | 377 if (!possibleAncestor || !descendant) |
| 378 return false; | |
| 379 | |
| 380 AXObject* ancestor = descendant; | |
| 381 while (ancestor) { | |
| 382 if (ancestor == possibleAncestor) | |
| 383 return true; | |
| 384 ancestor = ancestor->parentObject(); | |
| 385 } | |
| 386 return false; | |
| 387 } | |
| 388 | |
| 389 } // namespace | |
| 390 | |
| 391 InspectorAccessibilityAgent::InspectorAccessibilityAgent( | |
| 392 Page* page, | |
| 393 InspectorDOMAgent* domAgent) | |
| 394 : m_page(page), m_domAgent(domAgent) {} | |
| 395 | |
| 396 void InspectorAccessibilityAgent::getPartialAXTree( | |
| 397 ErrorString* errorString, | |
| 398 int domNodeId, | |
| 399 std::unique_ptr<protocol::Array<AXNode>>* nodes) { | |
| 400 if (!m_domAgent->enabled()) { | |
| 401 *errorString = "DOM agent must be enabled"; | |
| 402 return; | |
| 403 } | |
| 404 Node* domNode = m_domAgent->assertNode(errorString, domNodeId); | |
| 405 if (!domNode) | |
| 406 return; | |
| 407 | |
| 408 Document& document = domNode->document(); | |
| 409 document.updateStyleAndLayoutIgnorePendingStylesheets(); | |
| 410 DocumentLifecycle::DisallowTransitionScope disallowTransition( | |
| 411 document.lifecycle()); | |
| 412 LocalFrame* localFrame = document.frame(); | |
| 413 if (!localFrame) { | |
| 414 *errorString = "Frame is detached."; | |
| 415 return; | |
| 416 } | |
| 417 std::unique_ptr<ScopedAXObjectCache> scopedCache = | |
| 418 ScopedAXObjectCache::create(document); | |
| 419 AXObjectCacheImpl* cache = toAXObjectCacheImpl(scopedCache->get()); | |
| 420 | |
| 421 AXObject* inspectedAXObject = cache->getOrCreate(domNode); | |
| 422 *nodes = protocol::Array<protocol::Accessibility::AXNode>::create(); | |
| 423 if (!inspectedAXObject || inspectedAXObject->accessibilityIsIgnored()) { | |
| 424 (*nodes)->addItem( | |
| 425 buildObjectForIgnoredNode(domNode, inspectedAXObject, *nodes, *cache)); | |
| 426 } else { | |
| 427 (*nodes)->addItem(buildProtocolAXObject(*inspectedAXObject, | |
| 428 inspectedAXObject, *nodes, *cache)); | |
| 429 } | |
| 430 | |
| 431 if (!inspectedAXObject) | |
| 432 return; | |
| 433 | |
| 434 AXObject* parent = inspectedAXObject->parentObjectUnignored(); | |
|
dmazzoni
2016/10/19 16:33:48
Will it be confusing if you can click on a node an
aboxhall
2016/10/19 23:49:05
Yeah, I think it's either that (i.e. show ignored
| |
| 435 if (!parent) | |
| 436 return; | |
| 437 | |
| 438 std::unique_ptr<AXNode> parentNodeObject = | |
| 439 buildProtocolAXObject(*parent, inspectedAXObject, *nodes, *cache); | |
| 440 | |
| 441 (*nodes)->addItem(std::move(parentNodeObject)); | |
|
dmazzoni
2016/10/19 16:33:48
Are you using parentNodeObject? If not, maybe just
aboxhall
2016/10/19 23:49:05
Done.
| |
| 442 AXObject* ancestor = parent->parentObjectUnignored(); | |
| 443 while (ancestor) { | |
| 444 (*nodes)->addItem( | |
| 445 buildProtocolAXObject(*ancestor, inspectedAXObject, *nodes, *cache)); | |
|
dmazzoni
2016/10/19 16:33:48
I think you can eliminate a few lines of code here
aboxhall
2016/10/19 23:49:05
Done (yeah, it was originally special-casing the p
| |
| 446 ancestor = ancestor->parentObjectUnignored(); | |
| 447 } | |
| 448 } | |
| 449 | |
| 450 std::unique_ptr<AXNode> InspectorAccessibilityAgent::buildObjectForIgnoredNode( | |
| 451 Node* domNode, | |
| 452 AXObject* axObject, | |
| 453 std::unique_ptr<protocol::Array<AXNode>>& nodes, | |
| 454 AXObjectCacheImpl& cache) const { | |
| 395 AXObject::IgnoredReasons ignoredReasons; | 455 AXObject::IgnoredReasons ignoredReasons; |
| 396 | 456 |
| 397 AXID axID = 0; | 457 AXID axID = 0; |
| 458 if (axObject) | |
| 459 axID = axObject->axObjectID(); | |
| 398 std::unique_ptr<AXNode> ignoredNodeObject = | 460 std::unique_ptr<AXNode> ignoredNodeObject = |
| 399 AXNode::create().setNodeId(String::number(axID)).setIgnored(true).build(); | 461 AXNode::create().setNodeId(String::number(axID)).setIgnored(true).build(); |
| 400 if (axObject) { | 462 if (axObject) { |
| 401 axObject->computeAccessibilityIsIgnored(&ignoredReasons); | 463 axObject->computeAccessibilityIsIgnored(&ignoredReasons); |
| 402 axID = axObject->axObjectID(); | 464 axID = axObject->axObjectID(); |
|
dmazzoni
2016/10/19 16:33:49
Duplicate, you just computed it above
aboxhall
2016/10/19 23:49:05
Done.
| |
| 403 AccessibilityRole role = axObject->roleValue(); | 465 AccessibilityRole role = AccessibilityRole::IgnoredRole; |
| 404 ignoredNodeObject->setRole(createRoleNameValue(role)); | 466 ignoredNodeObject->setRole(createRoleNameValue(role)); |
| 405 } else if (node && !node->layoutObject()) { | 467 |
| 468 populateRelatives(*axObject, axObject, *(ignoredNodeObject.get()), nodes, | |
| 469 cache); | |
| 470 } else if (domNode && !domNode->layoutObject()) { | |
| 471 populateDOMNodeRelatives(*domNode, *(ignoredNodeObject.get()), nodes, | |
| 472 cache); | |
| 406 ignoredReasons.append(IgnoredReason(AXNotRendered)); | 473 ignoredReasons.append(IgnoredReason(AXNotRendered)); |
| 407 } | 474 } |
| 408 | 475 |
| 476 if (domNode) | |
| 477 ignoredNodeObject->setDomNodeId(DOMNodeIds::idForNode(domNode)); | |
| 478 | |
| 409 std::unique_ptr<protocol::Array<AXProperty>> ignoredReasonProperties = | 479 std::unique_ptr<protocol::Array<AXProperty>> ignoredReasonProperties = |
| 410 protocol::Array<AXProperty>::create(); | 480 protocol::Array<AXProperty>::create(); |
| 411 for (size_t i = 0; i < ignoredReasons.size(); i++) | 481 for (size_t i = 0; i < ignoredReasons.size(); i++) |
| 412 ignoredReasonProperties->addItem(createProperty(ignoredReasons[i])); | 482 ignoredReasonProperties->addItem(createProperty(ignoredReasons[i])); |
| 413 ignoredNodeObject->setIgnoredReasons(std::move(ignoredReasonProperties)); | 483 ignoredNodeObject->setIgnoredReasons(std::move(ignoredReasonProperties)); |
| 414 | 484 |
| 415 return ignoredNodeObject; | 485 return ignoredNodeObject; |
| 416 } | 486 } |
| 417 | 487 |
| 418 std::unique_ptr<AXNode> buildProtocolAXObject(AXObject* axObject) { | 488 void InspectorAccessibilityAgent::populateDOMNodeRelatives( |
| 419 AccessibilityRole role = axObject->roleValue(); | 489 Node& inspectedDOMNode, |
| 490 AXNode& nodeObject, | |
| 491 std::unique_ptr<protocol::Array<AXNode>>& nodes, | |
| 492 AXObjectCacheImpl& cache) const { | |
| 493 // Walk up parents until an AXObject can be found. | |
| 494 Node* parentNode = inspectedDOMNode.parentNode(); | |
|
dmazzoni
2016/10/19 16:33:48
I'm not an expert at all, but I suspect you may wa
aboxhall
2016/10/19 23:49:05
That makes sense, thanks for catching.
| |
| 495 AXObject* parentAXObject = cache.getOrCreate(parentNode); | |
| 496 while (!parentAXObject) { | |
| 497 parentNode = parentNode->parentNode(); | |
| 498 parentAXObject = cache.getOrCreate(parentNode); | |
| 499 }; | |
| 500 if (parentAXObject) { | |
| 501 // Populate parent and siblings. | |
| 502 nodeObject.setParentId(String::number(parentAXObject->axObjectID())); | |
| 503 std::unique_ptr<AXNode> parentNodeObject = | |
| 504 buildProtocolAXObject(*parentAXObject, nullptr, nodes, cache); | |
| 505 std::unique_ptr<protocol::Array<AXNodeId>> siblingIds = | |
| 506 protocol::Array<AXNodeId>::create(); | |
| 507 findDOMNodeChildren(siblingIds, *parentNode, inspectedDOMNode, nodes, | |
| 508 cache); | |
| 509 parentNodeObject->setChildIds(std::move(siblingIds)); | |
| 510 nodes->addItem(std::move(parentNodeObject)); | |
| 511 } | |
| 512 // Then populate children. | |
| 513 std::unique_ptr<protocol::Array<AXNodeId>> childIds = | |
| 514 protocol::Array<AXNodeId>::create(); | |
| 515 findDOMNodeChildren(childIds, inspectedDOMNode, inspectedDOMNode, nodes, | |
| 516 cache); | |
| 517 } | |
| 518 | |
| 519 void InspectorAccessibilityAgent::findDOMNodeChildren( | |
| 520 std::unique_ptr<protocol::Array<AXNodeId>>& childIds, | |
| 521 Node& parentNode, | |
| 522 Node& inspectedDOMNode, | |
| 523 std::unique_ptr<protocol::Array<AXNode>>& nodes, | |
| 524 AXObjectCacheImpl& cache) const { | |
| 525 NodeList* childNodes = parentNode.childNodes(); | |
| 526 for (size_t i = 0; i < childNodes->length(); ++i) { | |
| 527 Node* childNode = childNodes->item(i); | |
| 528 if (childNode == &inspectedDOMNode) { | |
| 529 childIds->addItem(String::number(0)); | |
|
dmazzoni
2016/10/19 16:33:48
Can you document this magic number? Why is the ins
aboxhall
2016/10/19 23:49:05
It doesn't have an actual id - there is no AXNode
| |
| 530 continue; | |
| 531 } | |
| 532 AXObject* childAXObject = cache.getOrCreate(childNode); | |
| 533 if (childAXObject && !childAXObject->accessibilityIsIgnored()) { | |
| 534 addChild(childIds, *childAXObject, nullptr, nodes, cache); | |
| 535 continue; | |
| 536 } | |
| 537 | |
| 538 if (!childAXObject || | |
| 539 childNode->isShadowIncludingInclusiveAncestorOf(&inspectedDOMNode)) { | |
| 540 // If the inspected node may be a descendant of this node, keep walking | |
| 541 // recursively until we find its actual siblings. | |
| 542 findDOMNodeChildren(childIds, *childNode, inspectedDOMNode, nodes, cache); | |
| 543 continue; | |
| 544 } | |
| 545 | |
| 546 // Otherwise, just add the un-ignored children. | |
|
dmazzoni
2016/10/19 16:33:48
Reading through all of the special cases for build
aboxhall
2016/10/19 23:49:05
Not quite accurate - this is only called if there
aboxhall
2016/10/21 17:28:23
Ok, I tried that out and it actually doesn't buy u
| |
| 547 const AXObject::AXObjectVector& indirectChildren = | |
| 548 childAXObject->children(); | |
| 549 for (unsigned i = 0; i < indirectChildren.size(); ++i) | |
| 550 addChild(childIds, *(indirectChildren[i]), nullptr, nodes, cache); | |
| 551 } | |
| 552 } | |
| 553 | |
| 554 std::unique_ptr<AXNode> InspectorAccessibilityAgent::buildProtocolAXObject( | |
| 555 AXObject& axObject, | |
| 556 AXObject* inspectedAXObject, | |
| 557 std::unique_ptr<protocol::Array<AXNode>>& nodes, | |
| 558 AXObjectCacheImpl& cache) const { | |
| 559 AccessibilityRole role = axObject.roleValue(); | |
| 420 std::unique_ptr<AXNode> nodeObject = | 560 std::unique_ptr<AXNode> nodeObject = |
| 421 AXNode::create() | 561 AXNode::create() |
| 422 .setNodeId(String::number(axObject->axObjectID())) | 562 .setNodeId(String::number(axObject.axObjectID())) |
| 423 .setIgnored(false) | 563 .setIgnored(false) |
| 424 .build(); | 564 .build(); |
| 425 nodeObject->setRole(createRoleNameValue(role)); | 565 nodeObject->setRole(createRoleNameValue(role)); |
| 426 | 566 |
| 427 std::unique_ptr<protocol::Array<AXProperty>> properties = | 567 std::unique_ptr<protocol::Array<AXProperty>> properties = |
| 428 protocol::Array<AXProperty>::create(); | 568 protocol::Array<AXProperty>::create(); |
| 429 fillLiveRegionProperties(axObject, properties.get()); | 569 fillLiveRegionProperties(axObject, *(properties.get())); |
| 430 fillGlobalStates(axObject, properties.get()); | 570 fillGlobalStates(axObject, *(properties.get())); |
| 431 fillWidgetProperties(axObject, properties.get()); | 571 fillWidgetProperties(axObject, *(properties.get())); |
| 432 fillWidgetStates(axObject, properties.get()); | 572 fillWidgetStates(axObject, *(properties.get())); |
| 433 fillRelationships(axObject, properties.get()); | 573 fillRelationships(axObject, *(properties.get())); |
| 434 | 574 |
| 435 AXObject::NameSources nameSources; | 575 AXObject::NameSources nameSources; |
| 436 String computedName = axObject->name(&nameSources); | 576 String computedName = axObject.name(&nameSources); |
| 437 if (!nameSources.isEmpty()) { | 577 if (!nameSources.isEmpty()) { |
| 438 std::unique_ptr<AXValue> name = | 578 std::unique_ptr<AXValue> name = |
| 439 createValue(computedName, AXValueTypeEnum::ComputedString); | 579 createValue(computedName, AXValueTypeEnum::ComputedString); |
| 440 if (!nameSources.isEmpty()) { | 580 if (!nameSources.isEmpty()) { |
| 441 std::unique_ptr<protocol::Array<AXValueSource>> nameSourceProperties = | 581 std::unique_ptr<protocol::Array<AXValueSource>> nameSourceProperties = |
| 442 protocol::Array<AXValueSource>::create(); | 582 protocol::Array<AXValueSource>::create(); |
| 443 for (size_t i = 0; i < nameSources.size(); ++i) { | 583 for (size_t i = 0; i < nameSources.size(); ++i) { |
| 444 NameSource& nameSource = nameSources[i]; | 584 NameSource& nameSource = nameSources[i]; |
| 445 nameSourceProperties->addItem(createValueSource(nameSource)); | 585 nameSourceProperties->addItem(createValueSource(nameSource)); |
| 446 if (nameSource.text.isNull() || nameSource.superseded) | 586 if (nameSource.text.isNull() || nameSource.superseded) |
| 447 continue; | 587 continue; |
| 448 if (!nameSource.relatedObjects.isEmpty()) { | 588 if (!nameSource.relatedObjects.isEmpty()) { |
| 449 properties->addItem(createRelatedNodeListProperty( | 589 properties->addItem(createRelatedNodeListProperty( |
| 450 AXRelationshipAttributesEnum::Labelledby, | 590 AXRelationshipAttributesEnum::Labelledby, |
| 451 nameSource.relatedObjects)); | 591 nameSource.relatedObjects)); |
| 452 } | 592 } |
| 453 } | 593 } |
| 454 name->setSources(std::move(nameSourceProperties)); | 594 name->setSources(std::move(nameSourceProperties)); |
| 455 } | 595 } |
| 456 nodeObject->setProperties(std::move(properties)); | 596 nodeObject->setProperties(std::move(properties)); |
| 457 nodeObject->setName(std::move(name)); | 597 nodeObject->setName(std::move(name)); |
| 458 } else { | 598 } else { |
| 459 nodeObject->setProperties(std::move(properties)); | 599 nodeObject->setProperties(std::move(properties)); |
| 460 } | 600 } |
| 461 | 601 |
| 462 fillCoreProperties(axObject, nodeObject.get()); | 602 fillCoreProperties(axObject, inspectedAXObject, *(nodeObject.get()), nodes, |
| 603 cache); | |
| 463 return nodeObject; | 604 return nodeObject; |
| 464 } | 605 } |
| 465 | 606 |
| 466 } // namespace | 607 void InspectorAccessibilityAgent::fillCoreProperties( |
| 608 AXObject& axObject, | |
| 609 AXObject* inspectedAXObject, | |
| 610 AXNode& nodeObject, | |
| 611 std::unique_ptr<protocol::Array<AXNode>>& nodes, | |
| 612 AXObjectCacheImpl& cache) const { | |
| 613 AXNameFrom nameFrom; | |
| 614 AXObject::AXObjectVector nameObjects; | |
| 615 axObject.name(nameFrom, &nameObjects); | |
| 467 | 616 |
| 468 InspectorAccessibilityAgent::InspectorAccessibilityAgent( | 617 AXDescriptionFrom descriptionFrom; |
| 469 Page* page, | 618 AXObject::AXObjectVector descriptionObjects; |
| 470 InspectorDOMAgent* domAgent) | 619 String description = |
| 471 : m_page(page), m_domAgent(domAgent) {} | 620 axObject.description(nameFrom, descriptionFrom, &descriptionObjects); |
| 621 if (!description.isEmpty()) { | |
| 622 nodeObject.setDescription( | |
| 623 createValue(description, AXValueTypeEnum::ComputedString)); | |
| 624 } | |
| 625 // Value. | |
| 626 if (axObject.supportsRangeValue()) { | |
| 627 nodeObject.setValue(createValue(axObject.valueForRange())); | |
| 628 } else { | |
| 629 String stringValue = axObject.stringValue(); | |
| 630 if (!stringValue.isEmpty()) | |
| 631 nodeObject.setValue(createValue(stringValue)); | |
| 632 } | |
| 472 | 633 |
| 473 void InspectorAccessibilityAgent::getAXNodeChain( | 634 populateRelatives(axObject, inspectedAXObject, nodeObject, nodes, cache); |
| 474 ErrorString* errorString, | 635 |
| 475 int domNodeId, | 636 Node* node = axObject.getNode(); |
| 476 bool fetchAncestors, | 637 if (node) |
| 477 std::unique_ptr<protocol::Array<protocol::Accessibility::AXNode>>* nodes) { | 638 nodeObject.setDomNodeId(DOMNodeIds::idForNode(node)); |
| 478 if (!m_domAgent->enabled()) { | 639 } |
| 479 *errorString = "DOM agent must be enabled"; | 640 |
| 641 void InspectorAccessibilityAgent::populateRelatives( | |
| 642 AXObject& axObject, | |
| 643 AXObject* inspectedAXObject, | |
| 644 AXNode& nodeObject, | |
| 645 std::unique_ptr<protocol::Array<AXNode>>& nodes, | |
| 646 AXObjectCacheImpl& cache) const { | |
| 647 AXObject* parentObject = axObject.parentObject(); | |
| 648 if (parentObject && parentObject != inspectedAXObject) { | |
| 649 // Use unignored parent unless parent is inspected ignored object. | |
| 650 parentObject = axObject.parentObjectUnignored(); | |
| 651 } | |
| 652 if (parentObject) | |
| 653 nodeObject.setParentId(String::number(parentObject->axObjectID())); | |
| 654 | |
| 655 std::unique_ptr<protocol::Array<AXNodeId>> childIds = | |
| 656 protocol::Array<AXNodeId>::create(); | |
| 657 if (!inspectedAXObject) { | |
| 658 // If there is no AXObject for the inspected node, the caller will populate | |
| 659 // its relatives. | |
| 480 return; | 660 return; |
| 481 } | 661 } |
| 482 Node* node = m_domAgent->assertNode(errorString, domNodeId); | 662 |
| 483 if (!node) | 663 if (&axObject == inspectedAXObject->parentObjectUnignored() && |
| 664 inspectedAXObject->accessibilityIsIgnored()) { | |
| 665 // This is the parent of an ignored object, so search for its siblings. | |
| 666 addSiblingsOfIgnored(childIds, axObject, inspectedAXObject, nodes, cache); | |
| 667 } else { | |
| 668 addChildren(axObject, *inspectedAXObject, childIds, nodes, cache); | |
| 669 } | |
| 670 nodeObject.setChildIds(std::move(childIds)); | |
| 671 } | |
| 672 | |
| 673 void InspectorAccessibilityAgent::addSiblingsOfIgnored( | |
| 674 std::unique_ptr<protocol::Array<AXNodeId>>& childIds, | |
| 675 AXObject& parentAXObject, | |
| 676 AXObject* inspectedAXObject, | |
| 677 std::unique_ptr<protocol::Array<AXNode>>& nodes, | |
| 678 AXObjectCacheImpl& cache) const { | |
| 679 for (AXObject* childAXObject = parentAXObject.rawFirstChild(); childAXObject; | |
| 680 childAXObject = childAXObject->rawNextSibling()) { | |
| 681 if (childAXObject != inspectedAXObject && | |
| 682 childAXObject->accessibilityIsIgnored()) { | |
| 683 if (isAncestorOf(childAXObject, inspectedAXObject)) { | |
| 684 addSiblingsOfIgnored(childIds, *childAXObject, inspectedAXObject, nodes, | |
| 685 cache); | |
| 686 continue; | |
| 687 } | |
| 688 const AXObject::AXObjectVector& indirectChildren = | |
| 689 childAXObject->children(); | |
| 690 for (unsigned i = 0; i < indirectChildren.size(); ++i) { | |
| 691 addChild(childIds, *(indirectChildren[i]), inspectedAXObject, nodes, | |
| 692 cache); | |
| 693 } | |
| 694 continue; | |
| 695 } | |
| 696 addChild(childIds, *childAXObject, inspectedAXObject, nodes, cache); | |
| 697 } | |
| 698 } | |
| 699 | |
| 700 void InspectorAccessibilityAgent::addChild( | |
| 701 std::unique_ptr<protocol::Array<AXNodeId>>& childIds, | |
| 702 AXObject& childAXObject, | |
| 703 AXObject* inspectedAXObject, | |
| 704 std::unique_ptr<protocol::Array<AXNode>>& nodes, | |
| 705 AXObjectCacheImpl& cache) const { | |
| 706 childIds->addItem(String::number(childAXObject.axObjectID())); | |
| 707 if (&childAXObject == inspectedAXObject) | |
| 484 return; | 708 return; |
| 709 nodes->addItem( | |
| 710 buildProtocolAXObject(childAXObject, inspectedAXObject, nodes, cache)); | |
| 711 } | |
| 485 | 712 |
| 486 Document& document = node->document(); | 713 void InspectorAccessibilityAgent::addChildren( |
| 487 document.updateStyleAndLayoutIgnorePendingStylesheets(); | 714 AXObject& axObject, |
| 488 DocumentLifecycle::DisallowTransitionScope disallowTransition( | 715 AXObject& inspectedAXObject, |
| 489 document.lifecycle()); | 716 std::unique_ptr<protocol::Array<AXNodeId>>& childIds, |
| 490 LocalFrame* localFrame = document.frame(); | 717 std::unique_ptr<protocol::Array<AXNode>>& nodes, |
| 491 if (!localFrame) { | 718 AXObjectCacheImpl& cache) const { |
| 492 *errorString = "Frame is detached."; | 719 const AXObject::AXObjectVector& children = axObject.children(); |
| 493 return; | 720 for (unsigned i = 0; i < children.size(); i++) { |
| 494 } | 721 AXObject& childAXObject = *children[i].get(); |
| 495 std::unique_ptr<ScopedAXObjectCache> scopedCache = | 722 childIds->addItem(String::number(childAXObject.axObjectID())); |
| 496 ScopedAXObjectCache::create(document); | 723 if (&axObject == &inspectedAXObject || |
| 497 AXObjectCacheImpl* cache = toAXObjectCacheImpl(scopedCache->get()); | 724 &axObject == inspectedAXObject.parentObjectUnignored()) { |
| 498 AXObject* axObject = cache->getOrCreate(node); | 725 // Only add children/siblings of inspected node to returned nodes. |
| 499 *nodes = protocol::Array<protocol::Accessibility::AXNode>::create(); | 726 nodes->addItem(buildProtocolAXObject(childAXObject, &inspectedAXObject, |
| 500 if (!axObject || axObject->accessibilityIsIgnored()) { | 727 nodes, cache)); |
| 501 (*nodes)->addItem(buildObjectForIgnoredNode(node, axObject)); | |
| 502 } else { | |
| 503 (*nodes)->addItem(buildProtocolAXObject(axObject)); | |
| 504 } | |
| 505 | |
| 506 if (fetchAncestors && axObject) { | |
| 507 AXObject* parent = axObject->parentObjectUnignored(); | |
| 508 while (parent) { | |
| 509 (*nodes)->addItem(buildProtocolAXObject(parent)); | |
| 510 parent = parent->parentObjectUnignored(); | |
| 511 } | 728 } |
| 512 } | 729 } |
| 513 } | 730 } |
| 514 | 731 |
| 515 DEFINE_TRACE(InspectorAccessibilityAgent) { | 732 DEFINE_TRACE(InspectorAccessibilityAgent) { |
| 516 visitor->trace(m_page); | 733 visitor->trace(m_page); |
| 517 visitor->trace(m_domAgent); | 734 visitor->trace(m_domAgent); |
| 518 InspectorBaseAgent::trace(visitor); | 735 InspectorBaseAgent::trace(visitor); |
| 519 } | 736 } |
| 520 | 737 |
| 521 } // namespace blink | 738 } // namespace blink |
| OLD | NEW |