Bug 626660 - cache rendered text on a11y side, r=davidb, f=marcoz, a=betaN

This commit is contained in:
Alexander Surkov 2011-01-31 23:53:09 +08:00
parent 86117cb12b
commit e32b030dea
17 changed files with 389 additions and 160 deletions

View File

@ -279,7 +279,7 @@ AccStateChangeEvent::CreateXPCOMObject()
// XXX revisit this when coalescence is faster (eCoalesceFromSameSubtree)
AccTextChangeEvent::
AccTextChangeEvent(nsAccessible* aAccessible, PRInt32 aStart,
nsAString& aModifiedText, PRBool aIsInserted,
const nsAString& aModifiedText, PRBool aIsInserted,
EIsFromUserInput aIsFromUserInput)
: AccEvent(aIsInserted ?
static_cast<PRUint32>(nsIAccessibleEvent::EVENT_TEXT_INSERTED) :

View File

@ -206,7 +206,7 @@ class AccTextChangeEvent: public AccEvent
{
public:
AccTextChangeEvent(nsAccessible* aAccessible, PRInt32 aStart,
nsAString& aModifiedText, PRBool aIsInserted,
const nsAString& aModifiedText, PRBool aIsInserted,
EIsFromUserInput aIsFromUserInput = eAutoDetect);
// AccEvent

View File

@ -36,16 +36,15 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsEventShell.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "nsDocAccessible.h"
#include "NotificationController.h"
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "nsDocAccessible.h"
#include "nsEventShell.h"
#include "nsTextAccessible.h"
////////////////////////////////////////////////////////////////////////////////
// NotificationCollector
@ -574,6 +573,290 @@ NotificationController::CreateTextChangeEventFor(AccMutationEvent* aEvent)
aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
}
////////////////////////////////////////////////////////////////////////////////
// Notification controller: text leaf accessible text update
/**
* Used to find a difference between old and new text and fire text change
* events.
*/
class TextUpdater
{
public:
TextUpdater(nsDocAccessible* aDocument, nsTextAccessible* aTextLeaf) :
mDocument(aDocument), mTextLeaf(aTextLeaf) { }
~TextUpdater() { mDocument = nsnull; mTextLeaf = nsnull; }
/**
* Update text of the text leaf accessible, fire text change events for its
* container hypertext accessible.
*/
void Run(const nsAString& aNewText);
private:
TextUpdater();
TextUpdater(const TextUpdater&);
TextUpdater& operator = (const TextUpdater&);
/**
* Fire text change events based on difference between strings.
*/
void FindDiffNFireEvents(const nsDependentSubstring& aStr1,
const nsDependentSubstring& aStr2,
PRUint32** aMatrix,
PRUint32 aStartOffset);
/**
* Change type used to describe the diff between strings.
*/
enum ChangeType {
eNoChange,
eInsertion,
eRemoval,
eSubstitution
};
/**
* Helper to fire text change events.
*/
inline void MayFireEvent(nsAString* aInsertedText, nsAString* aRemovedText,
PRUint32 aOffset, ChangeType* aChange)
{
if (*aChange == eNoChange)
return;
if (*aChange == eRemoval || *aChange == eSubstitution) {
FireEvent(*aRemovedText, aOffset, PR_FALSE);
aRemovedText->Truncate();
}
if (*aChange == eInsertion || *aChange == eSubstitution) {
FireEvent(*aInsertedText, aOffset, PR_TRUE);
aInsertedText->Truncate();
}
*aChange = eNoChange;
}
/**
* Fire text change event.
*/
void FireEvent(const nsAString& aModText, PRUint32 aOffset, PRBool aType);
private:
nsDocAccessible* mDocument;
nsTextAccessible* mTextLeaf;
};
void
TextUpdater::Run(const nsAString& aNewText)
{
NS_ASSERTION(mTextLeaf, "No text leaf accessible?");
const nsString& oldText = mTextLeaf->Text();
PRUint32 oldLen = oldText.Length(), newLen = aNewText.Length();
PRUint32 minLen = oldLen < newLen ? oldLen : newLen;
// Skip coinciding begin substrings.
PRUint32 skipIdx = 0;
for (; skipIdx < minLen; skipIdx++) {
if (aNewText[skipIdx] != oldText[skipIdx])
break;
}
// No change, text append or removal to/from the end.
if (skipIdx == minLen) {
if (oldLen == newLen)
return;
// If text has been appended to the end, fire text inserted event.
if (oldLen < newLen) {
FireEvent(Substring(aNewText, oldLen), oldLen, PR_TRUE);
mTextLeaf->SetText(aNewText);
return;
}
// Text has been removed from the end, fire text removed event.
FireEvent(Substring(oldText, newLen), newLen, PR_FALSE);
mTextLeaf->SetText(aNewText);
return;
}
// Trim coinciding substrings from the end.
PRUint32 endIdx = minLen;
if (oldLen < newLen) {
PRUint32 delta = newLen - oldLen;
for (; endIdx > skipIdx; endIdx--) {
if (aNewText[endIdx + delta] != oldText[endIdx])
break;
}
} else {
PRUint32 delta = oldLen - newLen;
for (; endIdx > skipIdx; endIdx--) {
if (aNewText[endIdx] != oldText[endIdx + delta])
break;
}
}
PRUint32 oldEndIdx = oldLen - minLen + endIdx;
PRUint32 newEndIdx = newLen - minLen + endIdx;
// Find the difference starting from start character, we can skip initial and
// final coinciding characters since they don't affect on the Levenshtein
// distance.
const nsDependentSubstring& str1 =
Substring(oldText, skipIdx, oldEndIdx - skipIdx);
const nsDependentSubstring& str2 =
Substring(aNewText, skipIdx, newEndIdx - skipIdx);
// Compute the matrix.
PRUint32 len1 = str1.Length() + 1, len2 = str2.Length() + 1;
PRUint32** matrix = new PRUint32*[len1];
for (PRUint32 i = 0; i < len1; i++)
matrix[i] = new PRUint32[len2];
matrix[0][0] = 0;
for (PRUint32 i = 1; i < len1; i++)
matrix[i][0] = i;
for (PRUint32 j = 1; j < len2; j++)
matrix[0][j] = j;
for (PRUint32 i = 1; i < len1; i++) {
for (PRUint32 j = 1; j < len2; j++) {
if (str1[i - 1] != str2[j - 1]) {
PRUint32 left = matrix[i - 1][j];
PRUint32 up = matrix[i][j - 1];
PRUint32 upleft = matrix[i - 1][j - 1];
matrix[i][j] =
(left < up ? (upleft < left ? upleft : left) :
(upleft < up ? upleft : up)) + 1;
} else {
matrix[i][j] = matrix[i - 1][j - 1];
}
}
}
FindDiffNFireEvents(str1, str2, matrix, skipIdx);
for (PRUint32 i = 0; i < len1; i++)
delete[] matrix[i];
delete[] matrix;
mTextLeaf->SetText(aNewText);
}
void
TextUpdater::FindDiffNFireEvents(const nsDependentSubstring& aStr1,
const nsDependentSubstring& aStr2,
PRUint32** aMatrix,
PRUint32 aStartOffset)
{
// Find the difference.
ChangeType change = eNoChange;
nsAutoString insertedText;
nsAutoString removedText;
PRUint32 offset = 0;
PRInt32 i = aStr1.Length(), j = aStr2.Length();
while (i >= 0 && j >= 0) {
if (aMatrix[i][j] == 0) {
MayFireEvent(&insertedText, &removedText, offset + aStartOffset, &change);
return;
}
// move up left
if (i >= 1 && j >= 1) {
// no change
if (aStr1[i - 1] == aStr2[j - 1]) {
MayFireEvent(&insertedText, &removedText, offset + aStartOffset, &change);
i--; j--;
continue;
}
// substitution
if (aMatrix[i][j] == aMatrix[i - 1][j - 1] + 1) {
if (change != eSubstitution)
MayFireEvent(&insertedText, &removedText, offset + aStartOffset, &change);
offset = j - 1;
insertedText.Append(aStr1[i - 1]);
removedText.Append(aStr2[offset]);
change = eSubstitution;
i--; j--;
continue;
}
}
// move up, insertion
if (j >= 1 && aMatrix[i][j] == aMatrix[i][j - 1] + 1) {
if (change != eInsertion)
MayFireEvent(&insertedText, &removedText, offset + aStartOffset, &change);
offset = j - 1;
insertedText.Insert(aStr2[offset], 0);
change = eInsertion;
j--;
continue;
}
// move left, removal
if (i >= 1 && aMatrix[i][j] == aMatrix[i - 1][j] + 1) {
if (change != eRemoval) {
MayFireEvent(&insertedText, &removedText, offset + aStartOffset, &change);
offset = j;
}
removedText.Insert(aStr1[i - 1], 0);
change = eRemoval;
i--;
continue;
}
NS_NOTREACHED("Huh?");
return;
}
MayFireEvent(&insertedText, &removedText, offset + aStartOffset, &change);
}
void
TextUpdater::FireEvent(const nsAString& aModText, PRUint32 aOffset,
PRBool aIsInserted)
{
nsAccessible* parent = mTextLeaf->GetParent();
NS_ASSERTION(parent, "No parent for text leaf!");
nsHyperTextAccessible* hyperText = parent->AsHyperText();
NS_ASSERTION(hyperText, "Text leaf parnet is not hyper text!");
PRInt32 textLeafOffset = hyperText->GetChildOffset(mTextLeaf, PR_TRUE);
NS_ASSERTION(textLeafOffset != -1,
"Text leaf hasn't offset within hyper text!");
// Fire text change event.
nsRefPtr<AccEvent> textChangeEvent =
new AccTextChangeEvent(hyperText, textLeafOffset + aOffset, aModText,
aIsInserted);
mDocument->FireDelayedAccessibleEvent(textChangeEvent);
// Fire value change event.
if (hyperText->Role() == nsIAccessibleRole::ROLE_ENTRY) {
nsRefPtr<AccEvent> valueChangeEvent =
new AccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, hyperText,
eAutoDetect, AccEvent::eRemoveDupes);
mDocument->FireDelayedAccessibleEvent(valueChangeEvent);
}
}
PLDHashOperator
NotificationController::TextEnumerator(nsCOMPtrHashKey<nsIContent>* aEntry,
void* aUserArg)
@ -601,12 +884,12 @@ NotificationController::TextEnumerator(nsCOMPtrHashKey<nsIContent>* aEntry,
nsIContent* containerElm = containerNode->IsElement() ?
containerNode->AsElement() : nsnull;
nsAutoString renderedText;
textFrame->GetRenderedText(&renderedText);
nsAutoString text;
textFrame->GetRenderedText(&text);
// Remove text accessible if rendered text is empty.
if (textAcc) {
if (renderedText.IsEmpty()) {
if (text.IsEmpty()) {
#ifdef DEBUG_NOTIFICATIONS
PRUint32 index = containerNode->IndexOf(textNode);
@ -624,13 +907,36 @@ NotificationController::TextEnumerator(nsCOMPtrHashKey<nsIContent>* aEntry,
#endif
document->ContentRemoved(containerElm, textNode);
return PL_DHASH_NEXT;
}
// Update text of the accessible and fire text change events.
#ifdef DEBUG_TEXTCHANGE
PRUint32 index = containerNode->IndexOf(textNode);
nsCAutoString tag;
nsCAutoString id;
if (containerElm) {
containerElm->Tag()->ToUTF8String(tag);
nsIAtom* atomid = containerElm->GetID();
if (atomid)
atomid->ToUTF8String(id);
}
printf("\ntext may be changed: container: %s@id='%s', index in container: %d, old text '%s', new text: '%s'\n\n",
tag.get(), id.get(), index,
NS_ConvertUTF16toUTF8(textAcc->AsTextLeaf()->Text()).get(),
NS_ConvertUTF16toUTF8(text).get());
#endif
TextUpdater updater(document, textAcc->AsTextLeaf());
updater.Run(text);
return PL_DHASH_NEXT;
}
// Append an accessible if rendered text is not empty.
if (!renderedText.IsEmpty()) {
if (!text.IsEmpty()) {
#ifdef DEBUG_NOTIFICATIONS
PRUint32 index = containerNode->IndexOf(textNode);
@ -722,3 +1028,4 @@ NotificationController::ContentInsertion::Process()
mContainer = nsnull;
mInsertedContent.Clear();
}

View File

@ -51,6 +51,7 @@ class nsIContent;
#ifdef DEBUG_NOTIFICATIONS
#define DEBUG_CONTENTMUTATION
#define DEBUG_TEXTCHANGE
#endif
/**

View File

@ -913,27 +913,24 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
// Attempt to create an accessible based on what we know.
nsRefPtr<nsAccessible> newAcc;
if (content->IsNodeOfType(nsINode::eTEXT)) {
// --- Create HTML for visible text frames ---
nsIFrame* f = weakFrame.GetFrame();
if (f && f->IsEmpty()) {
nsAutoString renderedWhitespace;
f->GetRenderedText(&renderedWhitespace, nsnull, nsnull, 0, 1);
if (renderedWhitespace.IsEmpty()) {
// Really empty -- nothing is rendered
if (aIsSubtreeHidden)
*aIsSubtreeHidden = true;
return nsnull;
}
}
if (weakFrame.IsAlive()) {
newAcc = weakFrame.GetFrame()->CreateAccessible();
if (docAcc->BindToDocument(newAcc, nsnull))
return newAcc.forget();
// Create accessible for visible text frames.
if (content->IsNodeOfType(nsINode::eTEXT)) {
nsAutoString text;
weakFrame->GetRenderedText(&text, nsnull, nsnull, 0, PR_UINT32_MAX);
if (text.IsEmpty()) {
if (aIsSubtreeHidden)
*aIsSubtreeHidden = true;
return nsnull;
}
newAcc = weakFrame->CreateAccessible();
if (docAcc->BindToDocument(newAcc, nsnull)) {
newAcc->AsTextLeaf()->SetText(text);
return newAcc.forget();
}
return nsnull;
}

View File

@ -1248,14 +1248,12 @@ void nsDocAccessible::CharacterDataWillChange(nsIDocument *aDocument,
nsIContent* aContent,
CharacterDataChangeInfo* aInfo)
{
FireTextChangeEventForText(aContent, aInfo, PR_FALSE);
}
void nsDocAccessible::CharacterDataChanged(nsIDocument *aDocument,
nsIContent* aContent,
CharacterDataChangeInfo* aInfo)
{
FireTextChangeEventForText(aContent, aInfo, PR_TRUE);
}
void
@ -1684,81 +1682,6 @@ nsDocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
return false;
}
void
nsDocAccessible::FireValueChangeForTextFields(nsAccessible *aAccessible)
{
if (aAccessible->Role() != nsIAccessibleRole::ROLE_ENTRY)
return;
// Dependent value change event for text changes in textfields
nsRefPtr<AccEvent> valueChangeEvent =
new AccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible,
eAutoDetect, AccEvent::eRemoveDupes);
FireDelayedAccessibleEvent(valueChangeEvent);
}
void
nsDocAccessible::FireTextChangeEventForText(nsIContent *aContent,
CharacterDataChangeInfo* aInfo,
PRBool aIsInserted)
{
if (!IsContentLoaded())
return;
PRInt32 contentOffset = aInfo->mChangeStart;
PRUint32 contentLength = aIsInserted ?
aInfo->mReplaceLength: // text has been added
aInfo->mChangeEnd - contentOffset; // text has been removed
if (contentLength == 0)
return;
nsAccessible *accessible = GetAccService()->GetAccessible(aContent);
if (!accessible)
return;
nsAccessible* parent = accessible->GetParent();
if (!parent)
return;
nsHyperTextAccessible* textAccessible = parent->AsHyperText();
if (!textAccessible)
return;
// Get offset within hypertext accessible and invalidate cached offsets after
// this child accessible.
PRInt32 offset = textAccessible->GetChildOffset(accessible, PR_TRUE);
// Get added or removed text.
nsIFrame* frame = aContent->GetPrimaryFrame();
if (!frame)
return;
PRUint32 textOffset = 0;
nsresult rv = textAccessible->ContentToRenderedOffset(frame, contentOffset,
&textOffset);
if (NS_FAILED(rv))
return;
nsAutoString text;
rv = accessible->AppendTextTo(text, textOffset, contentLength);
if (NS_FAILED(rv))
return;
if (text.IsEmpty())
return;
// Normally we only fire delayed events created from the node, not an
// accessible object. See the AccTextChangeEvent constructor for details
// about this exceptional case.
nsRefPtr<AccEvent> event =
new AccTextChangeEvent(textAccessible, offset + textOffset, text,
aIsInserted);
FireDelayedAccessibleEvent(event);
FireValueChangeForTextFields(textAccessible);
}
// nsDocAccessible public member
nsresult
nsDocAccessible::FireDelayedAccessibleEvent(PRUint32 aEventType, nsINode *aNode,

View File

@ -415,25 +415,6 @@ protected:
*/
void ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute);
/**
* Fire text changed event for character data changed. The method is used
* from nsIMutationObserver methods.
*
* @param aContent the text node holding changed data
* @param aInfo info structure describing how the data was changed
* @param aIsInserted the flag pointed whether removed or inserted
* characters should be cause of event
*/
void FireTextChangeEventForText(nsIContent *aContent,
CharacterDataChangeInfo* aInfo,
PRBool aIsInserted);
/**
* Fire a value change event for the the given accessible if it is a text
* field (has a ROLE_ENTRY).
*/
void FireValueChangeForTextFields(nsAccessible *aAccessible);
/**
* Process the event when the queue of pending events is untwisted. Fire
* accessible events as result of the processing.

View File

@ -54,10 +54,16 @@ public:
virtual nsresult AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
PRUint32 aLength);
protected:
// nsTextAccessible
void SetText(const nsAString& aText) { mText = aText; }
const nsString& Text() const { return mText; }
protected:
// nsAccessible
virtual void CacheChildren();
protected:
nsString mText;
};

View File

@ -36,7 +36,7 @@ function editableTextTest(aID)
/**
* setTextContents test.
*/
this.setTextContents = function setTextContents(aStr)
this.setTextContents = function setTextContents(aStr, aResValue)
{
var testID = "setTextContents '" + aStr + "' for " + prettyName(aID);
@ -46,15 +46,15 @@ function editableTextTest(aID)
acc.setTextContents(aStr);
}
this.sheduleTest(aID, null, [0, aStr.length, aStr],
setTextContentsInvoke, getValueChecker(aID, aResValue),
testID);
this.scheduleTest(aID, null, [0, aStr.length, aStr],
setTextContentsInvoke, getValueChecker(aID, aResValue),
testID);
}
/**
* insertText test.
*/
this.insertText = function insertText(aStr, aPos, aResStr)
this.insertText = function insertText(aStr, aPos, aResStr, aResPos)
{
var testID = "insertText '" + aStr + "' at " + aPos + " for " +
prettyName(aID);
@ -65,7 +65,8 @@ function editableTextTest(aID)
acc.insertText(aStr, aPos);
}
this.scheduleTest(aID, null, [aPos, aPos + aStr.length, aStr],
var resPos = (aResPos != undefined) ? aResPos : aPos;
this.scheduleTest(aID, null, [resPos, resPos + aStr.length, aStr],
insertTextInvoke, getValueChecker(aID, aResStr), testID);
}
@ -110,7 +111,8 @@ function editableTextTest(aID)
/**
* cutText test.
*/
this.cutText = function cutText(aStartPos, aEndPos, aResStr)
this.cutText = function cutText(aStartPos, aEndPos, aResStr,
aResStartPos, aResEndPos)
{
var testID = "cutText from " + aStartPos + " to " + aEndPos + " for " +
prettyName(aID);
@ -121,7 +123,9 @@ function editableTextTest(aID)
acc.cutText(aStartPos, aEndPos);
}
this.scheduleTest(aID, [aStartPos, aEndPos, getTextFromClipboard], null,
var resStartPos = (aResStartPos != undefined) ? aResStartPos : aStartPos;
var resEndPos = (aResEndPos != undefined) ? aResEndPos : aEndPos;
this.scheduleTest(aID, [resStartPos, resEndPos, getTextFromClipboard], null,
cutTextInvoke, getValueChecker(aID, aResStr), testID);
}

View File

@ -64,12 +64,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452161
aTestRun.add(et);
}
//gA11yEventDumpToConsole = true; // debug stuff
function runTest()
{
var testRun = new editableTextTestRun();
addTestEditable("input", testRun);
// addTestEditable("div"); XXX: bug 452599
addTestEditable("div", testRun);
addTestEditable(getNode("frame").contentDocument, testRun);
testRun.run(); // Will call SimpleTest.finish();
@ -94,6 +96,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452161
<a target="_blank"
title="nsIAccessibleEditableText chrome tests"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=452161">Mozilla Bug 452161</a>
<a target="_blank"
title="Cache rendered text on a11y side"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=626660">
Mozilla Bug 626660
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
@ -101,7 +108,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452161
<input id="input"/>
<div id="div" contentEditable="true"/>
<div id="div" contentEditable="true"></div>
<iframe id="frame"/>
</body>

View File

@ -22,9 +22,14 @@
{
var et = new editableTextTest("input");
et.insertText("ee", 1, "heeello");
// 'ee' insertion/removal at 1 or 2 offset of 'hello'/'heeello' string
// reports 'ee' text was inserted/removed at 2 offset.
et.insertText("ee", 1, "heeello", 2);
et.copyText(1, 3, "ee");
et.cutText(1, 3, "hello");
et.cutText(1, 3, "hello", 2, 4);
et.insertText("ee", 2, "heeello", 2);
et.cutText(2, 4, "hello", 2, 4);
et.deleteText(1, 3, "hlo");
et.pasteText(1, "heelo");
@ -44,6 +49,11 @@
href="https://bugzilla.mozilla.org/show_bug.cgi?id=524115">
Mozilla Bug 524115
</a>
<a target="_blank"
title="Cache rendered text on a11y side"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=626660">
Mozilla Bug 626660
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">

View File

@ -90,6 +90,8 @@
}
}
//gA11yEventDumpToConsole = true; // debug stuff
var gQueue = null;
function doTest()
{

View File

@ -73,8 +73,7 @@
// Note: if input have label elements then the name isn't calculated
// from them.
testName("btn_labelledby_mixed_input",
"Submit Query Reset Submit Query");
// XXX Bug 567203 "input button Submit Query Reset Submit Query");
"input button Submit Query Reset Submit Query");
// Gets the name from the title of object element.
testName("btn_labelledby_mixed_object", "object");

View File

@ -52,11 +52,7 @@
children: [
{
role: ROLE_ENTRY,
children: [
{
role: ROLE_TEXT_LEAF // Text node for the node's value
}
]
children: [ ] // no text leaf accessible for text node
},
{
role: ROLE_COMBOBOX_LIST, // context menu
@ -94,7 +90,8 @@
role: ROLE_ENTRY,
children: [
{
role: ROLE_TEXT_LEAF
role: ROLE_TEXT_LEAF,
name: "http://mochi.test:8888/redirect-a11y.html"
}
]
},
@ -122,11 +119,7 @@
},
{
role: ROLE_ENTRY,
children: [
{
role: ROLE_TEXT_LEAF // Text node for the node's value
}
]
children: [ ] // no text leaf accessible for text node
},
{
role: ROLE_COMBOBOX_LIST, // context menu popup
@ -150,6 +143,11 @@
href="https://bugzilla.mozilla.org/show_bug.cgi?id=249292"
title="Ensure accessible children for toolbarbutton types 'menu' and 'menu-button'">
Mozilla Bug 249292
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=626660"
title="Cache rendered text on a11y side">
Mozilla Bug 626660
</a><br/>
<p id="display"></p>
<div id="content" style="display: none">

View File

@ -29,9 +29,7 @@
] }
] },
{ TEXT_LEAF: [ ] }, // body text
{ ENTRY: [ // input under document element
{ TEXT_LEAF: [ ] }
] },
{ ENTRY: [ ] }, // input under document element
{ PARAGRAPH: [ // link under document element
{ TEXT_LEAF: [ ] }, // link content
{ STATICTEXT: [ ] }, // generated content

View File

@ -47,9 +47,7 @@
// input@type="text", no value
accTree =
{ ENTRY: [
{ TEXT_LEAF: [ ] }
] };
{ ENTRY: [ ] };
testAccessibleTree("txc3", accTree);

View File

@ -323,9 +323,7 @@
{
var tree =
{ DOCUMENT: [
{ ENTRY: [
{ TEXT_LEAF: [ ] }
] }
{ ENTRY: [ ] }
] };
testAccessibleTree(this.docNode, tree);