From 250583af1b0eed43c0b12cb15f31d1e3f0d084c2 Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Wed, 1 Sep 2010 12:26:13 +0900 Subject: [PATCH] Bug 589399 - add pseudo HyperLinkAccessible interface, r=davidb, f=neil, a=davidb --HG-- rename : accessible/tests/mochitest/test_nsIAccessibleHyperLink.html => accessible/tests/mochitest/hyperlink/test_general.html rename : accessible/tests/mochitest/test_nsIAccessibleHyperLink.xul => accessible/tests/mochitest/hyperlink/test_general.xul --- accessible/src/atk/nsAccessibleWrap.cpp | 7 +- accessible/src/atk/nsMaiHyperlink.cpp | 71 +++---- accessible/src/atk/nsMaiHyperlink.h | 10 +- .../src/atk/nsMaiInterfaceHyperlinkImpl.cpp | 7 +- accessible/src/base/nsAccessible.cpp | 180 ++++++++++++------ accessible/src/base/nsAccessible.h | 46 ++++- .../src/base/nsBaseWidgetAccessible.cpp | 41 ++-- accessible/src/base/nsBaseWidgetAccessible.h | 6 +- .../src/html/nsHTMLImageMapAccessible.cpp | 91 ++++----- .../src/html/nsHTMLImageMapAccessible.h | 14 +- accessible/src/html/nsHTMLLinkAccessible.cpp | 24 +-- accessible/src/html/nsHTMLLinkAccessible.h | 7 +- accessible/src/msaa/CAccessibleHyperlink.cpp | 80 +++----- accessible/src/xul/nsXULTextAccessible.cpp | 50 +++-- accessible/src/xul/nsXULTextAccessible.h | 9 +- accessible/tests/mochitest/Makefile.in | 14 +- .../tests/mochitest/hyperlink/Makefile.in | 54 ++++++ .../test_general.html} | 0 .../test_general.xul} | 0 19 files changed, 436 insertions(+), 275 deletions(-) create mode 100644 accessible/tests/mochitest/hyperlink/Makefile.in rename accessible/tests/mochitest/{test_nsIAccessibleHyperLink.html => hyperlink/test_general.html} (100%) rename accessible/tests/mochitest/{test_nsIAccessibleHyperLink.xul => hyperlink/test_general.xul} (100%) diff --git a/accessible/src/atk/nsAccessibleWrap.cpp b/accessible/src/atk/nsAccessibleWrap.cpp index 0ec83cdeaad..84485e95593 100644 --- a/accessible/src/atk/nsAccessibleWrap.cpp +++ b/accessible/src/atk/nsAccessibleWrap.cpp @@ -452,11 +452,8 @@ nsAccessibleWrap::CreateMaiInterfaces(void) interfacesBits |= 1 << MAI_INTERFACE_IMAGE; } - //nsIAccessibleHyperLink - nsCOMPtr accessInterfaceHyperlink; - QueryInterface(NS_GET_IID(nsIAccessibleHyperLink), - getter_AddRefs(accessInterfaceHyperlink)); - if (accessInterfaceHyperlink) { + // HyperLinkAccessible + if (IsHyperLink()) { interfacesBits |= 1 << MAI_INTERFACE_HYPERLINK_IMPL; } diff --git a/accessible/src/atk/nsMaiHyperlink.cpp b/accessible/src/atk/nsMaiHyperlink.cpp index 9d5418cce28..d9f1a3b7192 100644 --- a/accessible/src/atk/nsMaiHyperlink.cpp +++ b/accessible/src/atk/nsMaiHyperlink.cpp @@ -93,7 +93,7 @@ static gint getAnchorCountCB(AtkHyperlink *aLink); G_END_DECLS static gpointer parent_class = NULL; -static nsIAccessibleHyperLink * +static nsAccessible* get_accessible_hyperlink(AtkHyperlink *aHyperlink); GType @@ -122,8 +122,8 @@ mai_atk_hyperlink_get_type(void) return type; } -MaiHyperlink::MaiHyperlink(nsIAccessibleHyperLink *aAcc): - mHyperlink(aAcc), +MaiHyperlink::MaiHyperlink(nsAccessible* aHyperLink) : + mHyperlink(aHyperLink), mMaiAtkHyperlink(nsnull) { } @@ -144,8 +144,7 @@ MaiHyperlink::GetAtkHyperlink(void) if (mMaiAtkHyperlink) return mMaiAtkHyperlink; - nsCOMPtr accessIf(do_QueryInterface(mHyperlink)); - if (!accessIf) + if (!mHyperlink->IsHyperLink()) return nsnull; mMaiAtkHyperlink = @@ -214,17 +213,18 @@ finalizeCB(GObject *aObj) gchar * getUriCB(AtkHyperlink *aLink, gint aLinkIndex) { - nsIAccessibleHyperLink *accHyperlink = get_accessible_hyperlink(aLink); - NS_ENSURE_TRUE(accHyperlink, nsnull); + nsAccessible* hyperlink = get_accessible_hyperlink(aLink); + NS_ENSURE_TRUE(hyperlink, nsnull); MaiAtkHyperlink *maiAtkHyperlink = MAI_ATK_HYPERLINK(aLink); - nsCOMPtr uri; - nsresult rv = accHyperlink->GetURI(aLinkIndex,getter_AddRefs(uri)); - if (NS_FAILED(rv) || !uri) + nsCOMPtr uri = hyperlink->GetAnchorURI(aLinkIndex); + if (!uri) return nsnull; + nsCAutoString cautoStr; - rv = uri->GetSpec(cautoStr); + nsresult rv = uri->GetSpec(cautoStr); + NS_ENSURE_SUCCESS(rv, nsnull); return g_strdup(cautoStr.get()); } @@ -232,14 +232,13 @@ getUriCB(AtkHyperlink *aLink, gint aLinkIndex) AtkObject * getObjectCB(AtkHyperlink *aLink, gint aLinkIndex) { - nsIAccessibleHyperLink *accHyperlink = get_accessible_hyperlink(aLink); - NS_ENSURE_TRUE(accHyperlink, nsnull); + nsAccessible* hyperlink = get_accessible_hyperlink(aLink); + NS_ENSURE_TRUE(hyperlink, nsnull); - nsCOMPtr accObj; - accHyperlink->GetAnchor(aLinkIndex, getter_AddRefs(accObj)); - NS_ENSURE_TRUE(accObj, nsnull); + nsAccessible* anchor = hyperlink->GetAnchor(aLinkIndex); + NS_ENSURE_TRUE(anchor, nsnull); - AtkObject *atkObj = nsAccessibleWrap::GetAtkObject(accObj); + AtkObject *atkObj = nsAccessibleWrap::GetAtkObject(anchor); //no need to add ref it, because it is "get" not "ref" return atkObj; } @@ -247,52 +246,42 @@ getObjectCB(AtkHyperlink *aLink, gint aLinkIndex) gint getEndIndexCB(AtkHyperlink *aLink) { - nsIAccessibleHyperLink *accHyperlink = get_accessible_hyperlink(aLink); - NS_ENSURE_TRUE(accHyperlink, -1); + nsAccessible* hyperlink = get_accessible_hyperlink(aLink); + NS_ENSURE_TRUE(hyperlink, -1); - PRInt32 endIndex = -1; - nsresult rv = accHyperlink->GetEndIndex(&endIndex); - - return (NS_FAILED(rv)) ? -1 : static_cast(endIndex); + return static_cast(hyperlink->EndOffset()); } gint getStartIndexCB(AtkHyperlink *aLink) { - nsIAccessibleHyperLink *accHyperlink = get_accessible_hyperlink(aLink); - NS_ENSURE_TRUE(accHyperlink, -1); + nsAccessible* hyperlink = get_accessible_hyperlink(aLink); + NS_ENSURE_TRUE(hyperlink, -1); - PRInt32 startIndex = -1; - nsresult rv = accHyperlink->GetStartIndex(&startIndex); - - return (NS_FAILED(rv)) ? -1 : static_cast(startIndex); + return static_cast(hyperlink->StartOffset()); } gboolean isValidCB(AtkHyperlink *aLink) { - nsIAccessibleHyperLink *accHyperlink = get_accessible_hyperlink(aLink); - NS_ENSURE_TRUE(accHyperlink, FALSE); + nsAccessible* hyperlink = get_accessible_hyperlink(aLink); + NS_ENSURE_TRUE(hyperlink, FALSE); - PRBool isValid = PR_FALSE; - nsresult rv = accHyperlink->GetValid(&isValid); - return (NS_FAILED(rv)) ? FALSE : static_cast(isValid); + return static_cast(hyperlink->IsValid()); } gint getAnchorCountCB(AtkHyperlink *aLink) { - nsIAccessibleHyperLink *accHyperlink = get_accessible_hyperlink(aLink); - NS_ENSURE_TRUE(accHyperlink, -1); + nsAccessible* hyperlink = get_accessible_hyperlink(aLink); + NS_ENSURE_TRUE(hyperlink, -1); - PRInt32 count = -1; - nsresult rv = accHyperlink->GetAnchorCount(&count); - return (NS_FAILED(rv)) ? -1 : static_cast(count); + return static_cast(hyperlink->AnchorCount()); } // Check if aHyperlink is a valid MaiHyperlink, and return the -// nsIAccessibleHyperLink related. -nsIAccessibleHyperLink * +// HyperLinkAccessible related. +nsAccessible* get_accessible_hyperlink(AtkHyperlink *aHyperlink) { NS_ENSURE_TRUE(MAI_IS_ATK_HYPERLINK(aHyperlink), nsnull); diff --git a/accessible/src/atk/nsMaiHyperlink.h b/accessible/src/atk/nsMaiHyperlink.h index 3262cb64209..5f9a6649d72 100644 --- a/accessible/src/atk/nsMaiHyperlink.h +++ b/accessible/src/atk/nsMaiHyperlink.h @@ -42,7 +42,7 @@ #define __MAI_HYPERLINK_H__ #include "nsMai.h" -#include "nsIAccessibleHyperLink.h" +#include "nsAccessible.h" struct _AtkHyperlink; typedef struct _AtkHyperlink AtkHyperlink; @@ -54,17 +54,17 @@ typedef struct _AtkHyperlink AtkHyperlink; class MaiHyperlink { public: - MaiHyperlink(nsIAccessibleHyperLink *aAcc); + MaiHyperlink(nsAccessible* aHyperLink); ~MaiHyperlink(); public: AtkHyperlink *GetAtkHyperlink(void); - nsIAccessibleHyperLink *GetAccHyperlink(void) { - return mHyperlink; + nsAccessible* GetAccHyperlink(void) { + return mHyperlink && mHyperlink->IsHyperLink() ? mHyperlink : nsnull; } protected: - nsIAccessibleHyperLink *mHyperlink; + nsAccessible* mHyperlink; AtkHyperlink *mMaiAtkHyperlink; public: static nsresult Initialize(AtkHyperlink *aObj, MaiHyperlink *aClass); diff --git a/accessible/src/atk/nsMaiInterfaceHyperlinkImpl.cpp b/accessible/src/atk/nsMaiInterfaceHyperlinkImpl.cpp index 558bf6c7673..1e29336e821 100644 --- a/accessible/src/atk/nsMaiInterfaceHyperlinkImpl.cpp +++ b/accessible/src/atk/nsMaiInterfaceHyperlinkImpl.cpp @@ -56,11 +56,8 @@ getHyperlinkCB(AtkHyperlinkImpl *aImpl) if (!accWrap) return nsnull; - nsCOMPtr accHyperlink; - accWrap->QueryInterface(NS_GET_IID(nsIAccessibleHyperLink), - getter_AddRefs(accHyperlink)); - NS_ENSURE_TRUE(accHyperlink, nsnull); - + NS_ENSURE_TRUE(accWrap->IsHyperLink(), nsnull); + MaiHyperlink *maiHyperlink = accWrap->GetMaiHyperlink(); NS_ENSURE_TRUE(maiHyperlink, nsnull); return maiHyperlink->GetAtkHyperlink(); diff --git a/accessible/src/base/nsAccessible.cpp b/accessible/src/base/nsAccessible.cpp index 0d5f6e60230..6f2ff0f83d1 100644 --- a/accessible/src/base/nsAccessible.cpp +++ b/accessible/src/base/nsAccessible.cpp @@ -180,10 +180,7 @@ nsresult nsAccessible::QueryInterface(REFNSIID aIID, void** aInstancePtr) } if (aIID.Equals(NS_GET_IID(nsIAccessibleHyperLink))) { - // Every embedded accessible within hypertext accessible implements - // hyperlink interface. - nsCOMPtr hyperTextParent = do_QueryObject(GetParent()); - if (hyperTextParent && nsAccUtils::IsEmbeddedObject(this)) { + if (IsHyperLink()) { *aInstancePtr = static_cast(this); NS_ADDREF_THIS(); return NS_OK; @@ -2525,7 +2522,12 @@ NS_IMETHODIMP nsAccessible::GetAnchorCount(PRInt32 *aAnchorCount) { NS_ENSURE_ARG_POINTER(aAnchorCount); - *aAnchorCount = 1; + *aAnchorCount = 0; + + if (IsDefunct()) + return NS_ERROR_FAILURE; + + *aAnchorCount = AnchorCount(); return NS_OK; } @@ -2539,8 +2541,8 @@ nsAccessible::GetStartIndex(PRInt32 *aStartIndex) if (IsDefunct()) return NS_ERROR_FAILURE; - PRInt32 endIndex; - return GetLinkOffset(aStartIndex, &endIndex); + *aStartIndex = StartOffset(); + return NS_OK; } // readonly attribute long nsIAccessibleHyperLink::endIndex @@ -2553,47 +2555,39 @@ nsAccessible::GetEndIndex(PRInt32 *aEndIndex) if (IsDefunct()) return NS_ERROR_FAILURE; - PRInt32 startIndex; - return GetLinkOffset(&startIndex, aEndIndex); + *aEndIndex = EndOffset(); + return NS_OK; } NS_IMETHODIMP nsAccessible::GetURI(PRInt32 aIndex, nsIURI **aURI) { NS_ENSURE_ARG_POINTER(aURI); - *aURI = nsnull; - if (aIndex != 0) + if (IsDefunct()) + return NS_ERROR_FAILURE; + + if (aIndex < 0 || aIndex >= static_cast(AnchorCount())) return NS_ERROR_INVALID_ARG; - // Check if it's a simple xlink. - if (nsCoreUtils::IsXLink(mContent)) { - nsAutoString href; - mContent->GetAttr(kNameSpaceID_XLink, nsAccessibilityAtoms::href, href); - - nsCOMPtr baseURI = mContent->GetBaseURI(); - nsCOMPtr document = mContent->GetOwnerDoc(); - return NS_NewURI(aURI, href, - document ? document->GetDocumentCharacterSet().get() : nsnull, - baseURI); - } - + *aURI = GetAnchorURI(aIndex).get(); return NS_OK; } NS_IMETHODIMP -nsAccessible::GetAnchor(PRInt32 aIndex, - nsIAccessible **aAccessible) +nsAccessible::GetAnchor(PRInt32 aIndex, nsIAccessible** aAccessible) { NS_ENSURE_ARG_POINTER(aAccessible); *aAccessible = nsnull; - if (aIndex != 0) + if (IsDefunct()) + return NS_ERROR_FAILURE; + + if (aIndex < 0 || aIndex >= static_cast(AnchorCount())) return NS_ERROR_INVALID_ARG; - *aAccessible = this; - NS_ADDREF_THIS(); + NS_IF_ADDREF(*aAccessible = GetAnchor(aIndex)); return NS_OK; } @@ -2602,12 +2596,12 @@ NS_IMETHODIMP nsAccessible::GetValid(PRBool *aValid) { NS_ENSURE_ARG_POINTER(aValid); - PRUint32 state = nsAccUtils::State(this); - *aValid = (0 == (state & nsIAccessibleStates::STATE_INVALID)); - // XXX In order to implement this we would need to follow every link - // Perhaps we can get information about invalid links from the cache - // In the mean time authors can use role="link" aria-invalid="true" - // to force it for links they internally know to be invalid + *aValid = PR_FALSE; + + if (IsDefunct()) + return NS_ERROR_FAILURE; + + *aValid = IsValid(); return NS_OK; } @@ -2616,33 +2610,14 @@ NS_IMETHODIMP nsAccessible::GetSelected(PRBool *aSelected) { NS_ENSURE_ARG_POINTER(aSelected); + *aSelected = PR_FALSE; - *aSelected = (gLastFocusedNode == GetNode()); + if (IsDefunct()) + return NS_ERROR_FAILURE; + + *aSelected = IsSelected(); return NS_OK; -} -nsresult -nsAccessible::GetLinkOffset(PRInt32 *aStartOffset, PRInt32 *aEndOffset) -{ - nsAccessible *parent = GetParent(); - NS_ENSURE_STATE(parent); - - PRUint32 characterCount = 0; - - PRInt32 childCount = parent->GetChildCount(); - for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) { - nsAccessible *sibling = parent->GetChildAt(childIdx); - - if (sibling == this) { - *aStartOffset = characterCount; - *aEndOffset = characterCount + 1; - return NS_OK; - } - - characterCount += nsAccUtils::TextLength(sibling); - } - - return NS_ERROR_FAILURE; } nsresult @@ -2969,6 +2944,95 @@ nsAccessible::IsInCache() #endif +//////////////////////////////////////////////////////////////////////////////// +// HyperLinkAccessible methods + +bool +nsAccessible::IsHyperLink() +{ + // Every embedded accessible within hypertext accessible implements + // hyperlink interface. + nsRefPtr hyperText = do_QueryObject(GetParent()); + return hyperText && nsAccUtils::IsEmbeddedObject(this); +} + +PRUint32 +nsAccessible::StartOffset() +{ + NS_PRECONDITION(IsHyperLink(), "StartOffset is called not on hyper link!"); + + nsRefPtr hyperText(do_QueryObject(GetParent())); + return hyperText ? hyperText->GetChildOffset(this) : 0; +} + +PRUint32 +nsAccessible::EndOffset() +{ + NS_PRECONDITION(IsHyperLink(), "EndOffset is called on not hyper link!"); + + nsRefPtr hyperText(do_QueryObject(GetParent())); + return hyperText ? (hyperText->GetChildOffset(this) + 1) : 0; +} + +bool +nsAccessible::IsValid() +{ + NS_PRECONDITION(IsHyperLink(), "IsValid is called on not hyper link!"); + + PRUint32 state = nsAccUtils::State(this); + return (0 == (state & nsIAccessibleStates::STATE_INVALID)); + // XXX In order to implement this we would need to follow every link + // Perhaps we can get information about invalid links from the cache + // In the mean time authors can use role="link" aria-invalid="true" + // to force it for links they internally know to be invalid +} + +bool +nsAccessible::IsSelected() +{ + NS_PRECONDITION(IsHyperLink(), "IsSelected is called on not hyper link!"); + return (gLastFocusedNode == GetNode()); +} + +PRUint32 +nsAccessible::AnchorCount() +{ + NS_PRECONDITION(IsHyperLink(), "AnchorCount is called on not hyper link!"); + return 1; +} + +nsAccessible* +nsAccessible::GetAnchor(PRUint32 aAnchorIndex) +{ + NS_PRECONDITION(IsHyperLink(), "GetAnchor is called on not hyper link!"); + return aAnchorIndex == 0 ? this : nsnull; +} + +already_AddRefed +nsAccessible::GetAnchorURI(PRUint32 aAnchorIndex) +{ + NS_PRECONDITION(IsHyperLink(), "GetAnchorURI is called on not hyper link!"); + + if (aAnchorIndex != 0) + return nsnull; + + // Check if it's a simple xlink. + if (nsCoreUtils::IsXLink(mContent)) { + nsAutoString href; + mContent->GetAttr(kNameSpaceID_XLink, nsAccessibilityAtoms::href, href); + + nsCOMPtr baseURI = mContent->GetBaseURI(); + nsCOMPtr document = mContent->GetOwnerDoc(); + nsIURI* anchorURI = nsnull; + NS_NewURI(&anchorURI, href, + document ? document->GetDocumentCharacterSet().get() : nsnull, + baseURI); + return anchorURI; + } + + return nsnull; +} + //////////////////////////////////////////////////////////////////////////////// // nsAccessible protected methods diff --git a/accessible/src/base/nsAccessible.h b/accessible/src/base/nsAccessible.h index 911d6ed1e32..7e1909e485f 100644 --- a/accessible/src/base/nsAccessible.h +++ b/accessible/src/base/nsAccessible.h @@ -327,6 +327,49 @@ public: */ void TestChildCache(nsAccessible *aCachedChild); + ////////////////////////////////////////////////////////////////////////////// + // HyperLinkAccessible + + /** + * Return true if the accessible is hyper link accessible. + */ + virtual bool IsHyperLink(); + + /** + * Return the start offset of the link within the parent accessible. + */ + virtual PRUint32 StartOffset(); + + /** + * Return the end offset of the link within the parent accessible. + */ + virtual PRUint32 EndOffset(); + + /** + * Return true if the link is valid (e. g. points to a valid URL). + */ + virtual bool IsValid(); + + /** + * Return true if the link currently has the focus. + */ + virtual bool IsSelected(); + + /** + * Return the number of anchors within the link. + */ + virtual PRUint32 AnchorCount(); + + /** + * Returns an anchor accessible at the given index. + */ + virtual nsAccessible* GetAnchor(PRUint32 aAnchorIndex); + + /** + * Returns an anchor URI at the given index. + */ + virtual already_AddRefed GetAnchorURI(PRUint32 aAnchorIndex); + protected: ////////////////////////////////////////////////////////////////////////////// @@ -383,9 +426,6 @@ protected: */ nsAccessible *GetFirstAvailableAccessible(nsINode *aStartNode) const; - // Hyperlink helpers - virtual nsresult GetLinkOffset(PRInt32* aStartOffset, PRInt32* aEndOffset); - ////////////////////////////////////////////////////////////////////////////// // Action helpers diff --git a/accessible/src/base/nsBaseWidgetAccessible.cpp b/accessible/src/base/nsBaseWidgetAccessible.cpp index 9b92b1079d1..223ce3fd3ee 100644 --- a/accessible/src/base/nsBaseWidgetAccessible.cpp +++ b/accessible/src/base/nsBaseWidgetAccessible.cpp @@ -204,27 +204,6 @@ nsLinkableAccessible::GetKeyboardShortcut(nsAString& aKeyboardShortcut) return nsAccessible::GetKeyboardShortcut(aKeyboardShortcut); } -//////////////////////////////////////////////////////////////////////////////// -// nsLinkableAccessible. nsIAccessibleHyperLink - -NS_IMETHODIMP -nsLinkableAccessible::GetURI(PRInt32 aIndex, nsIURI **aURI) -{ - if (mIsLink) { - nsAccessible *actionAcc = GetActionAccessible(); - if (actionAcc) { - nsCOMPtr hyperLinkAcc = do_QueryObject(actionAcc); - NS_ASSERTION(hyperLinkAcc, - "nsIAccessibleHyperLink isn't implemented."); - - if (hyperLinkAcc) - return hyperLinkAcc->GetURI(aIndex, aURI); - } - } - - return NS_ERROR_INVALID_ARG; -} - //////////////////////////////////////////////////////////////////////////////// // nsLinkableAccessible. nsAccessNode @@ -242,6 +221,26 @@ nsLinkableAccessible::Shutdown() nsAccessibleWrap::Shutdown(); } +//////////////////////////////////////////////////////////////////////////////// +// nsLinkableAccessible: HyperLinkAccessible + +already_AddRefed +nsLinkableAccessible::GetAnchorURI(PRUint32 aAnchorIndex) +{ + if (mIsLink) { + nsAccessible* link = GetActionAccessible(); + if (link) { + NS_ASSERTION(link->IsHyperLink(), + "nsIAccessibleHyperLink isn't implemented."); + + if (link->IsHyperLink()) + return link->GetAnchorURI(aAnchorIndex); + } + } + + return nsnull; +} + //////////////////////////////////////////////////////////////////////////////// // nsLinkableAccessible diff --git a/accessible/src/base/nsBaseWidgetAccessible.h b/accessible/src/base/nsBaseWidgetAccessible.h index 2fc286d108e..83ff99f958f 100644 --- a/accessible/src/base/nsBaseWidgetAccessible.h +++ b/accessible/src/base/nsBaseWidgetAccessible.h @@ -96,9 +96,6 @@ public: NS_IMETHOD TakeFocus(); NS_IMETHOD GetKeyboardShortcut(nsAString& _retval); - // nsIAccessibleHyperLink - NS_IMETHOD GetURI(PRInt32 i, nsIURI **aURI); - // nsAccessNode virtual PRBool Init(); virtual void Shutdown(); @@ -106,6 +103,9 @@ public: // nsAccessible virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState); + // HyperLinkAccessible + virtual already_AddRefed GetAnchorURI(PRUint32 aAnchorIndex); + protected: /** * Return an accessible for cached action node. diff --git a/accessible/src/html/nsHTMLImageMapAccessible.cpp b/accessible/src/html/nsHTMLImageMapAccessible.cpp index f5e3fbdfaa2..f529ddbfd4f 100644 --- a/accessible/src/html/nsHTMLImageMapAccessible.cpp +++ b/accessible/src/html/nsHTMLImageMapAccessible.cpp @@ -65,51 +65,6 @@ nsHTMLImageMapAccessible:: NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLImageMapAccessible, nsHTMLImageAccessible) -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLImageMapAccessible: nsIAccessibleHyperLink - -NS_IMETHODIMP -nsHTMLImageMapAccessible::GetAnchorCount(PRInt32 *aAnchorCount) -{ - NS_ENSURE_ARG_POINTER(aAnchorCount); - - return GetChildCount(aAnchorCount); -} - -NS_IMETHODIMP -nsHTMLImageMapAccessible::GetURI(PRInt32 aIndex, nsIURI **aURI) -{ - NS_ENSURE_ARG_POINTER(aURI); - *aURI = nsnull; - - nsAccessible *areaAcc = GetChildAt(aIndex); - if (!areaAcc) - return NS_ERROR_INVALID_ARG; - - nsCOMPtr areaNode; - areaAcc->GetDOMNode(getter_AddRefs(areaNode)); - - nsCOMPtr link(do_QueryInterface(areaNode)); - if (link) - *aURI = link->GetHrefURI().get(); - - return NS_OK; -} - -NS_IMETHODIMP -nsHTMLImageMapAccessible::GetAnchor(PRInt32 aIndex, nsIAccessible **aAccessible) -{ - NS_ENSURE_ARG_POINTER(aAccessible); - *aAccessible = nsnull; - - nsAccessible *areaAcc = GetChildAt(aIndex); - if (!areaAcc) - return NS_ERROR_INVALID_ARG; - - NS_ADDREF(*aAccessible = areaAcc); - return NS_OK; -} - //////////////////////////////////////////////////////////////////////////////// // nsHTMLImageMapAccessible: nsAccessible public @@ -120,6 +75,32 @@ nsHTMLImageMapAccessible::GetRoleInternal(PRUint32 *aRole) return NS_OK; } +//////////////////////////////////////////////////////////////////////////////// +// nsHTMLImageMapAccessible: HyperLinkAccessible + +PRUint32 +nsHTMLImageMapAccessible::AnchorCount() +{ + return GetChildCount(); +} + +nsAccessible* +nsHTMLImageMapAccessible::GetAnchor(PRUint32 aAnchorIndex) +{ + return GetChildAt(aAnchorIndex); +} + +already_AddRefed +nsHTMLImageMapAccessible::GetAnchorURI(PRUint32 aAnchorIndex) +{ + nsAccessible* area = GetChildAt(aAnchorIndex); + if (!area) + return nsnull; + + nsIContent* linkContent = area->GetContent(); + return linkContent ? linkContent->GetHrefURI() : nsnull; +} + //////////////////////////////////////////////////////////////////////////////// // nsHTMLImageMapAccessible: nsAccessible protected @@ -281,6 +262,26 @@ nsHTMLAreaAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, return NS_OK; } +//////////////////////////////////////////////////////////////////////////////// +// nsHTMLImageMapAccessible: HyperLinkAccessible + +PRUint32 +nsHTMLAreaAccessible::StartOffset() +{ + // Image map accessible is not hypertext accessible therefore + // StartOffset/EndOffset implementations of nsAccessible doesn't work here. + // We return index in parent because image map contains area links only which + // are embedded objects. + // XXX: image map should be a hypertext accessible. + return GetIndexInParent(); +} + +PRUint32 +nsHTMLAreaAccessible::EndOffset() +{ + return GetIndexInParent() + 1; +} + //////////////////////////////////////////////////////////////////////////////// // nsHTMLAreaAccessible: nsAccessible protected diff --git a/accessible/src/html/nsHTMLImageMapAccessible.h b/accessible/src/html/nsHTMLImageMapAccessible.h index a82881dfc2c..76d7010cd97 100644 --- a/accessible/src/html/nsHTMLImageMapAccessible.h +++ b/accessible/src/html/nsHTMLImageMapAccessible.h @@ -57,14 +57,14 @@ public: // nsISupports and cycle collector NS_DECL_ISUPPORTS_INHERITED - // nsIAccessibleHyperLink - NS_IMETHOD GetAnchorCount(PRInt32 *aAnchorCount); - NS_IMETHOD GetURI(PRInt32 aIndex, nsIURI **aURI); - NS_IMETHOD GetAnchor(PRInt32 aIndex, nsIAccessible **aAccessible); - // nsAccessible virtual nsresult GetRoleInternal(PRUint32 *aRole); + // HyperLinkAccessible + virtual PRUint32 AnchorCount(); + virtual nsAccessible* GetAnchor(PRUint32 aAnchorIndex); + virtual already_AddRefed GetAnchorURI(PRUint32 aAnchorIndex); + protected: // nsAccessible @@ -98,6 +98,10 @@ public: PRBool aDeepestChild, nsIAccessible **aChild); + // HyperLinkAccessible + virtual PRUint32 StartOffset(); + virtual PRUint32 EndOffset(); + protected: // nsAccessible diff --git a/accessible/src/html/nsHTMLLinkAccessible.cpp b/accessible/src/html/nsHTMLLinkAccessible.cpp index b525f7b921a..de28f85da12 100644 --- a/accessible/src/html/nsHTMLLinkAccessible.cpp +++ b/accessible/src/html/nsHTMLLinkAccessible.cpp @@ -163,23 +163,19 @@ nsHTMLLinkAccessible::DoAction(PRUint8 aIndex) } //////////////////////////////////////////////////////////////////////////////// -// nsIAccessibleHyperLink +// HyperLinkAccessible -NS_IMETHODIMP -nsHTMLLinkAccessible::GetURI(PRInt32 aIndex, nsIURI **aURI) +bool +nsHTMLLinkAccessible::IsHyperLink() { - NS_ENSURE_ARG_POINTER(aURI); - *aURI = nsnull; + // Expose HyperLinkAccessible unconditionally. + return true; +} - if (aIndex != 0) - return NS_ERROR_INVALID_ARG; - - if (IsDefunct()) - return NS_ERROR_FAILURE; - - nsCOMPtr uri = mContent->GetHrefURI(); - uri.forget(aURI); - return NS_OK; +already_AddRefed +nsHTMLLinkAccessible::GetAnchorURI(PRUint32 aAnchorIndex) +{ + return aAnchorIndex == 0 ? mContent->GetHrefURI() : nsnull; } //////////////////////////////////////////////////////////////////////////////// diff --git a/accessible/src/html/nsHTMLLinkAccessible.h b/accessible/src/html/nsHTMLLinkAccessible.h index 72e2eab7eca..a9b1972000c 100644 --- a/accessible/src/html/nsHTMLLinkAccessible.h +++ b/accessible/src/html/nsHTMLLinkAccessible.h @@ -56,13 +56,14 @@ public: NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName); NS_IMETHOD DoAction(PRUint8 aIndex); - // nsIAccessibleHyperLink - NS_IMETHOD GetURI(PRInt32 aIndex, nsIURI **aURI); - // nsAccessible virtual nsresult GetRoleInternal(PRUint32 *aRole); virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState); + // HyperLinkAccessible + virtual bool IsHyperLink(); + virtual already_AddRefed GetAnchorURI(PRUint32 aAnchorIndex); + protected: enum { eAction_Jump = 0 }; diff --git a/accessible/src/msaa/CAccessibleHyperlink.cpp b/accessible/src/msaa/CAccessibleHyperlink.cpp index 59ed9bd6d4a..89d25787e54 100644 --- a/accessible/src/msaa/CAccessibleHyperlink.cpp +++ b/accessible/src/msaa/CAccessibleHyperlink.cpp @@ -44,15 +44,8 @@ #include "AccessibleHyperlink.h" #include "AccessibleHyperlink_i.c" -#include "nsIAccessible.h" -#include "nsIAccessibleHyperlink.h" +#include "nsAccessible.h" #include "nsIWinAccessNode.h" -#include "nsAccessNodeWrap.h" - -#include "nsCOMPtr.h" -#include "nsString.h" - -#include "nsIURI.h" // IUnknown @@ -62,8 +55,8 @@ CAccessibleHyperlink::QueryInterface(REFIID iid, void** ppv) *ppv = NULL; if (IID_IAccessibleHyperlink == iid) { - nsCOMPtr acc(do_QueryObject(this)); - if (!acc) + nsRefPtr thisObj = do_QueryObject(this); + if (!thisObj->IsHyperLink()) return E_NOINTERFACE; *ppv = static_cast(this); @@ -82,21 +75,23 @@ CAccessibleHyperlink::get_anchor(long aIndex, VARIANT *aAnchor) __try { VariantInit(aAnchor); - nsCOMPtr acc(do_QueryObject(this)); - if (!acc) + nsRefPtr thisObj = do_QueryObject(this); + if (thisObj->IsDefunct() || !thisObj->IsHyperLink()) return E_FAIL; - nsCOMPtr anchor; - nsresult rv = acc->GetAnchor(aIndex, getter_AddRefs(anchor)); - if (NS_FAILED(rv)) - return GetHRESULT(rv); + if (aIndex < 0 || aIndex >= static_cast(thisObj->AnchorCount())) + return E_INVALIDARG; - nsCOMPtr winAccessNode(do_QueryInterface(anchor)); + nsAccessible* anchor = thisObj->GetAnchor(aIndex); + if (!anchor) + return S_FALSE; + + nsCOMPtr winAccessNode(do_QueryObject(anchor)); if (!winAccessNode) return E_FAIL; void *instancePtr = NULL; - rv = winAccessNode->QueryNativeInterface(IID_IUnknown, &instancePtr); + nsresult rv = winAccessNode->QueryNativeInterface(IID_IUnknown, &instancePtr); if (NS_FAILED(rv)) return E_FAIL; @@ -115,17 +110,19 @@ CAccessibleHyperlink::get_anchorTarget(long aIndex, VARIANT *aAnchorTarget) __try { VariantInit(aAnchorTarget); - nsCOMPtr acc(do_QueryObject(this)); - if (!acc) + nsRefPtr thisObj = do_QueryObject(this); + if (thisObj->IsDefunct() || !thisObj->IsHyperLink()) return E_FAIL; - nsCOMPtr uri; - nsresult rv = acc->GetURI(aIndex, getter_AddRefs(uri)); - if (NS_FAILED(rv) || !uri) - return GetHRESULT(rv); + if (aIndex < 0 || aIndex >= static_cast(thisObj->AnchorCount())) + return E_INVALIDARG; + + nsCOMPtr uri = thisObj->GetAnchorURI(aIndex); + if (!uri) + return S_FALSE; nsCAutoString prePath; - rv = uri->GetPrePath(prePath); + nsresult rv = uri->GetPrePath(prePath); if (NS_FAILED(rv)) return GetHRESULT(rv); @@ -153,16 +150,11 @@ CAccessibleHyperlink::get_startIndex(long *aIndex) __try { *aIndex = 0; - nsCOMPtr acc(do_QueryObject(this)); - if (!acc) + nsRefPtr thisObj = do_QueryObject(this); + if (thisObj->IsDefunct() || !thisObj->IsHyperLink()) return E_FAIL; - PRInt32 index = 0; - nsresult rv = acc->GetStartIndex(&index); - if (NS_FAILED(rv)) - return GetHRESULT(rv); - - *aIndex = index; + *aIndex = thisObj->StartOffset(); return S_OK; } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { } @@ -175,16 +167,11 @@ CAccessibleHyperlink::get_endIndex(long *aIndex) __try { *aIndex = 0; - nsCOMPtr acc(do_QueryObject(this)); - if (!acc) + nsRefPtr thisObj = do_QueryObject(this); + if (thisObj->IsDefunct() || !thisObj->IsHyperLink()) return E_FAIL; - PRInt32 index = 0; - nsresult rv = acc->GetEndIndex(&index); - if (NS_FAILED(rv)) - return GetHRESULT(rv); - - *aIndex = index; + *aIndex = thisObj->EndOffset(); return S_OK; } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { } @@ -197,16 +184,11 @@ CAccessibleHyperlink::get_valid(boolean *aValid) __try { *aValid = false; - nsCOMPtr acc(do_QueryObject(this)); - if (!acc) + nsRefPtr thisObj = do_QueryObject(this); + if (thisObj->IsDefunct() || !thisObj->IsHyperLink()) return E_FAIL; - PRBool isValid = PR_FALSE; - nsresult rv = acc->GetValid(&isValid); - if (NS_FAILED(rv)) - return GetHRESULT(rv); - - *aValid = isValid; + *aValid = thisObj->IsValid(); return S_OK; } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { } diff --git a/accessible/src/xul/nsXULTextAccessible.cpp b/accessible/src/xul/nsXULTextAccessible.cpp index ac28c683955..bba0f081ea0 100644 --- a/accessible/src/xul/nsXULTextAccessible.cpp +++ b/accessible/src/xul/nsXULTextAccessible.cpp @@ -238,26 +238,52 @@ nsXULLinkAccessible::DoAction(PRUint8 aIndex) } //////////////////////////////////////////////////////////////////////////////// -// nsXULLinkAccessible. nsIAccessibleHyperLink +// nsXULLinkAccessible: HyperLinkAccessible -NS_IMETHODIMP -nsXULLinkAccessible::GetURI(PRInt32 aIndex, nsIURI **aURI) +bool +nsXULLinkAccessible::IsHyperLink() { - NS_ENSURE_ARG_POINTER(aURI); - *aURI = nsnull; + // Expose HyperLinkAccessible unconditionally. + return true; +} - if (aIndex != 0) - return NS_ERROR_INVALID_ARG; +PRUint32 +nsXULLinkAccessible::StartOffset() +{ + // If XUL link accessible is not contained by hypertext accessible then + // start offset matches index in parent because the parent doesn't contains + // a text. + // XXX: accessible parent of XUL link accessible should be a hypertext + // accessible. + if (nsAccessible::IsHyperLink()) + return nsAccessible::StartOffset(); + return GetIndexInParent(); +} - if (IsDefunct()) - return NS_ERROR_FAILURE; +PRUint32 +nsXULLinkAccessible::EndOffset() +{ + if (nsAccessible::IsHyperLink()) + return nsAccessible::EndOffset(); + return GetIndexInParent() + 1; +} + +already_AddRefed +nsXULLinkAccessible::GetAnchorURI(PRUint32 aAnchorIndex) +{ + if (aAnchorIndex != 0) + return nsnull; nsAutoString href; mContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::href, href); nsCOMPtr baseURI = mContent->GetBaseURI(); nsIDocument* document = mContent->GetOwnerDoc(); - return NS_NewURI(aURI, href, - document ? document->GetDocumentCharacterSet().get() : nsnull, - baseURI); + + nsIURI* anchorURI = nsnull; + NS_NewURI(&anchorURI, href, + document ? document->GetDocumentCharacterSet().get() : nsnull, + baseURI); + + return anchorURI; } diff --git a/accessible/src/xul/nsXULTextAccessible.h b/accessible/src/xul/nsXULTextAccessible.h index 1eac3f296b9..0a3e855b5a0 100644 --- a/accessible/src/xul/nsXULTextAccessible.h +++ b/accessible/src/xul/nsXULTextAccessible.h @@ -91,14 +91,17 @@ public: NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName); NS_IMETHOD DoAction(PRUint8 aIndex); - // nsIAccessibleHyperLink - NS_IMETHOD GetURI(PRInt32 aIndex, nsIURI **aURI); - // nsAccessible virtual nsresult GetNameInternal(nsAString& aName); virtual nsresult GetRoleInternal(PRUint32 *aRole); virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState); + // HyperLinkAccessible + virtual bool IsHyperLink(); + virtual PRUint32 StartOffset(); + virtual PRUint32 EndOffset(); + virtual already_AddRefed GetAnchorURI(PRUint32 aAnchorIndex); + protected: enum { eAction_Jump = 0 }; diff --git a/accessible/tests/mochitest/Makefile.in b/accessible/tests/mochitest/Makefile.in index d6b719c4b7f..2dc5779d672 100644 --- a/accessible/tests/mochitest/Makefile.in +++ b/accessible/tests/mochitest/Makefile.in @@ -42,7 +42,17 @@ srcdir = @srcdir@ VPATH = @srcdir@ relativesrcdir = accessible -DIRS = actions attributes events relations selectable states table tree +DIRS = \ + actions \ + attributes \ + events \ + hyperlink \ + relations \ + selectable \ + states \ + table \ + tree \ + $(null) include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/rules.mk @@ -98,8 +108,6 @@ _TEST_FILES =\ test_nsIAccessible_selects.html \ test_nsIAccessible_focus.html \ test_nsIAccessibleDocument.html \ - test_nsIAccessibleHyperLink.html \ - test_nsIAccessibleHyperLink.xul \ test_nsIAccessibleHyperText.html \ test_nsIAccessibleImage.html \ test_nsIAccessNode_utils.html \ diff --git a/accessible/tests/mochitest/hyperlink/Makefile.in b/accessible/tests/mochitest/hyperlink/Makefile.in new file mode 100644 index 00000000000..aec1d3979cb --- /dev/null +++ b/accessible/tests/mochitest/hyperlink/Makefile.in @@ -0,0 +1,54 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2010 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Alexander Surkov (original author) +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +relativesrcdir = accessible/hyperlink + +include $(DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/rules.mk + +_TEST_FILES =\ + test_general.html \ + test_general.xul \ + $(NULL) + +libs:: $(_TEST_FILES) + $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir) diff --git a/accessible/tests/mochitest/test_nsIAccessibleHyperLink.html b/accessible/tests/mochitest/hyperlink/test_general.html similarity index 100% rename from accessible/tests/mochitest/test_nsIAccessibleHyperLink.html rename to accessible/tests/mochitest/hyperlink/test_general.html diff --git a/accessible/tests/mochitest/test_nsIAccessibleHyperLink.xul b/accessible/tests/mochitest/hyperlink/test_general.xul similarity index 100% rename from accessible/tests/mochitest/test_nsIAccessibleHyperLink.xul rename to accessible/tests/mochitest/hyperlink/test_general.xul