Bug 658005. Part 2. Add a frame visibility API that takes into account everything we need, and use it. r=roc

This commit is contained in:
Timothy Nikkel 2011-10-26 18:57:55 -05:00
parent 258cd4a079
commit 09778341dc
12 changed files with 144 additions and 59 deletions

View File

@ -1442,10 +1442,7 @@ IsAccessKeyTarget(nsIContent* aContent, nsIFrame* aFrame, nsAString& aKey)
if (aFrame->IsFocusable())
return true;
if (!aFrame->GetStyleVisibility()->IsVisible())
return false;
if (!aFrame->AreAncestorViewsVisible())
if (!aFrame->IsVisibleConsideringAncestors())
return false;
// XUL controls can be activated.

View File

@ -656,14 +656,7 @@ nsXULElement::PerformAccesskey(bool aKeyCausesActivation,
}
nsIFrame* frame = content->GetPrimaryFrame();
if (!frame)
return;
const nsStyleVisibility* vis = frame->GetStyleVisibility();
if (vis->mVisible == NS_STYLE_VISIBILITY_COLLAPSE ||
vis->mVisible == NS_STYLE_VISIBILITY_HIDDEN ||
!frame->AreAncestorViewsVisible())
if (!frame || !frame->IsVisibleConsideringAncestors())
return;
nsXULElement* elm = FromContent(content);

View File

@ -4821,8 +4821,11 @@ nsDocShell::GetVisibility(bool * aVisibility)
nsIFrame* frame = shellContent ? shellContent->GetPrimaryFrame() : nsnull;
bool isDocShellOffScreen = false;
docShell->GetIsOffScreenBrowser(&isDocShellOffScreen);
if (frame && !frame->AreAncestorViewsVisible() && !isDocShellOffScreen)
if (frame &&
!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) &&
!isDocShellOffScreen) {
return NS_OK;
}
treeItem = parentItem;
treeItem->GetParent(getter_AddRefs(parentItem));

View File

@ -1442,8 +1442,7 @@ nsFocusManager::CheckIfFocusable(nsIContent* aContent, PRUint32 aFlags)
// HTML areas do not have their own frame, and the img frame we get from
// GetPrimaryFrame() is not relevant as to whether it is focusable or
// not, so we have to do all the relevant checks manually for them.
return frame->AreAncestorViewsVisible() &&
frame->GetStyleVisibility()->IsVisible() &&
return frame->IsVisibleConsideringAncestors() &&
aContent->IsFocusable() ? aContent : nsnull;
}

View File

