diff --git a/mozilla/extensions/spatialnavigation/src/nsSpatialNavigation.cpp b/mozilla/extensions/spatialnavigation/src/nsSpatialNavigation.cpp index cd34476da82..818aadf7ed3 100755 --- a/mozilla/extensions/spatialnavigation/src/nsSpatialNavigation.cpp +++ b/mozilla/extensions/spatialnavigation/src/nsSpatialNavigation.cpp @@ -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 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()); /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/extensions/spatialnavigation/src/nsSpatialNavigationPrivate.h b/mozilla/extensions/spatialnavigation/src/nsSpatialNavigationPrivate.h index 973c7b3fd7b..f8b527b6bc5 100755 --- a/mozilla/extensions/spatialnavigation/src/nsSpatialNavigationPrivate.h +++ b/mozilla/extensions/spatialnavigation/src/nsSpatialNavigationPrivate.h @@ -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); diff --git a/mozilla/extensions/spatialnavigation/src/nsSpatialNavigationUtils.cpp b/mozilla/extensions/spatialnavigation/src/nsSpatialNavigationUtils.cpp index ae7b5980696..cc1091ff700 100755 --- a/mozilla/extensions/spatialnavigation/src/nsSpatialNavigationUtils.cpp +++ b/mozilla/extensions/spatialnavigation/src/nsSpatialNavigationUtils.cpp @@ -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 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); +}