Bug 527466 - (nsAccessibleTreeWalker) Less frame walking, more node walking, r=marcoz, davidb

This commit is contained in:
Alexander Surkov 2009-12-12 03:38:33 +08:00
Родитель 1332db996f
Коммит c91de797cc
4 изменённых файлов: 91 добавлений и 95 удалений

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

@ -46,7 +46,7 @@ interface nsObjectFrame;
interface nsIContent;
interface nsITimer;
[uuid(29384ba1-f9ce-425d-afb5-54e2ee949d87)]
[uuid(61098f48-4fcc-4b05-9cf3-c11b8efbe682)]
interface nsIAccessibilityService : nsIAccessibleRetrieval
{
nsIAccessible createOuterDocAccessible(in nsIDOMNode aNode);
@ -76,9 +76,18 @@ interface nsIAccessibilityService : nsIAccessibleRetrieval
nsIAccessible createHTMLTextFieldAccessible(in nsIFrame aFrame);
nsIAccessible createHTMLCaptionAccessible(in nsIFrame aFrame);
nsIAccessible getAccessible(in nsIDOMNode aNode, in nsIPresShell aPresShell,
in nsIWeakReference aWeakShell,
inout nsIFrame frameHint, out boolean aIsHidden);
/**
* Return an accessible for the given DOM node.
*
* @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 aFrameHint [in] the frame of the given node
* @param aIsHidden [out] indicates whether the node's frame is hidden
*/
nsIAccessible getAccessible(in nsIDOMNode aNode, in nsIPresShell aPresShell,
in nsIWeakReference aWeakShell,
in nsIFrame aFrameHint, out boolean aIsHidden);
// For gtk+ native window accessible
nsIAccessible addNativeRootAccessible(in voidPtr aAtkAccessible);

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

@ -1242,10 +1242,9 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessibleInShell(nsIDOMNode *aNode,
NS_ENSURE_ARG(aPresShell);
nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aPresShell));
nsIFrame *outFrameUnused = NULL;
PRBool isHiddenUnused = false;
return GetAccessible(aNode, aPresShell, weakShell,
&outFrameUnused, &isHiddenUnused, aAccessible);
nsnull, &isHiddenUnused, aAccessible);
}
NS_IMETHODIMP nsAccessibilityService::GetAccessibleInWeakShell(nsIDOMNode *aNode,
@ -1259,10 +1258,9 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessibleInWeakShell(nsIDOMNode *aNode
NS_ENSURE_ARG(aWeakShell);
nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(aWeakShell));
nsIFrame *outFrameUnused = NULL;
PRBool isHiddenUnused = false;
return GetAccessible(aNode, presShell, aWeakShell,
&outFrameUnused, &isHiddenUnused, aAccessible);
nsnull, &isHiddenUnused, aAccessible);
}
nsresult nsAccessibilityService::InitAccessible(nsIAccessible *aAccessibleIn,
@ -1315,13 +1313,13 @@ static PRBool HasRelatedContent(nsIContent *aContent)
NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
nsIPresShell *aPresShell,
nsIWeakReference *aWeakShell,
nsIFrame **aFrameHint,
nsIFrame *aFrameHint,
PRBool *aIsHidden,
nsIAccessible **aAccessible)
{
NS_ENSURE_ARG_POINTER(aAccessible);
NS_ENSURE_ARG_POINTER(aFrameHint);
*aAccessible = nsnull;
if (!aPresShell || !aWeakShell || gIsShutdown) {
return NS_ERROR_FAILURE;
}
@ -1334,7 +1332,7 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
// that can flush layout, either directly, or via DOM manipulation, or some
// CSS styles like :hover. We use the weak frame checks to avoid calling
// methods on a dead frame pointer.
nsWeakFrame weakFrame(*aFrameHint);
nsWeakFrame weakFrame(aFrameHint);
#ifdef DEBUG_A11Y
// Please leave this in for now, it's a convenient debugging method
@ -1391,7 +1389,6 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
CreateRootAccessible(aPresShell, nodeIsDoc, getter_AddRefs(newAcc)); // Does Init() for us
}
*aFrameHint = aPresShell->GetRootFrame();
NS_IF_ADDREF(*aAccessible = newAcc);
return NS_OK;
}
@ -1421,7 +1418,7 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
if (content->IsNodeOfType(nsINode::eTEXT)) {
++frameHintFailedForText;
}
frameHintNonexistant += !*aFrameHint;
frameHintNonexistant += !aFrameHint;
printf("Frame hint failures: %d / %d . Text fails = %d. No hint fails = %d \n", frameHintFailed, frameHintTried, frameHintFailedForText, frameHintNonexistant);
if (frameHintTried >= 354) {
printf("* "); // Aaron's break point
@ -1450,7 +1447,6 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
return NS_OK;
}
*aFrameHint = weakFrame.GetFrame();
}
}
@ -1460,10 +1456,8 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
*aIsHidden = PR_TRUE;
}
if (*aIsHidden) {
*aFrameHint = weakFrame.GetFrame();
if (*aIsHidden)
return NS_OK;
}
/**
* Attempt to create an accessible based on what we know
@ -1477,7 +1471,6 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
if (renderedWhitespace.IsEmpty()) {
// Really empty -- nothing is rendered
*aIsHidden = PR_TRUE;
*aFrameHint = weakFrame.GetFrame();
return NS_OK;
}
}
@ -1485,9 +1478,7 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
weakFrame.GetFrame()->GetAccessible(getter_AddRefs(newAcc));
}
nsresult rv = InitAccessible(newAcc, aAccessible, nsnull);
*aFrameHint = weakFrame.GetFrame();
return rv;
return InitAccessible(newAcc, aAccessible, nsnull);
}
PRBool isHTML = content->IsHTML();
@ -1504,16 +1495,12 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::name, name);
if (!name.IsEmpty()) {
*aIsHidden = PR_TRUE;
*aFrameHint = weakFrame.GetFrame();
return NS_OK;
}
nsresult rv =
CreateHyperTextAccessible(weakFrame.GetFrame(), getter_AddRefs(newAcc));
if (NS_FAILED(rv)) {
*aFrameHint = weakFrame.GetFrame();
return rv;
}
NS_ENSURE_SUCCESS(rv, rv);
}
nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(aNode);
@ -1522,7 +1509,6 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
// 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'
*aFrameHint = weakFrame.GetFrame();
return NS_OK;
}
@ -1580,7 +1566,6 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
// presentation if they aren't focusable and have not explicit ARIA
// role (don't create accessibles for them unless they need to fire
// focus events).
*aFrameHint = weakFrame.GetFrame();
return NS_OK;
}
@ -1628,10 +1613,7 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
nsresult rv =
CreateHTMLAccessibleByMarkup(weakFrame.GetFrame(), aWeakShell, aNode,
getter_AddRefs(newAcc));
if (NS_FAILED(rv)) {
*aFrameHint = weakFrame.GetFrame();
return rv;
}
NS_ENSURE_SUCCESS(rv, rv);
if (!newAcc) {
// Do not create accessible object subtrees for non-rendered table
@ -1649,7 +1631,6 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
// XXX This is not the ideal place for this code, but right now there
// is no better place:
*aIsHidden = PR_TRUE;
*aFrameHint = weakFrame.GetFrame();
return NS_OK;
}
f->GetAccessible(getter_AddRefs(newAcc)); // Try using frame to do it
@ -1661,10 +1642,7 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
// Elements may implement nsIAccessibleProvider via XBL. This allows them to
// say what kind of accessible to create.
nsresult rv = GetAccessibleByType(aNode, getter_AddRefs(newAcc));
if (NS_FAILED(rv)) {
*aFrameHint = weakFrame.GetFrame();
return rv;
}
NS_ENSURE_SUCCESS(rv, rv);
}
if (!newAcc) {
@ -1707,9 +1685,7 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
}
}
nsresult rv = InitAccessible(newAcc, aAccessible, roleMapEntry);
*aFrameHint = weakFrame.GetFrame();
return rv;
return InitAccessible(newAcc, aAccessible, roleMapEntry);
}
PRBool

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

@ -77,7 +77,7 @@ void nsAccessibleTreeWalker::GetKids(nsIDOMNode *aParentNode)
mState.frame = nsnull; // Don't walk frames in non-HTML content, just walk the DOM.
}
UpdateFrame(PR_TRUE);
WalkFrames();
// Walk frames? UpdateFrame() sets this when it sees anonymous frames
if (mState.siblingIndex == eSiblingsWalkFrames) {
@ -160,20 +160,40 @@ NS_IMETHODIMP nsAccessibleTreeWalker::PushState()
void nsAccessibleTreeWalker::GetNextDOMNode()
{
// Get next DOM node
// Get next DOM node and its frame.
if (mState.parentContent) {
mState.domNode = do_QueryInterface(mState.parentContent->GetChildAt(++mState.siblingIndex));
}
else if (mState.siblingIndex == eSiblingsWalkFrames) {
if (mState.frame.GetFrame()) {
mState.domNode = do_QueryInterface(mState.frame.GetFrame()->GetContent());
} else {
mState.domNode = nsnull;
mState.domNode =
do_QueryInterface(mState.parentContent->GetChildAt(++mState.siblingIndex));
} else if (mState.siblingIndex == eSiblingsWalkFrames) {
if (mState.frame.IsAlive()) {
mState.frame = mState.frame.GetFrame()->GetNextSibling();
if (mState.frame.IsAlive()) {
mState.domNode = do_QueryInterface(mState.frame.GetFrame()->GetContent());
return;
}
}
mState.domNode = nsnull;
return;
} else {
mState.siblingList->Item(++mState.siblingIndex,
getter_AddRefs(mState.domNode));
}
else {
mState.siblingList->Item(++mState.siblingIndex, getter_AddRefs(mState.domNode));
}
// Update the frame.
nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
NS_ASSERTION(presShell, "Huh? No presshell?");
if (!presShell)
return;
nsCOMPtr<nsIContent> content = do_QueryInterface(mState.domNode);
if (content)
mState.frame = presShell->GetRealPrimaryFrameFor(content);
else
mState.frame = presShell->GetRootFrame();
}
NS_IMETHODIMP nsAccessibleTreeWalker::GetNextSibling()
@ -185,7 +205,6 @@ NS_IMETHODIMP nsAccessibleTreeWalker::GetNextSibling()
while (PR_TRUE) {
// Get next frame
UpdateFrame(PR_FALSE);
GetNextDOMNode();
if (!mState.domNode) { // Done with current siblings
@ -219,7 +238,7 @@ NS_IMETHODIMP nsAccessibleTreeWalker::GetFirstChild()
while (mState.domNode) {
if ((mState.domNode != parent && GetAccessible()) || NS_SUCCEEDED(GetFirstChild()))
return NS_OK;
UpdateFrame(PR_FALSE);
GetNextDOMNode();
}
@ -227,50 +246,46 @@ NS_IMETHODIMP nsAccessibleTreeWalker::GetFirstChild()
return NS_ERROR_FAILURE;
}
void nsAccessibleTreeWalker::UpdateFrame(PRBool aTryFirstChild)
void
nsAccessibleTreeWalker::WalkFrames()
{
nsIFrame *curFrame = mState.frame.GetFrame();
if (!curFrame) {
return;
}
if (aTryFirstChild) {
// If the frame implements nsIAnonymousContentCreator interface then go down
// through the frames and obtain anonymous nodes for them.
nsIAnonymousContentCreator* creator = do_QueryFrame(curFrame);
nsIFrame *child = curFrame->GetFirstChild(nsnull);
mState.frame = child;
// If the frame implements nsIAnonymousContentCreator interface then go down
// through the frames and obtain anonymous nodes for them.
nsIAnonymousContentCreator* creator = do_QueryFrame(curFrame);
nsIFrame *child = curFrame->GetFirstChild(nsnull);
if (creator && child && mState.siblingIndex < 0) {
mState.domNode = do_QueryInterface(child->GetContent());
mState.siblingIndex = eSiblingsWalkFrames;
}
if (creator && child && mState.siblingIndex < 0) {
mState.frame = child;
mState.domNode = do_QueryInterface(child->GetContent());
mState.siblingIndex = eSiblingsWalkFrames;
}
// temporary workaround for Bug 359210. We never want to walk frames.
// Aaron Leventhal will refix :before and :after content later without walking frames.
#if 0
if (mState.frame && mState.siblingIndex < 0) {
// Container frames can contain generated content frames from
// :before and :after style rules, so we walk their frame trees
// instead of content trees
// XXX Walking the frame tree doesn't get us Aural CSS nodes, e.g.
// @media screen { display: none; }
// Asking the style system might be better (with ProbePseudoStyleFor(),
// except that we need to ask only for those display types that support
// :before and :after (which roughly means non-replaced elements)
// Here's some code to see if there is an :after rule for an element
// nsRefPtr<nsStyleContext> pseudoContext;
// nsStyleContext *styleContext = primaryFrame->GetStyleContext();
// if (aContent) {
// pseudoContext = presContext->StyleSet()->
// ProbePseudoStyleFor(content, nsAccessibilityAtoms::after, aStyleContext);
mState.domNode = do_QueryInterface(mState.frame->GetContent());
mState.siblingIndex = eSiblingsWalkFrames;
}
if (mState.frame && mState.siblingIndex < 0) {
// Container frames can contain generated content frames from
// :before and :after style rules, so we walk their frame trees
// instead of content trees
// XXX Walking the frame tree doesn't get us Aural CSS nodes, e.g.
// @media screen { display: none; }
// Asking the style system might be better (with ProbePseudoStyleFor(),
// except that we need to ask only for those display types that support
// :before and :after (which roughly means non-replaced elements)
// Here's some code to see if there is an :after rule for an element
// nsRefPtr<nsStyleContext> pseudoContext;
// nsStyleContext *styleContext = primaryFrame->GetStyleContext();
// if (aContent) {
// pseudoContext = presContext->StyleSet()->
// ProbePseudoStyleFor(content, nsAccessibilityAtoms::after, aStyleContext);
mState.domNode = do_QueryInterface(mState.frame->GetContent());
mState.siblingIndex = eSiblingsWalkFrames;
}
#endif
}
else {
mState.frame = curFrame->GetNextSibling();
}
}
/**
@ -286,11 +301,10 @@ PRBool nsAccessibleTreeWalker::GetAccessible()
mState.accessible = nsnull;
nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
nsIFrame *frame = mState.frame.GetFrame();
mAccService->GetAccessible(mState.domNode, presShell, mWeakShell,
&frame, &mState.isHidden,
mState.frame.GetFrame(), &mState.isHidden,
getter_AddRefs(mState.accessible));
mState.frame = frame;
return mState.accessible ? PR_TRUE : PR_FALSE;
}

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

@ -121,12 +121,9 @@ protected:
NS_IMETHOD PopState();
/**
* Change current state so that its frame is changed to next frame.
*
* @param aTryFirstChild [in] points whether we should move to child or
* sibling frame
* Make treewalker traverse by frame tree if necessary.
*/
void UpdateFrame(PRBool aTryFirstChild);
void WalkFrames();
/**
* Change current state so that its node is changed to next node.