Inital checkin of Spatial Navigation. Not part of the default build.

git-svn-id: svn://10.0.0.236/trunk@173382 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
dougt%meer.net
2005-05-13 19:42:15 +00:00
parent 95b53b2492
commit 33d689099e
13 changed files with 2641 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
DEPTH=../..
topsrcdir=@top_srcdir@
srcdir=@srcdir@
VPATH=@srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = snav
DIRS = public src
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,51 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Spatial Navigation
#
# The Initial Developer of the Original Code is Douglas F. Turner II
# Portions created by the Initial Developer are Copyright (C) 2004
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH=../../..
topsrcdir=@top_srcdir@
srcdir=@srcdir@
VPATH=@srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE=snav
XPIDL_MODULE=snav
XPIDLSRCS = nsISpatialNavigation.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,54 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Spatial Navigation
*
* The Initial Developer of the Original Code is
* Douglas F. Turner II
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsIDOMWindow;
[scriptable, uuid(ef7cb437-9eb3-47c7-9d89-71679bfefcc1)]
interface nsISpatialNavigation: nsISupports
{
void init(in nsIDOMWindow aWindow);
void shutdown();
void up();
void down();
void left();
void right();
readonly attribute nsIDOMWindow attachedWindow;
};

View File

@@ -0,0 +1,82 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Spatial Navigation
#
# The Initial Developer of the Original Code is Douglas F. Turner II
# Portions created by the Initial Developer are Copyright (C) 2004
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH=../../..
topsrcdir=@top_srcdir@
srcdir=@srcdir@
VPATH=@srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = snav
LIBRARY_NAME = snav
IS_COMPONENT = 1
REQUIRES = xpcom \
string \
pref \
js \
dom \
dom_base \
gfx \
layout \
content \
widget \
locale \
necko \
docshell \
view \
webshell \
windowwatcher \
webbrwsr \
$(NULL)
CPPSRCS= \
nsSpatialNavigation.cpp \
nsSpatialNavigationUtils.cpp \
nsSpatialNavigationService.cpp \
$(NULL)
DEFINES = -DMOZILLA_INTERNAL_API
EXTRA_DSO_LIBS = gkgfx
EXTRA_DSO_LDOPTS += $(LIBS_DIR) \
$(EXTRA_DSO_LIBS) \
$(MOZ_COMPONENT_LIBS)\
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,737 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Spatial Navigation
*
* The Initial Developer of the Original Code is
* Douglas F. Turner II <dougt@meer.net>
* Portions created by the Initial Developer are Copyright (C) 2004-2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsSpatialNavigationPrivate.h"
PRInt32 gRectFudge = 20;
PRInt32 gDirectionalBias = 3;
NS_INTERFACE_MAP_BEGIN(nsSpatialNavigation)
NS_INTERFACE_MAP_ENTRY(nsISpatialNavigation)
NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMKeyListener)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsSpatialNavigation)
NS_IMPL_RELEASE(nsSpatialNavigation)
nsSpatialNavigation::nsSpatialNavigation(nsSpatialNavigationService* aService)
{
NS_ASSERTION(aService, "Should not create this object without a valid service");
mService = aService; // back pointer -- no reference
mNavigationFramesState = PR_FALSE;
}
nsSpatialNavigation::~nsSpatialNavigation()
{
}
NS_IMETHODIMP
nsSpatialNavigation::HandleEvent(nsIDOMEvent* aEvent)
{
return NS_OK;
}
NS_IMETHODIMP
nsSpatialNavigation::KeyDown(nsIDOMEvent* aEvent)
{
return NS_OK;
}
NS_IMETHODIMP
nsSpatialNavigation::KeyUp(nsIDOMEvent* aEvent)
{
return NS_OK;
}
NS_IMETHODIMP
nsSpatialNavigation::KeyPress(nsIDOMEvent* aEvent)
{
// check to see if we are in a text field.
if (!mService->mIgnoreTextFields)
{
// based on nsTypeAheadFind.
//nsEvent should be renamed.
nsCOMPtr<nsIDOMNSEvent> nsEvent = do_QueryInterface(aEvent);
if (!nsEvent)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMEventTarget> domEventTarget;
nsEvent->GetOriginalTarget(getter_AddRefs(domEventTarget));
nsCOMPtr<nsIContent> targetContent = do_QueryInterface(domEventTarget);
if (targetContent->IsContentOfType(nsIContent::eHTML_FORM_CONTROL))
{
nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(targetContent));
PRInt32 controlType = formControl->GetType();
if (controlType == NS_FORM_TEXTAREA ||
controlType == NS_FORM_INPUT_TEXT ||
controlType == NS_FORM_INPUT_PASSWORD ||
controlType == NS_FORM_INPUT_FILE)
{
return NS_OK;
}
}
else if (targetContent->IsContentOfType(nsIContent::eHTML))
{
// Test for isindex, a deprecated kind of text field. We're using a string
// compare because <isindex> is not considered a form control, so it does
// not support nsIFormControl or eHTML_FORM_CONTROL, and it's not worth
// having a table of atoms just for it.
if (isContentOfType(targetContent, "isindex"))
return NS_OK;
}
}
PRUint32 keyCode;
PRBool isModifier;
nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aEvent));
if (!keyEvent)
return NS_ERROR_FAILURE;
if (NS_FAILED(keyEvent->GetKeyCode(&keyCode)))
return NS_ERROR_FAILURE;
// figure out what modifier to use
/************************************************
Value of the keyCodeModifier is
SHIFT = 0x00100000
CONTROL = 0x00001100
ALT = 0x00000012
*************************************************/
if (mService->mKeyCodeModifier & 0x00100000)
{
if (NS_FAILED(keyEvent->GetShiftKey(&isModifier)))
return NS_ERROR_FAILURE;
if (!isModifier)
return NS_OK;
}
if (mService->mKeyCodeModifier & 0x00001100)
{
if (NS_FAILED(keyEvent->GetCtrlKey(&isModifier)))
return NS_ERROR_FAILURE;
if (!isModifier)
return NS_OK;
}
if (mService->mKeyCodeModifier & 0x00000012)
{
if (NS_FAILED(keyEvent->GetAltKey(&isModifier)))
return NS_ERROR_FAILURE;
if (!isModifier)
return NS_OK;
}
if (keyCode == mService->mKeyCodeLeft)
{
// We're using this key, no one else should
aEvent->StopPropagation();
aEvent->PreventDefault();
return Left();
}
if (keyCode == mService->mKeyCodeRight)
{
aEvent->StopPropagation();
aEvent->PreventDefault();
return Right();
}
if (keyCode == mService->mKeyCodeUp)
{
aEvent->StopPropagation();
aEvent->PreventDefault();
return Up();
}
if (keyCode == mService->mKeyCodeDown)
{
aEvent->StopPropagation(); // We're using this key, no one else should
aEvent->PreventDefault();
return Down();
}
return NS_OK;
}
NS_IMETHODIMP
nsSpatialNavigation::Init(nsIDOMWindow *aWindow)
{
mTopWindow = aWindow;
nsCOMPtr<nsIDOM3EventTarget> target;
nsCOMPtr<nsIDOMEventGroup> systemGroup;
nsresult rv = getEventTargetFromWindow(aWindow, getter_AddRefs(target), getter_AddRefs(systemGroup));
if (NS_FAILED(rv))
return rv;
target->AddGroupedEventListener(NS_LITERAL_STRING("keypress"),
NS_STATIC_CAST(nsIDOMKeyListener*, this),
PR_FALSE,
systemGroup);
return NS_OK;
}
NS_IMETHODIMP
nsSpatialNavigation::Shutdown()
{
nsCOMPtr<nsIDOM3EventTarget> target;
nsCOMPtr<nsIDOMEventGroup> systemGroup;
nsresult rv = getEventTargetFromWindow(mTopWindow, getter_AddRefs(target), getter_AddRefs(systemGroup));
if (NS_FAILED(rv))
return rv;
target->RemoveGroupedEventListener(NS_LITERAL_STRING("keypress"),
NS_STATIC_CAST(nsIDOMKeyListener*, this),
PR_FALSE,
systemGroup);
mTopWindow = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsSpatialNavigation::Up()
{
return handleMove(eNavUp);
}
NS_IMETHODIMP
nsSpatialNavigation::Down()
{
return handleMove(eNavDown);
}
NS_IMETHODIMP
nsSpatialNavigation::Left()
{
return handleMove(eNavLeft);
}
NS_IMETHODIMP
nsSpatialNavigation::Right()
{
return handleMove(eNavRight);
}
NS_IMETHODIMP
nsSpatialNavigation::GetAttachedWindow(nsIDOMWindow * *aAttachedWindow)
{
NS_IF_ADDREF(*aAttachedWindow = mTopWindow);
return NS_OK;
}
void DoTraversal(int aDirection,
nsIBidirectionalEnumerator* aFrameTraversal,
nsIFrame* aFocusedFrame,
nsRect& aFocusedRect,
PRBool isAREA,
PRBool focusDocuments,
nsPresContext* aPresContext,
PRInt64* aDSoFar,
nsIContent** aCurrentContent)
{
*aCurrentContent = nsnull;
// There are some rects with zero width or height.
// calculating distance from a non point is troublesome.
// we will fix this up here by setting such a point to at
// least 1 px.
if (aFocusedRect.width == 0) {
aFocusedRect.width = 1;
}
if (aFocusedRect.height == 0) {
aFocusedRect.height = 1;
}
nsIFrame* frame;
nsRect frameRect;
PRInt64 d;
while (1)
{
aFrameTraversal->Next();
nsISupports* currentItem;
aFrameTraversal->CurrentItem(&currentItem);
frame = NS_STATIC_CAST(nsIFrame*, currentItem);
if (!frame)
break;
printf("got frame %x\n", frame);
// So, here we want to make sure that the frame that we
// nav to isn't part of the flow of the currently
// focused frame
if (!isAREA)
{
nsIFrame* flowFrame = aFocusedFrame;
PRBool currentFrameIsFocusedFrame = PR_FALSE;
while (flowFrame)
{
if (flowFrame == frame)
{
currentFrameIsFocusedFrame = PR_TRUE;
break;
}
flowFrame = flowFrame->GetNextInFlow();
}
if (currentFrameIsFocusedFrame)
continue;
}
////////////////////////////////////////////////////////////////////////////////////
// a special case for area's which are not enumerated by the nsIFrameTraversal
////////////////////////////////////////////////////////////////////////////////////
if (isMap(frame))
{
nsIContent* c = frame->GetContent();
nsCOMPtr<nsIDOMHTMLMapElement> element = do_QueryInterface(c);
if (!element)
continue;
nsCOMPtr<nsIDOMHTMLCollection> mapAreas;
element->GetAreas(getter_AddRefs(mapAreas));
if (!mapAreas)
continue;
PRUint32 length;
mapAreas->GetLength(&length);
for (PRUint32 i = 0; i < length; i++)
{
nsCOMPtr<nsIDOMNode> domNode;
mapAreas->Item(i,getter_AddRefs(domNode));
nsCOMPtr<nsIDOMHTMLAreaElement> e = do_QueryInterface(domNode);
nsCOMPtr<nsIContent> content= do_QueryInterface(domNode);
getFrameForContent(content, &frame);
getRectOfAreaElement(frame, e, &frameRect);
if (!isRectInDirection(aDirection, aFocusedRect, frameRect))
continue;
d = spatialDistance(aDirection, aFocusedRect, frameRect);
if ((*aDSoFar) > d)
{
(*aDSoFar) = d;
NS_IF_RELEASE(*aCurrentContent);
NS_ADDREF(*aCurrentContent = content);
}
}
continue;
}
////////////////////////////////////////////////////////////////////////////////////
// we don't want to worry about the same frame if we
// aren't an area
if (frame == aFocusedFrame ||
(aFocusedFrame && (frame->GetContent() == aFocusedFrame->GetContent())))
continue;
// make sure the frame is targetable for focus
if (!isTargetable(focusDocuments, frame))
continue;
// RECT !!
frameRect = makeRectRelativeToGlobalView(frame);
// no frames without size and be navigated to
// successfully.
if (frameRect.width == 0 || frameRect.height == 0)
continue;
// deflate the rect to avoid overlapping with other
// rects.
frameRect.Deflate(gRectFudge, gRectFudge);
if (!isRectInDirection(aDirection, aFocusedRect, frameRect))
continue;
d = spatialDistance(aDirection, aFocusedRect, frameRect);
if ((*aDSoFar) >= d)
{
#ifdef DEBUG_dougt
if (d == 0)
{
printf("there is overlapping content;\n");
}
#endif
(*aDSoFar) = d;
NS_IF_RELEASE(*aCurrentContent);
NS_ADDREF(*aCurrentContent = frame->GetContent());
}
}
}
inline void centerRect(int aDirection, nsRect& aRect)
{
if (aDirection == eNavLeft)
aRect.x = 1000000;
else if (aDirection == eNavRight)
aRect.x = 0;
else if (aDirection == eNavUp)
aRect.y = 1000000;
else
aRect.y = 0;
aRect.height = 1;
aRect.width = 1;
}
nsresult
nsSpatialNavigation::getContentInDirection(int aDirection,
nsPresContext* aPresContext,
nsRect& aFocusedRect,
nsIFrame* aFocusedFrame,
PRBool aIsAREA,
PRBool aFocusDocuments,
nsIContent** aContent)
{
// Check to see if we should decend into subdoc
nsIContent* subFrameContent = aFocusedFrame->GetContent();
nsCOMPtr<nsIDOMHTMLHtmlElement> hhElement = do_QueryInterface(subFrameContent);
nsCOMPtr<nsIDOMHTMLIFrameElement> iFrameElement = do_QueryInterface(subFrameContent);
if ( (hhElement || iFrameElement) && mNavigationFramesState)
{
aPresContext = getPresContext(subFrameContent);
centerRect(aDirection, aFocusedRect);
}
nsCOMPtr<nsIBidirectionalEnumerator> frameTraversal;
nsresult result = createFrameTraversal(FOCUS, aPresContext, getter_AddRefs(frameTraversal));
if (NS_FAILED(result))
return result;
nsCOMPtr<nsIContent> currentContent;
PRInt64 currentDistance = LL_MaxInt();
DoTraversal(aDirection,
frameTraversal,
aFocusedFrame,
aFocusedRect,
aIsAREA,
aFocusDocuments,
aPresContext,
&currentDistance,
aContent);
if ( (hhElement || iFrameElement) && mNavigationFramesState)
{
mNavigationFramesState = PR_FALSE;
}
return NS_OK;
}
nsresult
nsSpatialNavigation::handleMove(int direction)
{
PRUint32 type = FOCUS;
if (!mService->mEnabled)
return NS_OK;
nsCOMPtr<nsIContent> focusedContent;
getFocusedContent(direction, getter_AddRefs(focusedContent));
if (!focusedContent)
return NS_OK;
nsPresContext* presContext = getPresContext(focusedContent);
if(!presContext)
return NS_ERROR_NULL_POINTER;
nsIFrame* focusedFrame;
getFrameForContent(focusedContent, &focusedFrame);
nsRect focusedRect;
PRBool isAREA = isArea(focusedContent);
if (!isAREA)
{
// RECT !!
focusedRect = makeRectRelativeToGlobalView(focusedFrame);
// deflate the rect to avoid overlapping with other
// rects.
focusedRect.Deflate(gRectFudge, gRectFudge);
}
else
{
nsCOMPtr<nsIDOMHTMLAreaElement> e = do_QueryInterface(focusedContent);
getRectOfAreaElement(focusedFrame, e, &focusedRect);
}
nsCOMPtr<nsIContent> c;
getContentInDirection(direction, presContext, focusedRect, focusedFrame, PR_FALSE, isAREA, getter_AddRefs(c));
if (c) {
setFocusedContent(c);
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// do it all again at the parent document
///////////////////////////////////////////////////////////////////////////////////////////////////
{
nsCOMPtr<nsIDOMWindow> contentWindow = getContentWindow();
if (!contentWindow)
return NS_OK;
nsCOMPtr<nsIDOMDocument> domDoc;
contentWindow->GetDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
nsIPresShell *shell = doc->GetShellAt(0);
if (!shell) return NS_OK;
presContext = shell->GetPresContext();
nsIFrame* parentFrame = shell->GetRootFrame();
nsCOMPtr<nsIDocument> subdoc = focusedContent->GetDocument();
if (!subdoc) return NS_OK;
nsCOMPtr<nsIDOMDocument> subdomdoc = do_QueryInterface(subdoc);
nsCOMPtr<nsIDOMWindowInternal> domWindowInternal;
GetWindowFromDocument(subdomdoc, getter_AddRefs(domWindowInternal));
if (!domWindowInternal) return NS_OK;
nsCOMPtr<nsIDOMWindowInternal> domWindowInternal2 = domWindowInternal;
domWindowInternal2->GetOpener(getter_AddRefs(domWindowInternal));
if (!domWindowInternal)
domWindowInternal = domWindowInternal2;
nsCOMPtr<nsIDOMWindow> subdocWindow = do_QueryInterface(domWindowInternal);
if (!subdocWindow) return NS_OK;
subdocWindow->GetDocument(getter_AddRefs(subdomdoc));
if (!subdoc) return NS_OK;
nsIPresShell *subdocShell = subdoc->GetShellAt(0);
if (!subdocShell) return NS_OK;
nsPresContext *subdocPresContext = subdocShell->GetPresContext();
nsIFrame* subdocFrame = subdocShell->GetRootFrame();
nsRect subdocRect = subdocFrame->GetRect();
nsPoint frame_offset = subdocFrame->GetOffsetToExternal(parentFrame);
subdocRect.x = frame_offset.x;
subdocRect.y = frame_offset.y;
getContentInDirection(direction, presContext, subdocRect, subdocFrame, PR_TRUE, PR_FALSE, getter_AddRefs(c));
}
if (c) {
nsCOMPtr<nsIContent> subdocContent;
getContentFromFrame(c, getter_AddRefs(subdocContent));
if (subdocContent) {
mNavigationFramesState = PR_TRUE;
setFocusedContent(c);
return NS_OK;
}
setFocusedContent(c);
return NS_OK;
}
// if everything fails, default is to move the focus just as if the user hit tab.
// presContext->EventStateManager()->ShiftFocus(PR_TRUE, focusedContent);
///////////////////////////////////////////////////////////////////////////////////////////////////
return NS_OK;
}
void
nsSpatialNavigation::getFocusedContent(int direction, nsIContent** aContent)
{
*aContent = nsnull;
nsCOMPtr<nsIDOMWindow> contentWindow = getContentWindow();
if (!contentWindow)
return;
nsCOMPtr<nsPIDOMWindow> privateWindow = do_QueryInterface(contentWindow);
nsIFocusController *focusController = privateWindow->GetRootFocusController();
if (!focusController)
return;
nsCOMPtr<nsIDOMElement> element;
focusController->GetFocusedElement(getter_AddRefs(element));
if (element)
{
nsCOMPtr<nsIContent> content = do_QueryInterface(element);
NS_IF_ADDREF(*aContent = content);
return;
}
//xxxx should/can we prevent it from going into chrome???
if (direction == eNavLeft || direction == eNavUp)
focusController->MoveFocus(PR_FALSE, nsnull);
else
focusController->MoveFocus(PR_TRUE, nsnull);
// so there is no focused content -- lets make some up, hightlight it and return.
focusController->GetFocusedElement(getter_AddRefs(element));
}
void
nsSpatialNavigation::setFocusedContent(nsIContent* c)
{
if (!c)
return;
nsCOMPtr<nsIContent> subdocContent;
getContentFromFrame(c, getter_AddRefs(subdocContent));
if (subdocContent) {
c = subdocContent;
}
nsIContent* currentContent = c;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(currentContent);
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(element));
nsCOMPtr<nsIDOMWindow> contentWindow;
if (mService->mDisableJSWhenFocusing)
contentWindow = getContentWindow();
DisableJSScope foopy (contentWindow);
//#ifdef OLDER_LAYOUT
nsPresContext* presContext = getPresContext(c);
nsIFrame* frame = nsnull;
nsIPresShell *presShell = presContext->PresShell();
presShell->GetPrimaryFrameFor(c, &frame);
if (frame) {
presContext->EventStateManager()->SetContentState(c, NS_EVENT_STATE_FOCUS);
presShell->ScrollFrameIntoView(frame,
NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
presContext->EventStateManager()->MoveCaretToFocus();
}
//#else
nsCOMPtr<nsIDOMNSHTMLElement> nsElement = do_QueryInterface(element);
if (nsElement)
nsElement->Focus();
//#endif
}
nsIDOMWindow*
nsSpatialNavigation::getContentWindow()
{
nsIDOMWindow* resultWindow = nsnull;
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mTopWindow);
nsIDOMWindowInternal *rootWindow = window->GetPrivateRoot();
nsCOMPtr<nsIDOMWindow> windowContent;
rootWindow->GetContent(getter_AddRefs(windowContent));
if (!windowContent)
return nsnull;
NS_ADDREF(resultWindow = windowContent);
return resultWindow;
}
nsPresContext*
nsSpatialNavigation::getPresContext(nsIContent* content)
{
if (!content) return nsnull;
nsCOMPtr<nsIDocument> doc = content->GetDocument();
if (!doc) return nsnull;
// the only case where there could be more shells in printpreview
nsIPresShell *shell = doc->GetShellAt(0);
if (!shell) return nsnull;
nsPresContext *presContext = shell->GetPresContext();
return presContext;
}

View File

@@ -0,0 +1,273 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Spatial Navigation
*
* The Initial Developer of the Original Code is
* Douglas F. Turner II <dougt@meer.net>
* Portions created by the Initial Developer are Copyright (C) 2004-2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "memory.h"
#include "stdlib.h"
#include "nspr.h"
#include "nsXPCOM.h"
#include "nsCOMPtr.h"
#include "nsMemory.h"
#include "nsString.h"
#include "nsISpatialNavigation.h"
#include "nsArray.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsFrameTraversal.h"
#include "nsHTMLAtoms.h"
#include "nsIArray.h"
#include "nsIBaseWindow.h"
#include "nsICategoryManager.h"
#include "nsIChromeEventHandler.h"
#include "nsIComponentManager.h"
#include "nsIDOM3EventTarget.h"
#include "nsIDOMAbstractView.h"
#include "nsIDOMCSSStyleDeclaration.h"
#include "nsIDOMDocument.h"
#include "nsIDOMDocument.h"
#include "nsIDOMDocumentView.h"
#include "nsIDOMElementCSSInlineStyle.h"
#include "nsIDOMEvent.h"
#include "nsIDOMEventGroup.h"
#include "nsIDOMEventReceiver.h"
#include "nsIDOMHTMLAnchorElement.h"
#include "nsIDOMHTMLAreaElement.h"
#include "nsIDOMHTMLCollection.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMHTMLFrameElement.h"
#include "nsIDOMHTMLHtmlElement.h"
#include "nsIDOMHTMLIFrameElement.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIDOMHTMLMapElement.h"
#include "nsIDOMHTMLOptionElement.h"
#include "nsIDOMHTMLSelectElement.h"
#include "nsIDOMKeyEvent.h"
#include "nsIDOMKeyListener.h"
#include "nsIDOMNSEvent.h"
#include "nsIDOMNSHTMLElement.h"
#include "nsIDOMNSUIEvent.h"
#include "nsIDOMNode.h"
#include "nsIDOMWindow.h"
#include "nsIDOMWindowInternal.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIDocument.h"
#include "nsIDocumentViewer.h"
#include "nsIEventStateManager.h"
#include "nsIFile.h"
#include "nsIFocusController.h"
#include "nsIFormControl.h"
#include "nsIFrameFrame.h"
#include "nsIFrameLoader.h"
#include "nsIFrameTraversal.h"
#include "nsIGenericFactory.h"
#include "nsIHTMLDocument.h"
#include "nsIImageFrame.h"
#include "nsIImageMap.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsILineIterator.h"
#include "nsILocalFile.h"
#include "nsINameSpaceManager.h"
#include "nsINodeInfo.h"
#include "nsIObserver.h"
#include "nsIPrefBranchInternal.h"
#include "nsIPrefService.h"
#include "nsIProperties.h"
#include "nsIScriptContext.h"
#include "nsIScriptGlobalObject.h"
#include "nsIServiceManager.h"
#include "nsISound.h"
#include "nsIView.h"
#include "nsIViewManager.h"
#include "nsIWebBrowser.h"
#include "nsIWebBrowserChrome.h"
#include "nsIWindowWatcher.h"
#include "nsLayoutAtoms.h"
#include "nsLayoutCID.h"
#include "nsPIDOMWindow.h"
#include "nsStyleContext.h"
class nsSpatialNavigationService;
class nsSpatialNavigation;
class nsSpatialNavigation : public nsISpatialNavigation, public nsIDOMKeyListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISPATIALNAVIGATION
NS_DECL_NSIDOMEVENTLISTENER
// ----- nsIDOMKeyListener ----------------------------
NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);
nsSpatialNavigation(nsSpatialNavigationService* aService);
private:
~nsSpatialNavigation();
nsPresContext* getPresContext(nsIContent* aContent);
PRInt64 spatialDistance(int direction, nsRect& a, nsRect& b);
nsIDOMWindow* getContentWindow();
void setFocusedContent(nsIContent* aContent);
void getFocusedContent(int direction, nsIContent** aContent);
nsresult handleMove(int direction);
nsresult getContentInDirection(int direction, nsPresContext* presContext, nsRect& focusedRect, nsIFrame* focusedFrame, PRBool aFocusDocuments, PRBool isAREA, nsIContent** aContent);
nsCOMPtr<nsIDOMWindow> mTopWindow;
nsSpatialNavigationService* mService;
PRBool mNavigationFramesState;
};
class nsSpatialNavigationService: public nsIObserver
{
public:
nsSpatialNavigationService();
virtual ~nsSpatialNavigationService();
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
nsCOMArray<nsISpatialNavigation> mObjects;
PRBool mEnabled;
PRBool mIgnoreTextFields;
PRBool mDisableJSWhenFocusing;
PRInt32 mKeyCodeLeft;
PRInt32 mKeyCodeRight;
PRInt32 mKeyCodeUp;
PRInt32 mKeyCodeDown;
PRInt32 mKeyCodeModifier;
};
extern PRInt32 gRectFudge;
extern PRInt32 gDirectionalBias;
enum {
eNavLeft = 0,
eNavUp,
eNavRight,
eNavDown
};
// Utils
PRBool is_space (char c);
nscoord* lo_parse_coord_list (char *str, PRInt32* value_cnt);
nsresult createFrameTraversal (PRUint32 type, nsPresContext* presContext, nsIBidirectionalEnumerator** outTraversal);
nsresult getEventTargetFromWindow (nsIDOMWindow* aWindow, nsIDOM3EventTarget** aEventTarget, nsIDOMEventGroup** aSystemGroup);
void getContentFromFrame (nsIContent* c, nsIContent** outContent);
nsresult getFrameForContent (nsIContent* aContent, nsIFrame** aFrame);
PRBool isContentOfType (nsIContent* content, const char* type);
PRBool isArea (nsIContent* content);
PRBool isMap (nsIFrame* frame);
PRBool isTargetable (PRBool focusDocuments, nsIFrame* frame);
nsRect makeRectRelativeToGlobalView (nsIFrame *aFrame);
void poly2Rect (int sides, nscoord* coord, nsRect* rect);
void getRectOfAreaElement (nsIFrame* f, nsIDOMHTMLAreaElement* e, nsRect* r);
PRBool isRectInDirection (int direction, nsRect& focusedRect, nsRect& frameRect);
PRInt64 spatialDistance (int direction, nsRect& a, nsRect& b);
void GetWindowFromDocument (nsIDOMDocument* aDocument, nsIDOMWindowInternal** aWindow);
class DisableJSScope
{
public:
DisableJSScope(nsIDOMWindow* window) :
isEnabled(PR_FALSE), scriptContext(nsnull)
{
// My passing null, we don't do a thing
if (!window)
return;
// so, we want to set the focus to the next element, but
// we do not want onFocus to fire. The reason for this is
// that we want to have the "enter" key be able to trigger
// the targeted link after we have focused it. However,
// we have found a popular portal has a toolbar that, on
// onFocus, decides to move the focus as if the targeted
// content was clicked. The only way that I know how to
// do this is to disable javascript during this call.
nsCOMPtr<nsIScriptGlobalObject> sgo (do_QueryInterface(window));
if (!sgo)
return;
scriptContext = sgo->GetContext();
if (!scriptContext)
return;
isEnabled = scriptContext->GetScriptsEnabled();
if (isEnabled)
scriptContext->SetScriptsEnabled(PR_FALSE, PR_TRUE);
}
~DisableJSScope()
{
if (isEnabled && scriptContext)
{
// enable javascript again..
scriptContext->SetScriptsEnabled(PR_TRUE, PR_TRUE);
}
}
PRBool isEnabled;
nsIScriptContext *scriptContext;
};

