summaryrefslogtreecommitdiffstats
path: root/accessible/mac/mozActionElements.mm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /accessible/mac/mozActionElements.mm
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'accessible/mac/mozActionElements.mm')
-rw-r--r--accessible/mac/mozActionElements.mm228
1 files changed, 228 insertions, 0 deletions
diff --git a/accessible/mac/mozActionElements.mm b/accessible/mac/mozActionElements.mm
new file mode 100644
index 0000000000..f39f2c8ad5
--- /dev/null
+++ b/accessible/mac/mozActionElements.mm
@@ -0,0 +1,228 @@
+/* clang-format off */
+/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* clang-format on */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#import "mozActionElements.h"
+
+#import "MacUtils.h"
+#include "LocalAccessible-inl.h"
+#include "DocAccessible.h"
+#include "XULTabAccessible.h"
+#include "HTMLFormControlAccessible.h"
+
+#include "nsCocoaUtils.h"
+#include "mozilla/FloatingPoint.h"
+
+using namespace mozilla::a11y;
+
+@implementation mozButtonAccessible
+
+- (NSNumber*)moxHasPopup {
+ return @([self stateWithMask:states::HASPOPUP] != 0);
+}
+
+- (NSString*)moxPopupValue {
+ if ([self stateWithMask:states::HASPOPUP] != 0) {
+ return utils::GetAccAttr(self, nsGkAtoms::aria_haspopup);
+ }
+
+ return nil;
+}
+
+@end
+
+@implementation mozPopupButtonAccessible
+
+- (NSString*)moxTitle {
+ // Popup buttons don't have titles.
+ return @"";
+}
+
+- (BOOL)moxBlockSelector:(SEL)selector {
+ if (selector == @selector(moxHasPopup)) {
+ return YES;
+ }
+
+ return [super moxBlockSelector:selector];
+}
+
+- (NSArray*)moxChildren {
+ if ([self stateWithMask:states::EXPANDED] == 0) {
+ // If the popup button is collapsed don't return its children.
+ return @[];
+ }
+
+ return [super moxChildren];
+}
+
+- (void)stateChanged:(uint64_t)state isEnabled:(BOOL)enabled {
+ [super stateChanged:state isEnabled:enabled];
+
+ if (state == states::EXPANDED) {
+ // If the EXPANDED state is updated, fire AXMenu events on the
+ // popups child which is the actual menu.
+ if (mozAccessible* popup = (mozAccessible*)[self childAt:0]) {
+ [popup moxPostNotification:(enabled ? @"AXMenuOpened" : @"AXMenuClosed")];
+ }
+ }
+}
+
+@end
+
+@implementation mozRadioButtonAccessible
+
+- (NSArray*)moxLinkedUIElements {
+ return [[self getRelationsByType:RelationType::MEMBER_OF]
+ arrayByAddingObjectsFromArray:[super moxLinkedUIElements]];
+}
+
+@end
+
+@implementation mozCheckboxAccessible
+
+- (int)isChecked {
+ // check if we're checked or in a mixed state
+ uint64_t state =
+ [self stateWithMask:(states::CHECKED | states::PRESSED | states::MIXED)];
+ if (state & (states::CHECKED | states::PRESSED)) {
+ return kChecked;
+ }
+
+ if (state & states::MIXED) {
+ return kMixed;
+ }
+
+ return kUnchecked;
+}
+
+- (id)moxValue {
+ NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
+
+ return [NSNumber numberWithInt:[self isChecked]];
+
+ NS_OBJC_END_TRY_BLOCK_RETURN(nil);
+}
+
+- (void)stateChanged:(uint64_t)state isEnabled:(BOOL)enabled {
+ [super stateChanged:state isEnabled:enabled];
+
+ if (state & (states::CHECKED | states::PRESSED | states::MIXED)) {
+ [self moxPostNotification:NSAccessibilityValueChangedNotification];
+ }
+}
+
+@end
+
+@implementation mozPaneAccessible
+
+- (NSArray*)moxChildren {
+ // By default, all tab panels are exposed in the a11y tree
+ // even if the tab they represent isn't the active tab. To
+ // prevent VoiceOver from navigating background tab content,
+ // only expose the tab panel that is currently on screen.
+ for (mozAccessible* child in [super moxChildren]) {
+ if (!([child state] & states::OFFSCREEN)) {
+ return [NSArray arrayWithObject:GetObjectOrRepresentedView(child)];
+ }
+ }
+ MOZ_ASSERT_UNREACHABLE("We have no on screen tab content?");
+ return @[];
+}
+
+@end
+
+@implementation mozIncrementableAccessible
+
+- (id)moxValue {
+ return [NSNumber numberWithDouble:mGeckoAccessible->CurValue()];
+}
+
+- (NSString*)moxValueDescription {
+ nsAutoString valueDesc;
+ mGeckoAccessible->Value(valueDesc);
+ return nsCocoaUtils::ToNSString(valueDesc);
+}
+- (id)moxMinValue {
+ return [NSNumber numberWithDouble:mGeckoAccessible->MinValue()];
+}
+
+- (id)moxMaxValue {
+ return [NSNumber numberWithDouble:mGeckoAccessible->MaxValue()];
+}
+
+- (void)moxSetValue:(id)value {
+ [self setValue:([value doubleValue])];
+}
+
+- (void)moxPerformIncrement {
+ [self changeValueBySteps:1];
+}
+
+- (void)moxPerformDecrement {
+ [self changeValueBySteps:-1];
+}
+
+- (NSString*)moxOrientation {
+ RefPtr<AccAttributes> attributes = mGeckoAccessible->Attributes();
+ if (attributes) {
+ nsAutoString result;
+ attributes->GetAttribute(nsGkAtoms::aria_orientation, result);
+ if (result.Equals(u"horizontal"_ns)) {
+ return NSAccessibilityHorizontalOrientationValue;
+ } else if (result.Equals(u"vertical"_ns)) {
+ return NSAccessibilityVerticalOrientationValue;
+ }
+ }
+
+ return NSAccessibilityUnknownOrientationValue;
+}
+
+- (void)handleAccessibleEvent:(uint32_t)eventType {
+ switch (eventType) {
+ case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE:
+ case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
+ [self moxPostNotification:NSAccessibilityValueChangedNotification];
+ break;
+ default:
+ [super handleAccessibleEvent:eventType];
+ break;
+ }
+}
+
+/*
+ * Updates the accessible's current value by factor and step.
+ *
+ * factor: A signed integer representing the number of times to
+ * apply step to the current value. A positive value will increment,
+ * while a negative one will decrement.
+ * step: An unsigned integer specified by the webauthor and indicating the
+ * amount by which to increment/decrement the current value.
+ */
+- (void)changeValueBySteps:(int)factor {
+ MOZ_ASSERT(mGeckoAccessible, "mGeckoAccessible is null");
+
+ double newValue =
+ mGeckoAccessible->CurValue() + (mGeckoAccessible->Step() * factor);
+ [self setValue:(newValue)];
+}
+
+/*
+ * Updates the accessible's current value to the specified value
+ */
+- (void)setValue:(double)value {
+ MOZ_ASSERT(mGeckoAccessible, "mGeckoAccessible is null");
+ mGeckoAccessible->SetCurValue(value);
+}
+
+@end
+
+@implementation mozDatePickerAccessible
+
+- (NSString*)moxTitle {
+ return utils::LocalizedString(u"dateField"_ns);
+}
+
+@end