2012-06-07 04:26:45 +04:00
|
|
|
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=2 et sw=2 tw=80: */
|
|
|
|
/* 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 <Cocoa/Cocoa.h>
|
|
|
|
|
2012-12-02 04:58:25 +04:00
|
|
|
#include "Platform.h"
|
2015-05-29 20:42:23 +03:00
|
|
|
#include "ProxyAccessible.h"
|
2016-06-10 00:33:48 +03:00
|
|
|
#include "DocAccessibleParent.h"
|
2015-10-01 17:00:00 +03:00
|
|
|
#include "mozTableAccessible.h"
|
2012-06-07 04:26:45 +04:00
|
|
|
|
|
|
|
#include "nsAppShell.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace a11y {
|
|
|
|
|
2012-06-20 03:19:13 +04:00
|
|
|
// Mac a11y whitelisting
|
2012-06-07 04:26:45 +04:00
|
|
|
static bool sA11yShouldBeEnabled = false;
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
bool ShouldA11yBeEnabled() {
|
2012-06-20 03:19:13 +04:00
|
|
|
EPlatformDisabledState disabledState = PlatformDisabledState();
|
2019-01-21 20:18:16 +03:00
|
|
|
return (disabledState == ePlatformIsForceEnabled) ||
|
|
|
|
((disabledState == ePlatformIsEnabled) && sA11yShouldBeEnabled);
|
2012-06-07 04:26:45 +04:00
|
|
|
}
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
void PlatformInit() {}
|
2012-12-02 04:58:25 +04:00
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
void PlatformShutdown() {}
|
2012-12-02 04:58:25 +04:00
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
void ProxyCreated(ProxyAccessible* aProxy, uint32_t) {
|
2015-05-29 20:42:23 +03:00
|
|
|
// Pass in dummy state for now as retrieving proxy state requires IPC.
|
2015-10-01 17:00:00 +03:00
|
|
|
// Note that we can use ProxyAccessible::IsTable* functions here because they
|
|
|
|
// do not use IPC calls but that might change after bug 1210477.
|
|
|
|
Class type;
|
|
|
|
if (aProxy->IsTable())
|
|
|
|
type = [mozTableAccessible class];
|
|
|
|
else if (aProxy->IsTableRow())
|
|
|
|
type = [mozTableRowAccessible class];
|
|
|
|
else if (aProxy->IsTableCell())
|
|
|
|
type = [mozTableCellAccessible class];
|
|
|
|
else
|
|
|
|
type = GetTypeFromRole(aProxy->Role());
|
|
|
|
|
2015-05-29 20:42:23 +03:00
|
|
|
uintptr_t accWrap = reinterpret_cast<uintptr_t>(aProxy) | IS_PROXY;
|
|
|
|
mozAccessible* mozWrapper = [[type alloc] initWithAccessible:accWrap];
|
|
|
|
aProxy->SetWrapper(reinterpret_cast<uintptr_t>(mozWrapper));
|
2016-06-10 00:33:48 +03:00
|
|
|
|
2016-06-10 00:33:48 +03:00
|
|
|
mozAccessible* nativeParent = nullptr;
|
2016-06-10 00:33:48 +03:00
|
|
|
if (aProxy->IsDoc() && aProxy->AsDoc()->IsTopLevel()) {
|
2016-06-10 00:33:48 +03:00
|
|
|
// If proxy is top level, the parent we need to invalidate the children of
|
|
|
|
// will be a non-remote accessible.
|
2016-06-10 00:33:48 +03:00
|
|
|
Accessible* outerDoc = aProxy->OuterDocOfRemoteBrowser();
|
|
|
|
if (outerDoc) {
|
2016-06-10 00:33:48 +03:00
|
|
|
nativeParent = GetNativeFromGeckoAccessible(outerDoc);
|
2016-06-10 00:33:48 +03:00
|
|
|
}
|
2016-06-10 00:33:48 +03:00
|
|
|
} else {
|
|
|
|
// Non-top level proxies need proxy parents' children invalidated.
|
|
|
|
ProxyAccessible* parent = aProxy->Parent();
|
Bug 1581040: handle late creation/re-creation of OuterDocAccessible for OOP iframe. r=yzen,nika
1. When creating a DocAccessibleParent for an embedded document in an OOP iframe, it's possible that the embedder accessible hasn't been set yet.
This can occur if the iframe is initially hidden.
Previously, we incorrectly set the document up as a top level document (e.g. tab document) in this case.
Now, we set up the document as top level in its content process, set up the proxy, etc.
The document will be added to its child document later when the embedder is set.
2. When setting the embedder accessible for an OOP iframe, check if the embedded DocAccessibleParent already exists.
This can happen if an iframe is hidden and then shown or an iframe is reflowed by layout.
If it already exists, add the embedded (child) document to its embedder.
3. Mac's implementation of ProxyCreated requires that AddChildDoc be called *before* ProxyCreated so it can invalidate the native children of the parent.
Because it's possible for an OOP iframe document to be added to its embedder after the document is created, we can't satisfy this requirement for OOP iframe documents.
Therefore, we now allow a null parent in Mac's ProxyCreated and use the reorder event fired later to invalidate the native children.
Differential Revision: https://phabricator.services.mozilla.com/D51357
--HG--
extra : moz-landing-system : lando
2019-11-07 03:38:59 +03:00
|
|
|
MOZ_ASSERT(parent ||
|
|
|
|
// It's expected that an OOP iframe might not have a parent yet.
|
|
|
|
(aProxy->IsDoc() && aProxy->AsDoc()->IsTopLevelInContentProcess()),
|
|
|
|
"a non-top-level proxy is missing a parent?");
|
|
|
|
nativeParent = parent ? GetNativeFromProxy(parent) : nullptr;
|
2016-06-10 00:33:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (nativeParent) {
|
|
|
|
[nativeParent invalidateChildren];
|
2016-06-10 00:33:48 +03:00
|
|
|
}
|
2014-03-08 01:35:19 +04:00
|
|
|
}
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
void ProxyDestroyed(ProxyAccessible* aProxy) {
|
2016-06-10 00:33:48 +03:00
|
|
|
mozAccessible* nativeParent = nil;
|
2016-06-10 00:33:48 +03:00
|
|
|
if (aProxy->IsDoc() && aProxy->AsDoc()->IsTopLevel()) {
|
2016-06-10 00:33:48 +03:00
|
|
|
// Invalidate native parent in parent process's children on proxy destruction
|
2016-06-10 00:33:48 +03:00
|
|
|
Accessible* outerDoc = aProxy->OuterDocOfRemoteBrowser();
|
|
|
|
if (outerDoc) {
|
2016-06-10 00:33:48 +03:00
|
|
|
nativeParent = GetNativeFromGeckoAccessible(outerDoc);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!aProxy->Document()->IsShutdown()) {
|
|
|
|
// Only do if the document has not been shut down, else parent will return
|
|
|
|
// garbage since we don't shut down children from top down.
|
|
|
|
ProxyAccessible* parent = aProxy->Parent();
|
|
|
|
// Invalidate proxy parent's children.
|
|
|
|
if (parent) {
|
|
|
|
nativeParent = GetNativeFromProxy(parent);
|
|
|
|
}
|
2016-06-10 00:33:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-08 17:42:33 +03:00
|
|
|
mozAccessible* wrapper = GetNativeFromProxy(aProxy);
|
2015-05-29 20:42:23 +03:00
|
|
|
[wrapper expire];
|
|
|
|
[wrapper release];
|
|
|
|
aProxy->SetWrapper(0);
|
2016-06-10 00:33:48 +03:00
|
|
|
|
|
|
|
if (nativeParent) {
|
|
|
|
[nativeParent invalidateChildren];
|
|
|
|
}
|
2014-03-08 01:35:19 +04:00
|
|
|
}
|
2014-09-30 18:00:26 +04:00
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
void ProxyEvent(ProxyAccessible* aProxy, uint32_t aEventType) {
|
Bug 1581040: handle late creation/re-creation of OuterDocAccessible for OOP iframe. r=yzen,nika
1. When creating a DocAccessibleParent for an embedded document in an OOP iframe, it's possible that the embedder accessible hasn't been set yet.
This can occur if the iframe is initially hidden.
Previously, we incorrectly set the document up as a top level document (e.g. tab document) in this case.
Now, we set up the document as top level in its content process, set up the proxy, etc.
The document will be added to its child document later when the embedder is set.
2. When setting the embedder accessible for an OOP iframe, check if the embedded DocAccessibleParent already exists.
This can happen if an iframe is hidden and then shown or an iframe is reflowed by layout.
If it already exists, add the embedded (child) document to its embedder.
3. Mac's implementation of ProxyCreated requires that AddChildDoc be called *before* ProxyCreated so it can invalidate the native children of the parent.
Because it's possible for an OOP iframe document to be added to its embedder after the document is created, we can't satisfy this requirement for OOP iframe documents.
Therefore, we now allow a null parent in Mac's ProxyCreated and use the reorder event fired later to invalidate the native children.
Differential Revision: https://phabricator.services.mozilla.com/D51357
--HG--
extra : moz-landing-system : lando
2019-11-07 03:38:59 +03:00
|
|
|
if (aEventType == nsIAccessibleEvent::EVENT_REORDER && aProxy->ChildrenCount() == 1 &&
|
|
|
|
aProxy->ChildAt(0)->IsDoc()) {
|
|
|
|
// This is a remote OuterDocAccessible. The reorder event indicates that Its
|
|
|
|
// embedded document has been added or changed. If the document itself is
|
|
|
|
// an existing Accessible, ProxyCreated won't have been called, so we won't
|
|
|
|
// have invalidated native children. This can happen for in-process iframes
|
|
|
|
// if the OuterDocAccessible is re-created (e.g. due to layout reflow).
|
|
|
|
// It always happens for out-of-process iframes, as we must always call
|
|
|
|
// ProxyCreated before DocAccessibleParent::AddChildDoc for those.
|
|
|
|
mozAccessible* wrapper = GetNativeFromProxy(aProxy);
|
|
|
|
if (wrapper) {
|
|
|
|
[wrapper invalidateChildren];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-29 20:50:26 +03:00
|
|
|
// ignore everything but focus-changed, value-changed, caret and selection
|
|
|
|
// events for now.
|
|
|
|
if (aEventType != nsIAccessibleEvent::EVENT_FOCUS &&
|
|
|
|
aEventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE &&
|
2015-11-02 23:34:51 +03:00
|
|
|
aEventType != nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE &&
|
2015-05-29 20:50:26 +03:00
|
|
|
aEventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED &&
|
|
|
|
aEventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED)
|
|
|
|
return;
|
|
|
|
|
2015-06-08 17:42:33 +03:00
|
|
|
mozAccessible* wrapper = GetNativeFromProxy(aProxy);
|
2020-03-27 20:12:33 +03:00
|
|
|
if (wrapper) {
|
|
|
|
[wrapper firePlatformEvent:aEventType];
|
|
|
|
}
|
2014-09-30 18:00:26 +04:00
|
|
|
}
|
2015-05-13 21:21:23 +03:00
|
|
|
|
2020-04-02 19:42:46 +03:00
|
|
|
void ProxyStateChangeEvent(ProxyAccessible* aProxy, uint64_t aState, bool aEnabled) {
|
|
|
|
mozAccessible* wrapper = GetNativeFromProxy(aProxy);
|
|
|
|
if (wrapper) {
|
|
|
|
[wrapper stateChanged:aState isEnabled:aEnabled];
|
|
|
|
}
|
2015-05-13 21:21:23 +03:00
|
|
|
}
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
void ProxyCaretMoveEvent(ProxyAccessible* aTarget, int32_t aOffset) {
|
2015-06-08 17:42:33 +03:00
|
|
|
mozAccessible* wrapper = GetNativeFromProxy(aTarget);
|
2020-03-27 20:12:33 +03:00
|
|
|
if (wrapper) {
|
|
|
|
[wrapper firePlatformEvent:nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED];
|
|
|
|
}
|
2015-05-13 21:21:23 +03:00
|
|
|
}
|
2015-05-29 20:50:26 +03:00
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
void ProxyTextChangeEvent(ProxyAccessible*, const nsString&, int32_t, uint32_t, bool, bool) {}
|
2016-04-06 04:43:04 +03:00
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
void ProxyShowHideEvent(ProxyAccessible*, ProxyAccessible*, bool, bool) {}
|
2016-04-21 22:06:57 +03:00
|
|
|
|
2020-03-13 01:16:39 +03:00
|
|
|
void ProxySelectionEvent(ProxyAccessible* aTarget, ProxyAccessible* aWidget, uint32_t aEventType) {
|
|
|
|
mozAccessible* wrapper = GetNativeFromProxy(aWidget);
|
2020-03-27 20:12:33 +03:00
|
|
|
if (wrapper) {
|
|
|
|
[wrapper firePlatformEvent:aEventType];
|
|
|
|
}
|
2020-03-13 01:16:39 +03:00
|
|
|
}
|
2019-01-21 20:18:16 +03:00
|
|
|
} // namespace a11y
|
|
|
|
} // namespace mozilla
|
2012-06-07 04:26:45 +04:00
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
@interface GeckoNSApplication (a11y)
|
|
|
|
- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute;
|
2012-06-07 04:26:45 +04:00
|
|
|
@end
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
@implementation GeckoNSApplication (a11y)
|
2012-06-07 04:26:45 +04:00
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
|
2012-06-07 04:26:45 +04:00
|
|
|
if ([attribute isEqualToString:@"AXEnhancedUserInterface"])
|
|
|
|
mozilla::a11y::sA11yShouldBeEnabled = ([value intValue] == 1);
|
|
|
|
|
|
|
|
return [super accessibilitySetValue:value forAttribute:attribute];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|