Bug 686821 - expose offscreen state (no invisible state) for background tab accessibles, r=tbsaunde

This commit is contained in:
Alexander Surkov 2012-09-14 11:55:18 +09:00
parent eb24d5ccf0
commit c5b0bb718a
2 changed files with 77 additions and 33 deletions

View File

@ -43,6 +43,7 @@
#include "nsIForm.h"
#include "nsIFormControl.h"
#include "nsDeckFrame.h"
#include "nsLayoutUtils.h"
#include "nsIPresShell.h"
#include "nsIStringBundle.h"
@ -606,26 +607,35 @@ Accessible::TranslateString(const nsString& aKey, nsAString& aStringOut)
uint64_t
Accessible::VisibilityState()
{
uint64_t vstates = states::INVISIBLE | states::OFFSCREEN;
nsIFrame* frame = GetFrame();
if (!frame)
return vstates;
return states::INVISIBLE;
nsIPresShell* shell(mDoc->PresShell());
if (!shell)
return vstates;
// Walk the parent frame chain to see if there's invisible parent or the frame
// is in background tab.
if (!frame->GetStyleVisibility()->IsVisible())
return states::INVISIBLE;
// We need to know if at least a kMinPixels around the object is visible,
// otherwise it will be marked states::OFFSCREEN.
const uint16_t kMinPixels = 12;
const nsSize frameSize = frame->GetSize();
const nsRectVisibility rectVisibility =
shell->GetRectVisibility(frame, nsRect(nsPoint(0,0), frameSize),
nsPresContext::CSSPixelsToAppUnits(kMinPixels));
nsIFrame* curFrame = frame;
do {
nsIView* view = curFrame->GetView();
if (view && view->GetVisibility() == nsViewVisibility_kHide)
return states::INVISIBLE;
if (rectVisibility == nsRectVisibility_kVisible)
vstates &= ~states::OFFSCREEN;
// Offscreen state for background tab content.
nsIFrame* parentFrame = curFrame->GetParent();
nsDeckFrame* deckFrame = do_QueryFrame(parentFrame);
if (deckFrame && deckFrame->GetSelectedBox() != curFrame)
return states::OFFSCREEN;
if (!parentFrame) {
parentFrame = nsLayoutUtils::GetCrossDocParentFrame(curFrame);
if (parentFrame && !parentFrame->GetStyleVisibility()->IsVisible())
return states::INVISIBLE;
}
curFrame = parentFrame;
} while (curFrame);
// Zero area rects can occur in the first frame of a multi-frame text flow,
// in which case the rendered text is not empty and the frame should not be
@ -638,16 +648,21 @@ Accessible::VisibilityState()
nsAutoString renderedText;
frame->GetRenderedText(&renderedText, nullptr, nullptr, 0, 1);
if (renderedText.IsEmpty())
return vstates;
return states::INVISIBLE;
}
// XXX Do we really need to cross from content to chrome ancestor?
if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY))
return vstates;
// We need to know if at least a kMinPixels around the object is visible,
// otherwise it will be marked states::OFFSCREEN.
const uint16_t kMinPixels = 12;
const nsSize frameSize = frame->GetSize();
const nsRectVisibility rectVisibility =
mDoc->PresShell()->GetRectVisibility(frame, nsRect(nsPoint(0,0), frameSize),
nsPresContext::CSSPixelsToAppUnits(kMinPixels));
// Assume we are visible enough.
return vstates &= ~states::INVISIBLE;
if (rectVisibility != nsRectVisibility_kVisible)
return states::OFFSCREEN;
return 0;
}
uint64_t

View File

@ -16,27 +16,56 @@
src="../role.js"></script>
<script type="application/javascript"
src="../states.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript"
src="../browser.js"></script>
<script type="application/javascript">
function doTest()
function addTab(aURL)
{
testStates("div", 0, 0, STATE_INVISIBLE);
this.eventSeq = [
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 1)
];
this.invoke = function addTab_invoke()
{
tabBrowser().loadOneTab(aURL, null, "", null, false);
}
this.finalCheck = function addTab_finalCheck()
{
var tabDoc = tabDocumentAt(0);
var input = getAccessible(tabDoc.getElementById("input"));
testStates(input, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
}
this.getID = function addTab_getID()
{
return "add tab: " + aURL;
}
}
var gInputDocURI = "data:text/html,<html><input id='input'></html>";
function doTests()
{
testStates("div", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
testStates("div_off", STATE_OFFSCREEN, 0, STATE_INVISIBLE);
testStates("div_abschild", 0, 0, STATE_INVISIBLE);
testStates("div_abschild", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
// Confirm destruction of accessibles.
document.getElementById("div").style.visibility = "hidden";
document.getElementById("div_off").style.visibility="hidden";
document.getElementById("div_abschild").style.visibility="hidden";
document.body.clientWidth; // flush layout
testAccessibleTree("outer_div", {children:[]});
gQueue = new eventQueue();
// Accessibles in background tab should have offscreen state and no
// invisible state.
gQueue.push(new addTab("about:blank"));
SimpleTest.finish();
gQueue.onFinish = function() { closeBrowserWindow(); }
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
openBrowserWindow(doTests, gInputDocURI);
</script>
</head>