Bug 262578. No click to focus css scrollable areas like overflow:scroll, but you can still click there and scroll -- just no focus outline. r=mats, sr=roc

This commit is contained in:
aaronleventhal%moonset.net 2004-10-19 02:24:27 +00:00
parent 1b5234b527
commit e9feb9853d
11 changed files with 170 additions and 53 deletions

View File

@ -1874,7 +1874,8 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
break;
}
if (currFrame->IsFocusable()) {
PRInt32 tabIndexUnused;
if (currFrame->IsFocusable(&tabIndexUnused, PR_TRUE)) {
newFocus = currFrame->GetContent();
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(newFocus));
if (domElement)

View File

@ -350,19 +350,26 @@ nsLayoutUtils::FindSiblingViewFor(nsIView* aParentView, nsIFrame* aFrame) {
}
//static
nsPresContext::ScrollbarStyles
nsLayoutUtils::ScrollbarStylesOfView(nsIScrollableView *aScrollableView)
nsIScrollableFrame*
nsLayoutUtils::GetScrollableFrameFor(nsIScrollableView *aScrollableView)
{
nsIFrame *frame =
NS_STATIC_CAST(nsIFrame*, aScrollableView->View()->GetClientData());
nsIFrame *frame = GetFrameFor(aScrollableView->View());
if (frame && ((frame = frame->GetParent()))) {
nsIScrollableFrame *sf;
CallQueryInterface(frame, &sf);
if (sf)
return sf->GetScrollbarStyles();
return sf;
}
return nsPresContext::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN,
NS_STYLE_OVERFLOW_HIDDEN);
return nsnull;
}
//static
nsPresContext::ScrollbarStyles
nsLayoutUtils::ScrollbarStylesOfView(nsIScrollableView *aScrollableView)
{
nsIScrollableFrame *sf = GetScrollableFrameFor(aScrollableView);
return sf ? sf->GetScrollbarStyles() :
nsPresContext::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN,
NS_STYLE_OVERFLOW_HIDDEN);
}
// static
@ -370,7 +377,9 @@ nsIScrollableView*
nsLayoutUtils::GetNearestScrollingView(nsIView* aView, Direction aDirection)
{
// Find the first view that has a scrollable frame whose
// ScrollbarStyles is not NS_STYLE_OVERFLOW_HIDDEN in aDirection.
// ScrollbarStyles is not NS_STYLE_OVERFLOW_HIDDEN in aDirection
// and where there is something currently not visible
// that can be scrolled to in aDirection.
NS_ASSERTION(aView, "GetNearestScrollingView expects a non-null view");
nsIScrollableView* scrollableView = nsnull;
for (; aView; aView = aView->GetParent()) {
@ -378,12 +387,28 @@ nsLayoutUtils::GetNearestScrollingView(nsIView* aView, Direction aDirection)
if (scrollableView) {
nsPresContext::ScrollbarStyles ss =
nsLayoutUtils::ScrollbarStylesOfView(scrollableView);
nsIScrollableFrame *scrollableFrame = GetScrollableFrameFor(scrollableView);
// NS_ASSERTION(scrollableFrame, "Must have scrollable frame for view!");
if (!scrollableFrame) {
// XXX Once bug 260652 is fixed we should get scrollable frames for HTML
// frames and can uncomment the above scrollableFrame assertion instead
// of using this if condition.
break; // If scrollableView but not scrollable Frame, on an HTML <frame>
}
nsMargin margin = scrollableFrame->GetActualScrollbarSizes();
// Get size of total scrollable area
nscoord totalWidth, totalHeight;
scrollableView->GetContainerSize(&totalWidth, &totalHeight);
// Get size of currently visible area
nsSize visibleSize = GetFrameFor(aView)->GetSize();
// aDirection can be eHorizontal, eVertical, or eEither
if (aDirection != eHorizontal &&
ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN)
ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN &&
(totalHeight > visibleSize.height || margin.right))
break;
if (aDirection != eVertical &&
ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN)
ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN &&
(totalWidth > visibleSize.width || margin.bottom))
break;
}
}

View File

@ -42,13 +42,14 @@ class nsIFrame;
class nsPresContext;
class nsIContent;
class nsIAtom;
class nsIView;
class nsIScrollableView;
class nsIScrollableFrame;
#include "prtypes.h"
#include "nsStyleContext.h"
#include "nsAutoPtr.h"
#include "nsStyleSet.h"
#include "nsIView.h"
/**
* nsLayoutUtils is a namespace class used for various helper
@ -164,6 +165,22 @@ public:
static PRBool IsProperAncestorFrame(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
nsIFrame* aCommonAncestor = nsnull);
/**
* GetFrameFor returns the root frame for a view
* @param aView is the view to return the root frame for
* @return the root frame for the view
*/
static nsIFrame* GetFrameFor(nsIView *aView)
{ return NS_STATIC_CAST(nsIFrame*, aView->GetClientData()); }
/**
* GetScrollableFrameFor returns the scrollable frame for a scrollable view
* @param aScrollableView is the scrollable view to return the
* scrollable frame for.
* @return the scrollable frame for the scrollable view
*/
static nsIScrollableFrame* GetScrollableFrameFor(nsIScrollableView *aScrollableView);
static nsPresContext::ScrollbarStyles
ScrollbarStylesOfView(nsIScrollableView *aScrollableView);

