Platform.cpp (7925B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "Platform.h" 8 #include "DocAccessibleWrap.h" 9 #include "SessionAccessibility.h" 10 #include "mozilla/a11y/RemoteAccessible.h" 11 #include "mozilla/Components.h" 12 #include "nsIAccessibleEvent.h" 13 #include "nsIAccessiblePivot.h" 14 #include "nsIStringBundle.h" 15 #include "TextLeafRange.h" 16 17 #define ROLE_STRINGS_URL "chrome://global/locale/AccessFu.properties" 18 19 using namespace mozilla; 20 using namespace mozilla::a11y; 21 22 MOZ_RUNINIT static nsTHashMap<nsStringHashKey, nsString> sLocalizedStrings; 23 24 void a11y::PlatformInit() { 25 nsresult rv = NS_OK; 26 nsCOMPtr<nsIStringBundleService> stringBundleService = 27 components::StringBundle::Service(); 28 if (!stringBundleService) return; 29 30 nsCOMPtr<nsIStringBundle> stringBundle; 31 nsCOMPtr<nsIStringBundleService> sbs = components::StringBundle::Service(); 32 if (NS_FAILED(rv)) { 33 NS_WARNING("Failed to get string bundle service"); 34 return; 35 } 36 37 rv = sbs->CreateBundle(ROLE_STRINGS_URL, getter_AddRefs(stringBundle)); 38 if (NS_FAILED(rv)) { 39 NS_WARNING("Failed to get string bundle"); 40 return; 41 } 42 43 nsString localizedStr; 44 // Preload the state required localized string. 45 rv = stringBundle->GetStringFromName("stateRequired", localizedStr); 46 if (NS_SUCCEEDED(rv)) { 47 sLocalizedStrings.InsertOrUpdate(u"stateRequired"_ns, localizedStr); 48 } 49 50 // Preload heading level localized descriptions 1 thru 6. 51 for (int32_t level = 1; level <= 6; level++) { 52 nsAutoString token; 53 token.AppendPrintf("heading-%d", level); 54 55 nsAutoString formatString; 56 formatString.AppendInt(level); 57 AutoTArray<nsString, 1> formatParams; 58 formatParams.AppendElement(formatString); 59 rv = stringBundle->FormatStringFromName("headingLevel", formatParams, 60 localizedStr); 61 if (NS_SUCCEEDED(rv)) { 62 sLocalizedStrings.InsertOrUpdate(token, localizedStr); 63 } 64 } 65 66 // Preload any roles that have localized versions 67 #define ROLE(geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \ 68 msaaRole, ia2Role, androidClass, iosIsElement, uiaControlType, \ 69 nameRule) \ 70 rv = stringBundle->GetStringFromName(stringRole, localizedStr); \ 71 if (NS_SUCCEEDED(rv)) { \ 72 sLocalizedStrings.InsertOrUpdate(u##stringRole##_ns, localizedStr); \ 73 } 74 75 #include "RoleMap.h" 76 #undef ROLE 77 } 78 79 void a11y::PlatformShutdown() { sLocalizedStrings.Clear(); } 80 81 void a11y::ProxyCreated(RemoteAccessible* aProxy) { 82 SessionAccessibility::RegisterAccessible(aProxy); 83 } 84 85 void a11y::ProxyDestroyed(RemoteAccessible* aProxy) { 86 SessionAccessibility::UnregisterAccessible(aProxy); 87 } 88 89 void a11y::PlatformEvent(Accessible* aTarget, uint32_t aEventType) { 90 RefPtr<SessionAccessibility> sessionAcc = 91 SessionAccessibility::GetInstanceFor(aTarget); 92 if (!sessionAcc) { 93 return; 94 } 95 96 switch (aEventType) { 97 case nsIAccessibleEvent::EVENT_REORDER: 98 sessionAcc->SendWindowContentChangedEvent(); 99 break; 100 case nsIAccessibleEvent::EVENT_SCROLLING_START: 101 if (Accessible* result = AccessibleWrap::DoPivot( 102 aTarget, java::SessionAccessibility::HTML_GRANULARITY_DEFAULT, 103 true, true)) { 104 sessionAcc->SendAccessibilityFocusedEvent(result, false); 105 } 106 break; 107 default: 108 break; 109 } 110 } 111 112 void a11y::PlatformStateChangeEvent(Accessible* aTarget, uint64_t aState, 113 bool aEnabled) { 114 RefPtr<SessionAccessibility> sessionAcc = 115 SessionAccessibility::GetInstanceFor(aTarget); 116 117 if (!sessionAcc) { 118 return; 119 } 120 121 if (aState & states::CHECKED) { 122 sessionAcc->SendClickedEvent( 123 aTarget, java::SessionAccessibility::FLAG_CHECKABLE | 124 (aEnabled ? java::SessionAccessibility::FLAG_CHECKED : 0)); 125 } 126 127 if (aState & states::EXPANDED) { 128 sessionAcc->SendClickedEvent( 129 aTarget, 130 java::SessionAccessibility::FLAG_EXPANDABLE | 131 (aEnabled ? java::SessionAccessibility::FLAG_EXPANDED : 0)); 132 } 133 134 if (aState & states::SELECTED) { 135 sessionAcc->SendSelectedEvent(aTarget, aEnabled); 136 } 137 138 if (aState & states::BUSY) { 139 sessionAcc->SendWindowStateChangedEvent(aTarget); 140 } 141 } 142 143 void a11y::PlatformFocusEvent(Accessible* aTarget) { 144 if (RefPtr<SessionAccessibility> sessionAcc = 145 SessionAccessibility::GetInstanceFor(aTarget)) { 146 sessionAcc->SendFocusEvent(aTarget); 147 } 148 } 149 150 void a11y::PlatformCaretMoveEvent(Accessible* aTarget, int32_t aOffset, 151 bool aIsSelectionCollapsed, 152 int32_t aGranularity, bool aFromUser) { 153 RefPtr<SessionAccessibility> sessionAcc = 154 SessionAccessibility::GetInstanceFor(aTarget); 155 if (!sessionAcc) { 156 return; 157 } 158 159 if (!aTarget->IsDoc() && !aFromUser && !aIsSelectionCollapsed) { 160 // Pivot to the caret's position if it has an expanded selection. 161 // This is used mostly for find in page. 162 Accessible* leaf = TextLeafPoint::GetCaret(aTarget).mAcc; 163 MOZ_ASSERT(leaf); 164 if (leaf) { 165 if (Accessible* result = AccessibleWrap::DoPivot( 166 leaf, java::SessionAccessibility::HTML_GRANULARITY_DEFAULT, true, 167 true)) { 168 sessionAcc->SendAccessibilityFocusedEvent(result, false); 169 } 170 } 171 } 172 173 sessionAcc->SendTextSelectionChangedEvent(aTarget, aOffset); 174 } 175 176 void a11y::PlatformTextChangeEvent(Accessible* aTarget, const nsAString& aStr, 177 int32_t aStart, uint32_t aLen, 178 bool aIsInsert, bool aFromUser) { 179 RefPtr<SessionAccessibility> sessionAcc = 180 SessionAccessibility::GetInstanceFor(aTarget); 181 182 if (sessionAcc) { 183 sessionAcc->SendTextChangedEvent(aTarget, aStr, aStart, aLen, aIsInsert, 184 aFromUser); 185 } 186 } 187 188 void a11y::PlatformShowHideEvent(Accessible* aTarget, Accessible* aParent, 189 bool aInsert, bool aFromUser) { 190 // We rely on the window content changed events to be dispatched 191 // after the viewport cache is refreshed. 192 } 193 194 void a11y::PlatformSelectionEvent(Accessible*, Accessible*, uint32_t) {} 195 196 void a11y::PlatformScrollingEvent(Accessible* aTarget, uint32_t aEventType, 197 uint32_t aScrollX, uint32_t aScrollY, 198 uint32_t aMaxScrollX, uint32_t aMaxScrollY) { 199 if (aEventType == nsIAccessibleEvent::EVENT_SCROLLING) { 200 RefPtr<SessionAccessibility> sessionAcc = 201 SessionAccessibility::GetInstanceFor(aTarget); 202 203 if (sessionAcc) { 204 sessionAcc->SendScrollingEvent(aTarget, aScrollX, aScrollY, aMaxScrollX, 205 aMaxScrollY); 206 } 207 } 208 } 209 210 void a11y::PlatformAnnouncementEvent(Accessible* aTarget, 211 const nsAString& aAnnouncement, 212 uint16_t aPriority) { 213 RefPtr<SessionAccessibility> sessionAcc = 214 SessionAccessibility::GetInstanceFor(aTarget); 215 216 if (sessionAcc) { 217 sessionAcc->SendAnnouncementEvent(aTarget, aAnnouncement, aPriority); 218 } 219 } 220 221 bool a11y::LocalizeString(const nsAString& aToken, nsAString& aLocalized) { 222 MOZ_ASSERT(XRE_IsParentProcess()); 223 224 auto str = sLocalizedStrings.Lookup(aToken); 225 if (str) { 226 aLocalized.Assign(*str); 227 } else { 228 } 229 230 return !!str; 231 } 232 233 uint64_t a11y::GetCacheDomainsForKnownClients(uint64_t aCacheDomains) { 234 (void)aCacheDomains; 235 // XXX: Respond to clients such as TalkBack. For now, be safe and default to 236 // caching all domains. 237 return CacheDomain::All; 238 }