FocusManager::FocusDisposition FocusManager::IsInOrContainsFocus(const Accessible* aAccessible) const { Accessible* focus = FocusedAccessible(); if (!focus) return eNone; // If focused. if (focus == aAccessible) return eFocused; // If contains the focus. Accessible* child = focus->Parent(); while (child) { if (child == aAccessible) return eContainsFocus; child = child->Parent(); } // If contained by focus. child = aAccessible->Parent(); while (child) { if (child == focus) return eContainedByFocus; child = child->Parent(); } return eNone; }
bool EventQueue::PushEvent(AccEvent* aEvent) { NS_ASSERTION((aEvent->mAccessible && aEvent->mAccessible->IsApplication()) || aEvent->GetDocAccessible() == mDocument, "Queued event belongs to another document!"); if (!mEvents.AppendElement(aEvent)) return false; // Filter events. CoalesceEvents(); // Fire name change event on parent given that this event hasn't been // coalesced, the parent's name was calculated from its subtree, and the // subtree was changed. Accessible* target = aEvent->mAccessible; if (aEvent->mEventRule != AccEvent::eDoNotEmit && target->HasNameDependentParent() && (aEvent->mEventType == nsIAccessibleEvent::EVENT_NAME_CHANGE || aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED || aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED || aEvent->mEventType == nsIAccessibleEvent::EVENT_SHOW || aEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE)) { // Only continue traversing up the tree if it's possible that the parent // accessible's name can depend on this accessible's name. Accessible* parent = target->Parent(); while (parent && nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) { // Test possible name dependent parent. if (nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) { nsAutoString name; ENameValueFlag nameFlag = parent->Name(name); // If name is obtained from subtree, fire name change event. if (nameFlag == eNameFromSubtree) { RefPtr<AccEvent> nameChangeEvent = new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent); PushEvent(nameChangeEvent); } break; } parent = parent->Parent(); } } // Associate text change with hide event if it wasn't stolen from hiding // siblings during coalescence. AccMutationEvent* showOrHideEvent = downcast_accEvent(aEvent); if (showOrHideEvent && !showOrHideEvent->mTextChangeEvent) CreateTextChangeEventFor(showOrHideEvent); return true; }
Accessible* XULMenupopupAccessible::ContainerWidget() const { DocAccessible* document = Document(); nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(GetFrame()); while (menuPopupFrame) { Accessible* menuPopup = document->GetAccessible(menuPopupFrame->GetContent()); if (!menuPopup) // shouldn't be a real case return nullptr; nsMenuFrame* menuFrame = do_QueryFrame(menuPopupFrame->GetParent()); if (!menuFrame) // context menu or popups return nullptr; nsMenuParent* menuParent = menuFrame->GetMenuParent(); if (!menuParent) // menulist or menubutton return menuPopup->Parent(); if (menuParent->IsMenuBar()) { // menubar menu nsMenuBarFrame* menuBarFrame = static_cast<nsMenuBarFrame*>(menuParent); return document->GetAccessible(menuBarFrame->GetContent()); } // different kind of popups like panel or tooltip if (!menuParent->IsMenu()) return nullptr; menuPopupFrame = static_cast<nsMenuPopupFrame*>(menuParent); } MOZ_ASSERT_UNREACHABLE("Shouldn't be a real case."); return nullptr; }
Accessible* nsAccessiblePivot::AdjustStartPosition(Accessible* aAccessible, RuleCache& aCache, uint16_t* aFilterResult, nsresult* aResult) { Accessible* matched = aAccessible; *aResult = aCache.ApplyFilter(aAccessible, aFilterResult); if (aAccessible != mRoot && aAccessible != mModalRoot) { for (Accessible* temp = aAccessible->Parent(); temp && temp != mRoot && temp != mModalRoot; temp = temp->Parent()) { uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE; *aResult = aCache.ApplyFilter(temp, &filtered); NS_ENSURE_SUCCESS(*aResult, nullptr); if (filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE) { *aFilterResult = filtered; matched = temp; } } } if (aAccessible == mPosition && mStartOffset != -1 && mEndOffset != -1) { HyperTextAccessible* text = aAccessible->AsHyperText(); if (text) { matched = text->GetChildAtOffset(mStartOffset); } } return matched; }
Accessible* HTMLLabelIterator::Next() { // Get either <label for="[id]"> element which explicitly points to given // element, or <label> ancestor which implicitly point to it. Accessible* label = nullptr; while ((label = mRelIter.Next())) { if (IsLabel(label)) { return label; } } // Ignore ancestor label on not widget accessible. if (mLabelFilter == eSkipAncestorLabel || !mAcc->IsWidget()) return nullptr; // Go up tree to get a name of ancestor label if there is one (an ancestor // <label> implicitly points to us). Don't go up farther than form or // document. Accessible* walkUp = mAcc->Parent(); while (walkUp && !walkUp->IsDoc()) { nsIContent* walkUpEl = walkUp->GetContent(); if (IsLabel(walkUp) && !walkUpEl->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) { mLabelFilter = eSkipAncestorLabel; // prevent infinite loop return walkUp; } if (walkUpEl->IsHTMLElement(nsGkAtoms::form)) break; walkUp = walkUp->Parent(); } return nullptr; }
bool EventQueue::PushNameChange(Accessible* aTarget) { // Fire name change event on parent given that this event hasn't been // coalesced, the parent's name was calculated from its subtree, and the // subtree was changed. if (aTarget->HasNameDependentParent()) { // Only continue traversing up the tree if it's possible that the parent // accessible's name can depend on this accessible's name. Accessible* parent = aTarget->Parent(); while (parent && nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) { // Test possible name dependent parent. if (nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) { nsAutoString name; ENameValueFlag nameFlag = parent->Name(name); // If name is obtained from subtree, fire name change event. if (nameFlag == eNameFromSubtree) { RefPtr<AccEvent> nameChangeEvent = new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent); return PushEvent(nameChangeEvent); } break; } parent = parent->Parent(); } } return false; }
STDMETHODIMP ia2Accessible::get_accessibleWithCaret(IUnknown** aAccessible, long* aCaretOffset) { if (!aAccessible || !aCaretOffset) return E_INVALIDARG; *aAccessible = nullptr; *aCaretOffset = -1; AccessibleWrap* acc = static_cast<AccessibleWrap*>(this); if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED; int32_t caretOffset = -1; Accessible* accWithCaret = SelectionMgr()->AccessibleWithCaret(&caretOffset); if (!accWithCaret || acc->Document() != accWithCaret->Document()) return S_FALSE; Accessible* child = accWithCaret; while (!child->IsDoc() && child != acc) child = child->Parent(); if (child != acc) return S_FALSE; *aAccessible = static_cast<IAccessible2*>( static_cast<AccessibleWrap*>(accWithCaret)); (*aAccessible)->AddRef(); *aCaretOffset = caretOffset; return S_OK; }
void LinkableAccessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent) { AccessibleWrap::BindToParent(aParent, aIndexInParent); // Cache action content. mActionAcc = nullptr; mIsLink = false; mIsOnclick = false; if (nsCoreUtils::HasClickListener(mContent)) { mIsOnclick = true; return; } // XXX: The logic looks broken since the click listener may be registered // on non accessible node in parent chain but this node is skipped when tree // is traversed. Accessible* walkUpAcc = this; while ((walkUpAcc = walkUpAcc->Parent()) && !walkUpAcc->IsDoc()) { if (walkUpAcc->LinkState() & states::LINKED) { mIsLink = true; mActionAcc = walkUpAcc; return; } if (nsCoreUtils::HasClickListener(walkUpAcc->GetContent())) { mActionAcc = walkUpAcc; mIsOnclick = true; return; } } }
NS_IMETHODIMP ARIAGridCellAccessible::GetRowIndex(int32_t* aRowIndex) { NS_ENSURE_ARG_POINTER(aRowIndex); *aRowIndex = -1; if (IsDefunct()) return NS_ERROR_FAILURE; Accessible* row = Parent(); if (!row) return NS_OK; Accessible* table = row->Parent(); if (!table) return NS_OK; *aRowIndex = 0; int32_t indexInTable = row->IndexInParent(); for (int32_t idx = 0; idx < indexInTable; idx++) { row = table->GetChildAt(idx); if (row->Role() == roles::ROW) (*aRowIndex)++; } return NS_OK; }
Accessible* nsAccessiblePivot::SearchBackward(Accessible* aAccessible, nsIAccessibleTraversalRule* aRule, bool aSearchCurrent, nsresult* aResult) { *aResult = NS_OK; // Initial position could be unset, in that case return null. if (!aAccessible) return nullptr; RuleCache cache(aRule); uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE; Accessible* accessible = AdjustStartPosition(aAccessible, cache, &filtered, aResult); NS_ENSURE_SUCCESS(*aResult, nullptr); if (aSearchCurrent && (filtered & nsIAccessibleTraversalRule::FILTER_MATCH)) { return accessible; } Accessible* root = GetActiveRoot(); while (accessible != root) { Accessible* parent = accessible->Parent(); int32_t idxInParent = accessible->IndexInParent(); while (idxInParent > 0) { if (!(accessible = parent->GetChildAt(--idxInParent))) continue; *aResult = cache.ApplyFilter(accessible, &filtered); NS_ENSURE_SUCCESS(*aResult, nullptr); Accessible* lastChild = nullptr; while (!(filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE) && (lastChild = accessible->LastChild())) { parent = accessible; accessible = lastChild; idxInParent = accessible->IndexInParent(); *aResult = cache.ApplyFilter(accessible, &filtered); NS_ENSURE_SUCCESS(*aResult, nullptr); } if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH) return accessible; } if (!(accessible = parent)) break; *aResult = cache.ApplyFilter(accessible, &filtered); NS_ENSURE_SUCCESS(*aResult, nullptr); if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH) return accessible; } return nullptr; }
Accessible* HTMLSelectOptionAccessible::ContainerWidget() const { Accessible* parent = Parent(); if (parent && parent->IsHTMLOptGroup()) parent = parent->Parent(); return parent && parent->IsListControl() ? parent : nullptr; }
Accessible* nsAccessiblePivot::SearchForward(Accessible* aAccessible, nsIAccessibleTraversalRule* aRule, bool aSearchCurrent, nsresult* aResult) { *aResult = NS_OK; // Initial position could be not set, in that case begin search from root. Accessible* root = GetActiveRoot(); Accessible* accessible = (!aAccessible) ? root : aAccessible; RuleCache cache(aRule); uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE; accessible = AdjustStartPosition(accessible, cache, &filtered, aResult); NS_ENSURE_SUCCESS(*aResult, nullptr); if (aSearchCurrent && (filtered & nsIAccessibleTraversalRule::FILTER_MATCH)) return accessible; while (true) { Accessible* firstChild = nullptr; while (!(filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE) && (firstChild = accessible->FirstChild())) { accessible = firstChild; *aResult = cache.ApplyFilter(accessible, &filtered); NS_ENSURE_SUCCESS(*aResult, nullptr); if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH) return accessible; } Accessible* sibling = nullptr; Accessible* temp = accessible; do { if (temp == root) break; sibling = temp->NextSibling(); if (sibling) break; } while ((temp = temp->Parent())); if (!sibling) break; accessible = sibling; *aResult = cache.ApplyFilter(accessible, &filtered); NS_ENSURE_SUCCESS(*aResult, nullptr); if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH) return accessible; } return nullptr; }
Accessible* ApplicationAccessible::FocusedChild() { Accessible* focus = FocusMgr()->FocusedAccessible(); if (focus && focus->Parent() == this) return focus; return nullptr; }
nsresult ARIAGridCellAccessible::GetAttributesInternal(nsIPersistentProperties* aAttributes) { if (IsDefunct()) return NS_ERROR_FAILURE; nsresult rv = HyperTextAccessibleWrap::GetAttributesInternal(aAttributes); NS_ENSURE_SUCCESS(rv, rv); // Expose "table-cell-index" attribute. Accessible* thisRow = Parent(); if (!thisRow || thisRow->Role() != roles::ROW) return NS_OK; int32_t colIdx = 0, colCount = 0; uint32_t childCount = thisRow->ChildCount(); for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) { Accessible* child = thisRow->GetChildAt(childIdx); if (child == this) colIdx = colCount; roles::Role role = child->Role(); if (role == roles::GRID_CELL || role == roles::ROWHEADER || role == roles::COLUMNHEADER) colCount++; } Accessible* table = thisRow->Parent(); if (!table) return NS_OK; roles::Role tableRole = table->Role(); if (tableRole != roles::TABLE && tableRole != roles::TREE_TABLE) return NS_OK; int32_t rowIdx = 0; childCount = table->ChildCount(); for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) { Accessible* child = table->GetChildAt(childIdx); if (child == thisRow) break; if (child->Role() == roles::ROW) rowIdx++; } int32_t idx = rowIdx * colCount + colIdx; nsAutoString stringIdx; stringIdx.AppendInt(idx); nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::tableCellIndex, stringIdx); return NS_OK; }
bool TreeWalker::Seek(nsIContent* aChildNode) { MOZ_ASSERT(aChildNode, "Child cannot be null"); Reset(); if (mAnchorNode == aChildNode) { return true; } nsIContent* childNode = nullptr; nsINode* parentNode = aChildNode; do { childNode = parentNode->AsContent(); parentNode = childNode->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) && (mChildFilter & nsIContent::eAllButXBL) ? childNode->GetParentNode() : childNode->GetFlattenedTreeParent(); if (!parentNode || !parentNode->IsElement()) { return false; } // If ARIA owned child. Accessible* child = mDoc->GetAccessible(childNode); if (child && child->IsRelocated()) { MOZ_ASSERT(!(mFlags & eScoped), "Walker should not be scoped when seeking into relocated children"); if (child->Parent() != mContext) { return false; } Accessible* ownedChild = nullptr; while ((ownedChild = mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx++)) && ownedChild != child); MOZ_ASSERT(ownedChild, "A child has to be in ARIA owned elements"); mPhase = eAtARIAOwns; return true; } // Look in DOM. dom::AllChildrenIterator* iter = PrependState(parentNode->AsElement(), true); if (!iter->Seek(childNode)) { return false; } if (parentNode == mAnchorNode) { mPhase = eAtDOM; return true; } } while (true); return false; }
TableAccessible* HTMLTableCellAccessible::Table() const { Accessible* parent = const_cast<HTMLTableCellAccessible*>(this); while ((parent = parent->Parent())) { if (parent->IsTable()) return parent->AsTable(); } return nullptr; }
Accessible* XULColorPickerTileAccessible::ContainerWidget() const { Accessible* parent = Parent(); if (parent) { Accessible* grandParent = parent->Parent(); if (grandParent && grandParent->IsMenuButton()) return grandParent; } return nullptr; }
TableAccessible* HTMLTableCellAccessible::Table() const { Accessible* parent = const_cast<HTMLTableCellAccessible*>(this); while ((parent = parent->Parent())) { roles::Role role = parent->Role(); if (role == roles::TABLE || role == roles::TREE_TABLE) return parent->AsTable(); } return nullptr; }
bool FocusManager::IsFocusWithin(const Accessible* aContainer) const { Accessible* child = FocusedAccessible(); while (child) { if (child == aContainer) return true; child = child->Parent(); } return false; }
TableAccessible* XULListCellAccessible::Table() const { Accessible* thisRow = Parent(); if (!thisRow || thisRow->Role() != roles::ROW) return nullptr; Accessible* table = thisRow->Parent(); if (!table || table->Role() != roles::TABLE) return nullptr; return table->AsTable(); }
static const gchar* getKeyBindingCB(AtkAction *aAction, gint aActionIndex) { AccessibleWrap* acc = GetAccessibleWrap(ATK_OBJECT(aAction)); if (!acc) return nullptr; // Return all key bindings including access key and keyboard shortcut. nsAutoString keyBindingsStr; // Get access key. KeyBinding keyBinding = acc->AccessKey(); if (!keyBinding.IsEmpty()) { keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat); Accessible* parent = acc->Parent(); roles::Role role = parent ? parent->Role() : roles::NOTHING; if (role == roles::PARENT_MENUITEM || role == roles::MENUITEM || role == roles::RADIO_MENU_ITEM || role == roles::CHECK_MENU_ITEM) { // It is submenu, expose keyboard shortcuts from menu hierarchy like // "s;<Alt>f:s" nsAutoString keysInHierarchyStr = keyBindingsStr; do { KeyBinding parentKeyBinding = parent->AccessKey(); if (!parentKeyBinding.IsEmpty()) { nsAutoString str; parentKeyBinding.ToString(str, KeyBinding::eAtkFormat); str.Append(':'); keysInHierarchyStr.Insert(str, 0); } } while ((parent = parent->Parent()) && parent->Role() != roles::MENUBAR); keyBindingsStr.Append(';'); keyBindingsStr.Append(keysInHierarchyStr); } } else { // No access key, add ';' to point this. keyBindingsStr.Append(';'); } // Get keyboard shortcut. keyBindingsStr.Append(';'); keyBinding = acc->KeyboardShortcut(); if (!keyBinding.IsEmpty()) { keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat); } return AccessibleWrap::ReturnString(keyBindingsStr); }
Accessible* nsAccUtils::GetAncestorWithRole(Accessible* aDescendant, uint32_t aRole) { Accessible* document = aDescendant->Document(); Accessible* parent = aDescendant; while ((parent = parent->Parent())) { uint32_t testRole = parent->Role(); if (testRole == aRole) return parent; if (parent == document) break; } return nullptr; }
bool nsAccessiblePivot::IsDescendantOf(Accessible* aAccessible, Accessible* aAncestor) { if (!aAncestor || aAncestor->IsDefunct()) return false; // XXX Optimize with IsInDocument() when appropriate. Blocked by bug 759875. Accessible* accessible = aAccessible; do { if (accessible == aAncestor) return true; } while ((accessible = accessible->Parent())); return false; }
already_AddRefed<nsIAccessibleTable> nsHTMLTableCellAccessible::GetTableAccessible() { Accessible* parent = this; while ((parent = parent->Parent())) { roles::Role role = parent->Role(); if (role == roles::TABLE || role == roles::TREE_TABLE) { nsIAccessibleTable* tableAcc = nsnull; CallQueryInterface(parent, &tableAcc); return tableAcc; } } return nsnull; }
void TextRange::Text(nsAString& aText) const { Accessible* current = mStartContainer->GetChildAtOffset(mStartOffset); uint32_t startIntlOffset = mStartOffset - mStartContainer->GetChildOffset(current); while (current && TextInternal(aText, current, startIntlOffset)) { current = current->Parent(); if (!current) break; current = current->NextSibling(); } }
Accessible* nsAccUtils::GetSelectableContainer(Accessible* aAccessible, uint64_t aState) { if (!aAccessible) return nullptr; if (!(aState & states::SELECTABLE)) return nullptr; Accessible* parent = aAccessible; while ((parent = parent->Parent()) && !parent->IsSelect()) { if (parent->Role() == roles::PANE) return nullptr; } return parent; }
NS_IMETHODIMP nsAccessiblePivot::MoveToPoint(nsIAccessibleTraversalRule* aRule, int32_t aX, int32_t aY, bool aIgnoreNoMatch, bool aIsFromUserInput, uint8_t aArgc, bool* aResult) { NS_ENSURE_ARG_POINTER(aResult); NS_ENSURE_ARG_POINTER(aRule); *aResult = false; Accessible* root = GetActiveRoot(); NS_ENSURE_TRUE(root && !root->IsDefunct(), NS_ERROR_NOT_IN_TREE); RuleCache cache(aRule); Accessible* match = nullptr; Accessible* child = root->ChildAtPoint(aX, aY, Accessible::eDeepestChild); while (child && root != child) { uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE; nsresult rv = cache.ApplyFilter(child, &filtered); NS_ENSURE_SUCCESS(rv, rv); // Ignore any matching nodes that were below this one if (filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE) match = nullptr; // Match if no node below this is a match if ((filtered & nsIAccessibleTraversalRule::FILTER_MATCH) && !match) { int32_t childX, childY, childWidth, childHeight; child->GetBounds(&childX, &childY, &childWidth, &childHeight); // Double-check child's bounds since the deepest child may have been out // of bounds. This assures we don't return a false positive. if (aX >= childX && aX < childX + childWidth && aY >= childY && aY < childY + childHeight) match = child; } child = child->Parent(); } if (match || !aIgnoreNoMatch) *aResult = MovePivotInternal(match, nsIAccessiblePivot::REASON_POINT, (aArgc > 0) ? aIsFromUserInput : true); return NS_OK; }
NS_IMETHODIMP nsXULListCellAccessible::GetTable(nsIAccessibleTable **aTable) { NS_ENSURE_ARG_POINTER(aTable); *aTable = nsnull; if (IsDefunct()) return NS_ERROR_FAILURE; Accessible* thisRow = Parent(); if (!thisRow || thisRow->Role() != roles::ROW) return NS_OK; Accessible* table = thisRow->Parent(); if (!table || table->Role() != roles::TABLE) return NS_OK; CallQueryInterface(table, aTable); return NS_OK; }
Accessible* nsAccUtils::TableFor(Accessible* aRow) { if (aRow) { Accessible* table = aRow->Parent(); if (table) { roles::Role tableRole = table->Role(); if (tableRole == roles::GROUPING) { // if there's a rowgroup. table = table->Parent(); if (table) tableRole = table->Role(); } return (tableRole == roles::TABLE || tableRole == roles::TREE_TABLE || tableRole == roles::MATHML_TABLE) ? table : nullptr; } } return nullptr; }
uint32_t XULListCellAccessible::RowIdx() const { Accessible* row = Parent(); if (!row) return 0; Accessible* table = row->Parent(); if (!table) return 0; int32_t indexInTable = row->IndexInParent(); uint32_t rowIdx = 0; for (int32_t idx = 0; idx < indexInTable; idx++) { row = table->GetChildAt(idx); if (row->Role() == roles::ROW) rowIdx++; } return rowIdx; }