View File

@@ -0,0 +1,267 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Spatial Navigation
*
* The Initial Developer of the Original Code is
* Douglas F. Turner II <dougt@meer.net>
* Portions created by the Initial Developer are Copyright (C) 2004-2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsSpatialNavigationPrivate.h"
nsSpatialNavigationService::nsSpatialNavigationService()
{
mEnabled = PR_TRUE;
mIgnoreTextFields = PR_TRUE;
mDisableJSWhenFocusing = PR_TRUE;
mKeyCodeLeft = nsIDOMKeyEvent::DOM_VK_LEFT;
mKeyCodeRight = nsIDOMKeyEvent::DOM_VK_RIGHT;
mKeyCodeUp = nsIDOMKeyEvent::DOM_VK_UP;
mKeyCodeDown = nsIDOMKeyEvent::DOM_VK_DOWN;
mKeyCodeModifier = 0x00000012 | 0x00100000; // By default ALT and SHIFT
}
nsSpatialNavigationService::~nsSpatialNavigationService()
{
}
NS_IMPL_ISUPPORTS1(nsSpatialNavigationService, nsIObserver)
NS_IMETHODIMP
nsSpatialNavigationService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
{
nsresult rv;
if (!strcmp(aTopic,"domwindowopened"))
{
nsCOMPtr<nsIDOMWindow> chromeWindow = do_QueryInterface(aSubject);
nsSpatialNavigation* sn = new nsSpatialNavigation(this);
if (!sn)
return NS_ERROR_OUT_OF_MEMORY;
sn->Init(chromeWindow);
mObjects.AppendObject(sn); // the array owns the only reference to sn.
return NS_OK;
}
if (!strcmp(aTopic,"domwindowclosed"))
{
nsCOMPtr<nsIDOMWindow> chromeWindow = do_QueryInterface(aSubject);
// need to find it in our array
PRInt32 count = mObjects.Count();
for (PRInt32 i = 0; i < count; i++)
{
nsISpatialNavigation* sn = mObjects[i];
nsCOMPtr<nsIDOMWindow> attachedWindow;
sn->GetAttachedWindow(getter_AddRefs(attachedWindow));
if (attachedWindow == chromeWindow)
{
sn->Shutdown();
mObjects.RemoveObjectAt(i);
return NS_OK;
}
}
return NS_OK;
}
if (!strcmp(aTopic,"xpcom-startup"))
{
nsCOMPtr<nsIWindowWatcher> windowWatcher = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
windowWatcher->RegisterNotification(this);
nsCOMPtr<nsIPrefBranchInternal> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
NS_ENSURE_SUCCESS(rv, rv);
prefBranch->AddObserver("snav.", this, PR_FALSE);
return NS_OK;
}
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID))
{
nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
nsXPIDLCString cstr;
const char* pref = NS_ConvertUCS2toUTF8(aData).get();
if (!strcmp(pref, "snav.enabled"))
{
prefBranch->GetIntPref(pref, &mEnabled);
}
else if (!strcmp(pref, "snav.ignoreTextFields"))
{
prefBranch->GetIntPref(pref, &mIgnoreTextFields);
}
else if (!strcmp(pref, "snav.directionalBias"))
{
prefBranch->GetIntPref(pref, &gDirectionalBias);
if (gDirectionalBias == 0)
gDirectionalBias = 1;
}
else if (!strcmp(pref, "snav.disableJS"))
{
prefBranch->GetIntPref(pref, &mDisableJSWhenFocusing);
}
else if (!strcmp(pref, "snav.rectFudge"))
{
prefBranch->GetIntPref(pref, &gRectFudge);
}
else if (!strcmp(pref, "snav.keyCode.left"))
{
prefBranch->GetIntPref(pref, &mKeyCodeLeft);
}
else if (!strcmp(pref, "snav.keyCode.right"))
{
prefBranch->GetIntPref(pref, &mKeyCodeRight);
}
else if (!strcmp(pref, "snav.keyCode.up"))
{
prefBranch->GetIntPref(pref, &mKeyCodeUp);
}
else if (!strcmp(pref, "snav.keyCode.down"))
{
prefBranch->GetIntPref(pref, &mKeyCodeDown);
}
else if (!strcmp(pref, "snav.keyCode.modifier"))
{
prefBranch->GetIntPref(pref, &mKeyCodeModifier);
}
return NS_OK;
}
return NS_OK;
}
//------------------------------------------------------------------------------
// XPCOM REGISTRATION BELOW
//------------------------------------------------------------------------------
#define SpatialNavigation_CID \
{ 0xd1b91385, 0xe1c1, 0x46ec, \
{0x8d, 0x15, 0x88, 0x0c, 0x45, 0xbe, 0x8e, 0x0e} }
#define SpatialNavigation_ContractID "@mozilla.org/spatialNavigation/service;1"
#define SpatialNavigationService_CID \
{ 0x4125624b, 0xaf22, 0x4d50, \
{ 0x87, 0xf6, 0x40, 0x19, 0xc9, 0x85, 0x7b, 0x58} }
#define SpatialNavigationService_ContractID "@mozilla.org/spatialnavigation/service"
static NS_METHOD SpatialNavigationServiceRegistration(nsIComponentManager *aCompMgr,
nsIFile *aPath,
const char *registryLocation,
const char *componentType,
const nsModuleComponentInfo *info)
{
nsresult rv;
nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsICategoryManager> catman;
servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID,
NS_GET_IID(nsICategoryManager),
getter_AddRefs(catman));
if (NS_FAILED(rv))
return rv;
char* previous = nsnull;
rv = catman->AddCategoryEntry("xpcom-startup",
"SpatialNavigationService",
SpatialNavigationService_ContractID,
PR_TRUE,
PR_TRUE,
&previous);
if (previous)
nsMemory::Free(previous);
return rv;
}
static NS_METHOD SpatialNavigationServiceUnregistration(nsIComponentManager *aCompMgr,
nsIFile *aPath,
const char *registryLocation,
const nsModuleComponentInfo *info)
{
nsresult rv;
nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsICategoryManager> catman;
servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID,
NS_GET_IID(nsICategoryManager),
getter_AddRefs(catman));
if (NS_FAILED(rv))
return rv;
rv = catman->DeleteCategoryEntry("xpcom-startup",
"SpatialNavigationService",
PR_TRUE);
return rv;
}
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSpatialNavigationService)
static const nsModuleComponentInfo components[] =
{
{ "SpatialNavigationService",
SpatialNavigationService_CID,
SpatialNavigationService_ContractID,
nsSpatialNavigationServiceConstructor,
SpatialNavigationServiceRegistration,
SpatialNavigationServiceUnregistration
}
};
NS_IMPL_NSGETMODULE(SpatialNavigationModule, components)