View File

@ -3667,19 +3667,29 @@ PresShell::GetViewToScroll(nsLayoutUtils::Direction aDirection)
nsIScrollableView* scrollView = nsnull;
nsCOMPtr<nsIContent> focusedContent;
esm->GetFocusedContent(getter_AddRefs(focusedContent));
if (!focusedContent && mSelection) {
nsCOMPtr<nsISelection> domSelection;
mSelection->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(domSelection));
if (domSelection) {
nsCOMPtr<nsIDOMNode> focusedNode;
domSelection->GetFocusNode(getter_AddRefs(focusedNode));
focusedContent = do_QueryInterface(focusedNode);
}
}
if (focusedContent) {
nsIFrame* startFrame = nsnull;
GetPrimaryFrameFor(focusedContent, &startFrame);
if (startFrame) {
nsCOMPtr<nsIScrollableViewProvider> svp = do_QueryInterface(startFrame);
if (svp) {
scrollView = svp->GetScrollableView();
} else {
nsIView* startView = startFrame->GetClosestView();
if (startView)
scrollView =
nsLayoutUtils::GetNearestScrollingView(startView, aDirection);
}
// If this very frame provides a scroll view, start there instead of frame's
// closest view, because the scroll view may be inside a child frame.
// For example, this happens in the case of overflow:scroll.
// In that case we still use GetNearestScrollingView() because
// we need a scrolling view that matches aDirection.
nsIView* startView = svp? svp->GetScrollableView()->View() : startFrame->GetClosestView();
NS_ASSERTION(startView, "No view to start searching for scrollable view from");
scrollView = nsLayoutUtils::GetNearestScrollingView(startView, aDirection);
}
}
if (!scrollView) {

View File

@ -94,9 +94,9 @@ struct nsMargin;
typedef class nsIFrame nsIBox;
// IID for the nsIFrame interface
// 7a243690-a766-4394-bc13-788b1bf63ef1
// 8657598f-a18a-4b7f-96f3-6e7fe8a8beee
#define NS_IFRAME_IID \
{ 0x7a243690, 0xa766, 0x4394,{0xbc, 0x13, 0x78, 0x8b, 0x1b, 0xf6, 0x3e, 0xf1}}
{ 0x8657598f, 0xa18a, 0x4b7f, { 0x96, 0xf3, 0x6e, 0x7f, 0xe8, 0xa8, 0xbe, 0xee } }
/**
* Indication of how the frame can be split. This is used when doing runaround
@ -1269,9 +1269,10 @@ NS_PTR_TO_INT32(frame->GetProperty(nsLayoutAtoms::embeddingLevel))
* < 0 if not tabbable
* == 0 if in normal tab order
* > 0 can be tabbed to in the order specified by this value
* @param [in, optional] aWithMouse, is this focus query for mouse clicking
* @return whether the frame is focusable via mouse, kbd or script.
*/
PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
PRBool IsFocusable(PRInt32 *aTabIndex = nsnull, PRBool aWithMouse = PR_FALSE);
// BOX LAYOUT METHODS
// These methods have been migrated from nsIBox and are in the process of

View File

@ -42,13 +42,14 @@ class nsIFrame;
class nsPresContext;
class nsIContent;
class nsIAtom;
class nsIView;
class nsIScrollableView;
class nsIScrollableFrame;
#include "prtypes.h"
#include "nsStyleContext.h"
#include "nsAutoPtr.h"
#include "nsStyleSet.h"
#include "nsIView.h"
/**
* nsLayoutUtils is a namespace class used for various helper
@ -164,6 +165,22 @@ public:
static PRBool IsProperAncestorFrame(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
nsIFrame* aCommonAncestor = nsnull);
/**
* GetFrameFor returns the root frame for a view
* @param aView is the view to return the root frame for
* @return the root frame for the view
*/
static nsIFrame* GetFrameFor(nsIView *aView)
{ return NS_STATIC_CAST(nsIFrame*, aView->GetClientData()); }
/**
* GetScrollableFrameFor returns the scrollable frame for a scrollable view
* @param aScrollableView is the scrollable view to return the
* scrollable frame for.
* @return the scrollable frame for the scrollable view
*/
static nsIScrollableFrame* GetScrollableFrameFor(nsIScrollableView *aScrollableView);
static nsPresContext::ScrollbarStyles
ScrollbarStylesOfView(nsIScrollableView *aScrollableView);

View File

@ -350,19 +350,26 @@ nsLayoutUtils::FindSiblingViewFor(nsIView* aParentView, nsIFrame* aFrame) {
}
//static
nsPresContext::ScrollbarStyles
nsLayoutUtils::ScrollbarStylesOfView(nsIScrollableView *aScrollableView)
nsIScrollableFrame*
nsLayoutUtils::GetScrollableFrameFor(nsIScrollableView *aScrollableView)
{
nsIFrame *frame =
NS_STATIC_CAST(nsIFrame*, aScrollableView->View()->GetClientData());
nsIFrame *frame = GetFrameFor(aScrollableView->View());
if (frame && ((frame = frame->GetParent()))) {
nsIScrollableFrame *sf;
CallQueryInterface(frame, &sf);
if (sf)
return sf->GetScrollbarStyles();
return sf;
}
return nsPresContext::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN,
NS_STYLE_OVERFLOW_HIDDEN);
return nsnull;
}
//static
nsPresContext::ScrollbarStyles
nsLayoutUtils::ScrollbarStylesOfView(nsIScrollableView *aScrollableView)
{
nsIScrollableFrame *sf = GetScrollableFrameFor(aScrollableView);
return sf ? sf->GetScrollbarStyles() :
nsPresContext::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN,
NS_STYLE_OVERFLOW_HIDDEN);
}
// static
@ -370,7 +377,9 @@ nsIScrollableView*
nsLayoutUtils::GetNearestScrollingView(nsIView* aView, Direction aDirection)
{
// Find the first view that has a scrollable frame whose
// ScrollbarStyles is not NS_STYLE_OVERFLOW_HIDDEN in aDirection.
// ScrollbarStyles is not NS_STYLE_OVERFLOW_HIDDEN in aDirection
// and where there is something currently not visible
// that can be scrolled to in aDirection.
NS_ASSERTION(aView, "GetNearestScrollingView expects a non-null view");
nsIScrollableView* scrollableView = nsnull;
for (; aView; aView = aView->GetParent()) {
@ -378,12 +387,28 @@ nsLayoutUtils::GetNearestScrollingView(nsIView* aView, Direction aDirection)
if (scrollableView) {
nsPresContext::ScrollbarStyles ss =
nsLayoutUtils::ScrollbarStylesOfView(scrollableView);
nsIScrollableFrame *scrollableFrame = GetScrollableFrameFor(scrollableView);
// NS_ASSERTION(scrollableFrame, "Must have scrollable frame for view!");
if (!scrollableFrame) {
// XXX Once bug 260652 is fixed we should get scrollable frames for HTML
// frames and can uncomment the above scrollableFrame assertion instead
// of using this if condition.
break; // If scrollableView but not scrollable Frame, on an HTML <frame>
}
nsMargin margin = scrollableFrame->GetActualScrollbarSizes();
// Get size of total scrollable area
nscoord totalWidth, totalHeight;
scrollableView->GetContainerSize(&totalWidth, &totalHeight);
// Get size of currently visible area
nsSize visibleSize = GetFrameFor(aView)->GetSize();
// aDirection can be eHorizontal, eVertical, or eEither
if (aDirection != eHorizontal &&
ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN)
ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN &&
(totalHeight > visibleSize.height || margin.right))
break;
if (aDirection != eVertical &&
ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN)
ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN &&
(totalWidth > visibleSize.width || margin.bottom))
break;
}
}

