Bug 1642707: Add web area class and attributes r=eeejay

Differential Revision: https://phabricator.services.mozilla.com/D80473
This commit is contained in:
Morgan Reschenberg 2020-06-26 04:00:49 +00:00
parent 537f656a8e
commit 117fa600ac
10 changed files with 207 additions and 8 deletions

View File

@ -12,6 +12,7 @@
#include "gfxPlatform.h"
#import "MOXMathAccessibles.h"
#import "MOXWebAreaAccessible.h"
#import "mozAccessible.h"
#import "mozActionElements.h"
#import "mozHTMLAccessible.h"
@ -174,6 +175,9 @@ Class a11y::GetTypeFromRole(roles::Role aRole) {
case roles::COMBOBOX:
return [mozPopupButtonAccessible class];
case roles::DOCUMENT:
return [MOXWebAreaAccessible class];
case roles::PUSHBUTTON:
return [mozButtonAccessible class];

View File

@ -129,6 +129,25 @@
// AXMenuItemMarkChar
- (NSString* _Nullable)moxMenuItemMarkChar;
// AXLoaded
- (NSNumber* _Nullable)moxLoaded;
// AXLoadingProgress
- (NSNumber* _Nullable)moxLoadingProgress;
// Webkit also implements the following:
// // AXCaretBrowsingEnabled
// - (NSString* _Nullable)moxCaretBrowsingEnabled;
// // AXLayoutCount
// - (NSString* _Nullable)moxLayoutCount;
// // AXWebSessionID
// - (NSString* _Nullable)moxWebSessionID;
// // AXPreventKeyboardDOMEventDispatch
// - (NSString* _Nullable)moxPreventKeyboardDOMEventDispatch;
// Table Attributes
// AXRowCount

View File

@ -0,0 +1,23 @@
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=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 "mozAccessible.h"
@interface MOXWebAreaAccessible : mozAccessible
// overrides
- (NSURL* _Nullable)moxURL;
// overrides
- (NSNumber* _Nullable)moxLoaded;
// overrides
- (NSNumber* _Nullable)moxLoadingProgress;
// overrides
- (void)handleAccessibleEvent:(uint32_t)eventType;
@end

View File

@ -0,0 +1,88 @@
/* -*- (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 "MOXWebAreaAccessible.h"
#include "nsCocoaUtils.h"
#include "DocAccessibleParent.h"
using namespace mozilla::a11y;
@implementation MOXWebAreaAccessible
- (NSURL* _Nullable)moxURL {
if ([self isExpired]) {
return nil;
}
nsAutoString url;
if (mGeckoAccessible.IsAccessible()) {
MOZ_ASSERT(mGeckoAccessible.AsAccessible()->IsDoc());
DocAccessible* acc = mGeckoAccessible.AsAccessible()->AsDoc();
acc->URL(url);
} else {
ProxyAccessible* proxy = mGeckoAccessible.AsProxy();
proxy->URL(url);
}
if (url.IsEmpty()) {
return nil;
}
return [NSURL URLWithString:nsCocoaUtils::ToNSString(url)];
}
- (NSNumber* _Nullable)moxLoaded {
if ([self isExpired]) {
return nil;
}
// We are loaded if we aren't busy or stale
return @([self stateWithMask:(states::BUSY & states::STALE)] == 0);
}
// overrides
- (NSNumber* _Nullable)moxLoadingProgress {
if ([self isExpired]) {
return nil;
}
if ([self stateWithMask:states::STALE] != 0) {
// We expose stale state until the document is ready (DOM is loaded and tree is
// constructed) so we indicate load hasn't started while this state is present.
return @0.0;
}
if ([self stateWithMask:states::BUSY] != 0) {
// We expose state busy until the document and all its subdocuments are completely
// loaded, so we indicate partial loading here
return @0.5;
}
// if we are not busy and not stale, we are loaded
return @1.0;
}
- (void)handleAccessibleEvent:(uint32_t)eventType {
switch (eventType) {
case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE:
[self moxPostNotification:NSAccessibilityFocusedUIElementChangedNotification];
if ((mGeckoAccessible.IsProxy() && mGeckoAccessible.AsProxy()->IsDoc() &&
mGeckoAccessible.AsProxy()->AsDoc()->IsTopLevel()) ||
(mGeckoAccessible.IsAccessible() && !mGeckoAccessible.AsAccessible()->IsRoot() &&
mGeckoAccessible.AsAccessible()->AsDoc()->ParentDocument()->IsRoot())) {
// we fire an AXLoadComplete event on top-level documents only
[self moxPostNotification:@"AXLoadComplete"];
} else {
// otherwise the doc belongs to an iframe (IsTopLevelInContentProcess)
// and we fire AXLayoutComplete instead
[self moxPostNotification:@"AXLayoutComplete"];
}
break;
}
[super handleAccessibleEvent:eventType];
}
@end

View File

@ -64,13 +64,15 @@ void ProxyDestroyed(ProxyAccessible* aProxy) {
}
void ProxyEvent(ProxyAccessible* aProxy, uint32_t aEventType) {
// ignore everything but focus-changed, value-changed, caret and selection
// events for now.
// ignore everything but focus-changed, value-changed, caret,
// selection, and document load complete events for now.
NSLog(@"Event type is %u", aEventType);
if (aEventType != nsIAccessibleEvent::EVENT_FOCUS &&
aEventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE &&
aEventType != nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE &&
aEventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED &&
aEventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED &&
aEventType != nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE &&
aEventType != nsIAccessibleEvent::EVENT_REORDER)
return;

View File

@ -19,6 +19,7 @@ UNIFIED_SOURCES += [
'MacUtils.mm',
'MOXAccessibleBase.mm',
'MOXMathAccessibles.mm',
'MOXWebAreaAccessible.mm',
'mozAccessible.mm',
'mozActionElements.mm',
'mozHTMLAccessible.mm',

View File

@ -70,6 +70,8 @@ inline mozAccessible* GetNativeFromGeckoAccessible(mozilla::a11y::AccessibleOrPr
// Given a gecko accessibility event type, post the relevant
// system accessibility notification.
// Note: when overriding or adding new events, make sure your events aren't
// filtered out in Platform::ProxyEvent or AccessibleWrap::HandleAccEvent!
- (void)handleAccessibleEvent:(uint32_t)eventType;
// internal method to retrieve a child at a given index.

View File

@ -178,7 +178,7 @@ static const uint64_t kCacheInitialized = ((uint64_t)0x1) << 63;
// These accessible types are the exception to the rule of label vs. title:
// They may be named explicitly, but they still provide a label not a title.
return mRole == roles::GROUPING || mRole == roles::RADIO_GROUP || mRole == roles::FIGURE ||
mRole == roles::GRAPHIC;
mRole == roles::GRAPHIC || mRole == roles::DOCUMENT;
}
- (mozilla::a11y::AccessibleOrProxy)geckoAccessible {
@ -794,11 +794,6 @@ struct RoleDescrComparator {
case nsIAccessibleEvent::EVENT_FOCUS:
[self moxPostNotification:NSAccessibilityFocusedUIElementChangedNotification];
break;
case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE:
[self moxPostNotification:NSAccessibilityFocusedUIElementChangedNotification];
[self moxPostNotification:@"AXLoadComplete"];
[self moxPostNotification:@"AXLayoutComplete"];
break;
case nsIAccessibleEvent::EVENT_MENUPOPUP_START:
[self moxPostNotification:@"AXMenuOpened"];
break;

View File

@ -26,3 +26,4 @@ support-files =
[browser_mathml.js]
[browser_input.js]
[browser_focus.js]
[browser_webarea.js]

View File

@ -0,0 +1,64 @@
/* 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/. */
"use strict";
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
// Test web area role and AXLoadComplete event
addAccessibleTask(``, async (browser, accDoc) => {
let evt = waitForMacEvent("AXLoadComplete");
await SpecialPowers.spawn(browser, [], () => {
content.location = "data:text/html,<title>webarea test</title>";
});
let doc = await evt;
is(
doc.getAttributeValue("AXRole"),
"AXWebArea",
"document has AXWebArea role"
);
is(doc.getAttributeValue("AXValue"), "", "document has no AXValue");
is(doc.getAttributeValue("AXTitle"), null, "document has no AXTitle");
is(
doc.getAttributeValue("AXDescription"),
"webarea test",
"test has correct label"
);
is(doc.getAttributeValue("AXLoaded"), 1, "document has finished loading");
});
// Test iframe web area role and AXLayoutComplete event
addAccessibleTask(`<title>webarea test</title>`, async (browser, accDoc) => {
// We should get a layout complete after the page content
// loads, so we start the await here.
let evt = waitForMacEvent("AXLayoutComplete");
await SpecialPowers.spawn(browser, [], () => {
const iframe = content.document.createElement("iframe");
iframe.src = "data:text/html,hello world";
content.document.body.appendChild(iframe);
});
let doc = await evt;
is(
doc.getAttributeValue("AXRole"),
"AXWebArea",
"iframe document has AXWebArea role"
);
is(doc.getAttributeValue("AXValue"), "", "iframe document has no AXValue");
is(doc.getAttributeValue("AXTitle"), null, "iframe document has no AXTitle");
is(
doc.getAttributeValue("AXDescription"),
"data:text/html,hello world",
"test has correct label"
);
is(
doc.getAttributeValue("AXLoaded"),
1,
"iframe document has finished loading"
);
});