View File

@@ -0,0 +1,774 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Spatial Navigation
*
* The Initial Developer of the Original Code is
* Douglas F. Turner II <dougt@meer.net>
* Portions created by the Initial Developer are Copyright (C) 2004-2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsSpatialNavigationPrivate.h"
#include "nsIFrameDebug.h"
PRBool is_space(char c)
{
return (c == ' ' || c == '\f' || c == '\n' ||
c == '\r' || c == '\t' || c == '\v');
}
nscoord* lo_parse_coord_list(char *str, PRInt32* value_cnt)
{
char *tptr;
char *n_str;
PRInt32 i, cnt;
PRInt32 *value_list;
/*
* Nothing in an empty list
*/
*value_cnt = 0;
if (!str || *str == '\0')
{
return nsnull;
}
/*
* Skip beginning whitespace, all whitespace is empty list.
*/
n_str = str;
while (is_space(*n_str))
{
n_str++;
}
if (*n_str == '\0')
{
return nsnull;
}
/*
* Make a pass where any two numbers separated by just whitespace
* are given a comma separator. Count entries while passing.
*/
cnt = 0;
while (*n_str != '\0')
{
PRBool has_comma;
/*
* Skip to a separator
*/
tptr = n_str;
while (!is_space(*tptr) && *tptr != ',' && *tptr != '\0')
{
tptr++;
}
n_str = tptr;
/*
* If no more entries, break out here
*/
if (*n_str == '\0')
{
break;
}
/*
* Skip to the end of the separator, noting if we have a
* comma.
*/
has_comma = PR_FALSE;
while (is_space(*tptr) || *tptr == ',')
{
if (*tptr == ',')
{
if (has_comma == PR_FALSE)
{
has_comma = PR_TRUE;
}
else
{
break;
}
}
tptr++;
}
/*
* If this was trailing whitespace we skipped, we are done.
*/
if ((*tptr == '\0')&&(has_comma == PR_FALSE))
{
break;
}
/*
* Else if the separator is all whitespace, and this is not the
* end of the string, add a comma to the separator.
*/
else if (has_comma == PR_FALSE)
{
*n_str = ',';
}
/*
* count the entry skipped.
*/
cnt++;
n_str = tptr;
}
/*
* count the last entry in the list.
*/
cnt++;
/*
* Allocate space for the coordinate array.
*/
value_list = new nscoord[cnt];
if (!value_list)
{
return nsnull;
}
/*
* Second pass to copy integer values into list.
*/
tptr = str;
for (i=0; i<cnt; i++)
{
char *ptr;
ptr = strchr(tptr, ',');
if (ptr)
{
*ptr = '\0';
}
/*
* Strip whitespace in front of number because I don't
* trust atoi to do it on all platforms.
*/
while (is_space(*tptr))
{
tptr++;
}
if (*tptr == '\0')
{
value_list[i] = 0;
}
else
{
value_list[i] = (nscoord) ::atoi(tptr);
}
if (ptr)
{
*ptr = ',';
tptr = ptr + 1;
}
}
*value_cnt = cnt;
return value_list;
}
nsresult createFrameTraversal(PRUint32 type, nsPresContext* presContext,
nsIBidirectionalEnumerator** outTraversal)
{
nsresult result;
if (!presContext)
return NS_ERROR_FAILURE;
nsIPresShell* presShell = presContext->PresShell();
if (!presShell)
return NS_ERROR_FAILURE;
nsIFrame* frame = presShell->GetRootFrame();
if (!frame)
return NS_ERROR_FAILURE;
nsIFrameDebug* fd;
frame->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**) &fd);
if (fd)
fd->List(frame->GetPresContext(), stdout, 0);
nsCOMPtr<nsIBidirectionalEnumerator> frameTraversal;
static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
nsCOMPtr<nsIFrameTraversal> trav(do_CreateInstance(kFrameTraversalCID,&result));
if (NS_FAILED(result))
return result;
result = trav->NewFrameTraversal(getter_AddRefs(frameTraversal),
type,
presContext,
frame);
if (NS_FAILED(result))
return result;
NS_IF_ADDREF(*outTraversal = frameTraversal);
return NS_OK;
}
nsresult getEventTargetFromWindow(nsIDOMWindow* aWindow, nsIDOM3EventTarget** aEventTarget, nsIDOMEventGroup** aSystemGroup)
{
*aEventTarget = nsnull;
nsCOMPtr<nsPIDOMWindow> privateWindow = do_QueryInterface(aWindow);
if (!privateWindow)
return NS_ERROR_UNEXPECTED; // assert
nsIChromeEventHandler *chromeEventHandler = privateWindow->GetChromeEventHandler();
nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(chromeEventHandler));
if (!receiver)
return NS_ERROR_UNEXPECTED; // assert
nsCOMPtr<nsIDOMEventGroup> systemGroup;
receiver->GetSystemEventGroup(getter_AddRefs(systemGroup));
nsCOMPtr<nsIDOM3EventTarget> target(do_QueryInterface(receiver));
if (!target || !systemGroup)
return NS_ERROR_FAILURE;
NS_ADDREF(*aEventTarget = target);
NS_ADDREF(*aSystemGroup = systemGroup);
return NS_OK;
}
void getContentFromFrame(nsIContent* c, nsIContent** outContent)
{
*outContent = nsnull;
nsCOMPtr<nsIContent> result;
nsCOMPtr<nsIDOMDocument> contentDocument;
nsCOMPtr<nsIDOMHTMLFrameElement> domFrameElement = do_QueryInterface(c);
if (domFrameElement) {
domFrameElement->GetContentDocument(getter_AddRefs(contentDocument));
}
else {
nsCOMPtr<nsIDOMHTMLIFrameElement> domIFrameElement = do_QueryInterface(c);
if (domIFrameElement)
domIFrameElement->GetContentDocument(getter_AddRefs(contentDocument));
}
if (contentDocument) {
nsCOMPtr<nsIDOMElement> documentElement;
contentDocument->GetDocumentElement(getter_AddRefs(documentElement));
result = do_QueryInterface(documentElement);
}
NS_IF_ADDREF(*outContent = result);
}
nsresult getFrameForContent(nsIContent* aContent, nsIFrame** aFrame)
{
*aFrame = nsnull;
if (!aContent)
return NS_ERROR_FAILURE;
nsIDocument* doc = aContent->GetDocument();
if (!doc)
return NS_ERROR_FAILURE;
nsIFrame* frame;
nsIPresShell *presShell = doc->GetShellAt(0);
presShell->GetPrimaryFrameFor(aContent, &frame);
if (!frame)
return NS_ERROR_FAILURE;
*aFrame = frame;
return NS_OK;
}
PRBool
isContentOfType(nsIContent* content, const char* type)
{
if (!content)
return PR_FALSE;
nsINodeInfo *nodeInfo = content->GetNodeInfo();
if (nodeInfo)
{
nsIAtom* atom = nodeInfo->NameAtom();
if (atom)
return atom->EqualsUTF8(nsDependentCString(type));
}
return PR_FALSE;
}
PRBool
isArea(nsIContent* content)
{
if (!content || !content->IsContentOfType(nsIContent::eHTML))
return PR_FALSE;
return isContentOfType(content, "area");
}
PRBool
isDocument(nsIFrame* frame)
{
nsIContent* content = frame->GetContent();
if (!content || !content->IsContentOfType(nsIContent::eHTML))
return PR_FALSE;
return isContentOfType(content, "map");
}
PRBool
isMap(nsIFrame* frame)
{
nsIContent* content = frame->GetContent();
if (!content || !content->IsContentOfType(nsIContent::eHTML))
return PR_FALSE;
return isContentOfType(content, "map");
}
PRBool
isTargetable(PRBool focusDocuments, nsIFrame* frame)
{
nsIContent* currentContent = frame->GetContent();
if (!currentContent)
return PR_FALSE;
if (!currentContent->IsContentOfType(nsIContent::eHTML))
return PR_FALSE;
if (isContentOfType(currentContent, "map"))
return PR_TRUE;
if (isContentOfType(currentContent, "a"))
{
// an anchor isn't targetable unless it has a non-null href.
nsCOMPtr<nsIDOMHTMLAnchorElement> anchorElement = do_QueryInterface(currentContent);
nsAutoString uri;
anchorElement->GetHref(uri);
if (uri.IsEmpty()) {
return PR_FALSE;
}
return PR_TRUE;
}
nsCOMPtr<nsIFrameFrame> frameFrame(do_QueryInterface(frame));
if (frameFrame)
return PR_TRUE;
nsCOMPtr<nsIDOMHTMLIFrameElement> iFrameElement = do_QueryInterface(currentContent);
if (iFrameElement)
return PR_TRUE;
if (focusDocuments) {
nsCOMPtr<nsIDOMHTMLHtmlElement> hhElement(do_QueryInterface(currentContent));
if (hhElement)
return PR_TRUE;
}
// need to figure out how to determine if a element is
// either disabled, hidden, or it is inaccessible due to
// its parent being one of these.
PRBool disabled = PR_FALSE;
nsCOMPtr<nsIDOMHTMLSelectElement> selectElement = do_QueryInterface(currentContent);
if (selectElement && NS_SUCCEEDED(selectElement->GetDisabled(&disabled)))
return !disabled;
nsCOMPtr<nsIDOMHTMLOptionElement> optionElement = do_QueryInterface(currentContent);
if (optionElement && NS_SUCCEEDED(optionElement->GetDisabled(&disabled)))
return !disabled;
nsAutoString inputType;
nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(currentContent);
if (inputElement && NS_SUCCEEDED(inputElement->GetDisabled(&disabled)) && NS_SUCCEEDED(inputElement->GetType(inputType)))
return !disabled && (! inputType.EqualsIgnoreCase("hidden"));
return PR_FALSE;
}
nsRect makeRectRelativeToGlobalView(nsIFrame *aFrame)
{
nsRect result;
result.SetRect(0,0,0,0);
nsPoint offset;
if (!aFrame)
return result;
result = aFrame->GetRect();
nsIView* view;
aFrame->GetOffsetFromView(offset, &view);
nsIView* rootView = nsnull;
if (view) {
nsIViewManager* viewManager = view->GetViewManager();
NS_ASSERTION(viewManager, "View must have a viewmanager");
viewManager->GetRootView(rootView);
}
while (view) {
offset += view->GetPosition();
if (view == rootView) {
break;
}
view = view->GetParent();
}
result.MoveTo(offset);
return result;
}
void poly2Rect(int sides, nscoord* coord, nsRect* rect)
{
nscoord x1, x2, y1, y2, xtmp, ytmp;
x1 = x2 = coord[0];
y1 = y2 = coord[1];
for (PRInt32 i = 2; i < sides; i += 2)
{
xtmp = coord[i];
ytmp = coord[i+1];
x1 = x1 < xtmp ? x1 : xtmp;
y1 = y1 < ytmp ? y1 : ytmp;
x2 = x2 > xtmp ? x2 : xtmp;
y2 = y2 > ytmp ? y2 : ytmp;
}
rect->SetRect(x1, y1, x2, y2);
}
void getRectOfAreaElement(nsIFrame* f, nsIDOMHTMLAreaElement* e, nsRect* r)
{
if (!f || !e || !r)
return;
// RECT !!
nsRect frameRect = makeRectRelativeToGlobalView(f);
if (frameRect.width == 0)
frameRect.width = 1;
if (frameRect.height == 0)
frameRect.height = 1;
nsPoint offset;
offset.x = frameRect.x;
offset.y = frameRect.y;
nsAutoString coordstr;
e->GetCoords(coordstr);
NS_ConvertUTF16toUTF8 cp (coordstr);
PRInt32 count;
nscoord* coords = lo_parse_coord_list((char*) cp.get(), &count);
// FIX what about other shapes?
if (count == 4)
{
// x y width height
frameRect.SetRect(coords[0], coords[1], coords[2] - coords[0], coords[3] - coords[1]);
frameRect.x += offset.x;
frameRect.y += offset.y;
}
else if (count >=6)
poly2Rect(count, coords, &frameRect);
else
printf("area count not supported!! %d\n", count);
// find the center of the rect.
frameRect.x = frameRect.x + (frameRect.width / 2) - 1;
frameRect.width = 2;
frameRect.y = frameRect.y + (frameRect.height / 2) - 1;
frameRect.height = 2;
*r = frameRect;
}
// we want to determine if going in the |direction|
// direction from focusedRect will intercept the frameRect
PRBool isRectInDirection(int direction, nsRect& focusedRect, nsRect& frameRect)
{
if (direction == eNavLeft)
{
return (frameRect.x < focusedRect.x);
}
if (direction == eNavRight)
{
return (frameRect.x + frameRect.width > focusedRect.x + focusedRect.width);
}
if (direction == eNavUp)
{
return (frameRect.y < focusedRect.y);
}
if (direction == eNavDown)
{
return (frameRect.y + frameRect.height > focusedRect.y + focusedRect.height);
}
return PR_FALSE;
}
PRInt64 spatialDistance(int direction, nsRect& a, nsRect& b)
{
PRBool inlineNavigation = PR_FALSE;
nsPoint m, n;
if (direction == eNavLeft)
{
// |---|
// |---|
//
// |---| |---|
// |---| |---|
//
// |---|
// |---|
//
if (a.y > b.y + b.height)
{
// the b rect is above a.
m.x = a.x;
m.y = a.y;
n.x = b.x + b.width;
n.y = b.y + b.height;
}
else if (a.y + a.height < b.y)
{
// the b rect is below a.
m.x = a.x;
m.y = a.y + a.height;
n.x = b.x + b.width;
n.y = b.y;
}
else
{
m.x = a.x;
m.y = 0;
n.x = b.x + b.width;
n.y = 0;
// m.x = (a.x + (a.width / 2));
// m.y = (a.y + (a.height / 2));
// n.x = (b.x + (b.width / 2));
// n.y = (b.y + (b.height / 2));
}
}
else if (direction == eNavRight)
{
// |---|
// |---|
//
// |---| |---|
// |---| |---|
//
// |---|
// |---|
//
if (a.y > b.y + b.height)
{
// the b rect is above a.
m.x = a.x + a.width;
m.y = a.y;
n.x = b.x;
n.y = b.y + b.height;
}
else if (a.y + a.height < b.y)
{
// the b rect is below a.
m.x = a.x + a.width;
m.y = a.y + a.height;
n.x = b.x;
n.y = b.y;
}
else
{
m.x = a.x + a.width;
m.y = 0;
n.x = b.x;
n.y = 0;
// m.x = (a.x + (a.width / 2));
// m.y = (a.y + (a.height / 2));
// n.x = (b.x + (b.width / 2));
// n.y = (b.y + (b.height / 2));
}
}
else if (direction == eNavUp)
{
// |---| |---| |---|
// |---| |---| |---|
//
// |---|
// |---|
//
if (a.x > b.x + b.width)
{
// the b rect is to the left of a.
m.x = a.x;
m.y = a.y;
n.x = b.x + b.width;
n.y = b.y + b.height;
}
else if (a.x + a.width < b.x)
{
// the b rect is to the right of a
m.x = a.x + a.width;
m.y = a.y;
n.x = b.x;
n.y = b.y + b.height;
}
else
{
// both b and a share some common x's.
m.x = 0;
m.y = a.y;
n.x = 0;
n.y = b.y + b.height;
// m.x = (a.x + (a.width / 2));
// m.y = (a.y + (a.height / 2));
// n.x = (b.x + (b.width / 2));
// n.y = (b.y + (b.height / 2));
}
}
else if (direction == eNavDown)
{
// |---|
// |---|
//
// |---| |---| |---|
// |---| |---| |---|
//
if (a.x > b.x + b.width)
{
// the b rect is to the left of a.
m.x = a.x;
m.y = a.y + a.height;
n.x = b.x + b.width;
n.y = b.y;
}
else if (a.x + a.width < b.x)
{
// the b rect is to the right of a
m.x = a.x + a.width;
m.y = a.y + a.height;
n.x = b.x;
n.y = b.y;
}
else
{
// both b and a share some common x's.
m.x = 0;
m.y = a.y + a.height;
n.x = 0;
n.y = b.y;
// m.x = (a.x + (a.width / 2));
// m.y = (a.y + (a.height / 2));
// n.x = (b.x + (b.width / 2));
// n.y = (b.y + (b.height / 2));
}
}
// a is always the currently focused rect.
nsRect scopedRect = a;
scopedRect.Inflate(gRectFudge, gRectFudge);
if (direction == eNavLeft)
{
scopedRect.x = 0;
scopedRect.width = nscoord_MAX;
if (scopedRect.Intersects(b))
inlineNavigation = PR_TRUE;
}
else if (direction == eNavRight)
{
scopedRect.width = nscoord_MAX;
if (scopedRect.Intersects(b))
inlineNavigation = PR_TRUE;
}
else if (direction == eNavUp)
{
scopedRect.y = 0;
scopedRect.height = nscoord_MAX;
if (scopedRect.Intersects(b))
inlineNavigation = PR_TRUE;
}
else if (direction == eNavDown)
{
scopedRect.height = nscoord_MAX;
if (scopedRect.Intersects(b))
inlineNavigation = PR_TRUE;
}
PRInt64 d = ((m.x-n.x)*(m.x-n.x)) + ((m.y-n.y)*(m.y-n.y));
if(d<0)
d=d*(-1);
if (inlineNavigation)
d /= gDirectionalBias;
return d;
}
void GetWindowFromDocument(nsIDOMDocument* aDocument, nsIDOMWindowInternal** aWindow)
{
nsCOMPtr<nsIDOMDocumentView> docview = do_QueryInterface(aDocument);
nsCOMPtr<nsIDOMAbstractView> view;
docview->GetDefaultView(getter_AddRefs(view));
if (!view) return;
nsCOMPtr<nsIDOMWindowInternal> window = do_QueryInterface(view);
NS_IF_ADDREF(*aWindow = window);
}

