2 /* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #import "mozActionElements.h"
11 #include "LocalAccessible-inl.h"
12 #include "DocAccessible.h"
13 #include "XULTabAccessible.h"
14 #include "HTMLFormControlAccessible.h"
16 #include "nsCocoaUtils.h"
17 #include "mozilla/FloatingPoint.h"
19 using namespace mozilla::a11y;
21 @implementation mozButtonAccessible
23 - (NSNumber*)moxHasPopup {
24 return @([self stateWithMask:states::HASPOPUP] != 0);
27 - (NSString*)moxPopupValue {
28 if ([self stateWithMask:states::HASPOPUP] != 0) {
29 return utils::GetAccAttr(self, nsGkAtoms::aria_haspopup);
37 @implementation mozPopupButtonAccessible
39 - (NSString*)moxTitle {
40 // Popup buttons don't have titles.
44 - (BOOL)moxBlockSelector:(SEL)selector {
45 if (selector == @selector(moxHasPopup)) {
49 return [super moxBlockSelector:selector];
52 - (NSArray*)moxChildren {
53 if ([self stateWithMask:states::EXPANDED] == 0) {
54 // If the popup button is collapsed don't return its children.
58 return [super moxChildren];
61 - (void)stateChanged:(uint64_t)state isEnabled:(BOOL)enabled {
62 [super stateChanged:state isEnabled:enabled];
64 if (state == states::EXPANDED) {
65 // If the EXPANDED state is updated, fire AXMenu events on the
66 // popups child which is the actual menu.
67 if (mozAccessible* popup = (mozAccessible*)[self childAt:0]) {
68 [popup moxPostNotification:(enabled ? @"AXMenuOpened" : @"AXMenuClosed")];
75 @implementation mozRadioButtonAccessible
77 - (NSArray*)moxLinkedUIElements {
78 return [[self getRelationsByType:RelationType::MEMBER_OF]
79 arrayByAddingObjectsFromArray:[super moxLinkedUIElements]];
84 @implementation mozCheckboxAccessible
87 // check if we're checked or in a mixed state
89 [self stateWithMask:(states::CHECKED | states::PRESSED | states::MIXED)];
90 if (state & (states::CHECKED | states::PRESSED)) {
94 if (state & states::MIXED) {
102 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
104 return [NSNumber numberWithInt:[self isChecked]];
106 NS_OBJC_END_TRY_BLOCK_RETURN(nil);
109 - (void)stateChanged:(uint64_t)state isEnabled:(BOOL)enabled {
110 [super stateChanged:state isEnabled:enabled];
112 if (state & (states::CHECKED | states::PRESSED | states::MIXED)) {
113 [self moxPostNotification:NSAccessibilityValueChangedNotification];
119 @implementation mozPaneAccessible
121 - (NSArray*)moxChildren {
122 // By default, all tab panels are exposed in the a11y tree
123 // even if the tab they represent isn't the active tab. To
124 // prevent VoiceOver from navigating background tab content,
125 // only expose the tab panel that is currently on screen.
126 for (mozAccessible* child in [super moxChildren]) {
127 if (!([child state] & states::OFFSCREEN)) {
128 return [NSArray arrayWithObject:GetObjectOrRepresentedView(child)];
131 MOZ_ASSERT_UNREACHABLE("We have no on screen tab content?");
137 @implementation mozIncrementableAccessible
140 return [NSNumber numberWithDouble:mGeckoAccessible->CurValue()];
143 - (NSString*)moxValueDescription {
144 nsAutoString valueDesc;
145 mGeckoAccessible->Value(valueDesc);
146 return nsCocoaUtils::ToNSString(valueDesc);
149 return [NSNumber numberWithDouble:mGeckoAccessible->MinValue()];
153 return [NSNumber numberWithDouble:mGeckoAccessible->MaxValue()];
156 - (void)moxSetValue:(id)value {
157 [self setValue:([value doubleValue])];
160 - (void)moxPerformIncrement {
161 [self changeValueBySteps:1];
164 - (void)moxPerformDecrement {
165 [self changeValueBySteps:-1];
168 - (NSString*)moxOrientation {
169 RefPtr<AccAttributes> attributes = mGeckoAccessible->Attributes();
172 attributes->GetAttribute(nsGkAtoms::aria_orientation, result);
173 if (result.Equals(u"horizontal"_ns)) {
174 return NSAccessibilityHorizontalOrientationValue;
175 } else if (result.Equals(u"vertical"_ns)) {
176 return NSAccessibilityVerticalOrientationValue;
180 return NSAccessibilityUnknownOrientationValue;
183 - (void)handleAccessibleEvent:(uint32_t)eventType {
185 case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE:
186 case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
187 [self moxPostNotification:NSAccessibilityValueChangedNotification];
190 [super handleAccessibleEvent:eventType];
196 * Updates the accessible's current value by factor and step.
198 * factor: A signed integer representing the number of times to
199 * apply step to the current value. A positive value will increment,
200 * while a negative one will decrement.
201 * step: An unsigned integer specified by the webauthor and indicating the
202 * amount by which to increment/decrement the current value.
204 - (void)changeValueBySteps:(int)factor {
205 MOZ_ASSERT(mGeckoAccessible, "mGeckoAccessible is null");
208 mGeckoAccessible->CurValue() + (mGeckoAccessible->Step() * factor);
209 [self setValue:(newValue)];
213 * Updates the accessible's current value to the specified value
215 - (void)setValue:(double)value {
216 MOZ_ASSERT(mGeckoAccessible, "mGeckoAccessible is null");
217 mGeckoAccessible->SetCurValue(value);
222 @implementation mozDatePickerAccessible
224 - (NSString*)moxTitle {
225 return utils::LocalizedString(u"dateField"_ns);