Merging mozilla-central to mozilla-qt.
Merging mozilla-central to mozilla-qt.
--- a/.hgignore
+++ b/.hgignore
@@ -1,29 +1,27 @@
# .hgignore - List of filenames hg should ignore
# Filenames that should be ignored wherever they appear
~$
\.pyc$
+(^|/)TAGS$
# User files that may appear at the root
^\.mozconfig$
+^mozconfig$
^\.mozconfig\.mk$
^\.mozconfig\.out$
^configure$
^config\.cache$
^config\.log$
+^ID$
-# subtrees from other repositories
-^nsprpub/
-^dbm/
-^security/nss/
-^security/coreconf/
-^security/dbm/
+# Empty marker file that's generated when we check out NSS
+^security/manager/\.nss\.checkout$
# Build directories
-^obj-
-^objdir
+^obj
# Build directories for js shell
_DBG\.OBJ/
_OPT\.OBJ/
--- a/.hgtags
+++ b/.hgtags
@@ -1,3 +1,10 @@
df7a3c8ffeeaba229067efee5a20e21dae0dd877 MOZILLA_1_9_a4_BASE
4209e16b58411750ac73f761023e46b76b793e2c MOZILLA_1_9_a6_BASE
66a5c7bce7ee86a820d3c0d54fa07cb719be751c MOZILLA_1_9_a7_BASE
+caeba7562e495a9f604984df0b48b6f99bec3e2e FENNEC_M4
+9d9941eacb14827fdab4716710042fdde84eb60d FIREFOX_3_1a1_RELEASE
+9d9941eacb14827fdab4716710042fdde84eb60d FIREFOX_3_1a1_BUILD1
+c1d7e318a27574c995631fec166ad42672475702 FIREFOX_3_1a1_BUILD2
+c1d7e318a27574c995631fec166ad42672475702 FIREFOX_3_1a1_RELEASE
+afc4ee509d9ca3bb4031015c3c22963dcb4b7e7f FIREFOX_3_1a1_RELEASE
+afc4ee509d9ca3bb4031015c3c22963dcb4b7e7f FIREFOX_3_1a1_BUILD2
--- a/Makefile.in
+++ b/Makefile.in
@@ -61,16 +61,21 @@ tier_base_dirs = \
build \
probes \
$(NULL)
ifdef MOZ_MEMORY
tier_base_dirs += memory/jemalloc
endif
+ifdef ENABLE_TESTS
+# Additional makefile targets to call automated test suites
+include $(topsrcdir)/testing/testsuite-targets.mk
+endif
+
include $(topsrcdir)/$(MOZ_BUILD_APP)/build.mk
TIERS += testharness
# test harnesses
ifdef ENABLE_TESTS
tier_testharness_dirs += tools/test-harness
endif
--- a/accessible/public/msaa/ISimpleDOMDocument.idl
+++ b/accessible/public/msaa/ISimpleDOMDocument.idl
@@ -87,40 +87,32 @@ cpp_quote("// * See latest W3C CSS specs
cpp_quote("//")
cpp_quote("//")
cpp_quote("///////////////////////////////////////////////////////////////////////////////////////////////////////")
cpp_quote("")
cpp_quote("")
import "objidl.idl";
import "oaidl.idl";
-
-
-const long DISPID_DOC_URL = -5904;
-const long DISPID_DOC_TITLE = -5905;
-const long DISPID_DOC_MIMETYPE = -5906;
-const long DISPID_DOC_DOCTYPE = -5907;
-const long DISPID_DOC_NAMESPACE = -5908;
-const long DISPID_DOC_MEDIATYPES = -5909;
[object, uuid(0D68D6D0-D93D-4d08-A30D-F00DD1F45B24)]
interface ISimpleDOMDocument : IUnknown
{
- [propget, id(DISPID_DOC_URL)] HRESULT URL(
+ [propget] HRESULT URL(
[out, retval] BSTR * url
);
- [propget, id(DISPID_DOC_TITLE)] HRESULT title(
+ [propget] HRESULT title(
[out, retval] BSTR * title
);
- [propget, id(DISPID_DOC_MIMETYPE)] HRESULT mimeType(
+ [propget] HRESULT mimeType(
[out, retval] BSTR * mimeType
);
- [propget, id(DISPID_DOC_DOCTYPE)] HRESULT docType(
+ [propget] HRESULT docType(
[out, retval] BSTR * docType
);
- [propget, id(DISPID_DOC_NAMESPACE)] HRESULT nameSpaceURIForID(
+ [propget] HRESULT nameSpaceURIForID(
[in] short nameSpaceID,
[out, retval] BSTR * nameSpaceURI
);
- [propput, id(DISPID_DOC_MEDIATYPES)] HRESULT alternateViewMediaTypes(
+ [propput] HRESULT alternateViewMediaTypes(
[in] BSTR * commaSeparatedMediaTypes
);
}
--- a/accessible/public/msaa/ISimpleDOMNode.idl
+++ b/accessible/public/msaa/ISimpleDOMNode.idl
@@ -128,23 +128,19 @@ cpp_quote("// Returns the computed langu
cpp_quote("//")
cpp_quote("//")
cpp_quote("///////////////////////////////////////////////////////////////////////////////////////////////////////")
cpp_quote("")
cpp_quote("")
import "objidl.idl";
import "oaidl.idl";
-
-const long DISPID_NODE_NODEINFO = -5900;
-const long DISPID_NODE_ATTRIBUTES = -5901;
-const long DISPID_NODE_ATTRIBUTESFORNAMES = -5902;
-const long DISPID_NODE_COMPSTYLE = -5903;
-const long DISPID_NODE_COMPSTYLEFORPROPS = -5904;
-const long DISPID_NODE_LANGUAGE = -5905;
+
+import "ISimpleDOMText.idl";
+import "ISimpleDOMDocument.idl";
[object, uuid(1814ceeb-49e2-407f-af99-fa755a7d2607)]
interface ISimpleDOMNode : IUnknown
{
const unsigned short NODETYPE_ELEMENT = 1;
const unsigned short NODETYPE_ATTRIBUTE = 2;
const unsigned short NODETYPE_TEXT = 3;
const unsigned short NODETYPE_CDATA_SECTION = 4;
@@ -152,49 +148,49 @@ interface ISimpleDOMNode : IUnknown
const unsigned short NODETYPE_ENTITY = 6;
const unsigned short NODETYPE_PROCESSING_INSTRUCTION = 7;
const unsigned short NODETYPE_COMMENT = 8;
const unsigned short NODETYPE_DOCUMENT = 9;
const unsigned short NODETYPE_DOCUMENT_TYPE = 10;
const unsigned short NODETYPE_DOCUMENT_FRAGMENT = 11;
const unsigned short NODETYPE_NOTATION = 12;
- [propget, id(DISPID_NODE_NODEINFO)] HRESULT nodeInfo(
+ [propget] HRESULT nodeInfo(
[out] BSTR *nodeName, // for performance returns NULL for text nodes (true nodeName would be "#text")
[out] short *nameSpaceID,
[out] BSTR *nodeValue,
[out] unsigned int *numChildren,
[out] unsigned int *uniqueID, // In Win32 accessible events we generate, the target's childID matches to this
[out, retval] unsigned short *nodeType
);
- [propget, id(DISPID_NODE_ATTRIBUTES)] HRESULT attributes(
+ [propget] HRESULT attributes(
[in] unsigned short maxAttribs,
[out, size_is(maxAttribs), length_is(*numAttribs)] BSTR *attribNames,
[out, size_is(maxAttribs), length_is(*numAttribs)] short *nameSpaceID,
[out, size_is(maxAttribs), length_is(*numAttribs)] BSTR *attribValues,
[out, retval] unsigned short *numAttribs
);
- [propget, id(DISPID_NODE_ATTRIBUTESFORNAMES)] HRESULT attributesForNames(
+ [propget] HRESULT attributesForNames(
[in] unsigned short numAttribs,
[in, size_is(numAttribs), length_is(numAttribs)] BSTR *attribNames,
[in, size_is(numAttribs), length_is(numAttribs)] short *nameSpaceID,
[out, retval, size_is(numAttribs), length_is(numAttribs)] BSTR *attribValues
);
- [propget, id(DISPID_NODE_COMPSTYLE)] HRESULT computedStyle(
+ [propget] HRESULT computedStyle(
[in] unsigned short maxStyleProperties,
[in] boolean useAlternateView, // If TRUE, returns properites for media as set in nsIDOMDocument::set_alternateViewMediaTypes
[out, size_is(maxStyleProperties), length_is(*numStyleProperties)] BSTR *styleProperties,
[out, size_is(maxStyleProperties), length_is(*numStyleProperties)] BSTR *styleValues,
[out, retval] unsigned short *numStyleProperties
);
- [propget, id(DISPID_NODE_COMPSTYLEFORPROPS)] HRESULT computedStyleForProperties(
+ [propget] HRESULT computedStyleForProperties(
[in] unsigned short numStyleProperties,
[in] boolean useAlternateView, // If TRUE, returns properites for media as set in nsIDOMDocument::set_alternateViewMediaTypes
[in, size_is(numStyleProperties), length_is(numStyleProperties)] BSTR *styleProperties,
[out, retval, size_is(numStyleProperties), length_is(numStyleProperties)] BSTR *styleValues
);
HRESULT scrollTo([in] boolean placeTopLeft);
@@ -205,12 +201,23 @@ interface ISimpleDOMNode : IUnknown
[propget] HRESULT nextSibling([out, retval] ISimpleDOMNode **node);
[propget] HRESULT childAt([in] unsigned childIndex,
[out, retval] ISimpleDOMNode **node);
[propget] HRESULT innerHTML([out, retval] BSTR *innerHTML);
[propget, local] HRESULT localInterface([out][retval] void **localInterface);
- [propget, id(DISPID_NODE_LANGUAGE)] HRESULT language([out, retval] BSTR *language);
+ [propget] HRESULT language([out, retval] BSTR *language);
}
+[
+ uuid(a6245497-9c0b-4449-85a5-bd6ad07df8ea),
+ helpstring("ISimpleDOM Type Library")
+]
+library ISimpleDOM
+{
+ interface ISimpleDOMNode;
+ interface ISimpleDOMText;
+ interface ISimpleDOMDocument;
+};
+
--- a/accessible/public/msaa/Makefile.in
+++ b/accessible/public/msaa/Makefile.in
@@ -93,17 +93,17 @@ OS_LIBS = \
$(NULL)
$(MIDL_GENERATED_FILES): done_gen
done_gen: ISimpleDOMNode.idl \
ISimpleDOMDocument.idl \
ISimpleDOMText.idl
- $(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMNode.idl
+ $(MIDL) $(MIDL_FLAGS) -I $(srcdir) -Oicf $(srcdir)/ISimpleDOMNode.idl
$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMDocument.idl
$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMText.idl
touch $@
EXPORTS = \
ISimpleDOMNode.h \
ISimpleDOMNode_i.c \
ISimpleDOMDocument.h \
--- a/accessible/public/nsIAccessibleText.idl
+++ b/accessible/public/nsIAccessibleText.idl
@@ -39,18 +39,19 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
typedef long nsAccessibleTextBoundary;
interface nsIAccessible;
+interface nsIPersistentProperties;
-[scriptable, uuid(caa4f543-070e-4705-8428-2e53575c41bb)]
+[scriptable, uuid(0f4633b1-550c-4b50-8c04-0eb1005eef2f)]
interface nsIAccessibleText : nsISupports
{
// In parameters for character offsets:
// -1 will be treated as the equal to the end of the text
// -2 will be treated as the caret position
const PRInt32 TEXT_OFFSET_END_OF_TEXT = -1;
const PRInt32 TEXT_OFFSET_CARET = -2;
@@ -97,23 +98,34 @@ interface nsIAccessibleText : nsISupport
/**
* It would be better to return an unsigned long here,
* to allow unicode chars > 16 bits
*/
wchar getCharacterAtOffset (in long offset);
/**
- * Get the accessible and start/end offsets around the given offset.
- * This accessible get return the DOM node and layout frame
- * with the uniform attributes for this range of text
+ * Get the accessible start/end offsets around the given offset,
+ * return the text attributes for this range of text.
+ *
+ * @param includeDefAttrs [in] points whether text attributes applied to
+ * the entire accessible should be included or not.
+ * @param offset [in] text offset
+ * @param rangeStartOffset [out] start offset of the range of text
+ * @param rangeEndOffset [out] end offset of the range of text
*/
- nsIAccessible getAttributeRange (in long offset,
- out long rangeStartOffset,
- out long rangeEndOffset);
+ nsIPersistentProperties getTextAttributes(in boolean includeDefAttrs,
+ in long offset,
+ out long rangeStartOffset,
+ out long rangeEndOffset);
+
+ /**
+ * Return the text attributes that apply to the entire accessible.
+ */
+ readonly attribute nsIPersistentProperties defaultTextAttributes;
/**
* Returns the bounding box of the specified position.
*
* The virtual character after the last character of the represented text,
* i.e. the one at position length is a special case. It represents the
* current input position and will therefore typically be queried by AT more
* often than other positions. Because it does not represent an existing
@@ -218,19 +230,14 @@ interface nsIAccessibleText : nsISupport
Using wstring (UCS2) instead of string encoded in UTF-8.
Multibyte encodings (or at least potentially multi-byte
encodings) would be preferred for the reasons cited above.
The following methods will throw an exception on failure
(since not every text component will allow every operation):
setSelectionBounds, addSelection, removeSelection, setCaretOffset.
- getRangeAttributes defined to return an nsISupports
- interface instead of a pango specific data structure.
- It may be that some other return type is more appropriate
- for mozilla text attributes.
-
we assume that all text components support the idea of
a caret offset, whether visible or "virtual". If this
isn't the case, caretOffset can be made readonly and
a setCaretOffset method provided which throws an exception
on failure (as with *selection methods above).
*/
--- a/accessible/public/nsIAccessibleTreeCache.idl
+++ b/accessible/public/nsIAccessibleTreeCache.idl
@@ -42,17 +42,17 @@
interface nsIAccessible;
/**
* A private interface to operate with tree accessible.
*
* @status UNDER_REVIEW
*/
-[uuid(7e0f50b0-6444-4372-b00f-4ce81c6b058a)]
+[uuid(1dde5c3b-bede-43d1-aabf-dabc461113bd)]
interface nsIAccessibleTreeCache : nsISupports
{
/**
* Get tree item from cache according to row and column, create if doesn't
* exist in cache.
*
* @param aRow the given row index
* @param aColumn the given column object. If is is nsnull then primary
@@ -77,16 +77,22 @@ interface nsIAccessibleTreeCache : nsISu
* @param aStartRow row index invalidation starts from
* @param aEndRow row index invalidation ends, -1 means last row index
* @param aStartCol column index invalidation starts from
* @param aEndCol column index invalidation ends, -1 mens last column
* index
*/
void treeViewInvalidated(in long aStartRow, in long aEndRow,
in long aStartCol, in long aEndCol);
+
+ /**
+ * Invalidates children created for previous tree view.
+ */
+ void treeViewChanged();
+
};
[uuid(b71532f9-53b2-4647-a5b2-1c5f57e9aed6)]
interface nsPIAccessibleTreeItem : nsISupports
{
/**
* Get/set cached name.
*/
--- a/accessible/src/atk/nsAccessibleWrap.cpp
+++ b/accessible/src/atk/nsAccessibleWrap.cpp
@@ -366,18 +366,19 @@ void nsAccessibleWrap::SetMaiHyperlink(M
}
}
NS_IMETHODIMP nsAccessibleWrap::GetNativeInterface(void **aOutAccessible)
{
*aOutAccessible = nsnull;
if (!mAtkObject) {
- if (!IsEmbeddedObject(this)) {
- // We don't create ATK objects for nsIAccessible plain text leaves
+ if (!mWeakShell || !IsEmbeddedObject(this)) {
+ // We don't create ATK objects for node which has been shutdown, or
+ // nsIAccessible plain text leaves
return NS_ERROR_FAILURE;
}
GType type = GetMaiAtkType(CreateMaiInterfaces());
NS_ENSURE_TRUE(type, NS_ERROR_FAILURE);
mAtkObject =
reinterpret_cast<AtkObject *>
(g_object_new(type, NULL));
@@ -780,61 +781,75 @@ getRoleCB(AtkObject *aAtkObj)
atkRole = atkRoleMap[accRole]; // map to the actual value
NS_ASSERTION(atkRoleMap[nsIAccessibleRole::ROLE_LAST_ENTRY] ==
kROLE_ATK_LAST_ENTRY, "ATK role map skewed");
aAtkObj->role = static_cast<AtkRole>(atkRole);
}
return aAtkObj->role;
}
+AtkAttributeSet*
+ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes)
+{
+ if (!aAttributes)
+ return nsnull;
+
+ AtkAttributeSet *objAttributeSet = nsnull;
+ nsCOMPtr<nsISimpleEnumerator> propEnum;
+ nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum));
+ NS_ENSURE_SUCCESS(rv, nsnull);
+
+ PRBool hasMore;
+ while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
+ nsCOMPtr<nsISupports> sup;
+ rv = propEnum->GetNext(getter_AddRefs(sup));
+ NS_ENSURE_SUCCESS(rv, objAttributeSet);
+
+ nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
+ NS_ENSURE_TRUE(propElem, objAttributeSet);
+
+ nsCAutoString name;
+ rv = propElem->GetKey(name);
+ NS_ENSURE_SUCCESS(rv, objAttributeSet);
+
+ nsAutoString value;
+ rv = propElem->GetValue(value);
+ NS_ENSURE_SUCCESS(rv, objAttributeSet);
+
+ AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
+ objAttr->name = g_strdup(name.get());
+ objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get());
+ objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
+ }
+
+ //libspi will free it
+ return objAttributeSet;
+}
+
AtkAttributeSet *
GetAttributeSet(nsIAccessible* aAccessible)
{
- AtkAttributeSet *objAttributeSet = nsnull;
nsCOMPtr<nsIPersistentProperties> attributes;
aAccessible->GetAttributes(getter_AddRefs(attributes));
-
+
if (attributes) {
// Deal with attributes that we only need to expose in ATK
PRUint32 state;
aAccessible->GetFinalState(&state, nsnull);
if (state & nsIAccessibleStates::STATE_HASPOPUP) {
// There is no ATK state for haspopup, must use object attribute to expose the same info
nsAutoString oldValueUnused;
attributes->SetStringProperty(NS_LITERAL_CSTRING("haspopup"), NS_LITERAL_STRING("true"),
oldValueUnused);
}
- nsCOMPtr<nsISimpleEnumerator> propEnum;
- nsresult rv = attributes->Enumerate(getter_AddRefs(propEnum));
- NS_ENSURE_SUCCESS(rv, nsnull);
-
- PRBool hasMore;
- while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
- nsCOMPtr<nsISupports> sup;
- rv = propEnum->GetNext(getter_AddRefs(sup));
- nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
- NS_ENSURE_TRUE(propElem, nsnull);
-
- nsCAutoString name;
- rv = propElem->GetKey(name);
- NS_ENSURE_SUCCESS(rv, nsnull);
-
- nsAutoString value;
- rv = propElem->GetValue(value);
- NS_ENSURE_SUCCESS(rv, nsnull);
-
- AtkAttribute *objAttribute = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
- objAttribute->name = g_strdup(name.get());
- objAttribute->value = g_strdup(NS_ConvertUTF16toUTF8(value).get());
- objAttributeSet = g_slist_prepend(objAttributeSet, objAttribute);
- }
+ return ConvertToAtkAttributeSet(attributes);
}
- return objAttributeSet;
+ return nsnull;
}
AtkAttributeSet *
getAttributesCB(AtkObject *aAtkObj)
{
nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
return accWrap ? GetAttributeSet(accWrap) : nsnull;
@@ -849,18 +864,19 @@ getParentCB(AtkObject *aAtkObj)
return nsnull;
}
nsCOMPtr<nsIAccessible> accParent;
nsresult rv = accWrap->GetParent(getter_AddRefs(accParent));
if (NS_FAILED(rv) || !accParent)
return nsnull;
- atk_object_set_parent(aAtkObj,
- nsAccessibleWrap::GetAtkObject(accParent));
+ AtkObject *parent = nsAccessibleWrap::GetAtkObject(accParent);
+ if (parent)
+ atk_object_set_parent(aAtkObj, parent);
}
return aAtkObj->accessible_parent;
}
gint
getChildCountCB(AtkObject *aAtkObj)
{
nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
@@ -1096,22 +1112,28 @@ nsAccessibleWrap *GetAccessibleWrap(AtkO
}
NS_IMETHODIMP
nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
{
nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
NS_ENSURE_SUCCESS(rv, rv);
+ return FirePlatformEvent(aEvent);
+}
+
+nsresult
+nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent *aEvent)
+{
nsCOMPtr<nsIAccessible> accessible;
aEvent->GetAccessible(getter_AddRefs(accessible));
NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
PRUint32 type = 0;
- rv = aEvent->GetEventType(&type);
+ nsresult rv = aEvent->GetEventType(&type);
NS_ENSURE_SUCCESS(rv, rv);
AtkObject *atkObj = nsAccessibleWrap::GetAtkObject(accessible);
// We don't create ATK objects for nsIAccessible plain text leaves,
// just return NS_OK in such case
if (!atkObj) {
NS_ASSERTION(type == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
@@ -1185,16 +1207,23 @@ nsAccessibleWrap::FireAccessibleEvent(ns
MAI_LOG_DEBUG(("\n\nCaret postion: %d", caretOffset));
g_signal_emit_by_name(atkObj,
"text_caret_moved",
// Curent caret position
caretOffset);
} break;
+ case nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED:
+ MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_ATTRIBUTE_CHANGED\n"));
+
+ g_signal_emit_by_name(atkObj,
+ "text-attributes-changed");
+ break;
+
case nsIAccessibleEvent::EVENT_TABLE_MODEL_CHANGED:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_MODEL_CHANGED\n"));
g_signal_emit_by_name(atkObj, "model_changed");
break;
case nsIAccessibleEvent::EVENT_TABLE_ROW_INSERT:
{
MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_ROW_INSERT\n"));
@@ -1304,29 +1333,32 @@ nsAccessibleWrap::FireAccessibleEvent(ns
case nsIAccessibleEvent::EVENT_MENU_END:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENU_END\n"));
break;
case nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE:
{
MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_ACTIVATED\n"));
- nsDocAccessibleWrap *accDocWrap =
- static_cast<nsDocAccessibleWrap *>(accessible.get());
- accDocWrap->mActivated = PR_TRUE;
+ nsRootAccessible *rootAcc =
+ static_cast<nsRootAccessible *>(accessible.get());
+ rootAcc->mActivated = PR_TRUE;
guint id = g_signal_lookup ("activate", MAI_TYPE_ATK_OBJECT);
g_signal_emit(atkObj, id, 0);
+
+ // Always fire a current focus event after activation.
+ rootAcc->FireCurrentFocusEvent();
} break;
case nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE:
{
MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_DEACTIVATED\n"));
- nsDocAccessibleWrap *accDocWrap =
- static_cast<nsDocAccessibleWrap *>(accessible.get());
- accDocWrap->mActivated = PR_FALSE;
+ nsRootAccessible *rootAcc =
+ static_cast<nsRootAccessible *>(accessible.get());
+ rootAcc->mActivated = PR_FALSE;
guint id = g_signal_lookup ("deactivate", MAI_TYPE_ATK_OBJECT);
g_signal_emit(atkObj, id, 0);
} break;
case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE:
{
MAI_LOG_DEBUG(("\n\nReceived: EVENT_DOCUMENT_LOAD_COMPLETE\n"));
g_signal_emit_by_name (atkObj, "load_complete");
--- a/accessible/src/atk/nsAccessibleWrap.h
+++ b/accessible/src/atk/nsAccessibleWrap.h
@@ -111,16 +111,18 @@ public:
static const char * ReturnString(nsAString &aString) {
static nsCString returnedString;
returnedString = NS_ConvertUTF16toUTF8(aString);
return returnedString.get();
}
protected:
+ virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent);
+
nsresult FireAtkStateChangeEvent(nsIAccessibleEvent *aEvent,
AtkObject *aObject);
nsresult FireAtkTextChangedEvent(nsIAccessibleEvent *aEvent,
AtkObject *aObject);
nsresult FireAtkPropChangedEvent(nsIAccessibleEvent *aEvent,
AtkObject *aObject);
nsresult FireAtkShowHideEvent(nsIAccessibleEvent *aEvent,
AtkObject *aObject, PRBool aIsAdded);
--- a/accessible/src/atk/nsMaiInterfaceText.cpp
+++ b/accessible/src/atk/nsMaiInterfaceText.cpp
@@ -36,18 +36,19 @@
* 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 ***** */
#include "nsMaiInterfaceText.h"
#include "nsString.h"
+#include "nsIPersistentProperties2.h"
-AtkAttributeSet * GetAttributeSet(nsIAccessible* aAccessible);
+AtkAttributeSet* ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes);
void
textInterfaceInitCB(AtkTextIface *aIface)
{
NS_ASSERTION(aIface, "Invalid aIface");
if (!aIface)
return;
@@ -240,43 +241,59 @@ getCaretOffsetCB(AtkText *aText)
return (NS_FAILED(rv)) ? 0 : static_cast<gint>(offset);
}
AtkAttributeSet *
getRunAttributesCB(AtkText *aText, gint aOffset,
gint *aStartOffset,
gint *aEndOffset)
{
+ *aStartOffset = -1;
+ *aEndOffset = -1;
+
nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
if (!accWrap)
return nsnull;
nsCOMPtr<nsIAccessibleText> accText;
accWrap->QueryInterface(NS_GET_IID(nsIAccessibleText),
getter_AddRefs(accText));
NS_ENSURE_TRUE(accText, nsnull);
- nsCOMPtr<nsIAccessible> accessibleWithAttrs;
+ nsCOMPtr<nsIPersistentProperties> attributes;
PRInt32 startOffset = 0, endOffset = 0;
- nsresult rv =
- accText->GetAttributeRange(aOffset, &startOffset, &endOffset,
- getter_AddRefs(accessibleWithAttrs));
+ nsresult rv = accText->GetTextAttributes(PR_FALSE, aOffset,
+ &startOffset, &endOffset,
+ getter_AddRefs(attributes));
+ NS_ENSURE_SUCCESS(rv, nsnull);
+
*aStartOffset = startOffset;
*aEndOffset = endOffset;
- if (NS_FAILED(rv))
- return nsnull;
- return GetAttributeSet(accessibleWithAttrs);
+ return ConvertToAtkAttributeSet(attributes);
}
AtkAttributeSet *
getDefaultAttributesCB(AtkText *aText)
{
- /* not supported ??? */
- return nsnull;
+ nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (!accWrap)
+ return nsnull;
+
+ nsCOMPtr<nsIAccessibleText> accText;
+ accWrap->QueryInterface(NS_GET_IID(nsIAccessibleText),
+ getter_AddRefs(accText));
+ NS_ENSURE_TRUE(accText, nsnull);
+
+ nsCOMPtr<nsIPersistentProperties> attributes;
+ nsresult rv = accText->GetDefaultTextAttributes(getter_AddRefs(attributes));
+ if (NS_FAILED(rv))
+ return nsnull;
+
+ return ConvertToAtkAttributeSet(attributes);
}
void
getCharacterExtentsCB(AtkText *aText, gint aOffset,
gint *aX, gint *aY,
gint *aWidth, gint *aHeight,
AtkCoordType aCoords)
{
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -85,16 +85,17 @@ CPPSRCS = \
nsAccessibleRelation.cpp \
nsAccessibleTreeWalker.cpp \
nsBaseWidgetAccessible.cpp \
nsFormControlAccessible.cpp \
nsRootAccessible.cpp \
nsApplicationAccessible.cpp \
nsCaretAccessible.cpp \
nsTextAccessible.cpp \
+ nsTextUtils.cpp \
$(NULL)
EXPORTS = \
nsRootAccessible.h \
nsAccessibleEventData.h \
nsAccessNode.h \
$(NULL)
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -58,16 +58,17 @@
static const nsStateMapEntry kEndEntry = {nsnull, 0, 0}; // To fill in array of state mappings
nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
{
{"alert", nsIAccessibleRole::ROLE_ALERT, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
{"alertdialog", nsIAccessibleRole::ROLE_ALERT, eNameOkFromChildren, eNoValue, kNoReqStates, kEndEntry},
{"application", nsIAccessibleRole::ROLE_APPLICATION, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
+ {"article", nsIAccessibleRole::ROLE_DOCUMENT, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
{"button", nsIAccessibleRole::ROLE_PUSHBUTTON, eNameOkFromChildren, eNoValue, kNoReqStates,
{&nsAccessibilityAtoms::aria_pressed, kBoolState, nsIAccessibleStates::STATE_PRESSED},
{&nsAccessibilityAtoms::aria_pressed, "mixed", nsIAccessibleStates::STATE_MIXED}, kEndEntry},
{"checkbox", nsIAccessibleRole::ROLE_CHECKBUTTON, eNameOkFromChildren, eNoValue, nsIAccessibleStates::STATE_CHECKABLE,
{&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED},
{&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED},
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
{"columnheader", nsIAccessibleRole::ROLE_COLUMNHEADER, eNameOkFromChildren, eNoValue, kNoReqStates,
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -186,18 +186,17 @@ NS_IMETHODIMP nsAccessNode::Init()
do_QueryInterface(docAccessible);
NS_ASSERTION(privateDocAccessible, "No private docaccessible for docaccessible");
privateDocAccessible->CacheAccessNode(uniqueID, this);
// Make sure an ancestor in real content is cached
// so that nsDocAccessible::RefreshNodes() can find the anonymous subtree to release when
// the root node goes away
nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
- if (content && (content->IsNativeAnonymous() ||
- content->GetBindingParent())) {
+ if (content && content->IsInAnonymousSubtree()) {
// Specific examples of where this is used: <input type="file"> and <xul:findbar>
nsCOMPtr<nsIAccessible> parentAccessible;
docAccessible->GetAccessibleInParentChain(mDOMNode, PR_TRUE, getter_AddRefs(parentAccessible));
if (parentAccessible) {
PRInt32 childCountUnused;
parentAccessible->GetChildCount(&childCountUnused);
}
}
@@ -789,17 +788,17 @@ nsAccessNode::GetCacheEntry(nsAccessNode
void* aUniqueID,
nsIAccessNode **aAccessNode)
{
aCache.Get(aUniqueID, aAccessNode); // AddRefs for us
}
PLDHashOperator nsAccessNode::ClearCacheEntry(const void* aKey, nsCOMPtr<nsIAccessNode>& aAccessNode, void* aUserArg)
{
- NS_ASSERTION(!aAccessNode, "Calling ClearCacheEntry with a NULL pointer!");
+ NS_ASSERTION(aAccessNode, "Calling ClearCacheEntry with a NULL pointer!");
if (aAccessNode) {
nsCOMPtr<nsPIAccessNode> privateAccessNode(do_QueryInterface(aAccessNode));
privateAccessNode->Shutdown();
}
return PL_DHASH_REMOVE;
}
@@ -871,20 +870,17 @@ nsAccessNode::GetLanguage(nsAString& aLa
content = do_QueryInterface(docElement);
}
}
if (!content) {
return NS_ERROR_FAILURE;
}
}
- nsIContent *walkUp = content;
- while (walkUp && !walkUp->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::lang, aLanguage)) {
- walkUp = walkUp->GetParent();
- }
+ nsAccUtils::GetLanguageFor(content, nsnull, aLanguage);
if (aLanguage.IsEmpty()) { // Nothing found, so use document's language
nsIDocument *doc = content->GetOwnerDoc();
if (doc) {
doc->GetHeaderData(nsAccessibilityAtoms::headerContentLanguage, aLanguage);
}
}
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -40,16 +40,18 @@
* see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
*/
#ifndef _nsAccessNode_H_
#define _nsAccessNode_H_
#include "nsCOMPtr.h"
#include "nsAccessibilityAtoms.h"
+#include "nsAccessibilityUtils.h"
+
#include "nsIAccessibleTypes.h"
#include "nsIAccessNode.h"
#include "nsIContent.h"
#include "nsPIAccessNode.h"
#include "nsIDOMNode.h"
#include "nsINameSpaceManager.h"
#include "nsIStringBundle.h"
#include "nsWeakReference.h"
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -144,24 +144,25 @@ ACCESSIBILITY_ATOM(textbox, "textbox")
ACCESSIBILITY_ATOM(toolbaritem, "toolbaritem") // XUL
ACCESSIBILITY_ATOM(toolbarseparator, "toolbarseparator") // XUL
ACCESSIBILITY_ATOM(toolbarspring, "toolbarspring") // XUL
ACCESSIBILITY_ATOM(toolbarspacer, "toolbarspacer") // XUL
ACCESSIBILITY_ATOM(tooltip, "tooltip") // XUL
ACCESSIBILITY_ATOM(tr, "tr")
ACCESSIBILITY_ATOM(ul, "ul")
- // Alphabetical list of attributes
+ // Alphabetical list of attributes (DOM)
ACCESSIBILITY_ATOM(acceltext, "acceltext")
ACCESSIBILITY_ATOM(accesskey, "accesskey")
ACCESSIBILITY_ATOM(alt, "alt")
ACCESSIBILITY_ATOM(anonid, "anonid") // Used for ID's in XBL
ACCESSIBILITY_ATOM(contenteditable, "contenteditable")
ACCESSIBILITY_ATOM(control, "control")
ACCESSIBILITY_ATOM(disabled, "disabled")
+ACCESSIBILITY_ATOM(display, "display")
ACCESSIBILITY_ATOM(_class, "class")
ACCESSIBILITY_ATOM(cycles, "cycles") // used for XUL cycler attribute
ACCESSIBILITY_ATOM(curpos, "curpos") // XUL
ACCESSIBILITY_ATOM(data, "data")
ACCESSIBILITY_ATOM(droppable, "droppable") // XUL combo box
ACCESSIBILITY_ATOM(editable, "editable")
ACCESSIBILITY_ATOM(_for, "for")
ACCESSIBILITY_ATOM(hidden, "hidden") // XUL tree columns
@@ -180,16 +181,20 @@ ACCESSIBILITY_ATOM(src, "src")
ACCESSIBILITY_ATOM(selected, "selected")
ACCESSIBILITY_ATOM(summary, "summary")
ACCESSIBILITY_ATOM(tabindex, "tabindex")
ACCESSIBILITY_ATOM(title, "title")
ACCESSIBILITY_ATOM(tooltiptext, "tooltiptext")
ACCESSIBILITY_ATOM(type, "type")
ACCESSIBILITY_ATOM(value, "value")
+ // Alphabetical list of text attributes (AT API)
+ACCESSIBILITY_ATOM(invalid, "invalid")
+ACCESSIBILITY_ATOM(language, "language")
+
// ARIA (DHTML accessibility) attributes
// Also add to nsARIAMap.cpp and nsARIAMap.h
// ARIA role attribute
ACCESSIBILITY_ATOM(role, "role")
ACCESSIBILITY_ATOM(aria_activedescendant, "aria-activedescendant")
ACCESSIBILITY_ATOM(aria_atomic, "aria-atomic")
ACCESSIBILITY_ATOM(aria_autocomplete, "aria-autocomplete")
ACCESSIBILITY_ATOM(aria_busy, "aria-busy")
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1323,39 +1323,36 @@ NS_IMETHODIMP nsAccessibilityService::Ge
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(aNode));
if (element) {
element->GetAttribute(NS_LITERAL_STRING("type"), attrib);
if (attrib.EqualsLiteral("statusbarpanel"))
printf("## aaronl debugging attribute\n");
}
#endif
- nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
- if (content && content->Tag() == nsAccessibilityAtoms::map) {
- // Don't walk into maps, they take up no space.
- // The nsHTMLAreaAccessible's they contain are attached as
- // children of the appropriate nsHTMLImageAccessible.
- *aIsHidden = PR_TRUE;
- return NS_OK;
- }
-
// Check to see if we already have an accessible for this
// node in the cache
nsCOMPtr<nsIAccessNode> accessNode;
GetCachedAccessNode(aNode, aWeakShell, getter_AddRefs(accessNode));
nsCOMPtr<nsIAccessible> newAcc;
if (accessNode) {
- // Retrieved from cache
- // QI might not succeed if it's a node that's not accessible
+ // Retrieved from cache. QI might not succeed if it's a node that's not
+ // accessible. In this case try to create new accessible because one and
+ // the same DOM node may be accessible or not in time (for example,
+ // when it is visible or hidden).
newAcc = do_QueryInterface(accessNode);
- NS_IF_ADDREF(*aAccessible = newAcc);
- return NS_OK;
+ if (newAcc) {
+ NS_ADDREF(*aAccessible = newAcc);
+ return NS_OK;
+ }
}
+ nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
+
// No cache entry, so we must create the accessible
// Check to see if hidden first
nsCOMPtr<nsIDocument> nodeIsDoc;
if (!content) {
// This happens when we're on the document node, which will not QI to an
// nsIContent.
nodeIsDoc = do_QueryInterface(aNode);
NS_ENSURE_TRUE(nodeIsDoc, NS_ERROR_FAILURE); // No content, and not doc node
@@ -1456,31 +1453,51 @@ NS_IMETHODIMP nsAccessibilityService::Ge
*aIsHidden = PR_TRUE;
return NS_OK;
}
}
frame->GetAccessible(getter_AddRefs(newAcc));
return InitAccessible(newAcc, aAccessible, nsnull);
}
+ PRBool isHTML = content->IsNodeOfType(nsINode::eHTML);
+ if (isHTML && content->Tag() == nsAccessibilityAtoms::map) {
+ // Create hyper text accessible for HTML map if it is used to group links
+ // (see http://www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass). If the HTML
+ // map doesn't have 'name' attribute (or has empty name attribute) then we
+ // suppose it is used for links grouping. Otherwise we think it is used in
+ // conjuction with HTML image element and in this case we don't create any
+ // accessible for it and don't walk into it. The accessibles for HTML area
+ // (nsHTMLAreaAccessible) the map contains are attached as children of the
+ // appropriate accessible for HTML image (nsHTMLImageAccessible).
+ nsAutoString name;
+ content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::name, name);
+ if (!name.IsEmpty()) {
+ *aIsHidden = PR_TRUE;
+ return NS_OK;
+ }
+
+ nsresult rv = CreateHyperTextAccessible(frame, getter_AddRefs(newAcc));
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(aNode);
if (roleMapEntry && !nsCRT::strcmp(roleMapEntry->roleString, "presentation") &&
!content->IsFocusable()) { // For presentation only
// Only create accessible for role of "presentation" if it is focusable --
// in that case we need an accessible in case it gets focused, we
// don't want focus ever to be 'lost'
return NS_OK;
}
// Elements may implement nsIAccessibleProvider via XBL. This allows them to
// say what kind of accessible to create.
nsresult rv = GetAccessibleByType(aNode, getter_AddRefs(newAcc));
NS_ENSURE_SUCCESS(rv, rv);
-
- PRBool isHTML = content->IsNodeOfType(nsINode::eHTML);
+
if (!newAcc && !isHTML) {
if (content->GetNameSpaceID() == kNameSpaceID_SVG &&
content->Tag() == nsAccessibilityAtoms::svg) {
newAcc = new nsEnumRoleAccessible(aNode, aWeakShell,
nsIAccessibleRole::ROLE_DIAGRAM);
}
else if (content->GetNameSpaceID() == kNameSpaceID_MathML &&
content->Tag() == nsAccessibilityAtoms::math) {
@@ -1521,17 +1538,17 @@ NS_IMETHODIMP nsAccessibilityService::Ge
}
if (tableAccessible && nsAccessible::Role(tableAccessible) != nsIAccessibleRole::ROLE_TABLE) {
NS_ASSERTION(!roleMapEntry, "Should not be changing ARIA role, just overriding impl class role");
// Not in table: override role (roleMap entry was null).
roleMapEntry = &nsARIAMap::gEmptyRoleMap;
}
break;
}
- else if (tableFrame->GetType() == nsAccessibilityAtoms::tableCellFrame) {
+ else if (tableContent->Tag() == nsAccessibilityAtoms::table) {
// Stop before we are fooled by any additional table ancestors
// This table cell frameis part of a separate ancestor table.
tryTagNameOrFrame = PR_FALSE;
break;
}
}
if (!tableContent)
@@ -2044,24 +2061,25 @@ nsAccessibilityService::GetAccessibleFor
if (frame && (frame->GetType() == nsAccessibilityAtoms::boxFrame ||
frame->GetType() == nsAccessibilityAtoms::scrollFrame)) {
parentFrame = frame->GetParent();
if (parentFrame && parentFrame->GetType() == nsAccessibilityAtoms::deckFrame) {
// If deck frame is for xul:tabpanels element then the given node has
// tabpanel accessible.
nsCOMPtr<nsIContent> parentContent = parentFrame->GetContent();
+#ifdef MOZ_XUL
if (parentContent->NodeInfo()->Equals(nsAccessibilityAtoms::tabpanels,
kNameSpaceID_XUL)) {
*aAccessible = new nsXULTabpanelAccessible(aNode, weakShell);
- } else {
+ } else
+#endif
*aAccessible =
new nsEnumRoleAccessible(aNode, weakShell,
nsIAccessibleRole::ROLE_PROPERTYPAGE);
- }
NS_ENSURE_TRUE(*aAccessible, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(*aAccessible);
}
}
return NS_OK;
--- a/accessible/src/base/nsAccessibilityUtils.cpp
+++ b/accessible/src/base/nsAccessibilityUtils.cpp
@@ -220,45 +220,70 @@ nsAccUtils::SetAccAttrsForXULContainerIt
// Get item count.
PRUint32 itemsCount = 0;
container->GetItemCount(&itemsCount);
// Get item index.
PRInt32 indexOf = 0;
container->GetIndexOfItem(item, &indexOf);
-
- PRUint32 setSize = itemsCount, posInSet = indexOf;
- for (PRUint32 index = 0; index < itemsCount; index++) {
- nsCOMPtr<nsIDOMXULElement> currItem;
- container->GetItemAtIndex(index, getter_AddRefs(currItem));
- nsCOMPtr<nsIDOMNode> currNode(do_QueryInterface(currItem));
+
+ // Calculate set size and position in the set.
+ PRUint32 setSize = 0, posInSet = 0;
+ for (PRInt32 index = indexOf; index >= 0; index--) {
+ nsCOMPtr<nsIDOMXULElement> item;
+ container->GetItemAtIndex(index, getter_AddRefs(item));
+
+ nsCOMPtr<nsIAccessible> itemAcc;
+ nsAccessNode::GetAccService()->GetAccessibleFor(item,
+ getter_AddRefs(itemAcc));
+
+ if (itemAcc) {
+ PRUint32 itemRole = nsAccessible::Role(itemAcc);
+ if (itemRole == nsIAccessibleRole::ROLE_SEPARATOR)
+ break; // We reached the beginning of our group.
+
+ PRUint32 itemState = nsAccessible::State(itemAcc);
+ if (!(itemState & nsIAccessibleStates::STATE_INVISIBLE)) {
+ setSize++;
+ posInSet++;
+ }
+ }
+ }
+
+ for (PRInt32 index = indexOf + 1; index < itemsCount; index++) {
+ nsCOMPtr<nsIDOMXULElement> item;
+ container->GetItemAtIndex(index, getter_AddRefs(item));
nsCOMPtr<nsIAccessible> itemAcc;
- nsAccessNode::GetAccService()->GetAccessibleFor(currNode,
+ nsAccessNode::GetAccService()->GetAccessibleFor(item,
getter_AddRefs(itemAcc));
- if (!itemAcc ||
- nsAccessible::State(itemAcc) & nsIAccessibleStates::STATE_INVISIBLE) {
- setSize--;
- if (index < static_cast<PRUint32>(indexOf))
- posInSet--;
+
+ if (itemAcc) {
+ PRUint32 itemRole = nsAccessible::Role(itemAcc);
+ if (itemRole == nsIAccessibleRole::ROLE_SEPARATOR)
+ break; // We reached the end of our group.
+
+ PRUint32 itemState = nsAccessible::State(itemAcc);
+ if (!(itemState & nsIAccessibleStates::STATE_INVISIBLE))
+ setSize++;
}
}
// Get level of the item.
PRInt32 level = -1;
while (container) {
level++;
nsCOMPtr<nsIDOMXULContainerElement> parentContainer;
container->GetParentContainer(getter_AddRefs(parentContainer));
parentContainer.swap(container);
}
- SetAccGroupAttrs(aAttributes, level, posInSet + 1, setSize);
+ SetAccGroupAttrs(aAttributes, level, posInSet, setSize);
}
PRBool
nsAccUtils::HasListener(nsIContent *aContent, const nsAString& aEventType)
{
NS_ENSURE_TRUE(aContent, PR_FALSE);
nsCOMPtr<nsIEventListenerManager> listenerManager;
aContent->GetListenerManager(PR_FALSE, getter_AddRefs(listenerManager));
@@ -310,16 +335,34 @@ nsAccUtils::FireAccEvent(PRUint32 aEvent
nsCOMPtr<nsIAccessibleEvent> event =
new nsAccEvent(aEventType, aAccessible, aIsAsynch);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
return pAccessible->FireAccessibleEvent(event);
}
+already_AddRefed<nsIDOMElement>
+nsAccUtils::GetDOMElementFor(nsIDOMNode *aNode)
+{
+ nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
+
+ nsIDOMElement *element = nsnull;
+ if (node->IsNodeOfType(nsINode::eELEMENT))
+ CallQueryInterface(node, &element);
+ else if (node->IsNodeOfType(nsINode::eTEXT))
+ CallQueryInterface(node->GetNodeParent(), &element);
+ else if (node->IsNodeOfType(nsINode::eDOCUMENT)) {
+ nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(node));
+ domDoc->GetDocumentElement(&element);
+ }
+
+ return element;
+}
+
PRBool
nsAccUtils::IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
nsIDOMNode *aPossibleDescendantNode)
{
NS_ENSURE_TRUE(aPossibleAncestorNode && aPossibleDescendantNode, PR_FALSE);
nsCOMPtr<nsIDOMNode> loopNode = aPossibleDescendantNode;
nsCOMPtr<nsIDOMNode> parentNode;
@@ -744,29 +787,28 @@ nsAccUtils::FindNeighbourPointingToNode(
nsIContent*
nsAccUtils::FindNeighbourPointingToNode(nsIContent *aForNode,
nsIAtom **aRelationAttrs,
PRUint32 aAttrNum,
nsIAtom *aTagName,
PRUint32 aAncestorLevelsToSearch)
{
- nsCOMPtr<nsIContent> binding;
nsAutoString controlID;
if (!nsAccUtils::GetID(aForNode, controlID)) {
- binding = aForNode->GetBindingParent();
- if (binding == aForNode)
+ if (!aForNode->IsInAnonymousSubtree())
return nsnull;
aForNode->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::anonid, controlID);
if (controlID.IsEmpty())
return nsnull;
}
// Look for label in subtrees of nearby ancestors
+ nsCOMPtr<nsIContent> binding(aForNode->GetBindingParent());
PRUint32 count = 0;
nsIContent *labelContent = nsnull;
nsIContent *prevSearched = nsnull;
while (!labelContent && ++count <= aAncestorLevelsToSearch &&
(aForNode = aForNode->GetParent()) != nsnull) {
if (aForNode == binding) {
@@ -891,16 +933,29 @@ nsAccUtils::FindDescendantPointingToIDIm
if (labelContent) {
return labelContent;
}
}
}
return nsnull;
}
+void
+nsAccUtils::GetLanguageFor(nsIContent *aContent, nsIContent *aRootContent,
+ nsAString& aLanguage)
+{
+ aLanguage.Truncate();
+
+ nsIContent *walkUp = aContent;
+ while (walkUp && walkUp != aRootContent &&
+ !walkUp->GetAttr(kNameSpaceID_None,
+ nsAccessibilityAtoms::lang, aLanguage))
+ walkUp = walkUp->GetParent();
+}
+
nsRoleMapEntry*
nsAccUtils::GetRoleMapEntry(nsIDOMNode *aNode)
{
nsIContent *content = nsAccessible::GetRoleContent(aNode);
nsAutoString roleString;
if (!content || !content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::role, roleString)) {
return nsnull;
}
--- a/accessible/src/base/nsAccessibilityUtils.h
+++ b/accessible/src/base/nsAccessibilityUtils.h
@@ -134,16 +134,26 @@ public:
/**
* Fire accessible event of the given type for the given accessible.
*/
static nsresult FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
PRBool aIsAsynch = PR_FALSE);
/**
+ * Return DOM element related with the given node, i.e.
+ * a) itself if it is DOM element
+ * b) parent element if it is text node
+ * c) document element if it is document node.
+ *
+ * @param aNode [in] the given DOM node
+ */
+ static already_AddRefed<nsIDOMElement> GetDOMElementFor(nsIDOMNode *aNode);
+
+ /**
* Is the first passed in node an ancestor of the second?
* Note: A node is not considered to be the ancestor of itself.
* @param aPossibleAncestorNode -- node to test for ancestor-ness of aPossibleDescendantNode
* @param aPossibleDescendantNode -- node to test for descendant-ness of aPossibleAncestorNode
* @return PR_TRUE if aPossibleAncestorNode is an ancestor of aPossibleDescendantNode
*/
static PRBool IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
nsIDOMNode *aPossibleDescendantNode);
@@ -298,16 +308,26 @@ public:
* Check if the given element is XLink.
*
* @param aContent the given element
* @return PR_TRUE if the given element is XLink
*/
static PRBool IsXLink(nsIContent *aContent);
/**
+ * Returns language for the given node.
+ *
+ * @param aContent [in] the given node
+ * @param aRootContent [in] container of the given node
+ * @param aLanguage [out] language
+ */
+ static void GetLanguageFor(nsIContent *aContent, nsIContent *aRootContent,
+ nsAString& aLanguage);
+
+ /**
* Get the role map entry for a given DOM node. This will use the first
* ARIA role if the role attribute provides a space delimited list of roles.
* @param aNode The DOM node to get the role map entry for
* @return A pointer to the role map entry for the ARIA role, or nsnull if none
*/
static nsRoleMapEntry* GetRoleMapEntry(nsIDOMNode *aNode);
/**
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -1588,25 +1588,16 @@ nsresult nsAccessible::AppendFlatStringF
}
}
return NS_OK;
}
nsAutoString textEquivalent;
if (!aContent->IsNodeOfType(nsINode::eHTML)) {
if (aContent->IsNodeOfType(nsINode::eXUL)) {
- nsCOMPtr<nsIPresShell> shell = GetPresShell();
- if (!shell) {
- return NS_ERROR_FAILURE;
- }
- nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
- if (!frame || !frame->GetStyleVisibility()->IsVisible()) {
- return NS_OK;
- }
-
nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl(do_QueryInterface(aContent));
if (labeledEl) {
labeledEl->GetLabel(textEquivalent);
}
else {
if (aContent->NodeInfo()->Equals(nsAccessibilityAtoms::label, kNameSpaceID_XUL)) {
aContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value, textEquivalent);
}
@@ -1656,18 +1647,27 @@ nsresult nsAccessible::AppendFlatStringF
nsresult nsAccessible::AppendFlatStringFromSubtree(nsIContent *aContent, nsAString *aFlatString)
{
static PRBool isAlreadyHere; // Prevent recursion which can cause infinite loops
if (isAlreadyHere) {
return NS_OK;
}
+
isAlreadyHere = PR_TRUE;
- nsresult rv = AppendFlatStringFromSubtreeRecurse(aContent, aFlatString);
+
+ nsCOMPtr<nsIPresShell> shell = GetPresShell();
+ NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
+
+ nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
+ PRBool isHidden = (!frame || !frame->GetStyleVisibility()->IsVisible());
+ nsresult rv = AppendFlatStringFromSubtreeRecurse(aContent, aFlatString,
+ isHidden);
+
isAlreadyHere = PR_FALSE;
if (NS_SUCCEEDED(rv) && !aFlatString->IsEmpty()) {
nsAString::const_iterator start, end;
aFlatString->BeginReading(start);
aFlatString->EndReading(end);
PRInt32 spacesToTruncate = 0;
@@ -1676,37 +1676,55 @@ nsresult nsAccessible::AppendFlatStringF
if (spacesToTruncate > 0)
aFlatString->Truncate(aFlatString->Length() - spacesToTruncate);
}
return rv;
}
-nsresult nsAccessible::AppendFlatStringFromSubtreeRecurse(nsIContent *aContent, nsAString *aFlatString)
+nsresult
+nsAccessible::AppendFlatStringFromSubtreeRecurse(nsIContent *aContent,
+ nsAString *aFlatString,
+ PRBool aIsRootHidden)
{
// Depth first search for all text nodes that are decendants of content node.
// Append all the text into one flat string
PRUint32 numChildren = 0;
nsCOMPtr<nsIDOMXULSelectControlElement> selectControlEl(do_QueryInterface(aContent));
if (!selectControlEl) { // Don't walk children of elements with options, just get label directly
numChildren = aContent->GetChildCount();
}
if (numChildren == 0) {
// There are no children or they are irrelvant: get the text from the current node
AppendFlatStringFromContentNode(aContent, aFlatString);
return NS_OK;
}
// There are relevant children: use them to get the text.
+ nsCOMPtr<nsIPresShell> shell = GetPresShell();
+ NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
+
PRUint32 index;
for (index = 0; index < numChildren; index++) {
- AppendFlatStringFromSubtreeRecurse(aContent->GetChildAt(index), aFlatString);
+ nsCOMPtr<nsIContent> childContent = aContent->GetChildAt(index);
+
+ // Walk into hidden subtree if the the root parent is also hidden. This
+ // happens when the author explictly uses a hidden label or description.
+ if (!aIsRootHidden) {
+ nsIFrame *childFrame = shell->GetPrimaryFrameFor(childContent);
+ if (!childFrame || !childFrame->GetStyleVisibility()->IsVisible())
+ continue;
+ }
+
+ AppendFlatStringFromSubtreeRecurse(childContent, aFlatString,
+ aIsRootHidden);
}
+
return NS_OK;
}
nsIContent *nsAccessible::GetLabelContent(nsIContent *aForNode)
{
if (aForNode->IsNodeOfType(nsINode::eXUL))
return nsAccUtils::FindNeighbourPointingToNode(aForNode, nsAccessibilityAtoms::control,
nsAccessibilityAtoms::label);
@@ -2040,16 +2058,19 @@ NS_IMETHODIMP nsAccessible::GetFinalRole
return mDOMNode ? GetRole(aRole) : NS_ERROR_FAILURE; // Node already shut down
}
NS_IMETHODIMP
nsAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
{
NS_ENSURE_ARG_POINTER(aAttributes); // In/out param. Created if necessary.
+ if (IsDefunct())
+ return NS_ERROR_FAILURE;
+
nsCOMPtr<nsIContent> content = GetRoleContent(mDOMNode);
if (!content) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIPersistentProperties> attributes = *aAttributes;
if (!attributes) {
// Create only if an array wasn't already passed in
@@ -2109,46 +2130,72 @@ nsAccessible::GetAttributes(nsIPersisten
if (!nsAccUtils::HasAccGroupAttrs(attributes)) {
// The role of an accessible can be pointed by ARIA attribute but ARIA
// posinset, level, setsize may be skipped. Therefore we calculate here
// these properties to map them into description.
// If accessible is invisible we don't want to calculate group ARIA
// attributes for it.
if ((role == nsIAccessibleRole::ROLE_LISTITEM ||
- role == nsIAccessibleRole::ROLE_MENUITEM ||
- role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
- role == nsIAccessibleRole::ROLE_PAGETAB ||
- role == nsIAccessibleRole::ROLE_OPTION ||
- role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
- role == nsIAccessibleRole::ROLE_OUTLINEITEM) &&
+ role == nsIAccessibleRole::ROLE_MENUITEM ||
+ role == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
+ role == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM ||
+ role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
+ role == nsIAccessibleRole::ROLE_PAGETAB ||
+ role == nsIAccessibleRole::ROLE_OPTION ||
+ role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
+ role == nsIAccessibleRole::ROLE_OUTLINEITEM) &&
0 == (State(this) & nsIAccessibleStates::STATE_INVISIBLE)) {
+
+ PRUint32 baseRole = role;
+ if (role == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
+ role == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
+ baseRole = nsIAccessibleRole::ROLE_MENUITEM;
+
nsCOMPtr<nsIAccessible> parent = GetParent();
NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE);
PRInt32 positionInGroup = 0;
PRInt32 setSize = 0;
nsCOMPtr<nsIAccessible> sibling, nextSibling;
parent->GetFirstChild(getter_AddRefs(sibling));
NS_ENSURE_TRUE(sibling, NS_ERROR_FAILURE);
PRBool foundCurrent = PR_FALSE;
- PRUint32 siblingRole;
+ PRUint32 siblingRole, siblingBaseRole;
while (sibling) {
sibling->GetFinalRole(&siblingRole);
- if (siblingRole == role &&
+
+ siblingBaseRole = siblingRole;
+ if (siblingRole == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
+ siblingRole == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
+ siblingBaseRole = nsIAccessibleRole::ROLE_MENUITEM;
+
+ // If sibling is visible and has the same base role.
+ if (siblingBaseRole == baseRole &&
!(State(sibling) & nsIAccessibleStates::STATE_INVISIBLE)) {
++ setSize;
if (!foundCurrent) {
++ positionInGroup;
if (sibling == this)
foundCurrent = PR_TRUE;
}
}
+
+ // If the sibling is separator
+ if (siblingRole == nsIAccessibleRole::ROLE_SEPARATOR) {
+ if (foundCurrent) // the our group is ended
+ break;
+
+ // not our group, continue the searching
+ positionInGroup = 0;
+ setSize = 0;
+ }
+
sibling->GetNextSibling(getter_AddRefs(nextSibling));
sibling = nextSibling;
}
PRInt32 groupLevel = 0;
if (role == nsIAccessibleRole::ROLE_OUTLINEITEM) {
groupLevel = 1;
nsCOMPtr<nsIAccessible> nextParent;
@@ -2245,16 +2292,24 @@ nsAccessible::GetAttributesInternal(nsIP
if (!sameTypeParent || sameTypeParent == docShellTreeItem)
break;
nsIDocument *parentDoc = doc->GetParentDocument();
if (!parentDoc)
break;
startContent = parentDoc->FindContentForSubDocument(doc);
}
+ // Expose 'display' attribute.
+ nsAutoString displayValue;
+ nsresult rv = GetComputedStyleValue(EmptyString(),
+ NS_LITERAL_STRING("display"),
+ displayValue);
+ if (NS_SUCCEEDED(rv))
+ nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::display,
+ displayValue);
return NS_OK;
}
NS_IMETHODIMP
nsAccessible::GroupPosition(PRInt32 *aGroupLevel,
PRInt32 *aSimilarItemsInGroup,
PRInt32 *aPositionInGroup)
{
@@ -2463,34 +2518,49 @@ nsAccessible::GetARIAState(PRUint32 *aSt
return NS_OK;
}
PRUint32 index = 0;
while (MappedAttrState(content, aState, &nsARIAMap::gWAIUnivStateMap[index])) {
++ index;
}
- if (!mRoleMapEntry)
- return NS_OK;
-
- // Once DHTML role is used, we're only readonly if DHTML readonly used
- *aState &= ~nsIAccessibleStates::STATE_READONLY;
-
- if (content->HasAttr(kNameSpaceID_None, content->GetIDAttributeName())) {
- // If has a role & ID and aria-activedescendant on the container, assume focusable
- nsIContent *ancestorContent = content;
- while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {
- if (ancestorContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_activedescendant)) {
- // ancestor has activedescendant property, this content could be active
- *aState |= nsIAccessibleStates::STATE_FOCUSABLE;
- break;
+ if (mRoleMapEntry) {
+ // Once DHTML role is used, we're only readonly if DHTML readonly used
+ *aState &= ~nsIAccessibleStates::STATE_READONLY;
+
+ if (content->HasAttr(kNameSpaceID_None, content->GetIDAttributeName())) {
+ // If has a role & ID and aria-activedescendant on the container, assume focusable
+ nsIContent *ancestorContent = content;
+ while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {
+ if (ancestorContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_activedescendant)) {
+ // ancestor has activedescendant property, this content could be active
+ *aState |= nsIAccessibleStates::STATE_FOCUSABLE;
+ break;
+ }
}
}
}
+ if (*aState & nsIAccessibleStates::STATE_FOCUSABLE) {
+ // Special case: aria-disabled propagates from ancestors down to any focusable descendant
+ nsIContent *ancestorContent = content;
+ while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {
+ if (ancestorContent->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::aria_disabled,
+ nsAccessibilityAtoms::_true, eCaseMatters)) {
+ // ancestor has aria-disabled property, this is disabled
+ *aState |= nsIAccessibleStates::STATE_UNAVAILABLE;
+ break;
+ }
+ }
+ }
+
+ if (!mRoleMapEntry)
+ return NS_OK;
+
*aState |= mRoleMapEntry->state;
if (MappedAttrState(content, aState, &mRoleMapEntry->attributeMap1) &&
MappedAttrState(content, aState, &mRoleMapEntry->attributeMap2) &&
MappedAttrState(content, aState, &mRoleMapEntry->attributeMap3) &&
MappedAttrState(content, aState, &mRoleMapEntry->attributeMap4) &&
MappedAttrState(content, aState, &mRoleMapEntry->attributeMap5) &&
MappedAttrState(content, aState, &mRoleMapEntry->attributeMap6) &&
MappedAttrState(content, aState, &mRoleMapEntry->attributeMap7)) {
@@ -2654,18 +2724,21 @@ NS_IMETHODIMP
nsAccessible::GetNumActions(PRUint8 *aNumActions)
{
NS_ENSURE_ARG_POINTER(aNumActions);
*aNumActions = 0;
if (IsDefunct())
return NS_ERROR_FAILURE;
+ nsCOMPtr<nsIContent> content = GetRoleContent(mDOMNode);
+ if (!content)
+ return NS_OK;
+
// Check if it's an simple xlink.
- nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (nsAccUtils::IsXLink(content)) {
*aNumActions = 1;
return NS_OK;
}
// Has registered 'click' event handler.
PRBool isOnclick = nsAccUtils::HasListener(content,
NS_LITERAL_STRING("click"));
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -35,17 +35,16 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef _nsAccessible_H_
#define _nsAccessible_H_
#include "nsAccessNodeWrap.h"
-#include "nsAccessibilityUtils.h"
#include "nsIAccessible.h"
#include "nsPIAccessible.h"
#include "nsIAccessibleHyperLink.h"
#include "nsIAccessibleSelectable.h"
#include "nsIAccessibleValue.h"
#include "nsIAccessibleRole.h"
#include "nsIAccessibleStates.h"
@@ -192,17 +191,32 @@ protected:
nsresult AppendNameFromAccessibleFor(nsIContent *aContent, nsAString *aFlatString,
PRBool aFromValue = PR_FALSE);
nsresult AppendFlatStringFromContentNode(nsIContent *aContent, nsAString *aFlatString);
nsresult AppendStringWithSpaces(nsAString *aFlatString, const nsAString& textEquivalent);
// helper method to verify frames
static nsresult GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut);
static nsresult GetTranslatedString(const nsAString& aKey, nsAString& aStringOut);
- nsresult AppendFlatStringFromSubtreeRecurse(nsIContent *aContent, nsAString *aFlatString);
+
+ /**
+ * Walk into subtree and calculate the string which is used as the accessible
+ * name or description.
+ *
+ * @param aContent [in] traversed content
+ * @param aFlatString [in, out] result string
+ * @param aIsRootHidden [in] specifies whether root content (we started to
+ * traverse from) is hidden, in this case the result
+ * string is calculated from hidden children
+ * (this is used when hidden root content is explicitly
+ * specified as label or description by author)
+ */
+ nsresult AppendFlatStringFromSubtreeRecurse(nsIContent *aContent,
+ nsAString *aFlatString,
+ PRBool aIsRootHidden);
// Helpers for dealing with children
virtual void CacheChildren();
// nsCOMPtr<>& is useful here, because getter_AddRefs() nulls the comptr's value, and NextChild
// depends on the passed-in comptr being null or already set to a child (finding the next sibling).
nsIAccessible *NextChild(nsCOMPtr<nsIAccessible>& aAccessible);
@@ -241,16 +255,26 @@ protected:
*
* @param aAriaProperty - the ARIA property we're using
* @param aValue - value of the attribute
*
* @return - NS_OK_NO_ARIA_VALUE if there is no setted ARIA attribute
*/
nsresult GetAttrValue(nsIAtom *aAriaProperty, double *aValue);
+ /**
+ * Fires platform accessible event. It's notification method only. It does
+ * change nothing on Gecko side. Mostly you should use
+ * nsIAccessible::FireAccessibleEvent excepting special cases like we have
+ * in xul:tree accessible to lie to AT. Must be overridden in wrap classes.
+ *
+ * @param aEvent the accessible event to fire.
+ */
+ virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent) = 0;
+
// Data Members
nsCOMPtr<nsIAccessible> mParent;
nsIAccessible *mFirstChild, *mNextSibling;
nsRoleMapEntry *mRoleMapEntry; // Non-null indicates author-supplied role; possibly state & value as well
PRInt32 mAccChildCount;
};
--- a/accessible/src/base/nsCaretAccessible.cpp
+++ b/accessible/src/base/nsCaretAccessible.cpp
@@ -34,26 +34,26 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// NOTE: alphabetically ordered
#include "nsAccessibilityService.h"
#include "nsCaretAccessible.h"
#include "nsIAccessibleEvent.h"
-#include "nsICaret.h"
+#include "nsCaret.h"
#include "nsIDOMDocument.h"
#include "nsIDOMHTMLAnchorElement.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIDOMHTMLTextAreaElement.h"
#include "nsIFrame.h"
#include "nsIPresShell.h"
#include "nsRootAccessible.h"
-#include "nsISelectionController.h"
#include "nsISelectionPrivate.h"
+#include "nsISelection2.h"
#include "nsServiceManagerUtils.h"
#include "nsIViewManager.h"
#include "nsIWidget.h"
NS_IMPL_ISUPPORTS1(nsCaretAccessible, nsISelectionListener)
nsCaretAccessible::nsCaretAccessible( nsRootAccessible *aRootAccessible):
mLastCaretOffset(-1), mRootAccessible(aRootAccessible)
@@ -73,104 +73,150 @@ void nsCaretAccessible::Shutdown()
ClearControlSelectionListener(); // Clear the selection listener for the currently focused control
mLastTextAccessible = nsnull;
mLastUsedSelection = nsnull;
mRootAccessible = nsnull;
}
nsresult nsCaretAccessible::ClearControlSelectionListener()
{
+ nsCOMPtr<nsISelectionController> controller =
+ GetSelectionControllerForNode(mCurrentControl);
+
mCurrentControl = nsnull;
- mCurrentControlSelection = nsnull;
+
+ if (!controller)
+ return NS_OK;
- nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryReferent(mCurrentControlSelection));
- if (!selPrivate) {
- return NS_OK;
- }
+ // Remove 'this' registered as selection listener for the normal selection.
+ nsCOMPtr<nsISelection> normalSel;
+ controller->GetSelection(nsISelectionController::SELECTION_NORMAL,
+ getter_AddRefs(normalSel));
+ nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(normalSel));
+ NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
+
+ nsresult rv = selPrivate->RemoveSelectionListener(this);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Remove 'this' registered as selection listener for the spellcheck
+ // selection.
+ nsCOMPtr<nsISelection> spellcheckSel;
+ controller->GetSelection(nsISelectionController::SELECTION_SPELLCHECK,
+ getter_AddRefs(spellcheckSel));
+ selPrivate = do_QueryInterface(spellcheckSel);
+ NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
return selPrivate->RemoveSelectionListener(this);
}
nsresult nsCaretAccessible::SetControlSelectionListener(nsIDOMNode *aCurrentNode)
{
NS_ENSURE_TRUE(mRootAccessible, NS_ERROR_FAILURE);
ClearControlSelectionListener();
mCurrentControl = aCurrentNode;
mLastTextAccessible = nsnull;
// When focus moves such that the caret is part of a new frame selection
- // this removes the old selection listener and attaches a new one for the current focus
- nsCOMPtr<nsIPresShell> presShell =
- mRootAccessible->GetPresShellFor(aCurrentNode);
- if (!presShell)
- return NS_ERROR_FAILURE;
-
- nsCOMPtr<nsIDocument> doc = presShell->GetDocument();
- NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+ // this removes the old selection listener and attaches a new one for
+ // the current focus.
+ nsCOMPtr<nsISelectionController> controller =
+ GetSelectionControllerForNode(mCurrentControl);
+ NS_ENSURE_TRUE(controller, NS_ERROR_FAILURE);
- nsCOMPtr<nsIContent> content(do_QueryInterface(aCurrentNode));
- // The control selection listener is only for form controls, not for the document
- // When there is no document, the content will be null
- if (!content) {
- return NS_OK;
- }
-
- nsIFrame *frame = presShell->GetPrimaryFrameFor(content);
- NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
-
- nsPresContext *presContext = presShell->GetPresContext();
- NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
-
- nsCOMPtr<nsISelectionController> selCon;
- frame->GetSelectionController(presContext, getter_AddRefs(selCon));
- NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
-
- nsCOMPtr<nsISelection> domSel;
- selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel));
-
- nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(domSel));
+ // Register 'this' as selection listener for the normal selection.
+ nsCOMPtr<nsISelection> normalSel;
+ controller->GetSelection(nsISelectionController::SELECTION_NORMAL,
+ getter_AddRefs(normalSel));
+ nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(normalSel));
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
- mCurrentControlSelection = do_GetWeakReference(domSel);
+ nsresult rv = selPrivate->AddSelectionListener(this);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Register 'this' as selection listener for the spellcheck selection.
+ nsCOMPtr<nsISelection> spellcheckSel;
+ controller->GetSelection(nsISelectionController::SELECTION_SPELLCHECK,
+ getter_AddRefs(spellcheckSel));
+ selPrivate = do_QueryInterface(spellcheckSel);
+ NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
+
return selPrivate->AddSelectionListener(this);
}
nsresult
nsCaretAccessible::AddDocSelectionListener(nsIPresShell *aShell)
{
NS_ENSURE_TRUE(mRootAccessible, NS_ERROR_FAILURE);
nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(aShell);
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
nsCOMPtr<nsISelection> domSel;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel));
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(domSel);
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
+ nsresult rv = selPrivate->AddSelectionListener(this);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsISelection> spellcheckSel;
+ selCon->GetSelection(nsISelectionController::SELECTION_SPELLCHECK,
+ getter_AddRefs(spellcheckSel));
+ selPrivate = do_QueryInterface(spellcheckSel);
+ NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
+
return selPrivate->AddSelectionListener(this);
}
nsresult
nsCaretAccessible::RemoveDocSelectionListener(nsIPresShell *aShell)
{
nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(aShell);
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
nsCOMPtr<nsISelection> domSel;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel));
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(domSel);
NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
+ selPrivate->RemoveSelectionListener(this);
+
+ nsCOMPtr<nsISelection> spellcheckSel;
+ selCon->GetSelection(nsISelectionController::SELECTION_SPELLCHECK,
+ getter_AddRefs(spellcheckSel));
+ selPrivate = do_QueryInterface(spellcheckSel);
+ NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
+
return selPrivate->RemoveSelectionListener(this);
}
-NS_IMETHODIMP nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc, nsISelection *aSel, PRInt16 aReason)
+NS_IMETHODIMP
+nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc,
+ nsISelection *aSel,
+ PRInt16 aReason)
+{
+ nsCOMPtr<nsISelection2> sel2(do_QueryInterface(aSel));
+
+ PRInt16 type = 0;
+ sel2->GetType(&type);
+
+ if (type == nsISelectionController::SELECTION_NORMAL)
+ return NormalSelectionChanged(aDoc, aSel);
+
+ if (type == nsISelectionController::SELECTION_SPELLCHECK)
+ return SpellcheckSelectionChanged(aDoc, aSel);
+
+ return NS_OK;
+}
+
+nsresult
+nsCaretAccessible::NormalSelectionChanged(nsIDOMDocument *aDoc,
+ nsISelection *aSel)
{
NS_ENSURE_TRUE(mRootAccessible, NS_ERROR_FAILURE);
mLastUsedSelection = do_GetWeakReference(aSel);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
NS_ENSURE_TRUE(doc, NS_OK);
nsIPresShell *presShell = doc->GetPrimaryShell();
@@ -242,16 +288,48 @@ NS_IMETHODIMP nsCaretAccessible::NotifyS
nsCOMPtr<nsIAccessibleCaretMoveEvent> event =
new nsAccCaretMoveEvent(focusNode);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
return mRootAccessible->FireDelayedAccessibleEvent(event);
}
+nsresult
+nsCaretAccessible::SpellcheckSelectionChanged(nsIDOMDocument *aDoc,
+ nsISelection *aSel)
+{
+ // XXX: fire an event for accessible of focus node of the selection. If
+ // spellchecking is enabled then we will fire the number of events for
+ // the same accessible for newly appended range of the selection (for every
+ // misspelled word). If spellchecking is disabled (for example,
+ // @spellcheck="false" on html:body) then we won't fire any event.
+ nsCOMPtr<nsIDOMNode> targetNode;
+ aSel->GetFocusNode(getter_AddRefs(targetNode));
+ if (!targetNode)
+ return NS_OK;
+
+ nsCOMPtr<nsIAccessibleDocument> docAccessible =
+ nsAccessNode::GetDocAccessibleFor(targetNode);
+ NS_ENSURE_STATE(docAccessible);
+
+ nsCOMPtr<nsIAccessible> containerAccessible;
+ nsresult rv =
+ docAccessible->GetAccessibleInParentChain(targetNode, PR_TRUE,
+ getter_AddRefs(containerAccessible));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIAccessibleEvent> event =
+ new nsAccEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED,
+ containerAccessible, nsnull);
+ NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
+
+ return mRootAccessible->FireAccessibleEvent(event);
+}
+
nsRect
nsCaretAccessible::GetCaretRect(nsIWidget **aOutWidget)
{
nsRect caretRect;
NS_ENSURE_TRUE(aOutWidget, caretRect);
*aOutWidget = nsnull;
NS_ENSURE_TRUE(mRootAccessible, caretRect);
@@ -264,26 +342,26 @@ nsCaretAccessible::GetCaretRect(nsIWidge
nsCOMPtr<nsIDOMNode> lastNodeWithCaret;
lastAccessNode->GetDOMNode(getter_AddRefs(lastNodeWithCaret));
NS_ENSURE_TRUE(lastNodeWithCaret, caretRect);
nsCOMPtr<nsIPresShell> presShell = mRootAccessible->GetPresShellFor(lastNodeWithCaret);
NS_ENSURE_TRUE(presShell, caretRect);
- nsCOMPtr<nsICaret> caret;
+ nsRefPtr<nsCaret> caret;
presShell->GetCaret(getter_AddRefs(caret));
NS_ENSURE_TRUE(caret, caretRect);
PRBool isCollapsed;
nsIView *view;
nsCOMPtr<nsISelection> caretSelection(do_QueryReferent(mLastUsedSelection));
NS_ENSURE_TRUE(caretSelection, caretRect);
- caret->GetCaretCoordinates(nsICaret::eRenderingViewCoordinates, caretSelection,
+ caret->GetCaretCoordinates(nsCaret::eRenderingViewCoordinates, caretSelection,
&caretRect, &isCollapsed, &view);
if (!view || caretRect.IsEmpty()) {
return nsRect(); // Return empty rect
}
PRBool isVisible;
caret->GetCaretVisible(&isVisible);
if (!isVisible) {
@@ -312,8 +390,40 @@ nsCaretAccessible::GetCaretRect(nsIWidge
nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE))) {
caretRect.height -= charY - caretRect.y;
caretRect.y = charY;
}
return caretRect;
}
+already_AddRefed<nsISelectionController>
+nsCaretAccessible::GetSelectionControllerForNode(nsIDOMNode *aNode)
+{
+ if (!aNode)
+ return nsnull;
+
+ nsCOMPtr<nsIPresShell> presShell = mRootAccessible->GetPresShellFor(aNode);
+ if (!presShell)
+ return nsnull;
+
+ nsCOMPtr<nsIDocument> doc = presShell->GetDocument();
+ if (!doc)
+ return nsnull;
+
+ // Get selection controller only for form controls, not for the document.
+ nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
+ if (!content)
+ return nsnull;
+
+ nsIFrame *frame = presShell->GetPrimaryFrameFor(content);
+ if (!frame)
+ return nsnull;
+
+ nsPresContext *presContext = presShell->GetPresContext();
+ if (!presContext)
+ return nsnull;
+
+ nsISelectionController *controller = nsnull;
+ frame->GetSelectionController(presContext, &controller);
+ return controller;
+}
+
--- a/accessible/src/base/nsCaretAccessible.h
+++ b/accessible/src/base/nsCaretAccessible.h
@@ -35,23 +35,25 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef __nsCaretAccessible_h__
#define __nsCaretAccessible_h__
#include "nsIWeakReference.h"
#include "nsIAccessibleText.h"
-#include "nsICaret.h"
#include "nsIDOMNode.h"
#include "nsISelectionListener.h"
+#include "nsISelectionController.h"
#include "nsRect.h"
class nsRootAccessible;
class nsIView;
+class nsIPresShell;
+class nsIWidget;
/*
* This special accessibility class is for the caret, which is really the currently focused selection.
* There is only 1 visible caret per top level window (nsRootAccessible),
* However, there may be several visible selections.
*
* The important selections are the one owned by each document, and the one in the currently focused control.
*
@@ -114,27 +116,33 @@ public:
* instead of document because it is more direct than getting it from
* the document, and in any case it is unavailable from the doc after a pagehide.
* @param aShell PresShell for document to no longer listen to selection events from.
*/
nsresult RemoveDocSelectionListener(nsIPresShell *aShell);
nsRect GetCaretRect(nsIWidget **aOutWidget);
+protected:
+ nsresult NormalSelectionChanged(nsIDOMDocument *aDoc, nsISelection *aSel);
+ nsresult SpellcheckSelectionChanged(nsIDOMDocument *aDoc, nsISelection *aSel);
+
+ already_AddRefed<nsISelectionController>
+ GetSelectionControllerForNode(nsIDOMNode *aNode);
+
private:
// The currently focused control -- never a document.
// We listen to selection for one control at a time (the focused one)
// Document selection is handled separately via additional listeners on all active documents
// The current control is set via SetControlSelectionListener()
nsCOMPtr<nsIDOMNode> mCurrentControl; // Selection controller for the currently focused control
- nsCOMPtr<nsIWeakReference> mCurrentControlSelection;
- // Info for the the last selection event
- // If it was on a control, then mLastUsedSelection == mCurrentControlSelection
- // Otherwise, it's for a document where the selection changed
+ // Info for the the last selection event.
+ // If it was on a control, then it's control's selection. Otherwise, it's for
+ // a document where the selection changed.
nsCOMPtr<nsIWeakReference> mLastUsedSelection; // Weak ref to nsISelection
nsCOMPtr<nsIAccessibleText> mLastTextAccessible;
PRInt32 mLastCaretOffset;
nsRootAccessible *mRootAccessible;
};
#endif
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -80,17 +80,18 @@
PRUint32 nsDocAccessible::gLastFocusedAccessiblesState = 0;
nsIAtom *nsDocAccessible::gLastFocusedFrameType = nsnull;
//-----------------------------------------------------
// construction
//-----------------------------------------------------
nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell):
nsHyperTextAccessibleWrap(aDOMNode, aShell), mWnd(nsnull),
- mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE), mIsLoadCompleteFired(PR_FALSE)
+ mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE),
+ mIsLoadCompleteFired(PR_FALSE), mInFlushPendingEvents(PR_FALSE)
{
// For GTK+ native window, we do nothing here.
if (!mDOMNode)
return;
// Because of the way document loading happens, the new nsIWidget is created before
// the old one is removed. Since it creates the nsDocAccessible, for a brief moment
// there can be 2 nsDocAccessible's for the content area, although for 2 different
@@ -252,16 +253,19 @@ nsDocAccessible::GetState(PRUint32 *aSta
nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
if (!xulDoc)
#endif
{
// XXX Need to invent better check to see if doc is focusable,
// which it should be if it is scrollable. A XUL document could be focusable.
// See bug 376803.
*aState |= nsIAccessibleStates::STATE_FOCUSABLE;
+ if (gLastFocusedNode == mDOMNode) {
+ *aState |= nsIAccessibleStates::STATE_FOCUSED;
+ }
}
if (!mIsContentLoaded) {
*aState |= nsIAccessibleStates::STATE_BUSY;
if (aExtraState) {
*aExtraState |= nsIAccessibleStates::EXT_STATE_STALE;
}
}
@@ -508,18 +512,30 @@ NS_IMETHODIMP nsDocAccessible::GetCached
if (privateParent) {
privateParent->TestChildCache(accessible);
}
}
#endif
return NS_OK;
}
-NS_IMETHODIMP nsDocAccessible::CacheAccessNode(void *aUniqueID, nsIAccessNode *aAccessNode)
+NS_IMETHODIMP
+nsDocAccessible::CacheAccessNode(void *aUniqueID, nsIAccessNode *aAccessNode)
{
+ // If there is an access node for the given unique ID then let's shutdown it.
+ // The unique ID may be presented in the cache if originally we created
+ // access node object and then we want to create accessible object when
+ // DOM node is changed.
+ nsCOMPtr<nsIAccessNode> accessNode;
+ GetCacheEntry(mAccessNodeCache, aUniqueID, getter_AddRefs(accessNode));
+ if (accessNode) {
+ nsCOMPtr<nsPIAccessNode> prAccessNode = do_QueryInterface(accessNode);
+ prAccessNode->Shutdown();
+ }
+
PutCacheEntry(mAccessNodeCache, aUniqueID, aAccessNode);
return NS_OK;
}
NS_IMETHODIMP nsDocAccessible::GetParent(nsIAccessible **aParent)
{
// Hook up our new accessible with our parent
*aParent = nsnull;
@@ -581,17 +597,20 @@ NS_IMETHODIMP nsDocAccessible::Shutdown(
if (mFireEventTimer) {
// Doc being shut down before events fired,
mFireEventTimer->Cancel();
mFireEventTimer = nsnull;
if (mEventsToFire.Count() > 0 ) {
mEventsToFire.Clear();
// Make sure we release the kung fu death grip which is always
// there when there are still events left to be fired
- NS_RELEASE_THIS();
+ // If FlushPendingEvents() is in call stack,
+ // kung fu death grip will be released there.
+ if (!mInFlushPendingEvents)
+ NS_RELEASE_THIS();
}
}
// Remove from the cache after other parts of Shutdown(), so that Shutdown() procedures
// can find the doc or root accessible in the cache if they need it.
// We don't do this during ShutdownAccessibility() because that is already clearing the cache
if (!gIsShuttingDownApp)
gGlobalDocAccessibleCache.Remove(static_cast<void*>(kungFuDeathGripDoc));
@@ -849,18 +868,28 @@ NS_IMETHODIMP nsDocAccessible::FireDocLo
nsCOMPtr<nsIAccessibleStateChangeEvent> accEvent =
new nsAccStateChangeEvent(this, nsIAccessibleStates::STATE_BUSY, PR_FALSE, PR_FALSE);
FireAccessibleEvent(accEvent);
FireAnchorJumpEvent();
}
}
}
}
+
if (sameTypeRoot == treeItem) {
// Not a frame or iframe
+ if (!isFinished) {
+ // Fire state change event to set STATE_BUSY when document is loading. For
+ // example, Window-Eyes expects to get it.
+ nsCOMPtr<nsIAccessibleStateChangeEvent> accEvent =
+ new nsAccStateChangeEvent(this, nsIAccessibleStates::STATE_BUSY,
+ PR_FALSE, PR_TRUE);
+ FireAccessibleEvent(accEvent);
+ }
+
nsAccUtils::FireAccEvent(aEventType, this);
}
return NS_OK;
}
void nsDocAccessible::ScrollTimerCallback(nsITimer *aTimer, void *aClosure)
{
nsDocAccessible *docAcc = reinterpret_cast<nsDocAccessible*>(aClosure);
@@ -1487,16 +1516,17 @@ nsDocAccessible::FireDelayedAccessibleEv
0, nsITimer::TYPE_ONE_SHOT);
}
return NS_OK;
}
NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
{
+ mInFlushPendingEvents = PR_TRUE;
PRUint32 length = mEventsToFire.Count();
NS_ASSERTION(length, "How did we get here without events to fire?");
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
if (!presShell)
length = 0; // The doc is now shut down, don't fire events in it anymore
else
nsAccEvent::ApplyEventRules(mEventsToFire);
@@ -1510,18 +1540,18 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
nsCOMPtr<nsIAccessible> accessible;
accessibleEvent->GetAccessible(getter_AddRefs(accessible));
nsCOMPtr<nsIDOMNode> domNode;
accessibleEvent->GetDOMNode(getter_AddRefs(domNode));
PRUint32 eventType = nsAccEvent::EventType(accessibleEvent);
PRBool isFromUserInput = nsAccEvent::IsFromUserInput(accessibleEvent);
if (domNode == gLastFocusedNode &&
- eventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
- eventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW) {
+ (eventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
+ eventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW)) {
// If frame type didn't change for this event, then we don't actually need to invalidate
// However, we only keep track of the old frame type for the focus, where it's very
// important not to destroy and recreate the accessible for minor style changes,
// such as a:focus { overflow: scroll; }
nsCOMPtr<nsIContent> focusContent(do_QueryInterface(domNode));
if (focusContent) {
nsIFrame *focusFrame = presShell->GetRealPrimaryFrameFor(focusContent);
nsIAtom *newFrameType =
@@ -1607,17 +1637,18 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
// Test caret line # -- fire an EVENT_ALERT on the focused node so we can watch the
// line-number object attribute on it
nsCOMPtr<nsIAccessible> accForFocus;
GetAccService()->GetAccessibleFor(gLastFocusedNode, getter_AddRefs(accForFocus));
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_ALERT, accForFocus);
#endif
nsCOMPtr<nsIAccessibleCaretMoveEvent> caretMoveEvent =
new nsAccCaretMoveEvent(accessible, caretOffset);
- NS_ENSURE_TRUE(caretMoveEvent, NS_ERROR_OUT_OF_MEMORY);
+ if (!caretMoveEvent)
+ break; // Out of memory, break out to release kung fu death grip
FireAccessibleEvent(caretMoveEvent);
PRInt32 selectionCount;
accessibleText->GetSelectionCount(&selectionCount);
if (selectionCount) { // There's a selection so fire selection change as well
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
accessible, PR_TRUE);
@@ -1643,16 +1674,17 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
}
}
mEventsToFire.Clear(); // Clear out array
NS_RELEASE_THIS(); // Release kung fu death grip
// After a flood of events, reset so that user input flag is off
nsAccEvent::ResetLastInputState();
+ mInFlushPendingEvents = PR_FALSE;
return NS_OK;
}
void nsDocAccessible::FlushEventsCallback(nsITimer *aTimer, void *aClosure)
{
nsPIAccessibleDocument *accessibleDoc = static_cast<nsPIAccessibleDocument*>(aClosure);
NS_ASSERTION(accessibleDoc, "How did we get here without an accessible document?");
if (accessibleDoc) {
@@ -1723,19 +1755,18 @@ void nsDocAccessible::RefreshNodes(nsIDO
children->GetLength(&childCount);
nsCOMPtr<nsIDOMNode> possibleAnonNode;
for (PRUint32 index = 0; index < childCount; index++) {
nsCOMPtr<nsIAccessNode> childAccessNode;
children->QueryElementAt(index, NS_GET_IID(nsIAccessNode),
getter_AddRefs(childAccessNode));
childAccessNode->GetDOMNode(getter_AddRefs(possibleAnonNode));
nsCOMPtr<nsIContent> iterContent = do_QueryInterface(possibleAnonNode);
- if (iterContent && (iterContent->IsNativeAnonymous() ||
- iterContent->GetBindingParent())) {
- // GetBindingParent() check is a perf win -- make sure we don't
+ if (iterContent && iterContent->IsInAnonymousSubtree()) {
+ // IsInAnonymousSubtree() check is a perf win -- make sure we don't
// shut down the same subtree twice since we'll reach non-anon content via
// DOM traversal later in this method
RefreshNodes(possibleAnonNode);
}
}
}
}
@@ -1965,27 +1996,24 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
break;
}
roleMapEntry = nsAccUtils::GetRoleMapEntry(ancestorNode);
}
}
FireValueChangeForTextFields(containerAccessible);
- if (!isShowing) {
- // Fire an event so the assistive technology knows the children have changed
- // This is only used by older MSAA clients. Newer ones should derive this
- // from SHOW and HIDE so that they don't fetch extra objects
- if (childAccessible) {
- nsCOMPtr<nsIAccessibleEvent> reorderEvent =
- new nsAccEvent(nsIAccessibleEvent::EVENT_REORDER, containerAccessible,
- isAsynch, nsAccEvent::eCoalesceFromSameSubtree);
- NS_ENSURE_TRUE(reorderEvent, NS_ERROR_OUT_OF_MEMORY);
- FireDelayedAccessibleEvent(reorderEvent);
- }
+ if (childAccessible) {
+ // Fire an event so the MSAA clients know the children have changed. Also
+ // the event is used internally by MSAA part.
+ nsCOMPtr<nsIAccessibleEvent> reorderEvent =
+ new nsAccEvent(nsIAccessibleEvent::EVENT_REORDER, containerAccessible,
+ isAsynch, nsAccEvent::eCoalesceFromSameSubtree);
+ NS_ENSURE_TRUE(reorderEvent, NS_ERROR_OUT_OF_MEMORY);
+ FireDelayedAccessibleEvent(reorderEvent);
}
return NS_OK;
}
NS_IMETHODIMP
nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode,
PRBool aCanCreate,
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -216,13 +216,14 @@ class nsDocAccessible : public nsHyperTe
PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
PRPackedBool mIsContentLoaded;
PRPackedBool mIsLoadCompleteFired;
nsCOMArray<nsIAccessibleEvent> mEventsToFire;
protected:
PRBool mIsAnchor;
PRBool mIsAnchorJumped;
+ PRBool mInFlushPendingEvents;
static PRUint32 gLastFocusedAccessiblesState;
static nsIAtom *gLastFocusedFrameType;
};
#endif
--- a/accessible/src/base/nsOuterDocAccessible.cpp
+++ b/accessible/src/base/nsOuterDocAccessible.cpp
@@ -143,8 +143,40 @@ nsOuterDocAccessible::GetAttributesInter
aAttributes->GetStringProperty(NS_LITERAL_CSTRING("tag"), tag);
if (!tag.IsEmpty()) {
// We're overriding the ARIA attributes on an sub document, but we don't want to
// override the other attributes
return NS_OK;
}
return nsAccessible::GetAttributesInternal(aAttributes);
}
+
+// Internal frame, which is the doc's parent, should not have a click action
+NS_IMETHODIMP
+nsOuterDocAccessible::GetNumActions(PRUint8 *aNumActions)
+{
+ NS_ENSURE_ARG_POINTER(aNumActions);
+ *aNumActions = 0;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsOuterDocAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
+{
+ aName.Truncate();
+
+ return NS_ERROR_INVALID_ARG;
+}
+
+NS_IMETHODIMP
+nsOuterDocAccessible::GetActionDescription(PRUint8 aIndex, nsAString& aDescription)
+{
+ aDescription.Truncate();
+
+ return NS_ERROR_INVALID_ARG;
+}
+
+NS_IMETHODIMP
+nsOuterDocAccessible::DoAction(PRUint8 aIndex)
+{
+ return NS_ERROR_INVALID_ARG;
+}
--- a/accessible/src/base/nsOuterDocAccessible.h
+++ b/accessible/src/base/nsOuterDocAccessible.h
@@ -53,11 +53,15 @@ class nsOuterDocAccessible : public nsAc
nsIWeakReference* aShell);
NS_IMETHOD GetRole(PRUint32 *aRole);
NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible);
void CacheChildren();
nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
+ NS_IMETHOD GetNumActions(PRUint8 *aNumActions);
+ NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
+ NS_IMETHODIMP GetActionDescription(PRUint8 aIndex, nsAString& aDescription);
+ NS_IMETHOD DoAction(PRUint8 aIndex);
};
#endif
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -35,17 +35,16 @@
*
* ***** END LICENSE BLOCK ***** */
// NOTE: alphabetically ordered
#include "nsAccessibilityService.h"
#include "nsAccessibleEventData.h"
#include "nsHTMLSelectAccessible.h"
#include "nsIBaseWindow.h"
-#include "nsICaret.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeNode.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMEventTarget.h"
@@ -638,28 +637,16 @@ nsresult nsRootAccessible::HandleEventWi
if (eventType.EqualsLiteral("DOMContentLoaded")) {
// Don't create the doc accessible until load scripts have a chance to set
// role attribute for <body> or <html> element, because the value of
// role attribute will be cached when the doc accessible is Init()'d
TryFireEarlyLoadEvent(aTargetNode);
return NS_OK;
}
-#ifdef MOZ_XUL
- if (eventType.EqualsLiteral("TreeViewChanged")) { // Always asynch, always from user input
- if (!isTree)
- return NS_OK;
-
- nsCOMPtr<nsIContent> treeContent = do_QueryInterface(aTargetNode);
- nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);
- return accService->InvalidateSubtreeFor(eventShell, treeContent,
- nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
- }
-#endif
-
if (eventType.EqualsLiteral("popuphiding")) {
// If accessible focus was on or inside popup that closes,
// then restore it to true current focus.
// This is the case when we've been getting DOMMenuItemActive events
// inside of a combo box that closes. The real focus is on the combo box.
// It's also the case when a popup gets focus in ATK -- when it closes
// we need to fire an event to restore focus to where it was
if (!gLastFocusedNode ||
@@ -673,21 +660,32 @@ nsresult nsRootAccessible::HandleEventWi
nsCOMPtr<nsIAccessible> accessible;
accService->GetAccessibleInShell(aTargetNode, eventShell,
getter_AddRefs(accessible));
nsCOMPtr<nsPIAccessible> privAcc(do_QueryInterface(accessible));
if (!privAcc)
return NS_OK;
#ifdef MOZ_XUL
- if (eventType.EqualsLiteral("TreeRowCountChanged"))
- return HandleTreeRowCountChangedEvent(aEvent, accessible, localName);
-
- if (eventType.EqualsLiteral("TreeInvalidated"))
- return HandleTreeInvalidatedEvent(aEvent, accessible, localName);
+ if (isTree) {
+ nsCOMPtr<nsIAccessibleTreeCache> treeAcc(do_QueryInterface(accessible));
+ NS_ASSERTION(treeAcc,
+ "Accessible for xul:tree doesn't implement nsIAccessibleTreeCache interface.");
+
+ if (treeAcc) {
+ if (eventType.EqualsLiteral("TreeViewChanged"))
+ return treeAcc->TreeViewChanged();
+
+ if (eventType.EqualsLiteral("TreeRowCountChanged"))
+ return HandleTreeRowCountChangedEvent(aEvent, treeAcc);
+
+ if (eventType.EqualsLiteral("TreeInvalidated"))
+ return HandleTreeInvalidatedEvent(aEvent, treeAcc);
+ }
+ }
#endif
if (eventType.EqualsLiteral("RadioStateChange")) {
PRUint32 state = State(accessible);
// radiogroup in prefWindow is exposed as a list,
// and panebutton is exposed as XULListitem in A11y.
// nsXULListitemAccessible::GetState uses STATE_SELECTED in this case,
@@ -1090,22 +1088,18 @@ NS_IMETHODIMP nsRootAccessible::FireDocL
mIsContentLoaded = (aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE ||
aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED);
return NS_OK;
}
nsresult
nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
- nsIAccessible *aAccessible,
- const nsAString& aTargetName)
+ nsIAccessibleTreeCache *aAccessible)
{
- if (!aTargetName.EqualsLiteral("tree"))
- return NS_OK;
-
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
if (!dataEvent)
return NS_OK;
nsCOMPtr<nsIVariant> indexVariant;
dataEvent->GetData(NS_LITERAL_STRING("index"),
getter_AddRefs(indexVariant));
if (!indexVariant)
@@ -1116,30 +1110,23 @@ nsRootAccessible::HandleTreeRowCountChan
getter_AddRefs(countVariant));
if (!countVariant)
return NS_OK;
PRInt32 index, count;
indexVariant->GetAsInt32(&index);
countVariant->GetAsInt32(&count);
- nsCOMPtr<nsIAccessibleTreeCache> treeAccCache(do_QueryInterface(aAccessible));
- NS_ENSURE_STATE(treeAccCache);
-
- return treeAccCache->InvalidateCache(index, count);
+ return aAccessible->InvalidateCache(index, count);
}
nsresult
nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
- nsIAccessible *aAccessible,
- const nsAString& aTargetName)
+ nsIAccessibleTreeCache *aAccessible)
{
- if (!aTargetName.EqualsLiteral("tree"))
- return NS_OK;
-
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
if (!dataEvent)
return NS_OK;
PRInt32 startRow = 0, endRow = -1, startCol = 0, endCol = -1;
nsCOMPtr<nsIVariant> startRowVariant;
dataEvent->GetData(NS_LITERAL_STRING("startrow"),
@@ -1160,14 +1147,11 @@ nsRootAccessible::HandleTreeInvalidatedE
startColVariant->GetAsInt32(&startCol);
nsCOMPtr<nsIVariant> endColVariant;
dataEvent->GetData(NS_LITERAL_STRING("endcolumn"),
getter_AddRefs(endColVariant));
if (endColVariant)
endColVariant->GetAsInt32(&endCol);
- nsCOMPtr<nsIAccessibleTreeCache> treeAcc(do_QueryInterface(aAccessible));
- NS_ENSURE_STATE(treeAcc);
-
- return treeAcc->TreeViewInvalidated(startRow, endRow, startCol, endCol);
+ return aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
}
--- a/accessible/src/base/nsRootAccessible.h
+++ b/accessible/src/base/nsRootAccessible.h
@@ -33,19 +33,23 @@
* 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 ***** */
#ifndef _nsRootAccessible_H_
#define _nsRootAccessible_H_
+#include "nsCaretAccessible.h"
#include "nsDocAccessibleWrap.h"
+
+#include "nsIAccessibleDocument.h"
+#include "nsIAccessibleTreeCache.h"
+
#include "nsHashtable.h"
-#include "nsIAccessibleDocument.h"
#include "nsCaretAccessible.h"
#include "nsIDocument.h"
#include "nsIDOMFocusListener.h"
#include "nsIDOMFormListener.h"
#include "nsIDOMXULListener.h"
#include "nsITimer.h"
#define NS_ROOTACCESSIBLE_IMPL_CID \
@@ -98,46 +102,48 @@ class nsRootAccessible : public nsDocAcc
* @param aForceEvent Fire a focus event even if the last focused item was the same
* @return Boolean -- was a focus event actually fired
*/
PRBool FireAccessibleFocusEvent(nsIAccessible *aFocusAccessible,
nsIDOMNode *aFocusNode,
nsIDOMEvent *aFocusEvent,
PRBool aForceEvent = PR_FALSE,
PRBool aIsAsynch = PR_FALSE);
+ /**
+ * Fire an accessible focus event for the current focused node,
+ * if there is a focus.
+ */
+ void FireCurrentFocusEvent();
nsCaretAccessible *GetCaretAccessible();
private:
nsCOMPtr<nsITimer> mFireFocusTimer;
static void FireFocusCallback(nsITimer *aTimer, void *aClosure);
protected:
nsresult AddEventListeners();
nsresult RemoveEventListeners();
nsresult HandleEventWithTarget(nsIDOMEvent* aEvent,
nsIDOMNode* aTargetNode);
static void GetTargetNode(nsIDOMEvent *aEvent, nsIDOMNode **aTargetNode);
void TryFireEarlyLoadEvent(nsIDOMNode *aDocNode);
- void FireCurrentFocusEvent();
void GetChromeEventHandler(nsIDOMEventTarget **aChromeTarget);
/**
* Handles 'TreeRowCountChanged' event. Used in HandleEventWithTarget().
*/
nsresult HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
- nsIAccessible *aAccessible,
- const nsAString& aTargetName);
+ nsIAccessibleTreeCache *aAccessible);
/**
* Handles 'TreeInvalidated' event. Used in HandleEventWithTarget().
*/
nsresult HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
- nsIAccessible *aAccessible,
- const nsAString& aTargetName);
+ nsIAccessibleTreeCache *aAccessible);
#ifdef MOZ_XUL
PRUint32 GetChromeFlags();
#endif
already_AddRefed<nsIDocShellTreeItem>
GetContentDocShell(nsIDocShellTreeItem *aStart);
nsRefPtr<nsCaretAccessible> mCaretAccessible;
nsCOMPtr<nsIDOMNode> mCurrentARIAMenubar;
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsTextUtils.cpp
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Alexander Surkov <surkov.alexander@gmail.com> (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 ***** */
+
+#include "nsTextUtils.h"
+
+#include "nsAccessNode.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// nsLangTextAttr
+
+PRBool
+nsLangTextAttr::equal(nsIDOMElement *aElm)
+{
+ nsCOMPtr<nsIContent> content(do_QueryInterface(aElm));
+ if (!content)
+ return PR_FALSE;
+
+ nsAutoString lang;
+ nsAccUtils::GetLanguageFor(content, mRootContent, lang);
+
+ return lang == mLang;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsCSSTextAttr
+
+/**
+ * Item of the gCSSTextAttrsMap map.
+ */
+struct nsCSSTextAttrMapItem
+{
+ const char* mCSSName;
+ const char* mCSSValue;
+ const char* mAttrName;
+ const char* mAttrValue;
+};
+
+/**
+ * The map of CSS properties to text attributes.
+ */
+
+const char* const kAnyValue = nsnull;
+const char* const kCopyName = nsnull;
+const char* const kCopyValue = nsnull;
+
+static nsCSSTextAttrMapItem gCSSTextAttrsMap[] = {
+ // CSS name CSS value Attribute name Attribute name
+ { "background-color", kAnyValue, kCopyName, kCopyValue },
+ { "color", kAnyValue, kCopyName, kCopyValue },
+ { "font-family", kAnyValue, kCopyName, kCopyValue },
+ { "font-size", kAnyValue, kCopyName, kCopyValue },
+ { "font-style", kAnyValue, kCopyName, kCopyValue },
+ { "font-weight", kAnyValue, kCopyName, kCopyValue },
+ { "text-decoration", "line-through", "text-line-through-style", "solid" },
+ { "text-decoration", "underline", "text-underline-style", "solid" },
+ { "text-align", kAnyValue, kCopyName, kCopyValue },
+ { "text-indent", kAnyValue, kCopyName, kCopyValue },
+ { "vertical-align", kAnyValue, "text-position", kCopyValue }
+};
+
+nsCSSTextAttr::nsCSSTextAttr(PRBool aIncludeDefAttrValue, nsIDOMElement *aElm,
+ nsIDOMElement *aRootElm) :
+ mIndex(-1), mIncludeDefAttrValue(aIncludeDefAttrValue)
+{
+ nsAccessNode::GetComputedStyleDeclaration(EmptyString(), aElm,
+ getter_AddRefs(mStyleDecl));
+
+ if (!mIncludeDefAttrValue)
+ nsAccessNode::GetComputedStyleDeclaration(EmptyString(), aRootElm,
+ getter_AddRefs(mDefStyleDecl));
+}
+
+PRBool
+nsCSSTextAttr::equal(nsIDOMElement *aElm)
+{
+ if (!aElm || !mStyleDecl)
+ return PR_FALSE;
+
+ nsCOMPtr<nsIDOMCSSStyleDeclaration> currStyleDecl;
+ nsAccessNode::GetComputedStyleDeclaration(EmptyString(), aElm,
+ getter_AddRefs(currStyleDecl));
+ if (!currStyleDecl)
+ return PR_FALSE;
+
+ NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
+
+ nsAutoString currValue;
+ nsresult rv = currStyleDecl->GetPropertyValue(cssName, currValue);
+ if (NS_FAILED(rv))
+ return PR_FALSE;
+
+ nsAutoString value;
+ rv = mStyleDecl->GetPropertyValue(cssName, value);
+ return NS_SUCCEEDED(rv) && value == currValue;
+}
+
+PRBool
+nsCSSTextAttr::iterate()
+{
+ return ++mIndex < static_cast<PRInt32>(NS_ARRAY_LENGTH(gCSSTextAttrsMap));
+}
+
+PRBool
+nsCSSTextAttr::get(nsACString& aName, nsAString& aValue)
+{
+ if (!mStyleDecl)
+ return PR_FALSE;
+
+ NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
+ nsresult rv = mStyleDecl->GetPropertyValue(cssName, aValue);
+ if (NS_FAILED(rv))
+ return PR_FALSE;
+
+ // Don't expose text attribute if corresponding CSS value on the element
+ // equals to CSS value on the root element and we don't want to include
+ // default values.
+ if (!mIncludeDefAttrValue) {
+ if (!mDefStyleDecl)
+ return PR_FALSE;
+
+ nsAutoString defValue;
+ mDefStyleDecl->GetPropertyValue(cssName, defValue);
+ if (defValue == aValue)
+ return PR_FALSE;
+ }
+
+ // Don't expose text attribute if its required specific CSS value isn't
+ // matched with the CSS value we got.
+ const char *cssValue = gCSSTextAttrsMap[mIndex].mCSSValue;
+ if (cssValue != kAnyValue && !aValue.EqualsASCII(cssValue))
+ return PR_FALSE;
+
+ // Get the name of text attribute.
+ if (gCSSTextAttrsMap[mIndex].mAttrName != kCopyName)
+ aName = gCSSTextAttrsMap[mIndex].mAttrName;
+ else
+ aName = gCSSTextAttrsMap[mIndex].mCSSName;
+
+ // Get the value of text attribute.
+ const char *attrValue = gCSSTextAttrsMap[mIndex].mAttrValue;
+ if (attrValue != kCopyValue)
+ AppendASCIItoUTF16(attrValue, aValue);
+
+ return PR_TRUE;
+}
+
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsTextUtils.h
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Alexander Surkov <surkov.alexander@gmail.com> (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 ***** */
+
+#ifndef nsTextUtils_h_
+#define nsTextUtils_h_
+
+#include "nsIDOMElement.h"
+#include "nsIDOMCSSStyleDeclaration.h"
+
+#include "nsIContent.h"
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+/**
+ * Base class to work with text attributes. See derived classes below.
+ */
+class nsTextAttr
+{
+public:
+ /**
+ * Return true if the text attribute for the given element equals with
+ * predefined attribute.
+ */
+ virtual PRBool equal(nsIDOMElement *aElm) = 0;
+};
+
+/**
+ * Class is used for the work with 'lang' text attributes. Used in
+ * nsHyperTextAccessible.
+ */
+class nsLangTextAttr : public nsTextAttr
+{
+public:
+ nsLangTextAttr(nsAString& aLang, nsIContent *aRootContent) :
+ mLang(aLang), mRootContent(aRootContent) { }
+
+ virtual PRBool equal(nsIDOMElement *aElm);
+
+private:
+ nsString mLang;
+ nsCOMPtr<nsIContent> mRootContent;
+};
+
+/**
+ * Class is used for the work with CSS based text attributes. Used in
+ * nsHyperTextAccessible.
+ */
+class nsCSSTextAttr : public nsTextAttr
+{
+public:
+ nsCSSTextAttr(PRBool aIncludeDefAttrValue, nsIDOMElement *aElm,
+ nsIDOMElement *aRootElm);
+
+ // nsTextAttr
+ virtual PRBool equal(nsIDOMElement *aElm);
+
+ // nsCSSTextAttr
+ /**
+ * Interates through attributes.
+ */
+ PRBool iterate();
+
+ /**
+ * Get name and value of attribute.
+ */
+ PRBool get(nsACString& aName, nsAString& aValue);
+
+private:
+ PRInt32 mIndex;
+ PRBool mIncludeDefAttrValue;
+
+ nsCOMPtr<nsIDOMCSSStyleDeclaration> mStyleDecl;
+ nsCOMPtr<nsIDOMCSSStyleDeclaration> mDefStyleDecl;
+};
+
+#endif
--- a/accessible/src/html/nsHTMLFormControlAccessible.cpp
+++ b/accessible/src/html/nsHTMLFormControlAccessible.cpp
@@ -278,25 +278,28 @@ NS_IMETHODIMP nsHTMLButtonAccessible::Ge
NS_IMETHODIMP nsHTMLButtonAccessible::GetName(nsAString& aName)
{
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (!content) {
return NS_ERROR_FAILURE; // Node shut down
}
nsAutoString name;
- if (!content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value,
- name) &&
- !content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::alt,
- name)) {
- if (mRoleMapEntry) {
- // Use HTML label or DHTML accessibility's labelledby attribute for name
- GetHTMLName(name, PR_FALSE);
- }
- if (name.IsEmpty()) {
+ // Prefer aria-labelledby attribute for name
+ if (content->HasAttr(kNameSpaceID_None,
+ nsAccessibilityAtoms::aria_labelledby)) {
+ GetHTMLName(name, PR_FALSE);
+ }
+
+ if (name.IsEmpty()) {
+ // no label from HTML or ARIA
+ if (!content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value,
+ name) &&
+ !content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::alt,
+ name)) {
// Use the button's (default) label if nothing else works
nsIFrame* frame = GetFrame();
if (frame) {
nsIFormControlFrame* fcFrame;
CallQueryInterface(frame, &fcFrame);
if (fcFrame)
fcFrame->GetFormProperty(nsAccessibilityAtoms::defaultLabel, name);
}
@@ -458,28 +461,31 @@ nsHTMLTextFieldAccessible::GetState(PRUi
*aState |= nsIAccessibleStates::STATE_HASPOPUP;
}
}
if (content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::readonly)) {
*aState |= nsIAccessibleStates::STATE_READONLY;
}
- if (!aExtraState || !(*aExtraState & nsIAccessibleStates::EXT_STATE_EDITABLE))
+ if (!aExtraState)
return NS_OK;
nsCOMPtr<nsIDOMHTMLInputElement> htmlInput(do_QueryInterface(mDOMNode));
// Is it an <input> or a <textarea> ?
if (htmlInput) {
*aExtraState |= nsIAccessibleStates::EXT_STATE_SINGLE_LINE;
}
else {
*aExtraState |= nsIAccessibleStates::EXT_STATE_MULTI_LINE;
}
+ if (!(*aExtraState & nsIAccessibleStates::EXT_STATE_EDITABLE))
+ return NS_OK;
+
nsCOMPtr<nsIContent> bindingContent = content->GetBindingParent();
if (bindingContent &&
bindingContent->NodeInfo()->Equals(nsAccessibilityAtoms::textbox,
kNameSpaceID_XUL) &&
bindingContent->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::type,
nsAccessibilityAtoms::autocomplete,
eIgnoreCase)) {
// If parent is XUL textbox and value of @type attribute is "autocomplete",
--- a/accessible/src/html/nsHTMLLinkAccessible.cpp
+++ b/accessible/src/html/nsHTMLLinkAccessible.cpp
@@ -61,17 +61,26 @@ NS_IMETHODIMP
nsHTMLLinkAccessible::GetName(nsAString& aName)
{
aName.Truncate();
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
- return AppendFlatStringFromSubtree(content, &aName);
+ nsresult rv = AppendFlatStringFromSubtree(content, &aName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (aName.IsEmpty()) {
+ // Probably an image without alt or title inside, try to get the name on
+ // the link by usual way.
+ return GetHTMLName(aName, PR_FALSE);
+ }
+
+ return NS_OK;
}
NS_IMETHODIMP
nsHTMLLinkAccessible::GetRole(PRUint32 *aRole)
{
NS_ENSURE_ARG_POINTER(aRole);
*aRole = nsIAccessibleRole::ROLE_LINK;
@@ -97,19 +106,24 @@ nsHTMLLinkAccessible::GetState(PRUint32
*aState |= nsIAccessibleStates::STATE_SELECTABLE;
}
nsCOMPtr<nsILink> link = do_QueryInterface(mDOMNode);
NS_ENSURE_STATE(link);
nsLinkState linkState;
link->GetLinkState(linkState);
- if (linkState == eLinkState_NotLink) {
- // This is a named anchor, not a link with also a name attribute. bail out.
- return NS_OK;
+ if (linkState == eLinkState_NotLink || linkState == eLinkState_Unknown) {
+ // This is a either named anchor (a link with also a name attribute) or
+ // it doesn't have any attributes. Check if 'click' event handler is
+ // registered, otherwise bail out.
+ PRBool isOnclick = nsAccUtils::HasListener(content,
+ NS_LITERAL_STRING("click"));
+ if (!isOnclick)
+ return NS_OK;
}
*aState |= nsIAccessibleStates::STATE_LINKED;
if (linkState == eLinkState_Visited)
*aState |= nsIAccessibleStates::STATE_TRAVERSED;
return NS_OK;
@@ -133,35 +147,45 @@ nsHTMLLinkAccessible::GetValue(nsAString
return NS_OK;
}
NS_IMETHODIMP
nsHTMLLinkAccessible::GetNumActions(PRUint8 *aNumActions)
{
NS_ENSURE_ARG_POINTER(aNumActions);
+ if (!IsLinked())
+ return nsHyperTextAccessible::GetNumActions(aNumActions);
+
*aNumActions = 1;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLLinkAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
{
+ aName.Truncate();
+
+ if (!IsLinked())
+ return nsHyperTextAccessible::GetActionName(aIndex, aName);
+
// Action 0 (default action): Jump to link
- aName.Truncate();
if (aIndex != eAction_Jump)
return NS_ERROR_INVALID_ARG;
aName.AssignLiteral("jump");
return NS_OK;
}
NS_IMETHODIMP
nsHTMLLinkAccessible::DoAction(PRUint8 aIndex)
{
+ if (!IsLinked())
+ return nsHyperTextAccessible::DoAction(aIndex);
+
// Action 0 (default action): Jump to link
if (aIndex != eAction_Jump)
return NS_ERROR_INVALID_ARG;
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
@@ -180,8 +204,25 @@ nsHTMLLinkAccessible::GetURI(PRInt32 aIn
if (aIndex != 0)
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsILink> link(do_QueryInterface(mDOMNode));
NS_ENSURE_STATE(link);
return link->GetHrefURI(aURI);
}
+
+////////////////////////////////////////////////////////////////////////////////
+// Protected members
+
+PRBool
+nsHTMLLinkAccessible::IsLinked()
+{
+ nsCOMPtr<nsILink> link(do_QueryInterface(mDOMNode));
+ if (!link)
+ return PR_FALSE;
+
+ nsLinkState linkState;
+ nsresult rv = link->GetLinkState(linkState);
+
+ return NS_SUCCEEDED(rv) && linkState != eLinkState_NotLink &&
+ linkState != eLinkState_Unknown;
+}
--- a/accessible/src/html/nsHTMLLinkAccessible.h
+++ b/accessible/src/html/nsHTMLLinkAccessible.h
@@ -59,11 +59,16 @@ public:
NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
NS_IMETHOD DoAction(PRUint8 aIndex);
// nsIAccessibleHyperLink
NS_IMETHOD GetURI(PRInt32 aIndex, nsIURI **aURI);
protected:
enum { eAction_Jump = 0 };
+
+ /**
+ * Returns true if the link has href attribute.
+ */
+ PRBool IsLinked();
};
#endif
--- a/accessible/src/html/nsHTMLSelectAccessible.cpp
+++ b/accessible/src/html/nsHTMLSelectAccessible.cpp
@@ -330,17 +330,17 @@ nsHTMLSelectListAccessible::GetState(PRU
{
nsresult rv = nsHTMLSelectableAccessible::GetState(aState, aExtraState);
NS_ENSURE_SUCCESS(rv, rv);
if (!mDOMNode)
return NS_OK;
nsCOMPtr<nsIDOMHTMLSelectElement> select (do_QueryInterface(mDOMNode));
if (select) {
- if (*aState | nsIAccessibleStates::STATE_FOCUSED) {
+ if (*aState & nsIAccessibleStates::STATE_FOCUSED) {
// Treat first focusable option node as actual focus, in order
// to avoid confusing JAWS, which needs focus on the option
nsCOMPtr<nsIDOMNode> focusedOption;
nsHTMLSelectOptionAccessible::GetFocusedOptionNode(mDOMNode,
getter_AddRefs(focusedOption));
if (focusedOption) { // Clear focused state since it is on option
*aState &= ~nsIAccessibleStates::STATE_FOCUSED;
}
@@ -616,17 +616,17 @@ nsIFrame* nsHTMLSelectOptionAccessible::
* STATE_OFFSCREEN
*/
NS_IMETHODIMP
nsHTMLSelectOptionAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
{
// Upcall to nsAccessible, but skip nsHyperTextAccessible impl
// because we don't want EXT_STATE_EDITABLE or EXT_STATE_SELECTABLE_TEXT
nsresult rv = nsAccessible::GetState(aState, aExtraState);
- NS_ENSURE_TRUE(rv, rv);
+ NS_ENSURE_SUCCESS(rv, rv);
if (!mDOMNode)
return NS_OK;
PRUint32 selectState, selectExtState;
nsCOMPtr<nsIContent> selectContent = GetSelectState(&selectState,
&selectExtState);
if (selectState & nsIAccessibleStates::STATE_INVISIBLE) {
return NS_OK;
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -1166,21 +1166,23 @@ NS_IMETHODIMP nsHTMLTableAccessible::IsP
NS_ENSURE_TRUE(tableFrame , NS_ERROR_FAILURE);
nsSize tableSize = tableFrame->GetSize();
nsCOMPtr<nsIAccessibleDocument> docAccessible = GetDocAccessible();
nsCOMPtr<nsPIAccessNode> docAccessNode(do_QueryInterface(docAccessible));
NS_ENSURE_TRUE(docAccessNode, NS_ERROR_FAILURE);
nsIFrame *docFrame = docAccessNode->GetFrame();
NS_ENSURE_TRUE(docFrame , NS_ERROR_FAILURE);
nsSize docSize = docFrame->GetSize();
- PRInt32 percentageOfDocWidth = (100 * tableSize.width) / docSize.width;
- if (percentageOfDocWidth > 95) {
- // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
- // Probably for layout
- RETURN_LAYOUT_ANSWER(PR_TRUE, "<=4 columns, width hardcoded in pixels and 95% of document width");
+ if (docSize.width > 0) {
+ PRInt32 percentageOfDocWidth = (100 * tableSize.width) / docSize.width;
+ if (percentageOfDocWidth > 95) {
+ // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
+ // Probably for layout
+ RETURN_LAYOUT_ANSWER(PR_TRUE, "<=4 columns, width hardcoded in pixels and 95% of document width");
+ }
}
}
// Two column rules
if (rows * columns <= 10) {
RETURN_LAYOUT_ANSWER(PR_TRUE, "2-4 columns, 10 cells or less, non-bordered");
}
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -36,25 +36,28 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsHyperTextAccessible.h"
#include "nsAccessibilityAtoms.h"
#include "nsAccessibilityService.h"
#include "nsAccessibleTreeWalker.h"
+#include "nsTextUtils.h"
+
#include "nsPIAccessNode.h"
#include "nsIClipboard.h"
#include "nsContentCID.h"
#include "nsIDOMAbstractView.h"
#include "nsIDOMCharacterData.h"
#include "nsIDOMDocument.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMDocumentView.h"
#include "nsIDOMRange.h"
+#include "nsIDOMNSRange.h"
#include "nsIDOMWindowInternal.h"
#include "nsIDOMXULDocument.h"
#include "nsIEditingSession.h"
#include "nsIEditor.h"
#include "nsIFontMetrics.h"
#include "nsIFrame.h"
#include "nsFrameSelection.h"
#include "nsILineIterator.h"
@@ -632,17 +635,19 @@ nsresult nsHyperTextAccessible::DOMPoint
// Get accessible for this findNode, or if that node isn't accessible, use the
// accessible for the next DOM node which has one (based on forward depth first search)
nsCOMPtr<nsIAccessible> descendantAccessible;
if (findNode) {
nsCOMPtr<nsIContent> findContent = do_QueryInterface(findNode);
if (findContent->IsNodeOfType(nsINode::eHTML) &&
findContent->NodeInfo()->Equals(nsAccessibilityAtoms::br)) {
nsIContent *parent = findContent->GetParent();
- if (parent && parent->IsNativeAnonymous() && parent->GetChildCount() == 1) {
+ if (parent &&
+ parent->IsRootOfNativeAnonymousSubtree() &&
+ parent->GetChildCount() == 1) {
// This <br> is the only node in a text control, therefore it is the hacky
// "bogus node" used when there is no text in a control
*aHyperTextOffset = 0;
return NS_OK;
}
}
descendantAccessible = GetFirstAvailableAccessible(findNode);
}
@@ -666,17 +671,17 @@ nsresult nsHyperTextAccessible::DOMPoint
// addTextOffset, to put us after the embedded object char. We'll only treat the offset as
// before the embedded object char if we end at the very beginning of the child.
addTextOffset = addTextOffset > 0;
}
else {
// Start offset, inclusive
// Make sure the offset lands on the embedded object character in order to indicate
// the true inner offset is inside the subtree for that link
- addTextOffset = (TextLength(descendantAccessible) == addTextOffset) ? 1 : 0;
+ addTextOffset = (TextLength(descendantAccessible) == static_cast<PRInt32>(addTextOffset)) ? 1 : 0;
}
descendantAccessible = parentAccessible;
}
// Loop through, adding offsets until we reach childAccessible
// If childAccessible is null we will end up adding up the entire length of
// the hypertext, which is good -- it just means our offset node
// came after the last accessible child's node
@@ -694,16 +699,28 @@ nsresult nsHyperTextAccessible::DOMPoint
NS_ADDREF(*aFinalAccessible = childAccessible);
}
}
return NS_OK;
}
nsresult
+nsHyperTextAccessible::HypertextOffsetToDOMPoint(PRInt32 aHTOffset,
+ nsIDOMNode **aNode,
+ PRInt32 *aOffset)
+{
+ nsCOMPtr<nsIDOMNode> endNode;
+ PRInt32 endOffset;
+
+ return HypertextOffsetsToDOMRange(aHTOffset, aHTOffset, aNode, aOffset,
+ getter_AddRefs(endNode), &endOffset);
+}
+
+nsresult
nsHyperTextAccessible::HypertextOffsetsToDOMRange(PRInt32 aStartHTOffset,
PRInt32 aEndHTOffset,
nsIDOMNode **aStartNode,
PRInt32 *aStartOffset,
nsIDOMNode **aEndNode,
PRInt32 *aEndOffset)
{
NS_ENSURE_ARG_POINTER(aStartNode);
@@ -864,16 +881,19 @@ BOUNDARY_LINE_START From the line
BOUNDARY_LINE_END From the line end before/at/after the offset to the next line start.
*/
nsresult nsHyperTextAccessible::GetTextHelper(EGetTextType aType, nsAccessibleTextBoundary aBoundaryType,
PRInt32 aOffset, PRInt32 *aStartOffset, PRInt32 *aEndOffset,
nsAString &aText)
{
aText.Truncate();
+
+ NS_ENSURE_ARG_POINTER(aStartOffset);
+ NS_ENSURE_ARG_POINTER(aEndOffset);
*aStartOffset = *aEndOffset = 0;
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
if (!presShell) {
return NS_ERROR_FAILURE;
}
if (aOffset == nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT) {
@@ -883,30 +903,80 @@ nsresult nsHyperTextAccessible::GetTextH
GetCaretOffset(&aOffset);
if (aOffset > 0 && (aBoundaryType == BOUNDARY_LINE_START ||
aBoundaryType == BOUNDARY_LINE_END)) {
// It is the same character offset when the caret is visually at the very end of a line
// or the start of a new line. Getting text at the line should provide the line with the visual caret,
// otherwise screen readers will announce the wrong line as the user presses up or down arrow and land
// at the end of a line.
nsCOMPtr<nsISelection> domSel;
- nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel));
+ nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
+ nsnull, getter_AddRefs(domSel));
+ NS_ENSURE_SUCCESS(rv, rv);
+
nsCOMPtr<nsISelectionPrivate> privateSelection(do_QueryInterface(domSel));
nsCOMPtr<nsFrameSelection> frameSelection;
rv = privateSelection->GetFrameSelection(getter_AddRefs(frameSelection));
NS_ENSURE_SUCCESS(rv, rv);
+
if (frameSelection->GetHint() == nsFrameSelection::HINTLEFT) {
-- aOffset; // We are at the start of a line
}
}
}
else if (aOffset < 0) {
return NS_ERROR_FAILURE;
}
+ nsSelectionAmount amount;
+ PRBool needsStart = PR_FALSE;
+ switch (aBoundaryType) {
+ case BOUNDARY_CHAR:
+ amount = eSelectCharacter;
+ if (aType == eGetAt)
+ aType = eGetAfter; // Avoid returning 2 characters
+ break;
+
+ case BOUNDARY_WORD_START:
+ needsStart = PR_TRUE;
+ amount = eSelectWord;
+ break;
+
+ case BOUNDARY_WORD_END:
+ amount = eSelectWord;
+ break;
+
+ case BOUNDARY_LINE_START:
+ // Newlines are considered at the end of a line. Since getting
+ // the BOUNDARY_LINE_START gets the text from the line-start to the next
+ // line-start, the newline is included at the end of the string.
+ needsStart = PR_TRUE;
+ amount = eSelectLine;
+ break;
+
+ case BOUNDARY_LINE_END:
+ // Newlines are considered at the end of a line. Since getting
+ // the BOUNDARY_END_START gets the text from the line-end to the next
+ //line-end, the newline is included at the beginning of the string.
+ amount = eSelectLine;
+ break;
+
+ case BOUNDARY_ATTRIBUTE_RANGE:
+ {
+ nsresult rv = GetTextAttributes(PR_FALSE, aOffset,
+ aStartOffset, aEndOffset, nsnull);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return GetText(*aStartOffset, *aEndOffset, aText);
+ }
+
+ default: // Note, sentence support is deprecated and falls through to here
+ return NS_ERROR_INVALID_ARG;
+ }
+
PRInt32 startOffset = aOffset + (aBoundaryType == BOUNDARY_LINE_END); // Avoid getting the previous line
PRInt32 endOffset = startOffset;
// Convert offsets to frame-relative
nsCOMPtr<nsIAccessible> startAcc;
nsIFrame *startFrame = GetPosAndText(startOffset, endOffset, nsnull, nsnull,
nsnull, getter_AddRefs(startAcc));
@@ -924,70 +994,16 @@ nsresult nsHyperTextAccessible::GetTextH
return aOffset > textLength ? NS_ERROR_FAILURE : NS_OK;
}
else {
// We're on the last continuation since we're on the last character
startFrame = startFrame->GetLastContinuation();
}
}
- nsSelectionAmount amount;
- PRBool needsStart = PR_FALSE;
- switch (aBoundaryType)
- {
- case BOUNDARY_CHAR:
- amount = eSelectCharacter;
- if (aType == eGetAt) {
- aType = eGetAfter; // Avoid returning 2 characters
- }
- break;
- case BOUNDARY_WORD_START:
- needsStart = PR_TRUE;
- amount = eSelectWord;
- break;
- case BOUNDARY_WORD_END:
- amount = eSelectWord;
- break;
- case BOUNDARY_LINE_START:
- // Newlines are considered at the end of a line,
- // Since getting the BOUNDARY_LINE_START gets the text from the line-start
- // to the next line-start, the newline is included at the end of the string
- needsStart = PR_TRUE;
- amount = eSelectLine;
- break;
- case BOUNDARY_LINE_END:
- // Newlines are considered at the end of a line,
- // Since getting the BOUNDARY_END_START gets the text from the line-end
- // to the next line-end, the newline is included at the beginning of the string
- amount = eSelectLine;
- break;
- case BOUNDARY_ATTRIBUTE_RANGE:
- {
- // XXX We should merge identically formatted frames
- // XXX deal with static text case
- // XXX deal with boundary type
- nsIContent *textContent = startFrame->GetContent();
- // If not text, then it's represented by an embedded object char
- // (length of 1)
- // XXX did this mean to check for eTEXT?
- // XXX This is completely wrong, needs to be reimplemented
- PRInt32 textLength = textContent ? textContent->TextLength() : 1;
- if (textLength < 0) {
- return NS_ERROR_FAILURE;
- }
- *aStartOffset = aOffset - startOffset;
- *aEndOffset = *aStartOffset + textLength;
- startOffset = *aStartOffset;
- endOffset = *aEndOffset;
- return GetText(startOffset, endOffset, aText);
- }
- default: // Note, sentence support is deprecated and falls through to here
- return NS_ERROR_INVALID_ARG;
- }
-
PRInt32 finalStartOffset, finalEndOffset;
// If aType == eGetAt we'll change both the start and end offset from
// the original offset
if (aType == eGetAfter) {
finalStartOffset = aOffset;
}
else {
@@ -1066,41 +1082,116 @@ NS_IMETHODIMP nsHyperTextAccessible::Get
}
NS_IMETHODIMP nsHyperTextAccessible::GetTextAfterOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
{
return GetTextHelper(eGetAfter, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
}
-NS_IMETHODIMP nsHyperTextAccessible::GetAttributeRange(PRInt32 aOffset, PRInt32 *aRangeStartOffset,
- PRInt32 *aRangeEndOffset, nsIAccessible **aAccessibleWithAttrs)
+// nsIPersistentProperties
+// nsIAccessibleText::getTextAttributes(in boolean includeDefAttrs,
+// in long offset,
+// out long rangeStartOffset,
+// out long rangeEndOffset);
+NS_IMETHODIMP
+nsHyperTextAccessible::GetTextAttributes(PRBool aIncludeDefAttrs,
+ PRInt32 aOffset,
+ PRInt32 *aStartOffset,
+ PRInt32 *aEndOffset,
+ nsIPersistentProperties **aAttributes)
{
- // Return the range of text with common attributes around aOffset
- *aRangeStartOffset = *aRangeEndOffset = 0;
- *aAccessibleWithAttrs = nsnull;
+ // 1. First we get spell check, then language, then the set of CSS-based
+ // attributes.
+ // 2. As we get each new attribute, we pass the current start and end offsets
+ // as in/out parameters. In other words, as attributes are collected,
+ // the attribute range itself can only stay the same or get smaller.
+ //
+ // Example:
+ // Current: range 5-10
+ // Adding: range 7-12
+ // Result: range 7-10
- if (!mDOMNode) {
- return NS_ERROR_FAILURE;
+ NS_ENSURE_ARG_POINTER(aStartOffset);
+ *aStartOffset = 0;
+
+ NS_ENSURE_ARG_POINTER(aEndOffset);
+ nsresult rv = GetCharacterCount(aEndOffset);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (aAttributes) {
+ *aAttributes = nsnull;
+
+ nsCOMPtr<nsIPersistentProperties> attributes =
+ do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
+ NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
+
+ NS_ADDREF(*aAttributes = attributes);
}
- nsCOMPtr<nsIAccessible> accessible;
-
- while (NextChild(accessible)) {
- PRInt32 length = TextLength(accessible);
- NS_ENSURE_TRUE(length >= 0, NS_ERROR_FAILURE);
- if (*aRangeStartOffset + length > aOffset) {
- *aRangeEndOffset = *aRangeStartOffset + length;
- NS_ADDREF(*aAccessibleWithAttrs = accessible);
- return NS_OK;
- }
- *aRangeStartOffset += length;
+ if (!mDOMNode)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMNode> node;
+ PRInt32 nodeOffset = 0;
+ rv = HypertextOffsetToDOMPoint(aOffset, getter_AddRefs(node), &nodeOffset);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Set 'misspelled' text attribute.
+ rv = GetSpellTextAttribute(node, nodeOffset, aStartOffset, aEndOffset,
+ aAttributes ? *aAttributes : nsnull);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIContent> content(do_QueryInterface(node));
+ if (content && content->IsNodeOfType(nsINode::eELEMENT))
+ node = do_QueryInterface(content->GetChildAt(nodeOffset));
+
+ if (!node)
+ return NS_OK;
+
+ // Set 'lang' text attribute.
+ rv = GetLangTextAttributes(aIncludeDefAttrs, node,
+ aStartOffset, aEndOffset,
+ aAttributes ? *aAttributes : nsnull);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Set CSS based text attributes.
+ rv = GetCSSTextAttributes(aIncludeDefAttrs, node,
+ aStartOffset, aEndOffset,
+ aAttributes ? *aAttributes : nsnull);
+ return rv;
+}
+
+// nsIPersistentProperties
+// nsIAccessibleText::defaultTextAttributes
+NS_IMETHODIMP
+nsHyperTextAccessible::GetDefaultTextAttributes(nsIPersistentProperties **aAttributes)
+{
+ NS_ENSURE_ARG_POINTER(aAttributes);
+ *aAttributes = nsnull;
+
+ nsCOMPtr<nsIPersistentProperties> attributes =
+ do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
+ NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
+
+ NS_ADDREF(*aAttributes = attributes);
+
+ if (!mDOMNode)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMElement> element = nsAccUtils::GetDOMElementFor(mDOMNode);
+
+ nsCSSTextAttr textAttr(PR_TRUE, element, nsnull);
+ while (textAttr.iterate()) {
+ nsCAutoString name;
+ nsAutoString value, oldValue;
+ if (textAttr.get(name, value))
+ attributes->SetStringProperty(name, value, oldValue);
}
-
- return NS_ERROR_FAILURE;
+ return NS_OK;
}
nsresult
nsHyperTextAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
{
if (!mDOMNode) {
return NS_ERROR_FAILURE; // Node already shut down
}
@@ -1130,16 +1221,18 @@ nsHyperTextAccessible::GetAttributesInte
nsAutoString strHeadLevel;
strHeadLevel.AppendInt(headLevel);
nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::level,
strHeadLevel);
}
// Indicate when the current object uses block-level formatting
// via formatting: block
+ // XXX: 'formatting' attribute is deprecated and will be removed in Mozilla2,
+ // use 'display' attribute instead.
nsIFrame *frame = GetFrame();
if (frame && frame->GetType() == nsAccessibilityAtoms::blockFrame) {
nsAutoString oldValueUnused;
aAttributes->SetStringProperty(NS_LITERAL_CSTRING("formatting"), NS_LITERAL_STRING("block"),
oldValueUnused);
}
if (gLastFocusedNode == mDOMNode) {
@@ -1467,17 +1560,18 @@ nsresult nsHyperTextAccessible::SetSelec
// Set the selection
nsresult rv = SetSelectionBounds(0, aStartPos, aEndPos);
NS_ENSURE_SUCCESS(rv, rv);
// If range 0 was successfully set, clear any additional selection
// ranges remaining from previous selection
nsCOMPtr<nsISelection> domSel;
nsCOMPtr<nsISelectionController> selCon;
- GetSelections(getter_AddRefs(selCon), getter_AddRefs(domSel));
+ GetSelections(nsISelectionController::SELECTION_NORMAL,
+ getter_AddRefs(selCon), getter_AddRefs(domSel));
if (domSel) {
PRInt32 numRanges;
domSel->GetRangeCount(&numRanges);
for (PRInt32 count = 0; count < numRanges - 1; count ++) {
nsCOMPtr<nsIDOMRange> range;
domSel->GetRangeAt(1, getter_AddRefs(range));
domSel->RemoveRange(range);
@@ -1502,17 +1596,18 @@ NS_IMETHODIMP nsHyperTextAccessible::Set
/*
* Gets the offset position of the caret (cursor).
*/
NS_IMETHODIMP nsHyperTextAccessible::GetCaretOffset(PRInt32 *aCaretOffset)
{
*aCaretOffset = 0;
nsCOMPtr<nsISelection> domSel;
- nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel));
+ nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
+ nsnull, getter_AddRefs(domSel));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMNode> caretNode;
rv = domSel->GetFocusNode(getter_AddRefs(caretNode));
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 caretOffset;
domSel->GetFocusOffset(&caretOffset);
@@ -1520,17 +1615,18 @@ NS_IMETHODIMP nsHyperTextAccessible::Get
return DOMPointToHypertextOffset(caretNode, caretOffset, aCaretOffset);
}
PRInt32 nsHyperTextAccessible::GetCaretLineNumber()
{
// Provide the line number for the caret, relative to the
// currently focused node. Use a 1-based index
nsCOMPtr<nsISelection> domSel;
- GetSelections(nsnull, getter_AddRefs(domSel));
+ GetSelections(nsISelectionController::SELECTION_NORMAL, nsnull,
+ getter_AddRefs(domSel));
nsCOMPtr<nsISelectionPrivate> privateSelection(do_QueryInterface(domSel));
NS_ENSURE_TRUE(privateSelection, -1);
nsCOMPtr<nsFrameSelection> frameSelection;
privateSelection->GetFrameSelection(getter_AddRefs(frameSelection));
NS_ENSURE_TRUE(frameSelection, -1);
nsCOMPtr<nsIDOMNode> caretNode;
domSel->GetFocusNode(getter_AddRefs(caretNode));
@@ -1583,19 +1679,21 @@ PRInt32 nsHyperTextAccessible::GetCaretL
caretFrame = parentFrame;
}
NS_NOTREACHED("DOM ancestry had this hypertext but frame ancestry didn't");
return lineNumber;
}
-nsresult nsHyperTextAccessible::GetSelections(nsISelectionController **aSelCon,
- nsISelection **aDomSel,
- nsCOMArray<nsIDOMRange>* aRanges)
+nsresult
+nsHyperTextAccessible::GetSelections(PRInt16 aType,
+ nsISelectionController **aSelCon,
+ nsISelection **aDomSel,
+ nsCOMArray<nsIDOMRange>* aRanges)
{
if (!mDOMNode) {
return NS_ERROR_FAILURE;
}
if (aSelCon) {
*aSelCon = nsnull;
}
if (aDomSel) {
@@ -1603,65 +1701,60 @@ nsresult nsHyperTextAccessible::GetSelec
}
if (aRanges) {
aRanges->Clear();
}
nsCOMPtr<nsISelection> domSel;
nsCOMPtr<nsISelectionController> selCon;
- nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIEditor> editor;
GetAssociatedEditor(getter_AddRefs(editor));
nsCOMPtr<nsIPlaintextEditor> peditor(do_QueryInterface(editor));
if (peditor) {
// Case 1: plain text editor
// This is for form controls which have their own
// selection controller separate from the document, for example
// HTML:input, HTML:textarea, XUL:textbox, etc.
- if (aSelCon) {
- editor->GetSelectionController(getter_AddRefs(selCon));
- NS_ENSURE_TRUE(*aSelCon, NS_ERROR_FAILURE);
- }
-
- editor->GetSelection(getter_AddRefs(domSel));
- NS_ENSURE_TRUE(domSel, NS_ERROR_FAILURE);
-
- nsCOMPtr<nsIDOMElement> editorRoot;
- editor->GetRootElement(getter_AddRefs(editorRoot));
- startNode = do_QueryInterface(editorRoot);
- NS_ENSURE_STATE(startNode);
+ editor->GetSelectionController(getter_AddRefs(selCon));
}
else {
// Case 2: rich content subtree (can be rich editor)
// This uses the selection controller from the entire document
nsIFrame *frame = GetFrame();
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
// Get the selection and selection controller
frame->GetSelectionController(GetPresContext(),
getter_AddRefs(selCon));
- NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
- selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
- getter_AddRefs(domSel));
- NS_ENSURE_TRUE(domSel, NS_ERROR_FAILURE);
+ }
+ NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
- startNode = mDOMNode;
- }
+ selCon->GetSelection(aType, getter_AddRefs(domSel));
+ NS_ENSURE_TRUE(domSel, NS_ERROR_FAILURE);
if (aSelCon) {
NS_ADDREF(*aSelCon = selCon);
}
if (aDomSel) {
NS_ADDREF(*aDomSel = domSel);
}
+
if (aRanges) {
nsCOMPtr<nsISelection2> selection2(do_QueryInterface(domSel));
NS_ENSURE_TRUE(selection2, NS_ERROR_FAILURE);
+ nsCOMPtr<nsIDOMNode> startNode(mDOMNode);
+ if (peditor) {
+ nsCOMPtr<nsIDOMElement> editorRoot;
+ editor->GetRootElement(getter_AddRefs(editorRoot));
+ startNode = do_QueryInterface(editorRoot);
+ }
+ NS_ENSURE_STATE(startNode);
+
nsCOMPtr<nsIDOMNodeList> childNodes;
nsresult rv = startNode->GetChildNodes(getter_AddRefs(childNodes));
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 numChildren;
rv = childNodes->GetLength(&numChildren);
NS_ENSURE_SUCCESS(rv, rv);
rv = selection2->GetRangesForIntervalCOMArray(startNode, 0,
startNode, numChildren,
@@ -1685,34 +1778,36 @@ nsresult nsHyperTextAccessible::GetSelec
/*
* Gets the number of selected regions.
*/
NS_IMETHODIMP nsHyperTextAccessible::GetSelectionCount(PRInt32 *aSelectionCount)
{
nsCOMPtr<nsISelection> domSel;
nsCOMArray<nsIDOMRange> ranges;
- nsresult rv = GetSelections(nsnull, nsnull, &ranges);
+ nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
+ nsnull, nsnull, &ranges);
NS_ENSURE_SUCCESS(rv, rv);
*aSelectionCount = ranges.Count();
return NS_OK;
}
/*
* Gets the start and end offset of the specified selection.
*/
NS_IMETHODIMP nsHyperTextAccessible::GetSelectionBounds(PRInt32 aSelectionNum, PRInt32 *aStartOffset, PRInt32 *aEndOffset)
{
*aStartOffset = *aEndOffset = 0;
nsCOMPtr<nsISelection> domSel;
nsCOMArray<nsIDOMRange> ranges;
- nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel), &ranges);
+ nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
+ nsnull, getter_AddRefs(domSel), &ranges);
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 rangeCount = ranges.Count();
if (aSelectionNum < 0 || aSelectionNum >= rangeCount)
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIDOMRange> range = ranges[aSelectionNum];
@@ -1755,17 +1850,18 @@ NS_IMETHODIMP nsHyperTextAccessible::Get
* Changes the start and end offset of the specified selection.
*/
NS_IMETHODIMP
nsHyperTextAccessible::SetSelectionBounds(PRInt32 aSelectionNum,
PRInt32 aStartOffset,
PRInt32 aEndOffset)
{
nsCOMPtr<nsISelection> domSel;
- nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel));
+ nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
+ nsnull, getter_AddRefs(domSel));
NS_ENSURE_SUCCESS(rv, rv);
// Caret is a collapsed selection
PRBool isOnlyCaret = (aStartOffset == aEndOffset);
PRInt32 rangeCount;
domSel->GetRangeCount(&rangeCount);
nsCOMPtr<nsIDOMRange> range;
@@ -1803,32 +1899,34 @@ nsHyperTextAccessible::SetSelectionBound
}
/*
* Adds a selection bounded by the specified offsets.
*/
NS_IMETHODIMP nsHyperTextAccessible::AddSelection(PRInt32 aStartOffset, PRInt32 aEndOffset)
{
nsCOMPtr<nsISelection> domSel;
- nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel));
+ nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
+ nsnull, getter_AddRefs(domSel));
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 rangeCount;
domSel->GetRangeCount(&rangeCount);
return SetSelectionBounds(rangeCount, aStartOffset, aEndOffset);
}
/*
* Removes the specified selection.
*/
NS_IMETHODIMP nsHyperTextAccessible::RemoveSelection(PRInt32 aSelectionNum)
{
nsCOMPtr<nsISelection> domSel;
- nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel));
+ nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL,
+ nsnull, getter_AddRefs(domSel));
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 rangeCount;
domSel->GetRangeCount(&rangeCount);
if (aSelectionNum < 0 || aSelectionNum >= rangeCount)
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIDOMRange> range;
@@ -2030,8 +2128,361 @@ nsHyperTextAccessible::GetDOMPointByFram
*aNodeOffset = parent->IndexOf(content);
node = do_QueryInterface(parent);
}
NS_IF_ADDREF(*aNode = node);
return NS_OK;
}
+// nsHyperTextAccessible
+nsresult
+nsHyperTextAccessible::DOMRangeBoundToHypertextOffset(nsIDOMRange *aRange,
+ PRBool aIsStartBound,
+ PRBool aIsStartHTOffset,
+ PRInt32 *aHTOffset)
+{
+ nsCOMPtr<nsIDOMNode> node;
+ PRInt32 nodeOffset = 0;
+
+ nsresult rv;
+ if (aIsStartBound) {
+ rv = aRange->GetStartContainer(getter_AddRefs(node));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = aRange->GetStartOffset(&nodeOffset);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ rv = aRange->GetEndContainer(getter_AddRefs(node));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = aRange->GetEndOffset(&nodeOffset);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ nsCOMPtr<nsIAccessible> startAcc;
+ rv = DOMPointToHypertextOffset(node, nodeOffset, aHTOffset,
+ getter_AddRefs(startAcc));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (aIsStartHTOffset && !startAcc)
+ *aHTOffset = 0;
+
+ return NS_OK;
+}
+
+// nsHyperTextAccessible
+nsresult
+nsHyperTextAccessible::GetSpellTextAttribute(nsIDOMNode *aNode,
+ PRInt32 aNodeOffset,
+ PRInt32 *aHTStartOffset,
+ PRInt32 *aHTEndOffset,
+ nsIPersistentProperties *aAttributes)
+{
+ nsCOMArray<nsIDOMRange> ranges;
+ nsresult rv = GetSelections(nsISelectionController::SELECTION_SPELLCHECK,
+ nsnull, nsnull, &ranges);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PRInt32 rangeCount = ranges.Count();
+ if (!rangeCount)
+ return NS_OK;
+
+ for (PRInt32 index = 0; index < rangeCount; index++) {
+ nsCOMPtr<nsIDOMRange> range = ranges[index];
+ nsCOMPtr<nsIDOMNSRange> nsrange(do_QueryInterface(range));
+ NS_ENSURE_STATE(nsrange);
+
+ PRInt16 result;
+ rv = nsrange->ComparePoint(aNode, aNodeOffset, &result);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (result == 1) { // range is before point
+ PRInt32 startHTOffset = 0;
+ rv = DOMRangeBoundToHypertextOffset(range, PR_FALSE, PR_TRUE,
+ &startHTOffset);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (startHTOffset > *aHTStartOffset)
+ *aHTStartOffset = startHTOffset;
+
+ } else if (result == -1) { // range is after point
+ PRInt32 endHTOffset = 0;
+ rv = DOMRangeBoundToHypertextOffset(range, PR_TRUE, PR_FALSE,
+ &endHTOffset);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (endHTOffset < *aHTEndOffset)
+ *aHTEndOffset = endHTOffset;
+
+ } else { // point is in range
+ PRInt32 startHTOffset = 0;
+ rv = DOMRangeBoundToHypertextOffset(range, PR_TRUE, PR_TRUE,
+ &startHTOffset);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PRInt32 endHTOffset = 0;
+ rv = DOMRangeBoundToHypertextOffset(range, PR_FALSE, PR_FALSE,
+ &endHTOffset);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (startHTOffset > *aHTStartOffset)
+ *aHTStartOffset = startHTOffset;
+ if (endHTOffset < *aHTEndOffset)
+ *aHTEndOffset = endHTOffset;
+
+ if (aAttributes) {
+ nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::invalid,
+ NS_LITERAL_STRING("spelling"));
+ }
+
+ return NS_OK;
+ }
+ }
+
+ return NS_OK;
+}
+
+// nsHyperTextAccessible
+nsresult
+nsHyperTextAccessible::GetLangTextAttributes(PRBool aIncludeDefAttrs,
+ nsIDOMNode *aSourceNode,
+ PRInt32 *aStartHTOffset,
+ PRInt32 *aEndHTOffset,
+ nsIPersistentProperties *aAttributes)
+{
+ nsCOMPtr<nsIDOMElement> sourceElm(nsAccUtils::GetDOMElementFor(aSourceNode));
+
+ nsCOMPtr<nsIContent> content(do_QueryInterface(sourceElm));
+ nsCOMPtr<nsIContent> rootContent(do_QueryInterface(mDOMNode));
+
+ nsAutoString lang;
+ nsAccUtils::GetLanguageFor(content, rootContent, lang);
+
+ nsAutoString rootLang;
+ nsresult rv = GetLanguage(rootLang);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (aAttributes) {
+ // Expose 'language' text attribute if the DOM 'lang' attribute is
+ // presented and it's different from the 'lang' attribute on the root
+ // element or we should include default values of text attribute.
+ const nsAString& resultLang = lang.IsEmpty() ? rootLang : lang;
+ if (!resultLang.IsEmpty() && (aIncludeDefAttrs || lang != rootLang))
+ nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::language,
+ resultLang);
+ }
+
+ nsLangTextAttr textAttr(lang, rootContent);
+ return GetRangeForTextAttr(aSourceNode, &textAttr,
+ aStartHTOffset, aEndHTOffset);
+}
+
+// nsHyperTextAccessible
+nsresult
+nsHyperTextAccessible::GetCSSTextAttributes(PRBool aIncludeDefAttrs,
+ nsIDOMNode *aSourceNode,
+ PRInt32 *aStartHTOffset,
+ PRInt32 *aEndHTOffset,
+ nsIPersistentProperties *aAttributes)
+{
+ nsCOMPtr<nsIDOMElement> sourceElm(nsAccUtils::GetDOMElementFor(aSourceNode));
+ nsCOMPtr<nsIDOMElement> rootElm(nsAccUtils::GetDOMElementFor(mDOMNode));
+
+ nsCSSTextAttr textAttr(aIncludeDefAttrs, sourceElm, rootElm);
+ while (textAttr.iterate()) {
+ nsCAutoString name;
+ nsAutoString value, oldValue;
+ if (aAttributes && textAttr.get(name, value))
+ aAttributes->SetStringProperty(name, value, oldValue);
+
+ nsresult rv = GetRangeForTextAttr(aSourceNode, &textAttr,
+ aStartHTOffset, aEndHTOffset);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
+}
+
+// nsHyperTextAccessible
+nsresult
+nsHyperTextAccessible::GetRangeForTextAttr(nsIDOMNode *aNode,
+ nsTextAttr *aComparer,
+ PRInt32 *aStartHTOffset,
+ PRInt32 *aEndHTOffset)
+{
+ nsCOMPtr<nsIDOMElement> rootElm(nsAccUtils::GetDOMElementFor(mDOMNode));
+ NS_ENSURE_STATE(rootElm);
+
+ nsCOMPtr<nsIDOMNode> tmpNode(aNode);
+ nsCOMPtr<nsIDOMNode> currNode(aNode);
+
+ // Navigate backwards and forwards from current node to the root node to
+ // calculate range bounds for the text attribute. Navigation sequence is the
+ // following:
+ // 1. Navigate through the siblings.
+ // 2. If the traversed sibling has children then navigate from its leaf child
+ // to it through whole tree of the traversed sibling.
+ // 3. Get the parent and cycle algorithm until the root node.
+
+ // Navigate backwards (find the start offset).
+ while (currNode && currNode != rootElm) {
+ nsCOMPtr<nsIDOMElement> currElm(nsAccUtils::GetDOMElementFor(currNode));
+ NS_ENSURE_STATE(currElm);
+
+ if (currNode != aNode && !aComparer->equal(currElm)) {
+ PRInt32 startHTOffset = 0;
+ nsCOMPtr<nsIAccessible> startAcc;
+ nsresult rv = DOMPointToHypertextOffset(tmpNode, -1, &startHTOffset,
+ getter_AddRefs(startAcc));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!startAcc)
+ startHTOffset = 0;
+
+ if (startHTOffset > *aStartHTOffset)
+ *aStartHTOffset = startHTOffset;
+
+ break;
+ }
+
+ currNode->GetPreviousSibling(getter_AddRefs(tmpNode));
+ if (tmpNode) {
+ // Navigate through the subtree of traversed children to calculate
+ // left bound of the range.
+ FindStartOffsetInSubtree(tmpNode, currNode, aComparer, aStartHTOffset);
+ }
+
+ currNode->GetParentNode(getter_AddRefs(tmpNode));
+ currNode.swap(tmpNode);
+ }
+
+ // Navigate forwards (find the end offset).
+ PRBool moveIntoSubtree = PR_TRUE;
+ currNode = aNode;
+ while (currNode && currNode != rootElm) {
+ nsCOMPtr<nsIDOMElement> currElm(nsAccUtils::GetDOMElementFor(currNode));
+ NS_ENSURE_STATE(currElm);
+
+ // Stop new end offset searching if the given text attribute changes its
+ // value.
+ if (!aComparer->equal(currElm)) {
+ PRInt32 endHTOffset = 0;
+ nsresult rv = DOMPointToHypertextOffset(currNode, -1, &endHTOffset);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (endHTOffset < *aEndHTOffset)
+ *aEndHTOffset = endHTOffset;
+
+ break;
+ }
+
+ if (moveIntoSubtree) {
+ // Navigate through subtree of traversed node. We use 'moveIntoSubtree'
+ // flag to avoid traversing the same subtree twice.
+ currNode->GetFirstChild(getter_AddRefs(tmpNode));
+ if (tmpNode)
+ FindEndOffsetInSubtree(tmpNode, aComparer, aEndHTOffset);
+ }
+
+ currNode->GetNextSibling(getter_AddRefs(tmpNode));
+ moveIntoSubtree = PR_TRUE;
+ if (!tmpNode) {
+ currNode->GetParentNode(getter_AddRefs(tmpNode));
+ moveIntoSubtree = PR_FALSE;
+ }
+
+ currNode.swap(tmpNode);
+ }
+
+ return NS_OK;
+}
+
+
+PRBool
+nsHyperTextAccessible::FindEndOffsetInSubtree(nsIDOMNode *aCurrNode,
+ nsTextAttr *aComparer,
+ PRInt32 *aHTOffset)
+{
+ if (!aCurrNode)
+ return PR_FALSE;
+
+ nsCOMPtr<nsIDOMElement> currElm(nsAccUtils::GetDOMElementFor(aCurrNode));
+ NS_ENSURE_STATE(currElm);
+
+ // If the given text attribute (pointed by nsTextAttr object) changes its
+ // value on the traversed element then fit the end of range.
+ if (!aComparer->equal(currElm)) {
+ PRInt32 endHTOffset = 0;
+ nsresult rv = DOMPointToHypertextOffset(aCurrNode, -1, &endHTOffset);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (endHTOffset < *aHTOffset)
+ *aHTOffset = endHTOffset;
+
+ return PR_TRUE;
+ }
+
+ // Deeply traverse into the tree to fit the end of range.
+ nsCOMPtr<nsIDOMNode> nextNode;
+ aCurrNode->GetFirstChild(getter_AddRefs(nextNode));
+ if (nextNode) {
+ PRBool res = FindEndOffsetInSubtree(nextNode, aComparer, aHTOffset);
+ if (res)
+ return res;
+ }
+
+ aCurrNode->GetNextSibling(getter_AddRefs(nextNode));
+ if (nextNode) {
+ if (FindEndOffsetInSubtree(nextNode, aComparer, aHTOffset))
+ return PR_TRUE;
+ }
+
+ return PR_FALSE;
+}
+
+PRBool
+nsHyperTextAccessible::FindStartOffsetInSubtree(nsIDOMNode *aCurrNode,
+ nsIDOMNode *aPrevNode,
+ nsTextAttr *aComparer,
+ PRInt32 *aHTOffset)
+{
+ if (!aCurrNode)
+ return PR_FALSE;
+
+ // Find the closest element back to the traversed element.
+ nsCOMPtr<nsIDOMNode> nextNode;
+ aCurrNode->GetLastChild(getter_AddRefs(nextNode));
+ if (nextNode) {
+ if (FindStartOffsetInSubtree(nextNode, aPrevNode, aComparer, aHTOffset))
+ return PR_TRUE;
+ }
+
+ nsCOMPtr<nsIDOMElement> currElm(nsAccUtils::GetDOMElementFor(aCurrNode));
+ NS_ENSURE_STATE(currElm);
+
+ // If the given text attribute (pointed by nsTextAttr object) changes its
+ // value on the traversed element then fit the start of range.
+ if (!aComparer->equal(currElm)) {
+ PRInt32 startHTOffset = 0;
+ nsCOMPtr<nsIAccessible> startAcc;
+ nsresult rv = DOMPointToHypertextOffset(aPrevNode, -1, &startHTOffset,
+ getter_AddRefs(startAcc));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!startAcc)
+ startHTOffset = 0;
+
+ if (startHTOffset > *aHTOffset)
+ *aHTOffset = startHTOffset;
+
+ return PR_TRUE;
+ }
+
+ // Moving backwards to find the start of range.
+ aCurrNode->GetPreviousSibling(getter_AddRefs(nextNode));
+ if (nextNode) {
+ if (FindStartOffsetInSubtree(nextNode, aCurrNode, aComparer, aHTOffset))
+ return PR_TRUE;
+ }
+
+ return PR_FALSE;
+}
--- a/accessible/src/html/nsHyperTextAccessible.h
+++ b/accessible/src/html/nsHyperTextAccessible.h
@@ -40,16 +40,18 @@
#ifndef _nsHyperTextAccessible_H_
#define _nsHyperTextAccessible_H_
#include "nsAccessibleWrap.h"
#include "nsIAccessibleText.h"
#include "nsIAccessibleHyperText.h"
#include "nsIAccessibleEditableText.h"
#include "nsAccessibleEventData.h"
+#include "nsTextUtils.h"
+
#include "nsFrameSelection.h"
#include "nsISelectionController.h"
enum EGetTextType { eGetBefore=-1, eGetAt=0, eGetAfter=1 };
// This character marks where in the text returned via nsIAccessibleText(),
// that embedded object characters exist
const PRUnichar kEmbeddedObjectChar = 0xfffc;
@@ -59,35 +61,37 @@ const PRUnichar kForcedNewLineChar = '\n
#define NS_HYPERTEXTACCESSIBLE_IMPL_CID \
{ /* 245f3bc9-224f-4839-a92e-95239705f30b */ \
0x245f3bc9, \
0x224f, \
0x4839, \
{ 0xa9, 0x2e, 0x95, 0x23, 0x97, 0x05, 0xf3, 0x0b } \
}
-
/**
* Special Accessible that knows how contain both text and embedded objects
*/
class nsHyperTextAccessible : public nsAccessibleWrap,
public nsIAccessibleText,
public nsIAccessibleHyperText,
public nsIAccessibleEditableText
{
public:
nsHyperTextAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIACCESSIBLETEXT
NS_DECL_NSIACCESSIBLEHYPERTEXT
NS_DECL_NSIACCESSIBLEEDITABLETEXT
NS_DECLARE_STATIC_IID_ACCESSOR(NS_HYPERTEXTACCESSIBLE_IMPL_CID)
+ // nsIAccessible
NS_IMETHOD GetRole(PRUint32 *aRole);
NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
+
+ // nsAccessible
virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
void CacheChildren();
// Convert content offset to rendered text offset
static nsresult ContentToRenderedOffset(nsIFrame *aFrame, PRInt32 aContentOffset,
PRUint32 *aRenderedOffset);
// Convert rendered text offset to content offset
@@ -120,16 +124,27 @@ public:
* descendant, then the returned offset will be on the relevant embedded object char.
*/
nsresult DOMPointToHypertextOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset,
PRInt32 *aHypertextOffset,
nsIAccessible **aFinalAccessible = nsnull,
PRBool aIsEndOffset = PR_FALSE);
/**
+ * Turn a hypertext offsets into DOM point.
+ *
+ * @param aHTOffset [in] the given start hypertext offset
+ * @param aNode [out] start node
+ * @param aOffset [out] offset inside the start node
+ */
+ nsresult HypertextOffsetToDOMPoint(PRInt32 aHTOffset,
+ nsIDOMNode **aNode,
+ PRInt32 *aOffset);
+
+ /**
* Turn a start and end hypertext offsets into DOM range.
*
* @param aStartHTOffset [in] the given start hypertext offset
* @param aEndHTOffset [in] the given end hypertext offset
* @param aStartNode [out] start node of the range
* @param aStartOffset [out] start offset of the range
* @param aEndNode [out] end node of the range
* @param aEndOffset [out] end offset of the range
@@ -206,37 +221,164 @@ protected:
nsIntRect *aBoundsRect = nsnull,
nsIAccessible **aStartAcc = nsnull,
nsIAccessible **aEndAcc = nsnull);
nsIntRect GetBoundsForString(nsIFrame *aFrame, PRUint32 aStartRenderedOffset, PRUint32 aEndRenderedOffset);
// Selection helpers
- /**
- * Get the relevant selection interfaces and ranges for the current hyper text
- * @param aSelCon The selection controller for the current hyper text, or nsnull if not needed
- * @param aDomSel The selection interface for the current hyper text, or nsnull if not needed
- * @param aRanges The selected ranges within the current subtree, or nsnull if not needed
+ /**
+ * Get the relevant selection interfaces and ranges for the current hyper
+ * text.
+ *
+ * @param aType [in] the selection type
+ * @param aSelCon [out, optional] the selection controller for the current
+ * hyper text
+ * @param aDomSel [out, optional] the selection interface for the current
+ * hyper text
+ * @param aRanges [out, optional] the selected ranges within the current
+ * subtree
*/
- nsresult GetSelections(nsISelectionController **aSelCon,
+ nsresult GetSelections(PRInt16 aType,
+ nsISelectionController **aSelCon,
nsISelection **aDomSel = nsnull,
nsCOMArray<nsIDOMRange>* aRanges = nsnull);
+
nsresult SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos);
/**
* Provide the line number for the caret, relative to the
* current DOM node.
* @return 1-based index for the line number with the caret
*/
PRInt32 GetCaretLineNumber();
// Helpers
nsresult GetDOMPointByFrameOffset(nsIFrame *aFrame, PRInt32 aOffset,
nsIAccessible *aAccessible,
nsIDOMNode **aNode, PRInt32 *aNodeOffset);
+
+
+ /**
+ * Return hyper text offset for the specified bound of the given DOM range.
+ * If the bound is outside of the hyper text then offset value is either
+ * 0 or number of characters of hyper text, it depends on type of requested
+ * offset. The method is a wrapper for DOMPointToHypertextOffset.
+ *
+ * @param aRange [in] the given range
+ * @param aIsStartBound [in] specifies whether the required range bound is
+ * start bound
+ * @param aIsStartOffset [in] the offset type, used when the range bound is
+ * outside of hyper text
+ * @param aHTOffset [out] the result offset
+ */
+ nsresult DOMRangeBoundToHypertextOffset(nsIDOMRange *aRange,
+ PRBool aIsStartBound,
+ PRBool aIsStartOffset,
+ PRInt32 *aHTOffset);
+
+ /**
+ * Set 'misspelled' text attribute and return range offsets where the
+ * attibute is stretched. If the text is not misspelled at the given offset
+ * then we expose only range offsets where text is not misspelled. The method
+ * is used by GetTextAttributes() method.
+ *
+ * @param aIncludeDefAttrs [in] points whether text attributes having default
+ * values of attributes should be included
+ * @param aSourceNode [in] the node we start to traverse from
+ * @param aStartOffset [in, out] the start offset
+ * @param aEndOffset [in, out] the end offset
+ * @param aAttributes [out, optional] result attributes
+ */
+ nsresult GetSpellTextAttribute(nsIDOMNode *aNode, PRInt32 aNodeOffset,
+ PRInt32 *aStartOffset,
+ PRInt32 *aEndOffset,
+ nsIPersistentProperties *aAttributes);
+
+ /**
+ * Set 'lang' text attribute and return range offsets where attibute is
+ * stretched. The method is used by GetTextAttributes() method.
+ *
+ * @param aIncludeDefAttrs [in] points whether text attributes having default
+ * values of attributes should be included
+ * @param aSourceNode [in] the node we start to traverse from
+ * @param aStartOffset [in, out] the start offset
+ * @param aEndOffset [in, out] the end offset
+ * @param aAttributes [out, optional] result attributes
+ */
+ nsresult GetLangTextAttributes(PRBool aIncludeDefAttrs,
+ nsIDOMNode *aSourceNode,
+ PRInt32 *aStartOffset,
+ PRInt32 *aEndOffset,
+ nsIPersistentProperties *aAttributes);
+
+ /**
+ * Set CSS based text attribute and return range offsets where attibutes are
+ * stretched. The method is used by GetTextAttributes() method.
+ *
+ * @param aIncludeDefAttrs [in] points whether text attributes having default
+ * values of attributes should be included
+ * @param aSourceNode [in] the node we start to traverse from
+ * @param aStartOffset [in, out] the start offset
+ * @param aEndOffset [in, out] the end offset
+ * @param aAttributes [out, optional] result attributes
+ */
+ nsresult GetCSSTextAttributes(PRBool aIncludeDefAttrs,
+ nsIDOMNode *aSourceNode,
+ PRInt32 *aStartOffset,
+ PRInt32 *aEndOffset,
+ nsIPersistentProperties *aAttributes);
+
+ /**
+ * Calculates range (start and end offsets) of text where the text attribute
+ * (pointed by nsTextAttr object) is stretched. New offsets may be smaller if
+ * the given text attribute changes its value before or after the given
+ * offsets.
+ *
+ * @param aNode [in] the node we start to traverse from
+ * @param aComparer [in] object used to describe the text attribute
+ * @param aStartHTOffset [in, out] the start offset
+ * @param aEndHTOffset [in, out] the end offset
+ */
+ nsresult GetRangeForTextAttr(nsIDOMNode *aNode,
+ nsTextAttr *aComparer,
+ PRInt32 *aStartHTOffset,
+ PRInt32 *aEndHTOffset);
+
+ /**
+ * Find new end offset for text attributes navigating through the tree. New
+ * end offset may be smaller if the given text attribute (pointed by
+ * nsTextAttr object) changes its value before the given end offset.
+ *
+ * @param aCurrNode [in] the first node of the tree
+ * @param aComparer [in] object used to describe the text attribute
+ * @param aHTOffset [in, out] the end offset
+ * @return true if the end offset has been changed
+ */
+ PRBool FindEndOffsetInSubtree(nsIDOMNode *aCurrNode,
+ nsTextAttr *aComparer,
+ PRInt32 *aHTOffset);
+
+ /**
+ * Find the start offset for text attributes navigating through the tree. New
+ * start offset may be bigger if the given text attribute (pointed by
+ * nsTextAttr object) changes its value after the given start offset.
+ *
+ * @param aCurrNode [in] the node navigating through thee thee is started
+ * from
+ * @param aPrevNode [in] the previous node placed before the start node
+ * @param aComparer [in] object used to describe the text attribute
+ * @param aHTOffset [in, out] the start offset
+ * @return true if the start offset has been changed
+ */
+ PRBool FindStartOffsetInSubtree(nsIDOMNode *aCurrNode,
+ nsIDOMNode *aPrevNode,
+ nsTextAttr *aComparer,
+ PRInt32 *aHTOffset);
+
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsHyperTextAccessible,
NS_HYPERTEXTACCESSIBLE_IMPL_CID)
#endif // _nsHyperTextAccessible_H_
--- a/accessible/src/mac/nsAccessibleWrap.h
+++ b/accessible/src/mac/nsAccessibleWrap.h
@@ -91,17 +91,19 @@ class nsAccessibleWrap : public nsAccess
return (state & nsIAccessibleStates::STATE_HASPOPUP);
}
// return this accessible's all children, adhering to "flat" accessibles by not returning their children.
void GetUnignoredChildren(nsTArray<nsRefPtr<nsAccessibleWrap> > &aChildrenArray);
virtual already_AddRefed<nsIAccessible> GetUnignoredParent();
protected:
-
+
+ virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent);
+
PRBool AncestorIsFlat() {
// we don't create a native object if we're child of a "flat" accessible; for example, on OS X buttons
// shouldn't have any children, because that makes the OS confused.
//
// to maintain a scripting environment where the XPCOM accessible hierarchy look the same
// on all platforms, we still let the C++ objects be created though.
nsCOMPtr<nsIAccessible> curParent = GetParent();
--- a/accessible/src/mac/nsAccessibleWrap.mm
+++ b/accessible/src/mac/nsAccessibleWrap.mm
@@ -164,18 +164,28 @@ nsAccessibleWrap::FireAccessibleEvent(ns
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
NS_ENSURE_ARG_POINTER(aEvent);
nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
NS_ENSURE_SUCCESS(rv, rv);
+ return FirePlatformEvent(aEvent);
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
+
+nsresult
+nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent *aEvent)
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
PRUint32 eventType;
- rv = aEvent->GetEventType(&eventType);
+ nsresult rv = aEvent->GetEventType(&eventType);
NS_ENSURE_SUCCESS(rv, rv);
// ignore everything but focus-changed and value-changed events for now.
if (eventType != nsIAccessibleEvent::EVENT_FOCUS &&
eventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE)
return NS_OK;
nsCOMPtr<nsIAccessible> accessible;
--- a/accessible/src/msaa/CAccessibleText.cpp
+++ b/accessible/src/msaa/CAccessibleText.cpp
@@ -43,16 +43,17 @@
#include "Accessible2.h"
#include "AccessibleText_i.c"
#include "nsIAccessible.h"
#include "nsIAccessibleText.h"
#include "nsIAccessibleTypes.h"
#include "nsIWinAccessNode.h"
#include "nsAccessNodeWrap.h"
+#include "nsAccessibleWrap.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#define GET_NSIACCESSIBLETEXT \
nsCOMPtr<nsIAccessibleText> textAcc(do_QueryInterface(this));\
NS_ASSERTION(textAcc,\
"Subclass of CAccessibleText doesn't implement nsIAccessibleText");\
@@ -103,42 +104,36 @@ CAccessibleText::get_attributes(long aOf
return E_INVALIDARG;
*aStartOffset = 0;
*aEndOffset = 0;
*aTextAttributes = NULL;
GET_NSIACCESSIBLETEXT
- nsCOMPtr<nsIAccessible> accessible;
PRInt32 startOffset = 0, endOffset = 0;
- textAcc->GetAttributeRange(aOffset, &startOffset, &endOffset,
- getter_AddRefs(accessible));
- if (!accessible)
- return E_FAIL;
-
- nsCOMPtr<nsIWinAccessNode> winAccessNode(do_QueryInterface(accessible));
- if (!winAccessNode)
- return E_FAIL;
-
- void *instancePtr = 0;
- winAccessNode->QueryNativeInterface(IID_IAccessible2, &instancePtr);
- if (!instancePtr)
- return E_FAIL;
-
- IAccessible2 *pAccessible2 = static_cast<IAccessible2*>(instancePtr);
- HRESULT hr = pAccessible2->get_attributes(aTextAttributes);
- pAccessible2->Release();
+ nsCOMPtr<nsIPersistentProperties> attributes;
+ nsresult rv = textAcc->GetTextAttributes(PR_TRUE, aOffset,
+ &startOffset, &endOffset,
+ getter_AddRefs(attributes));
+ if (NS_FAILED(rv))
+ return GetHRESULT(rv);
+
+ HRESULT hr = nsAccessibleWrap::ConvertToIA2Attributes(attributes,
+ aTextAttributes);
+ if (FAILED(hr))
+ return hr;
*aStartOffset = startOffset;
*aEndOffset = endOffset;
- return hr;
+
+ return S_OK;
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
- return E_NOTIMPL;
+ return E_FAIL;
}
STDMETHODIMP
CAccessibleText::get_caretOffset(long *aOffset)
{
__try {
*aOffset = -1;
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -70,16 +70,18 @@
#ifdef DEBUG_LEAKS
static gAccessibles = 0;
#endif
EXTERN_C GUID CDECL CLSID_Accessible =
{ 0x61044601, 0xa811, 0x4e2b, { 0xbb, 0xba, 0x17, 0xbf, 0xab, 0xd3, 0x29, 0xd7 } };
+static const PRInt32 kIEnumVariantDisconnected = -1;
+
/*
* Class nsAccessibleWrap
*/
//-----------------------------------------------------
// construction
//-----------------------------------------------------
nsAccessibleWrap::nsAccessibleWrap(nsIDOMNode* aNode, nsIWeakReference *aShell):
@@ -328,16 +330,22 @@ STDMETHODIMP nsAccessibleWrap::get_accVa
*pszValue = NULL;
nsCOMPtr<nsIAccessible> xpAccessible;
GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
if (xpAccessible) {
nsAutoString value;
if (NS_FAILED(xpAccessible->GetValue(value)))
return E_FAIL;
+ // see bug 438784: Need to expose URL on doc's value attribute.
+ // For this, reverting part of fix for bug 425693 to make this MSAA method
+ // behave IAccessible2-style.
+ if (value.IsEmpty())
+ return S_FALSE;
+
*pszValue = ::SysAllocStringLen(value.get(), value.Length());
if (!*pszValue)
return E_OUTOFMEMORY;
}
} __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
return S_OK;
}
@@ -1075,68 +1083,68 @@ STDMETHODIMP nsAccessibleWrap::put_accVa
/* [optional][in] */ VARIANT varChild,
/* [in] */ BSTR szValue)
{
return E_NOTIMPL;
}
#include "mshtml.h"
+////////////////////////////////////////////////////////////////////////////////
+// nsAccessibleWrap. IEnumVariant
+
STDMETHODIMP
-nsAccessibleWrap::Next(ULONG aNumElementsRequested, VARIANT FAR* pvar, ULONG FAR* aNumElementsFetched)
+nsAccessibleWrap::Next(ULONG aNumElementsRequested, VARIANT FAR* aPVar,
+ ULONG FAR* aNumElementsFetched)
{
- // If there are two clients using this at the same time, and they are
- // each using a different mEnumVariant position it would be bad, because
- // we have only 1 object and can only keep of mEnumVARIANT position once
-
// Children already cached via QI to IEnumVARIANT
__try {
*aNumElementsFetched = 0;
- PRInt32 numChildren;
- GetChildCount(&numChildren);
+ if (aNumElementsRequested <= 0 || !aPVar)
+ return E_INVALIDARG;
+
+ if (mEnumVARIANTPosition == kIEnumVariantDisconnected)
+ return CO_E_OBJNOTCONNECTED;
+
+ nsCOMPtr<nsIAccessible> traversedAcc;
+ nsresult rv = GetChildAt(mEnumVARIANTPosition, getter_AddRefs(traversedAcc));
+ if (!traversedAcc)
+ return S_FALSE;
- if (aNumElementsRequested <= 0 || !pvar ||
- mEnumVARIANTPosition >= numChildren) {
- return E_FAIL;
+ for (PRUint32 i = 0; i < aNumElementsRequested; i++) {
+ VariantInit(&aPVar[i]);
+
+ aPVar[i].pdispVal = NativeAccessible(traversedAcc);
+ aPVar[i].vt = VT_DISPATCH;
+ (*aNumElementsFetched)++;
+
+ nsCOMPtr<nsIAccessible> nextAcc;
+ traversedAcc->GetNextSibling(getter_AddRefs(nextAcc));
+ if (!nextAcc)
+ break;
+
+ traversedAcc = nextAcc;
}
- VARIANT varStart;
- VariantInit(&varStart);
- varStart.lVal = CHILDID_SELF;
- varStart.vt = VT_I4;
-
- accNavigate(NAVDIR_FIRSTCHILD, varStart, &pvar[0]);
+ mEnumVARIANTPosition += *aNumElementsFetched;
+ return (*aNumElementsFetched) < aNumElementsRequested ? S_FALSE : S_OK;
- for (long childIndex = 0; pvar[*aNumElementsFetched].vt == VT_DISPATCH; ++childIndex) {
- PRBool wasAccessibleFetched = PR_FALSE;
- nsAccessibleWrap *msaaAccessible =
- static_cast<nsAccessibleWrap*>(pvar[*aNumElementsFetched].pdispVal);
- if (!msaaAccessible)
- break;
- if (childIndex >= mEnumVARIANTPosition) {
- if (++*aNumElementsFetched >= aNumElementsRequested)
- break;
- wasAccessibleFetched = PR_TRUE;
- }
- msaaAccessible->accNavigate(NAVDIR_NEXT, varStart, &pvar[*aNumElementsFetched] );
- if (!wasAccessibleFetched)
- msaaAccessible->nsAccessNode::Release(); // this accessible will not be received by the caller
- }
-
- mEnumVARIANTPosition += static_cast<PRUint16>(*aNumElementsFetched);
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
- return NOERROR;
+ return E_FAIL;
}
STDMETHODIMP
nsAccessibleWrap::Skip(ULONG aNumElements)
{
__try {
- mEnumVARIANTPosition += static_cast<PRUint16>(aNumElements);
+ if (mEnumVARIANTPosition == kIEnumVariantDisconnected)
+ return CO_E_OBJNOTCONNECTED;
+
+ mEnumVARIANTPosition += aNumElements;
PRInt32 numChildren;
GetChildCount(&numChildren);
if (mEnumVARIANTPosition > numChildren)
{
mEnumVARIANTPosition = numChildren;
return S_FALSE;
@@ -1147,18 +1155,36 @@ nsAccessibleWrap::Skip(ULONG aNumElement
STDMETHODIMP
nsAccessibleWrap::Reset(void)
{
mEnumVARIANTPosition = 0;
return NOERROR;
}
+STDMETHODIMP
+nsAccessibleWrap::Clone(IEnumVARIANT FAR* FAR* ppenum)
+{
+__try {
+ *ppenum = nsnull;
+
+ nsCOMPtr<nsIArray> childArray;
+ nsresult rv = GetChildren(getter_AddRefs(childArray));
-// IAccessible2
+ *ppenum = new AccessibleEnumerator(childArray);
+ if (!*ppenum)
+ return E_OUTOFMEMORY;
+ NS_ADDREF(*ppenum);
+
+} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+ return NOERROR;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccessibleWrap. IAccessible2
STDMETHODIMP
nsAccessibleWrap::get_nRelations(long *aNRelations)
{
__try {
PRUint32 count = 0;
nsresult rv = GetRelationsCount(&count);
*aNRelations = count;
@@ -1553,99 +1579,22 @@ nsAccessibleWrap::get_attributes(BSTR *a
__try {
*aAttributes = NULL;
nsCOMPtr<nsIPersistentProperties> attributes;
nsresult rv = GetAttributes(getter_AddRefs(attributes));
if (NS_FAILED(rv))
return GetHRESULT(rv);
- if (!attributes)
- return S_FALSE;
-
- nsCOMPtr<nsISimpleEnumerator> propEnum;
- attributes->Enumerate(getter_AddRefs(propEnum));
- if (!propEnum)
- return E_FAIL;
-
- nsAutoString strAttrs;
-
- const char kCharsToEscape[] = ":;=,\\";
-
- PRBool hasMore = PR_FALSE;
- while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
- nsCOMPtr<nsISupports> propSupports;
- propEnum->GetNext(getter_AddRefs(propSupports));
-
- nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(propSupports));
- if (!propElem)
- return E_FAIL;
-
- nsCAutoString name;
- rv = propElem->GetKey(name);
- if (NS_FAILED(rv))
- return GetHRESULT(rv);
-
- PRUint32 offset = 0;
- while ((offset = name.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
- name.Insert('\\', offset);
- offset += 2;
- }
-
- nsAutoString value;
- rv = propElem->GetValue(value);
- if (NS_FAILED(rv))
- return E_FAIL;
-
- offset = 0;
- while ((offset = value.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
- value.Insert('\\', offset);
- offset += 2;
- }
-
- AppendUTF8toUTF16(name, strAttrs);
- strAttrs.Append(':');
- strAttrs.Append(value);
- strAttrs.Append(';');
- }
-
- if (strAttrs.IsEmpty())
- return S_FALSE;
-
- *aAttributes = ::SysAllocStringLen(strAttrs.get(), strAttrs.Length());
- return *aAttributes ? S_OK : E_OUTOFMEMORY;
+ return ConvertToIA2Attributes(attributes, aAttributes);
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
return E_FAIL;
}
-STDMETHODIMP
-nsAccessibleWrap::Clone(IEnumVARIANT FAR* FAR* ppenum)
-{
-__try {
- // Clone could be bad, the cloned items aren't tracked for shutdown
- // Then again, as long as the client releases the items in time, we're okay
- *ppenum = nsnull;
-
- nsAccessibleWrap *accessibleWrap = new nsAccessibleWrap(mDOMNode, mWeakShell);
- if (!accessibleWrap)
- return E_FAIL;
-
- IAccessible *msaaAccessible = static_cast<IAccessible*>(accessibleWrap);
- msaaAccessible->AddRef();
- QueryInterface(IID_IEnumVARIANT, (void**)ppenum);
- if (*ppenum)
- (*ppenum)->Skip(mEnumVARIANTPosition); // QI addrefed
- msaaAccessible->Release();
-
-} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
- return NOERROR;
-}
-
-
// For IDispatch support
STDMETHODIMP
nsAccessibleWrap::GetTypeInfoCount(UINT *p)
{
*p = 0;
return E_NOTIMPL;
}
@@ -1685,16 +1634,22 @@ NS_IMETHODIMP nsAccessibleWrap::GetNativ
NS_IMETHODIMP
nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
{
NS_ENSURE_ARG(aEvent);
nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
NS_ENSURE_SUCCESS(rv, rv);
+ return FirePlatformEvent(aEvent);
+}
+
+nsresult
+nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent *aEvent)
+{
PRUint32 eventType = 0;
aEvent->GetEventType(&eventType);
NS_ENSURE_TRUE(eventType > 0 &&
eventType < nsIAccessibleEvent::EVENT_LAST_ENTRY,
NS_ERROR_FAILURE);
PRUint32 winLastEntry = gWinEventMap[nsIAccessibleEvent::EVENT_LAST_ENTRY];
@@ -1740,16 +1695,21 @@ nsAccessibleWrap::FireAccessibleEvent(ns
// scrollbars and the child window contains only the client area.
// Details of the 2 window system:
// * Scrollbar window: caret drawing window & return value for WindowFromAccessibleObject()
// * Client area window: text drawing window & MSAA event window
// Fire MSAA event for client area window.
NotifyWinEvent(winEvent, hWnd, OBJID_CLIENT, childID);
+ // If the accessible children are changed then drop the IEnumVariant current
+ // position of the accessible.
+ if (eventType == nsIAccessibleEvent::EVENT_REORDER)
+ UnattachIEnumVariant();
+
return NS_OK;
}
//------- Helper methods ---------
PRInt32 nsAccessibleWrap::GetChildIDFor(nsIAccessible* aAccessible)
{
// A child ID of the window is required, when we use NotifyWinEvent,
@@ -1811,16 +1771,79 @@ nsAccessibleWrap::GetHWNDFor(nsIAccessib
accessibleDoc->GetWindowHandle(&handle);
hWnd = (HWND)handle;
}
return hWnd;
}
+HRESULT
+nsAccessibleWrap::ConvertToIA2Attributes(nsIPersistentProperties *aAttributes,
+ BSTR *aIA2Attributes)
+{
+ *aIA2Attributes = NULL;
+
+ // The format is name:value;name:value; with \ for escaping these
+ // characters ":;=,\".
+
+ if (!aAttributes)
+ return S_FALSE;
+
+ nsCOMPtr<nsISimpleEnumerator> propEnum;
+ aAttributes->Enumerate(getter_AddRefs(propEnum));
+ if (!propEnum)
+ return E_FAIL;
+
+ nsAutoString strAttrs;
+
+ const char kCharsToEscape[] = ":;=,\\";
+
+ PRBool hasMore = PR_FALSE;
+ while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
+ nsCOMPtr<nsISupports> propSupports;
+ propEnum->GetNext(getter_AddRefs(propSupports));
+
+ nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(propSupports));
+ if (!propElem)
+ return E_FAIL;
+
+ nsCAutoString name;
+ if (NS_FAILED(propElem->GetKey(name)))
+ return E_FAIL;
+
+ PRUint32 offset = 0;
+ while ((offset = name.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
+ name.Insert('\\', offset);
+ offset += 2;
+ }
+
+ nsAutoString value;
+ if (NS_FAILED(propElem->GetValue(value)))
+ return E_FAIL;
+
+ offset = 0;
+ while ((offset = value.FindCharInSet(kCharsToEscape, offset)) != kNotFound) {
+ value.Insert('\\', offset);
+ offset += 2;
+ }
+
+ AppendUTF8toUTF16(name, strAttrs);
+ strAttrs.Append(':');
+ strAttrs.Append(value);
+ strAttrs.Append(';');
+ }
+
+ if (strAttrs.IsEmpty())
+ return S_FALSE;
+
+ *aIA2Attributes = ::SysAllocStringLen(strAttrs.get(), strAttrs.Length());
+ return *aIA2Attributes ? S_OK : E_OUTOFMEMORY;
+}
+
IDispatch *nsAccessibleWrap::NativeAccessible(nsIAccessible *aXPAccessible)
{
if (!aXPAccessible) {
NS_WARNING("Not passing in an aXPAccessible");
return NULL;
}
nsCOMPtr<nsIAccessibleWin32Object> accObject(do_QueryInterface(aXPAccessible));
@@ -1836,16 +1859,22 @@ IDispatch *nsAccessibleWrap::NativeAcces
}
IAccessible *msaaAccessible;
aXPAccessible->GetNativeInterface((void**)&msaaAccessible);
return static_cast<IDispatch*>(msaaAccessible);
}
+void
+nsAccessibleWrap::UnattachIEnumVariant()
+{
+ if (mEnumVARIANTPosition > 0)
+ mEnumVARIANTPosition = kIEnumVariantDisconnected;
+}
void nsAccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild, nsIAccessible **aXPAccessible)
{
*aXPAccessible = nsnull;
if (!mWeakShell)
return; // Fail, we don't want to do anything after we've shut down
// if its us real easy - this seems to always be the case
--- a/accessible/src/msaa/nsAccessibleWrap.h
+++ b/accessible/src/msaa/nsAccessibleWrap.h
@@ -256,17 +256,21 @@ class nsAccessibleWrap : public nsAccess
/* [retval][out] */ long *indexInParent);
virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_locale(
/* [retval][out] */ IA2Locale *locale);
virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_attributes(
/* [retval][out] */ BSTR *attributes);
- public: // IEnumVariantMethods
+ public: // IEnumVariant
+ // If there are two clients using this at the same time, and they are
+ // each using a different mEnumVariant position it would be bad, because
+ // we have only 1 object and can only keep of mEnumVARIANT position once.
+
virtual /* [local] */ HRESULT STDMETHODCALLTYPE Next(
/* [in] */ ULONG celt,
/* [length_is][size_is][out] */ VARIANT __RPC_FAR *rgVar,
/* [out] */ ULONG __RPC_FAR *pCeltFetched);
virtual HRESULT STDMETHODCALLTYPE Skip(
/* [in] */ ULONG celt);
@@ -287,16 +291,18 @@ class nsAccessibleWrap : public nsAccess
VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
// nsPIAccessible
NS_IMETHOD FireAccessibleEvent(nsIAccessibleEvent *aEvent);
// Helper methods
static PRInt32 GetChildIDFor(nsIAccessible* aAccessible);
static HWND GetHWNDFor(nsIAccessible *aAccessible);
+ static HRESULT ConvertToIA2Attributes(nsIPersistentProperties *aAttributes,
+ BSTR *aIA2Attributes);
/**
* System caret support: update the Windows caret position.
* The system caret works more universally than the MSAA caret
* For example, Window-Eyes, JAWS, ZoomText and Windows Tablet Edition use it
* We will use an invisible system caret.
* Gecko is still responsible for drawing its own caret
*/
@@ -307,21 +313,30 @@ class nsAccessibleWrap : public nsAccess
// NT4 does not have the oleacc that defines these methods. So we define copies here that automatically
// load the library only if needed.
static STDMETHODIMP AccessibleObjectFromWindow(HWND hwnd,DWORD dwObjectID,REFIID riid,void **ppvObject);
static STDMETHODIMP NotifyWinEvent(DWORD event,HWND hwnd,LONG idObjectType,LONG idObject);
static IDispatch *NativeAccessible(nsIAccessible *aXPAccessible);
+ /**
+ * Drops the IEnumVariant current position so that navigation methods
+ * Next() and Skip() doesn't work until Reset() method is called. The method
+ * is used when children of the accessible are changed.
+ */
+ void UnattachIEnumVariant();
+
protected:
+ virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent);
+
// mEnumVARIANTPosition not the current accessible's position, but a "cursor" of
// where we are in the current list of children, with respect to
// nsIEnumVariant::Reset(), Skip() and Next().
- PRUint16 mEnumVARIANTPosition;
+ PRInt32 mEnumVARIANTPosition;
enum navRelations {
NAVRELATION_CONTROLLED_BY = 0x1000,
NAVRELATION_CONTROLLER_FOR = 0x1001,
NAVRELATION_LABEL_FOR = 0x1002,
NAVRELATION_LABELLED_BY = 0x1003,
NAVRELATION_MEMBER_OF = 0x1004,
NAVRELATION_NODE_CHILD_OF = 0x1005,
--- a/accessible/src/other/nsAccessibleWrap.h
+++ b/accessible/src/other/nsAccessibleWrap.h
@@ -46,11 +46,16 @@
#include "nsCOMPtr.h"
#include "nsAccessible.h"
class nsAccessibleWrap : public nsAccessible
{
public: // construction, destruction
nsAccessibleWrap(nsIDOMNode*, nsIWeakReference *aShell);
virtual ~nsAccessibleWrap();
+
+ protected:
+ virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent) {
+ return NS_OK;
+ }
};
#endif
--- a/accessible/src/xul/nsXULSelectAccessible.cpp
+++ b/accessible/src/xul/nsXULSelectAccessible.cpp
@@ -835,21 +835,23 @@ nsXULListitemAccessible::GetListAccessib
nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
do_QueryInterface(mDOMNode);
if (!listItem)
return nsnull;
nsCOMPtr<nsIDOMXULSelectControlElement> list;
listItem->GetControl(getter_AddRefs(list));
- if (!list)
+
+ nsCOMPtr<nsIDOMNode> listNode(do_QueryInterface(list));
+ if (!listNode)
return nsnull;
nsIAccessible *listAcc = nsnull;
- GetAccService()->GetAccessibleInWeakShell(list, mWeakShell, &listAcc);
+ GetAccService()->GetAccessibleInWeakShell(listNode, mWeakShell, &listAcc);
return listAcc;
}
////////////////////////////////////////////////////////////////////////////////
// nsXULListitemAccessible. nsIAccessible
/**
* If there is a Listcell as a child ( not anonymous ) use it, otherwise
--- a/accessible/src/xul/nsXULTreeAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeAccessible.cpp
@@ -631,32 +631,34 @@ nsXULTreeAccessible::InvalidateCache(PRI
// treeViewInvalidated(in long aStartRow, in long aEndRow,
// in long aStartCol, in long aEndCol);
NS_IMETHODIMP
nsXULTreeAccessible::TreeViewInvalidated(PRInt32 aStartRow, PRInt32 aEndRow,
PRInt32 aStartCol, PRInt32 aEndCol)
{
NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
- PRInt32 endRow = aEndRow, endCol = aEndCol;
+ PRInt32 endRow = aEndRow;
nsresult rv;
if (endRow == -1) {
PRInt32 rowCount = 0;
rv = mTreeView->GetRowCount(&rowCount);
NS_ENSURE_SUCCESS(rv, rv);
endRow = rowCount - 1;
}
nsCOMPtr<nsITreeColumns> treeColumns;
mTree->GetColumns(getter_AddRefs(treeColumns));
NS_ENSURE_STATE(treeColumns);
#ifdef MOZ_ACCESSIBILITY_ATK
+ PRInt32 endCol = aEndCol;
+
if (endCol == -1) {
PRInt32 colCount = 0;
rv = treeColumns->GetCount(&colCount);
NS_ENSURE_SUCCESS(rv, rv);
endCol = colCount - 1;
}
#else
@@ -700,26 +702,58 @@ nsXULTreeAccessible::TreeViewInvalidated
}
}
}
}
return NS_OK;
}
+// void nsIAccessibleTreeCache::treeViewChanged();
+NS_IMETHODIMP
+nsXULTreeAccessible::TreeViewChanged()
+{
+ if (!mTree)
+ return NS_ERROR_FAILURE;
+
+ // Fire only notification destroy/create events on accessible tree to lie to
+ // AT because it should be expensive to fire destroy events for each tree item
+ // in cache.
+ nsCOMPtr<nsIAccessibleEvent> eventDestroy =
+ new nsAccEvent(nsIAccessibleEvent::EVENT_DOM_DESTROY,
+ this, PR_FALSE);
+ NS_ENSURE_TRUE(eventDestroy, NS_ERROR_OUT_OF_MEMORY);
+
+ nsresult rv = FirePlatformEvent(eventDestroy);
+
+ ClearCache(*mAccessNodeCache);
+
+ mTree->GetView(getter_AddRefs(mTreeView));
+
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIAccessibleEvent> eventCreate =
+ new nsAccEvent(nsIAccessibleEvent::EVENT_DOM_CREATE,
+ this, PR_FALSE);
+ NS_ENSURE_TRUE(eventCreate, NS_ERROR_OUT_OF_MEMORY);
+
+ return FirePlatformEvent(eventCreate);
+}
+
nsresult nsXULTreeAccessible::GetColumnCount(nsITreeBoxObject* aBoxObject, PRInt32* aCount)
{
NS_ENSURE_TRUE(aBoxObject, NS_ERROR_FAILURE);
nsCOMPtr<nsITreeColumns> treeColumns;
aBoxObject->GetColumns(getter_AddRefs(treeColumns));
NS_ENSURE_TRUE(treeColumns, NS_ERROR_FAILURE);
return treeColumns->GetCount(aCount);
}
-// ---------- nsXULTreeitemAccessible ----------
+////////////////////////////////////////////////////////////////////////////////
+// nsXULTreeitemAccessible
nsXULTreeitemAccessible::nsXULTreeitemAccessible(nsIAccessible *aParent, nsIDOMNode *aDOMNode, nsIWeakReference *aShell, PRInt32 aRow, nsITreeColumn* aColumn)
: nsLeafAccessible(aDOMNode, aShell)
{
mParent = aParent; // xxx todo: do we need this? We already have mParent on nsAccessible
nsXULTreeAccessible::GetTreeBoxObject(aDOMNode, getter_AddRefs(mTree));
if (mTree)
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -42,27 +42,40 @@ srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = accessible
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
moz.png \
+ nsIAccessible_name.css \
+ nsIAccessible_name.xbl \
test_aria_activedescendant.html \
+ test_aria_role_article.html \
test_bug368835.xul \
test_bug420863.html \
+ test_cssattrs.html \
test_groupattrs.xul \
- test_table_indexes.html \
+ $(warning test_table_indexes.html temporarily disabled) \
+ test_nsIAccessible_name.html \
+ test_nsIAccessible_name.xul \
test_nsIAccessibleTable_1.html \
test_nsIAccessibleTable_2.html \
test_nsIAccessibleTable_3.html \
test_nsIAccessibleTable_4.html \
test_nsIAccessibleTable_listboxes.xul \
+ test_nsIAccessibleDocument.html \
test_nsIAccessibleHyperLink.html \
test_nsIAccessibleHyperLink.xul \
test_nsIAccessibleHyperText.html \
test_nsIAccessibleImage.html \
+ test_nsOuterDocAccessible.html \
+ test_textattrs.html \
+ test_textboxes.html \
+ test_textboxes.xul \
+ testTextboxes.js \
test_bug428479.html \
+ test_bug429285.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/nsIAccessible_name.css
@@ -0,0 +1,11 @@
+box.first {
+ -moz-binding: url('chrome://mochikit/content/a11y/accessible/nsIAccessible_name.xbl#first');
+}
+
+.second {
+ -moz-binding: url('chrome://mochikit/content/a11y/accessible/nsIAccessible_name.xbl#second');
+}
+
+.third {
+ -moz-binding: url('chrome://mochikit/content/a11y/accessible/nsIAccessible_name.xbl#third');
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/nsIAccessible_name.xbl
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+
+<bindings xmlns="http://www.mozilla.org/xbl"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <binding id="first">
+ <content>
+ <xul:textbox anonid="labeled" class="bottom"/>
+ <xul:label control="labeled" value="Label"/>
+ <children/>
+ </content>
+ </binding>
+
+ <binding id="second">
+ <content>
+ <xul:box class="first">
+ <xul:label control="toplabeled" value="Top textbox"/>
+ <xul:textbox anonid="toplabeled" class="top"/>
+ </xul:box>
+ <children/>
+ </content>
+ </binding>
+
+</bindings>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/testTextboxes.js
@@ -0,0 +1,93 @@
+const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+
+// Mapping needed state flags for easier handling.
+const state_focusable =
+ Components.interfaces.nsIAccessibleStates.STATE_FOCUSABLE;
+const state_focused =
+ Components.interfaces.nsIAccessibleStates.STATE_FOCUSED;
+const state_readonly =
+ Components.interfaces.nsIAccessibleStates.STATE_READONLY;
+
+const ext_state_multi_line =
+ Components.interfaces.nsIAccessibleStates.EXT_STATE_MULTI_LINE;
+const ext_state_editable =
+ Components.interfaces.nsIAccessibleStates.EXT_STATE_EDITABLE;
+const ext_state_required =
+ Components.interfaces.nsIAccessibleStates.STATE_REQUIRED;
+const ext_state_invalid =
+ Components.interfaces.nsIAccessibleStates.STATE_INVALID;
+
+// Mapping needed final roles
+const role_entry = Components.interfaces.nsIAccessibleRole.ROLE_ENTRY;
+const role_password_text =
+ Components.interfaces.nsIAccessibleRole.ROLE_PASSWORD_TEXT;
+
+var gAccRetrieval = null;
+
+function testValue(aID, aAcc, aValue, aRole)
+{
+ if (aRole == role_password_text) {
+ var value;
+ try {
+ value = aAcc.value;
+ do_throw("We do not want a value on " + aID + "!");
+ } catch(e) {
+ is(e.result, Components.results.NS_ERROR_FAILURE,
+ "Wrong return value for getValue on " + aID + "!");
+ }
+ } else
+ is(aAcc.value, aValue, "Wrong value for " + aID + "!");
+}
+
+function testStates(aID, aAcc, aState, aExtraState, aAbsentState)
+{
+ var state = {}, extraState = {};
+ aAcc.getFinalState(state, extraState);
+ is(state.value & aState, aState, "wrong state bits for " + aID + "!");
+ is(extraState.value & aExtraState, aExtraState,
+ "wrong extraState bits for " + aID + "!");
+ if (aAbsentState != 0)
+ is(state.value & aAbsentState, 0, "state bits should not be present in ID "
+ + aID + "!");
+ if (state.value & state_readonly)
+ // if state is readonly, ext state must not be ext_state_editable.
+ is(extraState.value & ext_state_editable, 0,
+ "Read-only " + aID + " cannot be editable!");
+}
+
+function testAction(aID, aAcc, aNumActions, aActionName, aActionDescription)
+{
+ var numActions = aAcc.numActions;
+ is(numActions, aNumActions, "Wrong number of actions for " + aID + "!");
+
+ if (numActions != 0) {
+ // Test first action. Normally only 1 should be present.
+ is(aAcc.getActionName(0), aActionName,
+ "Wrong name of action for " + aID + "!");
+ is(aAcc.getActionDescription(0), aActionDescription,
+ "Wrong description of action for " + aID + "!");
+ }
+}
+
+function testThis(aID, aName, aValue, aDescription, aRole, aState,
+ aExtraState, aAbsentState, aNumActions, aActionName,
+ aActionDescription)
+{
+ var elem = document.getElementById(aID);
+ var acc = null;
+ try {
+ acc = gAccRetrieval.getAccessibleFor(elem);
+ } catch(e) {}
+ ok(acc, "No accessible for " + aID + "!");
+
+ if (acc) {
+ is(acc.name, aName, "Wrong name for " + aID + "!");
+ testValue(aID, acc, aValue, aRole);
+ is(acc.description, aDescription, "Wrong description for " + aID + "!");
+ is(acc.role, aRole, "Wrong role for " + aID + "!");
+
+ testStates(aID, acc, aState, aExtraState, aAbsentState);
+
+ testAction(aID, acc, aNumActions, aActionName, aActionDescription);
+ }
+}
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_aria_role_article.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=429666
+-->
+<head>
+ <title>Expose ROLE_DOCUMENT for ARIA landmarks that inherit from document chrome tests</title>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript">
+ function doTest()
+ {
+ var accRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(Components.interfaces.nsIAccessibleRetrieval);
+
+ // Test article exposed as document
+ var articleElement = document.getElementById("testArticle");
+ var articleAcc = null;
+ try {
+ articleAcc = accRetrieval.getAccessibleFor(articleElement);
+ } catch(e) { }
+ ok(articleAcc, "no accessible for article!");
+ if (articleAcc) {
+ is(articleAcc.finalRole,
+ Components.interfaces.nsIAccessibleRole.ROLE_DOCUMENT,
+ "Wrong role for article!");
+ is(articleAcc.name, "Test article", "Wrong name for article!");
+ }
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=429666">Mozilla Bug 429666</a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+ <div id="testArticle" role="article" title="Test article">
+ <p>This is a paragraph inside the article.</p>
+ </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_bug429285.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=429285
+-->
+<head>
+ <title>Propagate aria-disabled state to descendants chrome tests</title>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript">
+ // Mapping needed state flags for easier handling.
+ const state_disabled =
+ Components.interfaces.nsIAccessibleStates.STATE_UNAVAILABLE;
+ const state_focusable =
+ Components.interfaces.nsIAccessibleStates.STATE_FOCUSABLE;
+
+ const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+ const nsIAccessible = Components.interfaces.nsIAccessible;
+
+ var gAccRetrieval = null;
+
+ function testChildren(aID, aAcc)
+ {
+ // Check state of aAcc first.
+ var state = {}, extraState = {};
+ aAcc.getFinalState(state, extraState);
+ if (state.value & state_focusable) {
+ is(state.value & state_disabled, state_disabled,
+ "Wrong disabled state bit for " + aID + "!");
+ }
+
+ // Iterate over its children to see if they are disabled, too.
+ var children = null;
+ try {
+ children = aAcc.children;
+ } catch(e) {}
+ ok(children, "Could not get children for " + aID +"!");
+
+ if (children) {
+ for (var i=0; i<children.length; i++) {
+ var childAcc = children.queryElementAt(i, nsIAccessible);
+ // Test and recurse over its children as well.
+ testChildren(childAcc.name, childAcc);
+ }
+ }
+ }
+
+ function doTest()
+ {
+ gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(nsIAccessibleRetrieval);
+
+ var groupItem = document.getElementById("group");
+ var groupAcc = null;
+ try {
+ groupAcc = gAccRetrieval.getAccessibleFor(groupItem);
+ } catch (e) {}
+ ok (groupAcc,
+ "No accessible for group element!");
+
+ if (groupAcc) {
+ var state = {}, extraState = {};
+ groupAcc.getFinalState(state, extraState);
+ is(state.value & state_disabled, state_disabled,
+ "Wrong disabled state bit for Group element!");
+ testChildren("group", groupAcc);
+ }
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=429285"
+ title="Propagate aria-disabled to descendants">
+ Mozilla Bug 429285
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <div id="group" role="group" aria-disabled="true">
+ <button>hi</button>
+ <div tabindex="0" role="listbox" aria-activedescendant="item1">
+ <div role="option" id="item1">Item 1</div>
+ <div role="option" id="item2">Item 2</div>
+ <div role="option" id="item3">Item 3</div>
+ <div role="option" id="item4">Item 4</div>
+ </div>
+ <div role="slider" tabindex="0">A slider</div>
+ </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_cssattrs.html
@@ -0,0 +1,85 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=439566
+-->
+<head>
+ <title>CSS-like attributes tests</title>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript">
+ const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+
+ var gAccRetrieval = null;
+
+ function testAttr(aID, aName, aValue)
+ {
+ var acc = null;
+ try {
+ acc = gAccRetrieval.getAccessibleFor(document.getElementById(aID));
+ } catch(e) { }
+
+ if (!acc) {
+ ok(false, "Can't get accessible object for " + aID);
+ return;
+ }
+
+ var attrs = null;
+ try {
+ attrs = acc.attributes;
+ } catch(e) { }
+
+ if (!attrs) {
+ ok(false, "Can't get accessible attributes for " + aID);
+ return;
+ }
+
+ is(attrs.getStringProperty(aName), aValue,
+ "Accessible with ID " + aID + " has wrong attribute value");
+ }
+
+ function doTest()
+ {
+ gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(nsIAccessibleRetrieval);
+
+ testAttr("span", "display", "inline");
+ testAttr("div", "display", "block");
+ testAttr("p", "display", "block");
+ testAttr("input", "display", "inline");
+ testAttr("table", "display", "table");
+ testAttr("tr", "display", "table-row");
+ testAttr("td", "display", "table-cell");
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=439566"
+ title="Include the css display property as an IAccessible2 object attribute">
+ Mozilla Bug 439566
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <span id="span" role="group">It's span</span>
+ <div id="div">It's div</div>
+ <p id="p">It's paragraph"</p>
+ <input id="input"/>
+ <table id="table">
+ <tr id="tr" role="group">
+ <td id="td">td</td>
+ </tr>
+ </table>
+</body>
+</html>
--- a/accessible/tests/mochitest/test_groupattrs.xul
+++ b/accessible/tests/mochitest/test_groupattrs.xul
@@ -16,58 +16,135 @@
function accAttributes(aId)
{
this.getAttribute = function getAttribute(aName)
{
try {
return this.mAttrs.getStringProperty(aName);
} catch (e) {
- alert(e);
return "";
}
}
this.mAcc = gAccService.getAccessibleFor(document.getElementById(aId));
- this.mAttrs = this.mAcc.attributes;
+ ok(this.mAcc, "Can't get accessible for " + aId);
+
+ if (this.mAcc)
+ this.mAttrs = this.mAcc.attributes;
+ }
+
+ function testGroupAttrs(aID, aPosInSet, aSetSize, aLevel)
+ {
+ var attrs = new accAttributes(aID);
+ is(attrs.getAttribute("posinset"), aPosInSet, "Wrong posinset on " + aID);
+ is(attrs.getAttribute("setsize"), aSetSize, "Wrong setsize on " + aID);
+ if (aLevel)
+ is(attrs.getAttribute("level"), aLevel, "Wrong level on " + aID);
}
function doTest()
{
// Activate accessibility, otherwise events aren't fired.
gAccService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
getService(Components.interfaces.nsIAccessibleRetrieval);
- var attrs = new accAttributes("item1");
- is(attrs.getAttribute("posinset"), "1", "Wrong posinset on item1.");
- is(attrs.getAttribute("setsize"), "2", "Wrong setsize on item1.");
+ //////////////////////////////////////////////////////////////////////////
+ // xul:listbox (bug 417317)
+ testGroupAttrs("item1", "1", "2");
+ testGroupAttrs("item2", "2", "2");
+
+ //////////////////////////////////////////////////////////////////////////
+ // xul:menu (bug 443881)
+ var menu1 = document.getElementById("menu_item1");
+ menu1.open = true;
+
+ window.setTimeout(function() {
+ var menu2 = document.getElementById("menu_item2");
+ menu2.open = true;
- attrs = new accAttributes("item2");
- is(attrs.getAttribute("posinset"), "2", "Wrong posinset on item2.");
- is(attrs.getAttribute("setsize"), "2", "Wrong setsize on item2.");
+ window.setTimeout(function() {
+ testGroupAttrs("menu_item1.1", "1", "1");
+ testGroupAttrs("menu_item1.2", "1", "3");
+ testGroupAttrs("menu_item1.4", "2", "3");
+ testGroupAttrs("menu_item2", "3", "3");
+ testGroupAttrs("menu_item2.1", "1", "2", "1");
+ testGroupAttrs("menu_item2.2", "2", "2", "1");
- SimpleTest.finish();
+ SimpleTest.finish();
+ }, 0);
+ }, 0);
+
+ //////////////////////////////////////////////////////////////////////////
+ // ARIA menu (bug 441888)
+ testGroupAttrs("aria-menuitem", "1", "3");
+ testGroupAttrs("aria-menuitemcheckbox", "2", "3");
+ testGroupAttrs("aria-menuitemradio", "3", "3");
+ testGroupAttrs("aria-menuitem2", "1", "1");
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=417317"
title="Certain types of LISTITEM accessibles no longer get attributes set like 'x of y', regression from fix for bug 389926">
Mozilla Bug 417317
- </a>
+ </a><br/>
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=443881"
+ title="take into account separators in xul menus when group attributes are calculating">
+ Mozilla Bug 443881
+ </a><br/>
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=441888"
+ title="ARIA checked menu items are not included in the total list of menu items">
+ Mozilla Bug 441888
+ </a><br/>
+
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<listbox>
<listitem label="item1" id="item1"/>
<listitem label="item2" id="item2"/>
</listbox>
+
+ <menubar>
+ <menu label="item1" id="menu_item1">
+ <menupopup>
+ <menuitem label="item1.1" id="menu_item1.1"/>
+ <menuseparator/>
+ <menuitem label="item1.2" id="menu_item1.2"/>
+ <menuitem label="item1.3" hidden="true"/>
+ <menuitem label="item1.4" id="menu_item1.4"/>
+ <menu label="item2" id="menu_item2">
+ <menupopup>
+ <menuitem label="item2.1" id="menu_item2.1"/>
+ <menuitem label="item2.2" id="menu_item2.2"/>
+ </menupopup>
+ </menu>
+ </menupopup>
+ </menu>
+ </menubar>
+
+ <vbox>
+ <description role="menuitem" id="aria-menuitem"
+ value="conventional menuitem"/>
+ <description role="menuitemcheckbox" id="aria-menuitemcheckbox"
+ value="conventional checkbox menuitem"/>
+ <description role="menuitem" hidden="true"/>
+ <description role="menuitemradio" id="aria-menuitemradio"
+ value="conventional radio menuitem"/>
+ <description role="separator"
+ value="conventional separator"/>
+ <description role="menuitem" id="aria-menuitem2"
+ value="conventional menuitem"/>
+ </vbox>
</window>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_nsIAccessibleDocument.html
@@ -0,0 +1,111 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=441737
+-->
+<head>
+ <title>nsIAccessibleDocument chrome tests</title>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript">
+ const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+ const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
+ const nsIAccessibleDocument = Components.interfaces.nsIAccessibleDocument;
+ const nsIDOMDocument = Components.interfaces.nsIDOMDocument;
+ const nsIDOMWindow = Components.interfaces.nsIDOMWindow;
+
+ // needed state flag
+ const state_focusable =
+ Components.interfaces.nsIAccessibleStates.STATE_FOCUSABLE;
+ const state_readonly =
+ Components.interfaces.nsIAccessibleStates.STATE_READONLY;
+
+ var gAccRetrieval = null;
+
+ function doTest()
+ {
+ gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(nsIAccessibleRetrieval);
+
+ // Get accessible for body tag.
+ var docAcc = null;
+ try {
+ docAcc = gAccRetrieval.getAccessibleFor(document).
+ QueryInterface(nsIAccessibleDocument);
+ } catch(e) {}
+ ok(docAcc, "No accessible with interface for document!");
+
+ if (docAcc) {
+ // nsIAccessible
+ is(docAcc.name, "nsIAccessibleDocument chrome tests",
+ "Name for document accessible not correct!");
+ is(docAcc.role, nsIAccessibleRole.ROLE_DOCUMENT,
+ "Wrong role for document!");
+
+ // check if it is focusable, read-only.
+ var state = {}, extraState = {}
+ docAcc.getFinalState(state, extraState);
+ var desiredStates = (state_focusable | state_readonly);
+ is(state.value & desiredStates, desiredStates,
+ "Wrong state bits for document!");
+
+ // No actions wanted on doc
+ is(docAcc.numActions, 0, "Wrong number of actions for document!");
+
+ // attributes should contain tag:body
+ attributes = docAcc.attributes;
+ is(attributes.getStringProperty("tag"), "BODY",
+ "Wrong attribute on document!");
+
+ // nsIAccessibleDocument
+ is(docAcc.URL, "chrome://mochikit/content/a11y/accessible/test_nsIAccessibleDocument.html",
+ "Wrong URL for document!");
+ is(docAcc.title, "nsIAccessibleDocument chrome tests",
+ "Wrong title for document!");
+ is(docAcc.mimeType, "text/html",
+ "Wrong mime type for document!");
+ // nsDocAccessible::getDocType currently returns NS_ERROR_FAILURE.
+ // See bug 442005. After fixing, please remove this comment and
+ // uncomment the below two lines to enable the test.
+// is(docAcc.docType, "HTML",
+// "Wrong type of document!");
+
+ // Test for correct nsIDOMDocument retrieval.
+ var domDoc = null;
+ try {
+ domDoc = docAcc.document.QueryInterface(nsIDOMDocument);
+ } catch(e) {}
+ ok(domDoc, "no nsIDOMDocument for this doc accessible!");
+ is(domDoc, document, "Document nodes do not match!");
+
+ // Test for correct nsIDOMWindow retrieval.
+ var domWindow = null;
+ try {
+ domWindow = docAcc.window.QueryInterface(nsIDOMWindow);
+ } catch(e) {}
+ ok(domWindow, "no nsIDOMWindow for this doc accessible!");
+ is(domWindow, window, "Window nodes do not match!");
+ }
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=441737"
+ title="nsAccessibleDocument chrome tests">
+ Mozilla Bug 441737
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+</body>
+</html>
--- a/accessible/tests/mochitest/test_nsIAccessibleHyperLink.html
+++ b/accessible/tests/mochitest/test_nsIAccessibleHyperLink.html
@@ -6,16 +6,18 @@ https://bugzilla.mozilla.org/show_bug.cg
<head>
<title>nsIHyperLinkAccessible chrome tests</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript">
+ var gAccRetrieval = null;
+
function testThis(aID, aAcc, aRole, aAnchors, aName, aValid, aStartIndex,
aEndIndex)
{
is(aAcc.finalRole, aRole, "Wrong role for ID " + aID + "!");
is(aAcc.anchorCount, aAnchors, "Wrong number of anchors for ID "
+ aID + "!");
is(aAcc.getAnchor(0).name, aName, "Wrong name for ID "
+ aID + "!");
@@ -31,28 +33,56 @@ https://bugzilla.mozilla.org/show_bug.cg
{
is(aAcc.selected, aSelectedBefore,
"Wrong selected state before focus for ID " + aID + "!");
document.getElementById(aID).focus();
is(aAcc.selected, aSelectedAfter,
"Wrong seleccted state after focus for ID " + aID + "!");
}
- function testStates(aID, aAcc, aState, aExtraState, aAbsentState)
+ function testStates(aID, aAcc, aState, aExtraState, aAbsentState,
+ aShowStateDebugFlag)
{
var state = {}, extraState = {};
aAcc.getFinalState(state, extraState);
+
+ if (aShowStateDebugFlag) {
+ var list = gAccRetrieval.getStringStates(state.value, 0);
+
+ var str = "";
+ for (var i = 0; i < list.length; i++)
+ str += list.item(i) + "\n";
+
+ alert(str);
+ }
+
is(state.value & aState, aState, "Wrong state bits for ID " + aID + "!");
is(extraState.value & aExtraState, aExtraState,
"Wrong extra state bits for ID " + aID + "!");
if (aAbsentState != 0)
is(state.value & aAbsentState, 0, "state bits should not be present in ID "
+ aID + "!");
}
-
+
+ function testAction(aId, aAcc, aActionName)
+ {
+ var numActions = aActionName ? 1 : 0;
+ is(aAcc.numActions, numActions,
+ "Wrong actions number for ID " + aId);
+ try {
+ is(aAcc.getActionName(0), aActionName,
+ "Wrong action name for ID " + aId);
+ } catch (e) {
+ if (numActions)
+ ok(false, "Exception on action name getting for ID " + aId);
+ else
+ ok(true, "Correct action name for ID " + aId);
+ }
+ }
+
function doTest()
{
// Mapping needed state flags for easier handling.
const state_focusable =
Components.interfaces.nsIAccessibleStates.STATE_FOCUSABLE;
const state_focused =
Components.interfaces.nsIAccessibleStates.STATE_FOCUSED;
const state_selectable =
@@ -66,25 +96,25 @@ https://bugzilla.mozilla.org/show_bug.cg
Components.interfaces.nsIAccessibleStates.EXT_STATE_MULTI_LINE;
const ext_state_horizontal =
Components.interfaces.nsIAccessibleStates.EXT_STATE_HORIZONTAL;
const ext_state_required =
Components.interfaces.nsIAccessibleStates.STATE_REQUIRED;
const ext_state_invalid =
Components.interfaces.nsIAccessibleStates.STATE_INVALID;
- var accService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
- getService(Components.interfaces.nsIAccessibleRetrieval);
+ gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(Components.interfaces.nsIAccessibleRetrieval);
//////////////////////////////////////////////////////////////////////////
// normal hyperlink
var normalHyperlinkElement = document.getElementById("NormalHyperlink");
var normalHyperlinkAcc;
try {
- normalHyperlinkAcc = accService.getAccessibleFor(normalHyperlinkElement).
+ normalHyperlinkAcc = gAccRetrieval.getAccessibleFor(normalHyperlinkElement).
QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
} catch(e) {
ok(normalHyperlinkAcc, "no interface for normal hyperlink!");
}
testThis("NormalHyperlink", normalHyperlinkAcc,
Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
"Mozilla Foundation", true, 18, 19);
is(normalHyperlinkAcc.getURI(0).spec, "http://www.mozilla.org/",
@@ -97,40 +127,41 @@ https://bugzilla.mozilla.org/show_bug.cg
(state_focusable | state_focused | state_linked),
(ext_state_horizontal), (0));
//////////////////////////////////////////////////////////////////////////
// ARIA hyperlink
var ariaHyperlinkElement = document.getElementById("AriaHyperlink");
var ariaHyperlinkAcc;
try {
- ariaHyperlinkAcc = accService.getAccessibleFor(ariaHyperlinkElement).
+ ariaHyperlinkAcc = gAccRetrieval.getAccessibleFor(ariaHyperlinkElement).
QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
} catch(e) {
ok(ariaHyperlinkAcc, "no interface for ARIA Hyperlink!");
}
testThis("AriaHyperlink", ariaHyperlinkAcc,
Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
"Mozilla Foundation Home", true, 32, 33);
testStates("AriaHyperlink", ariaHyperlinkAcc,
(state_focusable | state_linked),
(ext_state_horizontal), (0));
testFocus("AriaHyperlink", ariaHyperlinkAcc, false, true);
testStates("AriaHyperlink", ariaHyperlinkAcc,
(state_focusable | state_focused | state_linked),
(ext_state_horizontal), (0));
+ testAction("AriaHyperlink", ariaHyperlinkAcc, "click");
//////////////////////////////////////////////////////////////////////////
// ARIA hyperlink with status invalid
var invalidAriaHyperlinkElement =
document.getElementById("InvalidAriaHyperlink");
var invalidAriaHyperlinkAcc;
try {
invalidAriaHyperlinkAcc =
- accService.getAccessibleFor(invalidAriaHyperlinkElement).
+ gAccRetrieval.getAccessibleFor(invalidAriaHyperlinkElement).
QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
} catch(e) {
ok(invalidAriaHyperlinkAcc, "no interface for invalid ARIA hyperlink!");
}
is(invalidAriaHyperlinkAcc.valid, false, "Should not be valid!");
testStates("InvalidAriaHyperlink", invalidAriaHyperlinkAcc,
(state_linked),
(ext_state_horizontal), (state_focusable));
@@ -139,17 +170,17 @@ https://bugzilla.mozilla.org/show_bug.cg
//////////////////////////////////////////////////////////////////////////
// image map and its link children
var imageMapHyperlinkElement =
document.getElementById("imgmap");
var imageMapHyperlinkAcc;
try {
imageMapHyperlinkAcc =
- accService.getAccessibleFor(imageMapHyperlinkElement).
+ gAccRetrieval.getAccessibleFor(imageMapHyperlinkElement).
QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
} catch(e) {
ok(imageMapHyperlinkAcc, "no Image Map interface!");
}
testThis("imgmap", imageMapHyperlinkAcc,
Components.interfaces.nsIAccessibleRole.ROLE_IMAGE_MAP, 2,
"b", true, 83, 84);
is(imageMapHyperlinkAcc.getURI(0).spec,
@@ -197,83 +228,212 @@ https://bugzilla.mozilla.org/show_bug.cg
(0), (0));
//////////////////////////////////////////////////////////////////////////
// empty hyperlink
var emptyLinkElement = document.getElementById("emptyLink");
var EmptyHLAcc;
try {
EmptyHLAcc =
- accService.getAccessibleFor(emptyLinkElement).
+ gAccRetrieval.getAccessibleFor(emptyLinkElement).
QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
} catch (e) {
ok(EmptyHLAcc, "no interface for empty link!");
}
testThis("emptyLink", EmptyHLAcc,
Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
- "", true, 98, 99);
+ null, true, 98, 99);
testStates("emptyLink", EmptyHLAcc,
(state_focusable | state_linked),
(ext_state_horizontal), (0));
+ testAction("emptyLink", EmptyHLAcc, "jump");
//////////////////////////////////////////////////////////////////////////
// normal hyperlink with embedded span
var hyperlinkElementWithSpan = document.getElementById("LinkWithSpan");
var hyperlinkWithSpanAcc;
try {
hyperlinkWithSpanAcc =
- accService.getAccessibleFor(hyperlinkElementWithSpan).
+ gAccRetrieval.getAccessibleFor(hyperlinkElementWithSpan).
QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
} catch(e) {
ok(hyperlinkWithSpanAcc, "no interface for hyperlink with span!");
}
testThis("LinkWithSpan", hyperlinkWithSpanAcc,
Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
"Heise Online", true, 124, 125);
is(hyperlinkWithSpanAcc.getURI(0).spec, "http://www.heise.de/",
"URI wrong for hyperlinkElementWithSpan!");
testStates("LinkWithSpan", hyperlinkWithSpanAcc,
(state_focusable | state_linked),
(ext_state_horizontal), (0));
testFocus("LinkWithSpan", hyperlinkWithSpanAcc, false, true);
testStates("LinkWithSpan", hyperlinkWithSpanAcc,
(state_focusable | state_focused | state_linked),
(ext_state_horizontal), (0));
+ testAction("LinkWithSpan", hyperlinkWithSpanAcc, "jump");
//////////////////////////////////////////////////////////////////////////
// Named anchor, should never have state_linked
var namedAnchorElement = document.getElementById("namedAnchor");
var namedAnchorAcc;
try {
- namedAnchorAcc = accService.getAccessibleFor(namedAnchorElement).
+ namedAnchorAcc = gAccRetrieval.getAccessibleFor(namedAnchorElement).
QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
} catch(e) {
ok(namedAnchorAcc, "no interface for named anchor!");
}
testThis("namedAnchor", namedAnchorAcc,
Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
"This should never be of state_linked", true, 202, 203);
testStates("namedAnchor", namedAnchorAcc,
(state_selectable),
(ext_state_horizontal), (state_focusable | state_linked));
+ testAction("namedAnchor", namedAnchorAcc, "");
+ //////////////////////////////////////////////////////////////////////////
+ // No link (hasn't any attribute), should never have state_linked
+ var noLinkElement = document.getElementById("noLink");
+ var noLinkAcc;
+ try {
+ noLinkAcc = gAccRetrieval.getAccessibleFor(noLinkElement).
+ QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
+ } catch(e) {
+ ok(noLinkAcc, "no interface for named anchor!");
+ }
+ testThis("noLink", noLinkAcc,
+ Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
+ "This should never be of state_linked", true, 262, 263);
+ testStates("noLink", noLinkAcc,
+ 0,
+ (ext_state_horizontal), (state_focusable | state_linked));
+ testAction("noLink", noLinkAcc, "");
+
+ //////////////////////////////////////////////////////////////////////////
+ // Link with registered 'click' event, should have state_linked
+ var linkWithClickElement = document.getElementById("linkWithClick");
+ var linkWithClickAcc;
+ try {
+ linkWithClickAcc = gAccRetrieval.getAccessibleFor(linkWithClickElement).
+ QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
+ } catch(e) {
+ ok(linkWithClickAcc, "no interface for named anchor!");
+ }
+ testThis("linkWithClick", linkWithClickAcc,
+ Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
+ "This should have state_linked", true, 301, 302);
+ testStates("linkWithClick", linkWithClickAcc,
+ (state_linked),
+ (ext_state_horizontal), 0);
+ testAction("linkWithClick", linkWithClickAcc, "click");
+
+ //////////////////////////////////////////////////////////////////////////
+ // Maps to group links (bug 431615).
+ var linksMapElement = document.getElementById("linksmap");
+ var linksMapAcc;
+ try {
+ linksMapAcc = gAccRetrieval.getAccessibleFor(linksMapElement);
+ } catch(e) { }
+
+ ok(linksMapAcc, "no accessible for map grouping links!");
+
+ //////////////////////////////////////////////////////////////////////////
+ // Link with title attribute, no name from the subtree (bug 438325).
+ var id = "linkWithTitleNoNameFromSubtree";
+ var linkElement = document.getElementById(id);
+ var linkAcc;
+ try {
+ linkAcc = gAccRetrieval.getAccessibleFor(linkElement).
+ QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
+ } catch(e) {
+ ok(linkAcc, "no interface for link with ID " + id + "!");
+ }
+ testThis(id, linkAcc,
+ Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
+ "Link with title", true, 354, 355);
+ testStates(id, linkAcc,
+ (state_linked),
+ (ext_state_horizontal), 0);
+ testAction(id, linkAcc, "jump");
+
+ //////////////////////////////////////////////////////////////////////////
+ // Link with title attribute, name from the subtree - onsreen name
+ // (bug 438325).
+ id = "linkWithTitleNameFromSubtree";
+ linkElement = document.getElementById(id);
+ linkAcc;
+ try {
+ linkAcc = gAccRetrieval.getAccessibleFor(linkElement).
+ QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
+ } catch(e) {
+ ok(linkAcc, "no interface for link with ID " + id + "!");
+ }
+ testThis(id, linkAcc,
+ Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
+ "the name from subtree", true, 403, 404);
+ testStates(id, linkAcc,
+ (state_linked),
+ (ext_state_horizontal), 0);
+ testAction(id, linkAcc, "jump");
+
+ //////////////////////////////////////////////////////////////////////////
+ // Link with title attribute, name from the nested html:img (bug 438325).
+ id = "linkWithTitleNameFromImg";
+ linkElement = document.getElementById(id);
+ linkAcc;
+ try {
+ linkAcc = gAccRetrieval.getAccessibleFor(linkElement).
+ QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
+ } catch(e) {
+ ok(linkAcc, "no interface for link with ID " + id + "!");
+ }
+ testThis(id, linkAcc,
+ Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
+ "The title for link", true, 458, 459);
+ testStates(id, linkAcc,
+ (state_linked),
+ (ext_state_horizontal), 0);
+ testAction(id, linkAcc, "jump");
+
+ //////////////////////////////////////////////////////////////////////////
+ // Link with label, no name from the subtree (bug 438325).
+ id = "linkWithLabelNoNameFromSubtree";
+ linkElement = document.getElementById(id);
+ linkAcc;
+ try {
+ linkAcc = gAccRetrieval.getAccessibleFor(linkElement).
+ QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
+ } catch(e) {
+ ok(linkAcc, "no interface for link with ID " + id + "!");
+ }
+ testThis(id, linkAcc,
+ Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
+ "Link with label and nested image:", true, 462, 463);
+ testStates(id, linkAcc,
+ (state_linked),
+ (ext_state_horizontal), 0);
+ testAction(id, linkAcc, "jump");
+
+ //////////////////////////////////////////////////////////////////////////
+ //
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418368">Mozilla Bug 418368</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
+
<br>Simple link:<br>
<a id="NormalHyperlink" href="http://www.mozilla.org">Mozilla Foundation</a>
<br>ARIA link:<br>
<span id="AriaHyperlink" role="link"
onclick="window.open('http://www.mozilla.org/');"
tabindex="0">Mozilla Foundation Home</span>
<br>Invalid, non-focusable hyperlink:<br>
<span id="InvalidAriaHyperlink" role="link" aria-invalid="true"
@@ -288,16 +448,51 @@ https://bugzilla.mozilla.org/show_bug.cg
coords="0,0,13,14"
alt="a"
shape="rect"></area>
</map>
<img width="447" id="imgmap"
height="15"
usemap="#atoz_map"
src="http://www.bbc.co.uk/radio4/images/letters.gif"></img>
+
<br>Empty link:<br>
<a id="emptyLink" href=""><img src=""></img></a>
+
<br>Link with embedded span<br>
<a id="LinkWithSpan" href="http://www.heise.de/"><span lang="de">Heise Online</span></a>
+
<br>Named anchor, must not have "linked" state for it to be exposed correctly:<br>
<a id="namedAnchor" name="named_anchor">This should never be of state_linked</a>
+
+ <br>Link having no attributes, must not have "linked" state:</br>
+ <a id="noLink">This should never be of state_linked</a>
+
+ <br>Link with registered 'click' event: </br>
+ <a id="linkWithClick" onclick="var clicked = true;">This should have state_linked</a>
+
+ <br>Link with title attribute (no name from subtree): </br>
+ <a id="linkWithTitleNoNameFromSubtree" href="http://www.heise.de/"
+ title="Link with title"><img src=""/></a>
+
+ <br>Link with title attribute (name from subtree): </br>
+ <a id="linkWithTitleNameFromSubtree" href="http://www.heise.de/"
+ title="Link with title">the name from subtree</a>
+
+ <br>Link with title attribute (name from nested image): </br>
+ <a id="linkWithTitleNameFromImg" href="http://www.heise.de/"
+ title="Link with title"><img src="" alt="The title for link"/></a>
+
+ <br><label for="linkWithLabelNoNameFromSubtree">Link with label and nested image: </label></br>
+ <a id="linkWithLabelNoNameFromSubtree"
+ href="http://www.heise.de/"><img src=""/></a>
+
+ <br>Map that is used to group links (www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass),
+ also see the bug 431615:<br>
+ <map id="linksmap" title="Site navigation">
+ <ul>
+ <li><a href="http://mozilla.org">About the project</a></li>
+ <li><a href="http://mozilla.org">Sites and sounds</a></li>
+ </ul>
+ </map>
+
</body>
</html>
--- a/accessible/tests/mochitest/test_nsIAccessibleImage.html
+++ b/accessible/tests/mochitest/test_nsIAccessibleImage.html
@@ -12,65 +12,100 @@ https://bugzilla.mozilla.org/show_bug.cg
<script type="application/javascript">
const nsIAccessibleImage = Components.interfaces.nsIAccessibleImage;
const nsIAccessibleCoordinateType =
Components.interfaces.nsIAccessibleCoordinateType;
var gAccRetrieval;
- function testCords(aID, aImageAcc, aCordType, aXCoordinate, aYCoordinate,
- aCoordTypeString)
+ function testCoordinates(aID, aAcc, aWidth, aHeight)
{
- var x = {}, y = {};
- aImageAcc.getImagePosition(aCordType, x, y);
- is(x.value, aXCoordinate,
- "Wrong " + aCoordTypeString + " x offset for " + aID + "!");
- is(y.value, aYCoordinate,
- "Wrong " + aCoordTypeString + " y offset for " + aID + "!");
- }
+ var screenX = {}, screenY = {}, windowX = {}, windowY = {}, parentX = {},
+ parentY = {};
- function testCoordinates(aID, aAcc, aXCoordinates, aYCoordinates, aWidth,
- aHeight)
- {
- var imageAcc;
+ var imageAcc = null;
try {
imageAcc = aAcc.QueryInterface(nsIAccessibleImage);
} catch(e) {}
ok(imageAcc, "no image interface for " + aID + "!");
- testCords(aID, imageAcc,
- nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE,
- aXCoordinates[0], aYCoordinates[0], "screen");
- testCords(aID, imageAcc,
- nsIAccessibleCoordinateType.COORDTYPE_WINDOW_RELATIVE,
- aXCoordinates[1], aYCoordinates[1], "window");
- testCords(aID, imageAcc,
- nsIAccessibleCoordinateType.COORDTYPE_PARENT_RELATIVE,
- aXCoordinates[2], aYCoordinates[2], "parent");
+ if (!imageAcc)
+ return;
+
+ // get screen coordinates.
+ imageAcc.getImagePosition(
+ nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE,
+ screenX, screenY);
+ // get window coordinates.
+ imageAcc.getImagePosition(
+ nsIAccessibleCoordinateType.COORDTYPE_WINDOW_RELATIVE,
+ windowX, windowY);
+ // get parent related coordinates.
+ imageAcc.getImagePosition(
+ nsIAccessibleCoordinateType.COORDTYPE_PARENT_RELATIVE,
+ parentX, parentY);
+ // XXX For linked images, a negative parentY value is returned, and the
+ // screenY coordinate is the link's screenY coordinate minus 1.
+ // Until this is fixed, set parentY to -1 if it's negative.
+ if (parentY.value < 0) {
+ parentY.value = -1;
+ }
+
+ // See if asking image for child at image's screen coordinates gives
+ // correct accessible. getChildAtPoint operates on screen coordinates.
+ var tempAcc = null;
+ try {
+ tempAcc = imageAcc.getChildAtPoint(screenX.value, screenY.value);
+ } catch(e) {}
+ is(tempAcc, imageAcc,
+ "Wrong accessible returned for position of " + aID + "!");
+
+ // get image's parent.
+ var imageParentAcc = null;
+ try {
+ imageParentAcc = imageAcc.parent;
+ } catch(e) {}
+ ok(imageParentAcc, "no parent accessible for " + aID + "!");
+
+ if (imageParentAcc) {
+ // See if parent's screen coordinates plus image's parent relative
+ // coordinates equal to image's screen coordinates.
+ var parentAccX = {}, parentAccY = {}, parentAccWidth = {},
+ parentAccHeight = {};
+ imageParentAcc.getBounds(parentAccX, parentAccY, parentAccWidth,
+ parentAccHeight);
+ is(parentAccX.value + parentX.value, screenX.value,
+ "Wrong screen x coordinate for " + aID + "!");
+ is(parentAccY.value + parentY.value, screenY.value,
+ "Wrong screen y coordinate for " + aID + "!");
+ }
var width = {}, height = {};
imageAcc.getImageSize(width, height);
is(width.value, aWidth, "Wrong width for " + aID + "!");
is(height.value, aHeight, "wrong height for " + aID + "!");
}
- function testThis(aID, aName, aSRC, aXCoordinates, aYCoordinates, aWidth,
- aHeight)
+ function testThis(aID, aName, aSRC, aWidth, aHeight)
{
var elem = document.getElementById(aID);
var acc;
try {
acc = gAccRetrieval.getAccessibleFor(elem);
} catch(e) {}
ok(acc, "No accessible for " + aID + "!");
+
+ if (!acc)
+ return;
+
is(acc.name, aName, "wrong name for " + aID + "!");
// test coordinates and size
- testCoordinates(aID, acc, aXCoordinates, aYCoordinates, aWidth, aHeight);
+ testCoordinates(aID, acc, aWidth, aHeight);
// bug 429659: Make sure the SRC attribute is set for any image
var attributes;
try {
attributes = acc.attributes;
} catch(e) {}
ok(attributes, "no attributes on " + aID + "!");
is(attributes.getStringProperty("src"), aSRC,
@@ -78,64 +113,44 @@ https://bugzilla.mozilla.org/show_bug.cg
}
function doTest()
{
gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
getService(Components.interfaces.nsIAccessibleRetrieval);
// Test non-linked image
- var xCords = [16, 12, 8];
- var yCords = [227, 223, 113];
- testThis("nonLinkedImage", null, "moz.png", xCords, yCords, 89, 38);
+ testThis("nonLinkedImage", null, "moz.png", 89, 38);
// Test linked image
- xCords = [16, 12, 0];
- yCords = [289, 285, -27];
- testThis("linkedImage", null, "moz.png", xCords, yCords, 93, 42);
+ testThis("linkedImage", null, "moz.png", 93, 42);
// Test non-linked image with alt attribute
- xCords = [16, 12, 8];
- yCords = [356, 352, 242];
- testThis("nonLinkedImageWithAlt", "MoFo", "moz.png", xCords, yCords, 89, 38);
+ testThis("nonLinkedImageWithAlt", "MoFo", "moz.png", 89, 38);
// Test linked image with alt attribute
- xCords = [16, 12, 0];
- yCords = [418, 414, -27];
- testThis("linkedImageWithAlt", "MoFo link", "moz.png", xCords, yCords, 93, 42);
+ testThis("linkedImageWithAlt", "MoFo link", "moz.png", 93, 42);
// Test non-linked image with title attribute
- xCords = [16, 12, 8];
- yCords = [485, 481, 371];
- testThis("nonLinkedImageWithTitle", "MoFo logo", "moz.png", xCords, yCords, 89, 38);
+ testThis("nonLinkedImageWithTitle", "MoFo logo", "moz.png", 89, 38);
// Test linked image with title attribute
- xCords = [16, 12, 0];
- yCords = [547, 543, -27];
- testThis("linkedImageWithTitle", "Link to MoFo", "moz.png", xCords, yCords, 93, 42);
+ testThis("linkedImageWithTitle", "Link to MoFo", "moz.png", 93, 42);
// Test simple image with empty alt attribute
- xCords = [16, 12, 8];
- yCords = [614, 610, 500];
- testThis("nonLinkedImageEmptyAlt", "", "moz.png", xCords, yCords, 89, 38);
+ testThis("nonLinkedImageEmptyAlt", "", "moz.png", 89, 38);
// Test linked image with empty alt attribute
- xCords = [16, 12, 0];
- yCords = [676, 672, -27];
- testThis("linkedImageEmptyAlt", "", "moz.png", xCords, yCords, 93, 42);
+ testThis("linkedImageEmptyAlt", "", "moz.png", 93, 42);
// Test simple image with empty alt attribute and title
- xCords = [16, 12, 8];
- yCords = [743, 739, 629];
- testThis("nonLinkedImageEmptyAltAndTitle", "MozillaFoundation", "moz.png", xCords, yCords, 89, 38);
+ testThis("nonLinkedImageEmptyAltAndTitle", "MozillaFoundation", "moz.png", 89, 38);
// Test linked image with empty alt attribute and title
- xCords = [16, 12, 0];
- yCords = [805, 801, -27];
- testThis("linkedImageEmptyAltAndTitle", "Link to Mozilla Foundation", "moz.png", xCords, yCords, 93, 42);
+ testThis("linkedImageEmptyAltAndTitle", "Link to Mozilla Foundation", "moz.png", 93, 42);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</head>
--- a/accessible/tests/mochitest/test_nsIAccessibleTable_4.html
+++ b/accessible/tests/mochitest/test_nsIAccessibleTable_4.html
@@ -95,16 +95,36 @@ function doTest()
is(accTable4.role, Ci.nsIAccessibleRole.ROLE_TABLE, "wrong role");
is(accTable4.cellRefAt(0,0).firstChild.name, "cell0", "wrong cell");
is(accTable4.cellRefAt(0,1).firstChild.name, "cell1", "wrong cell");
is(accTable4.cellRefAt(1,0).firstChild.name, "cell2", "wrong cell");
is(accTable4.cellRefAt(1,1).firstChild.name, "cell3", "wrong cell");
}
+ // Test table with display:inline and an outside table. We shouldn't be fooled
+ // by the outside table and shouldn't create table accessible and table cell
+ // accessible in this case
+ var table5 = document.getElementById("table5");
+ accNotCreated = false;
+ try {
+ var accTable1 = accService.getAccessibleFor(table1);
+ } catch (e) {
+ accNotCreated = true;
+ }
+ ok(accNotCreated, "wrongly created table accessible");
+ var t5Cell = document.getElementById("t5_cell");
+ accNotCreated = false;
+ try {
+ var accCell = accService.getAccessibleFor(t5Cell);
+ } catch (e) {
+ accNotCreated = true;
+ }
+ ok(accNotCreated, "wrongly created table cell accessible");
+
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</head>
<body >
@@ -145,11 +165,23 @@ addLoadEvent(doTest);
<td>cell0</td>
<td>cell1</td>
</tr>
<tr>
<td>cell2</td>
<td>cell3</td>
</tr>
</table>
+
+ <table>
+ <tr>
+ <td style="display:block">
+ <table style="display:inline" id="table5">
+ <tr><td id="t5_cell">cell0</td></tr>
+ </table>
+ </td>
+ <td>cell1</td>
+ </tr>
+ </table>
+
</center>
</body>
</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_nsIAccessible_name.html
@@ -0,0 +1,273 @@
+<html>
+
+<head>
+ <title>nsIAccessible::name calculation</title>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript">
+ const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+ const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
+
+ var gAccRetrieval = null;
+
+ function testName(aID, aName)
+ {
+ var elm = document.getElementById(aID);
+ if (!elm) {
+ ok(false, "There is no element with ID " + aID);
+ return;
+ }
+
+ var acc = null;
+ try {
+ acc = gAccRetrieval.getAccessibleFor(elm);
+ } catch(e) {
+ }
+
+ if (!acc) {
+ ok(false, "There is no accessible for " + aID);
+ return;
+ }
+
+ is(acc.name, aName, "Wrong name of the accessible for " + aID);
+ }
+
+ function doTest()
+ {
+ gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(nsIAccessibleRetrieval);
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // aria-labelledby
+
+ // Single relation. The value of 'aria-labelledby' contains the ID of
+ // an element. Gets the name from text node of that element.
+ testName("btn_labelledby_text", "text");
+
+ // Multiple relations. The value of 'aria-labelledby' contains the IDs
+ // of elements. Gets the name from text nodes of those elements.
+ testName("btn_labelledby_texts", "text1 text2");
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name from subtree (single relation labelled_by).
+
+ // Gets the name from text nodes contained by nested elements
+ testName("btn_labelledby_mixed", "nomore text");
+
+ // Gets the name from text nodes contained by nested elements, ignores
+ // hidden elements (bug 443081).
+ testName("btn_labelledby_mixed_hidden_child", "nomore text2");
+
+ // Gets the name from hidden text nodes contained by nested elements,
+ // (label element is hidden entirely), (bug 443081).
+ testName("btn_labelledby_mixed_hidden", "lala more hidden text");
+
+ // Gets the name from text nodes contained by nested elements having block
+ // representation (every text node value in the name should be devided by
+ // spaces)
+ testName("btn_labelledby_mixed_block", "text more text");
+
+ // Gets the name from text nodes contained by html:td (every text node
+ // value in the name should be devided by spaces).
+ // XXX: this case is rather a feature than strong wanted behaviour.
+ testName("btn_labelledby_mixed_table", "text space text");
+
+ // Gets the name from image accessible.
+ testName("btn_labelledby_mixed_img", "text image");
+
+ // Gets the name from input accessibles
+ // Note: if input have label elements then the name isn't calculated
+ // from them.
+ testName("btn_labelledby_mixed_input",
+ "input button Submit Query Reset input image");
+
+ // Gets the name from the title of object element.
+ testName("btn_labelledby_mixed_object", "object");
+
+ // Gets the name from text nodes. Element br adds space between them.
+ testName("btn_labelledby_mixed_br", "text text");
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // label element
+
+ // The label element contains the button. The name is calculated from
+ // this button.
+ // Note: the name contains the content of the button.
+ testName("btn_label_inside", "text10text");
+
+ // The label element and the button are placed in the same form. Gets
+ // the name from the label subtree.
+ testName("btn_label_inform", "in form");
+
+ // The label element is placed outside of form where the button is.
+ // Do not take into account the label.
+ testName("btn_label_outform", "12");
+
+ // The label element and the button are in the same document. Gets the
+ // name from the label subtree.
+ testName("btn_label_indocument", "in document");
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // name from children
+
+ // ARIA role button is presented allowing the name calculation from
+ // children.
+ testName("btn_children", "14");
+
+ // ARIA role option is presented allowing the name calculation from
+ // visible children (bug 443081).
+ testName("lb_opt1_children_hidden", "i am visible");
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // title attribute
+
+ // If nothing is left. Let's try title attribute.
+ testName("btn_title", "title");
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+
+</head>
+
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=444279"
+ title="mochitest for accessible name calculating">
+ Mozilla Bug 444279
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <!-- aria-labelledby, single relation -->
+ <span id="labelledby_text">text</span>
+ <button id="btn_labelledby_text"
+ aria-labelledby="labelledby_text">1</button>
+ <br/>
+
+ <!-- aria-labelledby, multiple relations -->
+ <span id="labelledby_text1">text1</span>
+ <span id="labelledby_text2">text2</span>
+ <button id="btn_labelledby_texts"
+ aria-labelledby="labelledby_text1 labelledby_text2">2</button>
+ <br/>
+
+ <!-- the name from subtree, mixed content -->
+ <span id="labelledby_mixed">no<span>more text</span></span>
+ <button id="btn_labelledby_mixed"
+ aria-labelledby="labelledby_mixed">3</button>
+ <br/>
+
+ <!-- the name from subtree, mixed/hidden content -->
+ <span id="labelledby_mixed_hidden_child">
+ no<span>more
+ <span style="display: none;">hidden</span>
+ text2
+ <span style="visibility: hidden">hidden2</span>
+ </span>
+ </span>
+ <button id="btn_labelledby_mixed_hidden_child"
+ aria-labelledby="labelledby_mixed_hidden_child">3.1</button>
+ <br/>
+
+ <!-- the name from subtree, mixed/completely hidden content -->
+ <span id="labelledby_mixed_hidden"
+ style="display: none;">lala <span>more hidden </span>text</span></span>
+ <button id="btn_labelledby_mixed_hidden"
+ aria-labelledby="labelledby_mixed_hidden">3.2</button>
+ <br/>
+
+ <!-- the name from subtree, mixed content, block structure -->
+ <div id="labelledby_mixed_block"><div>text</div>more text</div></div>
+ <button id="btn_labelledby_mixed_block"
+ aria-labelledby="labelledby_mixed_block">4</button>
+ <br/>
+
+ <!-- the name from subtree, mixed content, table structure -->
+ <table><tr>
+ <td id="labelledby_mixed_table">text<span>space</span>text</td>
+ </tr></table>
+ <button id="btn_labelledby_mixed_table"
+ aria-labelledby="labelledby_mixed_table">5</button>
+ <br/>
+
+ <!-- the name from subtree, child img -->
+ <span id="labelledby_mixed_img">text<img alt="image"/></span>
+ <button id="btn_labelledby_mixed_img"
+ aria-labelledby="labelledby_mixed_img">6</button>
+ <br/>
+
+ <!-- the name from subtree, child inputs -->
+ <span id="labelledby_mixed_input">
+ <input type="button" id="input_button" title="input button"/>
+ <input type="submit" id="input_submit"/>
+ <input type="reset" id="input_reset"/>
+ <input type="image" id="input_image" title="input image"/>
+ </span>
+ <button id="btn_labelledby_mixed_input"
+ aria-labelledby="labelledby_mixed_input">7</button>
+ <br/>
+
+ <!-- the name from subtree, child object -->
+ <span id="labelledby_mixed_object">
+ <object data="about:blank" title="object"></object>
+ </span>
+ <button id="btn_labelledby_mixed_object"
+ aria-labelledby="labelledby_mixed_object">8</button>
+ <br/>
+
+ <!-- the name from subtree, child br -->
+ <span id="labelledby_mixed_br">text<br/>text</span>
+ <button id="btn_labelledby_mixed_br"
+ aria-labelledby="labelledby_mixed_br">9</button>
+ <br/>
+
+ <!-- label element, label contains the button -->
+ <label>text<button id="btn_label_inside">10</button>text</label>
+ <br/>
+
+ <!-- label element, label and the button are in the same form -->
+ <form>
+ <label for="btn_label_inform">in form</label>
+ <button id="btn_label_inform">11</button>
+ </form>
+
+ <!-- label element, label is outside of the form of the button -->
+ <label for="btn_label_outform">out form</label>
+ <form>
+ <button id="btn_label_outform">12</button>
+ </form>
+
+ <!-- label element, label and the button are in the same document -->
+ <label for="btn_label_indocument">in document</label>
+ <button id="btn_label_indocument">13</button>
+
+ <!-- name from children -->
+ <span id="btn_children" role="button">14</span>
+
+ <!-- name from children, hidden children -->
+ <div role="listbox" tabindex="0">
+ <div id="lb_opt1_children_hidden" role="option" tabindex="0">
+ <span>i am visible</span>
+ <span style="display:none">i am hidden</span>
+ </div>
+ </div>
+
+ <!-- name from title attribute -->
+ <span id="btn_title" role="group" title="title">15</span>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_nsIAccessible_name.xul
@@ -0,0 +1,318 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/a11y/accessible/nsIAccessible_name.css"
+ type="text/css"?>
+
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="Accessibility Name Calculating Test.">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript">
+ <![CDATA[
+ const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+ const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
+
+ var gAccRetrieval = null;
+
+ function testName(aID, aName)
+ {
+ var elm = document.getElementById(aID);
+ if (!elm) {
+ ok(false, "There is no element with ID " + aID);
+ return null;
+ }
+
+ var acc = null;
+ try {
+ acc = gAccRetrieval.getAccessibleFor(elm);
+ } catch(e) {
+ }
+
+ if (!acc) {
+ ok(false, "There is no accessible for " + aID);
+ return null;
+ }
+
+ is(acc.name, aName, "Wrong name of the accessible for " + aID);
+ return acc;
+ }
+
+ function doTest()
+ {
+ gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(nsIAccessibleRetrieval);
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // aria-labelledby
+
+ // Single relation. The value of 'aria-labelledby' contains the ID of
+ // an element. Gets the name from text node of that element.
+ testName("btn_labelledby_text", "text");
+
+ // Multiple relations. The value of 'aria-labelledby' contains the IDs
+ // of elements. Gets the name from text nodes of those elements.
+ testName("btn_labelledby_texts", "text1 text2");
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name from subtree (single relation labelled_by).
+
+ // Gets the name from text nodes contained by nested elements.
+ testName("btn_labelledby_mixed", "nomore text");
+
+ // Gets the name from text nodes and selected item of menulist
+ // (other items are ignored).
+ testName("btn_labelledby_mixed_menulist",
+ "nomore text selected item more text");
+
+ // Gets the name from text nodes contained by nested elements, ignores
+ // hidden elements (bug 443081).
+ testName("btn_labelledby_mixed_hidden_child", "nomore text2");
+
+ // Gets the name from hidden text nodes contained by nested elements,
+ // (label element is hidden entirely), (bug 443081)
+ testName("btn_labelledby_mixed_hidden", "lala more hidden text");
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name for nsIDOMXULLabeledControlElement.
+
+ // Gets the name from @label attribute.
+ testName("btn_nsIDOMXULLabeledControlElement", "labeled element");
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name for nsIDOMXULSelectControlItemElement.
+
+ // Gets the name from @label attribute.
+ testName("li_nsIDOMXULSelectControlItemElement", "select control item");
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name if the XUL element doesn't implement nsIDOMXULSelectControlElement
+ // and has @label attribute.
+
+ testName("box_not_nsIDOMXULSelectControlElement", "box");
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name from the label element.
+
+ // The label and button are placed on 2nd level relative common parent.
+ testName("btn_label_1", "label1");
+
+ // The label is on 1st, the button is on 5th level relative common parent.
+ testName("btn_label_2", "label2");
+
+ // The label and button are siblings.
+ testName("btn_label_3", "label3");
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name from the label element in anonymous content (see bug 362365).
+
+ // Get the name from anonymous label element for anonymous textbox
+ // (@anonid is used).
+ var ID = "box_label_anon1";
+ var box1Acc = testName(ID, "");
+ if (box1Acc) {
+ var textboxAcc = box1Acc.firstChild;
+ is(textboxAcc.name, "Label",
+ "Wrong label for anonymous textbox of " + ID);
+ }
+
+ // Get the name from anonymous label element for anonymous textbox
+ // (@anonid is used). Nested bindings.
+ ID = "box_label_anon2";
+ var box2Acc = testName(ID, "");
+ if (box2Acc) {
+ var textboxAcc = box2Acc.firstChild;
+ is(textboxAcc.name, "Label",
+ "Wrong label for anonymous textbox of " + ID);
+
+ var topTextboxAcc = box2Acc.lastChild;
+ is(topTextboxAcc.name, "Top textbox",
+ "Wrong label for anonymous textbox of " + ID);
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // tooltiptext (if nothing above isn't presented then tooltiptext is used)
+ testName("box_tooltiptext", "tooltiptext label");
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name from the @title attribute of <toolbaritem/> (original bug 237249).
+
+ // Direct child of toolbaritem.
+ var textboxAcc = testName("toolbaritem_textbox", "ooospspss");
+
+ // Element from anonymous content of direct child of toolbaritem.
+ var dropmarkerAcc = textboxAcc.lastChild;
+ is(dropmarkerAcc.finalRole, nsIAccessibleRole.ROLE_PUSHBUTTON,
+ "The last child of autocomplete textbox 'toolbaritem_textbox' should be dropmarker.");
+ is(dropmarkerAcc.name, "ooospspss",
+ "Wrong name for dropmarker of autocomplete textbox 'toolbaritem_textbox'.");
+
+ // Child from subtree of toolbaritem.
+ testName("toolbaritem_hboxbutton", "ooospspss");
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name from children
+
+ // ARIA role button is presented allowing the name calculation from
+ // children.
+ testName("box_children", "14");
+
+ // ARIA role option is presented allowing the name calculation from
+ // the visible children (bug 443081)
+ testName("lb_opt1_children_hidden", "i am visible");
+
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ ]]>
+ </script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=444279"
+ title="mochitest for accessible name calculating">
+ Mozilla Bug 444279
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <!-- aria-labelledby, single relation -->
+ <description id="labelledby_text">text</description>
+ <button id="btn_labelledby_text"
+ aria-labelledby="labelledby_text"/>
+
+ <!-- aria-labelledby, multiple relations -->
+ <description id="labelledby_text1">text1</description>
+ <description id="labelledby_text2">text2</description>
+ <button id="btn_labelledby_texts"
+ aria-labelledby="labelledby_text1 labelledby_text2"/>
+
+ <!-- the name from subtree, mixed content -->
+ <description id="labelledby_mixed">
+ no<description>more text</description>
+ </description>
+ <button id="btn_labelledby_mixed"
+ aria-labelledby="labelledby_mixed"/>
+
+ <!-- the name from subtree, mixed/hidden content -->
+ <description id="labelledby_mixed_hidden_child">no<description>more <description hidden="true">hidden</description>text2</description></description>
+ <button id="btn_labelledby_mixed_hidden_child"
+ aria-labelledby="labelledby_mixed_hidden_child"/>
+
+ <!-- the name from subtree, mixed/completely hidden content -->
+ <description id="labelledby_mixed_hidden"
+ hidden="true">lala <description>more hidden </description>text</description>
+ <button id="btn_labelledby_mixed_hidden"
+ aria-labelledby="labelledby_mixed_hidden"/>
+ <br/>
+
+ <!-- the name from subtree, mixed content, ignore items of menulist -->
+ <description id="labelledby_mixed_menulist">
+ no<description>more text</description>
+ <menulist>
+ <menupopup>
+ <menuitem label="selected item"/>
+ <menuitem label="item"/>
+ </menupopup>
+ </menulist>
+ more text
+ </description>
+ <button id="btn_labelledby_mixed_menulist"
+ aria-labelledby="labelledby_mixed_menulist"/>
+
+ <!-- nsIDOMXULLabeledControlElement -->
+ <button id="btn_nsIDOMXULLabeledControlElement"
+ label="labeled element"/>
+
+ <!-- nsIDOMXULSelectControlItemElement -->
+ <listbox>
+ <listitem id="li_nsIDOMXULSelectControlItemElement"
+ label="select control item"/>
+ </listbox>
+
+ <!-- not nsIDOMXULSelectControlElement -->
+ <box id="box_not_nsIDOMXULSelectControlElement" role="group" label="box"/>
+
+ <!-- label element -->
+ <hbox>
+ <box>
+ <label control="btn_label_1">label1</label>
+ </box>
+ <label control="btn_label_2">label2</label>
+ <box>
+ <button id="btn_label_1"/>
+ <box>
+ <box>
+ <box>
+ <button id="btn_label_2"/>
+ </box>
+ </box>
+ </box>
+ </box>
+ <label control="btn_label_3">label3</label>
+ <button id="btn_label_3"/>
+ </hbox>
+
+ <!-- label element, anonymous content -->
+ <box id="box_label_anon1"
+ class="first"
+ role="group"/>
+
+ <box id="box_label_anon2"
+ class="second"
+ role="group"/>
+
+ <!-- tooltiptext -->
+ <box id="box_tooltiptext"
+ role="group"
+ tooltiptext="tooltiptext label"/>
+
+ <!-- the name from @title of toolbaritem -->
+ <toolbar>
+ <toolbaritem title="ooospspss">
+ <textbox id="toolbaritem_textbox"
+ flex="1"
+ type="autocomplete"
+ enablehistory="true">
+ <hbox role="button" id="toolbaritem_hboxbutton">
+ <description value="button"/>
+ </hbox>
+ </textbox>
+ </toolbaritem>
+ </toolbar>
+
+ <!-- name from children -->
+ <box id="box_children" role="button">14</box>
+
+ <!-- name from children, hidden children -->
+ <vbox role="listbox" tabindex="0">
+ <hbox id="lb_opt1_children_hidden" role="option" tabindex="0">
+ <description>i am visible</description>
+ <description style="display:none">i am hidden</description>
+ </hbox>
+ </vbox>
+
+</window>
+
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_nsOuterDocAccessible.html
@@ -0,0 +1,106 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=441519
+-->
+<head>
+ <title>nsOuterDocAccessible chrome tests</title>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript">
+ const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+ const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
+
+ // needed state flag
+ const state_focusable =
+ Components.interfaces.nsIAccessibleStates.STATE_FOCUSABLE;
+
+ // needed error return value
+ const ns_error_invalid_arg = Components.results.NS_ERROR_INVALID_ARG;
+
+ var gAccRetrieval = null;
+
+ function doTest()
+ {
+ gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(nsIAccessibleRetrieval);
+
+ // Get accessible for body tag.
+ var docAcc = null;
+ try {
+ docAcc = gAccRetrieval.getAccessibleFor(document);
+ } catch(e) {}
+ ok(docAcc, "No accessible for document!");
+
+ if (docAcc) {
+ var outerDocAcc = null;
+ try {
+ outerDocAcc = docAcc.parent;
+ } catch(e) {}
+ ok(outerDocAcc, "No internal frame parent for document!");
+
+ if (outerDocAcc) {
+ is(outerDocAcc.role, nsIAccessibleRole.ROLE_INTERNAL_FRAME,
+ "Wrong role for internal frame!");
+
+ // check if it is focusable, not desired.
+ var state = {}, extraState = {}
+ outerDocAcc.getFinalState(state, extraState);
+ is(state.value & state_focusable, 0,
+ "Wrong focusable state bit for internal frame!");
+
+ // see bug 428954: No name wanted for internal frame
+ is(outerDocAcc.name, "", "Wrong name for internal frame!");
+
+ // see bug 440770, no actions wanted on outer doc
+ is(outerDocAcc.numActions, 0,
+ "Wrong number of actions for internal frame!");
+ var actionTempStr; // not really used, just needs to receive a value
+ try {
+ actionTempStr = outerDocAcc.getActionName(0);
+ do_throw("No exception thrown for actionName!");
+ } catch(e) {
+ ok(e.result, ns_error_invalid_arg,
+ "Wrong return value for actionName call!");
+ }
+
+ try {
+ actionTempStr = outerDocAcc.getActionDescription(0);
+ do_throw("No exception thrown for actionDescription!");
+ } catch(e) {
+ ok(e.result, ns_error_invalid_arg,
+ "Wrong return value for actionDescription call!");
+ }
+
+ try {
+ outerDocAcc.doAction(0);
+ do_throw("No exception thrown for doAction!");
+ } catch(e) {
+ ok(e.result, ns_error_invalid_arg,
+ "Wrong return value for doAction call!");
+ }
+ }
+ }
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=441519"
+ title="nsOuterDocAccessible chrome tests">
+ Mozilla Bug 441519
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_textattrs.html
@@ -0,0 +1,476 @@
+<html>
+
+<head>
+ <title>Text attributes tests</title>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript">
+ const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+ const nsIAccessibleText = Components.interfaces.nsIAccessibleText;
+ const nsIAccessibleEvent = Components.interfaces.nsIAccessibleEvent;
+
+ const nsIDOMNSEditableElement =
+ Components.interfaces.nsIDOMNSEditableElement;
+ const nsIObserverService = Components.interfaces.nsIObserverService;
+
+ var gAccRetrieval = null;
+
+ /**
+ * Test text attributes.
+ *
+ * @param aID the ID of DOM element having text accessible
+ * @param aOffset the offset inside text accessible to fetch
+ * text attributes
+ * @param aAttrs the map of text attributes (name/value pairs)
+ * @param aStartOffset the start offset where text attributes are
+ * applied
+ * @param aEndOffset the end offset where text attribute are applied
+ * @param aDefAttrs the list of default text attributes (name/value
+ * pairs)
+ */
+ function testTextAttrs(aID, aOffset,
+ aAttrs, aStartOffset, aEndOffset, aDefAttrs)
+ {
+ var node = document.getElementById(aID);
+ if (!node) {
+ ok(false, "Can't get the element with ID " + aID);
+ return;
+ }
+
+ var accessible = null;
+ try {
+ accessible = gAccRetrieval.getAccessibleFor(node);
+ accessible.QueryInterface(nsIAccessibleText);
+ } catch (e) {
+ }
+
+ if (!accessible) {
+ ok(false, "Can't query nsIAccessibleText interface for " + aID);
+ return;
+ }
+
+ var startOffset = { value: -1 };
+ var endOffset = { value: -1 };
+ var attrs = null;
+ try {
+ attrs = accessible.getTextAttributes(false,
+ aOffset,
+ startOffset, endOffset);
+ } catch (e) {
+ }
+
+ if (!attrs) {
+ ok(false, "Can't get text attributes for " + aID);
+ return;
+ }
+
+ var errorMsg = " for " + aID + "at offset " + aOffset;
+ is(startOffset.value, aStartOffset,
+ "Wrong start offset" + errorMsg);
+ is(endOffset.value, aEndOffset,
+ "Wrong end offset" + errorMsg);
+
+ compareTextAttrs(errorMsg, attrs, aAttrs);
+
+ var defAttrs = null;
+ try{
+ defAttrs = accessible.defaultTextAttributes;
+ } catch (e) {
+ }
+
+ if (!defAttrs) {
+ ok(false, "Can't get default attributes for " + aID);
+ return;
+ }
+
+ compareTextAttrs(errorMsg, defAttrs, aDefAttrs);
+ }
+
+ function compareTextAttrs(aErrorMsg, aAttrs, aExpectedAttrs)
+ {
+ var enumerate = aAttrs.enumerate();
+ while (enumerate.hasMoreElements()) {
+ var prop = enumerate.getNext().
+ QueryInterface(Components.interfaces.nsIPropertyElement);
+
+ if (!(prop.key in aExpectedAttrs))
+ ok(false,
+ "Unexpected attribute '" + prop.key + "'" + aErrorMsg);
+ else
+ is(prop.value, aExpectedAttrs[prop.key],
+ "Attribute '" + prop.key + "' has wrong value" + aErrorMsg);
+ }
+
+ for (var name in aExpectedAttrs) {
+ var value = "";
+ try {
+ value = aAttrs.getStringProperty(name);
+ } catch(e) {
+ }
+
+ if (!value)
+ ok(false,
+ "There is no expected attribute '" + name + "'" + aErrorMsg);
+ }
+ }
+
+ var gObserverService = null;
+ var gA11yEventObserver = null;
+
+ function testSpellTextAttrs()
+ {
+ gA11yEventObserver = {
+ observe: function observe(aSubject, aTopic, aData)
+ {
+ if (aTopic != "accessible-event")
+ return;
+
+
+ var event = aSubject.QueryInterface(nsIAccessibleEvent);
+
+ if (event.eventType == nsIAccessibleEvent.EVENT_TEXT_ATTRIBUTE_CHANGED)
+ this.mTextAttrChangedEventCounter++;
+ },
+
+ mTextAttrChangedEventCounter: 0
+ };
+
+ // Add accessibility event listeners
+ var gObserverService = Components.classes["@mozilla.org/observer-service;1"].
+ getService(nsIObserverService);
+
+ gObserverService.addObserver(gA11yEventObserver, "accessible-event",
+ false);
+
+ ID = "area8";
+
+ var node = document.getElementById(ID);
+ node.focus();
+
+ var editor = node.QueryInterface(nsIDOMNSEditableElement).editor;
+ var spellchecker = editor.getInlineSpellChecker(true);
+ spellchecker.enableRealTimeSpell = true;
+
+ window.setTimeout(function()
+ {
+ var defAttrs = {
+ "font-style": "normal",
+ "text-align": "start",
+ "font-size": "11px",
+ "background-color": "rgb(255, 255, 255)",
+ "font-weight": "400",
+ "text-indent": "0px",
+ "color": "rgb(0, 0, 0)",
+ "font-family": "Lucida Grande",
+ "text-position": "baseline"
+ };
+
+ var attrs = { "background-color": "transparent" };
+ var misspelledAttrs = {
+ "background-color": "transparent",
+ "invalid": "spelling"
+ };
+
+ testTextAttrs(ID, 0, attrs, 0, 11, defAttrs);
+ testTextAttrs(ID, 11, misspelledAttrs, 11, 17, defAttrs);
+ testTextAttrs(ID, 18, misspelledAttrs, 18, 22, defAttrs);
+
+ is(gA11yEventObserver.mTextAttrChangedEventCounter, 2,
+ "Wrong count of 'text attribute changed' events for " + ID);
+
+ // Remove a11y events listener
+ gObserverService.removeObserver(gA11yEventObserver,
+ "accessible-event");
+
+ SimpleTest.finish();
+ }, 0);
+ }
+
+ function doTest()
+ {
+ gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(nsIAccessibleRetrieval);
+
+ //////////////////////////////////////////////////////////////////////////
+ // area1
+ var ID = "area1";
+ var defAttrs = {
+ "font-style": "normal",
+ "text-align": "start",
+ "font-size": "16px",
+ "background-color": "transparent",
+ "font-weight": "400",
+ "text-indent": "0px",
+ "color": "rgb(0, 0, 0)",
+ "font-family": "serif",
+ "text-position": "baseline"
+ };
+
+ var attrs = {};
+ testTextAttrs(ID, 0, attrs, 0, 7, defAttrs);
+
+ attrs = {"font-weight": "401"};
+ testTextAttrs(ID, 7, attrs, 7, 11, defAttrs);
+
+ attrs = {};
+ testTextAttrs(ID, 12, attrs, 11, 18, defAttrs);
+
+ //////////////////////////////////////////////////////////////////////////
+ // area2
+ ID = "area2";
+ defAttrs = {
+ "font-style": "normal",
+ "text-align": "start",
+ "font-size": "16px",
+ "background-color": "transparent",
+ "font-weight": "400",
+ "text-indent": "0px",
+ "color": "rgb(0, 0, 0)",
+ "font-family": "serif",
+ "text-position": "baseline"
+ };
+
+ attrs = {};
+ testTextAttrs(ID, 0, attrs, 0, 7, defAttrs);
+
+ attrs = {"font-weight": "401"};
+ testTextAttrs(ID, 7, attrs, 7, 12, defAttrs);
+
+ attrs = {"font-style": "italic", "font-weight": "401"};
+ testTextAttrs(ID, 13, attrs, 12, 19, defAttrs);
+
+ attrs = {"font-weight": "401"};
+ testTextAttrs(ID, 20, attrs, 19, 23, defAttrs);
+
+ attrs = {};
+ testTextAttrs(ID, 24, attrs, 23, 30, defAttrs);
+
+ //////////////////////////////////////////////////////////////////////////
+ // area3
+ ID = "area3";
+ defAttrs = {
+ "font-style": "normal",
+ "text-align": "start",
+ "font-size": "16px",
+ "background-color": "transparent",
+ "font-weight": "400",
+ "text-indent": "0px",
+ "color": "rgb(0, 0, 0)",
+ "font-family": "serif",
+ "text-position": "baseline"
+ };
+
+ attrs = {"color": "rgb(0, 128, 0)"};
+ testTextAttrs(ID, 0, attrs, 0, 6, defAttrs);
+
+ attrs = {"color": "rgb(255, 0, 0)"};
+ testTextAttrs(ID, 6, attrs, 6, 26, defAttrs);
+
+ attrs = {"color": "rgb(0, 128, 0)"};
+ testTextAttrs(ID, 26, attrs, 26, 50, defAttrs);
+
+ //////////////////////////////////////////////////////////////////////////
+ // area4
+ ID = "area4";
+ defAttrs = {
+ "font-style": "normal",
+ "text-align": "start",
+ "font-size": "16px",
+ "background-color": "transparent",
+ "font-weight": "400",
+ "text-indent": "0px",
+ "color": "rgb(0, 0, 0)",
+ "font-family": "serif",
+ "text-position": "baseline"
+ };
+
+ attrs = {"color": "rgb(0, 128, 0)"};
+ testTextAttrs(ID, 0, attrs, 0, 16, defAttrs);
+
+ attrs = {"color": "rgb(255, 0, 0)"};
+ testTextAttrs(ID, 16, attrs, 16, 33, defAttrs);
+
+ attrs = {"color": "rgb(0, 128, 0)"};
+ testTextAttrs(ID, 34, attrs, 33, 46, defAttrs);
+
+ //////////////////////////////////////////////////////////////////////////
+ // area5
+ ID = "area5";
+ defAttrs = {
+ "font-style": "normal",
+ "text-align": "start",
+ "font-size": "16px",
+ "background-color": "transparent",
+ "font-weight": "400",
+ "text-indent": "0px",
+ "color": "rgb(0, 0, 0)",
+ "font-family": "serif",
+ "text-position": "baseline"
+ };
+
+ attrs = {"color": "rgb(0, 128, 0)"};
+ testTextAttrs(ID, 0, attrs, 0, 5, defAttrs);
+
+ attrs = {};
+ testTextAttrs(ID, 7, attrs, 5, 8, defAttrs);
+
+ attrs = {"color": "rgb(255, 0, 0)"};
+ testTextAttrs(ID, 9, attrs, 8, 11, defAttrs);
+
+ attrs = {};
+ testTextAttrs(ID, 11, attrs, 11, 18, defAttrs);
+
+ //////////////////////////////////////////////////////////////////////////
+ // area6 (CSS vertical-align property, bug 445938)
+ ID = "area6";
+ defAttrs = {
+ "font-style": "normal",
+ "text-align": "start",
+ "font-size": "16px",
+ "background-color": "transparent",
+ "font-weight": "400",
+ "text-indent": "0px",
+ "color": "rgb(0, 0, 0)",
+ "font-family": "serif",
+ "text-position": "baseline"
+ };
+
+ attrs = {};
+ testTextAttrs(ID, 0, attrs, 0, 5, defAttrs);
+
+ attrs = {"text-position": "super", "font-size": "13px" };
+ testTextAttrs(ID, 5, attrs, 5, 13, defAttrs);
+
+ attrs = {};
+ testTextAttrs(ID, 13, attrs, 13, 27, defAttrs);
+
+ attrs = {"text-position": "super" };
+ testTextAttrs(ID, 27, attrs, 27, 35, defAttrs);
+
+ attrs = {};
+ testTextAttrs(ID, 35, attrs, 35, 39, defAttrs);
+
+ attrs = {"text-position": "sub", "font-size": "13px" };
+ testTextAttrs(ID, 39, attrs, 39, 50, defAttrs);
+
+ attrs = {};
+ testTextAttrs(ID, 50, attrs, 50, 55, defAttrs);
+
+ attrs = {"text-position": "sub" };
+ testTextAttrs(ID, 55, attrs, 55, 64, defAttrs);
+
+ //////////////////////////////////////////////////////////////////////////
+ // area7
+ ID = "area7";
+ defAttrs = {
+ "font-style": "normal",
+ "text-align": "start",
+ "font-size": "16px",
+ "background-color": "transparent",
+ "font-weight": "400",
+ "text-indent": "0px",
+ "color": "rgb(0, 0, 0)",
+ "font-family": "serif",
+ "text-position": "baseline"
+ };
+
+ attrs = {"language": "ru"};
+ testTextAttrs(ID, 0, attrs, 0, 12, defAttrs);
+
+ attrs = {"language": "en"};
+ testTextAttrs(ID, 12, attrs, 12, 13, defAttrs);
+
+ attrs = {"language" :"en", "background-color": "rgb(0, 0, 255)"};
+ testTextAttrs(ID, 13, attrs, 13, 26, defAttrs);
+
+ attrs = {"language": "en" };
+ testTextAttrs(ID, 26, attrs, 26, 27, defAttrs);
+
+ attrs = {"language": "de"};
+ testTextAttrs(ID, 27, attrs, 27, 42, defAttrs);
+
+ attrs = {"language": "en"};
+ testTextAttrs(ID, 42, attrs, 42, 43, defAttrs);
+
+ attrs = {};
+ testTextAttrs(ID, 43, attrs, 43, 50, defAttrs);
+
+ attrs = {"color": "rgb(255, 0, 255)"};
+ testTextAttrs(ID, 50, attrs, 50, 57, defAttrs);
+
+ attrs = {"font-weight": "401", "color": "rgb(255, 0, 255)" };
+ testTextAttrs(ID, 57, attrs, 57, 61, defAttrs);
+
+ attrs = {"color": "rgb(255, 0, 255)"};
+ testTextAttrs(ID, 61, attrs, 61, 68, defAttrs);
+
+ //////////////////////////////////////////////////////////////////////////
+ // test spelling text attributes
+ testSpellTextAttrs(); // Will call SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=345759"
+ title="Implement text attributes">
+ Mozilla Bug 345759
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <p id="area1">Normal <b>Bold</b> Normal</p>
+ <p id="area2">Normal <b>Bold <i>Italic </i>Bold</b> Normal</p>
+ <p id="area3">
+ <span style="color: green">
+ Green
+ <span style="color: red">but children are red</span>
+ </span><span style="color: green">
+ Another green section.
+ </span>
+ </p>
+ <p id="area4">
+ <span style="color: green">
+ Green
+ </span><span style="color: green">
+ Green too
+ <span style="color: red">with red children</span>
+ Green again
+ </span>
+ </p>
+ <p id="area5">
+ <span style="color: green">Green</span>
+ <img src="moz.png" alt="image"/>
+ <span style="color: red">Red</span>Normal
+ </p>
+ <p id="area6">
+ This <sup>sentence</sup> has the word
+ <span style="vertical-align:super;">sentence</span> in
+ <sub>superscript</sub> and
+ <span style="vertical-align:sub;">subscript</span>
+ </p>
+
+ <p lang="en" id="area7">
+ <span lang="ru">Привет</span>
+ <span style="background-color: blue">Blue BG color</span>
+ <span lang="de">Ich bin/Du bist</span>
+ <span lang="en">
+ Normal
+ <span style="color: magenta">Magenta<b>Bold</b>Magenta</span>
+ </span>
+ </p>
+
+ <input id="area8" value="valid text inalid tixt"/>
+
+ <p id="output"/>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_textboxes.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=442648
+-->
+<head>
+ <title>nsIAccessible textboxes chrome tests</title>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript" src="chrome://mochikit/content/a11y/accessible/testTextboxes.js"></script>
+
+ <script type="application/javascript">
+ function doTest()
+ {
+ gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(nsIAccessibleRetrieval);
+
+ //////////////////////////////////////////////////////////////////////////
+ // normal textbox without content and with no proper label
+ testThis("unlabelled_Textbox", // ID
+ null, // name
+ "", // value
+ "", // description
+ role_entry, // role
+ (state_focusable), // state
+ (ext_state_editable), // extState
+ (state_readonly), // absentState
+ 1, // numActions
+ "activate", // ActionName
+ "Activate"); // ActionDescription
+
+ //////////////////////////////////////////////////////////////////////////
+ // normal textbox without content and with a proper label
+ testThis("labelled_textbox", // ID
+ "Second textbox:", // name
+ "", // value
+ "", // description
+ role_entry, // role
+ (state_focusable), // state
+ (ext_state_editable), // extState
+ (state_readonly), // absentState
+ 1, // numActions
+ "activate", // ActionName
+ "Activate"); // ActionDescription
+
+ //////////////////////////////////////////////////////////////////////////
+ // normal textbox with content and with a proper label
+ testThis("prefilled_textbox", // ID
+ "Textbox with predefined value:", // name
+ "I have some text", // value
+ "", // description
+ role_entry, // role
+ (state_focusable), // state
+ (ext_state_editable), // extState
+ (state_readonly), // absentState
+ 1, // numActions
+ "activate", // ActionName
+ "Activate"); // ActionDescription
+
+ //////////////////////////////////////////////////////////////////////////
+ // password textbox with a proper label
+ testThis("password_textbox", // ID
+ "Enter some password here:", // name
+ "", // value
+ "", // description
+ role_password_text, // role
+ (state_focusable), // state
+ (ext_state_editable), // extState
+ (state_readonly), // absentState
+ 1, // numActions
+ "activate", // ActionName
+ "Activate"); // ActionDescription
+
+ //////////////////////////////////////////////////////////////////////////
+ // textarea without content and label
+ testThis("unlabelled_Textarea", // ID
+ null, // name
+ "", // value
+ "", // description
+ role_entry, // role
+ (state_focusable), // state
+ (ext_state_editable | ext_state_multi_line), // extState
+ (state_readonly), // absentState
<