View File

@@ -0,0 +1,272 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type"
content="text/html; charset=ISO-8859-1">
<title>Spatial Navigation Test Cases</title>
</head>
<body>
<div style="margin-left: 40px; text-align: center;">
<h1 style="text-align: left;"><a name="mozTocId276802" class="mozTocH1"></a>Spatial
Navigation Fun</h1>
<h2 style="text-align: left;"><br>
</h2>
<div style="text-align: left;"><br>
</div>
<br>
<br>
<h2 style="text-align: left;"><a name="mozTocId192805" class="mozTocH2"></a>3x3
Centered Table Test</h2>
</div>
<table
style="text-align: left; width: 100%; margin-left: auto; margin-right: auto;"
border="1" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="vertical-align: top; text-align: center;"><a href="a">test</a></td>
<td style="vertical-align: top; text-align: center;"><a href="a">test</a></td>
<td style="vertical-align: top; text-align: center;"><a href="a">test</a></td>
</tr>
<tr>
<td style="vertical-align: top; text-align: center;"><a href="a">test</a></td>
<td style="vertical-align: top; text-align: center;"><a href="a">test</a></td>
<td style="vertical-align: top; text-align: center;"><a href="a">test</a></td>
</tr>
<tr>
<td style="vertical-align: top; text-align: center;"><a href="a">test</a></td>
<td style="vertical-align: top; text-align: center;"><a href="a">test</a></td>
<td style="vertical-align: top; text-align: center;"><a href="a">test</a></td>
</tr>
</tbody>
</table>
<div style="margin-left: 40px; text-align: center;"><br>
<br>
<div style="text-align: left;">
<h2><a name="mozTocId557796" class="mozTocH2"></a>Vertical Sine Test</h2>
<br>
</div>
<div style="text-align: left;"><a href="a">test<br>
</a>
<div style="margin-left: 40px;"><a href="a">test<br>
</a></div>
<div style="margin-left: 80px;"><a href="a">test<br>
</a></div>
<div style="margin-left: 40px;"><a href="a">test<br>
</a></div>
<a href="a">test<br>
</a>
<div style="margin-left: 40px;"><a href="a">test<br>
</a></div>
<div style="margin-left: 80px;"><a href="a">test<br>
</a></div>
<div style="margin-left: 40px;"><a href="a">test<br>
</a></div>
<a href="a">test<br>
</a>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; <a href="a">test<br>
</a><br>
<br>
<br>
<h2><a name="mozTocId261391" class="mozTocH2"></a>Increasing sentence
length</h2>
<br>
<a href="a">H</a><br>
<a href="p">Ho<br>
</a><a href="p">How<br>
</a><a href="p">How <br>
</a><a href="p">How N</a><br>
<a href="p">How No</a><br>
<a href="p">How Now</a><br>
<a href="p">How Now </a><br>
<a href="p">How Now B</a><br>
<a href="p">How Now Br</a><br>
<a href="p">How Now Bro</a><br>
<a href="p">How Now Brow</a><br>
<a href="p">How Now Brown</a><br>
<a href="p">How Now Brown </a><br>
<a href="p">How Now Brown C</a><br>
<a href="p">How Now Brown Co</a><br>
<a href="p">How Now Brown Cow</a><br>
<br>
<h2><a name="mozTocId100946" class="mozTocH2"></a>Split sentence<br>
</h2>
<br>
<a href="p">H</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
<a href="p">ow Now Brown Cow</a><br>
<a href="p">Ho</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; <a href="p">w
Now Brown Cow</a><br>
<a href="p">How</a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="p">Now Brown Cow</a><br>
<a href="p">How N</a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp; <a
href="p">ow Brown Cow</a><br>
<a href="p">How No</a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;
&nbsp; &nbsp; &nbsp;&nbsp; <a href="p">w Brown Cow</a><br>
<a href="p">How Now </a>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; <a href="p">Brown Cow</a><br>
<a href="p">How Now B</a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; <a href="p">rown Cow</a><br>
<a href="p">How Now Br</a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; <a href="p">own Cow</a><br>
<a href="p">How Now Bro</a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; <a href="p">wn Cow</a><br>
<a href="p">How Now Brow</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a href="p">n Cow</a><br>
<a href="p">How Now Brown</a> &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; <a href="p">Cow</a><br>
<a href="p">How Now Brown C</a> &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; <a href="p">ow</a><br>
<a href="p">How Now Brown Co</a> &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; <a href="p">w</a><br>
<a href="p">How Now Brown Cow</a><br>
<br>
<br>
<h2>Line Wrap Test</h2>
<br>
<table style="text-align: left; width: 393px; height: 72px;" border="1"
cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="vertical-align: top;"><span class="huge"><a href="a">Which
of the following constanst do you like the most, one is g, one is pi,
and the other is e. </a><br>
</span></td>
<td style="vertical-align: top;"><a href="a">3.14</a><br>
<a href="a">2.71</a><br>
<a href="a">6.67</a><br>
</td>
</tr>
</tbody>
</table>
<br>
<h2><a name="mozTocId625391" class="mozTocH2"></a>Javascript Hover Test</h2>
When going from any link to the following link, you should NOT get an
alert dialog.&nbsp; However, if you mouse over this link, you should
see a dialog.<br>
<br>
<a href="a" onmouseover='alert("onMouseOver")'
onmouseout='alert("onMouseOut")'>Test</a><br>
<br>
<h2><a name="mozTocId272030" class="mozTocH2"></a>Overlapped Anchors</h2>
<br>
<table style="text-align: left; width: 100%;" border="1" cellpadding="2"
cellspacing="2">
<tbody>
<tr>
<td style="vertical-align: top;">
<div style="text-align: left;"><a href="a"><img
src="mozilla-star.png"
title="" alt="" style="border: 0px solid ; width: 57px; height: 57px;"></a><a
href="a"><img
src="mozilla-star.png"
title="" alt="" style="border: 0px solid ; width: 57px; height: 57px;"
hspace="0"></a><br>
</div>
<br>
<br>
<br>
<br>
</td>
</tr>
</tbody>
</table>
<br>
<br>
<h2><a name="mozTocId16012" class="mozTocH2"></a>Area Tag (Rect)<br>
</h2>
<br>
<br>
<img src="mozilla-star.png" title="" alt=""
style="width: 513px; height: 513px;"><br>
<br>
<h2><a name="mozTocId922752" class="mozTocH2"></a>Area Tag (Circle)<br>
</h2>
<br>
<br>
<img
src="mozilla-star.png"
title="" alt="" style="width: 513px; height: 513px;"><br>
<br>
<h2><a name="mozTocId216319" class="mozTocH2"></a>Area Tag (Polygon)<br>
</h2>
<br>
<br>
<img
src="mozilla-star.png"
title="" alt="" style="height: 513px; width: 513px;"><br>
<br>
<br>
<a href="http://www.visa.com/globalgateway/gg_map.html">A
nice poly test case</a>
<br>
<h2>FrameSets</h2>
<br>
<frameset cols="25%,25%,*">
<frame src="links.html" />
<frame src="links.html" />
<frame src="links.html" />
</frameset>
<br>
<br>
<h2>IFrames</h2>
<br>
<iframe src="links.html"></iframe> <br>
<br>
<br>
<h2>DIVs</h2>
<br>
<div id=v>
<a href="a">a</a>
<div id="Div1">
<a href="a">a</a>
</div>
<a href="a">a</a>
</div>
<br>
<br>
</div>
</div>
<a href="last">last</a>
<p>
<p> A select example
<FORM ACTION="SelectExample" METHOD="POST">
<SELECT NAME="parameter" SIZE=1>
<OPTION VALUE="value1" SELECTED> first setting </OPTION>
<OPTION VALUE="value2"> second setting </OPTION>
</SELECT>
<INPUT TYPE="Submit" NAME="Submit" VALUE="Evaluate">
</FORM>
<p>
<p> A option example
<FORM ACTION="OptionExample" METHOD="POST">
<SELECT NAME="a" SIZE=10>
<OPTION>a
<OPTION>b
<OPTION>c
<OPTION>d
<OPTION>e
<OPTION>f
<OPTION>g
</SELECT>
<p>
</body>
</html>

