tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DocAccessibleWrap.mm (4473B)


      1 /* clang-format off */
      2 /* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      3 /* clang-format on */
      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/. */
      7 
      8 #include "DocAccessibleWrap.h"
      9 #include "ARIAMap.h"
     10 #include "DocAccessible-inl.h"
     11 #include "nsAccUtils.h"
     12 
     13 #import "mozAccessible.h"
     14 #import "MOXTextMarkerDelegate.h"
     15 
     16 using namespace mozilla;
     17 using namespace mozilla::a11y;
     18 
     19 DocAccessibleWrap::DocAccessibleWrap(dom::Document* aDocument,
     20                                     PresShell* aPresShell)
     21    : DocAccessible(aDocument, aPresShell) {}
     22 
     23 void DocAccessibleWrap::Shutdown() {
     24  [MOXTextMarkerDelegate destroyForDoc:this];
     25  DocAccessible::Shutdown();
     26 }
     27 
     28 DocAccessibleWrap::~DocAccessibleWrap() {}
     29 
     30 void DocAccessibleWrap::AttributeChanged(dom::Element* aElement,
     31                                         int32_t aNameSpaceID,
     32                                         nsAtom* aAttribute,
     33                                         AttrModType aModType,
     34                                         const nsAttrValue* aOldValue) {
     35  DocAccessible::AttributeChanged(aElement, aNameSpaceID, aAttribute, aModType,
     36                                  aOldValue);
     37  if (aAttribute == nsGkAtoms::aria_errormessage) {
     38    LocalAccessible* accessible =
     39        mContent != aElement ? GetAccessible(aElement) : this;
     40    if (!accessible) {
     41      return;
     42    }
     43    FireDelayedEvent(nsIAccessibleEvent::EVENT_ERRORMESSAGE_CHANGED,
     44                     accessible);
     45  }
     46 
     47  if (aAttribute == nsGkAtoms::aria_live) {
     48    LocalAccessible* accessible =
     49        mContent != aElement ? GetAccessible(aElement) : this;
     50    if (!accessible) {
     51      return;
     52    }
     53 
     54    static const dom::Element::AttrValuesArray sLiveRegionValues[] = {
     55        nsGkAtoms::OFF, nsGkAtoms::polite, nsGkAtoms::assertive, nullptr};
     56    int32_t attrValue = nsAccUtils::FindARIAAttrValueIn(
     57        aElement, nsGkAtoms::aria_live, sLiveRegionValues, eIgnoreCase);
     58    if (attrValue > 0) {
     59      if (!aOldValue || aOldValue->IsEmptyString() ||
     60          aOldValue->Equals(nsGkAtoms::OFF, eIgnoreCase)) {
     61        // This element just got an active aria-live attribute value
     62        FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_ADDED,
     63                         accessible);
     64      }
     65    } else {
     66      if (aOldValue && (aOldValue->Equals(nsGkAtoms::polite, eIgnoreCase) ||
     67                        aOldValue->Equals(nsGkAtoms::assertive, eIgnoreCase))) {
     68        // This element lost an active live region
     69        FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED,
     70                         accessible);
     71      } else if (attrValue == 0) {
     72        // aria-live="off", check if its a role-based live region that
     73        // needs to be removed.
     74        if (const nsRoleMapEntry* roleMap = accessible->ARIARoleMap()) {
     75          // aria role defines it as a live region. It's live!
     76          if (roleMap->liveAttRule == ePoliteLiveAttr ||
     77              roleMap->liveAttRule == eAssertiveLiveAttr) {
     78            FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED,
     79                             accessible);
     80          }
     81        } else if (nsStaticAtom* value = GetAccService()->MarkupAttribute(
     82                       aElement, nsGkAtoms::aria_live)) {
     83          // HTML element defines it as a live region. It's live!
     84          if (value == nsGkAtoms::polite || value == nsGkAtoms::assertive) {
     85            FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED,
     86                             accessible);
     87          }
     88        }
     89      }
     90    }
     91  }
     92 }
     93 
     94 void DocAccessibleWrap::QueueNewLiveRegion(LocalAccessible* aAccessible) {
     95  if (!aAccessible) {
     96    return;
     97  }
     98 
     99  mNewLiveRegions.Insert(aAccessible->UniqueID());
    100 }
    101 
    102 void DocAccessibleWrap::ProcessNewLiveRegions() {
    103  for (const auto& uniqueID : mNewLiveRegions) {
    104    if (LocalAccessible* liveRegion =
    105            GetAccessibleByUniqueID(const_cast<void*>(uniqueID))) {
    106      FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_ADDED, liveRegion);
    107    }
    108  }
    109 
    110  mNewLiveRegions.Clear();
    111 }
    112 
    113 void DocAccessibleWrap::DoInitialUpdate() {
    114  DocAccessible::DoInitialUpdate();
    115  if (IsLiveRegion(mDocumentNode->GetBodyElement())) {
    116    // Check if this doc's body element is a live region
    117    QueueNewLiveRegion(this);
    118  }
    119 
    120  ProcessNewLiveRegions();
    121 }