View File

@ -4546,7 +4546,7 @@ nsFrame::GetStyleDataExternal(nsStyleStructID aSID) const
}
PRBool
nsIFrame::IsFocusable(PRInt32 *aTabIndex)
nsIFrame::IsFocusable(PRInt32 *aTabIndex, PRBool aWithMouse)
{
PRInt32 tabIndex = -1;
PRBool isFocusable = PR_FALSE;
@ -4574,13 +4574,18 @@ nsIFrame::IsFocusable(PRInt32 *aTabIndex)
tabIndex = 0;
}
isFocusable = mContent->IsFocusable(&tabIndex);
if (!isFocusable && GetType() == nsLayoutAtoms::scrollFrame &&
if (!isFocusable && !aWithMouse &&
GetType() == nsLayoutAtoms::scrollFrame &&
mContent->IsContentOfType(nsIContent::eHTML) &&
!mContent->IsNativeAnonymous() && mContent->GetParent() &&
!mContent->HasAttr(kNameSpaceID_None, nsHTMLAtoms::tabindex)) {
// Elements with scrollable view always focusable & tabbable
// 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.
nsCOMPtr<nsIScrollableFrame> scrollFrame = do_QueryInterface(this);
if (scrollFrame) {
nsIScrollableFrame::ScrollbarStyles styles =

View File

@ -94,9 +94,9 @@ struct nsMargin;
typedef class nsIFrame nsIBox;
// IID for the nsIFrame interface
// 7a243690-a766-4394-bc13-788b1bf63ef1
// 8657598f-a18a-4b7f-96f3-6e7fe8a8beee
#define NS_IFRAME_IID \
{ 0x7a243690, 0xa766, 0x4394,{0xbc, 0x13, 0x78, 0x8b, 0x1b, 0xf6, 0x3e, 0xf1}}
{ 0x8657598f, 0xa18a, 0x4b7f, { 0x96, 0xf3, 0x6e, 0x7f, 0xe8, 0xa8, 0xbe, 0xee } }
/**
* Indication of how the frame can be split. This is used when doing runaround
@ -1269,9 +1269,10 @@ NS_PTR_TO_INT32(frame->GetProperty(nsLayoutAtoms::embeddingLevel))
* < 0 if not tabbable
* == 0 if in normal tab order
* > 0 can be tabbed to in the order specified by this value
* @param [in, optional] aWithMouse, is this focus query for mouse clicking
* @return whether the frame is focusable via mouse, kbd or script.
*/
PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
PRBool IsFocusable(PRInt32 *aTabIndex = nsnull, PRBool aWithMouse = PR_FALSE);
// BOX LAYOUT METHODS
// These methods have been migrated from nsIBox and are in the process of

View File

@ -4546,7 +4546,7 @@ nsFrame::GetStyleDataExternal(nsStyleStructID aSID) const
}
PRBool
nsIFrame::IsFocusable(PRInt32 *aTabIndex)
nsIFrame::IsFocusable(PRInt32 *aTabIndex, PRBool aWithMouse)
{
PRInt32 tabIndex = -1;
PRBool isFocusable = PR_FALSE;
@ -4574,13 +4574,18 @@ nsIFrame::IsFocusable(PRInt32 *aTabIndex)
tabIndex = 0;
}
isFocusable = mContent->IsFocusable(&tabIndex);
if (!isFocusable && GetType() == nsLayoutAtoms::scrollFrame &&
if (!isFocusable && !aWithMouse &&
GetType() == nsLayoutAtoms::scrollFrame &&
mContent->IsContentOfType(nsIContent::eHTML) &&
!mContent->IsNativeAnonymous() && mContent->GetParent() &&
!mContent->HasAttr(kNameSpaceID_None, nsHTMLAtoms::tabindex)) {
// Elements with scrollable view always focusable & tabbable
// 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.
nsCOMPtr<nsIScrollableFrame> scrollFrame = do_QueryInterface(this);
if (scrollFrame) {
nsIScrollableFrame::ScrollbarStyles styles =

View File

@ -3667,19 +3667,29 @@ PresShell::GetViewToScroll(nsLayoutUtils::Direction aDirection)
nsIScrollableView* scrollView = nsnull;
nsCOMPtr<nsIContent> focusedContent;
esm->GetFocusedContent(getter_AddRefs(focusedContent));
if (!focusedContent && mSelection) {
nsCOMPtr<nsISelection> domSelection;
mSelection->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(domSelection));
if (domSelection) {
nsCOMPtr<nsIDOMNode> focusedNode;
domSelection->GetFocusNode(getter_AddRefs(focusedNode));
focusedContent = do_QueryInterface(focusedNode);
}
}
if (focusedContent) {
nsIFrame* startFrame = nsnull;
GetPrimaryFrameFor(focusedContent, &startFrame);
if (startFrame) {
nsCOMPtr<nsIScrollableViewProvider> svp = do_QueryInterface(startFrame);
if (svp) {
scrollView = svp->GetScrollableView();
} else {
nsIView* startView = startFrame->GetClosestView();
if (startView)
scrollView =
nsLayoutUtils::GetNearestScrollingView(startView, aDirection);
}
// If this very frame provides a scroll view, start there instead of frame's
// closest view, because the scroll view may be inside a child frame.
// For example, this happens in the case of overflow:scroll.
// In that case we still use GetNearestScrollingView() because
// we need a scrolling view that matches aDirection.
nsIView* startView = svp? svp->GetScrollableView()->View() : startFrame->GetClosestView();
NS_ASSERTION(startView, "No view to start searching for scrollable view from");
scrollView = nsLayoutUtils::GetNearestScrollingView(startView, aDirection);
}
}
if (!scrollView) {