View File

@@ -0,0 +1,2 @@
<iframe src="links.html"></iframe> <br>
<a href="a">a</a>

View File

@@ -0,0 +1,9 @@
<html>
<head></head>
<body>
<p>
<a href="a">a</a>
<a href="a">a</a>
<a href="a">a</a>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,107 @@
///////////////////////////////////////////////////////////
// snav.enabled
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// snav.ignoreTextFields
///////////////////////////////////////////////////////////
This preference when enabled will ensure that text fields
and inputs retain focus even if spatial navigation was
requested.
Default: TRUE
///////////////////////////////////////////////////////////
// snav.directionalBias
///////////////////////////////////////////////////////////
When calculating distances between elements on the screen,
elements may be given a bias if the elements are in the
direction of navigation. The bias is a given by a fraction
such that:
bias distance = true distance / directional bias
DEFAULT: 3
///////////////////////////////////////////////////////////
// snav.disableJS
///////////////////////////////////////////////////////////
Disable onFocus event that an element may recieve during
spatial navigation. On some pages we have found that the
page decides to move the focus as if the targeted content
was clicked. This may lead to an undesirable behavior.
DEFAULT: TRUE
///////////////////////////////////////////////////////////
// snav.rectFudge
///////////////////////////////////////////////////////////
To reduce the chance that a element overlaps with another
element, we reduce the elements height and width by this
value.
DEFAULT: 20
///////////////////////////////////////////////////////////
// snav.keyCode.left
///////////////////////////////////////////////////////////
This preference is the key code which corresponds to the
left direction.
DEFAULT: DOM_VK_LEFT
SEE: nsIDOMKeyEvent
///////////////////////////////////////////////////////////
// snav.keyCode.right
///////////////////////////////////////////////////////////
This preference is the key code which corresponds to the
right direction.
DEFAULT: DOM_VK_RIGHT
SEE: nsIDOMKeyEvent
///////////////////////////////////////////////////////////
// snav.keyCode.up
///////////////////////////////////////////////////////////
This preference is the key code which corresponds to the
up direction.
DEFAULT: DOM_VK_UP
SEE: nsIDOMKeyEvent
///////////////////////////////////////////////////////////
// snav.keyCode.down
///////////////////////////////////////////////////////////
This preference is the key code which corresponds to the
down direction.
DEFAULT: DOM_VK_DOWN
SEE: nsIDOMKeyEvent
///////////////////////////////////////////////////////////
// snav.keyCode.modifier
///////////////////////////////////////////////////////////
This preference is the key code which corresponds to the
required modifier keys. These values are given as follows:
NONE = 0
SHIFT = 0x00100000
CONTROL = 0x00001100
ALT = 0x00000012
DEFAULT: ALT | SHIFT