зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
18d865bedc
Коммит
f10d3e436c
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -217,7 +217,7 @@ nsDeckFrame::GetSelectedIndex()
|
|||
return index;
|
||||
}
|
||||
|
||||
nsIBox*
|
||||
nsIFrame*
|
||||
nsDeckFrame::GetSelectedBox()
|
||||
{
|
||||
return (mIndex >= 0) ? mFrames.FrameAt(mIndex) : nsnull;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче