2 /* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "DocAccessibleWrap.h"
10 #include "DocAccessible-inl.h"
11 #include "nsAccUtils.h"
13 #import "mozAccessible.h"
14 #import "MOXTextMarkerDelegate.h"
16 using namespace mozilla;
17 using namespace mozilla::a11y;
19 DocAccessibleWrap::DocAccessibleWrap(dom::Document* aDocument,
20 PresShell* aPresShell)
21 : DocAccessible(aDocument, aPresShell) {}
23 void DocAccessibleWrap::Shutdown() {
24 [MOXTextMarkerDelegate destroyForDoc:this];
25 DocAccessible::Shutdown();
28 DocAccessibleWrap::~DocAccessibleWrap() {}
30 void DocAccessibleWrap::AttributeChanged(dom::Element* aElement,
32 nsAtom* aAttribute, int32_t aModType,
33 const nsAttrValue* aOldValue) {
34 DocAccessible::AttributeChanged(aElement, aNameSpaceID, aAttribute, aModType,
36 if (aAttribute == nsGkAtoms::aria_live) {
37 LocalAccessible* accessible =
38 mContent != aElement ? GetAccessible(aElement) : this;
43 static const dom::Element::AttrValuesArray sLiveRegionValues[] = {
44 nsGkAtoms::OFF, nsGkAtoms::polite, nsGkAtoms::assertive, nullptr};
45 int32_t attrValue = nsAccUtils::FindARIAAttrValueIn(
46 aElement, nsGkAtoms::aria_live, sLiveRegionValues, eIgnoreCase);
48 if (!aOldValue || aOldValue->IsEmptyString() ||
49 aOldValue->Equals(nsGkAtoms::OFF, eIgnoreCase)) {
50 // This element just got an active aria-live attribute value
51 FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_ADDED,
55 if (aOldValue && (aOldValue->Equals(nsGkAtoms::polite, eIgnoreCase) ||
56 aOldValue->Equals(nsGkAtoms::assertive, eIgnoreCase))) {
57 // This element lost an active live region
58 FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED,
60 } else if (attrValue == 0) {
61 // aria-live="off", check if its a role-based live region that
62 // needs to be removed.
63 if (const nsRoleMapEntry* roleMap = accessible->ARIARoleMap()) {
64 // aria role defines it as a live region. It's live!
65 if (roleMap->liveAttRule == ePoliteLiveAttr ||
66 roleMap->liveAttRule == eAssertiveLiveAttr) {
67 FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED,
70 } else if (nsStaticAtom* value = GetAccService()->MarkupAttribute(
71 aElement, nsGkAtoms::aria_live)) {
72 // HTML element defines it as a live region. It's live!
73 if (value == nsGkAtoms::polite || value == nsGkAtoms::assertive) {
74 FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED,
83 void DocAccessibleWrap::QueueNewLiveRegion(LocalAccessible* aAccessible) {
88 mNewLiveRegions.Insert(aAccessible->UniqueID());
91 void DocAccessibleWrap::ProcessNewLiveRegions() {
92 for (const auto& uniqueID : mNewLiveRegions) {
93 if (LocalAccessible* liveRegion =
94 GetAccessibleByUniqueID(const_cast<void*>(uniqueID))) {
95 FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_ADDED, liveRegion);
99 mNewLiveRegions.Clear();
102 void DocAccessibleWrap::DoInitialUpdate() {
103 DocAccessible::DoInitialUpdate();
104 ProcessNewLiveRegions();