Files
Mozilla/mozilla/accessible/src/base/nsAccessible.cpp
aaronl%netscape.com 6f8a6caab0 Some more accessibility changes that didn't make it in
git-svn-id: svn://10.0.0.236/branches/MOZILLA_0_9_2_BRANCH@101628 18797224-902f-48f8-a5cc-f745e15eee43
2001-08-22 05:09:19 +00:00

1605 lines
44 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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 mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsAccessible.h"
#include "nsIAccessibilityService.h"
#include "nsCOMPtr.h"
#include "nsIDocument.h"
#include "nsIPresShell.h"
#include "nsIPresContext.h"
#include "nsIContent.h"
#include "nsIFrame.h"
#include "nsIScrollableView.h"
#include "nsRootAccessible.h"
#include "nsIScriptGlobalObject.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMElement.h"
#include "nsIEventStateManager.h"
#include "nsHTMLFormControlAccessible.h"
#include "nsHTMLLinkAccessible.h"
#include "nsIDOMHTMLAreaElement.h"
#include "nsIServiceManager.h"
#include "nsIStringBundle.h"
#include "nsXPIDLString.h"
#include "nsIDOMComment.h"
#include "nsITextContent.h"
#include "nsIEventStateManager.h"
#include "nsIDOMHTMLImageElement.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIDOMHTMLBRElement.h"
#include "nsIAtom.h"
#include "nsHTMLAtoms.h"
#include "nsLayoutAtoms.h"
#include "nsINameSpaceManager.h"
#include "nsGUIEvent.h"
#include "nsILink.h"
#include "nsIStyleContext.h"
#include "nsStyleConsts.h"
#include "nsReadableUtils.h"
// IFrame Helpers
#include "nsIDocShell.h"
#include "nsIWebShell.h"
#include "nsIScriptGlobalObject.h"
#include "nsIDOMHTMLIFrameElement.h"
#include "nsIDOMHTMLFrameElement.h"
#include "nsIDocShellTreeItem.h"
#ifdef NS_DEBUG
#include "nsIFrameDebug.h"
#include "nsIDOMCharacterData.h"
#endif
//#define DEBUG_LEAKS
#ifdef DEBUG_LEAKS
static gnsAccessibles = 0;
#endif
static NS_DEFINE_CID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
/** This class is used to walk the DOM tree. It skips
* everything but nodes that either implement nsIAccessible
* or have primary frames that implement "GetAccessible"
*/
class nsDOMTreeWalker {
public:
nsDOMTreeWalker(nsIWeakReference* aShell, nsIDOMNode* aContent);
PRBool GetNextSibling();
PRBool GetPreviousSibling();
PRBool GetParent();
PRBool GetFirstChild();
PRBool GetLastChild();
PRBool GetChildBefore(nsIDOMNode* aParent, nsIDOMNode* aChild);
PRInt32 GetCount();
PRBool GetAccessible();
nsCOMPtr<nsIWeakReference> mPresShell;
nsCOMPtr<nsIAccessible> mAccessible;
nsCOMPtr<nsIDOMNode> mDOMNode;
nsCOMPtr<nsIAccessibilityService> mAccService;
};
nsDOMTreeWalker::nsDOMTreeWalker(nsIWeakReference* aPresShell, nsIDOMNode* aNode)
{
mDOMNode = aNode;
mAccessible = nsnull;
mPresShell = aPresShell;
mAccService = do_GetService("@mozilla.org/accessibilityService;1");
}
PRBool nsDOMTreeWalker::GetParent()
{
if (!mDOMNode)
{
mAccessible = nsnull;
return PR_FALSE;
}
// do we already have an accessible? Ask it.
if (mAccessible)
{
nsCOMPtr<nsIAccessible> acc;
nsresult rv = mAccessible->GetAccParent(getter_AddRefs(acc));
if (NS_SUCCEEDED(rv) && acc) {
mAccessible = acc;
acc->AccGetDOMNode(getter_AddRefs(mDOMNode));
return PR_TRUE;
}
}
nsCOMPtr<nsIDOMNode> parent;
mDOMNode->GetParentNode(getter_AddRefs(parent));
// if no parent then we hit the root
// we want to return the accessible outside of us. So walk out of
// the document if we can
if (!parent) {
nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mPresShell));
if (presShell) {
nsCOMPtr<nsIPresShell> parentPresShell;
nsCOMPtr<nsIContent> content;
if (NS_SUCCEEDED(nsAccessible::GetParentPresShellAndContent(presShell,
getter_AddRefs(parentPresShell),
getter_AddRefs(content)))) {
nsIFrame* frame;
parentPresShell->GetPrimaryFrameFor(content, &frame);
if (frame) {
nsCOMPtr<nsIAccessible> accessible;
frame->GetAccessible(getter_AddRefs(accessible));
if (!accessible)
accessible = do_QueryInterface(content);
if (accessible) {
nsCOMPtr<nsIWeakReference> wr = do_GetWeakReference(parentPresShell);
accessible->AccGetDOMNode(getter_AddRefs(mDOMNode));
mAccessible = accessible;
mPresShell = wr;
return PR_TRUE;
}
}
}
mAccessible = new nsRootAccessible(mPresShell);
mAccessible->AccGetDOMNode(getter_AddRefs(mDOMNode));
return PR_TRUE;
}
mAccessible = nsnull;
mDOMNode = nsnull;
return PR_FALSE;
}
mDOMNode = parent;
if (GetAccessible())
return PR_TRUE;
return GetParent();
}
PRBool nsDOMTreeWalker::GetNextSibling()
{
//printf("Get next\n");
if (!mDOMNode)
{
mAccessible = nsnull;
return PR_FALSE;
}
// do we already have an accessible? Ask it.
if (mAccessible)
{
nsCOMPtr<nsIAccessible> acc;
nsresult rv = mAccessible->GetAccNextSibling(getter_AddRefs(acc));
if (NS_SUCCEEDED(rv) && acc) {
mAccessible = acc;
acc->AccGetDOMNode(getter_AddRefs(mDOMNode));
return PR_TRUE;
}
}
// get next sibling
nsCOMPtr<nsIDOMNode> next;
mDOMNode->GetNextSibling(getter_AddRefs(next));
// if failed
if (!next)
{
// do we already have an accessible? Ask it.
if (mAccessible)
{
nsCOMPtr<nsIAccessible> acc;
nsresult rv = mAccessible->GetAccParent(getter_AddRefs(acc));
// if there is a parent then this is the last child.
if (NS_SUCCEEDED(rv)) {
mAccessible = nsnull;
mDOMNode = nsnull;
return PR_FALSE;
}
}
// if parent has content
nsCOMPtr<nsIDOMNode> parent;
mDOMNode->GetParentNode(getter_AddRefs(parent));
// if no parent fail
if (!parent) {
mAccessible = nsnull;
mDOMNode = nsnull;
return PR_FALSE;
}
// fail if we reach a parent that is accessible
mDOMNode = parent;
if (GetAccessible())
{
// fail
mAccessible = nsnull;
mDOMNode = nsnull;
return PR_FALSE;
} else {
// next on parent
mDOMNode = parent;
return GetNextSibling();
}
}
// if next has content
mDOMNode = next;
if (GetAccessible())
return PR_TRUE;
// if next doesn't have node
// call first on next
mDOMNode = next;
if (GetFirstChild())
return PR_TRUE;
// call next on next
mDOMNode = next;
return GetNextSibling();
}
PRBool nsDOMTreeWalker::GetFirstChild()
{
if (!mDOMNode)
{
mAccessible = nsnull;
return PR_FALSE;
}
// do we already have an accessible? Ask it.
if (mAccessible)
{
nsCOMPtr<nsIAccessible> acc;
nsresult rv = mAccessible->GetAccFirstChild(getter_AddRefs(acc));
if (NS_SUCCEEDED(rv) && acc) {
mAccessible = acc;
acc->AccGetDOMNode(getter_AddRefs(mDOMNode));
return PR_TRUE;
}
}
// get first child
nsCOMPtr<nsIDOMNode> child;
mDOMNode->GetFirstChild(getter_AddRefs(child));
while(child)
{
mDOMNode = child;
// if the child has a content node done
if (GetAccessible())
return PR_TRUE;
else if (GetFirstChild()) // otherwise try first child
return PR_TRUE;
// get next sibling
nsCOMPtr<nsIDOMNode> next;
child->GetNextSibling(getter_AddRefs(next));
child = next;
}
// fail
mAccessible = nsnull;
mDOMNode = nsnull;
return PR_FALSE;
}
PRBool nsDOMTreeWalker::GetChildBefore(nsIDOMNode* aParent, nsIDOMNode* aChild)
{
mDOMNode = aParent;
if (!mDOMNode)
{
mAccessible = nsnull;
return PR_FALSE;
}
GetFirstChild();
// if the child is not us
if (mDOMNode == aChild) {
mAccessible = nsnull;
mDOMNode = nsnull;
return PR_FALSE;
}
nsCOMPtr<nsIDOMNode> prev(mDOMNode);
nsCOMPtr<nsIAccessible> prevAccessible(mAccessible);
while(mDOMNode)
{
GetNextSibling();
if (mDOMNode == aChild)
break;
prev = mDOMNode;
prevAccessible = mAccessible;
}
mAccessible = prevAccessible;
mDOMNode = prev;
return PR_TRUE;
}
PRBool nsDOMTreeWalker::GetPreviousSibling()
{
nsCOMPtr<nsIDOMNode> child(mDOMNode);
GetParent();
return GetChildBefore(mDOMNode, child);
}
PRBool nsDOMTreeWalker::GetLastChild()
{
return GetChildBefore(mDOMNode, nsnull);
}
PRInt32 nsDOMTreeWalker::GetCount()
{
nsCOMPtr<nsIDOMNode> node(mDOMNode);
nsCOMPtr<nsIAccessible> a(mAccessible);
GetFirstChild();
PRInt32 count = 0;
while(mDOMNode)
{
count++;
GetNextSibling();
}
mDOMNode = node;
mAccessible = a;
return count;
}
/**
* If the DOM node's frame has and accessible or the DOMNode
* itself implements nsIAccessible return it.
*/
PRBool nsDOMTreeWalker::GetAccessible()
{
mAccessible = nsnull;
return (mAccService &&
NS_SUCCEEDED(mAccService->GetAccessibleFor(mDOMNode, getter_AddRefs(mAccessible))) &&
mAccessible);
}
/*
* Class nsAccessible
*/
//-------------------------`----------------------------
// construction
//-----------------------------------------------------
nsAccessible::nsAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell)
{
NS_INIT_REFCNT();
// get frame and node
mDOMNode = aNode;
mPresShell = aShell;
nsCOMPtr<nsIDocument> document;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (content)
content->GetDocument(*getter_AddRefs(document));
if (document) {
nsCOMPtr<nsIScriptGlobalObject> ourGlobal;
document->GetScriptGlobalObject(getter_AddRefs(ourGlobal));
nsCOMPtr<nsPIDOMWindow> ourWindow(do_QueryInterface(ourGlobal));
if(ourWindow)
ourWindow->GetRootFocusController(getter_AddRefs(mFocusController));
}
#ifdef NS_DEBUG_X
{
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(aShell));
printf(">>> %p Created Acc - Con: %p Acc: %p PS: %p",
(nsIAccessible*)this, aContent, aAccessible, shell.get());
if (shell && aContent != nsnull) {
nsIFrame* frame;
shell->GetPrimaryFrameFor(aContent, &frame);
char * name;
if (GetNameForFrame(frame, &name)) {
printf(" Name:[%s]", name);
nsMemory::Free(name);
}
}
printf("\n");
}
#endif
#ifdef DEBUG_LEAKS
printf("nsAccessibles=%d\n", ++gnsAccessibles);
#endif
}
//-----------------------------------------------------
// destruction
//-----------------------------------------------------
nsAccessible::~nsAccessible()
{
#ifdef DEBUG_LEAKS
printf("nsAccessibles=%d\n", --gnsAccessibles);
#endif
}
NS_IMETHODIMP nsAccessible::GetAccName(nsAWritableString& _retval)
{
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mDOMNode));
if (elt)
return elt->GetAttribute(NS_LITERAL_STRING("title"), _retval);
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsAccessible::GetAccParent(nsIAccessible ** aAccParent)
{
nsCOMPtr<nsIPresContext> context;
GetPresContext(context);
nsDOMTreeWalker walker(mPresShell, mDOMNode);
if (walker.GetParent()) {
*aAccParent = walker.mAccessible;
NS_ADDREF(*aAccParent);
return NS_OK;
}
*aAccParent = nsnull;
return NS_OK;
}
/* readonly attribute nsIAccessible accNextSibling; */
NS_IMETHODIMP nsAccessible::GetAccNextSibling(nsIAccessible * *aAccNextSibling)
{
nsDOMTreeWalker walker(mPresShell, mDOMNode);
walker.GetNextSibling();
if (walker.mAccessible && walker.mDOMNode)
{
*aAccNextSibling = walker.mAccessible;
NS_ADDREF(*aAccNextSibling);
return NS_OK;
}
*aAccNextSibling = nsnull;
return NS_OK;
}
/* readonly attribute nsIAccessible accPreviousSibling; */
NS_IMETHODIMP nsAccessible::GetAccPreviousSibling(nsIAccessible * *aAccPreviousSibling)
{
// failed? Lets do some default behavior
nsDOMTreeWalker walker(mPresShell, mDOMNode);
walker.GetPreviousSibling();
if (walker.mAccessible && walker.mDOMNode)
{
*aAccPreviousSibling = walker.mAccessible;
NS_ADDREF(*aAccPreviousSibling);
return NS_OK;
}
*aAccPreviousSibling = nsnull;
return NS_OK;
}
/* readonly attribute nsIAccessible accFirstChild; */
NS_IMETHODIMP nsAccessible::GetAccFirstChild(nsIAccessible * *aAccFirstChild)
{
nsDOMTreeWalker walker(mPresShell, mDOMNode);
walker.GetFirstChild();
if (walker.mAccessible && walker.mDOMNode)
{
*aAccFirstChild = walker.mAccessible;
NS_ADDREF(*aAccFirstChild);
return NS_OK;
}
*aAccFirstChild = nsnull;
return NS_OK;
}
/* readonly attribute nsIAccessible accFirstChild; */
NS_IMETHODIMP nsAccessible::GetAccLastChild(nsIAccessible * *aAccLastChild)
{
nsDOMTreeWalker walker(mPresShell, mDOMNode);
walker.GetLastChild();
if (walker.mAccessible && walker.mDOMNode)
{
*aAccLastChild = walker.mAccessible;
NS_ADDREF(*aAccLastChild);
return NS_OK;
}
*aAccLastChild = nsnull;
return NS_OK;
}
/* readonly attribute long accChildCount; */
NS_IMETHODIMP nsAccessible::GetAccChildCount(PRInt32 *aAccChildCount)
{
nsDOMTreeWalker walker(mPresShell, mDOMNode);
*aAccChildCount = walker.GetCount();
return NS_OK;
}
nsresult nsAccessible::GetTranslatedString(PRUnichar *aKey, nsAWritableString *aStringOut)
{
static nsCOMPtr<nsIStringBundle> stringBundle;
static PRBool firstTime = PR_TRUE;
if (firstTime) {
firstTime = PR_FALSE;
nsresult rv;
nsCOMPtr<nsIStringBundleService> stringBundleService =
do_GetService(kStringBundleServiceCID, &rv);
// nsCOMPtr<nsIStringBundleService> stringBundleService(do_GetService(kStringBundleServiceCID, &rv));
if (!stringBundleService) {
NS_WARNING("ERROR: Failed to get StringBundle Service instance.\n");
return NS_ERROR_FAILURE;
}
stringBundleService->CreateBundle(ACCESSIBLE_BUNDLE_URL, getter_AddRefs(stringBundle));
}
nsXPIDLString xsValue;
if (!stringBundle ||
NS_FAILED(stringBundle->GetStringFromName(aKey, getter_Copies(xsValue))))
return NS_ERROR_FAILURE;
aStringOut->Assign(xsValue);
return NS_OK;
}
/* readonly attribute wstring accState; */
NS_IMETHODIMP nsAccessible::GetAccState(PRUint32 *aAccState)
{
nsresult rv = NS_OK;
*aAccState = 0;
nsCOMPtr<nsIDOMElement> currElement(do_QueryInterface(mDOMNode));
if (currElement) {
*aAccState |= STATE_FOCUSABLE;
if (mFocusController) {
nsCOMPtr<nsIDOMElement> focusedElement;
rv = mFocusController->GetFocusedElement(getter_AddRefs(focusedElement));
if (NS_SUCCEEDED(rv) && focusedElement == currElement)
*aAccState |= STATE_FOCUSED;
}
}
return rv;
}
/* readonly attribute boolean accFocused; */
NS_IMETHODIMP nsAccessible::GetAccFocused(nsIAccessible * *aAccFocused)
{
nsCOMPtr<nsIDOMElement> focusedElement;
if (mFocusController) {
mFocusController->GetFocusedElement(getter_AddRefs(focusedElement));
}
nsIFrame *frame = nsnull;
if (focusedElement) {
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mPresShell));
if (!shell) {
*aAccFocused = nsnull;
return NS_OK;
}
nsCOMPtr<nsIContent> content(do_QueryInterface(focusedElement));
if (shell && content)
shell->GetPrimaryFrameFor(content, &frame);
}
if (frame) {
nsCOMPtr<nsIAccessible> acc(do_QueryInterface(frame));
if (acc) {
*aAccFocused = acc;
NS_ADDREF(*aAccFocused);
return NS_OK;
}
}
*aAccFocused = nsnull;
return NS_OK;
}
/* nsIAccessible accGetChildAt (in long x, in long y); */
NS_IMETHODIMP nsAccessible::AccGetAt(PRInt32 tx, PRInt32 ty, nsIAccessible **_retval)
{
PRInt32 x,y,w,h;
AccGetBounds(&x,&y,&w,&h);
if (tx > x && tx < x + w && ty > y && ty < y + h)
{
nsCOMPtr<nsIAccessible> child;
nsCOMPtr<nsIAccessible> next;
GetAccFirstChild(getter_AddRefs(child));
PRInt32 cx,cy,cw,ch;
while(child) {
child->AccGetBounds(&cx,&cy,&cw,&ch);
if (tx > cx && tx < cx + cw && ty > cy && ty < cy + ch)
{
*_retval = child;
NS_ADDREF(*_retval);
return NS_OK;
}
child->GetAccNextSibling(getter_AddRefs(next));
child = next;
}
*_retval = this;
NS_ADDREF(this);
return NS_OK;
}
*_retval = nsnull;
return NS_OK;
}
NS_IMETHODIMP nsAccessible::AccGetDOMNode(nsIDOMNode **_retval)
{
*_retval = mDOMNode;
NS_IF_ADDREF(*_retval);
return NS_OK;
}
nsresult nsAccessible::GetDocShellFromPS(nsIPresShell* aPresShell, nsIDocShell** aDocShell)
{
*aDocShell = nsnull;
if (aPresShell) {
nsCOMPtr<nsIDocument> doc;
aPresShell->GetDocument(getter_AddRefs(doc));
if (doc) {
nsCOMPtr<nsIScriptGlobalObject> scriptObj;
doc->GetScriptGlobalObject(getter_AddRefs(scriptObj));
if (scriptObj) {
scriptObj->GetDocShell(aDocShell);
return *aDocShell != nsnull?NS_OK:NS_ERROR_FAILURE;
}
}
}
return NS_ERROR_FAILURE;
}
//-------------------------------------------------------
// This gets ref counted copies of the PresShell, PresContext,
// and Root Content for a given nsIDocShell
nsresult
nsAccessible::GetDocShellObjects(nsIDocShell* aDocShell,
nsIPresShell** aPresShell,
nsIPresContext** aPresContext,
nsIContent** aContent)
{
NS_ENSURE_ARG_POINTER(aDocShell);
NS_ENSURE_ARG_POINTER(aPresShell);
NS_ENSURE_ARG_POINTER(aPresContext);
NS_ENSURE_ARG_POINTER(aContent);
aDocShell->GetPresShell(aPresShell); // this addrefs
if (*aPresShell == nsnull) return NS_ERROR_FAILURE;
aDocShell->GetPresContext(aPresContext); // this addrefs
if (*aPresContext == nsnull) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDocument> doc;
(*aPresShell)->GetDocument(getter_AddRefs(doc));
if (!doc) return NS_ERROR_FAILURE;
return doc->GetRootContent(aContent); // this addrefs
}
//-------------------------------------------------------
//
nsresult
nsAccessible::GetDocShells(nsIPresShell* aPresShell,
nsIDocShell** aDocShell,
nsIDocShell** aParentDocShell)
{
NS_ENSURE_ARG_POINTER(aPresShell);
NS_ENSURE_ARG_POINTER(aDocShell);
NS_ENSURE_ARG_POINTER(aParentDocShell);
*aDocShell = nsnull;
// Start by finding our PresShell and from that
// we get our nsIDocShell in order to walk the DocShell tree
if (NS_SUCCEEDED(GetDocShellFromPS(aPresShell, aDocShell))) {
// Now that we have the DocShell QI
// it to a tree item to find it's parent
nsCOMPtr<nsIDocShell> docShell = *aDocShell;
nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(docShell));
if (item) {
nsCOMPtr<nsIDocShellTreeItem> itemParent;
item->GetParent(getter_AddRefs(itemParent));
// QI to get the WebShell for the parent document
nsCOMPtr<nsIDocShell> pDocShell(do_QueryInterface(itemParent));
if (pDocShell) {
*aParentDocShell = pDocShell.get();
NS_ADDREF(*aParentDocShell);
return NS_OK;
}
}
}
NS_IF_RELEASE(*aDocShell);
return NS_ERROR_FAILURE;
}
//-------------------------------------------------------
//
nsresult
nsAccessible::GetParentPresShellAndContent(nsIPresShell* aPresShell,
nsIPresShell** aParentPresShell,
nsIContent** aSubShellContent)
{
NS_ENSURE_ARG_POINTER(aPresShell);
NS_ENSURE_ARG_POINTER(aParentPresShell);
NS_ENSURE_ARG_POINTER(aSubShellContent);
*aParentPresShell = nsnull;
*aSubShellContent = nsnull;
nsCOMPtr<nsIDocShell> docShell;
nsCOMPtr<nsIDocShell> parentDocShell;
if (NS_FAILED(GetDocShells(aPresShell,
getter_AddRefs(docShell),
getter_AddRefs(parentDocShell)))) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIPresContext> parentPresContext;
nsCOMPtr<nsIContent> parentRootContent;
if (NS_FAILED(GetDocShellObjects(parentDocShell,
aParentPresShell,
getter_AddRefs(parentPresContext),
getter_AddRefs(parentRootContent)))) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIWebShell> webShell(do_QueryInterface(docShell));
if (FindContentForWebShell(*aParentPresShell, parentRootContent,
webShell, aSubShellContent)) {
return NS_OK;
}
return NS_ERROR_FAILURE;
}
PRBool
nsAccessible::FindContentForWebShell(nsIPresShell* aParentPresShell,
nsIContent* aParentContent,
nsIWebShell* aWebShell,
nsIContent** aFoundContent)
{
NS_ASSERTION(aWebShell, "Pointer is null!");
NS_ASSERTION(aParentPresShell, "Pointer is null!");
NS_ASSERTION(aParentContent, "Pointer is null!");
NS_ASSERTION(aFoundContent, "Pointer is null!");
nsCOMPtr<nsIDOMHTMLIFrameElement> iFrame(do_QueryInterface(aParentContent));
nsCOMPtr<nsIDOMHTMLFrameElement> frame(do_QueryInterface(aParentContent));
#ifdef NS_DEBUG_X
{
printf("** FindContent - Content %p",aParentContent);
nsIFrame* frame;
aParentPresShell->GetPrimaryFrameFor(aParentContent, &frame);
if (frame) {
char * name;
GetNameForFrame(frame, &name);
printf(" [%s]", name?name:"<no name>");
if (name) nsMemory::Free(name);
}
printf("\n");
}
#endif
if (iFrame || frame) {
//printf("********* Found IFrame %p\n", aParentContent);
nsCOMPtr<nsISupports> supps;
aParentPresShell->GetSubShellFor(aParentContent, getter_AddRefs(supps));
if (supps) {
nsCOMPtr<nsIWebShell> webShell(do_QueryInterface(supps));
//printf("********* Checking %p == %p (parent)\n", webShell.get(), aWebShell);
if (webShell.get() == aWebShell) {
//printf("********* Found WebShell %p \n", aWebShell);
*aFoundContent = aParentContent;
NS_ADDREF(aParentContent);
return PR_TRUE;
}
}
}
// walk children content
PRInt32 count;
aParentContent->ChildCount(count);
for (PRInt32 i=0;i<count;i++) {
nsIContent* child;
aParentContent->ChildAt(i, child);
if (FindContentForWebShell(aParentPresShell, child, aWebShell, aFoundContent)) {
return PR_TRUE;
}
}
return PR_FALSE;
}
// Calculate a frame's position in screen coordinates
nsresult
nsAccessible::GetAbsoluteFramePosition(nsIPresContext* aPresContext,
nsIFrame *aFrame,
nsRect& aAbsoluteTwipsRect,
nsRect& aAbsolutePixelRect)
{
//XXX: This code needs to take the view's offset into account when calculating
//the absolute coordinate of the frame.
nsresult rv = NS_OK;
aFrame->GetRect(aAbsoluteTwipsRect);
// zero these out,
// because the GetOffsetFromView figures them out
// We're only keeping the height and width in aAbsoluteTwipsRect
aAbsoluteTwipsRect.x = 0;
aAbsoluteTwipsRect.y = 0;
// Get conversions between twips and pixels
float t2p;
float p2t;
aPresContext->GetTwipsToPixels(&t2p);
aPresContext->GetPixelsToTwips(&p2t);
// Add in frame's offset from it it's containing view
nsIView *containingView = nsnull;
nsPoint offset(0,0);
rv = aFrame->GetOffsetFromView(aPresContext, offset, &containingView);
if (containingView == nsnull) {
aFrame->GetView(aPresContext, &containingView);
nsRect r;
aFrame->GetRect(r);
offset.x = r.x;
offset.y = r.y;
}
if (NS_SUCCEEDED(rv) && (nsnull != containingView)) {
aAbsoluteTwipsRect.x += offset.x;
aAbsoluteTwipsRect.y += offset.y;
nsPoint viewOffset;
containingView->GetPosition(&viewOffset.x, &viewOffset.y);
nsIView * parent;
containingView->GetParent(parent);
// if we don't have a parent view then
// check to see if we have a widget and adjust our offset for the widget
if (parent == nsnull) {
nsIWidget * widget;
containingView->GetWidget(widget);
if (nsnull != widget) {
// Add in the absolute offset of the widget.
nsRect absBounds;
nsRect lc;
widget->WidgetToScreen(lc, absBounds);
// Convert widget coordinates to twips
aAbsoluteTwipsRect.x += NSIntPixelsToTwips(absBounds.x, p2t);
aAbsoluteTwipsRect.y += NSIntPixelsToTwips(absBounds.y, p2t);
NS_RELEASE(widget);
}
rv = NS_OK;
} else {
while (nsnull != parent) {
nsPoint po;
parent->GetPosition(&po.x, &po.y);
viewOffset.x += po.x;
viewOffset.y += po.y;
nsIScrollableView * scrollView;
if (NS_OK == containingView->QueryInterface(NS_GET_IID(nsIScrollableView), (void **)&scrollView)) {
nscoord x;
nscoord y;
scrollView->GetScrollPosition(x, y);
viewOffset.x -= x;
viewOffset.y -= y;
}
nsIWidget * widget;
parent->GetWidget(widget);
if (nsnull != widget) {
// Add in the absolute offset of the widget.
nsRect absBounds;
nsRect lc;
widget->WidgetToScreen(lc, absBounds);
// Convert widget coordinates to twips
aAbsoluteTwipsRect.x += NSIntPixelsToTwips(absBounds.x, p2t);
aAbsoluteTwipsRect.y += NSIntPixelsToTwips(absBounds.y, p2t);
NS_RELEASE(widget);
break;
}
parent->GetParent(parent);
}
aAbsoluteTwipsRect.x += viewOffset.x;
aAbsoluteTwipsRect.y += viewOffset.y;
}
}
// convert to pixel coordinates
if (NS_SUCCEEDED(rv)) {
aAbsolutePixelRect.x = NSTwipsToIntPixels(aAbsoluteTwipsRect.x, t2p);
aAbsolutePixelRect.y = NSTwipsToIntPixels(aAbsoluteTwipsRect.y, t2p);
aAbsolutePixelRect.width = NSTwipsToIntPixels(aAbsoluteTwipsRect.width, t2p);
aAbsolutePixelRect.height = NSTwipsToIntPixels(aAbsoluteTwipsRect.height, t2p);
}
return rv;
}
void nsAccessible::GetBounds(nsRect& aTotalBounds, nsIFrame** aBoundingFrame)
{
/*
* This method is used to determine the bounds of a content node.
* Because HTML wraps and links are not always rectangular, this
* method uses the following algorithm:
*
* 1) Start with an empty rectangle
* 2) Add the rect for the primary frame from for the DOM node.
* 3) For each next frame at the same depth with the same DOM node, add that rect to total
* 4) If that frame is an inline frame, search deeper at that point in the tree, adding all rects
*/
// Initialization area
*aBoundingFrame = nsnull;
nsIFrame *firstFrame = GetBoundsFrame();
if (!firstFrame)
return;
// Find common relative parent
// This is an ancestor frame that will incompass all frames for this content node.
// We need the relative parent so we can get absolute screen coordinates
nsIFrame *ancestorFrame = firstFrame;
while (ancestorFrame) {
*aBoundingFrame = ancestorFrame;
if (IsCorrectFrameType(ancestorFrame, nsLayoutAtoms::blockFrame) ||
IsCorrectFrameType(ancestorFrame, nsLayoutAtoms::areaFrame)) {
break;
}
ancestorFrame->GetParent(&ancestorFrame);
}
// Get ready for loop
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(presContext);
nsIFrame *iterFrame = firstFrame;
nsCOMPtr<nsIContent> firstContent(do_QueryInterface(mDOMNode));
nsCOMPtr<nsIContent> iterContent(firstContent);
nsRect currFrameBounds;
PRInt32 depth = 0;
// Look only at frames below this depth, or at this depth (if we're still on the content node we started with)
while (iterContent == firstContent || depth > 0) {
// Coordinates will come back relative to parent frame
nsIFrame *parentFrame = iterFrame;
iterFrame->GetRect(currFrameBounds);
// Make this frame's bounds relative to common parent frame
while (parentFrame != *aBoundingFrame) {
parentFrame->GetParent(&parentFrame);
if (!parentFrame)
break;
nsRect parentFrameBounds;
parentFrame->GetRect(parentFrameBounds);
// Add this frame's bounds to our total rectangle
currFrameBounds.x += parentFrameBounds.x;
currFrameBounds.y += parentFrameBounds.y;
}
// Add this frame's bounds to total
aTotalBounds.UnionRect(aTotalBounds, currFrameBounds);
nsIFrame *iterNextFrame = nsnull;
if (IsCorrectFrameType(iterFrame, nsLayoutAtoms::inlineFrame)) {
// Only do deeper bounds search if we're on an inline frame
// Inline frames can contain larger frames inside of them
iterFrame->FirstChild(presContext, nsnull, &iterNextFrame);
}
if (iterNextFrame)
++depth; // Child was found in code above this: We are going deeper in this iteration of the loop
else {
// Use next sibling if it exists, or go back up the tree to get the first next-in-flow or next-sibling
// within our search
while (iterFrame) {
iterFrame->GetNextInFlow(&iterNextFrame);
if (!iterNextFrame)
iterFrame->GetNextSibling(&iterNextFrame);
if (iterNextFrame || --depth < 0)
break;
iterFrame->GetParent(&iterFrame);
}
}
// Get ready for the next round of our loop
iterFrame = iterNextFrame;
if (iterFrame == nsnull)
break;
iterContent = nsnull;
if (depth == 0)
iterFrame->GetContent(getter_AddRefs(iterContent));
}
}
/* void accGetBounds (out long x, out long y, out long width, out long height); */
NS_IMETHODIMP nsAccessible::AccGetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height)
{
// This routine will get the entire rectange for all the frames in this node
// -------------------------------------------------------------------------
// Primary Frame for node
// Another frame, same node <- Example
// Another frame, same node
float t2p;
nsCOMPtr<nsIPresContext> presContext;
GetPresContext(presContext);
if (!presContext)
{
*x = *y = *width = *height = 0;
return NS_ERROR_FAILURE;
}
presContext->GetTwipsToPixels(&t2p); // Get pixels to twips conversion factor
nsRect unionRectTwips;
nsIFrame* aRelativeFrame = nsnull;
GetBounds(unionRectTwips, &aRelativeFrame); // Unions up all primary frames for this node and all siblings after it
*x = NSTwipsToIntPixels(unionRectTwips.x, t2p);
*y = NSTwipsToIntPixels(unionRectTwips.y, t2p);
*width = NSTwipsToIntPixels(unionRectTwips.width, t2p);
*height = NSTwipsToIntPixels(unionRectTwips.height, t2p);
// We have the union of the rectangle, now we need to put it in absolute screen coords
if (presContext) {
nsRect orgRectTwips, frameRectTwips, orgRectPixels;
// Get the offset of this frame in screen coordinates
if (NS_SUCCEEDED(GetAbsoluteFramePosition(presContext, aRelativeFrame, orgRectTwips, orgRectPixels))) {
aRelativeFrame->GetRect(frameRectTwips); // Usually just the primary frame, but can be the choice list frame for an nsSelectAccessible
// Add in the absolute coorinates.
// Since these absolute coordinates are for the primary frame,
// also subtract the difference between our primary frame and our bounds frame
*x += orgRectPixels.x - NSTwipsToIntPixels(frameRectTwips.x, t2p);
*y += orgRectPixels.y - NSTwipsToIntPixels(frameRectTwips.y, t2p);
}
}
return NS_OK;
}
// helpers
/**
* Static
* Helper method to help sub classes make sure they have the proper
* frame when walking the frame tree to get at children and such
*/
PRBool nsAccessible::IsCorrectFrameType( nsIFrame* aFrame, nsIAtom* aAtom )
{
NS_ASSERTION(aFrame != nsnull, "aFrame is null in call to IsCorrectFrameType!");
NS_ASSERTION(aAtom != nsnull, "aAtom is null in call to IsCorrectFrameType!");
nsCOMPtr<nsIAtom> frameType;
aFrame->GetFrameType(getter_AddRefs(frameType));
return (frameType.get() == aAtom);
}
nsIFrame* nsAccessible::GetBoundsFrame()
{
return GetFrame();
}
nsIFrame* nsAccessible::GetFrame()
{
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mPresShell));
if (!shell)
return nsnull;
nsIFrame* frame = nsnull;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
shell->GetPrimaryFrameFor(content, &frame);
return frame;
}
void nsAccessible::GetPresContext(nsCOMPtr<nsIPresContext>& aContext)
{
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mPresShell));
if (shell) {
shell->GetPresContext(getter_AddRefs(aContext));
} else
aContext = nsnull;
}
/* void accRemoveSelection (); */
NS_IMETHODIMP nsAccessible::AccRemoveSelection()
{
nsCOMPtr<nsISelectionController> control(do_QueryReferent(mPresShell));
if (!control) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsISelection> selection;
nsresult rv = control->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIDOMNode> parent;
rv = mDOMNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(rv))
return rv;
rv = selection->Collapse(parent, 0);
if (NS_FAILED(rv))
return rv;
return NS_OK;
}
/* void accTakeSelection (); */
NS_IMETHODIMP nsAccessible::AccTakeSelection()
{
nsCOMPtr<nsISelectionController> control(do_QueryReferent(mPresShell));
if (!control) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsISelection> selection;
nsresult rv = control->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIDOMNode> parent;
rv = mDOMNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(rv))
return rv;
PRInt32 offsetInParent = 0;
nsCOMPtr<nsIDOMNode> child;
rv = parent->GetFirstChild(getter_AddRefs(child));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIDOMNode> next;
while(child)
{
if (child == mDOMNode) {
// Collapse selection to just before desired element,
rv = selection->Collapse(parent, offsetInParent);
if (NS_FAILED(rv))
return rv;
// then extend it to just after
rv = selection->Extend(parent, offsetInParent+1);
return rv;
}
child->GetNextSibling(getter_AddRefs(next));
child = next;
offsetInParent++;
}
// didn't find a child
return NS_ERROR_FAILURE;
}
/* void accTakeFocus (); */
NS_IMETHODIMP nsAccessible::AccTakeFocus()
{
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mPresShell));
if (!shell) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIPresContext> context;
shell->GetPresContext(getter_AddRefs(context));
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
content->SetFocus(context);
return NS_OK;
}
NS_IMETHODIMP nsAccessible::AppendFlatStringFromContentNode(nsIContent *aContent, nsAWritableString *aFlatString)
{
nsCOMPtr<nsITextContent> textContent(do_QueryInterface(aContent));
if (textContent) {
nsCOMPtr<nsIDOMComment> commentNode(do_QueryInterface(aContent));
if (!commentNode) {
PRBool isHTMLBlock = PR_FALSE;
nsIFrame *frame;
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mPresShell));
if (!shell) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIContent> parentContent;
aContent->GetParent(*getter_AddRefs(parentContent));
if (parentContent) {
nsresult rv = shell->GetPrimaryFrameFor(parentContent, &frame);
if (NS_SUCCEEDED(rv)) {
// If this text is inside a block level frame (as opposed to span level), we need to add spaces around that
// block's text, so we don't get words jammed together in final name
// Extra spaces will be trimmed out later
nsCOMPtr<nsIStyleContext> styleContext;
frame->GetStyleContext(getter_AddRefs(styleContext));
if (styleContext) {
const nsStyleDisplay* display = (const nsStyleDisplay*)styleContext->GetStyleData(eStyleStruct_Display);
if (display->IsBlockLevel() || display->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL) {
isHTMLBlock = PR_TRUE;
aFlatString->Append(NS_LITERAL_STRING(" "));
}
}
}
}
nsAutoString text;
textContent->CopyText(text);
if (text.Length()>0)
aFlatString->Append(text);
if (isHTMLBlock)
aFlatString->Append(NS_LITERAL_STRING(" "));
}
return NS_OK;
}
nsCOMPtr<nsIDOMHTMLBRElement> brElement(do_QueryInterface(aContent));
if (brElement) {
aFlatString->Append(NS_LITERAL_STRING(" "));
return NS_OK;
}
nsCOMPtr<nsIDOMHTMLImageElement> imageContent(do_QueryInterface(aContent));
nsCOMPtr<nsIDOMHTMLInputElement> inputContent(do_QueryInterface(aContent));
if (imageContent || inputContent) {
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(aContent));
nsAutoString textEquivalent;
elt->GetAttribute(NS_LITERAL_STRING("alt"), textEquivalent);
if (textEquivalent.IsEmpty())
elt->GetAttribute(NS_LITERAL_STRING("title"), textEquivalent);
if (textEquivalent.IsEmpty())
elt->GetAttribute(NS_LITERAL_STRING("name"), textEquivalent);
if (textEquivalent.IsEmpty())
elt->GetAttribute(NS_LITERAL_STRING("src"), textEquivalent);
if (!textEquivalent.IsEmpty()) {
aFlatString->Append(NS_LITERAL_STRING(" "));
aFlatString->Append(textEquivalent);
aFlatString->Append(NS_LITERAL_STRING(" "));
return NS_OK;
}
}
return NS_OK;
}
NS_IMETHODIMP nsAccessible::AppendFlatStringFromSubtree(nsIContent *aContent, nsAWritableString *aFlatString)
{
// Depth first search for all text nodes that are decendants of content node.
// Append all the text into one flat string
PRInt32 numChildren = 0;
aContent->ChildCount(numChildren);
if (numChildren == 0) {
AppendFlatStringFromContentNode(aContent, aFlatString);
return NS_OK;
}
nsIContent *contentWalker;
PRInt32 index;
for (index = 0; index < numChildren; index++) {
aContent->ChildAt(index, contentWalker);
AppendFlatStringFromSubtree(contentWalker, aFlatString);
}
return NS_OK;
}
// ------- nsHTMLBlockAccessible ------
nsHTMLBlockAccessible::nsHTMLBlockAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):nsAccessible(aNode, aShell)
{
}
/* nsIAccessible accGetAt (in long x, in long y); */
NS_IMETHODIMP nsHTMLBlockAccessible::AccGetAt(PRInt32 tx, PRInt32 ty, nsIAccessible **_retval)
{
// We're going to find the child that contains coordinates (tx,ty)
PRInt32 x,y,w,h;
AccGetBounds(&x,&y,&w,&h); // Get bounds for this accessible
if (tx > x && tx < x + w && ty > y && ty < y + h)
{
// It's within this nsIAccessible, let's drill down
nsCOMPtr<nsIAccessible> child;
nsCOMPtr<nsIAccessible> smallestChild;
PRInt32 smallestArea = -1;
nsCOMPtr<nsIAccessible> next;
GetAccFirstChild(getter_AddRefs(child));
PRInt32 cx,cy,cw,ch; // Child bounds
while(child) {
child->AccGetBounds(&cx,&cy,&cw,&ch);
// ok if there are multiple frames the contain the point
// and they overlap then pick the smallest. We need to do this
// for text frames.
// For example, A point that's in block #2 is also in block #1, but we want to return #2:
//
// [[block #1 is long wrapped text that continues to
// another line]] [[here is a shorter block #2]]
if (tx > cx && tx < cx + cw && ty > cy && ty < cy + ch)
{
if (smallestArea == -1 || cw*ch < smallestArea) {
smallestArea = cw*ch;
smallestChild = child;
}
}
child->GetAccNextSibling(getter_AddRefs(next));
child = next;
}
if (smallestChild != nsnull)
{
*_retval = smallestChild;
NS_ADDREF(*_retval);
return NS_OK;
}
*_retval = this;
NS_ADDREF(this);
return NS_OK;
}
*_retval = nsnull;
return NS_OK;
}
//-------------
// nsLeafFrameAccessible
//-------------
nsLeafAccessible::nsLeafAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
nsAccessible(aNode, aShell)
{
}
/* nsIAccessible getAccFirstChild (); */
NS_IMETHODIMP nsLeafAccessible::GetAccFirstChild(nsIAccessible **_retval)
{
*_retval = nsnull;
return NS_OK;
}
/* nsIAccessible getAccLastChild (); */
NS_IMETHODIMP nsLeafAccessible::GetAccLastChild(nsIAccessible **_retval)
{
*_retval = nsnull;
return NS_OK;
}
/* long getAccChildCount (); */
NS_IMETHODIMP nsLeafAccessible::GetAccChildCount(PRInt32 *_retval)
{
*_retval = 0;
return NS_OK;
}
//----------------
// nsLinkableAccessible
//----------------
nsLinkableAccessible::nsLinkableAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
nsAccessible(aNode, aShell), mIsALinkCached(PR_FALSE), mLinkContent(nsnull), mIsLinkVisited(PR_FALSE)
{
}
/* long GetAccState (); */
NS_IMETHODIMP nsLinkableAccessible::GetAccState(PRUint32 *_retval)
{
nsAccessible::GetAccState(_retval);
*_retval |= STATE_READONLY | STATE_SELECTABLE;
if (IsALink()) {
*_retval |= STATE_LINKED;
if (mIsLinkVisited)
*_retval |= STATE_TRAVERSED;
}
// Get current selection and find out if current node is in it
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mPresShell));
if (!shell) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIPresContext> context;
shell->GetPresContext(getter_AddRefs(context));
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
nsIFrame *frame;
if (content && NS_SUCCEEDED(shell->GetPrimaryFrameFor(content, &frame))) {
nsCOMPtr<nsISelectionController> selCon;
frame->GetSelectionController(context,getter_AddRefs(selCon));
if (selCon) {
nsCOMPtr<nsISelection> domSel;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel));
if (domSel) {
PRBool isSelected = PR_FALSE, isCollapsed = PR_TRUE;
domSel->ContainsNode(mDOMNode, PR_TRUE, &isSelected);
domSel->GetIsCollapsed(&isCollapsed);
if (isSelected && !isCollapsed)
*_retval |=STATE_SELECTED;
}
}
}
// Focused? Do we implement that here or up the chain?
return NS_OK;
}
NS_IMETHODIMP nsLinkableAccessible::GetAccValue(nsAWritableString& _retval)
{
if (IsALink()) {
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mLinkContent));
if (elt)
return elt->GetAttribute(NS_LITERAL_STRING("href"), _retval);
}
return NS_ERROR_FAILURE;
}
/* PRUint8 getAccNumActions (); */
NS_IMETHODIMP nsLinkableAccessible::GetAccNumActions(PRUint8 *_retval)
{
*_retval = 1;
return NS_OK;
}
/* wstring getAccActionName (in PRUint8 index); */
NS_IMETHODIMP nsLinkableAccessible::GetAccActionName(PRUint8 index, nsAWritableString& _retval)
{
// Action 0 (default action): Jump to link
if (index == 0) {
if (IsALink()) {
_retval = NS_LITERAL_STRING("jump");
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
/* void accDoAction (in PRUint8 index); */
NS_IMETHODIMP nsLinkableAccessible::AccDoAction(PRUint8 index)
{
// Action 0 (default action): Jump to link
if (index == 0) {
if (IsALink()) {
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mPresShell));
if (!shell) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIPresContext> presContext;
shell->GetPresContext(getter_AddRefs(presContext));
if (presContext) {
nsMouseEvent linkClickEvent;
linkClickEvent.eventStructType = NS_EVENT;
linkClickEvent.message = NS_MOUSE_LEFT_CLICK;
linkClickEvent.isShift = PR_FALSE;
linkClickEvent.isControl = PR_FALSE;
linkClickEvent.isAlt = PR_FALSE;
linkClickEvent.isMeta = PR_FALSE;
linkClickEvent.clickCount = 0;
linkClickEvent.widget = nsnull;
nsEventStatus eventStatus = nsEventStatus_eIgnore;
mLinkContent->HandleDOMEvent(presContext,
&linkClickEvent,
nsnull,
NS_EVENT_FLAG_INIT,
&eventStatus);
return NS_OK;
}
}
}
return NS_ERROR_FAILURE;
}
PRBool nsLinkableAccessible::IsALink()
{
if (mIsALinkCached) // Cached answer?
return mLinkContent? PR_TRUE: PR_FALSE;
nsCOMPtr<nsIContent> walkUpContent(do_QueryInterface(mDOMNode));
if (walkUpContent) {
nsCOMPtr<nsIContent> tempContent = walkUpContent;
while (walkUpContent) {
nsCOMPtr<nsILink> link(do_QueryInterface(walkUpContent));
if (link) {
mLinkContent = tempContent;
mIsALinkCached = PR_TRUE;
nsLinkState linkState;
link->GetLinkState(linkState);
if (linkState == eLinkState_Visited)
mIsLinkVisited = PR_TRUE;
return PR_TRUE;
}
walkUpContent->GetParent(*getter_AddRefs(tempContent));
walkUpContent = tempContent;
}
}
mIsALinkCached = PR_TRUE; // Cached that there is no link
return PR_FALSE;
}