| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "content/browser/accessibility/accessibility_tree_formatter.h" | 5 #include "content/browser/accessibility/accessibility_tree_formatter.h" |
| 6 | 6 |
| 7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
| 8 | 8 |
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 10 #include "base/stringprintf.h" | |
| 11 #include "base/strings/sys_string_conversions.h" | |
| 12 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| 13 #include "content/browser/accessibility/browser_accessibility_cocoa.h" | 11 #include "content/browser/accessibility/browser_accessibility_cocoa.h" |
| 14 #include "content/browser/accessibility/browser_accessibility_mac.h" | 12 #include "content/browser/accessibility/browser_accessibility_mac.h" |
| 15 #include "content/browser/accessibility/browser_accessibility_manager.h" | 13 #include "content/browser/accessibility/browser_accessibility_manager.h" |
| 16 | 14 |
| 17 using base::StringPrintf; | |
| 18 using base::SysNSStringToUTF8; | |
| 19 using base::SysNSStringToUTF16; | |
| 20 using std::string; | |
| 21 | |
| 22 namespace content { | 15 namespace content { |
| 23 | 16 |
| 24 namespace { | 17 namespace { |
| 25 | 18 |
| 26 NSArray* ALL_ATTRIBUTES = [NSArray arrayWithObjects: | 19 string16 Format(const char *prefix, |
| 27 NSAccessibilityRoleDescriptionAttribute, | 20 id value, |
| 28 NSAccessibilityTitleAttribute, | 21 const char *suffix) { |
| 29 NSAccessibilityValueAttribute, | 22 if (value == nil) |
| 30 NSAccessibilityMinValueAttribute, | 23 return UTF8ToUTF16(""); |
| 31 NSAccessibilityMaxValueAttribute, | 24 NSString* format_str = |
| 32 NSAccessibilityValueDescriptionAttribute, | 25 [NSString stringWithFormat:@"%s%%@%s", prefix, suffix]; |
| 33 NSAccessibilityDescriptionAttribute, | 26 NSString* tmp = [NSString stringWithFormat:format_str, value]; |
| 34 NSAccessibilityHelpAttribute, | 27 return UTF8ToUTF16([tmp cStringUsingEncoding:NSUTF8StringEncoding]); |
| 35 @"AXInvalid", | 28 } |
| 36 NSAccessibilityDisclosingAttribute, | |
| 37 NSAccessibilityDisclosureLevelAttribute, | |
| 38 @"AXAccessKey", | |
| 39 @"AXARIAAtomic", | |
| 40 @"AXARIABusy", | |
| 41 @"AXARIALive", | |
| 42 @"AXARIARelevant", | |
| 43 NSAccessibilityEnabledAttribute, | |
| 44 NSAccessibilityFocusedAttribute, | |
| 45 @"AXLoaded", | |
| 46 @"AXLoadingProcess", | |
| 47 NSAccessibilityNumberOfCharactersAttribute, | |
| 48 NSAccessibilityOrientationAttribute, | |
| 49 @"AXRequired", | |
| 50 NSAccessibilityURLAttribute, | |
| 51 NSAccessibilityVisibleCharacterRangeAttribute, | |
| 52 @"AXVisited", | |
| 53 nil]; | |
| 54 | 29 |
| 55 const char* kPositionDictAttr = "position"; | 30 string16 FormatPosition(BrowserAccessibility* node) { |
| 56 const char* kXCoordDictAttr = "x"; | |
| 57 const char* kYCoordDictAttr = "y"; | |
| 58 const char* kSizeDictAttr = "size"; | |
| 59 const char* kWidthDictAttr = "width"; | |
| 60 const char* kHeightDictAttr = "height"; | |
| 61 | |
| 62 scoped_ptr<DictionaryValue> PopulatePosition(const BrowserAccessibility& node) { | |
| 63 scoped_ptr<DictionaryValue> position(new DictionaryValue); | |
| 64 // The NSAccessibility position of an object is in global coordinates and | 31 // The NSAccessibility position of an object is in global coordinates and |
| 65 // based on the lower-left corner of the object. To make this easier and less | 32 // based on the lower-left corner of the object. To make this easier and less |
| 66 // confusing, convert it to local window coordinates using the top-left | 33 // confusing, convert it to local window coordinates using the top-left |
| 67 // corner when dumping the position. | 34 // corner when dumping the position. |
| 68 BrowserAccessibility* root = node.manager()->GetRoot(); | 35 BrowserAccessibility* root = node->manager()->GetRoot(); |
| 69 BrowserAccessibilityCocoa* cocoa_root = root->ToBrowserAccessibilityCocoa(); | 36 BrowserAccessibilityCocoa* cocoa_root = root->ToBrowserAccessibilityCocoa(); |
| 70 NSPoint root_position = [[cocoa_root position] pointValue]; | 37 NSPoint root_position = [[cocoa_root position] pointValue]; |
| 71 NSSize root_size = [[cocoa_root size] sizeValue]; | 38 NSSize root_size = [[cocoa_root size] sizeValue]; |
| 72 int root_top = -static_cast<int>(root_position.y + root_size.height); | 39 int root_top = -static_cast<int>(root_position.y + root_size.height); |
| 73 int root_left = static_cast<int>(root_position.x); | 40 int root_left = static_cast<int>(root_position.x); |
| 74 | 41 |
| 75 BrowserAccessibilityCocoa* cocoa_node = | 42 BrowserAccessibilityCocoa* cocoa_node = node->ToBrowserAccessibilityCocoa(); |
| 76 const_cast<BrowserAccessibility*>(&node)->ToBrowserAccessibilityCocoa(); | |
| 77 NSPoint node_position = [[cocoa_node position] pointValue]; | 43 NSPoint node_position = [[cocoa_node position] pointValue]; |
| 78 NSSize node_size = [[cocoa_node size] sizeValue]; | 44 NSSize node_size = [[cocoa_node size] sizeValue]; |
| 79 | 45 |
| 80 position->SetInteger(kXCoordDictAttr, | 46 NSString* position_str = |
| 81 static_cast<int>(node_position.x - root_left)); | 47 [NSString stringWithFormat:@"position=(%d, %d)", |
| 82 position->SetInteger(kYCoordDictAttr, | 48 static_cast<int>(node_position.x - root_left), |
| 83 static_cast<int>(-node_position.y - node_size.height - root_top)); | 49 static_cast<int>( |
| 84 return position.Pass(); | 50 -node_position.y - node_size.height - root_top)]; |
| 51 return UTF8ToUTF16([position_str cStringUsingEncoding:NSUTF8StringEncoding]); |
| 85 } | 52 } |
| 86 | 53 |
| 87 scoped_ptr<DictionaryValue> | 54 string16 FormatSize(BrowserAccessibility* node) { |
| 88 PopulateSize(const BrowserAccessibilityCocoa* cocoa_node) { | 55 BrowserAccessibilityCocoa* cocoa_node = node->ToBrowserAccessibilityCocoa(); |
| 89 scoped_ptr<DictionaryValue> size(new DictionaryValue); | |
| 90 NSSize node_size = [[cocoa_node size] sizeValue]; | 56 NSSize node_size = [[cocoa_node size] sizeValue]; |
| 91 size->SetInteger(kHeightDictAttr, static_cast<int>(node_size.height)); | 57 NSString* size_str = |
| 92 size->SetInteger(kWidthDictAttr, static_cast<int>(node_size.width)); | 58 [NSString stringWithFormat:@"size=(%d, %d)", |
| 93 return size.Pass(); | 59 static_cast<int>(node_size.width), |
| 60 static_cast<int>(node_size.height)]; |
| 61 return UTF8ToUTF16([size_str cStringUsingEncoding:NSUTF8StringEncoding]); |
| 94 } | 62 } |
| 95 | 63 |
| 96 } // namespace | 64 } // namespace |
| 97 | 65 |
| 98 void AccessibilityTreeFormatter::Initialize() {} | 66 void AccessibilityTreeFormatter::Initialize() {} |
| 99 | 67 |
| 100 void AccessibilityTreeFormatter::AddProperties(const BrowserAccessibility& node, | 68 string16 AccessibilityTreeFormatter::ToString(BrowserAccessibility* node, |
| 101 DictionaryValue* dict) { | 69 char* prefix) { |
| 102 BrowserAccessibilityCocoa* cocoa_node = | 70 StartLine(); |
| 103 const_cast<BrowserAccessibility*>(&node)->ToBrowserAccessibilityCocoa(); | 71 NSArray* requestedAttributes = [NSArray arrayWithObjects: |
| 72 NSAccessibilityRoleDescriptionAttribute, |
| 73 NSAccessibilityTitleAttribute, |
| 74 NSAccessibilityValueAttribute, |
| 75 NSAccessibilityMinValueAttribute, |
| 76 NSAccessibilityMaxValueAttribute, |
| 77 NSAccessibilityValueDescriptionAttribute, |
| 78 NSAccessibilityDescriptionAttribute, |
| 79 NSAccessibilityHelpAttribute, |
| 80 @"AXInvalid", |
| 81 NSAccessibilityDisclosingAttribute, |
| 82 NSAccessibilityDisclosureLevelAttribute, |
| 83 @"AXAccessKey", |
| 84 @"AXARIAAtomic", |
| 85 @"AXARIABusy", |
| 86 @"AXARIALive", |
| 87 @"AXARIARelevant", |
| 88 NSAccessibilityEnabledAttribute, |
| 89 NSAccessibilityFocusedAttribute, |
| 90 @"AXLoaded", |
| 91 @"AXLoadingProcess", |
| 92 NSAccessibilityNumberOfCharactersAttribute, |
| 93 NSAccessibilityOrientationAttribute, |
| 94 @"AXRequired", |
| 95 NSAccessibilityURLAttribute, |
| 96 NSAccessibilityVisibleCharacterRangeAttribute, |
| 97 @"AXVisited", |
| 98 nil]; |
| 99 |
| 100 NSArray* defaultAttributes = [NSArray arrayWithObjects: |
| 101 NSAccessibilityTitleAttribute, |
| 102 NSAccessibilityValueAttribute, |
| 103 nil]; |
| 104 |
| 105 BrowserAccessibilityCocoa* cocoa_node = node->ToBrowserAccessibilityCocoa(); |
| 104 NSArray* supportedAttributes = [cocoa_node accessibilityAttributeNames]; | 106 NSArray* supportedAttributes = [cocoa_node accessibilityAttributeNames]; |
| 105 | 107 |
| 106 string role = SysNSStringToUTF8( | 108 Add(true, |
| 107 [cocoa_node accessibilityAttributeValue:NSAccessibilityRoleAttribute]); | 109 Format("", [cocoa_node accessibilityAttributeValue: |
| 108 dict->SetString(SysNSStringToUTF8(NSAccessibilityRoleAttribute), role); | 110 NSAccessibilityRoleAttribute], |
| 109 | 111 "")); |
| 110 NSString* subrole = | 112 Add(false, |
| 111 [cocoa_node accessibilityAttributeValue:NSAccessibilitySubroleAttribute]; | 113 Format("subrole=", [cocoa_node accessibilityAttributeValue: |
| 112 if (subrole != nil) { | 114 NSAccessibilitySubroleAttribute], |
| 113 dict->SetString(SysNSStringToUTF8(NSAccessibilitySubroleAttribute), | 115 "")); |
| 114 SysNSStringToUTF8(subrole)); | 116 for (NSString* requestedAttribute in requestedAttributes) { |
| 115 } | |
| 116 | |
| 117 for (NSString* requestedAttribute in ALL_ATTRIBUTES) { | |
| 118 if (![supportedAttributes containsObject:requestedAttribute]) { | 117 if (![supportedAttributes containsObject:requestedAttribute]) { |
| 119 continue; | 118 continue; |
| 120 } | 119 } |
| 121 id value = [cocoa_node accessibilityAttributeValue:requestedAttribute]; | 120 NSString* methodName = |
| 122 if (value != nil) { | 121 [cocoa_node methodNameForAttribute:requestedAttribute]; |
| 123 dict->SetString( | 122 Add([defaultAttributes containsObject:requestedAttribute], |
| 124 SysNSStringToUTF8(requestedAttribute), | 123 Format([[NSString stringWithFormat:@"%@='", methodName] |
| 125 SysNSStringToUTF16([NSString stringWithFormat:@"%@", value])); | 124 cStringUsingEncoding:NSUTF8StringEncoding], |
| 126 } | 125 [cocoa_node accessibilityAttributeValue: |
| 126 requestedAttribute], |
| 127 "'")); |
| 127 } | 128 } |
| 128 dict->Set(kPositionDictAttr, PopulatePosition(node).release()); | 129 Add(false, FormatPosition(node)); |
| 129 dict->Set(kSizeDictAttr, PopulateSize(cocoa_node).release()); | 130 Add(false, FormatSize(node)); |
| 130 } | |
| 131 | 131 |
| 132 string16 AccessibilityTreeFormatter::ToString(const DictionaryValue& dict, | 132 return ASCIIToUTF16(prefix) + FinishLine() + ASCIIToUTF16("\n"); |
| 133 const string16& indent) { | |
| 134 string16 line; | |
| 135 NSArray* defaultAttributes = | |
| 136 [NSArray arrayWithObjects:NSAccessibilityTitleAttribute, | |
| 137 NSAccessibilityValueAttribute, | |
| 138 nil]; | |
| 139 string s_value; | |
| 140 dict.GetString(SysNSStringToUTF8(NSAccessibilityRoleAttribute), &s_value); | |
| 141 WriteAttribute(true, UTF8ToUTF16(s_value), &line); | |
| 142 | |
| 143 string subroleAttribute = SysNSStringToUTF8(NSAccessibilitySubroleAttribute); | |
| 144 if (dict.GetString(subroleAttribute, &s_value)) { | |
| 145 WriteAttribute(false, | |
| 146 StringPrintf("%s=%s", | |
| 147 subroleAttribute.c_str(), s_value.c_str()), | |
| 148 &line); | |
| 149 } | |
| 150 | |
| 151 for (NSString* requestedAttribute in ALL_ATTRIBUTES) { | |
| 152 string requestedAttributeUTF8 = SysNSStringToUTF8(requestedAttribute); | |
| 153 if (!dict.GetString(requestedAttributeUTF8, &s_value)) | |
| 154 continue; | |
| 155 WriteAttribute([defaultAttributes containsObject:requestedAttribute], | |
| 156 StringPrintf("%s='%s'", | |
| 157 requestedAttributeUTF8.c_str(), | |
| 158 s_value.c_str()), | |
| 159 &line); | |
| 160 } | |
| 161 const DictionaryValue* d_value = NULL; | |
| 162 if (dict.GetDictionary(kPositionDictAttr, &d_value)) { | |
| 163 WriteAttribute(false, | |
| 164 FormatCoordinates(kPositionDictAttr, | |
| 165 kXCoordDictAttr, kYCoordDictAttr, | |
| 166 *d_value), | |
| 167 &line); | |
| 168 } | |
| 169 if (dict.GetDictionary(kSizeDictAttr, &d_value)) { | |
| 170 WriteAttribute(false, | |
| 171 FormatCoordinates(kSizeDictAttr, | |
| 172 kWidthDictAttr, kHeightDictAttr, *d_value), | |
| 173 &line); | |
| 174 } | |
| 175 | |
| 176 return indent + line + ASCIIToUTF16("\n"); | |
| 177 } | 133 } |
| 178 | 134 |
| 179 // static | 135 // static |
| 180 const base::FilePath::StringType | 136 const base::FilePath::StringType |
| 181 AccessibilityTreeFormatter::GetActualFileSuffix() { | 137 AccessibilityTreeFormatter::GetActualFileSuffix() { |
| 182 return FILE_PATH_LITERAL("-actual-mac.txt"); | 138 return FILE_PATH_LITERAL("-actual-mac.txt"); |
| 183 } | 139 } |
| 184 | 140 |
| 185 // static | 141 // static |
| 186 const base::FilePath::StringType | 142 const base::FilePath::StringType |
| 187 AccessibilityTreeFormatter::GetExpectedFileSuffix() { | 143 AccessibilityTreeFormatter::GetExpectedFileSuffix() { |
| 188 return FILE_PATH_LITERAL("-expected-mac.txt"); | 144 return FILE_PATH_LITERAL("-expected-mac.txt"); |
| 189 } | 145 } |
| 190 | 146 |
| 191 // static | 147 // static |
| 192 const string AccessibilityTreeFormatter::GetAllowEmptyString() { | 148 const std::string AccessibilityTreeFormatter::GetAllowEmptyString() { |
| 193 return "@MAC-ALLOW-EMPTY:"; | 149 return "@MAC-ALLOW-EMPTY:"; |
| 194 } | 150 } |
| 195 | 151 |
| 196 // static | 152 // static |
| 197 const string AccessibilityTreeFormatter::GetAllowString() { | 153 const std::string AccessibilityTreeFormatter::GetAllowString() { |
| 198 return "@MAC-ALLOW:"; | 154 return "@MAC-ALLOW:"; |
| 199 } | 155 } |
| 200 | 156 |
| 201 // static | 157 // static |
| 202 const string AccessibilityTreeFormatter::GetDenyString() { | 158 const std::string AccessibilityTreeFormatter::GetDenyString() { |
| 203 return "@MAC-DENY:"; | 159 return "@MAC-DENY:"; |
| 204 } | 160 } |
| 205 | 161 |
| 206 } // namespace content | 162 } // namespace content |
| OLD | NEW |