Bug 606125 - develop a way to handle visibility style, r=marcoz, davidb, sr=bz, a=blocking

--HG--
rename : accessible/tests/mochitest/treeupdate/test_tableinsubtree.html => accessible/tests/mochitest/treeupdate/test_ariadialog.html
This commit is contained in:
Alexander Surkov 2010-11-13 12:49:26 -05:00
Родитель 8466507cd8
Коммит 6e8119fa5f
12 изменённых файлов: 648 добавлений и 76 удалений

Просмотреть файл

@ -113,16 +113,16 @@ nsAccTreeWalker::GetNextChildInternal(PRBool aNoWalkUp)
nsIContent* childNode = mState->childList->GetNodeAt(mState->childIdx);
mState->childIdx++;
PRBool isHidden = PR_FALSE;
bool isSubtreeHidden = false;
nsRefPtr<nsAccessible> accessible =
GetAccService()->GetOrCreateAccessible(childNode, presShell, mWeakShell,
&isHidden);
&isSubtreeHidden);
if (accessible)
return accessible.forget();
// Walk down into subtree to find accessibles.
if (!isHidden) {
if (!isSubtreeHidden) {
if (!PushState(childNode))
break;

Просмотреть файл

@ -869,13 +869,13 @@ already_AddRefed<nsAccessible>
nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
nsIPresShell* aPresShell,
nsIWeakReference* aWeakShell,
PRBool* aIsHidden)
bool* aIsSubtreeHidden)
{
if (!aPresShell || !aWeakShell || !aNode || gIsShutdown)
return nsnull;
if (aIsHidden)
*aIsHidden = PR_FALSE;
if (aIsSubtreeHidden)
*aIsSubtreeHidden = false;
// Check to see if we already have an accessible for this node in the cache.
nsAccessible *cachedAccessible = GetCachedAccessible(aNode, aWeakShell);
@ -916,10 +916,11 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
// methods on a dead frame pointer.
nsWeakFrame weakFrame = content->GetPrimaryFrame();
// Check frame to see if it is hidden.
if (!weakFrame.GetFrame()) {
if (aIsHidden)
*aIsHidden = PR_TRUE;
// Check frame and its visibility. Note, hidden frame allows visible
// elements in subtree.
if (!weakFrame.GetFrame() || !weakFrame->GetStyleVisibility()->IsVisible()) {
if (aIsSubtreeHidden && !weakFrame.GetFrame())
*aIsSubtreeHidden = true;
return nsnull;
}
@ -953,8 +954,8 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
f->GetRenderedText(&renderedWhitespace, nsnull, nsnull, 0, 1);
if (renderedWhitespace.IsEmpty()) {
// Really empty -- nothing is rendered
if (aIsHidden)
*aIsHidden = PR_TRUE;
if (aIsSubtreeHidden)
*aIsSubtreeHidden = true;
return nsnull;
}
@ -982,8 +983,8 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
nsAutoString name;
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::name, name);
if (!name.IsEmpty()) {
if (aIsHidden)
*aIsHidden = PR_TRUE;
if (aIsSubtreeHidden)
*aIsSubtreeHidden = true;
return nsnull;
}
@ -1107,8 +1108,8 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
// captions. This could not be done in
// nsTableCaptionFrame::GetAccessible() because the descendants of
// the table caption would still be created. By setting
// *aIsHidden = PR_TRUE we ensure that no descendant accessibles are
// created.
// *aIsSubtreeHidden = true we ensure that no descendant accessibles
// are created.
nsIFrame* f = weakFrame.GetFrame();
if (!f) {
f = aPresShell->GetRealPrimaryFrameFor(content);
@ -1117,8 +1118,8 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
f->GetRect().IsEmpty()) {
// XXX This is not the ideal place for this code, but right now there
// is no better place:
if (aIsHidden)
*aIsHidden = PR_TRUE;
if (aIsSubtreeHidden)
*aIsSubtreeHidden = true;
return nsnull;
}

Просмотреть файл

@ -111,9 +111,9 @@ public:
virtual void RemoveNativeRootAccessible(nsAccessible* aRootAccessible);
virtual void ContentRangeInserted(nsIPresShell* aPresShell,
nsIContent* aContainer,
nsIContent* aStartChild,
nsIContent* aEndChild);
nsIContent* aContainer,
nsIContent* aStartChild,
nsIContent* aEndChild);
virtual void ContentRemoved(nsIPresShell* aPresShell, nsIContent* aContainer,
nsIContent* aChild);
@ -138,16 +138,16 @@ public:
* Return an accessible for the given DOM node from the cache or create new
* one.
*
* @param aNode [in] the given node
* @param aPresShell [in] the pres shell of the node
* @param aWeakShell [in] the weak shell for the pres shell
* @param aIsHidden [out, optional] indicates whether the node's frame is
* hidden
* @param aNode [in] the given node
* @param aPresShell [in] the pres shell of the node
* @param aWeakShell [in] the weak shell for the pres shell
* @param aIsSubtreeHidden [out, optional] indicates whether the node's
* frame and its subtree is hidden
*/
already_AddRefed<nsAccessible>
GetOrCreateAccessible(nsINode* aNode, nsIPresShell* aPresShell,
nsIWeakReference* aWeakShell,
PRBool* aIsHidden = nsnull);
bool* aIsSubtreeHidden = nsnull);
/**
* Return an accessible for the given DOM node.

Просмотреть файл

@ -237,11 +237,6 @@ nsresult
nsTextEquivUtils::AppendFromAccessible(nsAccessible *aAccessible,
nsAString *aString)
{
// Ignore hidden accessible for name computation.
nsIFrame* frame = aAccessible->GetFrame();
if (!frame || !frame->GetStyleVisibility()->IsVisible())
return NS_OK;
//XXX: is it necessary to care the accessible is not a document?
if (aAccessible->IsContent()) {
nsresult rv = AppendTextEquivFromTextContent(aAccessible->GetContent(),

Просмотреть файл

@ -320,27 +320,41 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree)
if (!acc)
return;
for (var prop in aAccTree) {
var accTree = aAccTree;
// Support of simplified accessible tree object.
var key = Object.keys(accTree)[0];
var roleName = "ROLE_" + key;
if (roleName in nsIAccessibleRole) {
accTree = {
role: nsIAccessibleRole[roleName],
children: accTree[key]
};
}
// Test accessible properties.
for (var prop in accTree) {
var msg = "Wrong value of property '" + prop + "' for " + prettyName(acc) + ".";
if (prop == "role") {
is(roleToString(acc[prop]), roleToString(aAccTree[prop]), msg);
is(roleToString(acc[prop]), roleToString(accTree[prop]), msg);
} else if (prop == "states") {
var statesObj = aAccTree[prop];
var statesObj = accTree[prop];
testStates(acc, statesObj.states, statesObj.extraStates,
statesObj.absentStates, statesObj.absentExtraStates);
} else if (prop != "children") {
is(acc[prop], aAccTree[prop], msg);
is(acc[prop], accTree[prop], msg);
}
}
if ("children" in aAccTree && aAccTree["children"] instanceof Array) {
// Test children.
if ("children" in accTree && accTree["children"] instanceof Array) {
var children = acc.children;
is(children.length, aAccTree.children.length,
is(children.length, accTree.children.length,
"Different amount of expected children of " + prettyName(acc) + ".");
if (aAccTree.children.length == children.length) {
if (accTree.children.length == children.length) {
var childCount = children.length;
// nsIAccessible::firstChild
@ -390,7 +404,7 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree)
"Wrong previous sibling of " + prettyName(child));
// Go down through subtree
testAccessibleTree(child, aAccTree.children[i]);
testAccessibleTree(child, accTree.children[i]);
}
}
}

Просмотреть файл

@ -293,6 +293,13 @@
gQueue.push(new changeStyle(id, "display", "none", kHideEvents));
gQueue.push(new changeStyle(id, "display", "inline", kShowEvents));
// Show/hide events by changing of visibility style of accessible DOM node
// from 'visible' to 'hidden', 'hidden' to 'visible'.
var id = "link2";
getAccessible(id);
gQueue.push(new changeStyle(id, "visibility", "hidden", kHideEvents));
gQueue.push(new changeStyle(id, "visibility", "visible", kShowEvents));
// Show/hide events by changing of display style of accessible DOM node
// from 'inline' to 'block', 'block' to 'inline'.
var id = "link3";
@ -300,6 +307,12 @@
gQueue.push(new changeStyle(id, "display", "block", kHideAndShowEvents));
gQueue.push(new changeStyle(id, "display", "inline", kHideAndShowEvents));
// Show/hide events by changing of visibility style of accessible DOM node
// from 'collapse' to 'visible', 'visible' to 'collapse'.
var id = "link4";
gQueue.push(new changeStyle(id, "visibility", "visible", kShowEvents));
gQueue.push(new changeStyle(id, "visibility", "collapse", kHideEvents));
// Show/hide events by adding new accessible DOM node and removing old one.
var id = "link5";
gQueue.push(new cloneAndAppendToDOM(id));
@ -343,6 +356,10 @@
gQueue.push(new changeClass("container2", "link7", "displayNone",
kHideEvents));
gQueue.push(new changeClass("container3", "link8", "", kShowEvents));
gQueue.push(new changeClass("container3", "link8", "visibilityHidden",
kHideEvents));
gQueue.invoke(); // Will call SimpleTest.finish();
}
@ -367,6 +384,11 @@
title="Rework accessible tree update code"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=570275">
Mozilla Bug 570275
</a><br>
<a target="_blank"
title="Develop a way to handle visibility style"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=606125">
Mozilla Bug 606125
</a>
<p id="display"></p>

Просмотреть файл

@ -70,9 +70,6 @@
var tabsAccTree = {
role: ROLE_PAGETABLIST,
children: [
{
role: ROLE_PUSHBUTTON // tab scroll up button
},
{
role: ROLE_PAGETAB,
children: [
@ -91,9 +88,6 @@
},
{
role: ROLE_PUSHBUTTON
},
{
role: ROLE_PUSHBUTTON // tab scroll down button
}
]
};

Просмотреть файл

@ -46,12 +46,13 @@ include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
test_ariadialog.html \
test_doc.html \
test_list_editabledoc.html \
test_list.html \
test_recreation.html \
test_tableinsubtree.html \
test_textleaf.html \
test_visibility.html \
$(NULL)
libs:: $(_TEST_FILES)

Просмотреть файл

@ -34,9 +34,10 @@
this.invoke = function showARIADialog_invoke()
{
this.node.style.display = "block";
getNode("dialog").style.display = "block";
getNode("table").style.visibility = "visible";
getNode("a").textContent = "link";
getNode("input").value = "hello";
getNode("cell").textContent = "cell1";
getNode("input").focus();
}
@ -46,22 +47,11 @@
role: ROLE_DIALOG,
children: [
{
role: ROLE_TABLE,
children: [
{
role: ROLE_ROW,
children: [
{
role: ROLE_CELL,
children: [ { role: ROLE_TEXT_LEAF } ]
},
{
role: ROLE_CELL,
children: [ { role: ROLE_ENTRY } ]
}
]
}
]
role: ROLE_PUSHBUTTON,
children: [ { role: ROLE_TEXT_LEAF } ]
},
{
role: ROLE_ENTRY
}
]
};
@ -110,8 +100,18 @@
</pre>
<div id="dialog" role="dialog" style="display: none;">
<table>
<tr><td id="cell"></td><td><input id="input"></td>
<table id="table" role="presentation"
style="display: block; position: fixed; top: 88px; left: 312.5px; z-index: 10010; visibility: hidden;">
<tbody>
<tr>
<td role="presentation">
<div role="presentation">
<a id="a" role="button">text</a>
</div>
<input id="input">
</td>
</tr>
</tbody>
</table>
</div>

Просмотреть файл

@ -0,0 +1,439 @@
<!DOCTYPE html>
<html>
<head>
<title>Style visibility tree update test</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="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
////////////////////////////////////////////////////////////////////////////
// Invokers
/**
* Hide parent while child stays visible.
*/
function test1(aContainerID, aParentID, aChildID)
{
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode(aParentID)),
new invokerChecker(EVENT_SHOW, getNode(aChildID)),
new invokerChecker(EVENT_REORDER, getNode(aContainerID))
];
this.invoke = function invoke()
{
var tree =
{ SECTION: [
{ SECTION: [
{ SECTION: [
{ TEXT_LEAF: [] }
] }
] }
] };
testAccessibleTree(aContainerID, tree);
getNode(aParentID).style.visibility = "hidden";
}
this.finalCheck = function finalCheck()
{
var tree =
{ SECTION: [
{ SECTION: [
{ TEXT_LEAF: [] }
] }
] };
testAccessibleTree(aContainerID, tree);
}
this.getID = function getID()
{
return "hide parent while child stays visible";
}
}
/**
* Hide grand parent while its children stay visible.
*/
function test2(aContainerID, aGrandParentID, aChildID, aChild2ID)
{
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode(aGrandParentID)),
new invokerChecker(EVENT_SHOW, getNode(aChildID)),
new invokerChecker(EVENT_SHOW, getNode(aChild2ID)),
new invokerChecker(EVENT_REORDER, getNode(aContainerID))
];
this.invoke = function invoke()
{
var tree =
{ SECTION: [ // container
{ SECTION: [ // grand parent
{ SECTION: [
{ SECTION: [ // child
{ TEXT_LEAF: [] }
] },
{ SECTION: [ // child2
{ TEXT_LEAF: [] }
] }
] }
] }
] };
testAccessibleTree(aContainerID, tree);
getNode(aGrandParentID).style.visibility = "hidden";
}
this.finalCheck = function finalCheck()
{
var tree =
{ SECTION: [ // container
{ SECTION: [ // child
{ TEXT_LEAF: [] }
] },
{ SECTION: [ // child2
{ TEXT_LEAF: [] }
] }
] };
testAccessibleTree(aContainerID, tree);
}
this.getID = function getID()
{
return "hide grand parent while its children stay visible";
}
}
/**
* Change container style, hide parents while their children stay visible.
*/
function test3(aContainerID, aParentID, aParent2ID, aChildID, aChild2ID)
{
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode(aParentID)),
new invokerChecker(EVENT_SHOW, getNode(aChildID)),
new invokerChecker(EVENT_HIDE, getNode(aParent2ID)),
new invokerChecker(EVENT_SHOW, getNode(aChild2ID)),
new invokerChecker(EVENT_REORDER, getNode(aContainerID))
];
this.invoke = function invoke()
{
var tree =
{ SECTION: [ // container
{ SECTION: [ // parent
{ SECTION: [ // child
{ TEXT_LEAF: [] }
] }
] },
{ SECTION: [ // parent2
{ SECTION: [ // child2
{ TEXT_LEAF: [] }
] },
] }
] };
testAccessibleTree(aContainerID, tree);
getNode(aContainerID).style.color = "red";
getNode(aParentID).style.visibility = "hidden";
getNode(aParent2ID).style.visibility = "hidden";
}
this.finalCheck = function finalCheck()
{
var tree =
{ SECTION: [ // container
{ SECTION: [ // child
{ TEXT_LEAF: [] }
] },
{ SECTION: [ // child2
{ TEXT_LEAF: [] }
] }
] };
testAccessibleTree(aContainerID, tree);
}
this.getID = function getID()
{
return "change container style, hide parents while their children stay visible";
}
}
/**
* Change container style and make visible child inside the table.
*/
function test4(aContainerID, aChildID)
{
this.eventSeq = [
new invokerChecker(EVENT_SHOW, getNode(aChildID)),
new invokerChecker(EVENT_REORDER, getNode(aChildID).parentNode)
];
this.invoke = function invoke()
{
var tree =
{ SECTION: [
{ TABLE: [
{ ROW: [
{ CELL: [ ] }
] }
] }
] };
testAccessibleTree(aContainerID, tree);
getNode(aContainerID).style.color = "red";
getNode(aChildID).style.visibility = "visible";
}
this.finalCheck = function finalCheck()
{
var tree =
{ SECTION: [
{ TABLE: [
{ ROW: [
{ CELL: [
{ SECTION: [
{ TEXT_LEAF: [] }
] }
] }
] }
] }
] };
testAccessibleTree(aContainerID, tree);
}
this.getID = function getID()
{
return "change container style, make visible child insdie the table";
}
}
/**
* Hide subcontainer while child inside the table stays visible.
*/
function test5(aContainerID, aSubContainerID, aChildID)
{
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode(aSubContainerID)),
new invokerChecker(EVENT_SHOW, getNode(aChildID)),
new invokerChecker(EVENT_REORDER, getNode(aContainerID))
];
this.invoke = function invoke()
{
var tree =
{ SECTION: [ // container
{ SECTION: [ // subcontainer
{ TABLE: [
{ ROW: [
{ CELL: [
{ SECTION: [ // child
{ TEXT_LEAF: [] }
] }
] }
] }
] }
] }
] };
testAccessibleTree(aContainerID, tree);
getNode(aSubContainerID).style.visibility = "hidden";
}
this.finalCheck = function finalCheck()
{
var tree =
{ SECTION: [ // container
{ SECTION: [ // child
{ TEXT_LEAF: [] }
] }
] };
testAccessibleTree(aContainerID, tree);
}
this.getID = function getID()
{
return "hide subcontainer while child inside the table stays visible";
}
}
/**
* Hide subcontainer while its child and child inside the nested table stays visible.
*/
function test6(aContainerID, aSubContainerID, aChildID, aChild2ID)
{
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode(aSubContainerID)),
new invokerChecker(EVENT_SHOW, getNode(aChildID)),
new invokerChecker(EVENT_SHOW, getNode(aChild2ID)),
new invokerChecker(EVENT_REORDER, getNode(aContainerID))
];
this.invoke = function invoke()
{
var tree =
{ SECTION: [ // container
{ SECTION: [ // subcontainer
{ TABLE: [
{ ROW: [
{ CELL: [
{ TABLE: [ // nested table
{ ROW: [
{ CELL: [
{ SECTION: [ // child
{ TEXT_LEAF: [] } ]} ]} ]} ]} ]} ]} ]},
{ SECTION: [ // child2
{ TEXT_LEAF: [] } ]} ]} ]};
testAccessibleTree(aContainerID, tree);
// invoke
getNode(aSubContainerID).style.visibility = "hidden";
}
this.finalCheck = function finalCheck()
{
var tree =
{ SECTION: [ // container
{ SECTION: [ // child
{ TEXT_LEAF: [] } ]},
{ SECTION: [ // child2
{ TEXT_LEAF: [] } ]} ]};
testAccessibleTree(aContainerID, tree);
}
this.getID = function getID()
{
return "hide subcontainer while its child and child inside the nested table stays visible";
}
}
////////////////////////////////////////////////////////////////////////////
// Test
//gA11yEventDumpID = "eventdump"; // debug stuff
//gA11yEventDumpToConsole = true;
var gQueue = null;
function doTest()
{
gQueue = new eventQueue();
gQueue.push(new test1("t1_container", "t1_parent", "t1_child"));
gQueue.push(new test2("t2_container", "t2_grandparent", "t2_child", "t2_child2"));
gQueue.push(new test3("t3_container", "t3_parent", "t3_parent2", "t3_child", "t3_child2"));
gQueue.push(new test4("t4_container", "t4_child"));
gQueue.push(new test5("t5_container", "t5_subcontainer", "t5_child"));
gQueue.push(new test6("t6_container", "t6_subcontainer", "t6_child", "t6_child2"));
gQueue.invoke(); // SimpleTest.finish() will be called in the end
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="Develop a way to handle visibility style"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=606125">
Mozilla Bug 606125
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<!-- hide parent while child stays visible -->
<div id="t1_container">
<div id="t1_parent">
<div id="t1_child" style="visibility: visible">text</div>
</div>
</div>
<!-- hide grandparent while its children stay visible -->
<div id="t2_container">
<div id="t2_grandparent">
<div>
<div id="t2_child" style="visibility: visible">text</div>
<div id="t2_child2" style="visibility: visible">text</div>
</div>
</div>
</div>
<!-- change container style, hide parents while their children stay visible -->
<div id="t3_container">
<div id="t3_parent">
<div id="t3_child" style="visibility: visible">text</div>
</div>
<div id="t3_parent2">
<div id="t3_child2" style="visibility: visible">text</div>
</div>
</div>
<!-- change container style, show child inside the table -->
<div id="t4_container">
<table>
<tr>
<td>
<div id="t4_child" style="visibility: hidden;">text</div>
</td>
</tr>
</table>
</div>
<!-- hide subcontainer while child inside the table stays visible -->
<div id="t5_container">
<div id="t5_subcontainer">
<table>
<tr>
<td>
<div id="t5_child" style="visibility: visible;">text</div>
</td>
</tr>
</table>
</div>
</div>
<!-- hide subcontainer while its child and child inside the nested table stays visible -->
<div id="t6_container">
<div id="t6_subcontainer">
<table>
<tr>
<td>
<table>
<tr>
<td>
<div id="t6_child" style="visibility: visible;">text</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
<div id="t6_child2" style="visibility: visible">text</div>
</div>
</div>
<div id="eventdump"></div>
</body>
</html>

Просмотреть файл

@ -96,6 +96,10 @@
#include "nsFrameManager.h"
#ifdef ACCESSIBILITY
#include "nsIAccessibilityService.h"
#endif
#ifdef DEBUG
//#define NOISY_DEBUG
//#define DEBUG_UNDISPLAYED_MAP
@ -1000,7 +1004,9 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
nsStyleChangeList *aChangeList,
nsChangeHint aMinChange,
nsRestyleHint aRestyleHint,
RestyleTracker& aRestyleTracker)
RestyleTracker& aRestyleTracker,
DesiredA11yNotifications aDesiredA11yNotifications,
nsTArray<nsIContent*>& aVisibleKidsOfHiddenElement)
{
if (!NS_IsHintSubset(nsChangeHint_NeedDirtyReflow, aMinChange)) {
// If aMinChange doesn't include nsChangeHint_NeedDirtyReflow, clear out
@ -1047,6 +1053,12 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
// could oldContext be null?
if (oldContext) {
oldContext->AddRef();
#ifdef ACCESSIBILITY
PRBool wasFrameVisible = mPresShell->IsAccessibilityActive() ?
oldContext->GetStyleVisibility()->IsVisible() : PR_FALSE;
#endif
nsIAtom* const pseudoTag = oldContext->GetPseudo();
const nsCSSPseudoElements::Type pseudoType = oldContext->GetPseudoType();
nsIContent* localContent = aFrame->GetContent();
@ -1100,7 +1112,9 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
assumeDifferenceHint = ReResolveStyleContext(aPresContext, providerFrame,
aParentContent, aChangeList,
aMinChange, aRestyleHint,
aRestyleTracker);
aRestyleTracker,
aDesiredA11yNotifications,
aVisibleKidsOfHiddenElement);
// The provider's new context becomes the parent context of
// aFrame's context.
@ -1399,7 +1413,44 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
}
if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
A11yNotificationType ourA11yNotification = eDontNotify;
DesiredA11yNotifications kidsDesiredA11yNotification =
aDesiredA11yNotifications;
#ifdef ACCESSIBILITY
// Notify a11y for primary frame only if it's a root frame of visibility
// changes or its parent frame was hidden while it stays visible and
// it is not inside a {ib} split or is the first frame of {ib} split.
if (mPresShell->IsAccessibilityActive() && !aFrame->GetPrevContinuation() &&
!nsLayoutUtils::FrameIsNonFirstInIBSplit(aFrame)) {
if (aDesiredA11yNotifications == eSendAllNotifications) {
PRBool isFrameVisible = newContext->GetStyleVisibility()->IsVisible();
if (isFrameVisible != wasFrameVisible) {
if (isFrameVisible) {
// Notify a11y the element (perhaps with its children) was shown.
// We don't fall into this case if this element gets or stays shown
// while its parent becomes hidden.
kidsDesiredA11yNotification = eSkipNotifications;
ourA11yNotification = eNotifyShown;
} else {
// The element is being hidden; its children may stay visible, or
// become visible after being hidden previously. If we'll find
// visible children then we should notify a11y about that as if
// they were inserted into tree. Notify a11y this element was
// hidden.
kidsDesiredA11yNotification = eNotifyIfShown;
ourA11yNotification = eNotifyHidden;
}
}
} else if (aDesiredA11yNotifications == eNotifyIfShown &&
newContext->GetStyleVisibility()->IsVisible()) {
// Notify a11y that element stayed visible while its parent was
// hidden.
aVisibleKidsOfHiddenElement.AppendElement(aFrame->GetContent());
kidsDesiredA11yNotification = eSkipNotifications;
}
}
#endif
// There is no need to waste time crawling into a frame's children on a frame change.
// The act of reconstructing frames will force new style contexts to be resolved on all
// of this frame's descendants anyway, so we want to avoid wasting time processing
@ -1442,7 +1493,9 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
NS_SubtractHint(aMinChange,
nsChangeHint_ReflowFrame),
childRestyleHint,
aRestyleTracker);
aRestyleTracker,
kidsDesiredA11yNotification,
aVisibleKidsOfHiddenElement);
} while (outOfFlowFrame = outOfFlowFrame->GetNextContinuation());
// reresolve placeholder's context under the same parent
@ -1450,14 +1503,18 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
ReResolveStyleContext(aPresContext, child, content,
aChangeList, aMinChange,
childRestyleHint,
aRestyleTracker);
aRestyleTracker,
kidsDesiredA11yNotification,
aVisibleKidsOfHiddenElement);
}
else { // regular child frame
if (child != resolvedChild) {
ReResolveStyleContext(aPresContext, child, content,
aChangeList, aMinChange,
childRestyleHint,
aRestyleTracker);
aRestyleTracker,
kidsDesiredA11yNotification,
aVisibleKidsOfHiddenElement);
} else {
NOISY_TRACE_FRAME("child frame already resolved as descendant, skipping",aFrame);
}
@ -1469,8 +1526,40 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
childList = aFrame->GetAdditionalChildListName(listIndex++);
} while (childList);
// XXX need to do overflow frames???
}
#ifdef ACCESSIBILITY
// Send notifications about visibility changes.
if (ourA11yNotification == eNotifyShown) {
nsCOMPtr<nsIAccessibilityService> accService =
do_GetService("@mozilla.org/accessibilityService;1");
if (accService) {
nsIPresShell* presShell = aFrame->PresContext()->GetPresShell();
nsIContent* content = aFrame->GetContent();
accService->ContentRangeInserted(presShell, content->GetParent(),
content,
content->GetNextSibling());
}
} else if (ourA11yNotification == eNotifyHidden) {
nsCOMPtr<nsIAccessibilityService> accService =
do_GetService("@mozilla.org/accessibilityService;1");
if (accService) {
nsIPresShell* presShell = aFrame->PresContext()->GetPresShell();
nsIContent* content = aFrame->GetContent();
accService->ContentRemoved(presShell, content->GetParent(), content);
// Process children staying shown.
PRUint32 visibleContentCount = aVisibleKidsOfHiddenElement.Length();
for (PRUint32 idx = 0; idx < visibleContentCount; idx++) {
nsIContent* content = aVisibleKidsOfHiddenElement[idx];
accService->ContentRangeInserted(presShell, content->GetParent(),
content, content->GetNextSibling());
}
aVisibleKidsOfHiddenElement.Clear();
}
}
#endif
}
}
return aMinChange;
@ -1500,6 +1589,7 @@ nsFrameManager::ComputeStyleChangeFor(nsIFrame *aFrame,
FramePropertyTable *propTable = GetPresContext()->PropertyTable();
nsTArray<nsIContent*> visibleKidsOfHiddenElement;
do {
// Outer loop over special siblings
do {
@ -1509,7 +1599,9 @@ nsFrameManager::ComputeStyleChangeFor(nsIFrame *aFrame,
aChangeList, topLevelChange,
aRestyleDescendants ?
eRestyle_Subtree : eRestyle_Self,
aRestyleTracker);
aRestyleTracker,
eSendAllNotifications,
visibleKidsOfHiddenElement);
NS_UpdateHint(topLevelChange, frameChange);
if (topLevelChange & nsChangeHint_ReconstructFrame) {

Просмотреть файл

@ -202,6 +202,18 @@ public:
}
private:
enum DesiredA11yNotifications {
eSkipNotifications,
eSendAllNotifications,
eNotifyIfShown
};
enum A11yNotificationType {
eDontNotify,
eNotifyShown,
eNotifyHidden
};
// Use eRestyle_Self for the aRestyleHint argument to mean
// "reresolve our style context but not kids", use eRestyle_Subtree
// to mean "reresolve our style context and kids", and use
@ -214,7 +226,9 @@ private:
nsStyleChangeList *aChangeList,
nsChangeHint aMinChange,
nsRestyleHint aRestyleHint,
RestyleTracker& aRestyleTracker);
RestyleTracker& aRestyleTracker,
DesiredA11yNotifications aDesiredA11yNotifications,
nsTArray<nsIContent*>& aVisibleKidsOfHiddenElement);
};
#endif