@ -5251,8 +5251,11 @@ static nsIView* FindFloatingViewContaining(nsIView* aView, nsPoint aPt)
return nsnull;
nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
if (frame && !frame->PresContext()->PresShell()->IsActive()) {
return nsnull;
if (frame) {
if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
!frame->PresContext()->PresShell()->IsActive()) {
return nsnull;
}
}
for (nsIView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
@ -5285,8 +5288,11 @@ static nsIView* FindViewContaining(nsIView* aView, nsPoint aPt)
}
nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
if (frame && !frame->PresContext()->PresShell()->IsActive()) {
return nsnull;
if (frame) {
if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
!frame->PresContext()->PresShell()->IsActive()) {
return nsnull;
}
}
for (nsIView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
@ -6864,7 +6870,7 @@ PresShell::WillPaint(bool aWillSendDidPaint)
{
// Don't bother doing anything if some viewmanager in our tree is painting
// while we still have painting suppressed or we are not active.
if (mPaintingSuppressed || !mIsActive) {
if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
return;
}
@ -6890,7 +6896,7 @@ PresShell::WillPaint(bool aWillSendDidPaint)
NS_IMETHODIMP_(void)
PresShell::DidPaint()
{
if (mPaintingSuppressed || !mIsActive) {
if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
return;
}
@ -6903,6 +6909,33 @@ PresShell::DidPaint()
}
}
NS_IMETHODIMP_(bool)
PresShell::IsVisible()
{
if (!mViewManager)
return false;
nsIView* view = mViewManager->GetRootView();
if (!view)
return true;
// inner view of subdoc frame
view = view->GetParent();
if (!view)
return true;
// subdoc view
view = view->GetParent();
if (!view)
return true;
nsIFrame* frame = static_cast<nsIFrame*>(view->GetClientData());
if (!frame)
return true;
return frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY);
}
nsresult
PresShell::GetAgentStyleSheets(nsCOMArray<nsIStyleSheet>& aSheets)
{

View File

@ -337,6 +337,7 @@ public:
NS_IMETHOD_(void) DispatchSynthMouseMove(nsGUIEvent *aEvent,
bool aFlushOnHoverChange);
NS_IMETHOD_(void) ClearMouseCapture(nsIView* aView);
NS_IMETHOD_(bool) IsVisible();
// caret handling
virtual NS_HIDDEN_(already_AddRefed<nsCaret>) GetCaret() const;

View File

@ -119,6 +119,7 @@
#include "nsSVGIntegrationUtils.h"
#include "nsSVGEffects.h"
#include "nsChangeHint.h"
#include "nsDeckFrame.h"
#include "gfxContext.h"
#include "CSSCalc.h"
@ -301,6 +302,48 @@ nsIFrame::CheckAndClearPaintedState()
return result;
}
bool
nsIFrame::IsVisibleConsideringAncestors(PRUint32 aFlags) const
{
if (!GetStyleVisibility()->IsVisible()) {
return false;
}
const nsIFrame* frame = this;
while (frame) {
nsIView* view = frame->GetView();
if (view && view->GetVisibility() == nsViewVisibility_kHide)
return false;
nsIFrame* parent = frame->GetParent();
nsDeckFrame* deck = do_QueryFrame(parent);
if (deck) {
if (deck->GetSelectedBox() != frame)
return false;
}
if (parent) {
frame = parent;
} else {
parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
if (!parent)
break;
if ((aFlags & nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) == 0 &&
parent->PresContext()->IsChrome() && !frame->PresContext()->IsChrome()) {
break;
}
if (!parent->GetStyleVisibility()->IsVisible())
return false;
frame = parent;
}
}
return true;
}
static bool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
const nsIFrame* aFrame,
const nsStyleDisplay* aDisp,
@ -7005,38 +7048,34 @@ nsIFrame::IsFocusable(PRInt32 *aTabIndex, bool aWithMouse)
}
bool isFocusable = false;
if (mContent && mContent->IsElement() && AreAncestorViewsVisible()) {
const nsStyleVisibility* vis = GetStyleVisibility();
if (vis->mVisible != NS_STYLE_VISIBILITY_COLLAPSE &&
vis->mVisible != NS_STYLE_VISIBILITY_HIDDEN) {
const nsStyleUserInterface* ui = GetStyleUserInterface();
if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
// Pass in default tabindex of -1 for nonfocusable and 0 for focusable
tabIndex = 0;
}
isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
if (!isFocusable && !aWithMouse &&
GetType() == nsGkAtoms::scrollFrame &&
mContent->IsHTML() &&
!mContent->IsRootOfNativeAnonymousSubtree() &&
mContent->GetParent() &&
!mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
// Elements with scrollable view are focusable with script & tabbable
// Otherwise you couldn't scroll them with keyboard, which is
// an accessibility issue (e.g. Section 508 rules)
// However, we don't make them to be focusable with the mouse,
// because the extra focus outlines are considered unnecessarily ugly.
// When clicked on, the selection position within the element
// will be enough to make them keyboard scrollable.
nsIScrollableFrame *scrollFrame = do_QueryFrame(this);
if (scrollFrame &&
scrollFrame->GetScrollbarStyles() != nsIScrollableFrame::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) &&
!scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) {
// Scroll bars will be used for overflow
isFocusable = true;
tabIndex = 0;
}
if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors()) {
const nsStyleUserInterface* ui = GetStyleUserInterface();
if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
// Pass in default tabindex of -1 for nonfocusable and 0 for focusable
tabIndex = 0;
}
isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
if (!isFocusable && !aWithMouse &&
GetType() == nsGkAtoms::scrollFrame &&
mContent->IsHTML() &&
!mContent->IsRootOfNativeAnonymousSubtree() &&
mContent->GetParent() &&
!mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
// Elements with scrollable view are focusable with script & tabbable
// Otherwise you couldn't scroll them with keyboard, which is
// an accessibility issue (e.g. Section 508 rules)
// However, we don't make them to be focusable with the mouse,
// because the extra focus outlines are considered unnecessarily ugly.
// When clicked on, the selection position within the element
// will be enough to make them keyboard scrollable.
nsIScrollableFrame *scrollFrame = do_QueryFrame(this);
if (scrollFrame &&
scrollFrame->GetScrollbarStyles() != nsIScrollableFrame::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) &&
!scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) {
// Scroll bars will be used for overflow
isFocusable = true;
tabIndex = 0;
}
}
}

