Scroll when target is off screen. NPODB

This commit is contained in:
dougt%meer.net 2006-05-16 02:45:48 +00:00
parent b0d4b44133
commit 2a5c5c4ec1
3 changed files with 104 additions and 22 deletions

View File

@ -37,8 +37,7 @@
#include "nsSpatialNavigationPrivate.h"
PRInt32 gRectFudge = 20;
PRInt32 gDirectionalBias = 3;
PRInt32 gScrollOffset = 26;
PRInt32 gDirectionalBias = 1;
NS_INTERFACE_MAP_BEGIN(nsSpatialNavigation)
NS_INTERFACE_MAP_ENTRY(nsISpatialNavigation)
@ -573,8 +572,23 @@ nsSpatialNavigation::handleMove(int direction)
getContentInDirection(direction, presContext, focusedRect, focusedFrame, PR_FALSE, isAREA, getter_AddRefs(c));
if (c) {
setFocusedContent(c);
return NS_OK;
nsIDocument* doc = c->GetDocument();
if (!doc)
return NS_ERROR_FAILURE;
nsIPresShell *presShell = doc->GetShellAt(0);
nsIFrame* cframe = presShell->GetPrimaryFrameFor(c);
PRBool b = IsPartiallyVisible(presShell, cframe);
if (b)
setFocusedContent(c);
else
ScrollWindow(direction, getContentWindow());
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -653,21 +667,7 @@ nsSpatialNavigation::handleMove(int direction)
// how about this, if we find anything, we just scroll the
// page in the direction of the navigation??
{
nsCOMPtr<nsIDOMWindow> contentWindow = getContentWindow();
if (!contentWindow)
return NS_OK;
if (direction == eNavLeft)
contentWindow->ScrollBy(-1* gScrollOffset, 0);
else if (direction == eNavRight)
contentWindow->ScrollBy(gScrollOffset, 0);
else if (direction == eNavUp)
contentWindow->ScrollBy(0, -1 * gScrollOffset);
else
contentWindow->ScrollBy(0, gScrollOffset);
}
ScrollWindow(direction, getContentWindow());
///////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -46,7 +46,6 @@
#include "nsISpatialNavigation.h"
#include "nsArray.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsFrameTraversal.h"
@ -124,7 +123,6 @@
#include "nsPIDOMWindow.h"
#include "nsStyleContext.h"
class nsSpatialNavigationService;
class nsSpatialNavigation;
@ -219,6 +217,8 @@ void getRectOfAreaElement (nsIFrame* f, nsIDOMHTMLAreaElement* e, ns
PRBool isRectInDirection (int direction, nsRect& focusedRect, nsRect& frameRect);
PRInt64 spatialDistance (int direction, nsRect& a, nsRect& b);
void GetWindowFromDocument (nsIDOMDocument* aDocument, nsIDOMWindowInternal** aWindow);
PRBool IsPartiallyVisible (nsIPresShell* shell, nsIFrame* frame);
void ScrollWindow (int direction, nsIDOMWindow* window);

View File

@ -210,7 +210,7 @@ nsresult createFrameTraversal(PRUint32 type, nsPresContext* presContext,
if (!presShell)
return NS_ERROR_FAILURE;
nsIFrame* frame = presShell->GetRootFrame();
nsIFrame* frame = presShell->GetRootFrame();
if (!frame)
return NS_ERROR_FAILURE;
@ -767,3 +767,85 @@ void GetWindowFromDocument(nsIDOMDocument* aDocument, nsIDOMWindowInternal** aWi
nsCOMPtr<nsIDOMWindowInternal> window = do_QueryInterface(view);
NS_IF_ADDREF(*aWindow = window);
}
PRBool IsPartiallyVisible(nsIPresShell* shell, nsIFrame* frame)
{
// We need to know if at least a kMinPixels around the object is visible
// Otherwise it will be marked STATE_OFFSCREEN and STATE_INVISIBLE
const PRUint16 kMinPixels = 12;
// Set up the variables we need, return false if we can't get at them all
nsIViewManager* viewManager = shell->GetViewManager();
if (!viewManager)
return PR_FALSE;
// If visibility:hidden or visibility:collapsed then mark with STATE_INVISIBLE
if (!frame->GetStyleVisibility()->IsVisible())
{
return PR_FALSE;
}
nsPresContext *presContext = shell->GetPresContext();
if (!presContext)
return PR_FALSE;
// Get the bounds of the current frame, relative to the current view.
// We don't use the more accurate GetBoundsRect, because that is more expensive
// and the STATE_OFFSCREEN flag that this is used for only needs to be a rough indicator
nsRect relFrameRect = frame->GetRect();
nsPoint frameOffset;
nsIView *containingView = frame->GetViewExternal();
if (!containingView) {
frame->GetOffsetFromView(frameOffset, &containingView);
if (!containingView)
return PR_FALSE; // no view -- not visible
relFrameRect.x = frameOffset.x;
relFrameRect.y = frameOffset.y;
}
float p2t;
p2t = presContext->PixelsToTwips();
nsRectVisibility rectVisibility;
viewManager->GetRectVisibility(containingView, relFrameRect,
NS_STATIC_CAST(PRUint16, (kMinPixels * p2t)),
&rectVisibility);
if (rectVisibility == nsRectVisibility_kVisible ||
(rectVisibility == nsRectVisibility_kZeroAreaRect && frame->GetNextInFlow())) {
// This view says it is visible, but we need to check the parent view chain :(
// Note: zero area rects can occur in the first frame of a multi-frame text flow,
// in which case the next frame exists because the text flow is visible
while ((containingView = containingView->GetParent()) != nsnull) {
if (containingView->GetVisibility() == nsViewVisibility_kHide) {
return PR_FALSE;
}
}
return PR_TRUE;
}
return PR_FALSE;
}
const static PRInt32 gScrollOffset = (26*3);
void ScrollWindow(int direction, nsIDOMWindow* contentWindow)
{
if (!contentWindow)
return;
if (direction == eNavLeft)
contentWindow->ScrollBy(-1* gScrollOffset, 0);
else if (direction == eNavRight)
contentWindow->ScrollBy(gScrollOffset, 0);
else if (direction == eNavUp)
contentWindow->ScrollBy(0, -1 * gScrollOffset);
else
contentWindow->ScrollBy(0, gScrollOffset);
}