NS_IMETHODIMP xpcAccessible::GetRelationByType(uint32_t aType, nsIAccessibleRelation** aRelation) { NS_ENSURE_ARG_POINTER(aRelation); *aRelation = nullptr; NS_ENSURE_ARG(aType <= static_cast<uint32_t>(RelationType::LAST)); if (IntlGeneric().IsNull()) return NS_ERROR_FAILURE; if (IntlGeneric().IsAccessible()) { Relation rel = Intl()->RelationByType(static_cast<RelationType>(aType)); NS_ADDREF(*aRelation = new nsAccessibleRelation(aType, &rel)); return NS_OK; } ProxyAccessible* proxy = IntlGeneric().AsProxy(); nsTArray<ProxyAccessible*> targets = proxy->RelationByType(static_cast<RelationType>(aType)); NS_ADDREF(*aRelation = new nsAccessibleRelation(aType, &targets)); return NS_OK; }
NS_IMETHODIMP xpcAccessible::GetAttributes(nsIPersistentProperties** aAttributes) { NS_ENSURE_ARG_POINTER(aAttributes); *aAttributes = nullptr; if (IntlGeneric().IsNull()) { return NS_ERROR_FAILURE; } if (Accessible* acc = Intl()) { nsCOMPtr<nsIPersistentProperties> attributes = acc->Attributes(); attributes.swap(*aAttributes); return NS_OK; } ProxyAccessible* proxy = IntlGeneric().AsProxy(); AutoTArray<Attribute, 10> attrs; proxy->Attributes(&attrs); nsCOMPtr<nsIPersistentProperties> props = do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID); uint32_t attrCount = attrs.Length(); nsAutoString unused; for (uint32_t i = 0; i < attrCount; i++) { props->SetStringProperty(attrs[i].Name(), attrs[i].Value(), unused); } props.forget(aAttributes); return NS_OK; }
AtkAttributeSet * getAttributesCB(AtkObject *aAtkObj) { AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); if (accWrap) return GetAttributeSet(accWrap); ProxyAccessible* proxy = GetProxy(aAtkObj); if (!proxy) return nullptr; nsAutoTArray<Attribute, 10> attrs; proxy->Attributes(&attrs); if (attrs.IsEmpty()) return nullptr; AtkAttributeSet* objAttributeSet = nullptr; for (uint32_t i = 0; i < attrs.Length(); i++) { AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute)); objAttr->name = g_strdup(attrs[i].Name().get()); objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(attrs[i].Value()).get()); objAttributeSet = g_slist_prepend(objAttributeSet, objAttr); } return objAttributeSet; }
ipc::IPCResult DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID, bool aCreating) { // We do not use GetAccessible here because we want to be sure to not get the // document it self. ProxyEntry* e = mAccessibles.GetEntry(aParentID); if (!e) { return IPC_FAIL(this, "binding to nonexistant proxy!"); } ProxyAccessible* outerDoc = e->mProxy; MOZ_ASSERT(outerDoc); // OuterDocAccessibles are expected to only have a document as a child. // However for compatibility we tolerate replacing one document with another // here. if (outerDoc->ChildrenCount() > 1 || (outerDoc->ChildrenCount() == 1 && !outerDoc->ChildAt(0)->IsDoc())) { return IPC_FAIL(this, "binding to proxy that can't be a outerDoc!"); } aChildDoc->SetParent(outerDoc); outerDoc->SetChildDoc(aChildDoc); mChildDocs.AppendElement(aChildDoc->mActorID); aChildDoc->mParentDoc = mActorID; if (aCreating) { ProxyCreated(aChildDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT); } return IPC_OK(); }
bool DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID) { if (mShutdown) return true; MOZ_DIAGNOSTIC_ASSERT(CheckDocTree()); // We shouldn't actually need this because mAccessibles shouldn't have an // entry for the document itself, but it doesn't hurt to be explicit. if (!aRootID) { NS_ERROR("trying to hide entire document?"); return false; } ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID); if (!rootEntry) { NS_ERROR("invalid root being removed!"); return true; } ProxyAccessible* root = rootEntry->mProxy; if (!root) { NS_ERROR("invalid root being removed!"); return true; } ProxyAccessible* parent = root->Parent(); parent->RemoveChild(root); root->Shutdown(); MOZ_DIAGNOSTIC_ASSERT(CheckDocTree()); return true; }
bool DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID, bool aCreating) { // We do not use GetAccessible here because we want to be sure to not get the // document it self. ProxyEntry* e = mAccessibles.GetEntry(aParentID); if (!e) return false; ProxyAccessible* outerDoc = e->mProxy; MOZ_ASSERT(outerDoc); // OuterDocAccessibles are expected to only have a document as a child. // However for compatibility we tolerate replacing one document with another // here. if (outerDoc->ChildrenCount() > 1 || (outerDoc->ChildrenCount() == 1 && !outerDoc->ChildAt(0)->IsDoc())) { return false; } aChildDoc->mParent = outerDoc; outerDoc->SetChildDoc(aChildDoc); mChildDocs.AppendElement(aChildDoc); aChildDoc->mParentDoc = this; if (aCreating) { ProxyCreated(aChildDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT); } return true; }
AtkRole getRoleCB(AtkObject *aAtkObj) { if (aAtkObj->role != ATK_ROLE_INVALID) return aAtkObj->role; AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); a11y::role role; if (!accWrap) { ProxyAccessible* proxy = GetProxy(aAtkObj); if (!proxy) return ATK_ROLE_INVALID; role = proxy->Role(); } else { #ifdef DEBUG NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap), "Does not support Text interface when it should"); #endif role = accWrap->Role(); } #define ROLE(geckoRole, stringRole, atkRole, macRole, \ msaaRole, ia2Role, nameRule) \ case roles::geckoRole: \ aAtkObj->role = atkRole; \ break; switch (role) { #include "RoleMap.h" default: MOZ_CRASH("Unknown role."); }; #undef ROLE if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1)) aAtkObj->role = ATK_ROLE_LIST; else if (aAtkObj->role == ATK_ROLE_TABLE_ROW && !IsAtkVersionAtLeast(2, 1)) aAtkObj->role = ATK_ROLE_LIST_ITEM; else if (aAtkObj->role == ATK_ROLE_MATH && !IsAtkVersionAtLeast(2, 12)) aAtkObj->role = ATK_ROLE_PANEL; else if (aAtkObj->role == ATK_ROLE_STATIC && !IsAtkVersionAtLeast(2, 16)) aAtkObj->role = ATK_ROLE_TEXT; else if ((aAtkObj->role == ATK_ROLE_MATH_FRACTION || aAtkObj->role == ATK_ROLE_MATH_ROOT) && !IsAtkVersionAtLeast(2, 16)) aAtkObj->role = ATK_ROLE_UNKNOWN; return aAtkObj->role; }
NS_IMETHODIMP xpcAccessible::GetId(nsAString& aID) { ProxyAccessible* proxy = IntlGeneric().AsProxy(); if (!proxy) { return NS_ERROR_FAILURE; } nsString id; proxy->DOMNodeID(id); aID.Assign(id); return NS_OK; }
uint32_t DocAccessibleParent::AddSubtree(ProxyAccessible* aParent, const nsTArray<a11y::AccessibleData>& aNewTree, uint32_t aIdx, uint32_t aIdxInParent) { if (aNewTree.Length() <= aIdx) { NS_ERROR("bad index in serialized tree!"); return 0; } const AccessibleData& newChild = aNewTree[aIdx]; if (newChild.Role() > roles::LAST_ROLE) { NS_ERROR("invalid role"); return 0; } if (mAccessibles.Contains(newChild.ID())) { NS_ERROR("ID already in use"); return 0; } auto role = static_cast<a11y::role>(newChild.Role()); ProxyAccessible* newProxy = new ProxyAccessible(newChild.ID(), aParent, this, role, newChild.Interfaces()); aParent->AddChildAt(aIdxInParent, newProxy); mAccessibles.PutEntry(newChild.ID())->mProxy = newProxy; ProxyCreated(newProxy, newChild.Interfaces()); #if defined(XP_WIN) WrapperFor(newProxy)->SetID(newChild.MsaaID()); #endif uint32_t accessibles = 1; uint32_t kids = newChild.ChildrenCount(); for (uint32_t i = 0; i < kids; i++) { uint32_t consumed = AddSubtree(newProxy, aNewTree, aIdx + accessibles, i); if (!consumed) return 0; accessibles += consumed; } MOZ_ASSERT(newProxy->ChildrenCount() == kids); return accessibles; }
bool DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID) { ProxyAccessible* outerDoc = mAccessibles.GetEntry(aParentID)->mProxy; if (!outerDoc) return false; aChildDoc->mParent = outerDoc; outerDoc->SetChildDoc(aChildDoc); mChildDocs.AppendElement(aChildDoc); aChildDoc->mParentDoc = this; ProxyCreated(aChildDoc, 0); return true; }
static gboolean setCurrentValueCB(AtkValue *obj, const GValue *value) { ProxyAccessible* proxy = nullptr; AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj)); if (!accWrap) { proxy = GetProxy(ATK_OBJECT(obj)); if (!proxy) { return FALSE; } } double accValue =g_value_get_double(value); return accWrap ? accWrap->SetCurValue(accValue) : proxy->SetCurValue(accValue); }
bool ProxyAccessibleWrap::WrapperRangeInfo(double* aCurVal, double* aMinVal, double* aMaxVal, double* aStep) { if (HasNumericValue()) { ProxyAccessible* proxy = Proxy(); *aCurVal = proxy->CurValue(); *aMinVal = proxy->MinValue(); *aMaxVal = proxy->MaxValue(); *aStep = proxy->Step(); return true; } return false; }
const gchar * getDocumentAttributeValueCB(AtkDocument *aDocument, const gchar *aAttrName) { ProxyAccessible* proxy = nullptr; DocAccessible* document = nullptr; AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument)); if (accWrap) { if (!accWrap->IsDoc()) { return nullptr; } document = accWrap->AsDoc(); } else { proxy = GetProxy(ATK_OBJECT(aDocument)); if (!proxy) { return nullptr; } } nsAutoString attrValue; if (!strcasecmp(aAttrName, kDocTypeName)) { if (document) { document->DocType(attrValue); } else { proxy->DocType(attrValue); } } else if (!strcasecmp(aAttrName, kDocUrlName)) { if (document) { document->URL(attrValue); } else { proxy->URL(attrValue); } } else if (!strcasecmp(aAttrName, kMimeTypeName)) { if (document) { document->MimeType(attrValue); } else { proxy->MimeType(attrValue); } } else { return nullptr; } return attrValue.IsEmpty() ? nullptr : AccessibleWrap::ReturnString(attrValue); }
bool DocAccessibleParent::RecvShowEvent(const ShowEventData& aData) { if (mShutdown) return true; if (aData.NewTree().IsEmpty()) { NS_ERROR("no children being added"); return false; } ProxyAccessible* parent = nullptr; if (aData.ID()) { ProxyEntry* e = mAccessibles.GetEntry(aData.ID()); if (e) parent = e->mProxy; } else { parent = this; } // XXX This should really never happen, but sometimes we fail to fire the // required show events. if (!parent) { NS_ERROR("adding child to unknown accessible"); return false; } uint32_t newChildIdx = aData.Idx(); if (newChildIdx > parent->ChildrenCount()) { NS_ERROR("invalid index to add child at"); return false; } uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx); MOZ_ASSERT(consumed == aData.NewTree().Length()); #ifdef DEBUG for (uint32_t i = 0; i < consumed; i++) { uint64_t id = aData.NewTree()[i].ID(); MOZ_ASSERT(mAccessibles.GetEntry(id)); } #endif return consumed != 0; }
bool DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID, const bool& aFromUser) { if (mShutdown) return true; MOZ_DIAGNOSTIC_ASSERT(CheckDocTree()); // We shouldn't actually need this because mAccessibles shouldn't have an // entry for the document itself, but it doesn't hurt to be explicit. if (!aRootID) { NS_ERROR("trying to hide entire document?"); return false; } ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID); if (!rootEntry) { NS_ERROR("invalid root being removed!"); return true; } ProxyAccessible* root = rootEntry->mProxy; if (!root) { NS_ERROR("invalid root being removed!"); return true; } ProxyAccessible* parent = root->Parent(); ProxyShowHideEvent(root, parent, false, aFromUser); RefPtr<xpcAccHideEvent> event = nullptr; if (nsCoreUtils::AccEventObserversExist()) { uint32_t type = nsIAccessibleEvent::EVENT_HIDE; xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(root); xpcAccessibleGeneric* xpcParent = GetXPCAccessible(parent); ProxyAccessible* next = root->NextSibling(); xpcAccessibleGeneric* xpcNext = next ? GetXPCAccessible(next) : nullptr; ProxyAccessible* prev = root->PrevSibling(); xpcAccessibleGeneric* xpcPrev = prev ? GetXPCAccessible(prev) : nullptr; xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this); nsIDOMNode* node = nullptr; event = new xpcAccHideEvent(type, xpcAcc, doc, node, aFromUser, xpcParent, xpcNext, xpcPrev); } parent->RemoveChild(root); root->Shutdown(); MOZ_DIAGNOSTIC_ASSERT(CheckDocTree()); if (event) { nsCoreUtils::DispatchAccEvent(Move(event)); } return true; }
NS_IMETHODIMP xpcAccessible::GetPreviousSibling(nsIAccessible** aPreviousSibling) { NS_ENSURE_ARG_POINTER(aPreviousSibling); *aPreviousSibling = nullptr; if (IntlGeneric().IsNull()) return NS_ERROR_FAILURE; if (IntlGeneric().IsAccessible()) { nsresult rv = NS_OK; NS_IF_ADDREF(*aPreviousSibling = ToXPC(Intl()->GetSiblingAtOffset(-1, &rv))); return rv; } ProxyAccessible* proxy = IntlGeneric().AsProxy(); NS_ENSURE_STATE(proxy); NS_IF_ADDREF(*aPreviousSibling = ToXPC(proxy->PrevSibling())); return *aPreviousSibling ? NS_OK : NS_ERROR_FAILURE; }
static void getMinimumIncrementCB(AtkValue *obj, GValue *minimumIncrement) { ProxyAccessible* proxy = nullptr; AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj)); if (!accWrap) { proxy = GetProxy(ATK_OBJECT(obj)); if (!proxy) { return; } } memset(minimumIncrement, 0, sizeof (GValue)); double accValue = accWrap ? accWrap->Step() : proxy->Step(); if (IsNaN(accValue)) accValue = 0; // zero if the minimum increment is undefined g_value_init(minimumIncrement, G_TYPE_DOUBLE); g_value_set_double(minimumIncrement, accValue); }
static void getMinimumValueCB(AtkValue *obj, GValue *value) { ProxyAccessible* proxy = nullptr; AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj)); if (!accWrap) { proxy = GetProxy(ATK_OBJECT(obj)); if (!proxy) { return; } } memset(value, 0, sizeof (GValue)); double accValue = accWrap ? accWrap->MinValue() : proxy->MinValue(); if (IsNaN(accValue)) return; g_value_init(value, G_TYPE_DOUBLE); g_value_set_double(value, accValue); }
bool DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID) { ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID); if (!rootEntry) { NS_ERROR("invalid root being removed!"); return true; } ProxyAccessible* root = rootEntry->mProxy; if (!root) { NS_ERROR("invalid root being removed!"); return true; } ProxyAccessible* parent = root->Parent(); parent->RemoveChild(root); root->Shutdown(); return true; }
xpcAccessibleGeneric::~xpcAccessibleGeneric() { if (mIntl.IsNull()) { return; } xpcAccessibleDocument* xpcDoc = nullptr; if (mIntl.IsAccessible()) { Accessible* acc = mIntl.AsAccessible(); if (!acc->IsDoc() && !acc->IsApplication()) { xpcDoc = GetAccService()->GetXPCDocument(acc->Document()); xpcDoc->NotifyOfShutdown(acc); } } else { ProxyAccessible* proxy = mIntl.AsProxy(); if (!proxy->IsDoc()) { xpcDoc = GetAccService()->GetXPCDocument(proxy->Document()); xpcDoc->NotifyOfShutdown(proxy); } } }
static AtkAttributeSet* getDefaultAttributesCB(AtkText *aText) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); if (accWrap) { HyperTextAccessible* text = accWrap->AsHyperText(); if (!text || !text->IsTextRole()) { return nullptr; } nsCOMPtr<nsIPersistentProperties> attributes = text->DefaultTextAttributes(); return ConvertToAtkTextAttributeSet(attributes); } ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText)); if (!proxy) { return nullptr; } nsAutoTArray<Attribute, 10> attrs; proxy->DefaultTextAttributes(&attrs); return ConvertToAtkTextAttributeSet(attrs); }
bool DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID, bool aCreating) { // We do not use GetAccessible here because we want to be sure to not get the // document it self. ProxyEntry* e = mAccessibles.GetEntry(aParentID); if (!e) return false; ProxyAccessible* outerDoc = e->mProxy; MOZ_ASSERT(outerDoc); aChildDoc->mParent = outerDoc; outerDoc->SetChildDoc(aChildDoc); mChildDocs.AppendElement(aChildDoc); aChildDoc->mParentDoc = this; if (aCreating) { ProxyCreated(aChildDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT); } return true; }
static AtkAttributeSet* getRunAttributesCB(AtkText *aText, gint aOffset, gint *aStartOffset, gint *aEndOffset) { *aStartOffset = -1; *aEndOffset = -1; int32_t startOffset = 0, endOffset = 0; AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); if (accWrap) { HyperTextAccessible* text = accWrap->AsHyperText(); if (!text || !text->IsTextRole()) { return nullptr; } nsCOMPtr<nsIPersistentProperties> attributes = text->TextAttributes(false, aOffset, &startOffset, &endOffset); *aStartOffset = startOffset; *aEndOffset = endOffset; return ConvertToAtkTextAttributeSet(attributes); } ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText)); if (!proxy) { return nullptr; } nsAutoTArray<Attribute, 10> attrs; proxy->TextAttributes(false, aOffset, &attrs, &startOffset, &endOffset); *aStartOffset = startOffset; *aEndOffset = endOffset; return ConvertToAtkTextAttributeSet(attrs); }
bool DocAccessibleParent::RecvShowEvent(const ShowEventData& aData, const bool& aFromUser) { if (mShutdown) return true; MOZ_DIAGNOSTIC_ASSERT(CheckDocTree()); if (aData.NewTree().IsEmpty()) { NS_ERROR("no children being added"); return false; } ProxyAccessible* parent = GetAccessible(aData.ID()); // XXX This should really never happen, but sometimes we fail to fire the // required show events. if (!parent) { NS_ERROR("adding child to unknown accessible"); return true; } uint32_t newChildIdx = aData.Idx(); if (newChildIdx > parent->ChildrenCount()) { NS_ERROR("invalid index to add child at"); return true; } uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx); MOZ_ASSERT(consumed == aData.NewTree().Length()); // XXX This shouldn't happen, but if we failed to add children then the below // is pointless and can crash. if (!consumed) { return true; } #ifdef DEBUG for (uint32_t i = 0; i < consumed; i++) { uint64_t id = aData.NewTree()[i].ID(); MOZ_ASSERT(mAccessibles.GetEntry(id)); } #endif MOZ_DIAGNOSTIC_ASSERT(CheckDocTree()); ProxyAccessible* target = parent->ChildAt(newChildIdx); ProxyShowHideEvent(target, parent, true, aFromUser); if (!nsCoreUtils::AccEventObserversExist()) { return true; } uint32_t type = nsIAccessibleEvent::EVENT_SHOW; xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target); xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this); nsIDOMNode* node = nullptr; RefPtr<xpcAccEvent> event = new xpcAccEvent(type, xpcAcc, doc, node, aFromUser); nsCoreUtils::DispatchAccEvent(Move(event)); return true; }