2020-08-26 00:40:32 +03:00
|
|
|
/* clang-format off */
|
2006-11-24 17:37:00 +03:00
|
|
|
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2020-08-26 00:40:32 +03:00
|
|
|
/* clang-format on */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* 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/. */
|
2006-11-24 17:37:00 +03:00
|
|
|
|
2006-11-15 14:08:14 +03:00
|
|
|
#import "mozActionElements.h"
|
2012-01-27 10:14:09 +04:00
|
|
|
|
|
|
|
#import "MacUtils.h"
|
2021-02-20 02:14:32 +03:00
|
|
|
#include "LocalAccessible-inl.h"
|
2012-06-29 03:04:50 +04:00
|
|
|
#include "DocAccessible.h"
|
2012-06-11 03:44:50 +04:00
|
|
|
#include "XULTabAccessible.h"
|
2020-05-29 20:37:46 +03:00
|
|
|
#include "HTMLFormControlAccessible.h"
|
2006-11-15 14:08:14 +03:00
|
|
|
|
2012-06-29 03:04:50 +04:00
|
|
|
#include "nsDeckFrame.h"
|
2008-02-22 23:13:17 +03:00
|
|
|
#include "nsObjCExceptions.h"
|
|
|
|
|
2011-07-27 16:43:01 +04:00
|
|
|
using namespace mozilla::a11y;
|
|
|
|
|
2006-11-24 17:37:00 +03:00
|
|
|
enum CheckboxValue {
|
|
|
|
// these constants correspond to the values in the OS
|
|
|
|
kUnchecked = 0,
|
|
|
|
kChecked = 1,
|
|
|
|
kMixed = 2
|
|
|
|
};
|
|
|
|
|
2006-11-15 14:08:14 +03:00
|
|
|
@implementation mozButtonAccessible
|
|
|
|
|
2020-05-29 02:02:52 +03:00
|
|
|
- (NSNumber*)moxHasPopup {
|
|
|
|
return @([self stateWithMask:states::HASPOPUP] != 0);
|
2006-11-15 14:08:14 +03:00
|
|
|
}
|
|
|
|
|
2020-05-29 02:02:52 +03:00
|
|
|
- (NSString*)moxPopupValue {
|
|
|
|
if ([self stateWithMask:states::HASPOPUP] != 0) {
|
|
|
|
return utils::GetAccAttr(self, "haspopup");
|
2020-05-07 21:07:34 +03:00
|
|
|
}
|
|
|
|
|
2020-05-29 02:02:52 +03:00
|
|
|
return nil;
|
2015-05-29 18:41:54 +03:00
|
|
|
}
|
|
|
|
|
2006-11-15 14:08:14 +03:00
|
|
|
@end
|
|
|
|
|
2020-05-16 00:31:08 +03:00
|
|
|
@implementation mozPopupButtonAccessible
|
2020-05-29 02:02:52 +03:00
|
|
|
|
2020-05-29 01:41:13 +03:00
|
|
|
- (NSString*)moxTitle {
|
2020-05-16 00:31:08 +03:00
|
|
|
// Popup buttons don't have titles.
|
|
|
|
return @"";
|
|
|
|
}
|
|
|
|
|
2020-05-29 02:02:52 +03:00
|
|
|
- (BOOL)moxBlockSelector:(SEL)selector {
|
|
|
|
if (selector == @selector(moxHasPopup)) {
|
|
|
|
return YES;
|
2020-05-16 00:31:08 +03:00
|
|
|
}
|
|
|
|
|
2020-05-29 02:02:52 +03:00
|
|
|
return [super moxBlockSelector:selector];
|
2020-05-16 00:31:08 +03:00
|
|
|
}
|
|
|
|
|
2020-05-29 01:41:13 +03:00
|
|
|
- (NSArray*)moxChildren {
|
2020-05-16 00:31:08 +03:00
|
|
|
if ([self stateWithMask:states::EXPANDED] == 0) {
|
|
|
|
// If the popup button is collapsed don't return its children.
|
|
|
|
return @[];
|
|
|
|
}
|
|
|
|
|
2020-05-29 01:41:13 +03:00
|
|
|
return [super moxChildren];
|
2020-05-16 00:31:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
- (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]) {
|
2020-05-27 20:24:44 +03:00
|
|
|
[popup moxPostNotification:(enabled ? @"AXMenuOpened" : @"AXMenuClosed")];
|
2020-05-16 00:31:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2020-05-29 20:37:46 +03:00
|
|
|
@implementation mozRadioButtonAccessible
|
|
|
|
|
2021-01-15 20:22:56 +03:00
|
|
|
- (NSArray*)moxLinkedUIElements {
|
|
|
|
return [[self getRelationsByType:RelationType::MEMBER_OF]
|
|
|
|
arrayByAddingObjectsFromArray:[super moxLinkedUIElements]];
|
2020-05-29 20:37:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2006-11-15 14:08:14 +03:00
|
|
|
@implementation mozCheckboxAccessible
|
|
|
|
|
2006-11-24 17:37:00 +03:00
|
|
|
- (int)isChecked {
|
|
|
|
// check if we're checked or in a mixed state
|
2020-08-26 00:40:32 +03:00
|
|
|
uint64_t state =
|
|
|
|
[self stateWithMask:(states::CHECKED | states::PRESSED | states::MIXED)];
|
2020-03-14 08:39:59 +03:00
|
|
|
if (state & (states::CHECKED | states::PRESSED)) {
|
|
|
|
return kChecked;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state & states::MIXED) {
|
|
|
|
return kMixed;
|
2006-11-24 17:37:00 +03:00
|
|
|
}
|
2015-06-08 17:59:19 +03:00
|
|
|
|
2006-11-24 17:37:00 +03:00
|
|
|
return kUnchecked;
|
2006-11-15 14:08:14 +03:00
|
|
|
}
|
|
|
|
|
2020-05-29 01:41:13 +03:00
|
|
|
- (id)moxValue {
|
2021-02-17 01:55:21 +03:00
|
|
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
2008-02-22 23:13:17 +03:00
|
|
|
|
2006-11-24 17:37:00 +03:00
|
|
|
return [NSNumber numberWithInt:[self isChecked]];
|
2008-02-22 23:13:17 +03:00
|
|
|
|
2021-02-17 01:55:21 +03:00
|
|
|
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
2006-11-15 14:08:14 +03:00
|
|
|
}
|
|
|
|
|
2020-12-01 12:29:56 +03:00
|
|
|
- (void)stateChanged:(uint64_t)state isEnabled:(BOOL)enabled {
|
|
|
|
[super stateChanged:state isEnabled:enabled];
|
|
|
|
|
|
|
|
if (state & (states::CHECKED | states::PRESSED | states::MIXED)) {
|
|
|
|
[self moxPostNotification:NSAccessibilityValueChangedNotification];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-15 14:08:14 +03:00
|
|
|
@end
|
2006-12-06 16:35:56 +03:00
|
|
|
|
2012-06-29 03:04:50 +04:00
|
|
|
@implementation mozPaneAccessible
|
|
|
|
|
2020-05-29 01:41:13 +03:00
|
|
|
- (NSArray*)moxChildren {
|
2020-05-27 18:50:47 +03:00
|
|
|
if (!mGeckoAccessible.AsAccessible()) return nil;
|
2012-06-29 03:04:50 +04:00
|
|
|
|
2020-08-26 00:40:32 +03:00
|
|
|
nsDeckFrame* deckFrame =
|
|
|
|
do_QueryFrame(mGeckoAccessible.AsAccessible()->GetFrame());
|
2012-07-30 18:20:58 +04:00
|
|
|
nsIFrame* selectedFrame = deckFrame ? deckFrame->GetSelectedBox() : nullptr;
|
2012-06-29 03:04:50 +04:00
|
|
|
|
2021-02-20 02:14:32 +03:00
|
|
|
LocalAccessible* selectedAcc = nullptr;
|
2012-06-29 03:04:50 +04:00
|
|
|
if (selectedFrame) {
|
|
|
|
nsINode* node = selectedFrame->GetContent();
|
2020-08-26 00:40:32 +03:00
|
|
|
selectedAcc =
|
|
|
|
mGeckoAccessible.AsAccessible()->Document()->GetAccessible(node);
|
2012-06-29 03:04:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (selectedAcc) {
|
|
|
|
mozAccessible* curNative = GetNativeFromGeckoAccessible(selectedAcc);
|
2020-08-26 00:40:32 +03:00
|
|
|
if (curNative)
|
|
|
|
return
|
|
|
|
[NSArray arrayWithObjects:GetObjectOrRepresentedView(curNative), nil];
|
2012-06-29 03:04:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
2020-03-17 20:32:33 +03:00
|
|
|
|
2020-04-28 20:20:16 +03:00
|
|
|
@implementation mozIncrementableAccessible
|
2020-03-17 20:32:33 +03:00
|
|
|
|
2021-03-16 19:17:53 +03:00
|
|
|
- (void)moxSetValue:(id)value {
|
|
|
|
[self setValue:([value doubleValue])];
|
|
|
|
}
|
|
|
|
|
2020-05-29 02:02:52 +03:00
|
|
|
- (void)moxPerformIncrement {
|
|
|
|
[self changeValueBySteps:1];
|
2020-03-17 20:32:33 +03:00
|
|
|
}
|
|
|
|
|
2020-05-29 02:02:52 +03:00
|
|
|
- (void)moxPerformDecrement {
|
|
|
|
[self changeValueBySteps:-1];
|
|
|
|
}
|
2020-03-17 20:32:33 +03:00
|
|
|
|
2020-05-29 02:02:52 +03:00
|
|
|
- (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;
|
2020-03-17 20:32:33 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2021-03-16 19:17:53 +03:00
|
|
|
* 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.
|
2020-03-17 20:32:33 +03:00
|
|
|
*/
|
|
|
|
- (void)changeValueBySteps:(int)factor {
|
2021-03-16 19:17:53 +03:00
|
|
|
MOZ_ASSERT(!mGeckoAccessible.IsNull(), "mGeckoAccessible is null");
|
|
|
|
|
|
|
|
if (LocalAccessible* acc = mGeckoAccessible.AsAccessible()) {
|
|
|
|
double newValue = acc->CurValue() + (acc->Step() * factor);
|
|
|
|
[self setValue:(newValue)];
|
|
|
|
} else {
|
|
|
|
RemoteAccessible* proxy = mGeckoAccessible.AsProxy();
|
|
|
|
double newValue = proxy->CurValue() + (proxy->Step() * factor);
|
|
|
|
[self setValue:(newValue)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Updates the accessible's current value to the specified value
|
|
|
|
*/
|
|
|
|
- (void)setValue:(double)value {
|
|
|
|
MOZ_ASSERT(!mGeckoAccessible.IsNull(), "mGeckoAccessible is null");
|
2020-03-17 20:32:33 +03:00
|
|
|
|
2021-02-20 02:14:32 +03:00
|
|
|
if (LocalAccessible* acc = mGeckoAccessible.AsAccessible()) {
|
2020-05-27 18:50:47 +03:00
|
|
|
double min = acc->MinValue();
|
|
|
|
double max = acc->MaxValue();
|
2020-04-28 20:20:16 +03:00
|
|
|
// Because min and max are not required attributes, we first check
|
|
|
|
// if the value is undefined. If this check fails,
|
2021-03-16 19:17:53 +03:00
|
|
|
// the value is defined, and we verify our new value falls
|
2020-04-28 20:20:16 +03:00
|
|
|
// within the bound (inclusive).
|
2021-03-16 19:17:53 +03:00
|
|
|
if ((IsNaN(min) || value >= min) && (IsNaN(max) || value <= max)) {
|
|
|
|
acc->SetCurValue(value);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RemoteAccessible* proxy = mGeckoAccessible.AsProxy();
|
|
|
|
double min = proxy->MinValue();
|
|
|
|
double max = proxy->MaxValue();
|
|
|
|
// As above, check if the value is within bounds.
|
|
|
|
if ((IsNaN(min) || value >= min) && (IsNaN(max) || value <= max)) {
|
|
|
|
proxy->SetCurValue(value);
|
2020-03-17 20:32:33 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|