diff --git a/accessible/src/generic/Accessible.cpp b/accessible/src/generic/Accessible.cpp
index 9407c893edd..8e0cc73c96d 100644
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -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
diff --git a/accessible/tests/mochitest/states/test_visibility.html b/accessible/tests/mochitest/states/test_visibility.html
index 94553bcc3de..41d4a7b1875 100644
--- a/accessible/tests/mochitest/states/test_visibility.html
+++ b/accessible/tests/mochitest/states/test_visibility.html
@@ -16,27 +16,56 @@
src="../role.js">
+
+