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"
9 #include "DocAccessible-inl.h"
11 #import "mozAccessible.h"
12 #import "MOXTextMarkerDelegate.h"
14 using namespace mozilla;
15 using namespace mozilla::a11y;
17 DocAccessibleWrap::DocAccessibleWrap(dom::Document* aDocument,
18 PresShell* aPresShell)
19 : DocAccessible(aDocument, aPresShell) {}
21 void DocAccessibleWrap::Shutdown() {
22 [MOXTextMarkerDelegate destroyForDoc:this];
23 DocAccessible::Shutdown();
26 DocAccessibleWrap::~DocAccessibleWrap() {}
28 void DocAccessibleWrap::AttributeChanged(dom::Element* aElement,
30 nsAtom* aAttribute, int32_t aModType,
31 const nsAttrValue* aOldValue) {
32 DocAccessible::AttributeChanged(aElement, aNameSpaceID, aAttribute, aModType,
34 if (aAttribute == nsGkAtoms::aria_live) {
35 LocalAccessible* accessible =
36 mContent != aElement ? GetAccessible(aElement) : this;
41 static const dom::Element::AttrValuesArray sLiveRegionValues[] = {
42 nsGkAtoms::OFF, nsGkAtoms::polite, nsGkAtoms::assertive, nullptr};
44 aElement->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::aria_live,
45 sLiveRegionValues, eIgnoreCase);
47 if (!aOldValue || aOldValue->IsEmptyString() ||
48 aOldValue->Equals(nsGkAtoms::OFF, eIgnoreCase)) {
49 // This element just got an active aria-live attribute value
50 FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_ADDED,
54 if (aOldValue && (aOldValue->Equals(nsGkAtoms::polite, eIgnoreCase) ||
55 aOldValue->Equals(nsGkAtoms::assertive, eIgnoreCase))) {
56 // This element lost an active live region
57 FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED,
59 } else if (attrValue == 0) {
60 // aria-live="off", check if its a role-based live region that
61 // needs to be removed.
62 if (const nsRoleMapEntry* roleMap = accessible->ARIARoleMap()) {
63 // aria role defines it as a live region. It's live!
64 if (roleMap->liveAttRule == ePoliteLiveAttr ||
65 roleMap->liveAttRule == eAssertiveLiveAttr) {
66 FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED,
69 } else if (nsStaticAtom* value = GetAccService()->MarkupAttribute(
70 aElement, nsGkAtoms::aria_live)) {
71 // HTML element defines it as a live region. It's live!
72 if (value == nsGkAtoms::polite || value == nsGkAtoms::assertive) {
73 FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED,
82 void DocAccessibleWrap::QueueNewLiveRegion(LocalAccessible* aAccessible) {
87 mNewLiveRegions.Insert(aAccessible->UniqueID());
90 void DocAccessibleWrap::ProcessNewLiveRegions() {
91 for (const auto& uniqueID : mNewLiveRegions) {
92 if (LocalAccessible* liveRegion =
93 GetAccessibleByUniqueID(const_cast<void*>(uniqueID))) {
94 FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_ADDED, liveRegion);
98 mNewLiveRegions.Clear();
101 void DocAccessibleWrap::DoInitialUpdate() {
102 DocAccessible::DoInitialUpdate();
103 ProcessNewLiveRegions();