diff --git a/accessible/src/html/nsHyperTextAccessible.cpp b/accessible/src/html/nsHyperTextAccessible.cpp
index 3846dfd87ee8..371701cb2ef6 100644
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -735,6 +735,30 @@ nsHyperTextAccessible::HypertextOffsetsToDOMRange(PRInt32 aStartHTOffset,
NS_ENSURE_ARG_POINTER(aEndOffset);
*aEndOffset = -1;
+ // If the given offsets are 0 and associated editor is empty then return
+ // collapsed range with editor root element as range container.
+ if (aStartHTOffset == 0 && aEndHTOffset == 0) {
+ nsCOMPtr editor;
+ GetAssociatedEditor(getter_AddRefs(editor));
+ if (editor) {
+ PRBool isEmpty = PR_FALSE;
+ editor->GetDocumentIsEmpty(&isEmpty);
+ if (isEmpty) {
+ nsCOMPtr editorRootElm;
+ editor->GetRootElement(getter_AddRefs(editorRootElm));
+
+ nsCOMPtr editorRoot(do_QueryInterface(editorRootElm));
+ if (editorRoot) {
+ *aStartOffset = *aEndOffset = 0;
+ NS_ADDREF(*aStartNode = editorRoot);
+ NS_ADDREF(*aEndNode = editorRoot);
+
+ return NS_OK;
+ }
+ }
+ }
+ }
+
nsCOMPtr startAcc, endAcc;
PRInt32 startOffset = aStartHTOffset, endOffset = aEndHTOffset;
nsIFrame *startFrame = nsnull, *endFrame = nsnull;
diff --git a/accessible/tests/mochitest/Makefile.in b/accessible/tests/mochitest/Makefile.in
index 716e74f688f2..1d48dd75b11f 100644
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -48,9 +48,11 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
moz.png \
longdesc_src.html \
+ common.js \
nsIAccessible_actions.js \
nsIAccessible_name.css \
nsIAccessible_name.xbl \
+ nsIAccessibleEditableText.js \
test_aria_activedescendant.html \
test_aria_role_article.html \
test_bug368835.xul \
@@ -62,16 +64,17 @@ _TEST_FILES =\
test_nsIAccessible_actions.xul \
test_nsIAccessible_name.html \
test_nsIAccessible_name.xul \
+ test_nsIAccessibleDocument.html \
+ test_nsIAccessibleEditableText.html \
+ test_nsIAccessibleHyperLink.html \
+ test_nsIAccessibleHyperLink.xul \
+ test_nsIAccessibleHyperText.html \
+ test_nsIAccessibleImage.html \
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 \
diff --git a/accessible/tests/mochitest/common.js b/accessible/tests/mochitest/common.js
new file mode 100644
index 000000000000..2c08774fb127
--- /dev/null
+++ b/accessible/tests/mochitest/common.js
@@ -0,0 +1,118 @@
+////////////////////////////////////////////////////////////////////////////////
+// Interfaces
+
+const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+
+const nsIAccessibleEvent = Components.interfaces.nsIAccessibleEvent;
+const nsIAccessibleStates = Components.interfaces.nsIAccessibleStates;
+const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
+const nsIAccessibleTypes = Components.interfaces.nsIAccessibleTypes;
+
+const nsIAccessibleRelation = Components.interfaces.nsIAccessibleRelation;
+
+const nsIAccessNode = Components.interfaces.nsIAccessNode;
+const nsIAccessible = Components.interfaces.nsIAccessible;
+
+const nsIAccessibleDocument = Components.interfaces.nsIAccessibleDocument;
+
+const nsIAccessibleText = Components.interfaces.nsIAccessibleText;
+const nsIAccessibleEditableText = Components.interfaces.nsIAccessibleEditableText;
+
+const nsIAccessibleHyperLink = Components.interfaces.nsIAccessibleHyperLink;
+const nsIAccessibleHyperText = Components.interfaces.nsIAccessibleHyperText;
+
+const nsIAccessibleImage = Components.interfaces.nsIAccessibleImage;
+const nsIAccessibleSelectable = Components.interfaces.nsIAccessibleSelectable;
+const nsIAccessibleTable = Components.interfaces.nsIAccessibleTable;
+const nsIAccessibleValue = Components.interfaces.nsIAccessibleValue;
+
+const nsIObserverService = Components.interfaces.nsIObserverService;
+
+const nsIDOMNode = Components.interfaces.nsIDOMNode;
+
+////////////////////////////////////////////////////////////////////////////////
+// General
+
+/**
+ * nsIAccessibleRetrieval, initialized when test is loaded.
+ */
+var gAccRetrieval = null;
+
+/**
+ * Return accessible for the given ID attribute or DOM element.
+ *
+ * @param aElmOrID [in] the ID attribute or DOM element to get an accessible
+ * for
+ * @param aInterfaces [in, optional] the accessible interface or the array of
+ * accessible interfaces to query it/them from obtained
+ * accessible
+ * @param aElmObj [out, optional] object to store DOM element which
+ * accessible is created for
+ */
+function getAccessible(aElmOrID, aInterfaces, aElmObj)
+{
+ var elm = null;
+
+ if (aElmOrID instanceof nsIDOMNode) {
+ elm = aElmOrID;
+ } else {
+ var elm = document.getElementById(aElmOrID);
+ if (!elm) {
+ ok(false, "Can't get DOM element for " + aID);
+ return null;
+ }
+ }
+
+ if (aElmObj && (typeof aElmObj == "object"))
+ aElmObj.value = elm;
+
+ var acc = null;
+ try {
+ acc = gAccRetrieval.getAccessibleFor(elm);
+ } catch (e) {
+ }
+
+ if (!acc) {
+ ok(false, "Can't get accessible for " + aID);
+ return null;
+ }
+
+ if (!aInterfaces)
+ return acc;
+
+ if (aInterfaces instanceof Array) {
+ for (var index = 0; index < aInterfaces.length; index++) {
+ try {
+ acc.QueryInterface(aInterfaces[index]);
+ } catch (e) {
+ ok(false, "Can't query " + aInterfaces[index] + " for " + aID);
+ return null;
+ }
+ }
+ return acc;
+ }
+
+ try {
+ acc.QueryInterface(aInterfaces);
+ } catch (e) {
+ ok(false, "Can't query " + aInterfaces + " for " + aID);
+ return null;
+ }
+
+ return acc;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// General
+
+function initialize()
+{
+ gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(nsIAccessibleRetrieval);
+}
+
+addLoadEvent(initialize);
diff --git a/accessible/tests/mochitest/nsIAccessibleEditableText.js b/accessible/tests/mochitest/nsIAccessibleEditableText.js
new file mode 100644
index 000000000000..52ea3d4fab0d
--- /dev/null
+++ b/accessible/tests/mochitest/nsIAccessibleEditableText.js
@@ -0,0 +1,105 @@
+function nsEditableText(aElmOrID)
+{
+ this.setTextContents = function setTextContents(aStr)
+ {
+ try {
+ this.mAcc.setTextContents(aStr);
+
+ is(this.getValue(), aStr,
+ "setTextContents: Can't set " + aStr +
+ " to element with ID '" + this.mID + "'");
+ } catch (e) {
+ ok(false,
+ "setTextContents: Can't set " + aStr +
+ "to element with ID '" + this.mID +
+ "', value '" + this.getValue() + "', exception" + e);
+ }
+ }
+
+ this.insertText = function insertText(aStr, aPos, aResStr)
+ {
+ try {
+ this.mAcc.insertText(aStr, aPos);
+
+ is(this.getValue(), aResStr,
+ "insertText: Can't insert " + aStr + " at " + aPos +
+ " to element with ID '" + this.mID + "'");
+ } catch (e) {
+ ok(false,
+ "insertText: Can't insert " + aStr + " at " + aPos +
+ " to element with ID '" + this.mID +
+ "', value '" + this.getValue() + "', exception " + e);
+ }
+ }
+
+ this.copyNPasteText = function copyNPasteText(aStartPos, aEndPos,
+ aPos, aResStr)
+ {
+ try {
+ this.mAcc.copyText(aStartPos, aEndPos);
+ this.mAcc.pasteText(aPos);
+
+ is(this.getValue(), aResStr,
+ "copyText & pasteText: Can't copy text from " + aStartPos +
+ " to " + aEndPos + " and paste to " + aPos +
+ " for element with ID '" + this.mID + "'");
+ } catch (e) {
+ ok(false,
+ "copyText & pasteText: Can't copy text from " + aStartPos +
+ " to " + aEndPos + " and paste to " + aPos +
+ " for element with ID '" + this.mID +
+ "', value '" + this.getValue() + "', exception " + e);
+ }
+ }
+
+ this.cutNPasteText = function copyNPasteText(aStartPos, aEndPos,
+ aPos, aResStr)
+ {
+ try {
+ this.mAcc.cutText(aStartPos, aEndPos);
+ this.mAcc.pasteText(aPos);
+
+ is(this.getValue(), aResStr,
+ "cutText & pasteText: Can't cut text from " + aStartPos +
+ " to " + aEndPos + " and paste to " + aPos +
+ " for element with ID '" + this.mID + "'");
+ } catch (e) {
+ ok(false,
+ "cutText & pasteText: Can't cut text from " + aStartPos +
+ " to " + aEndPos + " and paste to " + aPos +
+ " for element with ID '" + this.mID +
+ "', value '" + this.getValue() + "', exception " + e);
+ }
+ }
+
+ this.deleteText = function deleteText(aStartPos, aEndPos, aResStr)
+ {
+ try {
+ this.mAcc.deleteText(aStartPos, aEndPos);
+
+ is(this.getValue(), aResStr,
+ "deleteText: Can't delete text from " + aStartPos +
+ " to " + aEndPos + " for element with ID '" + this.mID + "'");
+ } catch (e) {
+ ok(false,
+ "deleteText: Can't delete text from " + aStartPos +
+ " to " + aEndPos + " for element with ID '" + this.mID +
+ "', value " + this.getValue() + ", exception " + e);
+ }
+ }
+
+ this.getValue = function getValue()
+ {
+ if (this.mElm instanceof Components.interfaces.nsIDOMNSEditableElement)
+ return this.mElm.value;
+ if (this.mElm instanceof Components.interfaces.nsIDOMHTMLDocument)
+ return this.mElm.body.textContent;
+ return this.mElm.textContent;
+ }
+
+ var elmObj = { value: null };
+ this.mAcc = getAccessible(aElmOrID, nsIAccessibleEditableText, elmObj);
+
+ this.mElm = elmObj.value;
+ this.mID = aElmOrID;
+}
diff --git a/accessible/tests/mochitest/test_nsIAccessibleEditableText.html b/accessible/tests/mochitest/test_nsIAccessibleEditableText.html
new file mode 100644
index 000000000000..d5c69f317bdf
--- /dev/null
+++ b/accessible/tests/mochitest/test_nsIAccessibleEditableText.html
@@ -0,0 +1,95 @@
+
+
+
+
+ nsIAccessibleEditableText chrome tests
+
+
+
+
+
+
+
+
+
+
+
+ Mozilla Bug 452161
+
+
+
+
+
+
+
+
+
+
+
+