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"> + +