Back to index

lightning-sunbird  0.9+nobinonly
nsBaseWidgetAccessible.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   John Gaunt (jgaunt@netscape.com)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsBaseWidgetAccessible.h"
00040 #include "nsAccessibilityAtoms.h"
00041 #include "nsIAccessibilityService.h"
00042 #include "nsIAccessibleDocument.h"
00043 #include "nsAccessibleWrap.h"
00044 #include "nsGUIEvent.h"
00045 #include "nsILink.h"
00046 #include "nsIFrame.h"
00047 #include "nsINameSpaceManager.h"
00048 #include "nsPresContext.h"
00049 #include "nsIPresShell.h"
00050 #include "nsIServiceManager.h"
00051 #include "nsIURI.h"
00052 
00053 // ------------
00054 // nsBlockAccessible
00055 // ------------
00056 
00057 nsBlockAccessible::nsBlockAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):nsAccessibleWrap(aNode, aShell)
00058 {
00059 }
00060 
00061 NS_IMPL_ISUPPORTS_INHERITED0(nsBlockAccessible, nsAccessible)
00062 
00063 /* nsIAccessible accGetAt (in long x, in long y); */
00064 NS_IMETHODIMP nsBlockAccessible::GetChildAtPoint(PRInt32 tx, PRInt32 ty,
00065                                                  nsIAccessible **aChildAtPoint)
00066 {
00067   *aChildAtPoint = nsnull;
00068   nsCOMPtr<nsIAccessible> childAtPoint;
00069 
00070   // We're going to find the child that contains coordinates (tx,ty)
00071   PRInt32 x,y,w,h;
00072   GetBounds(&x,&y,&w,&h);  // Get bounds for this accessible
00073   if (tx >= x && tx < x + w && ty >= y && ty < y + h)
00074   {
00075     // It's within this nsIAccessible, let's drill down
00076     nsCOMPtr<nsIAccessible> child;
00077     nsCOMPtr<nsIAccessible> next;
00078     GetFirstChild(getter_AddRefs(child));
00079     PRInt32 cx,cy,cw,ch;  // Child bounds
00080 
00081     while(child) {
00082       child->GetBounds(&cx,&cy,&cw,&ch);
00083       
00084       // if there are multiple accessibles the contain the point 
00085       // and they overlap then pick the one with a frame that contans the point
00086       
00087       // For example, A point that's in block #2 is also in block #1, but we want to return #2:
00088       // [[block #1 is long wrapped text that continues to
00089       // another line]]  [[here is a shorter block #2]]
00090 
00091       if (tx >= cx && tx < cx + cw && ty >= cy && ty < cy + ch) 
00092       {
00093         // See whether one of the frames for this accessible
00094         // contains this screen point
00095         if (!childAtPoint) {
00096           // Default in case accessible doesn't have a frame such as
00097           // tree items or combo box dropdown markers
00098           childAtPoint = child;
00099         }
00100         nsCOMPtr<nsPIAccessNode> accessNode(do_QueryInterface(child));
00101         if (accessNode) {
00102           nsIFrame *frame = accessNode->GetFrame();
00103           while (frame) {
00104             if (frame->GetScreenRectExternal().Contains(tx, ty)) {
00105               childAtPoint = child;
00106               break; // Definitely in this accessible, since one of its frame matches the point
00107             }
00108             frame = frame->GetNextInFlow();
00109           }
00110         }
00111       }
00112       child->GetNextSibling(getter_AddRefs(next));
00113       child = next;
00114     }
00115 
00116     *aChildAtPoint = childAtPoint ? childAtPoint : this;
00117     NS_ADDREF(*aChildAtPoint);
00118   }
00119 
00120   return NS_OK;
00121 }
00122 
00123 
00124 //-------------
00125 // nsLeafAccessible
00126 //-------------
00127 
00128 nsLeafAccessible::nsLeafAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
00129 nsAccessibleWrap(aNode, aShell)
00130 {
00131 }
00132 
00133 NS_IMPL_ISUPPORTS_INHERITED0(nsLeafAccessible, nsAccessible)
00134 
00135 /* nsIAccessible getFirstChild (); */
00136 NS_IMETHODIMP nsLeafAccessible::GetFirstChild(nsIAccessible **_retval)
00137 {
00138   *_retval = nsnull;
00139   return NS_OK;
00140 }
00141 
00142 /* nsIAccessible getLastChild (); */
00143 NS_IMETHODIMP nsLeafAccessible::GetLastChild(nsIAccessible **_retval)
00144 {
00145   *_retval = nsnull;
00146   return NS_OK;
00147 }
00148 
00149 /* long getAccChildCount (); */
00150 NS_IMETHODIMP nsLeafAccessible::GetChildCount(PRInt32 *_retval)
00151 {
00152   *_retval = 0;
00153   return NS_OK;
00154 }
00155 
00156 
00157 //----------------
00158 // nsLinkableAccessible
00159 //----------------
00160 
00161 nsLinkableAccessible::nsLinkableAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell) :
00162   nsAccessibleWrap(aNode, aShell),
00163   mActionContent(nsnull),
00164   mIsLink(PR_FALSE),
00165   mIsOnclick(PR_FALSE)
00166 {
00167   CacheActionContent();
00168 }
00169 
00170 NS_IMPL_ISUPPORTS_INHERITED0(nsLinkableAccessible, nsAccessible)
00171 
00172 NS_IMETHODIMP nsLinkableAccessible::TakeFocus()
00173 { 
00174   if (mActionContent && mActionContent->IsFocusable()) {
00175     mActionContent->SetFocus(nsCOMPtr<nsPresContext>(GetPresContext()));
00176   }
00177   
00178   return NS_OK;
00179 }
00180 
00181 /* long GetState (); */
00182 NS_IMETHODIMP nsLinkableAccessible::GetState(PRUint32 *aState)
00183 {
00184   nsAccessible::GetState(aState);
00185   if (mIsLink) {
00186     *aState |= STATE_LINKED;
00187     nsCOMPtr<nsILink> link = do_QueryInterface(mActionContent);
00188     if (link) {
00189       nsLinkState linkState;
00190       link->GetLinkState(linkState);
00191       if (linkState == eLinkState_Visited) {
00192         *aState |= STATE_TRAVERSED;
00193       }
00194     }
00195     // Make sure we also include all the states of the parent link, such as focusable, focused, etc.
00196     PRUint32 role;
00197     GetRole(&role);
00198     if (role != ROLE_LINK) {
00199       nsCOMPtr<nsIAccessible> parentAccessible;
00200       GetParent(getter_AddRefs(parentAccessible));
00201       if (parentAccessible) {
00202         PRUint32 orState = 0;
00203         parentAccessible->GetFinalState(&orState);
00204         *aState |= orState;
00205       }
00206     }
00207   }
00208   if (mActionContent && !mActionContent->IsFocusable()) {
00209     *aState &= ~STATE_FOCUSABLE; // Links must have href or tabindex
00210   }
00211 
00212   nsCOMPtr<nsIAccessibleDocument> docAccessible(GetDocAccessible());
00213   if (docAccessible) {
00214     PRBool isEditable;
00215     docAccessible->GetIsEditable(&isEditable);
00216     if (isEditable) {
00217       *aState &= ~(STATE_FOCUSED | STATE_FOCUSABLE); // Links not focusable in editor
00218     }
00219   }
00220   return NS_OK;
00221 }
00222 
00223 
00224 NS_IMETHODIMP nsLinkableAccessible::GetValue(nsAString& _retval)
00225 {
00226   if (mIsLink) {
00227     nsCOMPtr<nsIDOMNode> linkNode(do_QueryInterface(mActionContent));
00228     nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
00229     if (linkNode && presShell)
00230       return presShell->GetLinkLocation(linkNode, _retval);
00231   }
00232   return NS_ERROR_NOT_IMPLEMENTED;
00233 }
00234 
00235 
00236 /* PRUint8 getAccNumActions (); */
00237 NS_IMETHODIMP nsLinkableAccessible::GetNumActions(PRUint8 *aNumActions)
00238 {
00239   *aNumActions = mActionContent ? 1 : 0;
00240   return NS_OK;
00241 }
00242 
00243 /* wstring getAccActionName (in PRUint8 index); */
00244 NS_IMETHODIMP nsLinkableAccessible::GetActionName(PRUint8 index, nsAString& aActionName)
00245 {
00246   // Action 0 (default action): Jump to link
00247   aActionName.Truncate();
00248   if (index == eAction_Jump) {   
00249     if (mIsLink) {
00250       return nsAccessible::GetTranslatedString(NS_LITERAL_STRING("jump"), aActionName); 
00251     }
00252     else if (mIsOnclick) {
00253       return nsAccessible::GetTranslatedString(NS_LITERAL_STRING("click"), aActionName); 
00254     }
00255     return NS_ERROR_NOT_IMPLEMENTED;
00256   }
00257   return NS_ERROR_INVALID_ARG;
00258 }
00259 
00260 /* void accDoAction (in PRUint8 index); */
00261 NS_IMETHODIMP nsLinkableAccessible::DoAction(PRUint8 index)
00262 {
00263   // Action 0 (default action): Jump to link
00264   if (index == eAction_Jump) {
00265     if (mActionContent) {
00266       return DoCommand(mActionContent);
00267     }
00268   }
00269   return NS_ERROR_INVALID_ARG;
00270 }
00271 
00272 NS_IMETHODIMP nsLinkableAccessible::GetKeyboardShortcut(nsAString& aKeyboardShortcut)
00273 {
00274   if (mActionContent) {
00275     nsCOMPtr<nsIDOMNode> actionNode(do_QueryInterface(mActionContent));
00276     if (actionNode && mDOMNode != actionNode) {
00277       nsCOMPtr<nsIAccessible> accessible;
00278       nsCOMPtr<nsIAccessibilityService> accService = 
00279         do_GetService("@mozilla.org/accessibilityService;1");
00280       accService->GetAccessibleInWeakShell(actionNode, mWeakShell,
00281                                            getter_AddRefs(accessible));
00282       if (accessible) {
00283         accessible->GetKeyboardShortcut(aKeyboardShortcut);
00284       }
00285       return NS_OK;
00286     }
00287   }
00288   return nsAccessible::GetKeyboardShortcut(aKeyboardShortcut);
00289 }
00290 
00291 void nsLinkableAccessible::CacheActionContent()
00292 {
00293   for (nsCOMPtr<nsIContent> walkUpContent(do_QueryInterface(mDOMNode));
00294        walkUpContent;
00295        walkUpContent = walkUpContent->GetParent()) {
00296     nsIAtom *tag = walkUpContent->Tag();
00297     if ((tag == nsAccessibilityAtoms::a || tag == nsAccessibilityAtoms::area) &&
00298         walkUpContent->IsContentOfType(nsIContent::eHTML)) {
00299       nsCOMPtr<nsILink> link = do_QueryInterface(walkUpContent);
00300       if (link) {
00301         // Currently we do not expose <link> tags, because they are not typically
00302         // in <body> and rendered.
00303         // We do not yet support xlinks
00304         nsCOMPtr<nsIURI> uri;
00305         link->GetHrefURI(getter_AddRefs(uri));
00306         if (uri) {
00307           mActionContent = walkUpContent;
00308           mIsLink = PR_TRUE;
00309           break;
00310         }
00311       }
00312     }
00313     if (walkUpContent->HasAttr(kNameSpaceID_None,
00314                                nsAccessibilityAtoms::onclick)) {
00315       mActionContent = walkUpContent;
00316       mIsOnclick = PR_TRUE;
00317       break;
00318     }
00319   }
00320 }
00321 
00322 NS_IMETHODIMP nsLinkableAccessible::Shutdown()
00323 {
00324   mActionContent = nsnull;
00325   return nsAccessibleWrap::Shutdown();
00326 }
00327 
00328 //---------------------
00329 // nsEnumRoleAccessible
00330 //---------------------
00331 
00332 nsEnumRoleAccessible::nsEnumRoleAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell, PRUint32 aRole) :
00333   nsAccessibleWrap(aNode, aShell),
00334   mRole(aRole)
00335 {
00336 }
00337 
00338 NS_IMPL_ISUPPORTS_INHERITED0(nsEnumRoleAccessible, nsAccessible)