View File

@ -2760,6 +2760,19 @@ NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::EmbeddingLevelProperty()))
// clears this bit if so.
bool CheckAndClearPaintedState();
// CSS visibility just doesn't cut it because it doesn't inherit through
// documents. Also if this frame is in a hidden card of a deck then it isn't
// visible either and that isn't expressed using CSS visibility. Also if it
// is in a hidden view (there are a few cases left and they are hopefully
// going away soon).
// If the VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY flag is passed then we
// ignore the chrome/content boundary, otherwise we stop looking when we
// reach it.
enum {
VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY = 0x01
};
bool IsVisibleConsideringAncestors(PRUint32 aFlags = 0) const;
protected:
// Members
nsRect mRect;

View File

@ -217,7 +217,7 @@ nsDeckFrame::GetSelectedIndex()
return index;
}
nsIBox*
nsIFrame*
nsDeckFrame::GetSelectedBox()
{
return (mIndex >= 0) ? mFrames.FrameAt(mIndex) : nsnull;

View File

@ -97,10 +97,11 @@ public:
nsDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
nsIFrame* GetSelectedBox();
protected:
// REVIEW: Sorry, I couldn't resist devirtualizing these.
nsIBox* GetSelectedBox();
void IndexChanged(nsPresContext* aPresContext);
PRInt32 GetSelectedIndex();
void HideBox(nsPresContext* aPresContext, nsIBox* aBox);

View File

@ -50,8 +50,8 @@ class nsRegion;
class nsIntRegion;
#define NS_IVIEWOBSERVER_IID \
{ 0xdc283a18, 0x61cb, 0x468c, \
{ 0x8d, 0xb8, 0x9b, 0x81, 0xf7, 0xc9, 0x33, 0x25 } }
{ 0xac6eec35, 0x65d2, 0x4fe8, \
{ 0xa1, 0x37, 0x1a, 0xc3, 0xf6, 0x51, 0x52, 0x56 } }
class nsIViewObserver : public nsISupports
{
@ -145,6 +145,11 @@ public:
*/
NS_IMETHOD_(void) ClearMouseCapture(nsIView* aView) = 0;
/**
* Returns true if the view observer is visible in some way. Otherwise false.
*/
NS_IMETHOD_(bool) IsVisible() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIViewObserver, NS_IVIEWOBSERVER_IID)

View File

@ -265,7 +265,7 @@ void nsViewManager::DoSetWindowDimensions(nscoord aWidth, nscoord aHeight)
NS_IMETHODIMP nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight)
{
if (mRootView) {
if (mRootView->IsEffectivelyVisible()) {
if (mRootView->IsEffectivelyVisible() && mObserver && mObserver->IsVisible()) {
if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
mDelayedResize != nsSize(aWidth, aHeight)) {
// We have a delayed resize; that now obsolete size may already have
@ -827,7 +827,8 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
? vm->mRootView->GetParent()->GetViewManager()
: nsnull) {
if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
vm->mRootView->IsEffectivelyVisible()) {
vm->mRootView->IsEffectivelyVisible() &&
mObserver && mObserver->IsVisible()) {
vm->FlushDelayedResize(true);
// Paint later.