Back to index

lightning-sunbird  0.9+nobinonly
nsSpatialNavigationUtils.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Spatial Navigation
00015  *
00016  * The Initial Developer of the Original Code is 
00017  * Douglas F. Turner II  <dougt@meer.net>
00018  * Portions created by the Initial Developer are Copyright (C) 2004-2005
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "nsSpatialNavigationPrivate.h"
00038 
00039 #ifdef DEBUG_outputframes
00040 #include "nsIFrameDebug.h"
00041 #endif
00042 
00043 static PRBool is_space(char c)
00044 {
00045   return (c == ' '  || c == '\f' || c == '\n' ||
00046           c == '\r' || c == '\t' || c == '\v');
00047 }
00048 
00049 nscoord* lo_parse_coord_list(char *str, PRInt32* value_cnt)
00050 {
00051   char *tptr;
00052   char *n_str;
00053   PRInt32 i, cnt;
00054   PRInt32 *value_list;
00055   
00056   /*
00057    * Nothing in an empty list
00058    */
00059   *value_cnt = 0;
00060   if (!str || *str == '\0')
00061   {
00062     return nsnull;
00063   }
00064   
00065   /*
00066    * Skip beginning whitespace, all whitespace is empty list.
00067    */
00068   n_str = str;
00069   while (is_space(*n_str))
00070   {
00071     n_str++;
00072   }
00073   if (*n_str == '\0')
00074   {
00075     return nsnull;
00076   }
00077   
00078   /*
00079    * Make a pass where any two numbers separated by just whitespace
00080    * are given a comma separator.  Count entries while passing.
00081    */
00082   cnt = 0;
00083   while (*n_str != '\0')
00084   {
00085     PRBool has_comma;
00086     
00087     /*
00088      * Skip to a separator
00089      */
00090     tptr = n_str;
00091     while (!is_space(*tptr) && *tptr != ',' && *tptr != '\0')
00092     {
00093       tptr++;
00094     }
00095     n_str = tptr;
00096     
00097     /*
00098      * If no more entries, break out here
00099      */
00100     if (*n_str == '\0')
00101     {
00102       break;
00103     }
00104     
00105     /*
00106      * Skip to the end of the separator, noting if we have a
00107      * comma.
00108      */
00109     has_comma = PR_FALSE;
00110     while (is_space(*tptr) || *tptr == ',')
00111     {
00112       if (*tptr == ',')
00113       {
00114         if (has_comma == PR_FALSE)
00115         {
00116           has_comma = PR_TRUE;
00117         }
00118         else
00119         {
00120           break;
00121         }
00122       }
00123       tptr++;
00124     }
00125     /*
00126      * If this was trailing whitespace we skipped, we are done.
00127      */
00128     if ((*tptr == '\0')&&(has_comma == PR_FALSE))
00129     {
00130       break;
00131     }
00132     /*
00133      * Else if the separator is all whitespace, and this is not the
00134      * end of the string, add a comma to the separator.
00135      */
00136     else if (has_comma == PR_FALSE)
00137     {
00138       *n_str = ',';
00139     }
00140     
00141     /*
00142      * count the entry skipped.
00143      */
00144     cnt++;
00145     
00146     n_str = tptr;
00147   }
00148   /*
00149    * count the last entry in the list.
00150    */
00151   cnt++;
00152   
00153   /*
00154    * Allocate space for the coordinate array.
00155    */
00156   value_list = new nscoord[cnt];
00157   if (!value_list)
00158   {
00159     return nsnull;
00160   }
00161   
00162   /*
00163    * Second pass to copy integer values into list.
00164    */
00165   tptr = str;
00166   for (i=0; i<cnt; i++)
00167   {
00168     char *ptr;
00169     
00170     ptr = strchr(tptr, ',');
00171     if (ptr)
00172     {
00173       *ptr = '\0';
00174     }
00175     /*
00176      * Strip whitespace in front of number because I don't
00177      * trust atoi to do it on all platforms.
00178      */
00179     while (is_space(*tptr))
00180     {
00181       tptr++;
00182     }
00183     if (*tptr == '\0')
00184     {
00185       value_list[i] = 0;
00186     }
00187     else
00188     {
00189       value_list[i] = (nscoord) ::atoi(tptr);
00190     }
00191     if (ptr)
00192     {
00193       *ptr = ',';
00194       tptr = ptr + 1;
00195     }
00196   }
00197   
00198   *value_cnt = cnt;
00199   return value_list;
00200 }
00201 
00202 nsresult createFrameTraversal(PRUint32 type, nsPresContext* presContext, 
00203                               nsIBidirectionalEnumerator** outTraversal)
00204 {
00205   nsresult result;
00206   if (!presContext)
00207     return NS_ERROR_FAILURE;    
00208   
00209   nsIPresShell* presShell = presContext->PresShell();
00210   if (!presShell)
00211     return NS_ERROR_FAILURE;
00212   
00213   nsIFrame* frame = presShell->GetRootFrame();
00214   
00215   if (!frame)
00216     return NS_ERROR_FAILURE;
00217 
00218 #ifdef DEBUG_outputframes
00219   nsIFrameDebug* fd;
00220   frame->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**) &fd);
00221   if (fd)
00222     fd->List(frame->GetPresContext(), stdout, 0);
00223 #endif
00224 
00225   nsCOMPtr<nsIBidirectionalEnumerator> frameTraversal;
00226   
00227   static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
00228   nsCOMPtr<nsIFrameTraversal> trav(do_CreateInstance(kFrameTraversalCID,&result));
00229   if (NS_FAILED(result))
00230     return result;
00231   
00232   result = trav->NewFrameTraversal(getter_AddRefs(frameTraversal),
00233                                    type, 
00234                                    presContext, 
00235                                    frame);
00236   if (NS_FAILED(result))
00237     return result;
00238   
00239   NS_IF_ADDREF(*outTraversal = frameTraversal);
00240   return NS_OK;
00241 }
00242 
00243 nsresult getEventTargetFromWindow(nsIDOMWindow* aWindow, nsIDOM3EventTarget** aEventTarget, nsIDOMEventGroup** aSystemGroup)
00244 {
00245   *aEventTarget = nsnull;
00246   nsCOMPtr<nsPIDOMWindow> privateWindow = do_QueryInterface(aWindow);
00247   
00248   if (!privateWindow)
00249     return NS_ERROR_UNEXPECTED; // assert
00250   
00251   nsIChromeEventHandler *chromeEventHandler = privateWindow->GetChromeEventHandler();
00252   
00253   nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(chromeEventHandler));
00254   if (!receiver)
00255     return NS_ERROR_UNEXPECTED; // assert
00256   
00257   nsCOMPtr<nsIDOMEventGroup> systemGroup;
00258   receiver->GetSystemEventGroup(getter_AddRefs(systemGroup));
00259   nsCOMPtr<nsIDOM3EventTarget> target(do_QueryInterface(receiver));
00260   
00261   if (!target || !systemGroup)
00262     return NS_ERROR_FAILURE;
00263   
00264   NS_ADDREF(*aEventTarget = target);
00265   NS_ADDREF(*aSystemGroup = systemGroup);
00266   return NS_OK;
00267 }
00268 
00269 void getContentFromFrame(nsIContent* c, nsIContent** outContent)
00270 {
00271   *outContent = nsnull;
00272 
00273   nsCOMPtr<nsIContent> result;
00274   nsCOMPtr<nsIDOMDocument> contentDocument;
00275 
00276   nsCOMPtr<nsIDOMHTMLFrameElement> domFrameElement = do_QueryInterface(c);
00277 
00278   if (domFrameElement) {
00279     domFrameElement->GetContentDocument(getter_AddRefs(contentDocument));
00280   }  
00281   else {
00282     nsCOMPtr<nsIDOMHTMLIFrameElement> domIFrameElement = do_QueryInterface(c);
00283        if (domIFrameElement)
00284       domIFrameElement->GetContentDocument(getter_AddRefs(contentDocument));
00285   }
00286 
00287   if (contentDocument) {
00288     nsCOMPtr<nsIDOMElement> documentElement;
00289     contentDocument->GetDocumentElement(getter_AddRefs(documentElement));
00290     result = do_QueryInterface(documentElement);
00291   }
00292   NS_IF_ADDREF(*outContent = result);
00293 }
00294 
00295 nsresult getFrameForContent(nsIContent* aContent, nsIFrame** aFrame)
00296 {
00297   *aFrame = nsnull;
00298 
00299   if (!aContent)
00300     return NS_ERROR_FAILURE;
00301   
00302   nsIDocument* doc = aContent->GetDocument();
00303   if (!doc)
00304     return NS_ERROR_FAILURE;
00305   
00306   nsIFrame* frame;
00307   nsIPresShell *presShell = doc->GetShellAt(0);
00308   presShell->GetPrimaryFrameFor(aContent, &frame);
00309   
00310   if (!frame)
00311     return NS_ERROR_FAILURE;
00312   
00313   *aFrame = frame;
00314   return NS_OK;
00315 }
00316 
00317 PRBool
00318 isContentOfType(nsIContent* content, const char* type)
00319 {
00320   if (!content)
00321        return PR_FALSE;
00322 
00323   nsINodeInfo *nodeInfo = content->GetNodeInfo();
00324   if (nodeInfo)
00325   {
00326     nsIAtom* atom =  nodeInfo->NameAtom();
00327     if (atom)
00328       return atom->EqualsUTF8(nsDependentCString(type));
00329   }
00330   return PR_FALSE;
00331 }
00332 
00333 PRBool
00334 isArea(nsIContent* content)
00335 {
00336   if (!content || !content->IsContentOfType(nsIContent::eHTML))
00337       return PR_FALSE;
00338 
00339   return isContentOfType(content, "area");
00340 }
00341 
00342 PRBool
00343 isMap(nsIFrame* frame)
00344 {
00345   nsIContent* content = frame->GetContent();
00346 
00347   if (!content || !content->IsContentOfType(nsIContent::eHTML))
00348       return PR_FALSE;
00349 
00350   return isContentOfType(content, "map");
00351 }
00352 
00353 PRBool 
00354 isTargetable(PRBool focusDocuments, nsIFrame* frame)
00355 {
00356   nsIContent* currentContent = frame->GetContent();
00357 
00358   if (!currentContent)
00359     return PR_FALSE;
00360 
00361   if (!currentContent->IsContentOfType(nsIContent::eHTML))
00362       return PR_FALSE;
00363 
00364   if (isContentOfType(currentContent, "map"))
00365     return PR_TRUE;
00366 
00367   if (isContentOfType(currentContent, "button"))
00368     return PR_TRUE;
00369 
00370   if (isContentOfType(currentContent, "a"))
00371   {
00372     // an anchor isn't targetable unless it has a non-null href.
00373     nsCOMPtr<nsIDOMHTMLAnchorElement> anchorElement = do_QueryInterface(currentContent);
00374     nsAutoString uri;
00375     anchorElement->GetHref(uri);
00376     if (uri.IsEmpty()) {
00377       return PR_FALSE; 
00378     }
00379     return PR_TRUE;
00380   }
00381 
00382   nsCOMPtr<nsIFrameFrame> frameFrame(do_QueryInterface(frame));
00383   if (frameFrame) 
00384     return PR_TRUE;
00385 
00386   nsCOMPtr<nsIDOMHTMLIFrameElement> iFrameElement = do_QueryInterface(currentContent);
00387   if (iFrameElement) 
00388     return PR_TRUE;
00389 
00390   if (focusDocuments) {
00391     nsCOMPtr<nsIDOMHTMLHtmlElement> hhElement(do_QueryInterface(currentContent));
00392     if (hhElement) 
00393       return PR_TRUE;
00394   }
00395 
00396   // need to figure out how to determine if a element is
00397   // either disabled, hidden, or it is inaccessible due to
00398   // its parent being one of these.
00399 
00400   PRBool disabled = PR_FALSE;
00401   
00402   nsCOMPtr<nsIDOMHTMLSelectElement> selectElement = do_QueryInterface(currentContent);
00403   if (selectElement && NS_SUCCEEDED(selectElement->GetDisabled(&disabled)))
00404     return !disabled;
00405 
00406   nsCOMPtr<nsIDOMHTMLOptionElement> optionElement = do_QueryInterface(currentContent);
00407   if (optionElement && NS_SUCCEEDED(optionElement->GetDisabled(&disabled)))
00408     return !disabled;
00409 
00410   nsAutoString inputType;
00411   nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(currentContent);
00412   if (inputElement && NS_SUCCEEDED(inputElement->GetDisabled(&disabled)) && NS_SUCCEEDED(inputElement->GetType(inputType)))
00413     return !disabled && (! inputType.LowerCaseEqualsLiteral("hidden")) && (!inputType.LowerCaseEqualsLiteral("button"));
00414 
00415   nsAutoString textareaType;
00416   nsCOMPtr<nsIDOMHTMLTextAreaElement> textareaElement = do_QueryInterface(currentContent);
00417   if (textareaElement && NS_SUCCEEDED(textareaElement->GetDisabled(&disabled)) && NS_SUCCEEDED(textareaElement->GetType(textareaType)))
00418     return !disabled && (! textareaType.LowerCaseEqualsLiteral("hidden"));
00419 
00420   return PR_FALSE;
00421 }
00422 
00423 nsRect makeRectRelativeToGlobalView(nsIFrame *aFrame)
00424 {
00425   nsRect result;
00426   result.SetRect(0,0,0,0);
00427 
00428   nsPoint offset;
00429 
00430   if (!aFrame)
00431     return result;
00432 
00433   result = aFrame->GetRect();
00434 
00435   nsIView* view;
00436   aFrame->GetOffsetFromView(offset, &view);
00437   
00438   nsIView* rootView = nsnull;
00439   if (view) {
00440     nsIViewManager* viewManager = view->GetViewManager();
00441     NS_ASSERTION(viewManager, "View must have a viewmanager");
00442     viewManager->GetRootView(rootView);
00443   }
00444   while (view) {
00445     offset  += view->GetPosition();
00446     if (view == rootView) {
00447       break;
00448     }
00449     view = view->GetParent();
00450   }
00451   
00452   result.MoveTo(offset);
00453   return result;
00454 }
00455 
00456 
00457 void poly2Rect(int sides, nscoord* coord, nsRect* rect)
00458 {
00459   nscoord x1, x2, y1, y2, xtmp, ytmp;
00460   x1 = x2 = coord[0];
00461   y1 = y2 = coord[1];
00462   for (PRInt32 i = 2; i < sides; i += 2) 
00463   {
00464     xtmp = coord[i];
00465     ytmp = coord[i+1];
00466     x1 = x1 < xtmp ? x1 : xtmp;
00467     y1 = y1 < ytmp ? y1 : ytmp;
00468     x2 = x2 > xtmp ? x2 : xtmp;
00469     y2 = y2 > ytmp ? y2 : ytmp;
00470   }
00471   rect->SetRect(x1, y1, x2, y2);
00472 }
00473 
00474 void getRectOfAreaElement(nsIFrame* f, nsIDOMHTMLAreaElement* e, nsRect* r)
00475 {
00476   if (!f || !e || !r)
00477     return;
00478 
00479   // RECT !!
00480   nsRect frameRect = makeRectRelativeToGlobalView(f);
00481   
00482   if (frameRect.width == 0)
00483     frameRect.width = 1;
00484   if (frameRect.height == 0)
00485     frameRect.height = 1;
00486   
00487   nsPoint offset;
00488   offset.x = frameRect.x;
00489   offset.y = frameRect.y;
00490   
00491 
00492   nsAutoString coordstr;
00493   e->GetCoords(coordstr);
00494 
00495   NS_ConvertUTF16toUTF8 cp (coordstr);
00496   
00497   PRInt32 count;
00498   nscoord* coords = lo_parse_coord_list((char*) cp.get(), &count);
00499   
00500   // FIX what about other shapes?
00501   
00502   if (count == 4) 
00503   {
00504     //                x          y          width                  height
00505     frameRect.SetRect(coords[0], coords[1], coords[2] - coords[0], coords[3] - coords[1]);
00506     
00507     frameRect.x += offset.x;
00508     frameRect.y += offset.y;
00509   }
00510   else if (count >=6)
00511     poly2Rect(count, coords, &frameRect);
00512 #ifdef DEBUG_dougt
00513   else
00514     printf("area count not supported!! %d\n", count);
00515 #endif
00516 
00517   // find the center of the rect.
00518 
00519   frameRect.x = frameRect.x + (frameRect.width / 2) - 1;
00520   frameRect.width = 2;
00521   frameRect.y = frameRect.y + (frameRect.height / 2) - 1;
00522   frameRect.height = 2;
00523 
00524   *r = frameRect;
00525 }
00526 
00527 // we want to determine if going in the |direction|
00528 // direction from focusedRect will intercept the frameRect
00529 
00530 PRBool isRectInDirection(int direction, nsRect& focusedRect, nsRect& frameRect)
00531 {
00532   if (direction == eNavLeft)
00533   {
00534     return (frameRect.x < focusedRect.x);
00535   }
00536   
00537   if (direction == eNavRight)
00538   {
00539     return (frameRect.x + frameRect.width > focusedRect.x + focusedRect.width);
00540   }
00541   
00542   if (direction == eNavUp)
00543   {
00544     return (frameRect.y < focusedRect.y);
00545   }
00546   
00547   if (direction == eNavDown)
00548   {
00549     return (frameRect.y + frameRect.height > focusedRect.y + focusedRect.height);
00550   }
00551   return PR_FALSE;
00552 }
00553 
00554 PRInt64 spatialDistance(int direction, nsRect& a, nsRect& b)
00555 {
00556   PRBool inlineNavigation = PR_FALSE;
00557   nsPoint m, n;
00558   
00559   if (direction == eNavLeft)
00560   {
00561     //  |---|
00562     //  |---|
00563     //
00564     //  |---|  |---|
00565     //  |---|  |---|
00566     //
00567     //  |---|
00568     //  |---|
00569     //
00570     
00571     if (a.y > b.y + b.height) 
00572     {
00573       // the b rect is above a.
00574       m.x = a.x;
00575       m.y = a.y;
00576       n.x = b.x + b.width;
00577       n.y = b.y + b.height;
00578     }
00579     else if (a.y + a.height < b.y)
00580     {
00581       // the b rect is below a.
00582       m.x = a.x;
00583       m.y = a.y + a.height;
00584       n.x = b.x + b.width;
00585       n.y = b.y;       
00586     }
00587     else
00588     {
00589       m.x = a.x;
00590       m.y = 0;
00591       n.x = b.x + b.width; 
00592       n.y = 0;
00593 
00594       //      m.x = (a.x + (a.width / 2));
00595       //      m.y = (a.y + (a.height / 2));
00596       //      n.x = (b.x + (b.width / 2));
00597       //      n.y = (b.y + (b.height / 2));
00598 
00599     }
00600   }
00601   else if (direction == eNavRight)
00602   {
00603     
00604     //         |---|
00605     //         |---|
00606     //
00607     //  |---|  |---|
00608     //  |---|  |---|
00609     //
00610     //         |---|
00611     //         |---|
00612     //
00613     
00614     if (a.y > b.y + b.height) 
00615     {
00616       // the b rect is above a.
00617       m.x = a.x + a.width;
00618       m.y = a.y;
00619       n.x = b.x;
00620       n.y = b.y + b.height;
00621     }
00622     else if (a.y + a.height < b.y)
00623     {
00624       // the b rect is below a.
00625       m.x = a.x + a.width;
00626       m.y = a.y + a.height;
00627       n.x = b.x;
00628       n.y = b.y;       
00629     }
00630     else
00631     {
00632       m.x = a.x + a.width;
00633       m.y = 0;
00634       n.x = b.x; 
00635       n.y = 0;
00636       
00637       //      m.x = (a.x + (a.width / 2));
00638       //      m.y = (a.y + (a.height / 2));
00639       //      n.x = (b.x + (b.width / 2));
00640       //      n.y = (b.y + (b.height / 2));
00641     }
00642   }
00643   else if (direction == eNavUp)
00644   {
00645     
00646     //  |---|  |---|  |---|
00647     //  |---|  |---|  |---|
00648     //
00649     //         |---|
00650     //         |---|
00651     //
00652     
00653     if (a.x > b.x + b.width) 
00654     {
00655       // the b rect is to the left of a.
00656       m.x = a.x;
00657       m.y = a.y;
00658       n.x = b.x + b.width;
00659       n.y = b.y + b.height;
00660     }
00661     else if (a.x + a.width < b.x)
00662     {
00663       // the b rect is to the right of a
00664       m.x = a.x + a.width;
00665       m.y = a.y;
00666       n.x = b.x;
00667       n.y = b.y + b.height;       
00668     }
00669     else
00670     {
00671       // both b and a share some common x's.
00672       m.x = 0;
00673       m.y = a.y;
00674       n.x = 0;
00675       n.y = b.y + b.height;
00676 
00677       //      m.x = (a.x + (a.width / 2));
00678       //      m.y = (a.y + (a.height / 2));     
00679       //      n.x = (b.x + (b.width / 2));
00680       //      n.y = (b.y + (b.height / 2));
00681     }
00682   }
00683   else if (direction == eNavDown)
00684   {
00685     //         |---|
00686     //         |---|
00687     //
00688     //  |---|  |---|  |---|
00689     //  |---|  |---|  |---|
00690     //
00691     
00692     if (a.x > b.x + b.width) 
00693     {
00694       // the b rect is to the left of a.
00695       m.x = a.x;
00696       m.y = a.y + a.height;
00697       n.x = b.x + b.width;
00698       n.y = b.y;
00699     }
00700     else if (a.x + a.width < b.x)
00701     {
00702       // the b rect is to the right of a
00703       m.x = a.x + a.width;
00704       m.y = a.y + a.height;
00705       n.x = b.x;
00706       n.y = b.y;       
00707     }
00708     else
00709     {
00710       // both b and a share some common x's.
00711       m.x = 0;
00712       m.y = a.y + a.height;
00713       n.x = 0;
00714       n.y = b.y;
00715 
00716       //      m.x = (a.x + (a.width / 2));
00717       //      m.y = (a.y + (a.height / 2));     
00718       //      n.x = (b.x + (b.width / 2));
00719       //      n.y = (b.y + (b.height / 2));
00720     }
00721   }
00722   
00723   // a is always the currently focused rect.
00724   
00725   nsRect scopedRect = a;
00726   scopedRect.Inflate(gRectFudge, gRectFudge);
00727   
00728   if (direction == eNavLeft)
00729   {
00730     scopedRect.x = 0;
00731     scopedRect.width = nscoord_MAX;
00732     if (scopedRect.Intersects(b))
00733       inlineNavigation = PR_TRUE;
00734   }
00735   else if (direction == eNavRight)
00736   {
00737     scopedRect.width = nscoord_MAX;
00738     if (scopedRect.Intersects(b))
00739       inlineNavigation = PR_TRUE;
00740   }
00741   else if (direction == eNavUp)
00742   {
00743     scopedRect.y = 0;
00744     scopedRect.height = nscoord_MAX;
00745     if (scopedRect.Intersects(b))
00746       inlineNavigation = PR_TRUE;
00747   }
00748   else if (direction == eNavDown)
00749   {
00750     scopedRect.height = nscoord_MAX;
00751     if (scopedRect.Intersects(b))
00752       inlineNavigation = PR_TRUE;
00753   }
00754   
00755   PRInt64 d = ((m.x-n.x)*(m.x-n.x)) + ((m.y-n.y)*(m.y-n.y));
00756   
00757   if(d<0)
00758     d=d*(-1);
00759   
00760   if (inlineNavigation)
00761        d /= gDirectionalBias;
00762   
00763   return d;
00764 }
00765 
00766 void GetWindowFromDocument(nsIDOMDocument* aDocument, nsIDOMWindowInternal** aWindow)
00767 {
00768   nsCOMPtr<nsIDOMDocumentView> docview = do_QueryInterface(aDocument);
00769 
00770   nsCOMPtr<nsIDOMAbstractView> view;
00771   docview->GetDefaultView(getter_AddRefs(view));
00772   if (!view) return;
00773   
00774   nsCOMPtr<nsIDOMWindowInternal> window = do_QueryInterface(view);
00775   NS_IF_ADDREF(*aWindow = window);
00776 }
00777 
00778 
00779 
00780 PRBool IsPartiallyVisible(nsIPresShell* shell, nsIFrame* frame) 
00781 {
00782    // We need to know if at least a kMinPixels around the object is visible
00783    // Otherwise it will be marked STATE_OFFSCREEN and STATE_INVISIBLE
00784    
00785    const PRUint16 kMinPixels  = 12;
00786     // Set up the variables we need, return false if we can't get at them all
00787  
00788    nsIViewManager* viewManager = shell->GetViewManager();
00789    if (!viewManager)
00790      return PR_FALSE;
00791  
00792  
00793    // If visibility:hidden or visibility:collapsed then mark with STATE_INVISIBLE
00794    if (!frame->GetStyleVisibility()->IsVisible())
00795    {
00796        return PR_FALSE;
00797    }
00798  
00799    nsPresContext *presContext = shell->GetPresContext();
00800    if (!presContext)
00801      return PR_FALSE;
00802  
00803    // Get the bounds of the current frame, relative to the current view.
00804    // We don't use the more accurate GetBoundsRect, because that is more expensive 
00805    // and the STATE_OFFSCREEN flag that this is used for only needs to be a rough indicator
00806  
00807    nsRect relFrameRect = frame->GetRect();
00808    nsPoint frameOffset;
00809    nsIView *containingView = frame->GetViewExternal();
00810    if (!containingView) {
00811      frame->GetOffsetFromView(frameOffset, &containingView);
00812      if (!containingView)
00813        return PR_FALSE;  // no view -- not visible
00814      relFrameRect.x = frameOffset.x;
00815      relFrameRect.y = frameOffset.y;
00816    }
00817  
00818    float p2t;
00819    p2t = presContext->PixelsToTwips();
00820    nsRectVisibility rectVisibility;
00821    viewManager->GetRectVisibility(containingView, relFrameRect, 
00822                                   NS_STATIC_CAST(PRUint16, (kMinPixels * p2t)), 
00823                                   &rectVisibility);
00824  
00825    if (rectVisibility == nsRectVisibility_kVisible ||
00826        (rectVisibility == nsRectVisibility_kZeroAreaRect && frame->GetNextInFlow())) {
00827      // This view says it is visible, but we need to check the parent view chain :(
00828      // Note: zero area rects can occur in the first frame of a multi-frame text flow,
00829      //       in which case the next frame exists because the text flow is visible
00830      while ((containingView = containingView->GetParent()) != nsnull) {
00831        if (containingView->GetVisibility() == nsViewVisibility_kHide) {
00832          return PR_FALSE;
00833        }
00834      }
00835      return PR_TRUE;
00836    }
00837  
00838    return PR_FALSE;
00839  }
00840 
00841 
00842 const static PRInt32 gScrollOffset = (26*3);
00843 
00844 
00845 void ScrollWindow(int direction, nsIDOMWindow* contentWindow)
00846 {
00847   if (!contentWindow)
00848     return;
00849   
00850   if (direction == eNavLeft)
00851     contentWindow->ScrollBy(-1* gScrollOffset, 0);
00852   else if (direction == eNavRight)
00853     contentWindow->ScrollBy(gScrollOffset, 0);
00854   else if (direction == eNavUp)
00855     contentWindow->ScrollBy(0, -1 * gScrollOffset);
00856   else
00857     contentWindow->ScrollBy(0, gScrollOffset);
00858 }