DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (c68fe15a81fc)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
/* -*- Mode: 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/. */

#ifndef mozilla_a11y_DocAccessible_inl_h_
#define mozilla_a11y_DocAccessible_inl_h_

#include "DocAccessible.h"
#include "nsAccessibilityService.h"
#include "nsAccessiblePivot.h"
#include "NotificationController.h"
#include "States.h"
#include "nsIScrollableFrame.h"
#include "mozilla/dom/DocumentInlines.h"

#ifdef A11Y_LOG
#  include "Logging.h"
#endif

namespace mozilla {
namespace a11y {

inline Accessible* DocAccessible::AccessibleOrTrueContainer(
    nsINode* aNode, bool aNoContainerIfPruned) const {
  // HTML comboboxes have no-content list accessible as an intermediate
  // containing all options.
  Accessible* container = GetAccessibleOrContainer(aNode, aNoContainerIfPruned);
  if (container && container->IsHTMLCombobox()) {
    return container->FirstChild();
  }
  return container;
}

inline nsIAccessiblePivot* DocAccessible::VirtualCursor() {
  if (!mVirtualCursor) {
    mVirtualCursor = new nsAccessiblePivot(this);
    mVirtualCursor->AddObserver(this);
  }
  return mVirtualCursor;
}

inline void DocAccessible::FireDelayedEvent(AccEvent* aEvent) {
#ifdef A11Y_LOG
  if (logging::IsEnabled(logging::eDocLoad)) logging::DocLoadEventFired(aEvent);
#endif

  mNotificationController->QueueEvent(aEvent);
}

inline void DocAccessible::FireDelayedEvent(uint32_t aEventType,
                                            Accessible* aTarget) {
  RefPtr<AccEvent> event = new AccEvent(aEventType, aTarget);
  FireDelayedEvent(event);
}

inline void DocAccessible::BindChildDocument(DocAccessible* aDocument) {
  mNotificationController->ScheduleChildDocBinding(aDocument);
}

template <class Class, class... Args>
inline void DocAccessible::HandleNotification(
    Class* aInstance, typename TNotification<Class, Args...>::Callback aMethod,
    Args*... aArgs) {
  if (mNotificationController) {
    mNotificationController->HandleNotification<Class, Args...>(
        aInstance, aMethod, aArgs...);
  }
}

inline void DocAccessible::UpdateText(nsIContent* aTextNode) {
  NS_ASSERTION(mNotificationController, "The document was shut down!");

  // Ignore the notification if initial tree construction hasn't been done yet.
  if (mNotificationController && HasLoadState(eTreeConstructed))
    mNotificationController->ScheduleTextUpdate(aTextNode);
}

inline void DocAccessible::NotifyOfLoad(uint32_t aLoadEventType) {
  mLoadState |= eDOMLoaded;
  mLoadEventType = aLoadEventType;

  // If the document is loaded completely then network activity was presumingly
  // caused by file loading. Fire busy state change event.
  if (HasLoadState(eCompletelyLoaded) && IsLoadEventTarget()) {
    RefPtr<AccEvent> stateEvent =
        new AccStateChangeEvent(this, states::BUSY, false);
    FireDelayedEvent(stateEvent);
  }
}

inline void DocAccessible::MaybeNotifyOfValueChange(Accessible* aAccessible) {
  if (aAccessible->IsCombobox() || aAccessible->Role() == roles::ENTRY ||
      aAccessible->Role() == roles::SPINBUTTON) {
    FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE, aAccessible);
  }
}

inline Accessible* DocAccessible::GetAccessibleEvenIfNotInMapOrContainer(
    nsINode* aNode) const {
  Accessible* acc = GetAccessibleEvenIfNotInMap(aNode);
  return acc ? acc : GetContainerAccessible(aNode);
}

inline void DocAccessible::CreateSubtree(Accessible* aChild) {
  // If a focused node has been shown then it could mean its frame was recreated
  // while the node stays focused and we need to fire focus event on
  // the accessible we just created. If the queue contains a focus event for
  // this node already then it will be suppressed by this one.
  Accessible* focusedAcc = nullptr;
  CacheChildrenInSubtree(aChild, &focusedAcc);

#ifdef A11Y_LOG
  if (logging::IsEnabled(logging::eVerbose)) {
    logging::Tree("TREE", "Created subtree", aChild);
  }
#endif

  // Fire events for ARIA elements.
  if (aChild->HasARIARole()) {
    roles::Role role = aChild->ARIARole();
    if (role == roles::MENUPOPUP) {
      FireDelayedEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START, aChild);
    } else if (role == roles::ALERT) {
      FireDelayedEvent(nsIAccessibleEvent::EVENT_ALERT, aChild);
    }
  }

  // XXX: do we really want to send focus to focused DOM node not taking into
  // account active item?
  if (focusedAcc) {
    FocusMgr()->DispatchFocusEvent(this, focusedAcc);
    SelectionMgr()->SetControlSelectionListener(
        focusedAcc->GetNode()->AsElement());
  }
}

inline DocAccessible::AttrRelProviders* DocAccessible::GetRelProviders(
    dom::Element* aElement, const nsAString& aID) const {
  DependentIDsHashtable* hash = mDependentIDsHashes.Get(
      aElement->GetUncomposedDocOrConnectedShadowRoot());
  if (hash) {
    return hash->Get(aID);
  }
  return nullptr;
}

inline DocAccessible::AttrRelProviders* DocAccessible::GetOrCreateRelProviders(
    dom::Element* aElement, const nsAString& aID) {
  dom::DocumentOrShadowRoot* docOrShadowRoot =
      aElement->GetUncomposedDocOrConnectedShadowRoot();
  DependentIDsHashtable* hash = mDependentIDsHashes.Get(docOrShadowRoot);
  if (!hash) {
    hash = new DependentIDsHashtable();
    mDependentIDsHashes.Put(docOrShadowRoot, hash);
  }

  AttrRelProviders* providers = hash->Get(aID);
  if (!providers) {
    providers = new AttrRelProviders();
    hash->Put(aID, providers);
  }
  return providers;
}

inline void DocAccessible::RemoveRelProvidersIfEmpty(dom::Element* aElement,
                                                     const nsAString& aID) {
  dom::DocumentOrShadowRoot* docOrShadowRoot =
      aElement->GetUncomposedDocOrConnectedShadowRoot();
  DependentIDsHashtable* hash = mDependentIDsHashes.Get(docOrShadowRoot);
  if (hash) {
    AttrRelProviders* providers = hash->Get(aID);
    if (providers && providers->Length() == 0) {
      hash->Remove(aID);
      if (mDependentIDsHashes.IsEmpty()) {
        mDependentIDsHashes.Remove(docOrShadowRoot);
      }
    }
  }
}

}  // namespace a11y
}  // namespace mozilla

#endif