зеркало из https://github.com/mozilla/gecko-dev.git
Bug 527466 - (nsAccessibleTreeWalker) Less frame walking, more node walking, r=marcoz, davidb
This commit is contained in:
Родитель
1332db996f
Коммит
c91de797cc
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче