summaryrefslogtreecommitdiffstats
path: root/accessible/mac/mozActionElements.mm
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/mac/mozActionElements.mm')
-rw-r--r--accessible/mac/mozActionElements.mm340
1 files changed, 340 insertions, 0 deletions
diff --git a/accessible/mac/mozActionElements.mm b/accessible/mac/mozActionElements.mm
new file mode 100644
index 000000000..5decd6ccc
--- /dev/null
+++ b/accessible/mac/mozActionElements.mm
@@ -0,0 +1,340 @@
+/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "Accessible-inl.h"
+#include "DocAccessible.h"
+#include "XULTabAccessible.h"
+
+#include "nsDeckFrame.h"
+#include "nsObjCExceptions.h"
+
+using namespace mozilla::a11y;
+
+enum CheckboxValue {
+ // these constants correspond to the values in the OS
+ kUnchecked = 0,
+ kChecked = 1,
+ kMixed = 2
+};
+
+@implementation mozButtonAccessible
+
+- (NSArray*)accessibilityAttributeNames
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
+ static NSArray *attributes = nil;
+ if (!attributes) {
+ attributes = [[NSArray alloc] initWithObjects:NSAccessibilityParentAttribute, // required
+ NSAccessibilityRoleAttribute, // required
+ NSAccessibilityRoleDescriptionAttribute,
+ NSAccessibilityPositionAttribute, // required
+ NSAccessibilitySizeAttribute, // required
+ NSAccessibilityWindowAttribute, // required
+ NSAccessibilityPositionAttribute, // required
+ NSAccessibilityTopLevelUIElementAttribute, // required
+ NSAccessibilityHelpAttribute,
+ NSAccessibilityEnabledAttribute, // required
+ NSAccessibilityFocusedAttribute, // required
+ NSAccessibilityTitleAttribute, // required
+ NSAccessibilityChildrenAttribute,
+ NSAccessibilityDescriptionAttribute,
+#if DEBUG
+ @"AXMozDescription",
+#endif
+ nil];
+ }
+ return attributes;
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
+}
+
+- (id)accessibilityAttributeValue:(NSString *)attribute
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
+ if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
+ if ([self hasPopup])
+ return [self children];
+ return nil;
+ }
+
+ if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
+ if ([self isTab])
+ return utils::LocalizedString(NS_LITERAL_STRING("tab"));
+
+ return NSAccessibilityRoleDescription([self role], nil);
+ }
+
+ return [super accessibilityAttributeValue:attribute];
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
+}
+
+- (BOOL)accessibilityIsIgnored
+{
+ return ![self getGeckoAccessible] && ![self getProxyAccessible];
+}
+
+- (NSArray*)accessibilityActionNames
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
+ if ([self isEnabled]) {
+ if ([self hasPopup])
+ return [NSArray arrayWithObjects:NSAccessibilityPressAction,
+ NSAccessibilityShowMenuAction,
+ nil];
+ return [NSArray arrayWithObject:NSAccessibilityPressAction];
+ }
+ return nil;
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
+}
+
+- (NSString*)accessibilityActionDescription:(NSString*)action
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
+ if ([action isEqualToString:NSAccessibilityPressAction]) {
+ if ([self isTab])
+ return utils::LocalizedString(NS_LITERAL_STRING("switch"));
+
+ return @"press button"; // XXX: localize this later?
+ }
+
+ if ([self hasPopup]) {
+ if ([action isEqualToString:NSAccessibilityShowMenuAction])
+ return @"show menu";
+ }
+
+ return nil;
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
+}
+
+- (void)accessibilityPerformAction:(NSString*)action
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+ if ([self isEnabled] && [action isEqualToString:NSAccessibilityPressAction]) {
+ // TODO: this should bring up the menu, but currently doesn't.
+ // once msaa and atk have merged better, they will implement
+ // the action needed to show the menu.
+ [self click];
+ }
+
+ NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+- (void)click
+{
+ // both buttons and checkboxes have only one action. we should really stop using arbitrary
+ // arrays with actions, and define constants for these actions.
+ if (AccessibleWrap* accWrap = [self getGeckoAccessible])
+ accWrap->DoAction(0);
+ else if (ProxyAccessible* proxy = [self getProxyAccessible])
+ proxy->DoAction(0);
+}
+
+- (BOOL)isTab
+{
+ if (AccessibleWrap* accWrap = [self getGeckoAccessible])
+ return accWrap->Role() == roles::PAGETAB;
+
+ if (ProxyAccessible* proxy = [self getProxyAccessible])
+ return proxy->Role() == roles::PAGETAB;
+
+ return false;
+}
+
+- (BOOL)hasPopup
+{
+ if (AccessibleWrap* accWrap = [self getGeckoAccessible])
+ return accWrap->NativeState() & states::HASPOPUP;
+
+ if (ProxyAccessible* proxy = [self getProxyAccessible])
+ return proxy->NativeState() & states::HASPOPUP;
+
+ return false;
+}
+
+@end
+
+@implementation mozCheckboxAccessible
+
+- (NSString*)accessibilityActionDescription:(NSString*)action
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
+ if ([action isEqualToString:NSAccessibilityPressAction]) {
+ if ([self isChecked] != kUnchecked)
+ return @"uncheck checkbox"; // XXX: localize this later?
+
+ return @"check checkbox"; // XXX: localize this later?
+ }
+
+ return nil;
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
+}
+
+- (int)isChecked
+{
+ uint64_t state = 0;
+ if (AccessibleWrap* accWrap = [self getGeckoAccessible])
+ state = accWrap->NativeState();
+ else if (ProxyAccessible* proxy = [self getProxyAccessible])
+ state = proxy->NativeState();
+
+ // check if we're checked or in a mixed state
+ if (state & states::CHECKED) {
+ return (state & states::MIXED) ? kMixed : kChecked;
+ }
+
+ return kUnchecked;
+}
+
+- (id)value
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
+ return [NSNumber numberWithInt:[self isChecked]];
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
+}
+
+@end
+
+@implementation mozTabsAccessible
+
+- (void)dealloc
+{
+ [mTabs release];
+
+ [super dealloc];
+}
+
+- (NSArray*)accessibilityAttributeNames
+{
+ // standard attributes that are shared and supported by root accessible (AXMain) elements.
+ static NSMutableArray* attributes = nil;
+
+ if (!attributes) {
+ attributes = [[super accessibilityAttributeNames] mutableCopy];
+ [attributes addObject:NSAccessibilityContentsAttribute];
+ [attributes addObject:NSAccessibilityTabsAttribute];
+ }
+
+ return attributes;
+}
+
+- (id)accessibilityAttributeValue:(NSString *)attribute
+{
+ if ([attribute isEqualToString:NSAccessibilityContentsAttribute])
+ return [super children];
+ if ([attribute isEqualToString:NSAccessibilityTabsAttribute])
+ return [self tabs];
+
+ return [super accessibilityAttributeValue:attribute];
+}
+
+/**
+ * Returns the selected tab (the mozAccessible)
+ */
+- (id)value
+{
+ mozAccessible* nativeAcc = nil;
+ if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
+ if (Accessible* accTab = accWrap->GetSelectedItem(0)) {
+ accTab->GetNativeInterface((void**)&nativeAcc);
+ }
+ } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
+ if (ProxyAccessible* proxyTab = proxy->GetSelectedItem(0)) {
+ nativeAcc = GetNativeFromProxy(proxyTab);
+ }
+ }
+
+ return nativeAcc;
+}
+
+/**
+ * Return the mozAccessibles that are the tabs.
+ */
+- (id)tabs
+{
+ if (mTabs)
+ return mTabs;
+
+ NSArray* children = [self children];
+ NSEnumerator* enumerator = [children objectEnumerator];
+ mTabs = [[NSMutableArray alloc] init];
+
+ id obj;
+ while ((obj = [enumerator nextObject]))
+ if ([obj isTab])
+ [mTabs addObject:obj];
+
+ return mTabs;
+}
+
+- (void)invalidateChildren
+{
+ [super invalidateChildren];
+
+ [mTabs release];
+ mTabs = nil;
+}
+
+@end
+
+@implementation mozPaneAccessible
+
+- (NSUInteger)accessibilityArrayAttributeCount:(NSString*)attribute
+{
+ AccessibleWrap* accWrap = [self getGeckoAccessible];
+ ProxyAccessible* proxy = [self getProxyAccessible];
+ if (!accWrap && !proxy)
+ return 0;
+
+ // By default this calls -[[mozAccessible children] count].
+ // Since we don't cache mChildren. This is faster.
+ if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
+ if (accWrap)
+ return accWrap->ChildCount() ? 1 : 0;
+
+ return proxy->ChildrenCount() ? 1 : 0;
+ }
+
+ return [super accessibilityArrayAttributeCount:attribute];
+}
+
+- (NSArray*)children
+{
+ if (![self getGeckoAccessible])
+ return nil;
+
+ nsDeckFrame* deckFrame = do_QueryFrame([self getGeckoAccessible]->GetFrame());
+ nsIFrame* selectedFrame = deckFrame ? deckFrame->GetSelectedBox() : nullptr;
+
+ Accessible* selectedAcc = nullptr;
+ if (selectedFrame) {
+ nsINode* node = selectedFrame->GetContent();
+ selectedAcc = [self getGeckoAccessible]->Document()->GetAccessible(node);
+ }
+
+ if (selectedAcc) {
+ mozAccessible *curNative = GetNativeFromGeckoAccessible(selectedAcc);
+ if (curNative)
+ return [NSArray arrayWithObjects:GetObjectOrRepresentedView(curNative), nil];
+ }
+
+ return nil;
+}
+
+@end