Back to index

lightning-sunbird  0.9+nobinonly
nsFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 // vim:cindent:ts=2:et:sw=2:
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Pierre Phaneuf <pp@ludusdesign.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 #include "nsCOMPtr.h"
00040 #include "nsFrame.h"
00041 #include "nsFrameList.h"
00042 #include "nsLineLayout.h"
00043 #include "nsIContent.h"
00044 #include "nsContentUtils.h"
00045 #include "nsIAtom.h"
00046 #include "nsString.h"
00047 #include "nsReadableUtils.h"
00048 #include "nsStyleContext.h"
00049 #include "nsReflowPath.h"
00050 #include "nsIView.h"
00051 #include "nsIViewManager.h"
00052 #include "nsIScrollableFrame.h"
00053 #include "nsPresContext.h"
00054 #include "nsCRT.h"
00055 #include "nsGUIEvent.h"
00056 #include "nsIDOMEvent.h"
00057 #include "nsPLDOMEvent.h"
00058 #include "nsStyleConsts.h"
00059 #include "nsIPresShell.h"
00060 #include "prlog.h"
00061 #include "prprf.h"
00062 #include <stdarg.h>
00063 #include "nsFrameManager.h"
00064 #include "nsCSSRendering.h"
00065 #include "nsLayoutUtils.h"
00066 #ifdef ACCESSIBILITY
00067 #include "nsIAccessible.h"
00068 #endif
00069 
00070 #include "nsIDOMText.h"
00071 #include "nsIDOMHTMLAnchorElement.h"
00072 #include "nsIDOMHTMLAreaElement.h"
00073 #include "nsIDOMHTMLImageElement.h"
00074 #include "nsIDOMHTMLHRElement.h"
00075 #include "nsIDOMHTMLInputElement.h"
00076 #include "nsIDeviceContext.h"
00077 #include "nsIEditorDocShell.h"
00078 #include "nsIEventStateManager.h"
00079 #include "nsISelection.h"
00080 #include "nsISelectionPrivate.h"
00081 #include "nsIFrameSelection.h"
00082 #include "nsHTMLParts.h"
00083 #include "nsLayoutAtoms.h"
00084 #include "nsCSSAnonBoxes.h"
00085 #include "nsCSSPseudoElements.h"
00086 #include "nsHTMLAtoms.h"
00087 #include "nsIHTMLContentSink.h" 
00088 #include "nsCSSFrameConstructor.h"
00089 
00090 #include "nsFrameTraversal.h"
00091 #include "nsStyleChangeList.h"
00092 #include "nsIDOMRange.h"
00093 #include "nsITableLayout.h"    //selection neccesity
00094 #include "nsITableCellLayout.h"//  "
00095 #include "nsITextControlFrame.h"
00096 #include "nsINameSpaceManager.h"
00097 #include "nsIPercentHeightObserver.h"
00098 #include "nsTextTransformer.h"
00099 
00100 // For triple-click pref
00101 #include "nsIServiceManager.h"
00102 #include "nsISelectionImageService.h"
00103 #include "imgIContainer.h"
00104 #include "imgIRequest.h"
00105 #include "gfxIImageFrame.h"
00106 #include "nsILookAndFeel.h"
00107 #include "nsLayoutCID.h"
00108 #include "nsWidgetsCID.h"     // for NS_LOOKANDFEEL_CID
00109 #include "nsUnicharUtils.h"
00110 #include "nsLayoutErrors.h"
00111 #include "nsContentErrors.h"
00112 #include "nsHTMLContainerFrame.h"
00113 #include "nsBoxLayoutState.h"
00114 
00115 static NS_DEFINE_CID(kSelectionImageService, NS_SELECTIONIMAGESERVICE_CID);
00116 static NS_DEFINE_CID(kLookAndFeelCID,  NS_LOOKANDFEEL_CID);
00117 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
00118 
00119 // Struct containing cached metrics for box-wrapped frames.
00120 struct nsBoxLayoutMetrics
00121 {
00122   nsSize mPrefSize;
00123   nsSize mMinSize;
00124   nsSize mMaxSize;
00125 
00126   nsSize mBlockMinSize;
00127   nsSize mBlockPrefSize;
00128   nscoord mBlockAscent;
00129 
00130   nscoord mFlex;
00131   nscoord mAscent;
00132 
00133   nsSize mLastSize;
00134   nsSize mOverflow;
00135 
00136   PRPackedBool mIncludeOverflow;
00137   PRPackedBool mWasCollapsed;
00138   PRPackedBool mStyleChange;
00139 };
00140 
00141 // Some Misc #defines
00142 #define SELECTION_DEBUG        0
00143 #define FORCE_SELECTION_UPDATE 1
00144 #define CALC_DEBUG             0
00145 
00146 
00147 #include "nsICaret.h"
00148 #include "nsILineIterator.h"
00149 
00150 //non Hack prototypes
00151 #if 0
00152 static void RefreshContentFrames(nsPresContext* aPresContext, nsIContent * aStartContent, nsIContent * aEndContent);
00153 #endif
00154 
00155 #include "prenv.h"
00156 
00157 // start nsIFrameDebug
00158 
00159 #ifdef NS_DEBUG
00160 static PRBool gShowFrameBorders = PR_FALSE;
00161 
00162 void nsIFrameDebug::ShowFrameBorders(PRBool aEnable)
00163 {
00164   gShowFrameBorders = aEnable;
00165 }
00166 
00167 PRBool nsIFrameDebug::GetShowFrameBorders()
00168 {
00169   return gShowFrameBorders;
00170 }
00171 
00172 static PRBool gShowEventTargetFrameBorder = PR_FALSE;
00173 
00174 void nsIFrameDebug::ShowEventTargetFrameBorder(PRBool aEnable)
00175 {
00176   gShowEventTargetFrameBorder = aEnable;
00177 }
00178 
00179 PRBool nsIFrameDebug::GetShowEventTargetFrameBorder()
00180 {
00181   return gShowEventTargetFrameBorder;
00182 }
00183 
00188 static PRLogModuleInfo* gLogModule;
00189 
00190 static PRLogModuleInfo* gFrameVerifyTreeLogModuleInfo;
00191 
00192 static PRBool gFrameVerifyTreeEnable = PRBool(0x55);
00193 
00194 PRBool
00195 nsIFrameDebug::GetVerifyTreeEnable()
00196 {
00197   if (gFrameVerifyTreeEnable == PRBool(0x55)) {
00198     if (nsnull == gFrameVerifyTreeLogModuleInfo) {
00199       gFrameVerifyTreeLogModuleInfo = PR_NewLogModule("frameverifytree");
00200       gFrameVerifyTreeEnable = 0 != gFrameVerifyTreeLogModuleInfo->level;
00201       printf("Note: frameverifytree is %sabled\n",
00202              gFrameVerifyTreeEnable ? "en" : "dis");
00203     }
00204   }
00205   return gFrameVerifyTreeEnable;
00206 }
00207 
00208 void
00209 nsIFrameDebug::SetVerifyTreeEnable(PRBool aEnabled)
00210 {
00211   gFrameVerifyTreeEnable = aEnabled;
00212 }
00213 
00214 static PRLogModuleInfo* gStyleVerifyTreeLogModuleInfo;
00215 
00216 static PRBool gStyleVerifyTreeEnable = PRBool(0x55);
00217 
00218 PRBool
00219 nsIFrameDebug::GetVerifyStyleTreeEnable()
00220 {
00221   if (gStyleVerifyTreeEnable == PRBool(0x55)) {
00222     if (nsnull == gStyleVerifyTreeLogModuleInfo) {
00223       gStyleVerifyTreeLogModuleInfo = PR_NewLogModule("styleverifytree");
00224       gStyleVerifyTreeEnable = 0 != gStyleVerifyTreeLogModuleInfo->level;
00225       printf("Note: styleverifytree is %sabled\n",
00226              gStyleVerifyTreeEnable ? "en" : "dis");
00227     }
00228   }
00229   return gStyleVerifyTreeEnable;
00230 }
00231 
00232 void
00233 nsIFrameDebug::SetVerifyStyleTreeEnable(PRBool aEnabled)
00234 {
00235   gStyleVerifyTreeEnable = aEnabled;
00236 }
00237 
00238 PRLogModuleInfo*
00239 nsIFrameDebug::GetLogModuleInfo()
00240 {
00241   if (nsnull == gLogModule) {
00242     gLogModule = PR_NewLogModule("frame");
00243   }
00244   return gLogModule;
00245 }
00246 
00247 void
00248 nsIFrameDebug::RootFrameList(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
00249 {
00250   if((nsnull == aPresContext) || (nsnull == out))
00251     return;
00252 
00253   nsIPresShell *shell = aPresContext->GetPresShell();
00254   if (nsnull != shell) {
00255     nsIFrame* frame = shell->FrameManager()->GetRootFrame();
00256     if(nsnull != frame) {
00257       nsIFrameDebug* debugFrame;
00258       nsresult rv;
00259       rv = frame->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**)&debugFrame);
00260       if(NS_SUCCEEDED(rv))
00261         debugFrame->List(aPresContext, out, aIndent);
00262     }
00263   }
00264 }
00265 #endif
00266 // end nsIFrameDebug
00267 
00268 
00269 // frame image selection drawing service implementation
00270 class SelectionImageService : public nsISelectionImageService
00271 {
00272 public:
00273   SelectionImageService();
00274   virtual ~SelectionImageService();
00275   NS_DECL_ISUPPORTS
00276   NS_DECL_NSISELECTIONIMAGESERVICE
00277 private:
00278   nsresult CreateImage(nscolor aImageColor, imgIContainer *aContainer);
00279   nsCOMPtr<imgIContainer> mContainer;
00280   nsCOMPtr<imgIContainer> mDisabledContainer;
00281 };
00282 
00283 NS_IMPL_ISUPPORTS1(SelectionImageService, nsISelectionImageService)
00284 
00285 SelectionImageService::SelectionImageService()
00286 {
00287 }
00288 
00289 SelectionImageService::~SelectionImageService()
00290 {
00291 }
00292 
00293 NS_IMETHODIMP
00294 SelectionImageService::GetImage(PRInt16 aSelectionValue, imgIContainer **aContainer)
00295 {
00296   *aContainer = nsnull;
00297 
00298   nsCOMPtr<imgIContainer>* container = &mContainer;
00299   nsILookAndFeel::nsColorID colorID;
00300   if (aSelectionValue == nsISelectionController::SELECTION_ON) {
00301     colorID = nsILookAndFeel::eColor_TextSelectBackground;
00302   } else if (aSelectionValue == nsISelectionController::SELECTION_ATTENTION) {
00303     colorID = nsILookAndFeel::eColor_TextSelectBackgroundAttention;
00304   } else {
00305     container = &mDisabledContainer;
00306     colorID = nsILookAndFeel::eColor_TextSelectBackgroundDisabled;
00307   }
00308 
00309   if (!*container) {
00310     nsresult result;
00311     *container = do_CreateInstance("@mozilla.org/image/container;1", &result);
00312     if (NS_FAILED(result))
00313       return result;
00314 
00315     nscolor color = NS_RGB(255, 255, 255);
00316     nsCOMPtr<nsILookAndFeel> look = do_GetService(kLookAndFeelCID);
00317     if (look)
00318       look->GetColor(colorID, color);
00319     CreateImage(color, *container);
00320   }
00321 
00322   *aContainer = *container; 
00323   NS_ADDREF(*aContainer);
00324   return NS_OK;
00325 }
00326 
00327 NS_IMETHODIMP
00328 SelectionImageService::Reset()
00329 {
00330   mContainer = 0;
00331   mDisabledContainer = 0;
00332   return NS_OK;
00333 }
00334 
00335 #define SEL_IMAGE_WIDTH 32
00336 #define SEL_IMAGE_HEIGHT 32
00337 #define SEL_ALPHA_AMOUNT 128
00338 
00339 nsresult
00340 SelectionImageService::CreateImage(nscolor aImageColor, imgIContainer *aContainer)
00341 {
00342   if (aContainer)
00343   {
00344     nsresult result = aContainer->Init(SEL_IMAGE_WIDTH,SEL_IMAGE_HEIGHT,nsnull);
00345     if (NS_SUCCEEDED(result))
00346     {
00347       nsCOMPtr<gfxIImageFrame> image = do_CreateInstance("@mozilla.org/gfx/image/frame;2",&result);
00348       if (NS_SUCCEEDED(result) && image)
00349       {
00350         image->Init(0, 0, SEL_IMAGE_WIDTH, SEL_IMAGE_HEIGHT, gfxIFormats::RGB_A8, 24);
00351         aContainer->AppendFrame(image);
00352 
00353         PRUint32 bpr, abpr;
00354         image->GetImageBytesPerRow(&bpr);
00355         image->GetAlphaBytesPerRow(&abpr);
00356 
00357         //its better to temporarily go after heap than put big data on stack
00358         unsigned char *row_data = (unsigned char *)malloc(bpr);
00359         if (!row_data)
00360           return NS_ERROR_OUT_OF_MEMORY;
00361         unsigned char *alpha = (unsigned char *)malloc(abpr);
00362         if (!alpha)
00363         {
00364           free (row_data);
00365           return NS_ERROR_OUT_OF_MEMORY;
00366         }
00367         unsigned char *data = row_data;
00368 
00369         PRInt16 i;
00370         for (i = 0; i < SEL_IMAGE_WIDTH; i++)
00371         {
00372 #if defined(XP_WIN) || defined(XP_OS2)
00373           *data++ = NS_GET_B(aImageColor);
00374           *data++ = NS_GET_G(aImageColor);
00375           *data++ = NS_GET_R(aImageColor);
00376 #else
00377 #if defined(XP_MAC) || defined(XP_MACOSX)
00378           *data++ = 0;
00379 #endif
00380           *data++ = NS_GET_R(aImageColor);
00381           *data++ = NS_GET_G(aImageColor);
00382           *data++ = NS_GET_B(aImageColor);
00383 #endif
00384         }
00385 
00386         memset((void *)alpha, SEL_ALPHA_AMOUNT, abpr);
00387 
00388         for (i = 0; i < SEL_IMAGE_HEIGHT; i++)
00389         {
00390           image->SetAlphaData(alpha, abpr, i*abpr);
00391           image->SetImageData(row_data,  bpr, i*bpr);
00392         }
00393         free(row_data);
00394         free(alpha);
00395         return NS_OK;
00396       }
00397     } 
00398   }
00399   return NS_ERROR_FAILURE;
00400 }
00401 
00402 
00403 nsresult NS_NewSelectionImageService(nsISelectionImageService** aResult)
00404 {
00405   *aResult = new SelectionImageService;
00406   if (!*aResult)
00407     return NS_ERROR_OUT_OF_MEMORY;
00408   NS_ADDREF(*aResult);
00409   return NS_OK;
00410 }
00411 
00412 
00413 //end selection service
00414 
00415 // a handy utility to set font
00416 void SetFontFromStyle(nsIRenderingContext* aRC, nsStyleContext* aSC) 
00417 {
00418   const nsStyleFont* font = aSC->GetStyleFont();
00419   const nsStyleVisibility* visibility = aSC->GetStyleVisibility();
00420 
00421   aRC->SetFont(font->mFont, visibility->mLangGroup);
00422 }
00423 
00424 nsresult
00425 NS_NewEmptyFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
00426 {
00427   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00428   if (nsnull == aNewFrame) {
00429     return NS_ERROR_NULL_POINTER;
00430   }
00431   nsFrame* it = new (aPresShell) nsFrame;
00432   if (nsnull == it) {
00433     return NS_ERROR_OUT_OF_MEMORY;
00434   }
00435   *aNewFrame = it;
00436   return NS_OK;
00437 }
00438 
00439 MOZ_DECL_CTOR_COUNTER(nsFrame)
00440 
00441 // Overloaded new operator. Initializes the memory to 0 and relies on an arena
00442 // (which comes from the presShell) to perform the allocation.
00443 void* 
00444 nsFrame::operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW
00445 {
00446   // Check the recycle list first.
00447   void* result = aPresShell->AllocateFrame(sz);
00448   
00449   if (result) {
00450     memset(result, 0, sz);
00451   }
00452 
00453   return result;
00454 }
00455 
00456 // Overridden to prevent the global delete from being called, since the memory
00457 // came out of an nsIArena instead of the global delete operator's heap.
00458 void 
00459 nsFrame::operator delete(void* aPtr, size_t sz)
00460 {
00461   // Don't let the memory be freed, since it will be recycled
00462   // instead. Don't call the global operator delete.
00463 
00464   // Stash the size of the object in the first four bytes of the
00465   // freed up memory.  The Destroy method can then use this information
00466   // to recycle the object.
00467   size_t* szPtr = (size_t*)aPtr;
00468   *szPtr = sz;
00469 }
00470 
00471 
00472 nsFrame::nsFrame()
00473 {
00474   MOZ_COUNT_CTOR(nsFrame);
00475 
00476   mState = NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY;
00477 }
00478 
00479 nsFrame::~nsFrame()
00480 {
00481   MOZ_COUNT_DTOR(nsFrame);
00482 
00483   NS_IF_RELEASE(mContent);
00484   if (mStyleContext)
00485     mStyleContext->Release();
00486 }
00487 
00489 // nsISupports
00490 
00491 nsresult nsFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
00492 {
00493   NS_PRECONDITION(aInstancePtr, "null out param");
00494 
00495 #ifdef DEBUG
00496   if (aIID.Equals(NS_GET_IID(nsIFrameDebug))) {
00497     *aInstancePtr = NS_STATIC_CAST(void*,NS_STATIC_CAST(nsIFrameDebug*,this));
00498     return NS_OK;
00499   }
00500 #endif
00501 
00502   if (aIID.Equals(NS_GET_IID(nsIFrame)) ||
00503       aIID.Equals(NS_GET_IID(nsISupports))) {
00504     *aInstancePtr = NS_STATIC_CAST(void*,NS_STATIC_CAST(nsIFrame*,this));
00505     return NS_OK;
00506   }
00507 
00508   *aInstancePtr = nsnull;
00509   return NS_NOINTERFACE;
00510 }
00511 
00512 nsrefcnt nsFrame::AddRef(void)
00513 {
00514   NS_WARNING("not supported for frames");
00515   return 1;
00516 }
00517 
00518 nsrefcnt nsFrame::Release(void)
00519 {
00520   NS_WARNING("not supported for frames");
00521   return 1;
00522 }
00523 
00525 // nsIFrame
00526 
00527 NS_IMETHODIMP
00528 nsFrame::Init(nsPresContext*  aPresContext,
00529               nsIContent*      aContent,
00530               nsIFrame*        aParent,
00531               nsStyleContext*  aContext,
00532               nsIFrame*        aPrevInFlow)
00533 {
00534   mContent = aContent;
00535   mParent = aParent;
00536 
00537   if (aContent) {
00538     NS_ADDREF(aContent);
00539     aContent->SetMayHaveFrame(PR_TRUE);
00540     NS_ASSERTION(mContent->MayHaveFrame(), "SetMayHaveFrame failed?");
00541   }
00542 
00543   if (aPrevInFlow) {
00544     // Make sure the general flags bits are the same
00545     nsFrameState state = aPrevInFlow->GetStateBits();
00546 
00547     // Make bits that are currently off (see constructor) the same:
00548     mState |= state & (NS_FRAME_REPLACED_ELEMENT |
00549                        NS_FRAME_SELECTED_CONTENT |
00550                        NS_FRAME_INDEPENDENT_SELECTION |
00551                        NS_FRAME_IS_SPECIAL);
00552   }
00553   if (mParent) {
00554     nsFrameState state = mParent->GetStateBits();
00555 
00556     // Make bits that are currently off (see constructor) the same:
00557     mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
00558                        NS_FRAME_GENERATED_CONTENT);
00559   }
00560   SetStyleContext(aPresContext, aContext);
00561 
00562   if (IsBoxWrapped())
00563     InitBoxMetrics(PR_FALSE);
00564 
00565   return NS_OK;
00566 }
00567 
00568 NS_IMETHODIMP nsFrame::SetInitialChildList(nsPresContext* aPresContext,
00569                                            nsIAtom*        aListName,
00570                                            nsIFrame*       aChildList)
00571 {
00572   // XXX This shouldn't be getting called at all, but currently is for backwards
00573   // compatility reasons...
00574 #if 0
00575   NS_ERROR("not a container");
00576   return NS_ERROR_UNEXPECTED;
00577 #else
00578   NS_ASSERTION(nsnull == aChildList, "not a container");
00579   return NS_OK;
00580 #endif
00581 }
00582 
00583 NS_IMETHODIMP
00584 nsFrame::AppendFrames(nsIAtom*        aListName,
00585                       nsIFrame*       aFrameList)
00586 {
00587   NS_PRECONDITION(PR_FALSE, "not a container");
00588   return NS_ERROR_UNEXPECTED;
00589 }
00590 
00591 NS_IMETHODIMP
00592 nsFrame::InsertFrames(nsIAtom*        aListName,
00593                       nsIFrame*       aPrevFrame,
00594                       nsIFrame*       aFrameList)
00595 {
00596   NS_PRECONDITION(PR_FALSE, "not a container");
00597   return NS_ERROR_UNEXPECTED;
00598 }
00599 
00600 NS_IMETHODIMP
00601 nsFrame::RemoveFrame(nsIAtom*        aListName,
00602                      nsIFrame*       aOldFrame)
00603 {
00604   NS_PRECONDITION(PR_FALSE, "not a container");
00605   return NS_ERROR_UNEXPECTED;
00606 }
00607 
00608 NS_IMETHODIMP
00609 nsFrame::ReplaceFrame(nsIAtom*        aListName,
00610                       nsIFrame*       aOldFrame,
00611                       nsIFrame*       aNewFrame)
00612 {
00613   NS_PRECONDITION(PR_FALSE, "not a container");
00614   return NS_ERROR_UNEXPECTED;
00615 }
00616 
00617 NS_IMETHODIMP
00618 nsFrame::Destroy(nsPresContext* aPresContext)
00619 {
00620   // Get the view pointer now before the frame properties disappear
00621   // when we call NotifyDestroyingFrame()
00622   nsIView* view = GetView();
00623 
00624   nsIPresShell *shell = aPresContext->GetPresShell();
00625   if (shell) {
00626     if (mState & NS_FRAME_OUT_OF_FLOW) {
00627       nsPlaceholderFrame* placeholder
00628         = shell->FrameManager()->GetPlaceholderFrameFor(this);
00629       if (placeholder) {
00630         NS_WARNING("Deleting out of flow without tearing down placeholder relationship");
00631         if (placeholder->GetOutOfFlowFrame()) {
00632           NS_ASSERTION(placeholder->GetOutOfFlowFrame() == this,
00633                        "no-one told the frame manager about this");
00634           shell->FrameManager()->UnregisterPlaceholderFrame(placeholder);
00635           placeholder->SetOutOfFlowFrame(nsnull);
00636         }
00637       }
00638     }
00639 
00640     shell->NotifyDestroyingFrame(this);
00641 
00642     if ((mState & NS_FRAME_EXTERNAL_REFERENCE) ||
00643         (mState & NS_FRAME_SELECTED_CONTENT)) {
00644       shell->ClearFrameRefs(this);
00645     }
00646   }
00647 
00648   //XXX Why is this done in nsFrame instead of some frame class
00649   // that actually loads images?
00650   aPresContext->StopImagesFor(this);
00651 
00652   if (view) {
00653     // Break association between view and frame
00654     view->SetClientData(nsnull);
00655     
00656     // Destroy the view
00657     view->Destroy();
00658   }
00659 
00660   // Deleting the frame doesn't really free the memory, since we're using an
00661   // arena for allocation, but we will get our destructors called.
00662   delete this;
00663 
00664   // Now that we're totally cleaned out, we need to add ourselves to the presshell's
00665   // recycler.
00666   size_t* sz = (size_t*)this;
00667   shell->FreeFrame(*sz, (void*)this);
00668 
00669   return NS_OK;
00670 }
00671 
00672 NS_IMETHODIMP
00673 nsFrame::GetOffsets(PRInt32 &aStart, PRInt32 &aEnd) const
00674 {
00675   aStart = 0;
00676   aEnd = 0;
00677   return NS_OK;
00678 }
00679 
00680 // Subclass hook for style post processing
00681 NS_IMETHODIMP nsFrame::DidSetStyleContext(nsPresContext* aPresContext)
00682 {
00683   return NS_OK;
00684 }
00685 
00686 NS_IMETHODIMP  nsFrame::CalcBorderPadding(nsMargin& aBorderPadding) const {
00687   NS_ASSERTION(mStyleContext!=nsnull,"null style context");
00688   if (mStyleContext) {
00689     nsStyleBorderPadding bpad;
00690     mStyleContext->GetBorderPaddingFor(bpad);
00691     if (!bpad.GetBorderPadding(aBorderPadding)) {
00692       const nsStylePadding* paddingStyle = GetStylePadding();
00693       paddingStyle->CalcPaddingFor(this, aBorderPadding);
00694       const nsStyleBorder* borderStyle = GetStyleBorder();
00695       aBorderPadding += borderStyle->GetBorder();
00696     }
00697     return NS_OK;
00698   }
00699   return NS_ERROR_FAILURE;
00700 }
00701 
00702 nsStyleContext*
00703 nsFrame::GetAdditionalStyleContext(PRInt32 aIndex) const
00704 {
00705   NS_PRECONDITION(aIndex >= 0, "invalid index number");
00706   return nsnull;
00707 }
00708 
00709 void
00710 nsFrame::SetAdditionalStyleContext(PRInt32 aIndex, 
00711                                    nsStyleContext* aStyleContext)
00712 {
00713   NS_PRECONDITION(aIndex >= 0, "invalid index number");
00714 }
00715 
00716 // Child frame enumeration
00717 
00718 nsIAtom*
00719 nsFrame::GetAdditionalChildListName(PRInt32 aIndex) const
00720 {
00721   NS_PRECONDITION(aIndex >= 0, "invalid index number");
00722   return nsnull;
00723 }
00724 
00725 nsIFrame*
00726 nsFrame::GetFirstChild(nsIAtom* aListName) const
00727 {
00728   return nsnull;
00729 }
00730 
00731 static nsIFrame*
00732 GetActiveSelectionFrame(nsIFrame* aFrame)
00733 {
00734   nsIView* mouseGrabber;
00735   aFrame->GetPresContext()->GetViewManager()->GetMouseEventGrabber(mouseGrabber);
00736   if (mouseGrabber) {
00737     nsIFrame* activeFrame = nsLayoutUtils::GetFrameFor(mouseGrabber);
00738     if (activeFrame) {
00739       return activeFrame;
00740     }
00741   }
00742     
00743   return aFrame;
00744 }
00745 
00746 PRInt16
00747 nsFrame::DisplaySelection(nsPresContext* aPresContext, PRBool isOkToTurnOn)
00748 {
00749   PRInt16 selType = nsISelectionController::SELECTION_OFF;
00750 
00751   nsCOMPtr<nsISelectionController> selCon;
00752   nsresult result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
00753   if (NS_SUCCEEDED(result) && selCon) {
00754     result = selCon->GetDisplaySelection(&selType);
00755     if (NS_SUCCEEDED(result) && (selType != nsISelectionController::SELECTION_OFF)) {
00756       // Check whether style allows selection.
00757       PRBool selectable;
00758       IsSelectable(&selectable, nsnull);
00759       if (!selectable) {
00760         selType = nsISelectionController::SELECTION_OFF;
00761         isOkToTurnOn = PR_FALSE;
00762       }
00763     }
00764     if (isOkToTurnOn && (selType == nsISelectionController::SELECTION_OFF)) {
00765       selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
00766       selType = nsISelectionController::SELECTION_ON;
00767     }
00768   }
00769   return selType;
00770 }
00771 
00772 void
00773 nsFrame::SetOverflowClipRect(nsIRenderingContext& aRenderingContext)
00774 {
00775   // 'overflow-clip' only applies to block-level elements and replaced
00776   // elements that have 'overflow' set to 'hidden', and it is relative
00777   // to the content area and applies to content only (not border or background)
00778   const nsStyleBorder* borderStyle = GetStyleBorder();
00779   const nsStylePadding* paddingStyle = GetStylePadding();
00780   
00781   // Start with the 'auto' values and then factor in user specified values
00782   nsRect  clipRect(0, 0, mRect.width, mRect.height);
00783 
00784   // XXX We don't support the 'overflow-clip' property yet, so just use the
00785   // content area (which is the default value) as the clip shape
00786 
00787   clipRect.Deflate(borderStyle->GetBorder());
00788   // XXX We need to handle percentage padding
00789   nsMargin padding;
00790   if (paddingStyle->GetPadding(padding)) {
00791     clipRect.Deflate(padding);
00792   }
00793 #ifdef DEBUG
00794   else {
00795     NS_WARNING("Percentage padding and CLIP overflow don't mix yet");
00796   }
00797 #endif
00798 
00799   // Set updated clip-rect into the rendering context
00800   aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect);
00801 }
00802 
00803 /********************************************************
00804 * Refreshes each content's frame
00805 *********************************************************/
00806 
00807 NS_IMETHODIMP
00808 nsFrame::Paint(nsPresContext*      aPresContext,
00809                nsIRenderingContext& aRenderingContext,
00810                const nsRect&        aDirtyRect,
00811                nsFramePaintLayer    aWhichLayer,
00812                PRUint32             aFlags)
00813 {
00814   if (aWhichLayer != NS_FRAME_PAINT_LAYER_FOREGROUND)
00815     return NS_OK;
00816   
00817   nsresult result; 
00818   nsIPresShell *shell = aPresContext->PresShell();
00819 
00820   PRInt16 displaySelection = nsISelectionDisplay::DISPLAY_ALL;
00821   if (!(aFlags & nsISelectionDisplay::DISPLAY_IMAGES))
00822   {
00823     result = shell->GetSelectionFlags(&displaySelection);
00824     if (NS_FAILED(result))
00825       return result;
00826     if (!(displaySelection & nsISelectionDisplay::DISPLAY_FRAMES))
00827       return NS_OK;
00828   }
00829 
00830 //check frame selection state
00831   PRBool isSelected;
00832   isSelected = (GetStateBits() & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
00833 //if not selected then return 
00834   if (!isSelected)
00835     return NS_OK; //nothing to do
00836 
00837 //get the selection controller
00838   nsCOMPtr<nsISelectionController> selCon;
00839   result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
00840   PRInt16 selectionValue;
00841   selCon->GetDisplaySelection(&selectionValue);
00842   displaySelection = selectionValue > nsISelectionController::SELECTION_HIDDEN;
00843 //check display selection state.
00844   if (!displaySelection)
00845     return NS_OK; //if frame does not allow selection. do nothing
00846 
00847 
00848   nsIContent *newContent = mContent->GetParent();
00849 
00850   //check to see if we are anonymous content
00851   PRInt32 offset = 0;
00852   if (newContent) {
00853     // XXXbz there has GOT to be a better way of determining this!
00854     offset = newContent->IndexOf(mContent);
00855   }
00856 
00857   SelectionDetails *details;
00858   if (NS_SUCCEEDED(result) && shell)
00859   {
00860     nsCOMPtr<nsIFrameSelection> frameSelection;
00861     if (NS_SUCCEEDED(result) && selCon)
00862     {
00863       frameSelection = do_QueryInterface(selCon); //this MAY implement
00864     }
00865     if (!frameSelection)
00866       frameSelection = shell->FrameSelection();
00867     result = frameSelection->LookUpSelection(newContent, offset, 
00868                                              1, &details, PR_FALSE);//look up to see what selection(s) are on this frame
00869   }
00870   
00871   if (details)
00872   {
00873     nsRect rect = GetRect();
00874     rect.width-=2;
00875     rect.height-=2;
00876     rect.x=1; //we are in the coordinate system of the frame now with regards to the rendering context.
00877     rect.y=1;
00878 
00879     nsCOMPtr<nsISelectionImageService> imageService;
00880     imageService = do_GetService(kSelectionImageService, &result);
00881     if (NS_SUCCEEDED(result) && imageService)
00882     {
00883       nsCOMPtr<imgIContainer> container;
00884       imageService->GetImage(selectionValue, getter_AddRefs(container));
00885       if (container)
00886       {
00887         nsRect rect(0, 0, mRect.width, mRect.height);
00888         rect.IntersectRect(rect,aDirtyRect);
00889         aRenderingContext.DrawTile(container,0,0,&rect);
00890       }
00891     }
00892 
00893     
00894     
00895     SelectionDetails *deletingDetails = details;
00896     while ((deletingDetails = details->mNext) != nsnull) {
00897       delete details;
00898       details = deletingDetails;
00899     }
00900     delete details;
00901   }
00902   return NS_OK;
00903 }
00904 
00905 void
00906 nsFrame::PaintSelf(nsPresContext*      aPresContext,
00907                    nsIRenderingContext& aRenderingContext,
00908                    const nsRect&        aDirtyRect,
00909                    PRIntn               aSkipSides,
00910                    PRBool               aUsePrintBackgroundSettings)
00911 {
00912   // The visibility check belongs here since child elements have the
00913   // opportunity to override the visibility property and display even if
00914   // their parent is hidden.
00915 
00916   PRBool isVisible;
00917   if (mRect.height == 0 || mRect.width == 0 ||
00918       NS_FAILED(IsVisibleForPainting(aPresContext, aRenderingContext,
00919                                      PR_TRUE, &isVisible)) ||
00920       !isVisible) {
00921     return;
00922   }
00923 
00924   // Paint our background and border
00925   const nsStyleBorder* border = GetStyleBorder();
00926   const nsStylePadding* padding = GetStylePadding();
00927   const nsStyleOutline* outline = GetStyleOutline();
00928 
00929   nsRect rect(0, 0, mRect.width, mRect.height);
00930   nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
00931                                   aDirtyRect, rect, *border, *padding,
00932                                   aUsePrintBackgroundSettings);
00933   nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
00934                               aDirtyRect, rect, *border, mStyleContext,
00935                               aSkipSides);
00936   nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this,
00937                                aDirtyRect, rect, *border, *outline,
00938                                mStyleContext, 0);
00939 }
00940 
00941 nsresult
00942 nsIFrame::CreateWidgetForView(nsIView* aView)
00943 {
00944   return aView->CreateWidget(kWidgetCID);
00945 }
00946 
00950 NS_IMETHODIMP  
00951 nsFrame::GetContentForEvent(nsPresContext* aPresContext,
00952                             nsEvent* aEvent,
00953                             nsIContent** aContent)
00954 {
00955   *aContent = GetContent();
00956   NS_IF_ADDREF(*aContent);
00957   return NS_OK;
00958 }
00959 
00960 void
00961 nsFrame::FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent)
00962 {
00963   nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aContent ? aContent : mContent);
00964   
00965   if (domNode) {
00966     nsPLDOMEvent *event = new nsPLDOMEvent(domNode, aDOMEventName);
00967     if (event && NS_FAILED(event->PostDOMEvent())) {
00968       PL_DestroyEvent(event);
00969     }
00970   }
00971 }
00972 
00976 NS_IMETHODIMP
00977 nsFrame::HandleEvent(nsPresContext* aPresContext, 
00978                      nsGUIEvent*     aEvent,
00979                      nsEventStatus*  aEventStatus)
00980 {
00981   switch (aEvent->message)
00982   {
00983   case NS_MOUSE_MOVE:
00984     {
00985       HandleDrag(aPresContext, aEvent, aEventStatus);
00986     }break;
00987   case NS_MOUSE_LEFT_BUTTON_DOWN:
00988     {
00989       HandlePress(aPresContext, aEvent, aEventStatus);
00990     }break;
00991   case NS_MOUSE_LEFT_BUTTON_UP:
00992     {
00993       HandleRelease(aPresContext, aEvent, aEventStatus);
00994     } break;
00995   default:
00996     break;
00997   }//end switch
00998   return NS_OK;
00999 }
01000 
01001 NS_IMETHODIMP
01002 nsFrame::GetDataForTableSelection(nsIFrameSelection *aFrameSelection, 
01003                                   nsIPresShell *aPresShell, nsMouseEvent *aMouseEvent, 
01004                                   nsIContent **aParentContent, PRInt32 *aContentOffset, PRInt32 *aTarget)
01005 {
01006   if (!aFrameSelection || !aPresShell || !aMouseEvent || !aParentContent || !aContentOffset || !aTarget)
01007     return NS_ERROR_NULL_POINTER;
01008 
01009   *aParentContent = nsnull;
01010   *aContentOffset = 0;
01011   *aTarget = 0;
01012 
01013   PRInt16 displaySelection;
01014   nsresult result = aPresShell->GetSelectionFlags(&displaySelection);
01015   if (NS_FAILED(result))
01016     return result;
01017 
01018   PRBool selectingTableCells = PR_FALSE;
01019   aFrameSelection->GetTableCellSelection(&selectingTableCells);
01020 
01021   // DISPLAY_ALL means we're in an editor.
01022   // If already in cell selection mode, 
01023   //  continue selecting with mouse drag or end on mouse up,
01024   //  or when using shift key to extend block of cells
01025   //  (Mouse down does normal selection unless Ctrl/Cmd is pressed)
01026   PRBool doTableSelection =
01027      displaySelection == nsISelectionDisplay::DISPLAY_ALL && selectingTableCells &&
01028      (aMouseEvent->message == NS_MOUSE_MOVE ||
01029       aMouseEvent->message == NS_MOUSE_LEFT_BUTTON_UP || 
01030       aMouseEvent->isShift);
01031 
01032   if (!doTableSelection)
01033   {  
01034     // In Browser, special 'table selection' key must be pressed for table selection
01035     // or when just Shift is pressed and we're already in table/cell selection mode
01036 #if defined(XP_MAC) || defined(XP_MACOSX)
01037     doTableSelection = aMouseEvent->isMeta || (aMouseEvent->isShift && selectingTableCells);
01038 #else
01039     doTableSelection = aMouseEvent->isControl || (aMouseEvent->isShift && selectingTableCells);
01040 #endif
01041   }
01042   if (!doTableSelection) 
01043     return NS_OK;
01044 
01045   // Get the cell frame or table frame (or parent) of the current content node
01046   nsIFrame *frame = this;
01047   PRBool foundCell = PR_FALSE;
01048   PRBool foundTable = PR_FALSE;
01049 
01050   // Get the limiting node to stop parent frame search
01051   nsCOMPtr<nsIContent> limiter;
01052   result = aFrameSelection->GetLimiter(getter_AddRefs(limiter));
01053 
01054   //We don't initiate row/col selection from here now,
01055   //  but we may in future
01056   //PRBool selectColumn = PR_FALSE;
01057   //PRBool selectRow = PR_FALSE;
01058 
01059   while (frame && NS_SUCCEEDED(result))
01060   {
01061     // Check for a table cell by querying to a known CellFrame interface
01062     nsITableCellLayout *cellElement;
01063     result = (frame)->QueryInterface(NS_GET_IID(nsITableCellLayout), (void **)&cellElement);
01064     if (NS_SUCCEEDED(result) && cellElement)
01065     {
01066       foundCell = PR_TRUE;
01067       //TODO: If we want to use proximity to top or left border
01068       //      for row and column selection, this is the place to do it
01069       break;
01070     }
01071     else
01072     {
01073       // If not a cell, check for table
01074       // This will happen when starting frame is the table or child of a table,
01075       //  such as a row (we were inbetween cells or in table border)
01076       nsITableLayout *tableElement;
01077       result = (frame)->QueryInterface(NS_GET_IID(nsITableLayout), (void **)&tableElement);
01078       if (NS_SUCCEEDED(result) && tableElement)
01079       {
01080         foundTable = PR_TRUE;
01081         //TODO: How can we select row when along left table edge
01082         //  or select column when along top edge?
01083         break;
01084       } else {
01085         frame = frame->GetParent();
01086         result = NS_OK;
01087         // Stop if we have hit the selection's limiting content node
01088         if (frame && frame->GetContent() == limiter.get())
01089           break;
01090       }
01091     }
01092   }
01093   // We aren't in a cell or table
01094   if (!foundCell && !foundTable) return NS_OK;
01095 
01096   nsIContent* tableOrCellContent = frame->GetContent();
01097   if (!tableOrCellContent) return NS_ERROR_FAILURE;
01098 
01099   nsCOMPtr<nsIContent> parentContent = tableOrCellContent->GetParent();
01100   if (!parentContent) return NS_ERROR_FAILURE;
01101 
01102   PRInt32 offset = parentContent->IndexOf(tableOrCellContent);
01103   // Not likely?
01104   if (offset < 0) return NS_ERROR_FAILURE;
01105 
01106   // Everything is OK -- set the return values
01107   *aParentContent = parentContent;
01108   NS_ADDREF(*aParentContent);
01109 
01110   *aContentOffset = offset;
01111 
01112 #if 0
01113   if (selectRow)
01114     *aTarget = nsISelectionPrivate::TABLESELECTION_ROW;
01115   else if (selectColumn)
01116     *aTarget = nsISelectionPrivate::TABLESELECTION_COLUMN;
01117   else 
01118 #endif
01119   if (foundCell)
01120     *aTarget = nsISelectionPrivate::TABLESELECTION_CELL;
01121   else if (foundTable)
01122     *aTarget = nsISelectionPrivate::TABLESELECTION_TABLE;
01123 
01124   return NS_OK;
01125 }
01126 
01127 /*
01128 NS_IMETHODIMP
01129 nsFrame::FrameOrParentHasSpecialSelectionStyle(PRUint8 aSelectionStyle, nsIFrame* *foundFrame)
01130 {
01131   nsIFrame* thisFrame = this;
01132   
01133   while (thisFrame)
01134   {
01135     if (thisFrame->GetStyleUserInterface()->mUserSelect == aSelectionStyle)
01136     {
01137       *foundFrame = thisFrame;
01138       return NS_OK;
01139     }
01140   
01141     thisFrame = thisFrame->GetParent();
01142   }
01143   
01144   *foundFrame = nsnull;
01145   return NS_OK;
01146 }
01147 */
01148 
01149 NS_IMETHODIMP
01150 nsFrame::IsSelectable(PRBool* aSelectable, PRUint8* aSelectStyle) const
01151 {
01152   if (!aSelectable) //its ok if aSelectStyle is null
01153     return NS_ERROR_NULL_POINTER;
01154 
01155   // Like 'visibility', we must check all the parents: if a parent
01156   // is not selectable, none of its children is selectable.
01157   //
01158   // The -moz-all value acts similarly: if a frame has 'user-select:-moz-all',
01159   // all its children are selectable, even those with 'user-select:none'.
01160   //
01161   // As a result, if 'none' and '-moz-all' are not present in the frame hierarchy,
01162   // aSelectStyle returns the first style that is not AUTO. If these values
01163   // are present in the frame hierarchy, aSelectStyle returns the style of the
01164   // topmost parent that has either 'none' or '-moz-all'.
01165   //
01166   // For instance, if the frame hierarchy is:
01167   //    AUTO     -> _MOZ_ALL -> NONE -> TEXT,     the returned value is _MOZ_ALL
01168   //    TEXT     -> NONE     -> AUTO -> _MOZ_ALL, the returned value is NONE
01169   //    _MOZ_ALL -> TEXT     -> AUTO -> AUTO,     the returned value is _MOZ_ALL
01170   //    AUTO     -> CELL     -> TEXT -> AUTO,     the returned value is TEXT
01171   //
01172   PRUint8 selectStyle  = NS_STYLE_USER_SELECT_AUTO;
01173   nsIFrame* frame      = (nsIFrame*)this;
01174 
01175   while (frame) {
01176     const nsStyleUIReset* userinterface = frame->GetStyleUIReset();
01177     switch (userinterface->mUserSelect) {
01178       case NS_STYLE_USER_SELECT_ALL:
01179       case NS_STYLE_USER_SELECT_NONE:
01180       case NS_STYLE_USER_SELECT_MOZ_ALL:
01181         // override the previous values
01182         selectStyle = userinterface->mUserSelect;
01183         break;
01184       default:
01185         // otherwise return the first value which is not 'auto'
01186         if (selectStyle == NS_STYLE_USER_SELECT_AUTO) {
01187           selectStyle = userinterface->mUserSelect;
01188         }
01189         break;
01190     }
01191     frame = frame->GetParent();
01192   }
01193 
01194   // convert internal values to standard values
01195   if (selectStyle == NS_STYLE_USER_SELECT_AUTO)
01196     selectStyle = NS_STYLE_USER_SELECT_TEXT;
01197   else
01198   if (selectStyle == NS_STYLE_USER_SELECT_MOZ_ALL)
01199     selectStyle = NS_STYLE_USER_SELECT_ALL;
01200   else
01201   if (selectStyle == NS_STYLE_USER_SELECT_MOZ_NONE)
01202     selectStyle = NS_STYLE_USER_SELECT_NONE;
01203 
01204   // return stuff
01205   if (aSelectable)
01206     *aSelectable = (selectStyle != NS_STYLE_USER_SELECT_NONE);
01207   if (aSelectStyle)
01208     *aSelectStyle = selectStyle;
01209   if (mState & NS_FRAME_GENERATED_CONTENT)
01210     *aSelectable = PR_FALSE;
01211   return NS_OK;
01212 }
01213 
01214 PRBool
01215 ContentContainsPoint(nsPresContext *aPresContext,
01216                      nsIContent *aContent,
01217                      nsPoint *aPoint,
01218                      nsIView *aRelativeView)
01219 {
01220   nsIPresShell *presShell = aPresContext->GetPresShell();
01221 
01222   if (!presShell) return PR_FALSE;
01223 
01224   nsIFrame *frame = nsnull;
01225 
01226   nsresult rv = presShell->GetPrimaryFrameFor(aContent, &frame);
01227 
01228   if (NS_FAILED(rv) || !frame) return PR_FALSE;
01229 
01230   nsIView *frameView = nsnull;
01231   nsPoint offsetPoint;
01232 
01233   // Get the view that contains the content's frame.
01234 
01235   rv = frame->GetOffsetFromView(offsetPoint, &frameView);
01236 
01237   if (NS_FAILED(rv) || !frameView) return PR_FALSE;
01238 
01239   // aPoint is relative to aRelativeView's upper left corner! Make sure
01240   // that our point is in the same view space our content frame's
01241   // rects are in.
01242 
01243   nsPoint point = *aPoint + aRelativeView->GetOffsetTo(frameView);
01244 
01245   // Now check to see if the point is within the bounds of the
01246   // content's primary frame, or any of it's continuation frames.
01247 
01248   while (frame) {
01249     // Get the frame's rect and make it relative to the
01250     // upper left corner of it's parent view.
01251 
01252     nsRect frameRect = frame->GetRect();
01253     frameRect.x = offsetPoint.x;
01254     frameRect.y = offsetPoint.y;
01255 
01256     if (frameRect.Contains(point)) {
01257       // point is within this frame's rect!
01258       return PR_TRUE;
01259     }
01260 
01261     frame = frame->GetNextInFlow();
01262 
01263   }
01264 
01265   return PR_FALSE;
01266 }
01267 
01271 NS_IMETHODIMP
01272 nsFrame::HandlePress(nsPresContext* aPresContext, 
01273                      nsGUIEvent*     aEvent,
01274                      nsEventStatus*  aEventStatus)
01275 {
01276   NS_ENSURE_ARG_POINTER(aEventStatus);
01277   if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
01278     return NS_OK;
01279   }
01280 
01281   //We often get out of sync state issues with mousedown events that
01282   //get interrupted by alerts/dialogs.
01283   //Check with the ESM to see if we should process this one
01284   PRBool eventOK;
01285   aPresContext->EventStateManager()->EventStatusOK(aEvent, &eventOK);
01286   if (!eventOK) 
01287     return NS_OK;
01288 
01289   nsresult rv;
01290   nsIPresShell *shell = aPresContext->GetPresShell();
01291   if (!shell)
01292     return NS_ERROR_FAILURE;
01293 
01294   // if we are in Navigator and the click is in a draggable node, we don't want
01295   // to start selection because we don't want to interfere with a potential
01296   // drag of said node and steal all its glory.
01297   PRInt16 isEditor = 0;
01298   shell->GetSelectionFlags ( &isEditor );
01299   //weaaak. only the editor can display frame selction not just text and images
01300   isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
01301 
01302   nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent;
01303   if (!isEditor && !keyEvent->isAlt) {
01304     
01305     for (nsIContent* content = mContent; content;
01306          content = content->GetParent()) {
01307       if ( nsContentUtils::ContentIsDraggable(content) ) {
01308         // coordinate stuff is the fix for bug #55921
01309         nsIView *dummyView = 0;
01310         nsRect frameRect = mRect;
01311         nsPoint offsetPoint;
01312 
01313         GetOffsetFromView(offsetPoint, &dummyView);
01314 
01315         frameRect.x = offsetPoint.x;
01316         frameRect.y = offsetPoint.y;
01317 
01318         if (frameRect.x <= aEvent->point.x && (frameRect.x + frameRect.width >= aEvent->point.x) &&
01319             frameRect.y <= aEvent->point.y && (frameRect.y + frameRect.height >= aEvent->point.y))
01320           return NS_OK;
01321       }
01322     }
01323   } // if browser, not editor
01324 
01325   // check whether style allows selection
01326   // if not, don't tell selection the mouse event even occurred.  
01327   PRBool  selectable;
01328   PRUint8 selectStyle;
01329   rv = IsSelectable(&selectable, &selectStyle);
01330   if (NS_FAILED(rv)) return rv;
01331   
01332   // check for select: none
01333   if (!selectable)
01334     return NS_OK;
01335 
01336   // When implementing NS_STYLE_USER_SELECT_ELEMENT, NS_STYLE_USER_SELECT_ELEMENTS and
01337   // NS_STYLE_USER_SELECT_TOGGLE, need to change this logic
01338   PRBool useFrameSelection = (selectStyle == NS_STYLE_USER_SELECT_TEXT);
01339 
01340   if (!IsMouseCaptured(aPresContext))
01341     CaptureMouse(aPresContext, PR_TRUE);
01342 
01343   PRInt16 displayresult = nsISelectionController::SELECTION_OFF;
01344   nsCOMPtr<nsISelectionController> selCon;
01345   rv = GetSelectionController(aPresContext, getter_AddRefs(selCon));
01346   //get the selection controller
01347   if (NS_SUCCEEDED(rv) && selCon) 
01348   {
01349     selCon->GetDisplaySelection(&displayresult);
01350     if (displayresult == nsISelectionController::SELECTION_OFF)
01351       return NS_OK;//nothing to do we cannot affect selection from here
01352   }
01353 
01354   //get the frame selection from sel controller
01355 
01356   // nsFrameState  state = GetStateBits();
01357   // if (state & NS_FRAME_INDEPENDENT_SELECTION) 
01358   nsCOMPtr<nsIFrameSelection> frameselection;
01359 
01360   if (useFrameSelection)
01361     frameselection = do_QueryInterface(selCon); //this MAY implement
01362 
01363   if (!frameselection)//if we must get it from the pres shell's
01364     frameselection = shell->FrameSelection();
01365 
01366   if (!frameselection)
01367     return NS_ERROR_FAILURE;
01368 
01369   nsMouseEvent *me = (nsMouseEvent *)aEvent;
01370 
01371 #if defined(XP_MAC) || defined(XP_MACOSX)
01372   if (me->isControl)
01373     return NS_OK;//short ciruit. hard coded for mac due to time restraints.
01374 #endif
01375     
01376   if (me->clickCount >1 )
01377   {
01378     rv = frameselection->SetMouseDownState( PR_TRUE );
01379   
01380     frameselection->SetMouseDoubleDown(PR_TRUE);
01381     return HandleMultiplePress(aPresContext, aEvent, aEventStatus);
01382   }
01383 
01384   nsCOMPtr<nsIContent> content;
01385   PRInt32 startOffset = 0, endOffset = 0;
01386   PRBool  beginFrameContent = PR_FALSE;
01387 
01388   rv = GetContentAndOffsetsFromPoint(aPresContext, aEvent->point, getter_AddRefs(content), startOffset, endOffset, beginFrameContent);
01389   // do we have CSS that changes selection behaviour?
01390   PRBool changeSelection = PR_FALSE;
01391   {
01392     nsCOMPtr<nsIContent>  selectContent;
01393     PRInt32   newStart, newEnd;
01394     if (NS_SUCCEEDED(frameselection->AdjustOffsetsFromStyle(this, &changeSelection, getter_AddRefs(selectContent), &newStart, &newEnd))
01395       && changeSelection)
01396     {
01397       content = selectContent;
01398       startOffset = newStart;
01399       endOffset = newEnd;
01400     }
01401   }
01402 
01403   if (NS_FAILED(rv))
01404     return rv;
01405 
01406   // Let Ctrl/Cmd+mouse down do table selection instead of drag initiation
01407   nsCOMPtr<nsIContent>parentContent;
01408   PRInt32  contentOffset;
01409   PRInt32 target;
01410   rv = GetDataForTableSelection(frameselection, shell, me, getter_AddRefs(parentContent), &contentOffset, &target);
01411   if (NS_SUCCEEDED(rv) && parentContent)
01412   {
01413     rv = frameselection->SetMouseDownState( PR_TRUE );
01414     if (NS_FAILED(rv)) return rv;
01415   
01416     return frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
01417   }
01418 
01419   PRBool supportsDelay = PR_FALSE;
01420 
01421   frameselection->GetDelayCaretOverExistingSelection(&supportsDelay);
01422   frameselection->SetDelayedCaretData(0);
01423 
01424   if (supportsDelay)
01425   {
01426     // Check if any part of this frame is selected, and if the
01427     // user clicked inside the selected region. If so, we delay
01428     // starting a new selection since the user may be trying to
01429     // drag the selected region to some other app.
01430 
01431     SelectionDetails *details = 0;
01432     PRBool isSelected = ((GetStateBits() & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT);
01433 
01434     if (isSelected)
01435     {
01436       rv = frameselection->LookUpSelection(content, 0, endOffset, &details, PR_FALSE);
01437 
01438       if (NS_FAILED(rv))
01439         return rv;
01440 
01441       //
01442       // If there are any details, check to see if the user clicked
01443       // within any selected region of the frame.
01444       //
01445 
01446       if (details)
01447       {
01448         SelectionDetails *curDetail = details;
01449 
01450         while (curDetail)
01451         {
01452           //
01453           // If the user clicked inside a selection, then just
01454           // return without doing anything. We will handle placing
01455           // the caret later on when the mouse is released. We ignore
01456           // the spellcheck selection.
01457           //
01458           if (curDetail->mType != nsISelectionController::SELECTION_SPELLCHECK &&
01459               curDetail->mStart <= startOffset && endOffset <= curDetail->mEnd)
01460           {
01461             delete details;
01462             rv = frameselection->SetMouseDownState( PR_FALSE );
01463 
01464             if (NS_FAILED(rv))
01465               return rv;
01466 
01467             return frameselection->SetDelayedCaretData(me);
01468           }
01469 
01470           curDetail = curDetail->mNext;
01471         }
01472 
01473         delete details;
01474       }
01475     }
01476   }
01477 
01478   rv = frameselection->SetMouseDownState( PR_TRUE );
01479 
01480   if (NS_FAILED(rv))
01481     return rv;
01482 
01483   rv = frameselection->HandleClick(content, startOffset , endOffset, me->isShift, PR_FALSE, beginFrameContent);
01484 
01485   if (NS_FAILED(rv))
01486     return rv;
01487 
01488   if (startOffset != endOffset)
01489     frameselection->MaintainSelection();
01490 
01491   if (isEditor && !me->isShift && (endOffset - startOffset) == 1)
01492   {
01493     // A single node is selected and we aren't extending an existing
01494     // selection, which means the user clicked directly on an object.
01495     // Check if the user clicked in a -moz-user-select:all subtree,
01496     // image, or hr. If so, we want to give the drag and drop
01497     // code a chance to execute so we need to turn off selection extension
01498     // when processing mouse move/drag events that follow this mouse
01499     // down event.
01500 
01501     PRBool disableDragSelect = PR_FALSE;
01502 
01503     if (changeSelection)
01504     {
01505       // The click hilited a -moz-user-select:all subtree.
01506       //
01507       // XXX: We really should be able to just do a:
01508       //
01509       //        disableDragSelect = PR_TRUE;
01510       //
01511       //      but we are working around the fact that in some cases,
01512       //      selection selects a -moz-user-select:all subtree even
01513       //      when the click was outside of the subtree. An example of
01514       //      this case would be when the subtree is at the end of a
01515       //      line and the user clicks to the right of it. In this case
01516       //      I would expect the caret to be placed next to the root of
01517       //      the subtree, but right now the whole subtree gets selected.
01518       //      This means that we have to do geometric frame containment
01519       //      checks on the point to see if the user truly clicked
01520       //      inside the subtree.
01521       
01522       nsIView *view = nsnull;
01523       nsPoint dummyPoint;
01524 
01525       // aEvent->point is relative to the upper left corner of the
01526       // frame's parent view. Unfortunately, the only way to get
01527       // the parent view is to call GetOffsetFromView().
01528 
01529       GetOffsetFromView(dummyPoint, &view);
01530 
01531       // Now check to see if the point is truly within the bounds
01532       // of any of the frames that make up the -moz-user-select:all subtree:
01533 
01534       if (view)
01535         disableDragSelect = ContentContainsPoint(aPresContext, content,
01536                                                  &aEvent->point, view);
01537     }
01538     else
01539     {
01540       // Check if click was in an image.
01541 
01542       nsIContent* frameContent = GetContent();
01543       nsCOMPtr<nsIDOMHTMLImageElement> img(do_QueryInterface(frameContent));
01544 
01545       disableDragSelect = img != nsnull;
01546 
01547       if (!img)
01548       {
01549         // Check if click was in an hr.
01550 
01551         nsCOMPtr<nsIDOMHTMLHRElement> hr(do_QueryInterface(frameContent));
01552         disableDragSelect = hr != nsnull;
01553       }
01554     }
01555 
01556     if (disableDragSelect)
01557     {
01558       // Click was in one of our draggable objects, so disable
01559       // selection extension during mouse moves.
01560 
01561       rv = frameselection->SetMouseDownState( PR_FALSE );
01562     }
01563   }
01564 
01565   return rv;
01566 }
01567  
01572 NS_IMETHODIMP
01573 nsFrame::HandleMultiplePress(nsPresContext* aPresContext, 
01574                              nsGUIEvent*     aEvent,
01575                              nsEventStatus*  aEventStatus)
01576 {
01577   NS_ENSURE_ARG_POINTER(aEventStatus);
01578   if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
01579     return NS_OK;
01580   }
01581 
01582   nsresult rv;
01583   if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
01584     return NS_OK;
01585   }
01586 
01587   // Find out whether we're doing line or paragraph selection.
01588   // Currently, triple-click selects line unless the user sets
01589   // browser.triple_click_selects_paragraph; quadruple-click
01590   // selects paragraph, if any platform actually implements it.
01591   PRBool selectPara = PR_FALSE;
01592   nsMouseEvent *me = (nsMouseEvent *)aEvent;
01593   if (!me) return NS_OK;
01594 
01595 #if 0 // Paragraph selection is currently broken - so disable it
01596   if (me->clickCount == 4)
01597     selectPara = PR_TRUE;
01598   else
01599 #endif
01600   if (me->clickCount == 3)
01601   {
01602     selectPara =
01603       nsContentUtils::GetBoolPref("browser.triple_click_selects_paragraph");
01604   }
01605   else
01606     return NS_OK;
01607 #ifdef DEBUG_akkana
01608   if (selectPara) printf("Selecting Paragraph\n");
01609   else printf("Selecting Line\n");
01610 #endif
01611 
01612   // Line or paragraph selection:
01613   PRInt32 startPos = 0;
01614   PRInt32 contentOffsetEnd = 0;
01615   nsCOMPtr<nsIContent> newContent;
01616   PRBool beginContent = PR_FALSE;
01617   rv = GetContentAndOffsetsFromPoint(aPresContext,
01618                                      aEvent->point,
01619                                      getter_AddRefs(newContent),
01620                                      startPos,
01621                                      contentOffsetEnd,
01622                                      beginContent);
01623   if (NS_FAILED(rv)) return rv;
01624   
01625   
01626   return PeekBackwardAndForward(selectPara ? eSelectParagraph
01627                                            : eSelectBeginLine,
01628                                 selectPara ? eSelectParagraph
01629                                            : eSelectEndLine,
01630                                 startPos, aPresContext, PR_TRUE);
01631 }
01632 
01633 NS_IMETHODIMP
01634 nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
01635                                 nsSelectionAmount aAmountForward,
01636                                 PRInt32 aStartPos,
01637                                 nsPresContext* aPresContext,
01638                                 PRBool aJumpLines)
01639 {
01640   nsCOMPtr<nsISelectionController> selcon;
01641   nsresult rv = GetSelectionController(aPresContext, getter_AddRefs(selcon));
01642   if (NS_FAILED(rv)) return rv;
01643 
01644   nsIPresShell *shell = aPresContext->GetPresShell();
01645   if (!shell || !selcon)
01646     return NS_ERROR_NOT_INITIALIZED;
01647 
01648   // Use peek offset one way then the other:
01649   nsCOMPtr<nsIContent> startContent;
01650   nsCOMPtr<nsIDOMNode> startNode;
01651   nsCOMPtr<nsIContent> endContent;
01652   nsCOMPtr<nsIDOMNode> endNode;
01653   nsPeekOffsetStruct startpos;
01654   startpos.SetData(shell,
01655                    0, 
01656                    aAmountBack,
01657                    eDirPrevious,
01658                    aStartPos,
01659                    PR_FALSE,
01660                    PR_TRUE,
01661                    aJumpLines,
01662                    PR_TRUE,  //limit on scrolled views
01663                    PR_FALSE);
01664   rv = PeekOffset(aPresContext, &startpos);
01665   if (NS_FAILED(rv))
01666     return rv;
01667   nsPeekOffsetStruct endpos;
01668   endpos.SetData(shell,
01669                  0, 
01670                  aAmountForward,
01671                  eDirNext,
01672                  aStartPos,
01673                  PR_FALSE,
01674                  PR_FALSE,
01675                  aJumpLines,
01676                  PR_TRUE,  //limit on scrolled views
01677                  PR_FALSE);
01678   rv = PeekOffset(aPresContext, &endpos);
01679   if (NS_FAILED(rv))
01680     return rv;
01681 
01682   endNode = do_QueryInterface(endpos.mResultContent, &rv);
01683   if (NS_FAILED(rv))
01684     return rv;
01685   startNode = do_QueryInterface(startpos.mResultContent, &rv);
01686   if (NS_FAILED(rv))
01687     return rv;
01688 
01689   nsCOMPtr<nsISelection> selection;
01690   if (NS_SUCCEEDED(selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
01691                                         getter_AddRefs(selection)))){
01692     rv = selection->Collapse(startNode,startpos.mContentOffset);
01693     if (NS_FAILED(rv))
01694       return rv;
01695     rv = selection->Extend(endNode,endpos.mContentOffset);
01696     if (NS_FAILED(rv))
01697       return rv;
01698   }
01699   //no release 
01700 
01701   // maintain selection
01702   nsCOMPtr<nsIFrameSelection> frameselection = do_QueryInterface(selcon); //this MAY implement
01703   if (!frameselection)
01704     frameselection = aPresContext->PresShell()->FrameSelection();
01705 
01706   return frameselection->MaintainSelection();
01707 }
01708 
01709 // Figure out which view we should point capturing at, given that drag started
01710 // in this frame.
01711 static nsIView* GetNearestCapturingView(nsIFrame* aFrame) {
01712   nsIView* view = nsnull;
01713   while (!(view = aFrame->GetMouseCapturer()) && aFrame->GetParent()) {
01714     aFrame = aFrame->GetParent();
01715   }
01716   if (!view) {
01717     // Use the root view. The root frame always has the root view.
01718     view = aFrame->GetView();
01719   }
01720   NS_ASSERTION(view, "No capturing view found");
01721   return view;
01722 }
01723 
01724 NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext, 
01725                                   nsGUIEvent*     aEvent,
01726                                   nsEventStatus*  aEventStatus)
01727 {
01728   PRBool  selectable;
01729   PRUint8 selectStyle;
01730   IsSelectable(&selectable, &selectStyle);
01731   if (!selectable)
01732     return NS_OK;
01733   if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
01734     return NS_OK;
01735   }
01736   nsIPresShell *presShell = aPresContext->PresShell();
01737 
01738   nsCOMPtr<nsIFrameSelection> frameselection;
01739   nsCOMPtr<nsISelectionController> selCon;
01740   
01741   nsresult result = GetSelectionController(aPresContext,
01742                                            getter_AddRefs(selCon));
01743   if (NS_SUCCEEDED(result) && selCon)
01744   {
01745     frameselection = do_QueryInterface(selCon); //this MAY implement
01746   }
01747   if (!frameselection)
01748     frameselection = presShell->FrameSelection();
01749 
01750   PRBool mouseDown = PR_FALSE;
01751   if (NS_SUCCEEDED(frameselection->GetMouseDownState(&mouseDown)) && !mouseDown)
01752     return NS_OK;            
01753 
01754   frameselection->StopAutoScrollTimer();
01755   // If we have capturing view, it must be ensured that |this| doesn't 
01756   // get deleted during HandleDrag.
01757   nsWeakFrame weakFrame = GetNearestCapturingView(this) ? this : nsnull;
01758 
01759   // Check if we are dragging in a table cell
01760   nsCOMPtr<nsIContent> parentContent;
01761   PRInt32 contentOffset;
01762   PRInt32 target;
01763   nsMouseEvent *me = (nsMouseEvent *)aEvent;
01764   result = GetDataForTableSelection(frameselection, presShell, me,
01765                                     getter_AddRefs(parentContent),
01766                                     &contentOffset, &target);      
01767 
01768   if (NS_SUCCEEDED(result) && parentContent)
01769     frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
01770   else
01771     frameselection->HandleDrag(aPresContext, this, aEvent->point);
01772 
01773   if (weakFrame) {
01774     nsIView* captureView = GetNearestCapturingView(this);
01775     if (captureView) {
01776       // Get the view that aEvent->point is relative to. This is disgusting.
01777       nsPoint dummyPoint;
01778       nsIView* eventView;
01779       GetOffsetFromView(dummyPoint, &eventView);
01780       nsPoint pt = aEvent->point + eventView->GetOffsetTo(captureView);
01781       frameselection->StartAutoScrollTimer(aPresContext, captureView, pt, 30);
01782     }
01783   }
01784 
01785   return NS_OK;
01786 }
01787 
01788 static void
01789 GetFrameSelectionFor(nsIFrame* aFrame, nsIFrameSelection** aFrameSel, nsISelectionController** aSelCon)
01790 {
01791   *aSelCon = nsnull;
01792   *aFrameSel = nsnull;
01793   nsresult result = aFrame->GetSelectionController(aFrame->GetPresContext(), aSelCon);
01794   if (NS_SUCCEEDED(result) && *aSelCon)
01795     CallQueryInterface(*aSelCon, aFrameSel);
01796   if (!*aFrameSel)
01797     NS_IF_ADDREF(*aFrameSel = aFrame->GetPresContext()->GetPresShell()->FrameSelection());
01798 }
01799 
01804 static nsresult
01805 HandleFrameSelection(nsIFrameSelection* aFrameSelection,
01806                      nsIContent*        aContent,
01807                      PRInt32            aStartOffset,
01808                      PRInt32            aEndOffset,
01809                      PRBool             aBeginFrameContent,
01810                      PRBool             aHandleTableSel,
01811                      PRInt32            aContentOffsetForTableSel,
01812                      PRInt32            aTargetForTableSel,
01813                      nsGUIEvent*        aEvent,
01814                      nsEventStatus*     aEventStatus)
01815 {
01816   if (!aFrameSelection) {
01817     return NS_OK;
01818   }
01819 
01820   nsresult rv = NS_OK;
01821 
01822   if (nsEventStatus_eConsumeNoDefault != *aEventStatus && aContent) {
01823     if (!aHandleTableSel) {
01824       nsMouseEvent* me = nsnull;
01825       aFrameSelection->GetDelayedCaretData(&me);
01826       if (!me) {
01827         return NS_ERROR_FAILURE;
01828       }
01829       // We are doing this to simulate what we would have done on HandlePress
01830       aFrameSelection->SetMouseDownState(PR_TRUE);
01831       rv = aFrameSelection->HandleClick(aContent, aStartOffset, aEndOffset,
01832                                         me->isShift, PR_FALSE,
01833                                         aBeginFrameContent);
01834       if (NS_FAILED(rv)) {
01835         return rv;
01836       }
01837     } else {
01838       aFrameSelection->SetMouseDownState(PR_FALSE);
01839       aFrameSelection->HandleTableSelection(aContent,
01840                                             aContentOffsetForTableSel,
01841                                             aTargetForTableSel,
01842                                             (nsMouseEvent *)aEvent);
01843       if (NS_FAILED(rv)) {
01844         return rv;
01845       }
01846     }
01847     aFrameSelection->SetDelayedCaretData(0);
01848   }
01849 
01850   aFrameSelection->SetMouseDownState(PR_FALSE);
01851   aFrameSelection->StopAutoScrollTimer();
01852   return NS_OK;
01853 }
01854 
01855 NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
01856                                      nsGUIEvent*    aEvent,
01857                                      nsEventStatus* aEventStatus)
01858 {
01859   nsIFrame* activeFrame = GetActiveSelectionFrame(this);
01860 
01861   // We can unconditionally stop capturing because
01862   // we should never be capturing when the mouse button is up
01863   CaptureMouse(aPresContext, PR_FALSE);
01864 
01865   PRBool selectionOff =
01866     (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF);
01867 
01868   nsCOMPtr<nsISelectionController> selCon;
01869   nsCOMPtr<nsIFrameSelection> frameselection;
01870   nsCOMPtr<nsIContent> content;
01871   PRInt32 contentOffsetForTableSel = 0;
01872   PRInt32 targetForTableSel = 0;
01873   PRBool handleTableSelection = PR_TRUE;
01874   PRInt32 startOffset = 0;
01875   PRInt32 endOffset = 0;
01876   PRBool beginFrameContent = PR_FALSE;
01877   nsresult rv = NS_OK;
01878 
01879   if (!selectionOff) {
01880     GetFrameSelectionFor(this, getter_AddRefs(frameselection), getter_AddRefs(selCon));
01881     if (nsEventStatus_eConsumeNoDefault != *aEventStatus && frameselection) {
01882       PRBool supportsDelay = PR_FALSE;
01883       frameselection->GetDelayCaretOverExistingSelection(&supportsDelay);
01884       if (supportsDelay) {
01885         // Check if the frameselection recorded the mouse going down.
01886         // If not, the user must have clicked in a part of the selection.
01887         // Place the caret before continuing!
01888         PRBool mouseDown = PR_FALSE;
01889         rv = frameselection->GetMouseDownState(&mouseDown);
01890         if (NS_FAILED(rv)) {
01891           return rv;
01892         }
01893 
01894         nsMouseEvent* me = nsnull;
01895         rv = frameselection->GetDelayedCaretData(&me);
01896 
01897         if (NS_SUCCEEDED(rv) && !mouseDown && me && me->clickCount < 2) {
01898           handleTableSelection = PR_FALSE;
01899 
01900           rv = GetContentAndOffsetsFromPoint(aPresContext, me->point,
01901                                              getter_AddRefs(content),
01902                                              startOffset, endOffset,
01903                                              beginFrameContent);
01904           if (NS_FAILED(rv)) {
01905             return rv;
01906           }
01907 
01908           // do we have CSS that changes selection behaviour?
01909           PRBool changeSelection = PR_FALSE;
01910           nsCOMPtr<nsIContent> selectContent;
01911           PRInt32 newStart = 0, newEnd = 0;
01912           nsresult rv2 =
01913             frameselection->AdjustOffsetsFromStyle(this, &changeSelection,
01914                                                    getter_AddRefs(selectContent),
01915                                                    &newStart, &newEnd);
01916           if (NS_SUCCEEDED(rv2) && changeSelection) {
01917             content = selectContent;
01918             startOffset = newStart;
01919             endOffset = newEnd;
01920           }
01921         } else {
01922           GetDataForTableSelection(frameselection,
01923                                    aPresContext->GetPresShell(),
01924                                    (nsMouseEvent *)aEvent,
01925                                    getter_AddRefs(content),
01926                                    &contentOffsetForTableSel,
01927                                    &targetForTableSel);
01928         }
01929       }
01930     }
01931   }
01932 
01933   // We might be capturing in some other document and the event just happened to
01934   // trickle down here. Make sure that document's frame selection is notified.
01935   if (activeFrame != this &&
01936       NS_STATIC_CAST(nsFrame*, activeFrame)->DisplaySelection(activeFrame->GetPresContext())
01937         != nsISelectionController::SELECTION_OFF) {
01938     nsCOMPtr<nsIFrameSelection> activeSelection;
01939     nsCOMPtr<nsISelectionController> activeSelCon;
01940     GetFrameSelectionFor(activeFrame, getter_AddRefs(activeSelection),
01941                          getter_AddRefs(activeSelCon));
01942     activeSelection->SetMouseDownState(PR_FALSE);
01943     activeSelection->StopAutoScrollTimer();
01944   }
01945 
01946   // Do not call any methods of the current object after this point!!!
01947   // The object is perhaps dead!
01948 
01949   return selectionOff
01950     ? NS_OK
01951     : HandleFrameSelection(frameselection, content, startOffset, endOffset,
01952                            beginFrameContent, handleTableSelection,
01953                            contentOffsetForTableSel, targetForTableSel,
01954                            aEvent, aEventStatus);
01955 }
01956 
01957 
01958 nsresult nsFrame::GetContentAndOffsetsFromPoint(nsPresContext* aCX,
01959                                                 const nsPoint&  aPoint,
01960                                                 nsIContent **   aNewContent,
01961                                                 PRInt32&        aContentOffset,
01962                                                 PRInt32&        aContentOffsetEnd,
01963                                                 PRBool&         aBeginFrameContent)
01964 {
01965   if (!aNewContent)
01966     return NS_ERROR_NULL_POINTER;
01967 
01968   // Traverse through children and look for the best one to give this
01969   // to if it fails the getposition call, make it yourself also only
01970   // look at primary list
01971   nsIFrame *closestFrame = nsnull;
01972   nsIView *view = GetClosestView();
01973   nsIFrame *kid = GetFirstChild(nsnull);
01974 
01975   if (kid) {
01976 #define HUGE_DISTANCE 999999 //some HUGE number that will always fail first comparison
01977 
01978     PRInt32 closestXDistance = HUGE_DISTANCE;
01979     PRInt32 closestYDistance = HUGE_DISTANCE;
01980 
01981     while (nsnull != kid) {
01982 
01983       // Skip over generated content kid frames, or frames
01984       // that don't have a proper parent-child relationship!
01985 
01986       PRBool skipThisKid = (kid->GetStateBits() & NS_FRAME_GENERATED_CONTENT) != 0;
01987 #if 0
01988       if (!skipThisKid) {
01989         // The frame's content is not generated. Now check
01990         // if it is anonymous content!
01991 
01992         nsIContent* kidContent = kid->GetContent();
01993         if (kidContent) {
01994           nsCOMPtr<nsIContent> content = kidContent->GetParent();
01995 
01996           if (content) {
01997             PRInt32 kidCount = content->ChildCount();
01998             PRInt32 kidIndex = content->IndexOf(kidContent);
01999 
02000             // IndexOf() should return -1 for the index if it doesn't
02001             // find kidContent in it's child list.
02002 
02003             if (kidIndex < 0 || kidIndex >= kidCount) {
02004               // Must be anonymous content! So skip it!
02005               skipThisKid = PR_TRUE;
02006             }
02007           }
02008         }
02009       }
02010 #endif //XXX we USED to skip anonymous content i dont think we should anymore leaving this here as a flah
02011 
02012       if (skipThisKid) {
02013         kid = kid->GetNextSibling();
02014         continue;
02015       }
02016 
02017       // Kid frame has content that has a proper parent-child
02018       // relationship. Now see if the aPoint inside it's bounding
02019       // rect or close by.
02020 
02021       nsPoint offsetPoint(0,0);
02022       nsIView * kidView = nsnull;
02023       kid->GetOffsetFromView(offsetPoint, &kidView);
02024 
02025       nsRect rect = kid->GetRect();
02026       rect.x = offsetPoint.x;
02027       rect.y = offsetPoint.y;
02028 
02029       nscoord fromTop = aPoint.y - rect.y;
02030       nscoord fromBottom = aPoint.y - rect.y - rect.height;
02031 
02032       PRInt32 yDistance;
02033       if (fromTop > 0 && fromBottom < 0)
02034         yDistance = 0;
02035       else
02036         yDistance = PR_MIN(abs(fromTop), abs(fromBottom));
02037 
02038       if (yDistance <= closestYDistance && rect.width > 0 && rect.height > 0)
02039       {
02040         if (yDistance < closestYDistance)
02041           closestXDistance = HUGE_DISTANCE;
02042 
02043         nscoord fromLeft = aPoint.x - rect.x;
02044         nscoord fromRight = aPoint.x - rect.x - rect.width;
02045 
02046         PRInt32 xDistance;
02047         if (fromLeft > 0 && fromRight < 0)
02048           xDistance = 0;
02049         else
02050           xDistance = PR_MIN(abs(fromLeft), abs(fromRight));
02051 
02052         if (xDistance == 0 && yDistance == 0)
02053         {
02054           closestFrame = kid;
02055           break;
02056         }
02057 
02058         if (xDistance < closestXDistance || (xDistance == closestXDistance && rect.x <= aPoint.x))
02059         {
02060           // If we are only near (not directly over) then don't traverse a frame with independent
02061           // selection (e.g. text and list controls) unless we're already inside such a frame,
02062           // except in "browsewithcaret" mode, bug 268497.
02063           if (!(kid->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) ||
02064               (GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) ||
02065               nsContentUtils::GetBoolPref("accessibility.browsewithcaret")) {
02066             closestXDistance = xDistance;
02067             closestYDistance = yDistance;
02068             closestFrame     = kid;
02069           }
02070         }
02071         // else if (xDistance > closestXDistance)
02072         //   break;//done
02073       }
02074     
02075       kid = kid->GetNextSibling();
02076     }
02077     if (closestFrame) {
02078 
02079       // If we cross a view boundary, we need to adjust
02080       // the coordinates because GetPosition() expects
02081       // them to be relative to the closest view.
02082 
02083       nsPoint newPoint     = aPoint;
02084       nsIView *closestView = closestFrame->GetClosestView();
02085 
02086       if (closestView && view != closestView)
02087         newPoint -= closestView->GetOffsetTo(view);
02088 
02089       // printf("      0x%.8x   0x%.8x  %4d  %4d\n",
02090       //        closestFrame, closestView, closestXDistance, closestYDistance);
02091 
02092       return closestFrame->GetContentAndOffsetsFromPoint(aCX, newPoint, aNewContent,
02093                                                          aContentOffset, aContentOffsetEnd,aBeginFrameContent);
02094     }
02095   }
02096 
02097   if (!mContent)
02098     return NS_ERROR_NULL_POINTER;
02099 
02100   nsPoint offsetPoint;
02101   GetOffsetFromView(offsetPoint, &view);
02102   nsRect thisRect = GetRect();
02103   thisRect.x = offsetPoint.x;
02104   thisRect.y = offsetPoint.y;
02105 
02106   NS_IF_ADDREF(*aNewContent = mContent->GetParent());
02107   if (*aNewContent){
02108     
02109     PRInt32 contentOffset(aContentOffset); //temp to hold old value in case of failure
02110     
02111     contentOffset = (*aNewContent)->IndexOf(mContent);
02112     if (contentOffset < 0) 
02113     {
02114       return NS_ERROR_FAILURE;
02115     }
02116     aContentOffset = contentOffset; //its clear save the result
02117 
02118     aBeginFrameContent = PR_TRUE;
02119     if (thisRect.Contains(aPoint))
02120       aContentOffsetEnd = aContentOffset +1;
02121     else 
02122     {
02123       //if we are a collapsed frame then dont check to see if we need to skip past this content
02124       //see bug http://bugzilla.mozilla.org/show_bug.cgi?id=103888
02125       if (thisRect.width && thisRect.height && ((thisRect.x + thisRect.width) < aPoint.x  || thisRect.y > aPoint.y))
02126       {
02127         aBeginFrameContent = PR_FALSE;
02128         aContentOffset++;
02129       }
02130       aContentOffsetEnd = aContentOffset;
02131     }
02132   }
02133   return NS_OK;
02134 }
02135 
02136 NS_IMETHODIMP
02137 nsFrame::GetCursor(const nsPoint& aPoint,
02138                    nsIFrame::Cursor& aCursor)
02139 {
02140   FillCursorInformationFromStyle(GetStyleUserInterface(), aCursor);
02141   if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
02142     aCursor.mCursor = NS_STYLE_CURSOR_DEFAULT;
02143   }
02144 
02145 
02146   return NS_OK;
02147 }
02148 
02149 NS_IMETHODIMP
02150 nsFrame::GetFrameForPoint(const nsPoint& aPoint,
02151                           nsFramePaintLayer aWhichLayer,
02152                           nsIFrame** aFrame)
02153 {
02154   if ((aWhichLayer == NS_FRAME_PAINT_LAYER_FOREGROUND) &&
02155       (mRect.Contains(aPoint))) {
02156     if (GetStyleVisibility()->IsVisible()) {
02157       *aFrame = this;
02158       return NS_OK;
02159     }
02160   }
02161   return NS_ERROR_FAILURE;
02162 }
02163 
02164 // Resize and incremental reflow
02165 
02166 // nsIHTMLReflow member functions
02167 
02168 NS_IMETHODIMP
02169 nsFrame::WillReflow(nsPresContext* aPresContext)
02170 {
02171 #ifdef DEBUG_dbaron_off
02172   // bug 81268
02173   NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW),
02174                "nsFrame::WillReflow: frame is already in reflow");
02175 #endif
02176 
02177   NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
02178                      ("WillReflow: oldState=%x", mState));
02179   mState |= NS_FRAME_IN_REFLOW;
02180   return NS_OK;
02181 }
02182 
02183 NS_IMETHODIMP
02184 nsFrame::DidReflow(nsPresContext*           aPresContext,
02185                    const nsHTMLReflowState*  aReflowState,
02186                    nsDidReflowStatus         aStatus)
02187 {
02188   NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
02189                      ("nsFrame::DidReflow: aStatus=%d", aStatus));
02190   if (NS_FRAME_REFLOW_FINISHED == aStatus) {
02191     mState &= ~(NS_FRAME_IN_REFLOW | NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
02192                 NS_FRAME_HAS_DIRTY_CHILDREN);
02193   }
02194 
02195   // Notify the percent height observer if this is an initial or resize reflow (XXX
02196   // it should probably be any type of reflow, but this would need further testing)
02197   // and there is a percent height but no computed height. The observer may be able to
02198   // initiate another reflow with a computed height. This happens in the case where a table
02199   // cell has no computed height but can fabricate one when the cell height is known.
02200   if (aReflowState && (aReflowState->mPercentHeightObserver)           && // an observer
02201       ((eReflowReason_Initial == aReflowState->reason) ||                 // initial or resize reflow
02202        (eReflowReason_Resize  == aReflowState->reason))                &&
02203       ((NS_UNCONSTRAINEDSIZE == aReflowState->mComputedHeight) ||         // no computed height 
02204        (0                    == aReflowState->mComputedHeight))        && 
02205       aReflowState->mStylePosition                                     && // percent height
02206       (eStyleUnit_Percent == aReflowState->mStylePosition->mHeight.GetUnit())) {
02207 
02208     nsIFrame* prevInFlow = GetPrevInFlow();
02209     if (!prevInFlow) { // 1st in flow
02210       aReflowState->mPercentHeightObserver->NotifyPercentHeight(*aReflowState);
02211     }
02212   }
02213 
02214   return NS_OK;
02215 }
02216 
02217 NS_IMETHODIMP
02218 nsFrame::CanContinueTextRun(PRBool& aContinueTextRun) const
02219 {
02220   // By default, a frame will *not* allow a text run to be continued
02221   // through it.
02222   aContinueTextRun = PR_FALSE;
02223   return NS_OK;
02224 }
02225 
02226 NS_IMETHODIMP
02227 nsFrame::Reflow(nsPresContext*          aPresContext,
02228                 nsHTMLReflowMetrics&     aDesiredSize,
02229                 const nsHTMLReflowState& aReflowState,
02230                 nsReflowStatus&          aStatus)
02231 {
02232   DO_GLOBAL_REFLOW_COUNT("nsFrame", aReflowState.reason);
02233   aDesiredSize.width = 0;
02234   aDesiredSize.height = 0;
02235   aDesiredSize.ascent = 0;
02236   aDesiredSize.descent = 0;
02237   if (aDesiredSize.mComputeMEW) {
02238     aDesiredSize.mMaxElementWidth = 0;
02239   }
02240   aStatus = NS_FRAME_COMPLETE;
02241   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
02242   return NS_OK;
02243 }
02244 
02245 NS_IMETHODIMP
02246 nsFrame::AdjustFrameSize(nscoord aExtraSpace, nscoord& aUsedSpace)
02247 {
02248   aUsedSpace = 0;
02249   return NS_OK;
02250 }
02251 
02252 NS_IMETHODIMP
02253 nsFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext,
02254                                 nsIRenderingContext& aRC,
02255                                 nscoord& aDeltaWidth,
02256                                 PRBool& aLastCharIsJustifiable)
02257 {
02258   aDeltaWidth = 0;
02259   aLastCharIsJustifiable = PR_FALSE;
02260   return NS_OK;
02261 }
02262 
02263 NS_IMETHODIMP
02264 nsFrame::CharacterDataChanged(nsPresContext* aPresContext,
02265                               nsIContent*     aChild,
02266                               PRBool          aAppend)
02267 {
02268   NS_NOTREACHED("should only be called for text frames");
02269   return NS_OK;
02270 }
02271 
02272 NS_IMETHODIMP
02273 nsFrame::AttributeChanged(nsIContent*     aChild,
02274                           PRInt32         aNameSpaceID,
02275                           nsIAtom*        aAttribute,
02276                           PRInt32         aModType)
02277 {
02278   return NS_OK;
02279 }
02280 
02281 // Flow member functions
02282 
02283 NS_IMETHODIMP nsFrame::IsSplittable(nsSplittableType& aIsSplittable) const
02284 {
02285   aIsSplittable = NS_FRAME_NOT_SPLITTABLE;
02286   return NS_OK;
02287 }
02288 
02289 nsIFrame* nsFrame::GetPrevInFlow() const
02290 {
02291   return nsnull;
02292 }
02293 
02294 NS_IMETHODIMP nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow)
02295 {
02296   // Ignore harmless requests to set it to NULL
02297   if (aPrevInFlow) {
02298     NS_ERROR("not splittable");
02299     return NS_ERROR_NOT_IMPLEMENTED;
02300   }
02301 
02302   return NS_OK;
02303 }
02304 
02305 nsIFrame* nsFrame::GetNextInFlow() const
02306 {
02307   return nsnull;
02308 }
02309 
02310 NS_IMETHODIMP nsFrame::SetNextInFlow(nsIFrame*)
02311 {
02312   NS_ERROR("not splittable");
02313   return NS_ERROR_NOT_IMPLEMENTED;
02314 }
02315 
02316 nsIView*
02317 nsIFrame::GetParentViewForChildFrame(nsIFrame* aFrame) const
02318 {
02319   return GetClosestView();
02320 }
02321 
02322 // Associated view object
02323 nsIView*
02324 nsIFrame::GetView() const
02325 {
02326   // Check the frame state bit and see if the frame has a view
02327   if (!(GetStateBits() & NS_FRAME_HAS_VIEW))
02328     return nsnull;
02329 
02330   // Check for a property on the frame
02331   nsresult rv;
02332   void *value = GetProperty(nsLayoutAtoms::viewProperty, &rv);
02333 
02334   NS_ENSURE_SUCCESS(rv, nsnull);
02335   NS_ASSERTION(value, "frame state bit was set but frame has no view");
02336   return NS_STATIC_CAST(nsIView*, value);
02337 }
02338 
02339 /* virtual */ nsIView*
02340 nsIFrame::GetViewExternal() const
02341 {
02342   return GetView();
02343 }
02344 
02345 nsresult
02346 nsIFrame::SetView(nsIView* aView)
02347 {
02348   if (aView) {
02349     aView->SetClientData(this);
02350 
02351     // Set a property on the frame
02352     nsresult rv = SetProperty(nsLayoutAtoms::viewProperty, aView, nsnull);
02353     NS_ENSURE_SUCCESS(rv, rv);
02354 
02355     // Set the frame state bit that says the frame has a view
02356     AddStateBits(NS_FRAME_HAS_VIEW);
02357 
02358     // Let all of the ancestors know they have a descendant with a view.
02359     for (nsIFrame* f = GetParent();
02360          f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
02361          f = f->GetParent())
02362       f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
02363   }
02364 
02365   return NS_OK;
02366 }
02367 
02368 nsIFrame* nsIFrame::GetAncestorWithViewExternal() const
02369 {
02370   return GetAncestorWithView();
02371 }
02372 
02373 // Find the first geometric parent that has a view
02374 nsIFrame* nsIFrame::GetAncestorWithView() const
02375 {
02376   for (nsIFrame* f = mParent; nsnull != f; f = f->GetParent()) {
02377     if (f->HasView()) {
02378       return f;
02379     }
02380   }
02381   return nsnull;
02382 }
02383 
02384 // virtual
02385 nsPoint nsIFrame::GetOffsetToExternal(const nsIFrame* aOther) const
02386 {
02387   return GetOffsetTo(aOther);
02388 }
02389 
02390 nsPoint nsIFrame::GetOffsetTo(const nsIFrame* aOther) const
02391 {
02392   NS_PRECONDITION(aOther,
02393                   "Must have frame for destination coordinate system!");
02394   // Note that if we hit a view while walking up the frame tree we need to stop
02395   // and switch to traversing the view tree so that we will deal with scroll
02396   // views properly.
02397   nsPoint offset(0, 0);
02398   const nsIFrame* f;
02399   for (f = this; !f->HasView() && f != aOther; f = f->GetParent()) {
02400     offset += f->GetPosition();
02401   }
02402   
02403   if (f != aOther) {
02404     // We found a view.  Switch to the view tree
02405     nsPoint toViewOffset(0, 0);
02406     nsIView* otherView = aOther->GetClosestView(&toViewOffset);
02407     offset += f->GetView()->GetOffsetTo(otherView) - toViewOffset;
02408   }
02409   
02410   return offset;
02411 }
02412 
02413 // virtual
02414 nsIntRect nsIFrame::GetScreenRectExternal() const
02415 {
02416   return GetScreenRect();
02417 }
02418 
02419 nsIntRect nsIFrame::GetScreenRect() const
02420 {
02421   nsIntRect retval(0,0,0,0);
02422   nsPoint toViewOffset(0,0);
02423   nsIView* view = GetClosestView(&toViewOffset);
02424 
02425   if (view) {
02426     nsPoint toWidgetOffset(0,0);
02427     nsIWidget* widget = view->GetNearestWidget(&toWidgetOffset);
02428 
02429     if (widget) {
02430       nsRect ourRect = mRect;
02431       ourRect.MoveTo(toViewOffset + toWidgetOffset);
02432       ourRect.ScaleRoundOut(GetPresContext()->TwipsToPixels());
02433       // Is it safe to pass the same rect for both args of WidgetToScreen?
02434       // It's not clear, so let's not...
02435       nsIntRect ourPxRect(ourRect.x, ourRect.y, ourRect.width, ourRect.height);
02436       
02437       widget->WidgetToScreen(ourPxRect, retval);
02438     }
02439   }
02440 
02441   return retval;
02442 }
02443 
02444 // Returns the offset from this frame to the closest geometric parent that
02445 // has a view. Also returns the containing view or null in case of error
02446 NS_IMETHODIMP nsFrame::GetOffsetFromView(nsPoint&  aOffset,
02447                                          nsIView** aView) const
02448 {
02449   NS_PRECONDITION(nsnull != aView, "null OUT parameter pointer");
02450   nsIFrame* frame = (nsIFrame*)this;
02451 
02452   *aView = nsnull;
02453   aOffset.MoveTo(0, 0);
02454   do {
02455     aOffset += frame->GetPosition();
02456     frame = frame->GetParent();
02457   } while (frame && !frame->HasView());
02458   if (frame)
02459     *aView = frame->GetView();
02460   return NS_OK;
02461 }
02462 
02463 // The (x,y) value of the frame's upper left corner is always
02464 // relative to its parentFrame's upper left corner, unless
02465 // its parentFrame has a view associated with it, in which case, it
02466 // will be relative to the upper left corner of the view returned
02467 // by a call to parentFrame->GetView().
02468 //
02469 // This means that while drilling down the frame hierarchy, from
02470 // parent to child frame, we sometimes need to take into account
02471 // crossing these view boundaries, because the coordinate system
02472 // changes from parent frame coordinate system, to the associated
02473 // view's coordinate system.
02474 //
02475 // GetOriginToViewOffset() is a utility method that returns the
02476 // offset necessary to map a point, relative to the frame's upper
02477 // left corner, into the coordinate system of the view associated
02478 // with the frame.
02479 //
02480 // If there is no view associated with the frame, or the view is
02481 // not a descendant of the frame's parent view (ex: scrolling popup menu),
02482 // the offset returned will be (0,0).
02483 
02484 NS_IMETHODIMP nsFrame::GetOriginToViewOffset(nsPoint&        aOffset,
02485                                              nsIView**       aView) const
02486 {
02487   nsresult rv = NS_OK;
02488 
02489   aOffset.MoveTo(0,0);
02490 
02491   if (aView)
02492     *aView = nsnull;
02493 
02494   if (HasView()) {
02495     nsIView *view = GetView();
02496     nsIView *parentView = nsnull;
02497     nsPoint offsetToParentView;
02498     rv = GetOffsetFromView(offsetToParentView, &parentView);
02499 
02500     if (NS_SUCCEEDED(rv)) {
02501       nsPoint viewOffsetFromParent(0,0);
02502       nsIView *pview = view;
02503 
02504       nsIViewManager* vVM = view->GetViewManager();
02505 
02506       while (pview && pview != parentView) {
02507         viewOffsetFromParent += pview->GetPosition();
02508 
02509         nsIView *tmpView = pview->GetParent();
02510         if (tmpView && vVM != tmpView->GetViewManager()) {
02511           // Don't cross ViewManager boundaries!
02512           // XXXbz why not?
02513           break;
02514         }
02515         pview = tmpView;
02516       }
02517 
02518 #ifdef DEBUG_KIN
02519       if (pview != parentView) {
02520         // XXX: At this point, pview is probably null since it traversed
02521         //      all the way up view's parent hierarchy and did not run across
02522         //      parentView. In the future, instead of just returning an offset
02523         //      of (0,0) for this case, we may want offsetToParentView to
02524         //      include the offset from the parentView to the top of the
02525         //      view hierarchy which would make both offsetToParentView and
02526         //      viewOffsetFromParent, offsets to the global coordinate space.
02527         //      We'd have to investigate any perf impact this would have before
02528         //      checking in such a change, so for now we just return (0,0).
02529         //      -- kin    
02530         NS_WARNING("view is not a descendant of parentView!");
02531       }
02532 #endif // DEBUG
02533 
02534       if (pview == parentView)
02535         aOffset = offsetToParentView - viewOffsetFromParent;
02536 
02537       if (aView)
02538         *aView = view;
02539     }
02540   }
02541 
02542   return rv;
02543 }
02544 
02545 /* virtual */ PRBool
02546 nsIFrame::AreAncestorViewsVisible() const
02547 {
02548   for (nsIView* view = GetClosestView(); view; view = view->GetParent()) {
02549     if (view->GetVisibility() == nsViewVisibility_kHide) {
02550       return PR_FALSE;
02551     }
02552   }
02553   return PR_TRUE;
02554 }
02555 
02556 nsIWidget*
02557 nsIFrame::GetWindow() const
02558 {
02559   return GetClosestView()->GetNearestWidget(nsnull);
02560 }
02561 
02562 nsIAtom*
02563 nsFrame::GetType() const
02564 {
02565   return nsnull;
02566 }
02567 
02568 PRBool
02569 nsIFrame::IsLeaf() const
02570 {
02571   return PR_TRUE;
02572 }
02573 
02574 void
02575 nsIFrame::Invalidate(const nsRect& aDamageRect,
02576                      PRBool        aImmediate) const
02577 {
02578   if (aDamageRect.IsEmpty()) {
02579     return;
02580   }
02581 
02582   // Don't allow invalidates to do anything when
02583   // painting is suppressed.
02584   nsIPresShell *shell = GetPresContext()->GetPresShell();
02585   if (shell) {
02586     PRBool suppressed = PR_FALSE;
02587     shell->IsPaintingSuppressed(&suppressed);
02588     if (suppressed)
02589       return;
02590   }
02591 
02592   nsRect damageRect(aDamageRect);
02593 
02594   PRUint32 flags = aImmediate ? NS_VMREFRESH_IMMEDIATE : NS_VMREFRESH_NO_SYNC;
02595   if (HasView()) {
02596     nsIView* view = GetView();
02597     view->GetViewManager()->UpdateView(view, damageRect, flags);
02598   } else {
02599     nsRect    rect(damageRect);
02600     nsPoint   offset;
02601   
02602     nsIView *view;
02603     GetOffsetFromView(offset, &view);
02604     NS_ASSERTION(view, "no view");
02605     rect += offset;
02606     view->GetViewManager()->UpdateView(view, rect, flags);
02607   }
02608 }
02609 
02610 static nsRect ComputeOutlineRect(const nsIFrame* aFrame, PRBool* aAnyOutline,
02611                                  const nsRect& aOverflowRect) {
02612   const nsStyleOutline* outline = aFrame->GetStyleOutline();
02613   PRUint8 outlineStyle = outline->GetOutlineStyle();
02614   nsRect r = aOverflowRect;
02615   *aAnyOutline = PR_FALSE;
02616   if (outlineStyle != NS_STYLE_BORDER_STYLE_NONE) {
02617     nscoord width;
02618 #ifdef DEBUG
02619     PRBool result = 
02620 #endif
02621       outline->GetOutlineWidth(width);
02622     NS_ASSERTION(result, "GetOutlineWidth had no cached outline width");
02623     if (width > 0) {
02624       nscoord offset;
02625       outline->GetOutlineOffset(offset);
02626       nscoord inflateBy = PR_MAX(width + offset, 0);
02627       r.Inflate(inflateBy, inflateBy);
02628       *aAnyOutline = PR_TRUE;
02629     }
02630   }
02631   return r;
02632 }
02633 
02634 nsRect
02635 nsIFrame::GetOverflowRect() const
02636 {
02637   // Note that in some cases the overflow area might not have been
02638   // updated (yet) to reflect any outline set on the frame or the area
02639   // of child frames. That's OK because any reflow that updates these
02640   // areas will invalidate the appropriate area, so any (mis)uses of
02641   // this method will be fixed up.
02642   nsRect* storedOA = NS_CONST_CAST(nsIFrame*, this)
02643     ->GetOverflowAreaProperty(PR_FALSE);
02644   if (storedOA) {
02645     return *storedOA;
02646   } else {
02647     return nsRect(nsPoint(0, 0), GetSize());
02648   }
02649 }
02650   
02651 void
02652 nsFrame::CheckInvalidateSizeChange(nsPresContext* aPresContext,
02653                                    nsHTMLReflowMetrics& aDesiredSize,
02654                                    const nsHTMLReflowState& aReflowState)
02655 {
02656   if (aDesiredSize.width == mRect.width
02657       && aDesiredSize.height == mRect.height)
02658     return;
02659 
02660   // Below, we invalidate the old frame area (or, in the case of
02661   // outline, combined area) if the outline, border or background
02662   // settings indicate that something other than the difference
02663   // between the old and new areas needs to be painted. We are
02664   // assuming that the difference between the old and new areas will
02665   // be invalidated by some other means. That also means invalidating
02666   // the old frame area is the same as invalidating the new frame area
02667   // (since in either case the UNION of old and new areas will be
02668   // invalidated)
02669 
02670   // Invalidate the entire old frame+outline if the frame has an outline
02671   PRBool anyOutline;
02672   nsRect r = ComputeOutlineRect(this, &anyOutline,
02673                                 aDesiredSize.mOverflowArea);
02674   if (anyOutline) {
02675     Invalidate(r);
02676     return;
02677   }
02678 
02679   // Invalidate the old frame borders if the frame has borders. Those borders
02680   // may be moving.
02681   const nsStyleBorder* border = GetStyleBorder();
02682   NS_FOR_CSS_SIDES(side) {
02683     if (border->GetBorderWidth(side) != 0) {
02684       Invalidate(nsRect(0, 0, mRect.width, mRect.height));
02685       return;
02686     }
02687   }
02688 
02689   // Invalidate the old frame background if the frame has a background
02690   // whose position depends on the size of the frame
02691   const nsStyleBackground* background = GetStyleBackground();
02692   if (background->mBackgroundFlags &
02693       (NS_STYLE_BG_X_POSITION_PERCENT | NS_STYLE_BG_Y_POSITION_PERCENT)) {
02694     Invalidate(nsRect(0, 0, mRect.width, mRect.height));
02695     return;
02696   }
02697 }
02698 
02699 // Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus
02700 // 4 for the frames above the document's frames: 
02701 //  the Viewport, GFXScroll, ScrollPort, and Canvas
02702 #define MAX_FRAME_DEPTH (MAX_REFLOW_DEPTH+4)
02703 
02704 PRBool
02705 nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState,
02706                             nsHTMLReflowMetrics& aMetrics)
02707 {
02708   if (aReflowState.mReflowDepth >  MAX_FRAME_DEPTH) {
02709     mState |= NS_FRAME_IS_UNFLOWABLE;
02710     mState &= ~NS_FRAME_OUTSIDE_CHILDREN;
02711     aMetrics.width = 0;
02712     aMetrics.height = 0;
02713     aMetrics.ascent = 0;
02714     aMetrics.descent = 0;
02715     aMetrics.mCarriedOutBottomMargin.Zero();
02716     aMetrics.mOverflowArea.x = 0;
02717     aMetrics.mOverflowArea.y = 0;
02718     aMetrics.mOverflowArea.width = 0;
02719     aMetrics.mOverflowArea.height = 0;
02720     if (aMetrics.mComputeMEW) {
02721       aMetrics.mMaxElementWidth = 0;
02722     }
02723     return PR_TRUE;
02724   }
02725   mState &= ~NS_FRAME_IS_UNFLOWABLE;
02726   return PR_FALSE;
02727 }
02728 
02729 // Style sizing methods
02730 /* virtual */ PRBool nsFrame::IsContainingBlock() const
02731 {
02732   const nsStyleDisplay* display = GetStyleDisplay();
02733 
02734   // Absolute positioning causes |display->mDisplay| to be set to block,
02735   // if needed.
02736   return display->mDisplay == NS_STYLE_DISPLAY_BLOCK || 
02737          display->mDisplay == NS_STYLE_DISPLAY_LIST_ITEM ||
02738          display->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL;
02739 }
02740 
02741 #ifdef NS_DEBUG
02742 
02743 PRInt32 nsFrame::ContentIndexInContainer(const nsIFrame* aFrame)
02744 {
02745   PRInt32 result = -1;
02746 
02747   nsIContent* content = aFrame->GetContent();
02748   if (content) {
02749     nsIContent* parentContent = content->GetParent();
02750     if (parentContent) {
02751       result = parentContent->IndexOf(content);
02752     }
02753   }
02754 
02755   return result;
02756 }
02757 
02758 #ifdef DEBUG_waterson
02759 
02763 void
02764 DebugListFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
02765 {
02766   ((nsFrame*) aFrame)->List(aPresContext, stdout, 0);
02767   printf("\n");
02768 }
02769 
02773 void
02774 DebugListFrameTree(nsPresContext* aPresContext, nsIFrame* aFrame)
02775 {
02776   nsIFrameDebug* fdbg;
02777   aFrame->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**) &fdbg);
02778   if (fdbg)
02779     fdbg->List(aPresContext, stdout, 0);
02780 }
02781 
02782 #endif
02783 
02784 
02785 // Debugging
02786 NS_IMETHODIMP
02787 nsFrame::List(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent) const
02788 {
02789   IndentBy(out, aIndent);
02790   ListTag(out);
02791 #ifdef DEBUG_waterson
02792   fprintf(out, " [parent=%p]", NS_STATIC_CAST(void*, mParent));
02793 #endif
02794   if (HasView()) {
02795     fprintf(out, " [view=%p]", NS_STATIC_CAST(void*, GetView()));
02796   }
02797   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
02798   if (0 != mState) {
02799     fprintf(out, " [state=%08x]", mState);
02800   }
02801   nsIFrame* prevInFlow = GetPrevInFlow();
02802   nsIFrame* nextInFlow = GetNextInFlow();
02803   if (nsnull != prevInFlow) {
02804     fprintf(out, " prev-in-flow=%p", NS_STATIC_CAST(void*, prevInFlow));
02805   }
02806   if (nsnull != nextInFlow) {
02807     fprintf(out, " next-in-flow=%p", NS_STATIC_CAST(void*, nextInFlow));
02808   }
02809   fprintf(out, " [content=%p]", NS_STATIC_CAST(void*, mContent));
02810   nsFrame* f = NS_CONST_CAST(nsFrame*, this);
02811   nsRect* overflowArea = f->GetOverflowAreaProperty(PR_FALSE);
02812   if (overflowArea) {
02813     fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea->x, overflowArea->y,
02814             overflowArea->width, overflowArea->height);
02815   }
02816   fputs("\n", out);
02817   return NS_OK;
02818 }
02819 
02820 NS_IMETHODIMP
02821 nsFrame::GetFrameName(nsAString& aResult) const
02822 {
02823   return MakeFrameName(NS_LITERAL_STRING("Frame"), aResult);
02824 }
02825 
02826 NS_IMETHODIMP_(nsFrameState)
02827 nsFrame::GetDebugStateBits() const
02828 {
02829   // We'll ignore these flags for the purposes of comparing frame state:
02830   //
02831   //   NS_FRAME_EXTERNAL_REFERENCE
02832   //     because this is set by the event state manager or the
02833   //     caret code when a frame is focused. Depending on whether
02834   //     or not the regression tests are run as the focused window
02835   //     will make this value vary randomly.
02836 #define IRRELEVANT_FRAME_STATE_FLAGS NS_FRAME_EXTERNAL_REFERENCE
02837 
02838 #define FRAME_STATE_MASK (~(IRRELEVANT_FRAME_STATE_FLAGS))
02839 
02840   return GetStateBits() & FRAME_STATE_MASK;
02841 }
02842 
02843 nsresult
02844 nsFrame::MakeFrameName(const nsAString& aType, nsAString& aResult) const
02845 {
02846   aResult = aType;
02847   if (mContent && !mContent->IsContentOfType(nsIContent::eTEXT)) {
02848     nsAutoString buf;
02849     mContent->Tag()->ToString(buf);
02850     aResult.Append(NS_LITERAL_STRING("(") + buf + NS_LITERAL_STRING(")"));
02851   }
02852   char buf[40];
02853   PR_snprintf(buf, sizeof(buf), "(%d)", ContentIndexInContainer(this));
02854   AppendASCIItoUTF16(buf, aResult);
02855   return NS_OK;
02856 }
02857 
02858 void
02859 nsFrame::XMLQuote(nsString& aString)
02860 {
02861   PRInt32 i, len = aString.Length();
02862   for (i = 0; i < len; i++) {
02863     PRUnichar ch = aString.CharAt(i);
02864     if (ch == '<') {
02865       nsAutoString tmp(NS_LITERAL_STRING("&lt;"));
02866       aString.Cut(i, 1);
02867       aString.Insert(tmp, i);
02868       len += 3;
02869       i += 3;
02870     }
02871     else if (ch == '>') {
02872       nsAutoString tmp(NS_LITERAL_STRING("&gt;"));
02873       aString.Cut(i, 1);
02874       aString.Insert(tmp, i);
02875       len += 3;
02876       i += 3;
02877     }
02878     else if (ch == '\"') {
02879       nsAutoString tmp(NS_LITERAL_STRING("&quot;"));
02880       aString.Cut(i, 1);
02881       aString.Insert(tmp, i);
02882       len += 5;
02883       i += 5;
02884     }
02885   }
02886 }
02887 #endif
02888 
02889 PRBool
02890 nsFrame::ParentDisablesSelection() const
02891 {
02892 /*
02893   // should never be called now
02894   nsIFrame* parent = GetParent();
02895   if (parent) {
02896          PRBool selectable;
02897          parent->IsSelectable(selectable);
02898     return (selectable ? PR_FALSE : PR_TRUE);
02899   }
02900   return PR_FALSE;
02901 */
02902 /*
02903   PRBool selected;
02904   if (NS_FAILED(GetSelected(&selected)))
02905     return PR_FALSE;
02906   if (selected)
02907     return PR_FALSE; //if this frame is selected and no one has overridden the selection from "higher up"
02908                      //then no one below us will be disabled by this frame.
02909   nsIFrame* target = GetParent();
02910   if (target)
02911     return ((nsFrame *)target)->ParentDisablesSelection();
02912   return PR_FALSE; //default this does not happen
02913   */
02914   
02915   return PR_FALSE;
02916 }
02917 
02918 nsresult 
02919 nsFrame::GetSelectionForVisCheck(nsPresContext * aPresContext, nsISelection** aSelection)
02920 {
02921   *aSelection = nsnull;
02922   nsresult rv = NS_OK;
02923 
02924   // start by checking to see if we are paginated which probably means
02925   // we are in print preview or printing
02926   if (aPresContext->IsPaginated()) {
02927     // now see if we are rendering selection only
02928     if (aPresContext->IsRenderingOnlySelection()) {
02929       // Check the quick way first (typically only leaf nodes)
02930       PRBool isSelected = (mState & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
02931       // if we aren't selected in the mState,
02932       // we could be a container so check to see if we are in the selection range
02933       // this is a expensive
02934       if (!isSelected) {
02935         nsIPresShell *shell = aPresContext->GetPresShell();
02936         if (shell) {
02937           nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(shell));
02938           if (selcon) {
02939             rv = selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSelection);
02940           }
02941         }
02942       }
02943     }
02944   } 
02945 
02946   return rv;
02947 }
02948 
02949 
02950 NS_IMETHODIMP
02951 nsFrame::IsVisibleForPainting(nsPresContext *     aPresContext, 
02952                               nsIRenderingContext& aRenderingContext,
02953                               PRBool               aCheckVis,
02954                               PRBool*              aIsVisible)
02955 {
02956   // first check to see if we are visible
02957   if (aCheckVis) {
02958     if (!GetStyleVisibility()->IsVisible()) {
02959       *aIsVisible = PR_FALSE;
02960       return NS_OK;
02961     }
02962   }
02963 
02964   // Start by assuming we are visible and need to be painted
02965   *aIsVisible = PR_TRUE;
02966 
02967   // NOTE: GetSelectionforVisCheck checks the pagination to make sure we are printing
02968   // In otherwords, the selection will ALWAYS be null if we are not printing, meaning
02969   // the visibility will be TRUE in that case
02970   nsCOMPtr<nsISelection> selection;
02971   nsresult rv = GetSelectionForVisCheck(aPresContext, getter_AddRefs(selection));
02972   if (NS_SUCCEEDED(rv) && selection) {
02973     nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
02974     selection->ContainsNode(node, PR_TRUE, aIsVisible);
02975   }
02976 
02977   return rv;
02978 }
02979 
02980 /* virtual */ PRBool
02981 nsFrame::IsEmpty()
02982 {
02983   return PR_FALSE;
02984 }
02985 
02986 /* virtual */ PRBool
02987 nsFrame::IsSelfEmpty()
02988 {
02989   return PR_FALSE;
02990 }
02991 
02992 NS_IMETHODIMP
02993 nsFrame::GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon)
02994 {
02995   if (!aPresContext || !aSelCon)
02996     return NS_ERROR_INVALID_ARG;
02997 
02998   nsIFrame *frame = this;
02999   while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
03000     nsITextControlFrame *tcf;
03001     if (NS_SUCCEEDED(frame->QueryInterface(NS_GET_IID(nsITextControlFrame),(void**)&tcf))) {
03002       return tcf->GetSelectionContr(aSelCon);
03003     }
03004     frame = frame->GetParent();
03005   }
03006 
03007   nsIPresShell *shell = aPresContext->GetPresShell();
03008   if (shell) {
03009     nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(shell);
03010     NS_IF_ADDREF(*aSelCon = selCon);
03011   }
03012 
03013   return NS_OK;
03014 }
03015 
03016 
03017 
03018 #ifdef NS_DEBUG
03019 NS_IMETHODIMP
03020 nsFrame::DumpRegressionData(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent, PRBool aIncludeStyleData)
03021 {
03022   IndentBy(out, aIndent);
03023   fprintf(out, "<frame va=\"%ld\" type=\"", PRUptrdiff(this));
03024   nsAutoString name;
03025   GetFrameName(name);
03026   XMLQuote(name);
03027   fputs(NS_LossyConvertUCS2toASCII(name).get(), out);
03028   fprintf(out, "\" state=\"%d\" parent=\"%ld\">\n",
03029           GetDebugStateBits(), PRUptrdiff(mParent));
03030 
03031   aIndent++;
03032   DumpBaseRegressionData(aPresContext, out, aIndent, aIncludeStyleData);
03033   aIndent--;
03034 
03035   IndentBy(out, aIndent);
03036   fprintf(out, "</frame>\n");
03037 
03038   return NS_OK;
03039 }
03040 
03041 void
03042 nsFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent, PRBool aIncludeStyleData)
03043 {
03044   if (nsnull != mNextSibling) {
03045     IndentBy(out, aIndent);
03046     fprintf(out, "<next-sibling va=\"%ld\"/>\n", PRUptrdiff(mNextSibling));
03047   }
03048 
03049   if (HasView()) {
03050     IndentBy(out, aIndent);
03051     fprintf(out, "<view va=\"%ld\">\n", PRUptrdiff(GetView()));
03052     aIndent++;
03053     // XXX add in code to dump out view state too...
03054     aIndent--;
03055     IndentBy(out, aIndent);
03056     fprintf(out, "</view>\n");
03057   }
03058 
03059   if(aIncludeStyleData) {
03060     if(mStyleContext) {
03061       IndentBy(out, aIndent);
03062       fprintf(out, "<stylecontext va=\"%ld\">\n", PRUptrdiff(mStyleContext));
03063       aIndent++;
03064       // Dump style context regression data
03065       mStyleContext->DumpRegressionData(aPresContext, out, aIndent);
03066       aIndent--;
03067       IndentBy(out, aIndent);
03068       fprintf(out, "</stylecontext>\n");
03069     }
03070   }
03071 
03072   IndentBy(out, aIndent);
03073   fprintf(out, "<bbox x=\"%d\" y=\"%d\" w=\"%d\" h=\"%d\"/>\n",
03074           mRect.x, mRect.y, mRect.width, mRect.height);
03075 
03076   // Now dump all of the children on all of the child lists
03077   nsIFrame* kid;
03078   nsIAtom* list = nsnull;
03079   PRInt32 listIndex = 0;
03080   do {
03081     kid = GetFirstChild(list);
03082     if (kid) {
03083       IndentBy(out, aIndent);
03084       if (nsnull != list) {
03085         nsAutoString listName;
03086         list->ToString(listName);
03087         fprintf(out, "<child-list name=\"");
03088         XMLQuote(listName);
03089         fputs(NS_LossyConvertUCS2toASCII(listName).get(), out);
03090         fprintf(out, "\">\n");
03091       }
03092       else {
03093         fprintf(out, "<child-list>\n");
03094       }
03095       aIndent++;
03096       while (kid) {
03097         nsIFrameDebug*  frameDebug;
03098 
03099         if (NS_SUCCEEDED(kid->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**)&frameDebug))) {
03100           frameDebug->DumpRegressionData(aPresContext, out, aIndent, aIncludeStyleData);
03101         }
03102         kid = kid->GetNextSibling();
03103       }
03104       aIndent--;
03105       IndentBy(out, aIndent);
03106       fprintf(out, "</child-list>\n");
03107     }
03108     list = GetAdditionalChildListName(listIndex++);
03109   } while (nsnull != list);
03110 }
03111 
03112 NS_IMETHODIMP
03113 nsFrame::VerifyTree() const
03114 {
03115   NS_ASSERTION(0 == (mState & NS_FRAME_IN_REFLOW), "frame is in reflow");
03116   return NS_OK;
03117 }
03118 #endif
03119 
03120 /*this method may.. invalidate if the state was changed or if aForceRedraw is PR_TRUE
03121   it will not update immediately.*/
03122 NS_IMETHODIMP
03123 nsFrame::SetSelected(nsPresContext* aPresContext, nsIDOMRange *aRange, PRBool aSelected, nsSpread aSpread)
03124 {
03125 /*
03126   if (aSelected && ParentDisablesSelection())
03127     return NS_OK;
03128 */
03129 
03130   // check whether style allows selection
03131   PRBool  selectable;
03132   IsSelectable(&selectable, nsnull);
03133   if (!selectable)
03134     return NS_OK;
03135 
03136 /*
03137   if (eSpreadDown == aSpread){
03138     nsIFrame* kid = GetFirstChild(nsnull);
03139     while (nsnull != kid) {
03140       kid->SetSelected(nsnull,aSelected,aSpread);
03141       kid = kid->GetNextSibling();
03142     }
03143   }
03144 */
03145   if ( aSelected ){
03146     AddStateBits(NS_FRAME_SELECTED_CONTENT);
03147   }
03148   else
03149     RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
03150 
03151   // Repaint this frame subtree's entire area
03152   Invalidate(GetOverflowRect(), PR_FALSE);
03153 
03154 #ifdef IBMBIDI
03155   PRInt32 start, end;
03156   nsIFrame* frame = GetNextSibling();
03157   if (frame) {
03158     GetFirstLeaf(aPresContext, &frame);
03159     GetOffsets(start, end);
03160     if (start && end) {
03161       frame->SetSelected(aPresContext, aRange, aSelected, aSpread);
03162     }
03163   }
03164 #endif // IBMBIDI
03165 
03166   return NS_OK;
03167 }
03168 
03169 NS_IMETHODIMP
03170 nsFrame::GetSelected(PRBool *aSelected) const
03171 {
03172   if (!aSelected )
03173     return NS_ERROR_NULL_POINTER;
03174   *aSelected = (PRBool)(mState & NS_FRAME_SELECTED_CONTENT);
03175   return NS_OK;
03176 }
03177 
03178 NS_IMETHODIMP
03179 nsFrame::GetPointFromOffset(nsPresContext* inPresContext, nsIRenderingContext* inRendContext, PRInt32 inOffset, nsPoint* outPoint)
03180 {
03181   NS_PRECONDITION(outPoint != nsnull, "Null parameter");
03182   nsPoint bottomLeft(0, 0);
03183   if (mContent)
03184   {
03185     nsIContent* newContent = mContent->GetParent();
03186     if (newContent){
03187       PRInt32 newOffset = newContent->IndexOf(mContent);
03188 
03189       if (inOffset > newOffset)
03190         bottomLeft.x = GetRect().width;
03191     }
03192   }
03193   *outPoint = bottomLeft;
03194   return NS_OK;
03195 }
03196 
03197 NS_IMETHODIMP
03198 nsFrame::GetChildFrameContainingOffset(PRInt32 inContentOffset, PRBool inHint, PRInt32* outFrameContentOffset, nsIFrame **outChildFrame)
03199 {
03200   NS_PRECONDITION(outChildFrame && outFrameContentOffset, "Null parameter");
03201   *outFrameContentOffset = (PRInt32)inHint;
03202   //the best frame to reflect any given offset would be a visible frame if possible
03203   //i.e. we are looking for a valid frame to place the blinking caret 
03204   nsRect rect = GetRect();
03205   if (!rect.width || !rect.height)
03206   {
03207     //if we have a 0 width or height then lets look for another frame that possibly has
03208     //the same content.  If we have no frames in flow then just let us return 'this' frame
03209     nsIFrame* nextFlow = GetNextInFlow();
03210     if (nextFlow)
03211       return nextFlow->GetChildFrameContainingOffset(inContentOffset, inHint, outFrameContentOffset, outChildFrame);
03212   }
03213   *outChildFrame = this;
03214   return NS_OK;
03215 }
03216 
03217 //
03218 // What I've pieced together about this routine:
03219 // Starting with a block frame (from which a line frame can be gotten)
03220 // and a line number, drill down and get the first/last selectable
03221 // frame on that line, depending on aPos->mDirection.
03222 // aOutSideLimit != 0 means ignore aLineStart, instead work from
03223 // the end (if > 0) or beginning (if < 0).
03224 //
03225 nsresult
03226 nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
03227                                         nsPeekOffsetStruct *aPos,
03228                                         nsIFrame *aBlockFrame, 
03229                                         PRInt32 aLineStart, 
03230                                         PRInt8 aOutSideLimit
03231                                         )
03232 {
03233   //magic numbers aLineStart will be -1 for end of block 0 will be start of block
03234   if (!aBlockFrame || !aPos)
03235     return NS_ERROR_NULL_POINTER;
03236 
03237   aPos->mResultFrame = nsnull;
03238   aPos->mResultContent = nsnull;
03239   aPos->mPreferLeft = (aPos->mDirection == eDirNext);
03240 
03241    nsresult result;
03242   nsCOMPtr<nsILineIteratorNavigator> it; 
03243   result = aBlockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(it));
03244   if (NS_FAILED(result) || !it)
03245     return result;
03246   PRInt32 searchingLine = aLineStart;
03247   PRInt32 countLines;
03248   result = it->GetNumLines(&countLines);
03249   if (aOutSideLimit > 0) //start at end
03250     searchingLine = countLines;
03251   else if (aOutSideLimit <0)//start at begining
03252     searchingLine = -1;//"next" will be 0  
03253   else 
03254     if ((aPos->mDirection == eDirPrevious && searchingLine == 0) || 
03255        (aPos->mDirection == eDirNext && searchingLine >= (countLines -1) )){
03256       //we need to jump to new block frame.
03257            return NS_ERROR_FAILURE;
03258     }
03259   PRInt32 lineFrameCount;
03260   nsIFrame *resultFrame = nsnull;
03261   nsIFrame *farStoppingFrame = nsnull; //we keep searching until we find a "this" frame then we go to next line
03262   nsIFrame *nearStoppingFrame = nsnull; //if we are backing up from edge, stop here
03263   nsIFrame *firstFrame;
03264   nsIFrame *lastFrame;
03265   nsRect  rect;
03266   PRBool isBeforeFirstFrame, isAfterLastFrame;
03267   PRBool found = PR_FALSE;
03268   while (!found)
03269   {
03270     if (aPos->mDirection == eDirPrevious)
03271       searchingLine --;
03272     else
03273       searchingLine ++;
03274     if ((aPos->mDirection == eDirPrevious && searchingLine < 0) || 
03275        (aPos->mDirection == eDirNext && searchingLine >= countLines ))
03276     {
03277       //we need to jump to new block frame.
03278       return NS_ERROR_FAILURE;
03279     }
03280     PRUint32 lineFlags;
03281     result = it->GetLine(searchingLine, &firstFrame, &lineFrameCount,
03282                          rect, &lineFlags);
03283     if (!lineFrameCount) 
03284       continue;
03285     if (NS_SUCCEEDED(result)){
03286       lastFrame = firstFrame;
03287       for (;lineFrameCount > 1;lineFrameCount --){
03288         //result = lastFrame->GetNextSibling(&lastFrame, searchingLine);
03289         result = it->GetNextSiblingOnLine(lastFrame, searchingLine);
03290         if (NS_FAILED(result) || !lastFrame){
03291           NS_ASSERTION(0,"should not be reached nsFrame\n");
03292           return NS_ERROR_FAILURE;
03293         }
03294       }
03295       GetLastLeaf(aPresContext, &lastFrame);
03296 
03297       if (aPos->mDirection == eDirNext){
03298         nearStoppingFrame = firstFrame;
03299         farStoppingFrame = lastFrame;
03300       }
03301       else{
03302         nearStoppingFrame = lastFrame;
03303         farStoppingFrame = firstFrame;
03304       }
03305       nsPoint offset;
03306       nsIView * view; //used for call of get offset from view
03307       aBlockFrame->GetOffsetFromView(offset,&view);
03308       nscoord newDesiredX  = aPos->mDesiredX - offset.x;//get desired x into blockframe coordinates!
03309       result = it->FindFrameAt(searchingLine, newDesiredX, &resultFrame, &isBeforeFirstFrame, &isAfterLastFrame);
03310       if(NS_FAILED(result))
03311         continue;
03312     }
03313 
03314     if (NS_SUCCEEDED(result) && resultFrame)
03315     {
03316       nsCOMPtr<nsILineIteratorNavigator> newIt; 
03317       //check to see if this is ANOTHER blockframe inside the other one if so then call into its lines
03318       result = resultFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(newIt));
03319       if (NS_SUCCEEDED(result) && newIt)
03320       {
03321         aPos->mResultFrame = resultFrame;
03322         return NS_OK;
03323       }
03324       //resultFrame is not a block frame
03325 
03326       nsCOMPtr<nsIBidirectionalEnumerator> frameTraversal;
03327       result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal), EXTENSIVE,
03328                                     aPresContext, resultFrame, aPos->mScrollViewStop);
03329       if (NS_FAILED(result))
03330         return result;
03331       nsISupports *isupports = nsnull;
03332       nsIFrame *storeOldResultFrame = resultFrame;
03333       while ( !found ){
03334         nsPresContext *context = aPos->mShell->GetPresContext();
03335         nsPoint point;
03336         point.x = aPos->mDesiredX;
03337 
03338         nsRect tempRect = resultFrame->GetRect();
03339         nsPoint offset;
03340         nsIView * view; //used for call of get offset from view
03341         result = resultFrame->GetOffsetFromView(offset, &view);
03342         if (NS_FAILED(result))
03343           return result;
03344         point.y = tempRect.height + offset.y;
03345 
03346         //special check. if we allow non-text selection then we can allow a hit location to fall before a table. 
03347         //otherwise there is no way to get and click signal to fall before a table (it being a line iterator itself)
03348         PRInt16 isEditor = 0;
03349         nsIPresShell *shell = aPresContext->GetPresShell();
03350         if (!shell)
03351           return NS_ERROR_FAILURE;
03352         shell->GetSelectionFlags ( &isEditor );
03353         isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
03354         if ( isEditor ) 
03355         {
03356           if (resultFrame->GetType() == nsLayoutAtoms::tableOuterFrame)
03357           {
03358             if (((point.x - offset.x + tempRect.x)<0) ||  ((point.x - offset.x+ tempRect.x)>tempRect.width))//off left/right side
03359             {
03360               nsIContent* content = resultFrame->GetContent();
03361               if (content)
03362               {
03363                 nsIContent* parent = content->GetParent();
03364                 if (parent)
03365                 {
03366                   aPos->mResultContent = parent;
03367                   aPos->mContentOffset = parent->IndexOf(content);
03368                   aPos->mPreferLeft = PR_FALSE;
03369                   if ((point.x - offset.x+ tempRect.x)>tempRect.width)
03370                   {
03371                     aPos->mContentOffset++;//go to end of this frame
03372                     aPos->mPreferLeft = PR_TRUE;
03373                   }
03374                   aPos->mContentOffsetEnd = aPos->mContentOffset;
03375                   //result frame is the result frames parent.
03376                   aPos->mResultFrame = resultFrame->GetParent();
03377                   return NS_POSITION_BEFORE_TABLE;
03378                 }
03379               }
03380             }
03381           }
03382         }
03383 
03384         if (!resultFrame->HasView())
03385         {
03386           rect = resultFrame->GetRect();
03387           result = resultFrame->GetContentAndOffsetsFromPoint(context,point,
03388                                         getter_AddRefs(aPos->mResultContent),
03389                                         aPos->mContentOffset,
03390                                         aPos->mContentOffsetEnd,
03391                                         aPos->mPreferLeft);
03392           if (NS_SUCCEEDED(result))
03393           {
03394             PRBool selectable;
03395             resultFrame->IsSelectable(&selectable, nsnull);
03396             if (selectable)
03397             {
03398               found = PR_TRUE;
03399               break;
03400             }
03401           }
03402         }
03403 
03404         if (aPos->mDirection == eDirPrevious && (resultFrame == farStoppingFrame))
03405           break;
03406         if (aPos->mDirection == eDirNext && (resultFrame == nearStoppingFrame))
03407           break;
03408         //always try previous on THAT line if that fails go the other way
03409         result = frameTraversal->Prev();
03410         if (NS_FAILED(result))
03411           break;
03412         result = frameTraversal->CurrentItem(&isupports);
03413         if (NS_FAILED(result) || !isupports)
03414           return result;
03415         //we must CAST here to an nsIFrame. nsIFrame doesnt really follow the rules
03416         resultFrame = (nsIFrame *)isupports;
03417       }
03418 
03419       if (!found){
03420         resultFrame = storeOldResultFrame;
03421         result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal), LEAF,
03422                                       aPresContext, resultFrame, aPos->mScrollViewStop);
03423       }
03424       while ( !found ){
03425         nsPresContext *context = aPos->mShell->GetPresContext();
03426 
03427         nsPoint point;
03428         point.x = aPos->mDesiredX;
03429         point.y = 0;
03430 
03431         result = resultFrame->GetContentAndOffsetsFromPoint(context,point,
03432                                           getter_AddRefs(aPos->mResultContent), aPos->mContentOffset,
03433                                           aPos->mContentOffsetEnd, aPos->mPreferLeft);
03434         if (NS_SUCCEEDED(result))
03435         {
03436           PRBool selectable;
03437           resultFrame->IsSelectable(&selectable, nsnull);
03438           if (selectable)
03439           {
03440             found = PR_TRUE;
03441             if (resultFrame == farStoppingFrame)
03442               aPos->mPreferLeft = PR_FALSE;
03443             else
03444               aPos->mPreferLeft = PR_TRUE;
03445             break;
03446           }
03447         }
03448         if (aPos->mDirection == eDirPrevious && (resultFrame == nearStoppingFrame))
03449           break;
03450         if (aPos->mDirection == eDirNext && (resultFrame == farStoppingFrame))
03451           break;
03452         //previous didnt work now we try "next"
03453         result = frameTraversal->Next();
03454         if (NS_FAILED(result))
03455           break;
03456         result = frameTraversal->CurrentItem(&isupports);
03457         if (NS_FAILED(result) || !isupports)
03458           break;
03459         //we must CAST here to an nsIFrame. nsIFrame doesnt really follow the rules
03460         resultFrame = (nsIFrame *)isupports;
03461       }
03462       aPos->mResultFrame = resultFrame;
03463     }
03464     else {
03465         //we need to jump to new block frame.
03466       aPos->mAmount = eSelectLine;
03467       aPos->mStartOffset = 0;
03468       aPos->mEatingWS = PR_FALSE;
03469       aPos->mPreferLeft = !(aPos->mDirection == eDirNext);
03470       if (aPos->mDirection == eDirPrevious)
03471         aPos->mStartOffset = -1;//start from end
03472      return aBlockFrame->PeekOffset(aPresContext, aPos);
03473     }
03474   }
03475   return NS_OK;
03476 }
03477 
03478 nsPeekOffsetStruct nsIFrame::GetExtremeCaretPosition(PRBool aStart)
03479 {
03480   nsPeekOffsetStruct result;
03481 
03482   result.mResultContent = this->GetContent();
03483   result.mContentOffset = 0;
03484 
03485   nsIFrame *resultFrame = this;
03486 
03487   if (aStart)
03488     nsFrame::GetFirstLeaf(GetPresContext(), &resultFrame);
03489   else
03490     nsFrame::GetLastLeaf(GetPresContext(), &resultFrame);
03491 
03492   NS_ASSERTION(resultFrame,"result frame for carent positioning is Null!");
03493 
03494   if (!resultFrame)
03495     return result;
03496 
03497   // there should be some more validity checks here, or earlier in the code,
03498   // in case we get to to some 'dummy' frames at the end of the content
03499     
03500   nsIContent* content = resultFrame->GetContent();
03501 
03502   NS_ASSERTION(resultFrame,"result frame content for carent positioning is Null!");
03503 
03504   if (!content)
03505     return result;
03506   
03507   // special case: if this is not a textnode,
03508   // position the caret to the offset of its parent instead
03509   // (position the caret to non-text element may make the caret missing)
03510 
03511   if (!content->IsContentOfType(nsIContent::eTEXT)) {
03512     // special case in effect
03513     nsIContent* parent = content->GetParent();
03514     NS_ASSERTION(parent,"element has no parent!");
03515     if (parent) {
03516       result.mResultContent = parent;
03517       result.mContentOffset = parent->IndexOf(content);
03518       if (!aStart)
03519         result.mContentOffset++; // go to end of this frame
03520       return result;
03521     }
03522   }
03523 
03524   result.mResultContent = content;
03525 
03526   PRInt32 start, end;
03527   nsresult rv;
03528   rv = resultFrame->GetOffsets(start,end);
03529   if (NS_SUCCEEDED(rv)) {
03530     result.mContentOffset = aStart ? start : end;
03531   }
03532 
03533   return result;
03534 }
03535 
03536 // Get a frame which can contain a line iterator
03537 // (which generally means it's a block frame).
03538 static nsILineIterator*
03539 GetBlockFrameAndLineIter(nsIFrame* aFrame, nsIFrame** aBlockFrame)
03540 {
03541   nsILineIterator* it;
03542   nsIFrame *blockFrame = aFrame;
03543 
03544   blockFrame = blockFrame->GetParent();
03545   if (!blockFrame) //if at line 0 then nothing to do
03546     return 0;
03547   nsresult result = blockFrame->QueryInterface(NS_GET_IID(nsILineIterator), (void**)&it);
03548   if (NS_SUCCEEDED(result) && it)
03549   {
03550     if (aBlockFrame)
03551       *aBlockFrame = blockFrame;
03552     return it;
03553   }
03554 
03555   while (blockFrame)
03556   {
03557     blockFrame = blockFrame->GetParent();
03558     if (blockFrame) {
03559       result = blockFrame->QueryInterface(NS_GET_IID(nsILineIterator),
03560                                           (void**)&it);
03561       if (NS_SUCCEEDED(result) && it)
03562       {
03563         if (aBlockFrame)
03564           *aBlockFrame = blockFrame;
03565         return it;
03566       }
03567     }
03568   }
03569   return 0;
03570 }
03571 
03572 nsresult
03573 nsFrame::PeekOffsetParagraph(nsPresContext* aPresContext,
03574                              nsPeekOffsetStruct *aPos)
03575 {
03576 #ifdef DEBUG_paragraph
03577   printf("Selecting paragraph\n");
03578 #endif
03579   nsIFrame* blockFrame;
03580   nsCOMPtr<nsILineIterator> iter (getter_AddRefs(GetBlockFrameAndLineIter(this, &blockFrame)));
03581   if (!blockFrame || !iter)
03582     return NS_ERROR_UNEXPECTED;
03583 
03584   PRInt32 thisLine;
03585   nsresult result = iter->FindLineContaining(this, &thisLine);
03586 #ifdef DEBUG_paragraph
03587   printf("Looping %s from line %d\n",
03588          aPos->mDirection == eDirPrevious ? "back" : "forward",
03589          thisLine);
03590 #endif
03591   if (NS_FAILED(result) || thisLine < 0)
03592     return result ? result : NS_ERROR_UNEXPECTED;
03593 
03594   // Now, theoretically, we should be able to loop over lines
03595   // looking for lines that end in breaks.
03596   PRInt32 di = (aPos->mDirection == eDirPrevious ? -1 : 1);
03597   for (PRInt32 i = thisLine; ; i += di)
03598   {
03599     nsIFrame* firstFrameOnLine;
03600     PRInt32 numFramesOnLine;
03601     nsRect lineBounds;
03602     PRUint32 lineFlags;
03603     if (i >= 0)
03604     {
03605       result = iter->GetLine(i, &firstFrameOnLine, &numFramesOnLine,
03606                              lineBounds, &lineFlags);
03607       if (NS_FAILED(result) || !firstFrameOnLine || !numFramesOnLine)
03608       {
03609 #ifdef DEBUG_paragraph
03610         printf("End loop at line %d\n", i);
03611 #endif
03612         break;
03613       }
03614     }
03615     if (lineFlags & NS_LINE_FLAG_ENDS_IN_BREAK || i < 0)
03616     {
03617       // Fill in aPos with the info on the new position
03618 #ifdef DEBUG_paragraph
03619       printf("Found a paragraph break at line %d\n", i);
03620 #endif
03621 
03622       // Save the old direction, but now go one line back the other way
03623       nsDirection oldDirection = aPos->mDirection;
03624       if (oldDirection == eDirPrevious)
03625         aPos->mDirection = eDirNext;
03626       else
03627         aPos->mDirection = eDirPrevious;
03628 #ifdef SIMPLE /* nope */
03629       result = GetNextPrevLineFromeBlockFrame(aPresContext,
03630                                               aPos,
03631                                               blockFrame,
03632                                               i,
03633                                               0);
03634       if (NS_FAILED(result))
03635         printf("GetNextPrevLineFromeBlockFrame failed\n");
03636 
03637 #else /* SIMPLE -- alas, nope */
03638       int edgeCase = 0;//no edge case. this should look at thisLine
03639       PRBool doneLooping = PR_FALSE;//tells us when no more block frames hit.
03640       //this part will find a frame or a block frame. if its a block frame
03641       //it will "drill down" to find a viable frame or it will return an error.
03642       do {
03643         result = GetNextPrevLineFromeBlockFrame(aPresContext,
03644                                                 aPos, 
03645                                                 blockFrame, 
03646                                                 thisLine, 
03647                                                 edgeCase //start from thisLine
03648           );
03649         if (aPos->mResultFrame == this)//we came back to same spot! keep going
03650         {
03651           aPos->mResultFrame = nsnull;
03652           if (aPos->mDirection == eDirPrevious)
03653             thisLine--;
03654           else
03655             thisLine++;
03656         }
03657         else
03658           doneLooping = PR_TRUE; //do not continue with while loop
03659         if (NS_SUCCEEDED(result) && aPos->mResultFrame)
03660         {
03661           result = aPos->mResultFrame->QueryInterface(NS_GET_IID(nsILineIterator),
03662                                                       getter_AddRefs(iter));
03663           if (NS_SUCCEEDED(result) && iter)//we've struck another block element!
03664           {
03665             doneLooping = PR_FALSE;
03666             if (aPos->mDirection == eDirPrevious)
03667               edgeCase = 1;//far edge, search from end backwards
03668             else
03669               edgeCase = -1;//near edge search from beginning onwards
03670             thisLine=0;//this line means nothing now.
03671             //everything else means something so keep looking "inside" the block
03672             blockFrame = aPos->mResultFrame;
03673 
03674           }
03675           else
03676             result = NS_OK;//THIS is to mean that everything is ok to the containing while loop
03677         }
03678       } while (!doneLooping);
03679 
03680 #endif /* SIMPLE -- alas, nope */
03681 
03682       // Restore old direction before returning:
03683       aPos->mDirection = oldDirection;
03684       return result;
03685     }
03686   }
03687 
03688   return NS_OK;
03689 }
03690 
03691 // Line and paragraph selection (and probably several other cases)
03692 // can get a containing frame from a line iterator, but then need
03693 // to "drill down" to get the content and offset corresponding to
03694 // the last child subframe.  Hence:
03695 // Alas, this doesn't entirely work; it's blocked by some style changes.
03696 static nsresult
03697 DrillDownToEndOfLine(nsIFrame* aFrame, PRInt32 aLineNo, PRInt32 aLineFrameCount,
03698                      nsRect& aUsedRect, nsPeekOffsetStruct* aPos)
03699 {
03700   if (!aFrame)
03701     return NS_ERROR_UNEXPECTED;
03702   nsresult rv = NS_ERROR_FAILURE;
03703   PRBool found = PR_FALSE;
03704   nsCOMPtr<nsIAtom> frameType;
03705   while (!found)  // this loop searches for a valid point to leave the peek offset struct.
03706   {
03707     nsIFrame *nextFrame = aFrame;
03708     nsIFrame *currentFrame = aFrame;
03709     PRInt32 i;
03710     for (i=1; i<aLineFrameCount && nextFrame; i++) //already have 1st frame
03711     {
03712                 currentFrame = nextFrame;
03713       // If we do GetNextSibling, we don't go far enough
03714       // (is aLineFrameCount too small?)
03715       // If we do GetNextInFlow, we hit a null.
03716       nextFrame = currentFrame->GetNextSibling();
03717     }
03718     if (!nextFrame) //premature leaving of loop.
03719     {
03720       nextFrame = currentFrame; //back it up. lets show a warning
03721       NS_WARNING("lineFrame Count lied to us from nsILineIterator!\n");
03722     }
03723     if (!nextFrame->GetRect().width) //this can happen with BR frames and or empty placeholder frames.
03724     {
03725       //if we do hit an empty frame then back up the current frame to the frame before it if there is one.
03726       nextFrame = currentFrame; 
03727     }
03728       
03729     nsPoint offsetPoint; //used for offset of result frame
03730     nsIView * view; //used for call of get offset from view
03731     nextFrame->GetOffsetFromView(offsetPoint, &view);
03732 
03733     offsetPoint.x += 2* aUsedRect.width; //2* just to be sure we are off the edge
03734     // This doesn't seem very efficient since GetPosition
03735     // has to do a binary search.
03736 
03737     nsPresContext *context = aPos->mShell->GetPresContext();
03738     PRInt32 endoffset;
03739     rv = nextFrame->GetContentAndOffsetsFromPoint(context,
03740                                                   offsetPoint,
03741                                                   getter_AddRefs(aPos->mResultContent),
03742                                                   aPos->mContentOffset,
03743                                                   endoffset,
03744                                                   aPos->mPreferLeft);
03745     if (NS_SUCCEEDED(rv))
03746       return PR_TRUE;
03747 
03748 #ifdef DEBUG_paragraph
03749     NS_ASSERTION(PR_FALSE, "Looping around in PeekOffset\n");
03750 #endif
03751     aLineFrameCount--;
03752     if (aLineFrameCount == 0)
03753       break;//just fail out
03754   }
03755   return rv;
03756 }
03757 
03758 
03759 NS_IMETHODIMP
03760 nsFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
03761 {
03762   if (!aPos || !aPos->mShell)
03763     return NS_ERROR_NULL_POINTER;
03764   nsresult result = NS_ERROR_FAILURE; 
03765   PRInt32 endoffset;
03766   nsPoint point;
03767   point.x = aPos->mDesiredX;
03768   point.y = 0;
03769   switch (aPos->mAmount){
03770   case eSelectCharacter : case eSelectWord:
03771     {
03772       if (mContent)
03773       {
03774         nsIContent* newContent = mContent->GetParent();
03775         if (newContent){
03776           aPos->mResultContent = newContent;
03777 
03778           PRInt32 newOffset = newContent->IndexOf(mContent);
03779 
03780           if (aPos->mDirection == eDirNext)
03781             aPos->mContentOffset = newOffset + 1;
03782           else
03783             aPos->mContentOffset = newOffset;//to beginning of frame
03784 
03785           nsTextTransformer::Initialize();
03786           if (nsTextTransformer::GetWordSelectEatSpaceAfter() &&
03787               aPos->mDirection == eDirNext && aPos->mEatingWS)
03788           {
03789             //If we want to stop at beginning of the next word
03790             //GetFrameFromDirection should not return NS_ERROR_FAILURE
03791             //at end of line
03792             aPos->mEatingWS = PR_FALSE;   
03793             result = GetFrameFromDirection(aPresContext, aPos);
03794             aPos->mEatingWS = PR_TRUE;
03795           }
03796           else
03797             result = GetFrameFromDirection(aPresContext, aPos);
03798 
03799           if (NS_FAILED(result))
03800             return result;
03801           PRBool selectable = PR_FALSE;
03802           if (aPos->mResultFrame)
03803             aPos->mResultFrame->IsSelectable(&selectable, nsnull);
03804           if (NS_FAILED(result) || !aPos->mResultFrame || !selectable)
03805           {
03806             return result?result:NS_ERROR_FAILURE;
03807           }
03808           return aPos->mResultFrame->PeekOffset(aPresContext, aPos);
03809         }
03810       }
03811       break;
03812     }//drop into no amount
03813     case eSelectNoAmount:
03814     {
03815       nsPresContext *context = aPos->mShell->GetPresContext();
03816       if (!context)
03817         return NS_OK;
03818       result = GetContentAndOffsetsFromPoint(context,point,
03819                              getter_AddRefs(aPos->mResultContent),
03820                              aPos->mContentOffset,
03821                              endoffset,
03822                              aPos->mPreferLeft);
03823     }break;
03824     case eSelectLine :
03825     {
03826       nsCOMPtr<nsILineIteratorNavigator> iter; 
03827       nsIFrame *blockFrame = this;
03828       nsIFrame *thisBlock = this;
03829       PRInt32   thisLine;
03830 
03831       while (NS_FAILED(result)){
03832         thisBlock = blockFrame;
03833         blockFrame = blockFrame->GetParent();
03834         if (!blockFrame) //if at line 0 then nothing to do
03835           return NS_OK;
03836         result = blockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(iter));
03837         while (NS_FAILED(result) && blockFrame)
03838         {
03839           thisBlock = blockFrame;
03840           blockFrame = blockFrame->GetParent();
03841           result = NS_OK;
03842           if (blockFrame) {
03843             result = blockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(iter));
03844           }
03845         }
03846         //this block is now one child down from blockframe
03847         if (NS_FAILED(result) || !iter || !blockFrame || !thisBlock)
03848         {
03849           return ((result) ? result : NS_ERROR_FAILURE);
03850         }
03851 
03852         if (thisBlock->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
03853         {
03854           //if we are searching for a frame that is not in flow we will not find it. 
03855           //we must instead look for its placeholder
03856           thisBlock =
03857             aPresContext->FrameManager()->GetPlaceholderFrameFor(thisBlock);
03858 
03859           if (!thisBlock)
03860             return NS_ERROR_FAILURE;
03861         }
03862 
03863         result = iter->FindLineContaining(thisBlock, &thisLine);
03864 
03865         if (NS_FAILED(result))
03866            return result;
03867 
03868         if (thisLine < 0) 
03869           return  NS_ERROR_FAILURE;
03870 
03871         int edgeCase = 0;//no edge case. this should look at thisLine
03872         PRBool doneLooping = PR_FALSE;//tells us when no more block frames hit.
03873         //this part will find a frame or a block frame. if its a block frame
03874         //it will "drill down" to find a viable frame or it will return an error.
03875         nsIFrame *lastFrame = this;
03876         do {
03877           result = GetNextPrevLineFromeBlockFrame(aPresContext,
03878                                                   aPos, 
03879                                                   blockFrame, 
03880                                                   thisLine, 
03881                                                   edgeCase //start from thisLine
03882             );
03883           if (NS_SUCCEEDED(result) && (!aPos->mResultFrame || aPos->mResultFrame == lastFrame))//we came back to same spot! keep going
03884           {
03885             aPos->mResultFrame = nsnull;
03886             if (aPos->mDirection == eDirPrevious)
03887               thisLine--;
03888             else
03889               thisLine++;
03890           }
03891           else //if failure or success with different frame.
03892             doneLooping = PR_TRUE; //do not continue with while loop
03893 
03894           lastFrame = aPos->mResultFrame; //set last frame 
03895 
03896           if (NS_SUCCEEDED(result) && aPos->mResultFrame 
03897             && blockFrame != aPos->mResultFrame)// make sure block element is not the same as the one we had before
03898           {
03899 /* SPECIAL CHECK FOR TABLE NAVIGATION
03900   tables need to navigate also and the frame that supports it is nsTableRowGroupFrame which is INSIDE
03901   nsTableOuterFrame.  if we have stumbled onto an nsTableOuter we need to drill into nsTableRowGroup
03902   if we hit a header or footer thats ok just go into them,
03903 */
03904             PRBool searchTableBool = PR_FALSE;
03905             if (aPos->mResultFrame->GetType() == nsLayoutAtoms::tableOuterFrame ||
03906                 aPos->mResultFrame->GetType() == nsLayoutAtoms::tableCellFrame)
03907             {
03908               nsIFrame *frame = aPos->mResultFrame->GetFirstChild(nsnull);
03909               //got the table frame now
03910               while(frame) //ok time to drill down to find iterator
03911               {
03912                 result = frame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),
03913                                                           getter_AddRefs(iter));
03914                 if (NS_SUCCEEDED(result))
03915                 {
03916                   aPos->mResultFrame = frame;
03917                   searchTableBool = PR_TRUE;
03918                   break; //while(frame)
03919                 }
03920                 frame = frame->GetFirstChild(nsnull);
03921               }
03922             }
03923             if (!searchTableBool)
03924               result = aPos->mResultFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),
03925                                                         getter_AddRefs(iter));
03926             if (NS_SUCCEEDED(result) && iter)//we've struck another block element!
03927             {
03928               doneLooping = PR_FALSE;
03929               if (aPos->mDirection == eDirPrevious)
03930                 edgeCase = 1;//far edge, search from end backwards
03931               else
03932                 edgeCase = -1;//near edge search from beginning onwards
03933               thisLine=0;//this line means nothing now.
03934               //everything else means something so keep looking "inside" the block
03935               blockFrame = aPos->mResultFrame;
03936 
03937             }
03938             else
03939             {
03940               result = NS_OK;//THIS is to mean that everything is ok to the containing while loop
03941               break;
03942             }
03943           }
03944         } while (!doneLooping);
03945       }
03946       break;
03947     }
03948 
03949     case eSelectParagraph:
03950       return PeekOffsetParagraph(aPresContext, aPos);
03951 
03952     case eSelectBeginLine:
03953     case eSelectEndLine:
03954     {
03955       nsCOMPtr<nsILineIteratorNavigator> it; 
03956       nsIFrame* thisBlock = this;
03957       nsIFrame* blockFrame = GetParent();
03958       if (!blockFrame) //if at line 0 then nothing to do
03959         return NS_OK;
03960       result = blockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(it));
03961       while (NS_FAILED(result) && blockFrame)
03962       {
03963         thisBlock = blockFrame;
03964         blockFrame = blockFrame->GetParent();
03965         result = NS_OK;
03966         if (blockFrame) {
03967           result = blockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(it));
03968         }
03969       }
03970       if (NS_FAILED(result) || !it || !blockFrame || !thisBlock)
03971         return result;
03972       //this block is now one child down from blockframe
03973 
03974       PRInt32   thisLine;
03975       result = it->FindLineContaining(thisBlock, &thisLine);
03976       if (NS_FAILED(result) || thisLine < 0 )
03977         return result;
03978 
03979       PRInt32 lineFrameCount;
03980       nsIFrame *firstFrame;
03981       nsRect  usedRect; 
03982       PRUint32 lineFlags;
03983       result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,usedRect,
03984                            &lineFlags);
03985 
03986       if (eSelectBeginLine == aPos->mAmount)
03987       {
03988         nsPresContext *context = aPos->mShell->GetPresContext();
03989         if (!context)
03990           return NS_OK;
03991 
03992         while (firstFrame)
03993         {
03994           nsPoint offsetPoint; //used for offset of result frame
03995           nsIView * view; //used for call of get offset from view
03996           firstFrame->GetOffsetFromView(offsetPoint, &view);
03997 
03998           offsetPoint.x = 0;//all the way to the left
03999           result = firstFrame->GetContentAndOffsetsFromPoint(context,
04000                                                              offsetPoint,
04001                                            getter_AddRefs(aPos->mResultContent),
04002                                            aPos->mContentOffset,
04003                                            endoffset,
04004                                            aPos->mPreferLeft);
04005           if (NS_SUCCEEDED(result))
04006             break;
04007           result = it->GetNextSiblingOnLine(firstFrame,thisLine);
04008           if (NS_FAILED(result))
04009             break;
04010         }
04011       }
04012       else  // eSelectEndLine
04013       {
04014         // We have the last frame, but we need to drill down
04015         // to get the last offset in the last content represented
04016         // by that frame.
04017         return DrillDownToEndOfLine(firstFrame, thisLine, lineFrameCount,
04018                                     usedRect, aPos);
04019       }
04020       return result;
04021     }
04022     break;
04023 
04024     default: 
04025     {
04026       if (NS_SUCCEEDED(result))
04027         result = aPos->mResultFrame->PeekOffset(aPresContext, aPos);
04028     }
04029   }                          
04030   return result;
04031 }
04032 
04033 
04034 NS_IMETHODIMP
04035 nsFrame::CheckVisibility(nsPresContext* , PRInt32 , PRInt32 , PRBool , PRBool *, PRBool *)
04036 {
04037   return NS_ERROR_NOT_IMPLEMENTED;
04038 }
04039 
04040 
04041 PRInt32
04042 nsFrame::GetLineNumber(nsIFrame *aFrame)
04043 {
04044   nsIFrame *blockFrame = aFrame;
04045   nsIFrame *thisBlock;
04046   PRInt32   thisLine;
04047   nsCOMPtr<nsILineIteratorNavigator> it; 
04048   nsresult result = NS_ERROR_FAILURE;
04049   while (NS_FAILED(result) && blockFrame)
04050   {
04051     thisBlock = blockFrame;
04052     blockFrame = blockFrame->GetParent();
04053     result = NS_OK;
04054     if (blockFrame) {
04055       result = blockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(it));
04056     }
04057   }
04058   if (!blockFrame || !it)
04059     return NS_ERROR_FAILURE;
04060   result = it->FindLineContaining(thisBlock, &thisLine);
04061   if (NS_FAILED(result))
04062     return -1;
04063   return thisLine;
04064 }
04065 
04066 
04067 //this will use the nsFrameTraversal as the default peek method.
04068 //this should change to use geometry and also look to ALL the child lists
04069 //we need to set up line information to make sure we dont jump across line boundaries
04070 NS_IMETHODIMP
04071 nsFrame::GetFrameFromDirection(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
04072 {
04073   nsIFrame *blockFrame = this;
04074   nsIFrame *thisBlock;
04075   PRInt32   thisLine;
04076   nsCOMPtr<nsILineIteratorNavigator> it; 
04077   PRBool preferLeft = aPos->mPreferLeft;
04078   nsresult result = NS_ERROR_FAILURE;
04079   while (NS_FAILED(result) && blockFrame)
04080   {
04081     thisBlock = blockFrame;
04082     blockFrame = blockFrame->GetParent();
04083     result = NS_OK;
04084     if (blockFrame) {
04085       result = blockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(it));
04086     }
04087   }
04088   if (!blockFrame || !it)
04089     return NS_ERROR_FAILURE;
04090   result = it->FindLineContaining(thisBlock, &thisLine);
04091   if (NS_FAILED(result))
04092     return result;
04093 
04094   nsIFrame *traversedFrame = this;
04095 
04096   nsIFrame *firstFrame;
04097   nsIFrame *lastFrame;
04098   nsRect  nonUsedRect;
04099   PRInt32 lineFrameCount;
04100   PRUint32 lineFlags;
04101 
04102 #ifdef IBMBIDI
04103   /* Check whether the visual and logical order of the frames are different */
04104   PRBool lineIsReordered = PR_FALSE;
04105   nsIFrame *firstVisual;
04106   nsIFrame *lastVisual;
04107   PRBool lineIsRTL;
04108   PRBool lineJump = PR_FALSE;
04109 
04110   it->GetDirection(&lineIsRTL);
04111   result = it->CheckLineOrder(thisLine, &lineIsReordered, &firstVisual, &lastVisual);
04112   if (NS_FAILED(result))
04113     return result;
04114 
04115   if (lineIsReordered) {
04116     firstFrame = firstVisual;
04117     lastFrame = lastVisual;
04118   }
04119   else
04120 #endif
04121   {
04122     result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,nonUsedRect,
04123                          &lineFlags);
04124     if (NS_FAILED(result))
04125       return result;
04126 
04127     lastFrame = firstFrame;
04128     for (;lineFrameCount > 1;lineFrameCount --){
04129       result = it->GetNextSiblingOnLine(lastFrame, thisLine);
04130       if (NS_FAILED(result) || !lastFrame){
04131         NS_ASSERTION(0,"should not be reached nsFrame\n");
04132         return NS_ERROR_FAILURE;
04133       }
04134     }
04135   }
04136 
04137   GetFirstLeaf(aPresContext, &firstFrame);
04138   GetLastLeaf(aPresContext, &lastFrame);
04139   //END LINE DATA CODE
04140   if 
04141 #ifndef IBMBIDI  // jumping lines in RTL paragraphs
04142       ((aPos->mDirection == eDirNext && lastFrame == this)
04143        ||(aPos->mDirection == eDirPrevious && firstFrame == this))
04144 #else
04145       (((lineIsRTL) &&
04146         ((aPos->mDirection == eDirNext && firstFrame == this)
04147          ||(aPos->mDirection == eDirPrevious && lastFrame == this)))
04148        ||
04149        ((!lineIsRTL) &&
04150         ((aPos->mDirection == eDirNext && lastFrame == this)
04151          ||(aPos->mDirection == eDirPrevious && firstFrame == this))))
04152 #endif
04153   {
04154     if (aPos->mJumpLines != PR_TRUE)
04155       return NS_ERROR_FAILURE;//we are done. cannot jump lines
04156 #ifdef IBMBIDI
04157     lineJump = PR_TRUE;
04158 #endif
04159     if (aPos->mAmount != eSelectWord)
04160     {
04161       preferLeft = (PRBool)!preferLeft;//drift to other side
04162       aPos->mAmount = eSelectNoAmount;
04163     }
04164     else{
04165       if (aPos->mEatingWS)//done finding what we wanted
04166         return NS_ERROR_FAILURE;
04167       if (aPos->mDirection == eDirNext)
04168       {
04169         preferLeft = (PRBool)!preferLeft;//drift to other side
04170       }
04171 #ifdef IBMBIDI
04172       if (lineIsRTL)
04173         aPos->mAmount = eSelectNoAmount;
04174 #endif
04175     }
04176 
04177   }
04178   if (aPos->mAmount == eSelectDir)
04179     aPos->mAmount = eSelectNoAmount;//just get to next frame.
04180   nsCOMPtr<nsIBidirectionalEnumerator> frameTraversal;
04181 #ifdef IBMBIDI
04182   result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
04183                                 lineIsReordered ? VISUAL : LEAF,
04184                                 aPresContext, 
04185                                 traversedFrame, aPos->mScrollViewStop);
04186 #else
04187   //if we are a container frame we MUST init with last leaf for eDirNext
04188   //
04189   result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal), LEAF, aPresContext, traversedFrame, aPos->mScrollViewStop);
04190 #endif
04191   if (NS_FAILED(result))
04192     return result;
04193   nsISupports *isupports = nsnull;
04194 #ifdef IBMBIDI
04195   nsIFrame *newFrame;
04196 
04197   for (;;) {
04198     if (lineIsRTL) 
04199       if (aPos->mDirection == eDirPrevious)
04200         result = frameTraversal->Next();
04201       else 
04202         result = frameTraversal->Prev();
04203     else
04204 #endif
04205       if (aPos->mDirection == eDirNext)
04206         result = frameTraversal->Next();
04207       else 
04208         result = frameTraversal->Prev();
04209     
04210   if (NS_FAILED(result))
04211     return result;
04212   result = frameTraversal->CurrentItem(&isupports);
04213   if (NS_FAILED(result))
04214     return result;
04215   if (!isupports)
04216     return NS_ERROR_NULL_POINTER;
04217   //we must CAST here to an nsIFrame. nsIFrame doesnt really follow the rules
04218   //for speed reasons
04219 #ifndef IBMBIDI
04220   nsIFrame *newFrame = (nsIFrame *)isupports;
04221 #else
04222   
04223   newFrame = (nsIFrame *)isupports;
04224   nsIContent *content = newFrame->GetContent();
04225   if (!lineJump && (content == mContent))
04226   {
04227     //we will continue if this is NOT a text node. 
04228     //in the case of a text node since that does not mean we are stuck. it could mean a change in style for
04229     //the text node.  in the case of a hruleframe with generated before and after content, we do not
04230     //want the splittable generated frame to get us stuck on an HR
04231     if (nsLayoutAtoms::textFrame != newFrame->GetType())
04232       continue;  //we should NOT be getting stuck on the same piece of content on the same line. skip to next line.
04233   }
04234   PRBool isBidiGhostFrame = (newFrame->GetRect().IsEmpty() &&
04235                              (newFrame->GetStateBits() & NS_FRAME_IS_BIDI));
04236   if (isBidiGhostFrame)
04237   {
04238     // If the rectangle is empty and the NS_FRAME_IS_BIDI flag is set, this is most likely 
04239     // a non-renderable frame created at the end of the line by Bidi reordering.
04240     lineJump = PR_TRUE;
04241     aPos->mAmount = eSelectNoAmount;
04242   }
04243   else
04244   {
04245     PRBool selectable =  PR_TRUE; //usually fine
04246     newFrame->IsSelectable(&selectable, nsnull);
04247     if (selectable)
04248       break; // for (;;)
04249   }
04250   PRBool newLineIsRTL = PR_FALSE;
04251   if (lineJump) {
04252     blockFrame = newFrame;
04253     nsresult result = NS_ERROR_FAILURE;
04254     while (NS_FAILED(result) && blockFrame)
04255     {
04256       thisBlock = blockFrame;
04257       blockFrame = blockFrame->GetParent();
04258       result = NS_OK;
04259       if (blockFrame) {
04260         result = blockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator), getter_AddRefs(it));
04261       }
04262     }
04263     if (!blockFrame || !it)
04264       return NS_ERROR_FAILURE;
04265     result = it->FindLineContaining(thisBlock, &thisLine);
04266     if (NS_FAILED(result))
04267       return result;
04268     it->GetDirection(&newLineIsRTL);
04269 
04270     result = it->CheckLineOrder(thisLine, &lineIsReordered, &firstVisual, &lastVisual);
04271     if (NS_FAILED(result))
04272       return result;
04273 
04274     if (lineIsReordered)
04275     {
04276       firstFrame = firstVisual;
04277       lastFrame = lastVisual;
04278     }
04279     else
04280     {
04281       result = it->GetLine(thisLine, &firstFrame, &lineFrameCount, nonUsedRect,
04282                            &lineFlags);
04283       if (NS_FAILED(result))
04284         return result;
04285       if (!firstFrame)
04286         return NS_ERROR_FAILURE;
04287 
04288       lastFrame = firstFrame;
04289       for (;lineFrameCount > 1;lineFrameCount --){
04290         result = it->GetNextSiblingOnLine(lastFrame, thisLine);
04291         if (NS_FAILED(result) || !lastFrame){
04292           NS_ASSERTION(0,"should not be reached nsFrame\n");
04293           return NS_ERROR_FAILURE;
04294         }
04295       }
04296     }
04297 
04298     GetFirstLeaf(aPresContext, &firstFrame);
04299     GetLastLeaf(aPresContext, &lastFrame);
04300 
04301     if (newLineIsRTL) {
04302       if (aPos->mDirection == eDirPrevious)
04303         newFrame = firstFrame;
04304       else
04305         newFrame = lastFrame;
04306     }
04307     else {
04308       if (aPos->mDirection == eDirNext)
04309         newFrame = firstFrame;
04310       else
04311         newFrame = lastFrame;
04312       }
04313     }
04314     PRBool selectable =  PR_TRUE; //usually fine
04315     newFrame->IsSelectable(&selectable, nsnull);
04316     if (!selectable)
04317       lineJump = PR_FALSE;
04318   } // for (;;) we will break from inside
04319 #endif // IBMBIDI
04320   if (aPos->mDirection == eDirNext)
04321     aPos->mStartOffset = 0;
04322   else
04323     aPos->mStartOffset = -1;
04324 #ifdef IBMBIDI
04325   PRUint8 oldLevel = NS_GET_EMBEDDING_LEVEL(this);
04326   PRUint8 newLevel = NS_GET_EMBEDDING_LEVEL(newFrame);
04327   if (newLevel & 1) // The new frame is RTL, go to the other end
04328     aPos->mStartOffset = -1 - aPos->mStartOffset;
04329 
04330   if ((aPos->mAmount == eSelectNoAmount) && ((newLevel & 1) != (oldLevel & 1)))  {
04331     preferLeft = (PRBool)!preferLeft;
04332   }
04333 #endif
04334   aPos->mResultFrame = newFrame;
04335   aPos->mPreferLeft = preferLeft;
04336   return NS_OK;
04337 }
04338 
04339 nsIView* nsIFrame::GetClosestView(nsPoint* aOffset) const
04340 {
04341   nsPoint offset(0,0);
04342   for (const nsIFrame *f = this; f; f = f->GetParent()) {
04343     if (f->HasView()) {
04344       if (aOffset)
04345         *aOffset = offset;
04346       return f->GetView();
04347     }
04348     offset += f->GetPosition();
04349   }
04350 
04351   NS_NOTREACHED("No view on any parent?  How did that happen?");
04352   return nsnull;
04353 }
04354 
04355 
04356 NS_IMETHODIMP
04357 nsFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild)
04358 {
04359   NS_ASSERTION(0, "nsFrame::ReflowDirtyChild() should never be called.");  
04360   return NS_ERROR_NOT_IMPLEMENTED;    
04361 }
04362 
04363 
04364 #ifdef ACCESSIBILITY
04365 NS_IMETHODIMP
04366 nsFrame::GetAccessible(nsIAccessible** aAccessible)
04367 {
04368   return NS_ERROR_NOT_IMPLEMENTED;
04369 }
04370 #endif
04371 
04372 // Destructor function for the overflow area property
04373 static void
04374 DestroyRectFunc(void*           aFrame,
04375                 nsIAtom*        aPropertyName,
04376                 void*           aPropertyValue,
04377                 void*           aDtorData)
04378 {
04379   delete (nsRect*)aPropertyValue;
04380 }
04381 
04382 nsRect*
04383 nsIFrame::GetOverflowAreaProperty(PRBool aCreateIfNecessary) 
04384 {
04385   if (!((GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) || aCreateIfNecessary)) {
04386     return nsnull;
04387   }
04388 
04389   nsPropertyTable *propTable = GetPresContext()->PropertyTable();
04390   void *value = propTable->GetProperty(this,
04391                                        nsLayoutAtoms::overflowAreaProperty);
04392 
04393   if (value) {
04394     return (nsRect*)value;  // the property already exists
04395   } else if (aCreateIfNecessary) {
04396     // The property isn't set yet, so allocate a new rect, set the property,
04397     // and return the newly allocated rect
04398     nsRect*  overflow = new nsRect(0, 0, 0, 0);
04399     propTable->SetProperty(this, nsLayoutAtoms::overflowAreaProperty,
04400                            overflow, DestroyRectFunc, nsnull);
04401     return overflow;
04402   }
04403 
04404   return nsnull;
04405 }
04406 
04407 void 
04408 nsIFrame::FinishAndStoreOverflow(nsRect* aOverflowArea, nsSize aNewSize)
04409 {
04410   // This is now called FinishAndStoreOverflow() instead of 
04411   // StoreOverflow() because frame-generic ways of adding overflow
04412   // can happen here, e.g. CSS2 outline.
04413   // If we find more things other than outline that need to be added,
04414   // we should think about starting a new method like GetAdditionalOverflow()
04415   NS_ASSERTION(aNewSize.width == 0 || aNewSize.height == 0 ||
04416                aOverflowArea->Contains(nsRect(nsPoint(0, 0), aNewSize)),
04417                "Computed overflow area must contain frame bounds");
04418 
04419   PRBool geometricOverflow =
04420     aOverflowArea->x < 0 || aOverflowArea->y < 0 ||
04421     aOverflowArea->XMost() > aNewSize.width || aOverflowArea->YMost() > aNewSize.height;
04422   // Clear geometric overflow area if we clip our children
04423   NS_ASSERTION((GetStyleDisplay()->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
04424                (GetStyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
04425                "If one overflow is clip, the other should be too");
04426   if (geometricOverflow &&
04427       GetStyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_CLIP) {
04428     *aOverflowArea = nsRect(nsPoint(0, 0), aNewSize);
04429     geometricOverflow = PR_FALSE;
04430   }
04431 
04432   PRBool hasOutline;
04433   nsRect outlineRect(ComputeOutlineRect(this, &hasOutline, *aOverflowArea));
04434 
04435   if (hasOutline || geometricOverflow) {
04436     // Throw out any overflow if we're -moz-hidden-unscrollable
04437     mState |= NS_FRAME_OUTSIDE_CHILDREN;
04438     nsRect* overflowArea = GetOverflowAreaProperty(PR_TRUE); 
04439     NS_ASSERTION(overflowArea, "should have created rect");
04440     *aOverflowArea = *overflowArea = outlineRect;
04441   } 
04442   else {
04443     if (mState & NS_FRAME_OUTSIDE_CHILDREN) {
04444       // remove the previously stored overflow area 
04445       DeleteProperty(nsLayoutAtoms::overflowAreaProperty);
04446     }
04447     mState &= ~NS_FRAME_OUTSIDE_CHILDREN;
04448   }   
04449 }
04450 
04451 void
04452 nsFrame::ConsiderChildOverflow(nsRect&   aOverflowArea,
04453                                nsIFrame* aChildFrame)
04454 {
04455   const nsStyleDisplay* disp = GetStyleDisplay();
04456   // check here also for hidden as table frames (table, tr and td) currently 
04457   // don't wrap their content into a scrollable frame if overflow is specified
04458   if (!disp->IsTableClip()) {
04459     nsRect* overflowArea = aChildFrame->GetOverflowAreaProperty();
04460     if (overflowArea) {
04461       nsRect childOverflow(*overflowArea);
04462       childOverflow.MoveBy(aChildFrame->GetPosition());
04463       aOverflowArea.UnionRect(aOverflowArea, childOverflow);
04464     }
04465     else {
04466       aOverflowArea.UnionRect(aOverflowArea, aChildFrame->GetRect());
04467     }
04468   }
04469 }
04470 
04471 NS_IMETHODIMP 
04472 nsFrame::GetParentStyleContextFrame(nsPresContext* aPresContext,
04473                                     nsIFrame**      aProviderFrame,
04474                                     PRBool*         aIsChild)
04475 {
04476   return DoGetParentStyleContextFrame(aPresContext, aProviderFrame, aIsChild);
04477 }
04478 
04479 
04489 static nsresult
04490 GetIBSpecialSibling(nsPresContext* aPresContext,
04491                     nsIFrame* aFrame,
04492                     nsIFrame** aSpecialSibling)
04493 {
04494   NS_PRECONDITION(aFrame, "Must have a non-null frame!");
04495   NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL,
04496                "GetIBSpecialSibling should not be called on a non-special frame");
04497   
04498   // Find the first-in-flow of the frame.  (Ugh.  This ends up
04499   // being O(N^2) when it is called O(N) times.)
04500   aFrame = aFrame->GetFirstInFlow();
04501 
04502   /*
04503    * Now look up the nsLayoutAtoms::IBSplitSpecialPrevSibling
04504    * property, which is only set on the anonymous block frames we're
04505    * interested in.
04506    */
04507   nsresult rv;
04508   nsIFrame *specialSibling = NS_STATIC_CAST(nsIFrame*,
04509                              aPresContext->PropertyTable()->GetProperty(aFrame,
04510                                nsLayoutAtoms::IBSplitSpecialPrevSibling, &rv));
04511 
04512   if (NS_PROPTABLE_PROP_NOT_THERE == rv) {
04513     *aSpecialSibling = nsnull;
04514     rv = NS_OK;
04515   } else if (NS_SUCCEEDED(rv)) {
04516     NS_ASSERTION(specialSibling, "null special sibling");
04517     *aSpecialSibling = specialSibling;
04518   }
04519 
04520   return rv;
04521 }
04522 
04533 static nsresult
04534 GetCorrectedParent(nsPresContext* aPresContext, nsIFrame* aFrame,
04535                    nsIFrame** aSpecialParent)
04536 {
04537   nsIFrame *parent = aFrame->GetParent();
04538   if (!parent) {
04539     *aSpecialParent = nsnull;
04540   } else {
04541     nsIAtom* pseudo = aFrame->GetStyleContext()->GetPseudoType();
04542     // Outer tables are always anon boxes; if we're in here for an outer
04543     // table, that actually means its the _inner_ table that wants to
04544     // know its parent.  So get the pseudo of the inner in that case.
04545     if (pseudo == nsCSSAnonBoxes::tableOuter) {
04546       pseudo =
04547         aFrame->GetFirstChild(nsnull)->GetStyleContext()->GetPseudoType();
04548     }
04549     *aSpecialParent = nsFrame::CorrectStyleParentFrame(parent, pseudo);
04550   }
04551 
04552   return NS_OK;
04553 }
04554 
04555 /* static */
04556 nsIFrame*
04557 nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
04558                                  nsIAtom* aChildPseudo)
04559 {
04560   NS_PRECONDITION(aProspectiveParent, "Must have a prospective parent");
04561 
04562   // Anon boxes are parented to their actual parent already, except
04563   // for non-elements.  Those should not be treated as an anon box.
04564   if (aChildPseudo && aChildPseudo != nsCSSAnonBoxes::mozNonElement &&
04565       nsCSSAnonBoxes::IsAnonBox(aChildPseudo)) {
04566     NS_ASSERTION(aChildPseudo != nsCSSAnonBoxes::mozAnonymousBlock &&
04567                  aChildPseudo != nsCSSAnonBoxes::mozAnonymousPositionedBlock,
04568                  "Should have dealt with kids that have NS_FRAME_IS_SPECIAL "
04569                  "elsewhere");
04570     return aProspectiveParent;
04571   }
04572 
04573   // Otherwise, walk up out of all anon boxes
04574   nsIFrame* parent = aProspectiveParent;
04575   do {
04576     if (parent->GetStateBits() & NS_FRAME_IS_SPECIAL) {
04577       nsIFrame* sibling;
04578       nsresult rv =
04579         GetIBSpecialSibling(parent->GetPresContext(), parent, &sibling);
04580       if (NS_FAILED(rv)) {
04581         // If GetIBSpecialSibling fails, then what?  we used to return what is
04582         // now |aProspectiveParent|, but maybe |parent| would make more sense?
04583         NS_NOTREACHED("Shouldn't get here");
04584         return aProspectiveParent;
04585       }
04586 
04587       if (sibling) {
04588         // |parent| was the block in an {ib} split; use the inline as
04589         // |the style parent.
04590         parent = sibling;
04591       }
04592     }
04593       
04594     nsIAtom* parentPseudo = parent->GetStyleContext()->GetPseudoType();
04595     if (!parentPseudo || !nsCSSAnonBoxes::IsAnonBox(parentPseudo) ||
04596         parentPseudo == nsCSSAnonBoxes::dummyOption) {
04597       return parent;
04598     }
04599 
04600     parent = parent->GetParent();
04601   } while (parent);
04602 
04603   // We can get here if aProspectiveParent is the scrollframe for a viewport
04604   // and the kids are the anonymous scrollbars.
04605   NS_ASSERTION(aProspectiveParent->GetStyleContext()->GetPseudoType() ==
04606                nsCSSAnonBoxes::viewportScroll,
04607                "Should have found a parent before this");
04608   return aProspectiveParent;
04609 }
04610 
04611 nsresult
04612 nsFrame::DoGetParentStyleContextFrame(nsPresContext* aPresContext,
04613                                       nsIFrame**      aProviderFrame,
04614                                       PRBool*         aIsChild)
04615 {
04616   *aIsChild = PR_FALSE;
04617   *aProviderFrame = nsnull;
04618   if (mContent && !mContent->GetParent() &&
04619       !GetStyleContext()->GetPseudoType()) {
04620     // we're a frame for the root.  We have no style context parent.
04621     return NS_OK;
04622   }
04623   
04624   if (!(mState & NS_FRAME_OUT_OF_FLOW)) {
04625     /*
04626      * If this frame is the anonymous block created when an inline
04627      * with a block inside it got split, then the parent style context
04628      * is on the first of the three special frames.  We can get to it
04629      * using GetIBSpecialSibling
04630      */
04631     if (mState & NS_FRAME_IS_SPECIAL) {
04632       nsresult rv = GetIBSpecialSibling(aPresContext, this, aProviderFrame);
04633       if (NS_FAILED(rv)) {
04634         NS_NOTREACHED("Shouldn't get here");
04635         *aProviderFrame = nsnull;
04636         return rv;
04637       }
04638 
04639       if (*aProviderFrame) {
04640         return NS_OK;
04641       }
04642     }
04643 
04644     // If this frame is one of the blocks that split an inline, we must
04645     // return the "special" inline parent, i.e., the parent that this
04646     // frame would have if we didn't mangle the frame structure.
04647     return GetCorrectedParent(aPresContext, this, aProviderFrame);
04648   }
04649 
04650   // For out-of-flow frames, we must resolve underneath the
04651   // placeholder's parent.
04652   nsIFrame *placeholder =
04653     aPresContext->FrameManager()->GetPlaceholderFrameFor(this);
04654   if (!placeholder) {
04655     NS_NOTREACHED("no placeholder frame for out-of-flow frame");
04656     GetCorrectedParent(aPresContext, this, aProviderFrame);
04657     return NS_ERROR_FAILURE;
04658   }
04659   return NS_STATIC_CAST(nsFrame*, placeholder)->
04660     GetParentStyleContextFrame(aPresContext, aProviderFrame, aIsChild);
04661 }
04662 
04663 //-----------------------------------------------------------------------------------
04664 
04665 
04666 
04667 
04668 void
04669 nsFrame::GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
04670 {
04671   if (!aFrame || !*aFrame)
04672     return;
04673   nsIFrame *child = *aFrame;
04674   //if we are a block frame then go for the last line of 'this'
04675   while (1){
04676     child = child->GetFirstChild(nsnull);
04677     if (!child)
04678       return;//nothing to do
04679     nsIFrame* siblingFrame;
04680     nsIContent* content;
04681     //ignore anonymous elements, e.g. mozTableAdd* mozTableRemove*
04682     //see bug 278197 comment #12 #13 for details
04683     while ((siblingFrame = child->GetNextSibling()) &&
04684            (content = siblingFrame->GetContent()) &&
04685            !content->IsNativeAnonymous())
04686       child = siblingFrame;
04687     *aFrame = child;
04688   }
04689 }
04690 
04691 void
04692 nsFrame::GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
04693 {
04694   if (!aFrame || !*aFrame)
04695     return;
04696   nsIFrame *child = *aFrame;
04697   while (1){
04698     child = child->GetFirstChild(nsnull);
04699     if (!child)
04700       return;//nothing to do
04701     *aFrame = child;
04702   }
04703 }
04704 
04705 NS_IMETHODIMP
04706 nsFrame::CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents)
04707 {
04708   // get its view
04709   nsIView* view = GetNearestCapturingView(this);
04710   if (!view) {
04711     return NS_ERROR_FAILURE;
04712   }
04713 
04714   nsIViewManager* viewMan = view->GetViewManager();
04715   if (!viewMan) {
04716     return NS_ERROR_FAILURE;
04717   }
04718 
04719   if (aGrabMouseEvents) {
04720     PRBool result;
04721     viewMan->GrabMouseEvents(view, result);
04722   } else {
04723     PRBool result;
04724     viewMan->GrabMouseEvents(nsnull, result);
04725   }
04726 
04727   return NS_OK;
04728 }
04729 
04730 PRBool
04731 nsFrame::IsMouseCaptured(nsPresContext* aPresContext)
04732 {
04733     // get its view
04734   nsIView* view = GetNearestCapturingView(this);
04735   
04736   if (view) {
04737     nsIViewManager* viewMan = view->GetViewManager();
04738 
04739     if (viewMan) {
04740         nsIView* grabbingView;
04741         viewMan->GetMouseEventGrabber(grabbingView);
04742         if (grabbingView == view)
04743           return PR_TRUE;
04744     }
04745   }
04746 
04747   return PR_FALSE;
04748 }
04749 
04750 nsresult
04751 nsIFrame::SetProperty(nsIAtom*           aPropName,
04752                       void*              aPropValue,
04753                       NSPropertyDtorFunc aPropDtorFunc,
04754                       void*              aDtorData)
04755 {
04756   return GetPresContext()->PropertyTable()->
04757     SetProperty(this, aPropName, aPropValue, aPropDtorFunc, aDtorData);
04758 }
04759 
04760 void* 
04761 nsIFrame::GetProperty(nsIAtom* aPropName, nsresult* aStatus) const
04762 {
04763   return GetPresContext()->PropertyTable()->GetProperty(this, aPropName,
04764                                                         aStatus);
04765 }
04766 
04767 /* virtual */ void* 
04768 nsIFrame::GetPropertyExternal(nsIAtom* aPropName, nsresult* aStatus) const
04769 {
04770   return GetProperty(aPropName, aStatus);
04771 }
04772 
04773 nsresult
04774 nsIFrame::DeleteProperty(nsIAtom* aPropName) const
04775 {
04776   return GetPresContext()->PropertyTable()->DeleteProperty(this, aPropName);
04777 }
04778 
04779 void*
04780 nsIFrame::UnsetProperty(nsIAtom* aPropName, nsresult* aStatus) const
04781 {
04782   return GetPresContext()->PropertyTable()->UnsetProperty(this, aPropName,
04783                                                           aStatus);
04784 }
04785 
04786 /* virtual */ const nsStyleStruct*
04787 nsFrame::GetStyleDataExternal(nsStyleStructID aSID) const
04788 {
04789   NS_ASSERTION(mStyleContext, "unexpected null pointer");
04790   return mStyleContext->GetStyleData(aSID);
04791 }
04792 
04793 /* virtual */ PRBool
04794 nsIFrame::IsFocusable(PRInt32 *aTabIndex, PRBool aWithMouse)
04795 {
04796   PRInt32 tabIndex = -1;
04797   if (aTabIndex) {
04798     *aTabIndex = -1; // Default for early return is not focusable
04799   }
04800   PRBool isFocusable = PR_FALSE;
04801 
04802   if (mContent && mContent->IsContentOfType(nsIContent::eELEMENT) &&
04803       AreAncestorViewsVisible()) {
04804     const nsStyleVisibility* vis = GetStyleVisibility();
04805     if (vis->mVisible != NS_STYLE_VISIBILITY_COLLAPSE &&
04806         vis->mVisible != NS_STYLE_VISIBILITY_HIDDEN) {
04807       if (mContent->IsContentOfType(nsIContent::eHTML)) {
04808         nsCOMPtr<nsISupports> container(GetPresContext()->GetContainer());
04809         nsCOMPtr<nsIEditorDocShell> editorDocShell(do_QueryInterface(container));
04810         if (editorDocShell) {
04811           PRBool isEditable;
04812           editorDocShell->GetEditable(&isEditable);
04813           if (isEditable) {
04814             return NS_OK;  // Editor content is not focusable
04815           }
04816         }
04817       }
04818       const nsStyleUserInterface* ui = GetStyleUserInterface();
04819       if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
04820           ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
04821         // Pass in default tabindex of -1 for nonfocusable and 0 for focusable
04822         tabIndex = 0;
04823       }
04824       isFocusable = mContent->IsFocusable(&tabIndex);
04825       if (!isFocusable && !aWithMouse &&
04826           GetType() == nsLayoutAtoms::scrollFrame &&
04827           mContent->IsContentOfType(nsIContent::eHTML) &&
04828           !mContent->IsNativeAnonymous() && mContent->GetParent() &&
04829           !mContent->HasAttr(kNameSpaceID_None, nsHTMLAtoms::tabindex)) {
04830         // Elements with scrollable view are focusable with script & tabbable
04831         // Otherwise you couldn't scroll them with keyboard, which is
04832         // an accessibility issue (e.g. Section 508 rules)
04833         // However, we don't make them to be focusable with the mouse,
04834         // because the extra focus outlines are considered unnecessarily ugly.
04835         // When clicked on, the selection position within the element 
04836         // will be enough to make them keyboard scrollable.
04837         nsCOMPtr<nsIScrollableFrame> scrollFrame = do_QueryInterface(this);
04838         if (scrollFrame) {
04839           nsIScrollableFrame::ScrollbarStyles styles =
04840             scrollFrame->GetScrollbarStyles();
04841           if (styles.mVertical == NS_STYLE_OVERFLOW_SCROLL ||
04842               styles.mVertical == NS_STYLE_OVERFLOW_AUTO ||
04843               styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL ||
04844               styles.mHorizontal == NS_STYLE_OVERFLOW_AUTO) {
04845             // Scroll bars will be used for overflow
04846             isFocusable = PR_TRUE;
04847             tabIndex = 0;
04848           }
04849         }
04850       }
04851     }
04852   }
04853 
04854   if (aTabIndex) {
04855     *aTabIndex = tabIndex;
04856   }
04857   return isFocusable;
04858 }
04859 
04860 /* static */
04861 void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
04862                                              nsIFrame::Cursor& aCursor)
04863 {
04864   aCursor.mCursor = ui->mCursor;
04865   aCursor.mHaveHotspot = PR_FALSE;
04866   aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
04867 
04868   for (nsCursorImage *item = ui->mCursorArray,
04869                  *item_end = ui->mCursorArray + ui->mCursorArrayLength;
04870        item < item_end; ++item) {
04871     PRUint32 status;
04872     nsresult rv = item->mImage->GetImageStatus(&status);
04873     if (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_FRAME_COMPLETE)) {
04874       // This is the one we want
04875       item->mImage->GetImage(getter_AddRefs(aCursor.mContainer));
04876       aCursor.mHaveHotspot = item->mHaveHotspot;
04877       aCursor.mHotspotX = item->mHotspotX;
04878       aCursor.mHotspotY = item->mHotspotY;
04879       break;
04880     }
04881   }
04882 }
04883 
04884 PRBool
04885 nsFrame::HasStyleChange()
04886 {
04887   return BoxMetrics()->mStyleChange;
04888 }
04889 
04890 void
04891 nsFrame::SetStyleChangeFlag(PRBool aDirty)
04892 {
04893   nsBox::SetStyleChangeFlag(aDirty);
04894   BoxMetrics()->mStyleChange = PR_TRUE;
04895 }
04896 
04897 NS_IMETHODIMP
04898 nsFrame::NeedsRecalc()
04899 {
04900   nsBoxLayoutMetrics *metrics = BoxMetrics();
04901 
04902   SizeNeedsRecalc(metrics->mPrefSize);
04903   SizeNeedsRecalc(metrics->mMinSize);
04904   SizeNeedsRecalc(metrics->mMaxSize);
04905   SizeNeedsRecalc(metrics->mBlockPrefSize);
04906   SizeNeedsRecalc(metrics->mBlockMinSize);
04907   CoordNeedsRecalc(metrics->mFlex);
04908   CoordNeedsRecalc(metrics->mAscent);
04909   return NS_OK;
04910 }
04911 
04912 NS_IMETHODIMP
04913 nsFrame::GetOverflow(nsSize& aOverflow)
04914 {
04915   aOverflow = BoxMetrics()->mOverflow;
04916   return NS_OK;
04917 }
04918 
04919 NS_IMETHODIMP
04920 nsFrame::SetIncludeOverflow(PRBool aInclude)
04921 {
04922   BoxMetrics()->mIncludeOverflow = aInclude;
04923   return NS_OK;
04924 }
04925 
04926 NS_IMETHODIMP
04927 nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
04928 {
04929 
04930   // Ok we need to compute our minimum, preferred, and maximum sizes.
04931   // 1) Maximum size. This is easy. Its infinite unless it is overloaded by CSS.
04932   // 2) Preferred size. This is a little harder. This is the size the block would be 
04933   //      if it were laid out on an infinite canvas. So we can get this by reflowing
04934   //      the block with and INTRINSIC width and height. We can also do a nice optimization
04935   //      for incremental reflow. If the reflow is incremental then we can pass a flag to 
04936   //      have the block compute the preferred width for us! Preferred height can just be
04937   //      the minimum height;
04938   // 3) Minimum size. This is a toughy. We can pass the block a flag asking for the max element
04939   //    size. That would give us the width. Unfortunately you can only ask for a maxElementSize
04940   //    during an incremental reflow. So on other reflows we will just have to use 0.
04941   //    The min height on the other hand is fairly easy we need to get the largest
04942   //    line height. This can be done with the line iterator.
04943 
04944   // if we do have a reflow state
04945   nsresult rv = NS_OK;
04946   const nsHTMLReflowState* reflowState = aState.GetReflowState();
04947   if (reflowState) {
04948     nsPresContext* presContext = aState.PresContext();
04949     nsReflowStatus status = NS_FRAME_COMPLETE;
04950     nsHTMLReflowMetrics desiredSize(PR_FALSE);
04951     nsReflowReason reason;
04952 
04953     // See if we an set the max element size and return the reflow states new reason. Sometimes reflow states need to 
04954     // be changed. Incremental dirty reflows targeted at us can be converted to Resize if we are not dirty. So make sure
04955     // we look at the reason returned.
04956     nsReflowPath *path = nsnull;
04957     PRBool canSetMaxElementWidth = CanSetMaxElementWidth(aState, reason, &path);
04958 
04959     NS_ASSERTION(reason != eReflowReason_Incremental || path,
04960                  "HandleIncrementalReflow should have changed the reason to dirty.");
04961 
04962     // If we don't have any HTML constraints and its a resize, then nothing in the block
04963     // could have changed, so no refresh is necessary.
04964     nsBoxLayoutMetrics* metrics = BoxMetrics();
04965     if (!DoesNeedRecalc(metrics->mBlockPrefSize) && reason == eReflowReason_Resize)
04966       return NS_OK;
04967 
04968     // get the old rect.
04969     nsRect oldRect = GetRect();
04970 
04971     // the rect we plan to size to.
04972     nsRect rect(oldRect);
04973     
04974     // if we can set the maxElementSize then 
04975     // tell the metrics we want it. And also tell it we want
04976     // to compute the max width. This will allow us to get the min width and the pref width.
04977     if (canSetMaxElementWidth) {
04978        desiredSize.mFlags |= NS_REFLOW_CALC_MAX_WIDTH;
04979        desiredSize.mComputeMEW = PR_TRUE;
04980     } else {
04981       // if we can't set the maxElementSize. Then we must reflow
04982       // uncontrained.
04983       rect.width = NS_UNCONSTRAINEDSIZE;
04984       rect.height = NS_UNCONSTRAINEDSIZE;
04985     }
04986 
04987     // Create a child reflow state, fix-up the reason and the
04988     // incremental reflow path.
04989     nsHTMLReflowState childReflowState(*reflowState);
04990     childReflowState.reason = reason;
04991     childReflowState.path   = path;
04992 
04993     // do the nasty.
04994     rv = BoxReflow(aState,
04995                    presContext, 
04996                    desiredSize, 
04997                    childReflowState, 
04998                    status,
04999                    rect.x,
05000                    rect.y,
05001                    rect.width,
05002                    rect.height);
05003 
05004     nsRect newRect = GetRect();
05005 
05006     // make sure we draw any size change
05007     if (reason == eReflowReason_Incremental && (oldRect.width != newRect.width || oldRect.height != newRect.height)) {
05008      newRect.x = 0;
05009      newRect.y = 0;
05010      Redraw(aState, &newRect);
05011     }
05012 
05013     // if someone asked the nsBoxLayoutState to get the max size lets handle that.
05014     nscoord* stateMaxElementWidth = aState.GetMaxElementWidth();
05015 
05016     // the max element size is the largest height and width
05017     if (stateMaxElementWidth) {
05018       if (metrics->mBlockMinSize.width > *stateMaxElementWidth)
05019         *stateMaxElementWidth = metrics->mBlockMinSize.width;
05020     }
05021  
05022     metrics->mBlockMinSize.height = 0;
05023     // if we can use the maxElmementSize then lets use it
05024     // if not then just use the desired.
05025     if (canSetMaxElementWidth) {
05026       metrics->mBlockPrefSize.width  = desiredSize.mMaximumWidth;
05027       metrics->mBlockMinSize.width   = desiredSize.mMaxElementWidth; 
05028       // ok we need the max ascent of the items on the line. So to do this
05029       // ask the block for its line iterator. Get the max ascent.
05030       nsCOMPtr<nsILineIterator> lines = do_QueryInterface(NS_STATIC_CAST(nsIFrame*, this));
05031       if (lines) 
05032       {
05033         metrics->mBlockMinSize.height = 0;
05034         int count = 0;
05035         nsIFrame* firstFrame = nsnull;
05036         PRInt32 framesOnLine;
05037         nsRect lineBounds;
05038         PRUint32 lineFlags;
05039 
05040         do {
05041            lines->GetLine(count, &firstFrame, &framesOnLine, lineBounds, &lineFlags);
05042  
05043            if (lineBounds.height > metrics->mBlockMinSize.height)
05044              metrics->mBlockMinSize.height = lineBounds.height;
05045 
05046            count++;
05047         } while(firstFrame);
05048       }
05049 
05050       metrics->mBlockPrefSize.height  = metrics->mBlockMinSize.height;
05051     } else {
05052       metrics->mBlockPrefSize.width = desiredSize.width;
05053       metrics->mBlockPrefSize.height = desiredSize.height;
05054       // this sucks. We could not get the width.
05055       metrics->mBlockMinSize.width = 0;
05056       metrics->mBlockMinSize.height = desiredSize.height;
05057     }
05058 
05059     metrics->mBlockAscent = desiredSize.ascent;
05060 
05061 #ifdef DEBUG_adaptor
05062     printf("min=(%d,%d), pref=(%d,%d), ascent=%d\n", metrics->mBlockMinSize.width,
05063                                                      metrics->mBlockMinSize.height,
05064                                                      metrics->mBlockPrefSize.width,
05065                                                      metrics->mBlockPrefSize.height,
05066                                                      metrics->mBlockAscent);
05067 #endif
05068   }
05069 
05070   return rv;
05071 }
05072 
05073 NS_IMETHODIMP
05074 nsFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize)
05075 {
05076   // If the size is cached, and there are no HTML constraints that we might
05077   // be depending on, then we just return the cached size.
05078   nsBoxLayoutMetrics *metrics = BoxMetrics();
05079   if (!DoesNeedRecalc(metrics->mPrefSize)) {
05080      aSize = metrics->mPrefSize;
05081      return NS_OK;
05082   }
05083 
05084   aSize.width = 0;
05085   aSize.height = 0;
05086 
05087   PRBool isCollapsed = PR_FALSE;
05088   IsCollapsed(aState, isCollapsed);
05089   if (isCollapsed) {
05090     return NS_OK;
05091   } else {
05092     // get our size in CSS.
05093     PRBool completelyRedefined = nsIBox::AddCSSPrefSize(aState, this, metrics->mPrefSize);
05094 
05095     // Refresh our caches with new sizes.
05096     if (!completelyRedefined) {
05097        RefreshSizeCache(aState);
05098        metrics->mPrefSize = metrics->mBlockPrefSize;
05099 
05100        // notice we don't need to add our borders or padding
05101        // in. Thats because the block did it for us.
05102        // but we do need to add insets so debugging will work.
05103        AddInset(metrics->mPrefSize);
05104        nsIBox::AddCSSPrefSize(aState, this, metrics->mPrefSize);
05105     }
05106   }
05107 
05108   aSize = metrics->mPrefSize;
05109 
05110   return NS_OK;
05111 }
05112 
05113 NS_IMETHODIMP
05114 nsFrame::GetMinSize(nsBoxLayoutState& aState, nsSize& aSize)
05115 {
05116   // Don't use the cache if we have HTMLReflowState constraints --- they might have changed
05117   nsBoxLayoutMetrics *metrics = BoxMetrics();
05118   if (!DoesNeedRecalc(metrics->mMinSize)) {
05119      aSize = metrics->mMinSize;
05120      return NS_OK;
05121   }
05122 
05123   aSize.width = 0;
05124   aSize.height = 0;
05125 
05126   PRBool isCollapsed = PR_FALSE;
05127   IsCollapsed(aState, isCollapsed);
05128   if (isCollapsed) {
05129     return NS_OK;
05130   } else {
05131     // get our size in CSS.
05132     PRBool completelyRedefined = nsIBox::AddCSSMinSize(aState, this, metrics->mMinSize);
05133 
05134     // Refresh our caches with new sizes.
05135     if (!completelyRedefined) {
05136        RefreshSizeCache(aState);
05137        metrics->mMinSize = metrics->mBlockMinSize;
05138        AddInset(metrics->mMinSize);
05139        nsIBox::AddCSSMinSize(aState, this, metrics->mMinSize);
05140     }
05141   }
05142 
05143   aSize = metrics->mMinSize;
05144 
05145   return NS_OK;
05146 }
05147 
05148 NS_IMETHODIMP
05149 nsFrame::GetMaxSize(nsBoxLayoutState& aState, nsSize& aSize)
05150 {
05151   // Don't use the cache if we have HTMLReflowState constraints --- they might have changed
05152   nsBoxLayoutMetrics *metrics = BoxMetrics();
05153   if (!DoesNeedRecalc(metrics->mMaxSize)) {
05154      aSize = metrics->mMaxSize;
05155      return NS_OK;
05156   }
05157 
05158   aSize.width = NS_INTRINSICSIZE;
05159   aSize.height = NS_INTRINSICSIZE;
05160 
05161   PRBool isCollapsed = PR_FALSE;
05162   IsCollapsed(aState, isCollapsed);
05163   if (isCollapsed) {
05164     return NS_OK;
05165   } else {
05166     metrics->mMaxSize.width = NS_INTRINSICSIZE;
05167     metrics->mMaxSize.height = NS_INTRINSICSIZE;
05168     nsBox::GetMaxSize(aState, metrics->mMaxSize);
05169   }
05170 
05171   aSize = metrics->mMaxSize;
05172 
05173   return NS_OK;
05174 }
05175 
05176 NS_IMETHODIMP
05177 nsFrame::GetFlex(nsBoxLayoutState& aState, nscoord& aFlex)
05178 {
05179   nsBoxLayoutMetrics *metrics = BoxMetrics();
05180   if (!DoesNeedRecalc(metrics->mFlex)) {
05181      aFlex = metrics->mFlex;
05182      return NS_OK;
05183   }
05184 
05185   metrics->mFlex = 0;
05186   nsBox::GetFlex(aState, metrics->mFlex);
05187 
05188   aFlex = metrics->mFlex;
05189 
05190   return NS_OK;
05191 }
05192 
05193 NS_IMETHODIMP
05194 nsFrame::GetAscent(nsBoxLayoutState& aState, nscoord& aAscent)
05195 {
05196   nsBoxLayoutMetrics *metrics = BoxMetrics();
05197   if (!DoesNeedRecalc(metrics->mAscent)) {
05198     aAscent = metrics->mAscent;
05199     return NS_OK;
05200   }
05201 
05202   PRBool isCollapsed = PR_FALSE;
05203   IsCollapsed(aState, isCollapsed);
05204   if (isCollapsed) {
05205     metrics->mAscent = 0;
05206   } else {
05207     // Refresh our caches with new sizes.
05208     RefreshSizeCache(aState);
05209     metrics->mAscent = metrics->mBlockAscent;
05210     nsMargin m(0, 0, 0, 0);
05211     GetInset(m);
05212     metrics->mAscent += m.top;
05213   }
05214 
05215   aAscent = metrics->mAscent;
05216 
05217   return NS_OK;
05218 }
05219 
05220 nsresult
05221 nsFrame::DoLayout(nsBoxLayoutState& aState)
05222 {
05223   nsRect ourRect(mRect);
05224 
05225   const nsHTMLReflowState* reflowState = aState.GetReflowState();
05226   nsPresContext* presContext = aState.PresContext();
05227   nsReflowStatus status = NS_FRAME_COMPLETE;
05228   nsHTMLReflowMetrics desiredSize(PR_FALSE);
05229   nsresult rv = NS_OK;
05230  
05231   if (reflowState) {
05232 
05233     nscoord* currentMEW = aState.GetMaxElementWidth();
05234 
05235     if (currentMEW) {
05236       desiredSize.mComputeMEW = PR_TRUE;
05237     }
05238 
05239     rv = BoxReflow(aState, presContext, desiredSize, *reflowState, status,
05240                    ourRect.x, ourRect.y, ourRect.width, ourRect.height);
05241 
05242     if (currentMEW && desiredSize.mMaxElementWidth > *currentMEW) {
05243       *currentMEW = desiredSize.mMaxElementWidth;
05244     }
05245 
05246     PRBool collapsed = PR_FALSE;
05247     IsCollapsed(aState, collapsed);
05248     if (collapsed) {
05249       SetSize(nsSize(0, 0));
05250     } else {
05251 
05252       // if our child needs to be bigger. This might happend with
05253       // wrapping text. There is no way to predict its height until we
05254       // reflow it. Now that we know the height reshuffle upward.
05255       if (desiredSize.width > ourRect.width ||
05256           desiredSize.height > ourRect.height) {
05257 
05258 #ifdef DEBUG_GROW
05259         DumpBox(stdout);
05260         printf(" GREW from (%d,%d) -> (%d,%d)\n",
05261                ourRect.width, ourRect.height,
05262                desiredSize.width, desiredSize.height);
05263 #endif
05264 
05265         if (desiredSize.width > ourRect.width)
05266           ourRect.width = desiredSize.width;
05267 
05268         if (desiredSize.height > ourRect.height)
05269           ourRect.height = desiredSize.height;
05270       }
05271 
05272       // ensure our size is what we think is should be. Someone could have
05273       // reset the frame to be smaller or something dumb like that. 
05274       SetSize(nsSize(ourRect.width, ourRect.height));
05275     }
05276   }
05277 
05278   SyncLayout(aState);
05279 
05280   return rv;
05281 }
05282 
05283 // Truncate the reflow path by pruning the subtree containing the
05284 // specified frame. This ensures that we don't accidentally
05285 // incrementally reflow a frame twice.
05286 // XXXwaterson We could be more efficient by remembering the parent in
05287 // FindReflowPathFor.
05288 static void
05289 PruneReflowPathFor(nsIFrame *aFrame, nsReflowPath *aReflowPath)
05290 {
05291   nsReflowPath::iterator iter, end = aReflowPath->EndChildren();
05292   for (iter = aReflowPath->FirstChild(); iter != end; ++iter) {
05293     if (*iter == aFrame) {
05294       aReflowPath->Remove(iter);
05295       break;
05296     }
05297 
05298     PruneReflowPathFor(aFrame, iter.get());
05299   }
05300 }
05301 
05302 nsresult
05303 nsFrame::BoxReflow(nsBoxLayoutState& aState,
05304                    nsPresContext*           aPresContext,
05305                    nsHTMLReflowMetrics&     aDesiredSize,
05306                    const nsHTMLReflowState& aReflowState,
05307                    nsReflowStatus&          aStatus,
05308                    nscoord                  aX,
05309                    nscoord                  aY,
05310                    nscoord                  aWidth,
05311                    nscoord                  aHeight,
05312                    PRBool                   aMoveFrame)
05313 {
05314   DO_GLOBAL_REFLOW_COUNT("nsBoxToBlockAdaptor", aReflowState.reason);
05315 
05316 #ifdef DEBUG_REFLOW
05317   nsAdaptorAddIndents();
05318   printf("Reflowing: ");
05319   nsFrame::ListTag(stdout, mFrame);
05320   printf("\n");
05321   gIndent2++;
05322 #endif
05323 
05324   //printf("width=%d, height=%d\n", aWidth, aHeight);
05325   /*
05326   nsIBox* parent;
05327   GetParentBox(&parent);
05328 
05329  // if (parent->GetStateBits() & NS_STATE_CURRENTLY_IN_DEBUG)
05330   //   printf("In debug\n");
05331   */
05332 
05333   nsBoxLayoutMetrics *metrics = BoxMetrics();
05334   aStatus = NS_FRAME_COMPLETE;
05335 
05336   PRBool redrawAfterReflow = PR_FALSE;
05337   PRBool needsReflow = PR_FALSE;
05338   PRBool redrawNow = PR_FALSE;
05339   nsReflowReason reason;
05340   nsReflowPath *path = nsnull;
05341 
05342   HandleIncrementalReflow(aState, 
05343                           aReflowState, 
05344                           reason,
05345                           &path,
05346                           redrawNow,
05347                           needsReflow, 
05348                           redrawAfterReflow, 
05349                           aMoveFrame);
05350 
05351   // If the NS_REFLOW_CALC_MAX_WIDTH flag is set on the nsHTMLReflowMetrics,
05352   // then we need to do a reflow so that aDesiredSize.mMaximumWidth will be set
05353   // correctly.
05354   needsReflow = needsReflow || (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH);
05355 
05356   if (redrawNow)
05357      Redraw(aState);
05358 
05359   // if we don't need a reflow then 
05360   // lets see if we are already that size. Yes? then don't even reflow. We are done.
05361   if (!needsReflow) {
05362       
05363       if (aWidth != NS_INTRINSICSIZE && aHeight != NS_INTRINSICSIZE) {
05364       
05365           // if the new calculated size has a 0 width or a 0 height
05366           if ((metrics->mLastSize.width == 0 || metrics->mLastSize.height == 0) && (aWidth == 0 || aHeight == 0)) {
05367                needsReflow = PR_FALSE;
05368                aDesiredSize.width = aWidth; 
05369                aDesiredSize.height = aHeight; 
05370                SetSize(nsSize(aDesiredSize.width, aDesiredSize.height));
05371           } else {
05372             aDesiredSize.width = metrics->mLastSize.width;
05373             aDesiredSize.height = metrics->mLastSize.height;
05374 
05375             // remove the margin. The rect of our child does not include it but our calculated size does.
05376             nscoord calcWidth = aWidth; 
05377             nscoord calcHeight = aHeight; 
05378             // don't reflow if we are already the right size
05379             if (metrics->mLastSize.width == calcWidth && metrics->mLastSize.height == calcHeight)
05380                   needsReflow = PR_FALSE;
05381             else
05382                   needsReflow = PR_TRUE;
05383    
05384           }
05385       } else {
05386           // if the width or height are intrinsic alway reflow because
05387           // we don't know what it should be.
05388          needsReflow = PR_TRUE;
05389       }
05390   }
05391                              
05392   // ok now reflow the child into the spacers calculated space
05393   if (needsReflow) {
05394 
05395     nsMargin border(0,0,0,0);
05396     GetBorderAndPadding(border);
05397 
05398 
05399     aDesiredSize.width = 0;
05400     aDesiredSize.height = 0;
05401 
05402     nsSize size(aWidth, aHeight);
05403 
05404     // create a reflow state to tell our child to flow at the given size.
05405     if (size.height != NS_INTRINSICSIZE) {
05406         size.height -= (border.top + border.bottom);
05407         if (size.height < 0)
05408           size.height = 0;
05409     }
05410 
05411     if (size.width != NS_INTRINSICSIZE) {
05412         size.width -= (border.left + border.right);
05413         if (size.width < 0)
05414           size.width = 0;
05415     }
05416 
05417     // Create with a reason of resize, and then change the `reason'
05418     // and `path' appropriately (since for incremental reflow, we'll
05419     // be mangling it so completely).
05420     nsHTMLReflowState reflowState(aPresContext, aReflowState, this,
05421                                   nsSize(size.width, NS_INTRINSICSIZE),
05422                                   eReflowReason_Resize);
05423     reflowState.reason = reason;
05424     reflowState.path   = path;
05425 
05426     // XXX this needs to subtract out the border and padding of mFrame since it is content size
05427     reflowState.mComputedWidth = size.width;
05428     reflowState.mComputedHeight = size.height;
05429 
05430     // if we were marked for style change.
05431     // 1) see if we are just supposed to do a resize if so convert to a style change. Kill 2 birds
05432     //    with 1 stone.
05433     // 2) If the command is incremental. See if its style change. If it is everything is ok if not
05434     //    we need to do a second reflow with the style change.
05435     // XXXwaterson This logic seems _very_ squirrely.
05436     if (metrics->mStyleChange) {
05437       if (reflowState.reason == eReflowReason_Resize) {
05438          // maxElementSize does not work on style change reflows.
05439          // so remove it if set.
05440          // XXXwaterson why doesn't MES computation work with a style change reflow?
05441          aDesiredSize.mComputeMEW = PR_FALSE;
05442 
05443          reflowState.reason = eReflowReason_StyleChange;
05444       }
05445       else if (reason == eReflowReason_Incremental) {
05446         PRBool reflowChild = PR_TRUE;
05447 
05448         if (path->mReflowCommand &&
05449             path->FirstChild() == path->EndChildren() &&
05450             path->mReflowCommand->Type() == eReflowType_StyleChanged) {
05451           // There's an incremental reflow targeted directly at our
05452           // frame, and our frame only (i.e., none of our descendants
05453           // are targets).
05454           reflowChild = PR_FALSE;
05455         }
05456 
05457         if (reflowChild) {
05458 #ifdef DEBUG_waterson
05459           printf("*** nsBoxToBlockAdaptor::Reflow: performing extra reflow on child frame\n");
05460 #endif
05461 
05462 #ifdef DEBUG_REFLOW
05463           nsAdaptorAddIndents();
05464           printf("Size=(%d,%d)\n",reflowState.mComputedWidth, reflowState.mComputedHeight);
05465           nsAdaptorAddIndents();
05466           nsAdaptorPrintReason(reflowState);
05467           printf("\n");
05468 #endif
05469 
05470           WillReflow(aPresContext);
05471           Reflow(aPresContext, aDesiredSize, reflowState, aStatus);
05472           DidReflow(aPresContext, &reflowState, NS_FRAME_REFLOW_FINISHED);
05473           reflowState.mComputedWidth = aDesiredSize.width - (border.left + border.right);
05474           reflowState.availableWidth = reflowState.mComputedWidth;
05475           reflowState.reason = eReflowReason_StyleChange;
05476           reflowState.path = nsnull;
05477         }
05478       }
05479 
05480       metrics->mStyleChange = PR_FALSE;
05481     }
05482 
05483     #ifdef DEBUG_REFLOW
05484       nsAdaptorAddIndents();
05485       printf("Size=(%d,%d)\n",reflowState.mComputedWidth, reflowState.mComputedHeight);
05486       nsAdaptorAddIndents();
05487       nsAdaptorPrintReason(reflowState);
05488       printf("\n");
05489     #endif
05490 
05491        // place the child and reflow
05492     WillReflow(aPresContext);
05493 
05494     Reflow(aPresContext, aDesiredSize, reflowState, aStatus);
05495 
05496     NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");
05497 
05498     // Save the ascent.  (bug 103925)
05499     PRBool isCollapsed = PR_FALSE;
05500     IsCollapsed(aState, isCollapsed);
05501     if (isCollapsed) {
05502       metrics->mAscent = 0;
05503     } else {
05504       metrics->mAscent = aDesiredSize.ascent;
05505     }
05506 
05507    // printf("width: %d, height: %d\n", aDesiredSize.mCombinedArea.width, aDesiredSize.mCombinedArea.height);
05508 
05509     // see if the overflow option is set. If it is then if our child's bounds overflow then
05510     // we will set the child's rect to include the overflow size.
05511        if (GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) {
05512          // make sure we store the overflow size
05513 
05514          // This kinda sucks. We should be able to handle the case
05515          // where there's overflow above or to the left of the
05516          // origin. But for now just chop that stuff off.
05517          metrics->mOverflow.width = aDesiredSize.mOverflowArea.XMost();
05518          metrics->mOverflow.height = aDesiredSize.mOverflowArea.YMost();
05519 
05520          // include the overflow size in our child's rect?
05521          if (metrics->mIncludeOverflow) {
05522              //printf("OutsideChildren width=%d, height=%d\n", aDesiredSize.mOverflowArea.width, aDesiredSize.mOverflowArea.height);
05523              aDesiredSize.width = aDesiredSize.mOverflowArea.XMost();
05524              if (aDesiredSize.width <= aWidth)
05525                aDesiredSize.height = aDesiredSize.mOverflowArea.YMost();
05526              else {
05527               if (aDesiredSize.width > aWidth)
05528               {
05529                  reflowState.mComputedWidth = aDesiredSize.width - (border.left + border.right);
05530                  reflowState.availableWidth = reflowState.mComputedWidth;
05531                  reflowState.reason = eReflowReason_Resize;
05532                  reflowState.path = nsnull;
05533                  DidReflow(aPresContext, &reflowState, NS_FRAME_REFLOW_FINISHED);
05534                  #ifdef DEBUG_REFLOW
05535                   nsAdaptorAddIndents();
05536                   nsAdaptorPrintReason(reflowState);
05537                   printf("\n");
05538                  #endif
05539                  WillReflow(aPresContext);
05540                  Reflow(aPresContext, aDesiredSize, reflowState, aStatus);
05541                  if (GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN)
05542                     aDesiredSize.height = aDesiredSize.mOverflowArea.YMost();
05543 
05544               }
05545              }
05546          }
05547        } else {
05548          metrics->mOverflow.width  = aDesiredSize.width;
05549          metrics->mOverflow.height = aDesiredSize.height;
05550        }
05551 
05552     if (redrawAfterReflow) {
05553        nsRect r = GetRect();
05554        r.width = aDesiredSize.width;
05555        r.height = aDesiredSize.height;
05556        Redraw(aState, &r);
05557     }
05558 
05559     PRBool changedSize = PR_FALSE;
05560 
05561     if (metrics->mLastSize.width != aDesiredSize.width || metrics->mLastSize.height != aDesiredSize.height)
05562        changedSize = PR_TRUE;
05563   
05564     PRUint32 layoutFlags = aState.LayoutFlags();
05565     nsContainerFrame::FinishReflowChild(this, aPresContext, &reflowState,
05566                                         aDesiredSize, aX, aY, layoutFlags | NS_FRAME_NO_MOVE_FRAME);
05567   } else {
05568     aDesiredSize.ascent = metrics->mBlockAscent;
05569   }
05570 
05571   // Clip the path we just reflowed, so that we don't incrementally
05572   // reflow it again: subsequent reflows will be treated as resize
05573   // reflows.
05574   if (path)
05575     PruneReflowPathFor(path->mFrame, aReflowState.path);
05576   
05577 #ifdef DEBUG_REFLOW
05578   if (aHeight != NS_INTRINSICSIZE && aDesiredSize.height != aHeight)
05579   {
05580           nsAdaptorAddIndents();
05581           printf("*****got taller!*****\n");
05582          
05583   }
05584   if (aWidth != NS_INTRINSICSIZE && aDesiredSize.width != aWidth)
05585   {
05586           nsAdaptorAddIndents();
05587           printf("*****got wider!******\n");
05588          
05589   }
05590 #endif
05591 
05592   if (aWidth == NS_INTRINSICSIZE)
05593      aWidth = aDesiredSize.width;
05594 
05595   if (aHeight == NS_INTRINSICSIZE)
05596      aHeight = aDesiredSize.height;
05597 
05598   metrics->mLastSize.width = aDesiredSize.width;
05599   metrics->mLastSize.height = aDesiredSize.height;
05600 
05601 #ifdef DEBUG_REFLOW
05602   gIndent2--;
05603 #endif
05604 
05605   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
05606   return NS_OK;
05607 }
05608 
05609 // Look for aFrame in the specified reflow path's tree, returning the
05610 // reflow path node corresponding to the frame if we find it.
05611 static nsReflowPath *
05612 FindReflowPathFor(nsIFrame *aFrame, nsReflowPath *aReflowPath)
05613 {
05614   nsReflowPath::iterator iter, end = aReflowPath->EndChildren();
05615   for (iter = aReflowPath->FirstChild(); iter != end; ++iter) {
05616     if (*iter == aFrame)
05617       return iter.get();
05618 
05619     nsReflowPath *subtree = FindReflowPathFor(aFrame, iter.get());
05620     if (subtree)
05621       return subtree;
05622   }
05623 
05624   return nsnull;
05625 }
05626 
05627 void
05628 nsFrame::HandleIncrementalReflow(nsBoxLayoutState& aState, 
05629                                  const nsHTMLReflowState& aReflowState,
05630                                  nsReflowReason& aReason,
05631                                  nsReflowPath** aReflowPath,
05632                                  PRBool& aRedrawNow,
05633                                  PRBool& aNeedsReflow,
05634                                  PRBool& aRedrawAfterReflow,
05635                                  PRBool& aMoveFrame)
05636 {
05637   nsFrameState childState = GetStateBits();
05638 
05639   aReason = aReflowState.reason;
05640 
05641     // handle or different types of reflow
05642   switch(aReason)
05643   {
05644    // if the child we are reflowing is the child we popped off the incremental 
05645    // reflow chain then we need to reflow it no matter what.
05646    // if its not the child we got from the reflow chain then this child needs reflow
05647    // because as a side effect of the incremental child changing size it needs to be resized.
05648    // This will happen a lot when a box that contains 2 children with different flexibilities
05649    // if on child gets bigger the other is affected because it is proprotional to the first.
05650    // so it might need to be resized. But we don't need to reflow it. If it is already the
05651    // needed size then we will do nothing. 
05652    case eReflowReason_Incremental: {
05653 
05654       // Grovel through the reflow path's children to find the path
05655       // that corresponds to the current frame. If we can't find a
05656       // child, then we'll convert the reflow to a dirty reflow,
05657       // below.
05658       nsReflowPath *path = FindReflowPathFor(this, aReflowState.path);
05659       if (path) {
05660           aNeedsReflow = PR_TRUE;
05661 
05662           // Return the path that we've found so that HTML incremental
05663           // reflow can proceed normally.
05664           if (aReflowPath)
05665             *aReflowPath = path;
05666 
05667           // if we hit the target then we have used up the chain.
05668           // next time a layout 
05669           break;
05670       } 
05671 
05672       // fall into dirty if the incremental child was use. It should be treated as a 
05673    }
05674 
05675    // if its dirty then see if the child we want to reflow is dirty. If it is then
05676    // mark it as needing to be reflowed.
05677    case eReflowReason_Dirty: {
05678         // XXX nsBlockFrames don't seem to be able to handle a reason of Dirty. So we  
05679         // send down a resize instead. If we did send down the dirty we would have wrapping problems. If you 
05680         // look at the main page it will initially come up ok but will have a unneeded horizontal 
05681         // scrollbar if you resize it will fix it self. The real fix is to fix block frame but
05682         // this will fix it for beta3.
05683         if (childState & NS_FRAME_FIRST_REFLOW) 
05684            aReason = eReflowReason_Initial;
05685         else
05686            aReason = eReflowReason_Resize;
05687 
05688         // get the frame state to see if it needs reflow
05689         aNeedsReflow = BoxMetrics()->mStyleChange || (childState & NS_FRAME_IS_DIRTY) || (childState & NS_FRAME_HAS_DIRTY_CHILDREN);
05690 
05691         // but of course by definition dirty reflows are supposed to redraw so
05692         // lets signal that we need to do that. We want to do it after as well because
05693         // the object may have changed size.
05694         if (aNeedsReflow) {
05695            aRedrawNow = PR_TRUE;
05696            aRedrawAfterReflow = PR_TRUE;
05697            //printf("Redrawing!!!/n");
05698         }
05699 
05700    } break;
05701 
05702    // if the a resize reflow then it doesn't need to be reflowed. Only if the size is different
05703    // from the new size would we actually do a reflow
05704    case eReflowReason_Resize:
05705        // blocks sometimes send resizes even when its children are dirty! We need to make sure we
05706        // repair in these cases. So check the flags here.
05707        aNeedsReflow = BoxMetrics()->mStyleChange || (childState & NS_FRAME_IS_DIRTY) || (childState & NS_FRAME_HAS_DIRTY_CHILDREN);
05708    break;
05709 
05710    // if its an initial reflow we must place the child.
05711    // otherwise we might think it was already placed when it wasn't
05712    case eReflowReason_Initial:
05713        aMoveFrame = PR_TRUE;
05714        aNeedsReflow = PR_TRUE;
05715    break;
05716 
05717    default:
05718        aNeedsReflow = PR_TRUE;
05719  
05720   }
05721 }
05722 
05723 PRBool
05724 nsFrame::GetWasCollapsed(nsBoxLayoutState& aState)
05725 {
05726   return BoxMetrics()->mWasCollapsed;
05727 }
05728 
05729 void
05730 nsFrame::SetWasCollapsed(nsBoxLayoutState& aState, PRBool aCollapsed)
05731 {
05732   BoxMetrics()->mWasCollapsed = aCollapsed;
05733 }
05734 
05735 PRBool 
05736 nsFrame::CanSetMaxElementWidth(nsBoxLayoutState& aState, nsReflowReason& aReason, nsReflowPath **aReflowPath)
05737 {
05738       PRBool redrawAfterReflow = PR_FALSE;
05739       PRBool needsReflow = PR_FALSE;
05740       PRBool redrawNow = PR_FALSE;
05741       PRBool move = PR_TRUE;
05742       const nsHTMLReflowState* reflowState = aState.GetReflowState();
05743 
05744       HandleIncrementalReflow(aState, 
05745                               *reflowState, 
05746                               aReason,
05747                               aReflowPath,
05748                               redrawNow,
05749                               needsReflow, 
05750                               redrawAfterReflow, 
05751                               move);
05752 
05753       // only  incremental reflows can handle maxelementsize being set.
05754       if (reflowState->reason == eReflowReason_Incremental) {
05755         nsReflowPath *path = *aReflowPath;
05756         if (path && path->mReflowCommand &&
05757             path->mReflowCommand->Type() == eReflowType_StyleChanged) {
05758           // MaxElement doesn't work on style change reflows.. :-(
05759           // XXXwaterson why?
05760           return PR_FALSE;
05761         }
05762 
05763         return PR_TRUE;
05764       }
05765 
05766       return PR_FALSE;
05767 }
05768 
05769 nsBoxLayoutMetrics*
05770 nsFrame::BoxMetrics() const
05771 {
05772   nsBoxLayoutMetrics* metrics =
05773     NS_STATIC_CAST(nsBoxLayoutMetrics*, GetProperty(nsLayoutAtoms::boxMetricsProperty));
05774   NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
05775   return metrics;
05776 }
05777 
05778 NS_IMETHODIMP
05779 nsFrame::SetParent(const nsIFrame* aParent)
05780 {
05781   PRBool wasBoxWrapped = IsBoxWrapped();
05782   nsIFrame::SetParent(aParent);
05783   if (!wasBoxWrapped && IsBoxWrapped())
05784     InitBoxMetrics(PR_TRUE);
05785   else if (wasBoxWrapped && !IsBoxWrapped())
05786     DeleteProperty(nsLayoutAtoms::boxMetricsProperty);
05787 
05788   if (aParent && aParent->IsBoxFrame()) {
05789     PRBool needsWidget = PR_FALSE;
05790     aParent->ChildrenMustHaveWidgets(needsWidget);
05791     if (needsWidget) {
05792         nsHTMLContainerFrame::CreateViewForFrame(this, nsnull, PR_TRUE);
05793         nsIView* view = GetView();
05794         if (!view->HasWidget())
05795           CreateWidgetForView(view);
05796     }
05797   }
05798 
05799   return NS_OK;
05800 }
05801 
05802 static void
05803 DeleteBoxMetrics(void    *aObject,
05804                  nsIAtom *aPropertyName,
05805                  void    *aPropertyValue,
05806                  void    *aData)
05807 {
05808   delete NS_STATIC_CAST(nsBoxLayoutMetrics*, aPropertyValue);
05809 }
05810 
05811 void
05812 nsFrame::InitBoxMetrics(PRBool aClear)
05813 {
05814   if (aClear)
05815     DeleteProperty(nsLayoutAtoms::boxMetricsProperty);
05816 
05817   nsBoxLayoutMetrics *metrics = new nsBoxLayoutMetrics();
05818   SetProperty(nsLayoutAtoms::boxMetricsProperty, metrics, DeleteBoxMetrics);
05819 
05820   NeedsRecalc();
05821   metrics->mBlockAscent = 0;
05822   metrics->mLastSize.SizeTo(0, 0);
05823   metrics->mOverflow.SizeTo(0, 0);
05824   metrics->mIncludeOverflow = PR_TRUE;
05825   metrics->mWasCollapsed = PR_FALSE;
05826   metrics->mStyleChange = PR_FALSE;
05827 }
05828 
05829 // Box layout debugging
05830 #ifdef DEBUG_REFLOW
05831 PRInt32 gIndent2 = 0;
05832 
05833 void
05834 nsAdaptorAddIndents()
05835 {
05836     for(PRInt32 i=0; i < gIndent2; i++)
05837     {
05838         printf(" ");
05839     }
05840 }
05841 
05842 void
05843 nsAdaptorPrintReason(nsHTMLReflowState& aReflowState)
05844 {
05845     char* reflowReasonString;
05846 
05847     switch(aReflowState.reason) 
05848     {
05849         case eReflowReason_Initial:
05850           reflowReasonString = "initial";
05851           break;
05852 
05853         case eReflowReason_Resize:
05854           reflowReasonString = "resize";
05855           break;
05856         case eReflowReason_Dirty:
05857           reflowReasonString = "dirty";
05858           break;
05859         case eReflowReason_StyleChange:
05860           reflowReasonString = "stylechange";
05861           break;
05862         case eReflowReason_Incremental: 
05863         {
05864             switch (aReflowState.reflowCommand->Type()) {
05865               case eReflowType_StyleChanged:
05866                  reflowReasonString = "incremental (StyleChanged)";
05867               break;
05868               case eReflowType_ReflowDirty:
05869                  reflowReasonString = "incremental (ReflowDirty)";
05870               break;
05871               default:
05872                  reflowReasonString = "incremental (Unknown)";
05873             }
05874         }                             
05875         break;
05876         default:
05877           reflowReasonString = "unknown";
05878           break;
05879     }
05880 
05881     printf("%s",reflowReasonString);
05882 }
05883 
05884 #endif
05885 #ifdef DEBUG_LAYOUT
05886 void
05887 nsFrame::GetBoxName(nsAutoString& aName)
05888 {
05889    nsIFrameDebug*  frameDebug;
05890    nsAutoString name;
05891    if (NS_SUCCEEDED(QueryInterface(NS_GET_IID(nsIFrameDebug), (void**)&frameDebug))) {
05892       frameDebug->GetFrameName(name);
05893    }
05894 
05895   aName = name;
05896 }
05897 #endif
05898 
05899 #ifdef NS_DEBUG
05900 static void
05901 GetTagName(nsFrame* aFrame, nsIContent* aContent, PRIntn aResultSize,
05902            char* aResult)
05903 {
05904   const char *nameStr = "";
05905   if (aContent) {
05906     aContent->Tag()->GetUTF8String(&nameStr);
05907   }
05908   PR_snprintf(aResult, aResultSize, "%s@%p", nameStr, aFrame);
05909 }
05910 
05911 void
05912 nsFrame::Trace(const char* aMethod, PRBool aEnter)
05913 {
05914   if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
05915     char tagbuf[40];
05916     GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
05917     PR_LogPrint("%s: %s %s", tagbuf, aEnter ? "enter" : "exit", aMethod);
05918   }
05919 }
05920 
05921 void
05922 nsFrame::Trace(const char* aMethod, PRBool aEnter, nsReflowStatus aStatus)
05923 {
05924   if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
05925     char tagbuf[40];
05926     GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
05927     PR_LogPrint("%s: %s %s, status=%scomplete%s",
05928                 tagbuf, aEnter ? "enter" : "exit", aMethod,
05929                 NS_FRAME_IS_NOT_COMPLETE(aStatus) ? "not" : "",
05930                 (NS_FRAME_REFLOW_NEXTINFLOW & aStatus) ? "+reflow" : "");
05931   }
05932 }
05933 
05934 void
05935 nsFrame::TraceMsg(const char* aFormatString, ...)
05936 {
05937   if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
05938     // Format arguments into a buffer
05939     char argbuf[200];
05940     va_list ap;
05941     va_start(ap, aFormatString);
05942     PR_vsnprintf(argbuf, sizeof(argbuf), aFormatString, ap);
05943     va_end(ap);
05944 
05945     char tagbuf[40];
05946     GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
05947     PR_LogPrint("%s: %s", tagbuf, argbuf);
05948   }
05949 }
05950 
05951 void
05952 nsFrame::VerifyDirtyBitSet(nsIFrame* aFrameList)
05953 {
05954   for (nsIFrame*f = aFrameList; f; f = f->GetNextSibling()) {
05955     NS_ASSERTION(f->GetStateBits() & NS_FRAME_IS_DIRTY, "dirty bit not set");
05956   }
05957 }
05958 
05959 // Start Display Reflow
05960 #ifdef DEBUG
05961 
05962 MOZ_DECL_CTOR_COUNTER(DR_cookie)
05963 
05964 DR_cookie::DR_cookie(nsPresContext*          aPresContext,
05965                      nsIFrame*                aFrame, 
05966                      const nsHTMLReflowState& aReflowState,
05967                      nsHTMLReflowMetrics&     aMetrics,
05968                      nsReflowStatus&          aStatus)
05969   :mPresContext(aPresContext), mFrame(aFrame), mReflowState(aReflowState), mMetrics(aMetrics), mStatus(aStatus)
05970 {
05971   MOZ_COUNT_CTOR(DR_cookie);
05972   mValue = nsFrame::DisplayReflowEnter(aPresContext, mFrame, mReflowState);
05973 }
05974 
05975 DR_cookie::~DR_cookie()
05976 {
05977   MOZ_COUNT_DTOR(DR_cookie);
05978   nsFrame::DisplayReflowExit(mPresContext, mFrame, mMetrics, mStatus, mValue);
05979 }
05980 
05981 struct DR_FrameTypeInfo;
05982 struct DR_FrameTreeNode;
05983 struct DR_Rule;
05984 
05985 struct DR_State
05986 {
05987   DR_State();
05988   ~DR_State();
05989   void Init();
05990   void AddFrameTypeInfo(nsIAtom* aFrameType,
05991                         const char* aFrameNameAbbrev,
05992                         const char* aFrameName);
05993   DR_FrameTypeInfo* GetFrameTypeInfo(nsIAtom* aFrameType);
05994   DR_FrameTypeInfo* GetFrameTypeInfo(char* aFrameName);
05995   void InitFrameTypeTable();
05996   DR_FrameTreeNode* CreateTreeNode(nsIFrame*                aFrame,
05997                                    const nsHTMLReflowState& aReflowState);
05998   void FindMatchingRule(DR_FrameTreeNode& aNode);
05999   PRBool RuleMatches(DR_Rule&          aRule,
06000                      DR_FrameTreeNode& aNode);
06001   PRBool GetToken(FILE* aFile,
06002                   char* aBuf);
06003   DR_Rule* ParseRule(FILE* aFile);
06004   void ParseRulesFile();
06005   void AddRule(nsVoidArray& aRules,
06006                DR_Rule&     aRule);
06007   PRBool IsWhiteSpace(int c);
06008   PRBool GetNumber(char*    aBuf, 
06009                  PRInt32&  aNumber);
06010   void PrettyUC(nscoord aSize,
06011                 char*   aBuf);
06012   void DisplayFrameTypeInfo(nsIFrame* aFrame,
06013                             PRInt32   aIndent);
06014   void DeleteTreeNode(DR_FrameTreeNode& aNode);
06015 
06016   PRBool      mInited;
06017   PRBool      mActive;
06018   PRInt32     mCount;
06019   nsVoidArray mWildRules;
06020   PRInt32     mAssert;
06021   PRInt32     mIndentStart;
06022   PRBool      mIndentUndisplayedFrames;
06023   nsVoidArray mFrameTypeTable;
06024   PRBool      mDisplayPixelErrors;
06025 
06026   // reflow specific state
06027   nsVoidArray mFrameTreeLeaves;
06028 };
06029 
06030 static DR_State *DR_state; // the one and only DR_State
06031 
06032 struct DR_RulePart 
06033 {
06034   DR_RulePart(nsIAtom* aFrameType) : mFrameType(aFrameType), mNext(0) {}
06035   void Destroy();
06036 
06037   nsIAtom*     mFrameType;
06038   DR_RulePart* mNext;
06039 };
06040 
06041 void DR_RulePart::Destroy()
06042 {
06043   if (mNext) {
06044     mNext->Destroy();
06045   }
06046   delete this;
06047 }
06048 
06049 MOZ_DECL_CTOR_COUNTER(DR_Rule)
06050 
06051 struct DR_Rule 
06052 {
06053   DR_Rule() : mLength(0), mTarget(nsnull), mDisplay(PR_FALSE) {
06054     MOZ_COUNT_CTOR(DR_Rule);
06055   }
06056   ~DR_Rule() {
06057     if (mTarget) mTarget->Destroy();
06058     MOZ_COUNT_DTOR(DR_Rule);
06059   }
06060   void AddPart(nsIAtom* aFrameType);
06061 
06062   PRUint32      mLength;
06063   DR_RulePart*  mTarget;
06064   PRBool        mDisplay;
06065 };
06066 
06067 void DR_Rule::AddPart(nsIAtom* aFrameType)
06068 {
06069   DR_RulePart* newPart = new DR_RulePart(aFrameType);
06070   newPart->mNext = mTarget;
06071   mTarget = newPart;
06072   mLength++;
06073 }
06074 
06075 MOZ_DECL_CTOR_COUNTER(DR_FrameTypeInfo)
06076 
06077 struct DR_FrameTypeInfo
06078 {
06079   DR_FrameTypeInfo(nsIAtom* aFrmeType, const char* aFrameNameAbbrev, const char* aFrameName);
06080   ~DR_FrameTypeInfo() { 
06081       MOZ_COUNT_DTOR(DR_FrameTypeInfo);
06082       PRInt32 numElements;
06083       numElements = mRules.Count();
06084       for (PRInt32 i = numElements - 1; i >= 0; i--) {
06085         delete (DR_Rule *)mRules.ElementAt(i);
06086       }
06087    }
06088 
06089   nsIAtom*    mType;
06090   char        mNameAbbrev[16];
06091   char        mName[32];
06092   nsVoidArray mRules;
06093 };
06094 
06095 DR_FrameTypeInfo::DR_FrameTypeInfo(nsIAtom* aFrameType, 
06096                                    const char* aFrameNameAbbrev, 
06097                                    const char* aFrameName)
06098 {
06099   mType = aFrameType;
06100   strcpy(mNameAbbrev, aFrameNameAbbrev);
06101   strcpy(mName, aFrameName);
06102   MOZ_COUNT_CTOR(DR_FrameTypeInfo);
06103 }
06104 
06105 MOZ_DECL_CTOR_COUNTER(DR_FrameTreeNode)
06106 
06107 struct DR_FrameTreeNode
06108 {
06109   DR_FrameTreeNode(nsIFrame* aFrame, DR_FrameTreeNode* aParent) : mFrame(aFrame), mParent(aParent), mDisplay(0), mIndent(0)
06110   {
06111     MOZ_COUNT_CTOR(DR_FrameTreeNode);
06112   }
06113 
06114   ~DR_FrameTreeNode()
06115   {
06116     MOZ_COUNT_DTOR(DR_FrameTreeNode);
06117   }
06118 
06119   nsIFrame*         mFrame;
06120   DR_FrameTreeNode* mParent;
06121   PRBool            mDisplay;
06122   PRUint32          mIndent;
06123 };
06124 
06125 // DR_State implementation
06126 
06127 MOZ_DECL_CTOR_COUNTER(DR_State)
06128 
06129 DR_State::DR_State() 
06130 : mInited(PR_FALSE), mActive(PR_FALSE), mCount(0), mAssert(-1), mIndentStart(0), 
06131   mIndentUndisplayedFrames(PR_FALSE), mDisplayPixelErrors(PR_FALSE)
06132 {
06133   MOZ_COUNT_CTOR(DR_State);
06134 }
06135 
06136 void DR_State::Init() 
06137 {
06138   char* env = PR_GetEnv("GECKO_DISPLAY_REFLOW_ASSERT");
06139   PRInt32 num;
06140   if (env) {
06141     if (GetNumber(env, num)) 
06142       mAssert = num;
06143     else 
06144       printf("GECKO_DISPLAY_REFLOW_ASSERT - invalid value = %s", env);
06145   }
06146 
06147   env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_START");
06148   if (env) {
06149     if (GetNumber(env, num)) 
06150       mIndentStart = num;
06151     else 
06152       printf("GECKO_DISPLAY_REFLOW_INDENT_START - invalid value = %s", env);
06153   }
06154 
06155   env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES");
06156   if (env) {
06157     if (GetNumber(env, num)) 
06158       mIndentUndisplayedFrames = num;
06159     else 
06160       printf("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES - invalid value = %s", env);
06161   }
06162 
06163   env = PR_GetEnv("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS");
06164   if (env) {
06165     if (GetNumber(env, num)) 
06166       mDisplayPixelErrors = num;
06167     else 
06168       printf("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS - invalid value = %s", env);
06169   }
06170 
06171   InitFrameTypeTable();
06172   ParseRulesFile();
06173   mInited = PR_TRUE;
06174 }
06175 
06176 DR_State::~DR_State()
06177 {
06178   MOZ_COUNT_DTOR(DR_State);
06179   PRInt32 numElements, i;
06180   numElements = mWildRules.Count();
06181   for (i = numElements - 1; i >= 0; i--) {
06182     delete (DR_Rule *)mWildRules.ElementAt(i);
06183   }
06184   numElements = mFrameTreeLeaves.Count();
06185   for (i = numElements - 1; i >= 0; i--) {
06186     delete (DR_FrameTreeNode *)mFrameTreeLeaves.ElementAt(i);
06187   }
06188   numElements = mFrameTypeTable.Count();
06189   for (i = numElements - 1; i >= 0; i--) {
06190     delete (DR_FrameTypeInfo *)mFrameTypeTable.ElementAt(i);
06191   }
06192 }
06193 
06194 PRBool DR_State::GetNumber(char*     aBuf, 
06195                            PRInt32&  aNumber)
06196 {
06197   if (sscanf(aBuf, "%d", &aNumber) > 0) 
06198     return PR_TRUE;
06199   else 
06200     return PR_FALSE;
06201 }
06202 
06203 PRBool DR_State::IsWhiteSpace(int c) {
06204   return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
06205 }
06206 
06207 PRBool DR_State::GetToken(FILE* aFile,
06208                           char* aBuf)
06209 {
06210   PRBool haveToken = PR_FALSE;
06211   aBuf[0] = 0;
06212   // get the 1st non whitespace char
06213   int c = -1;
06214   for (c = getc(aFile); (c > 0) && IsWhiteSpace(c); c = getc(aFile)) {
06215   }
06216 
06217   if (c > 0) {
06218     haveToken = PR_TRUE;
06219     aBuf[0] = c;
06220     // get everything up to the next whitespace char
06221     PRInt32 cX;
06222     for (cX = 1, c = getc(aFile); ; cX++, c = getc(aFile)) {
06223       if (c < 0) { // EOF
06224         ungetc(' ', aFile); 
06225         break;
06226       }
06227       else {
06228         if (IsWhiteSpace(c)) {
06229           break;
06230         }
06231         else {
06232           aBuf[cX] = c;
06233         }
06234       }
06235     }
06236     aBuf[cX] = 0;
06237   }
06238   return haveToken;
06239 }
06240 
06241 DR_Rule* DR_State::ParseRule(FILE* aFile)
06242 {
06243   char buf[128];
06244   PRInt32 doDisplay;
06245   DR_Rule* rule = nsnull;
06246   while (GetToken(aFile, buf)) {
06247     if (GetNumber(buf, doDisplay)) {
06248       if (rule) { 
06249         rule->mDisplay = (PRBool)doDisplay;
06250         break;
06251       }
06252       else {
06253         printf("unexpected token - %s \n", buf);
06254       }
06255     }
06256     else {
06257       if (!rule) {
06258         rule = new DR_Rule;
06259       }
06260       if (strcmp(buf, "*") == 0) {
06261         rule->AddPart(nsnull);
06262       }
06263       else {
06264         DR_FrameTypeInfo* info = GetFrameTypeInfo(buf);
06265         if (info) {
06266           rule->AddPart(info->mType);
06267         }
06268         else {
06269           printf("invalid frame type - %s \n", buf);
06270         }
06271       }
06272     }
06273   }
06274   return rule;
06275 }
06276 
06277 void DR_State::AddRule(nsVoidArray& aRules,
06278                        DR_Rule&     aRule)
06279 {
06280   PRInt32 numRules = aRules.Count();
06281   for (PRInt32 ruleX = 0; ruleX < numRules; ruleX++) {
06282     DR_Rule* rule = (DR_Rule*)aRules.ElementAt(ruleX);
06283     NS_ASSERTION(rule, "program error");
06284     if (aRule.mLength > rule->mLength) {
06285       aRules.InsertElementAt(&aRule, ruleX);
06286       return;
06287     }
06288   }
06289   aRules.AppendElement(&aRule);
06290 }
06291 
06292 void DR_State::ParseRulesFile()
06293 {
06294   char* path = PR_GetEnv("GECKO_DISPLAY_REFLOW_RULES_FILE");
06295   if (path) {
06296     FILE* inFile = fopen(path, "r");
06297     if (inFile) {
06298       for (DR_Rule* rule = ParseRule(inFile); rule; rule = ParseRule(inFile)) {
06299         if (rule->mTarget) {
06300           nsIAtom* fType = rule->mTarget->mFrameType;
06301           if (fType) {
06302             DR_FrameTypeInfo* info = GetFrameTypeInfo(fType);
06303             if (info) {
06304               AddRule(info->mRules, *rule);
06305             }
06306           }
06307           else {
06308             AddRule(mWildRules, *rule);
06309           }
06310           mActive = PR_TRUE;
06311         }
06312       }
06313     }
06314   }
06315 }
06316 
06317 
06318 void DR_State::AddFrameTypeInfo(nsIAtom* aFrameType,
06319                                 const char* aFrameNameAbbrev,
06320                                 const char* aFrameName)
06321 {
06322   mFrameTypeTable.AppendElement(new DR_FrameTypeInfo(aFrameType, aFrameNameAbbrev, aFrameName));
06323 }
06324 
06325 DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(nsIAtom* aFrameType)
06326 {
06327   PRInt32 numEntries = mFrameTypeTable.Count();
06328   NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
06329   for (PRInt32 i = 0; i < numEntries; i++) {
06330     DR_FrameTypeInfo* info = (DR_FrameTypeInfo*)mFrameTypeTable.ElementAt(i);
06331     if (info && (info->mType == aFrameType)) {
06332       return info;
06333     }
06334   }
06335   return (DR_FrameTypeInfo*)mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
06336 }
06337 
06338 DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(char* aFrameName)
06339 {
06340   PRInt32 numEntries = mFrameTypeTable.Count();
06341   NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
06342   for (PRInt32 i = 0; i < numEntries; i++) {
06343     DR_FrameTypeInfo* info = (DR_FrameTypeInfo*)mFrameTypeTable.ElementAt(i);
06344     if (info && ((strcmp(aFrameName, info->mName) == 0) || (strcmp(aFrameName, info->mNameAbbrev) == 0))) {
06345       return info;
06346     }
06347   }
06348   return (DR_FrameTypeInfo*)mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
06349 }
06350 
06351 void DR_State::InitFrameTypeTable()
06352 {  
06353   AddFrameTypeInfo(nsLayoutAtoms::areaFrame,             "area",      "area");
06354   AddFrameTypeInfo(nsLayoutAtoms::blockFrame,            "block",     "block");
06355   AddFrameTypeInfo(nsLayoutAtoms::brFrame,               "br",        "br");
06356   AddFrameTypeInfo(nsLayoutAtoms::bulletFrame,           "bullet",    "bullet");
06357   AddFrameTypeInfo(nsLayoutAtoms::gfxButtonControlFrame, "button",    "gfxButtonControl");
06358   AddFrameTypeInfo(nsLayoutAtoms::HTMLCanvasFrame,       "HTMLCanvas","HTMLCanvas");
06359   AddFrameTypeInfo(nsLayoutAtoms::subDocumentFrame,      "subdoc",    "subDocument");
06360   AddFrameTypeInfo(nsLayoutAtoms::imageFrame,            "img",       "image");
06361   AddFrameTypeInfo(nsLayoutAtoms::inlineFrame,           "inline",    "inline");
06362   AddFrameTypeInfo(nsLayoutAtoms::letterFrame,           "letter",    "letter");
06363   AddFrameTypeInfo(nsLayoutAtoms::lineFrame,             "line",      "line");
06364   AddFrameTypeInfo(nsLayoutAtoms::listControlFrame,      "select",    "select");
06365   AddFrameTypeInfo(nsLayoutAtoms::objectFrame,           "obj",       "object");
06366   AddFrameTypeInfo(nsLayoutAtoms::pageFrame,             "page",      "page");
06367   AddFrameTypeInfo(nsLayoutAtoms::placeholderFrame,      "place",     "placeholder");
06368   AddFrameTypeInfo(nsLayoutAtoms::positionedInlineFrame, "posInline", "positionedInline");
06369   AddFrameTypeInfo(nsLayoutAtoms::canvasFrame,           "canvas",    "canvas");
06370   AddFrameTypeInfo(nsLayoutAtoms::rootFrame,             "root",      "root");
06371   AddFrameTypeInfo(nsLayoutAtoms::scrollFrame,           "scroll",    "scroll");
06372   AddFrameTypeInfo(nsLayoutAtoms::tableCaptionFrame,     "caption",   "tableCaption");
06373   AddFrameTypeInfo(nsLayoutAtoms::tableCellFrame,        "cell",      "tableCell");
06374   AddFrameTypeInfo(nsLayoutAtoms::bcTableCellFrame,      "bcCell",    "bcTableCell");
06375   AddFrameTypeInfo(nsLayoutAtoms::tableColFrame,         "col",       "tableCol");
06376   AddFrameTypeInfo(nsLayoutAtoms::tableColGroupFrame,    "colG",      "tableColGroup");
06377   AddFrameTypeInfo(nsLayoutAtoms::tableFrame,            "tbl",       "table");
06378   AddFrameTypeInfo(nsLayoutAtoms::tableOuterFrame,       "tblO",      "tableOuter");
06379   AddFrameTypeInfo(nsLayoutAtoms::tableRowGroupFrame,    "rowG",      "tableRowGroup");
06380   AddFrameTypeInfo(nsLayoutAtoms::tableRowFrame,         "row",       "tableRow");
06381   AddFrameTypeInfo(nsLayoutAtoms::textInputFrame,        "textCtl",   "textInput");
06382   AddFrameTypeInfo(nsLayoutAtoms::textFrame,             "text",      "text");
06383   AddFrameTypeInfo(nsLayoutAtoms::viewportFrame,         "VP",        "viewport");
06384   AddFrameTypeInfo(nsnull,                               "unknown",   "unknown");
06385 }
06386 
06387 
06388 void DR_State::DisplayFrameTypeInfo(nsIFrame* aFrame,
06389                                     PRInt32   aIndent)
06390 { 
06391   DR_FrameTypeInfo* frameTypeInfo = GetFrameTypeInfo(aFrame->GetType());
06392   if (frameTypeInfo) {
06393     for (PRInt32 i = 0; i < aIndent; i++) {
06394       printf(" ");
06395     }
06396     if(!strcmp(frameTypeInfo->mNameAbbrev, "unknown")) {
06397       nsAutoString  name;
06398       nsIFrameDebug*  frameDebug;
06399       if (NS_SUCCEEDED(aFrame->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**)&frameDebug))) {
06400        frameDebug->GetFrameName(name);
06401        printf("%s %p ", NS_LossyConvertUCS2toASCII(name).get(), (void*)aFrame);
06402       }
06403       else {
06404         printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
06405       }
06406     }
06407     else {
06408       printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
06409     }
06410   }
06411 }
06412 
06413 PRBool DR_State::RuleMatches(DR_Rule&          aRule,
06414                              DR_FrameTreeNode& aNode)
06415 {
06416   NS_ASSERTION(aRule.mTarget, "program error");
06417 
06418   DR_RulePart* rulePart;
06419   DR_FrameTreeNode* parentNode;
06420   for (rulePart = aRule.mTarget->mNext, parentNode = aNode.mParent;
06421        rulePart && parentNode;
06422        rulePart = rulePart->mNext, parentNode = parentNode->mParent) {
06423     if (rulePart->mFrameType) {
06424       if (parentNode->mFrame) {
06425         if (rulePart->mFrameType != parentNode->mFrame->GetType()) {
06426           return PR_FALSE;
06427         }
06428       }
06429       else NS_ASSERTION(PR_FALSE, "program error");
06430     }
06431     // else wild card match
06432   }
06433   return PR_TRUE;
06434 }
06435 
06436 void DR_State::FindMatchingRule(DR_FrameTreeNode& aNode)
06437 {
06438   if (!aNode.mFrame) {
06439     NS_ASSERTION(PR_FALSE, "invalid DR_FrameTreeNode \n");
06440     return;
06441   }
06442 
06443   PRBool matchingRule = PR_FALSE;
06444 
06445   DR_FrameTypeInfo* info = GetFrameTypeInfo(aNode.mFrame->GetType());
06446   NS_ASSERTION(info, "program error");
06447   PRInt32 numRules = info->mRules.Count();
06448   for (PRInt32 ruleX = 0; ruleX < numRules; ruleX++) {
06449     DR_Rule* rule = (DR_Rule*)info->mRules.ElementAt(ruleX);
06450     if (rule && RuleMatches(*rule, aNode)) {
06451       aNode.mDisplay = rule->mDisplay;
06452       matchingRule = PR_TRUE;
06453       break;
06454     }
06455   }
06456   if (!matchingRule) {
06457     PRInt32 numWildRules = mWildRules.Count();
06458     for (PRInt32 ruleX = 0; ruleX < numWildRules; ruleX++) {
06459       DR_Rule* rule = (DR_Rule*)mWildRules.ElementAt(ruleX);
06460       if (rule && RuleMatches(*rule, aNode)) {
06461         aNode.mDisplay = rule->mDisplay;
06462         break;
06463       }
06464     }
06465   }
06466 
06467   if (aNode.mParent) {
06468     aNode.mIndent = aNode.mParent->mIndent;
06469     if (aNode.mDisplay || mIndentUndisplayedFrames) {
06470       aNode.mIndent++;
06471     }
06472   }
06473 }
06474     
06475 DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame*                aFrame,
06476                                            const nsHTMLReflowState& aReflowState)
06477 {
06478   // find the frame of the parent reflow state (usually just the parent of aFrame)
06479   const nsHTMLReflowState* parentRS = aReflowState.parentReflowState;
06480   nsIFrame* parentFrame = (parentRS) ? parentRS->frame : nsnull;
06481 
06482   // find the parent tree node leaf
06483   DR_FrameTreeNode* parentNode = nsnull;
06484   
06485   DR_FrameTreeNode* lastLeaf = nsnull;
06486   if(mFrameTreeLeaves.Count())
06487     lastLeaf = (DR_FrameTreeNode*)mFrameTreeLeaves.ElementAt(mFrameTreeLeaves.Count() - 1);
06488   if (lastLeaf) {
06489     for (parentNode = lastLeaf; parentNode && (parentNode->mFrame != parentFrame); parentNode = parentNode->mParent) {
06490     }
06491   }
06492   DR_FrameTreeNode* newNode = new DR_FrameTreeNode(aFrame, parentNode);
06493   FindMatchingRule(*newNode);
06494   if (lastLeaf && (lastLeaf == parentNode)) {
06495     mFrameTreeLeaves.RemoveElementAt(mFrameTreeLeaves.Count() - 1);
06496   }
06497   mFrameTreeLeaves.AppendElement(newNode);
06498   mCount++;
06499 
06500   return newNode;
06501 }
06502 
06503 void DR_State::PrettyUC(nscoord aSize,
06504                         char*   aBuf)
06505 {
06506   if (NS_UNCONSTRAINEDSIZE == aSize) {
06507     strcpy(aBuf, "UC");
06508   }
06509   else {
06510     if ((nscoord)0xdeadbeefU == aSize)
06511     {
06512       strcpy(aBuf, "deadbeef");
06513     }
06514     else {
06515       sprintf(aBuf, "%d", aSize);
06516     }
06517   }
06518 }
06519 
06520 void DR_State::DeleteTreeNode(DR_FrameTreeNode& aNode)
06521 {
06522   mFrameTreeLeaves.RemoveElement(&aNode);
06523   PRInt32 numLeaves = mFrameTreeLeaves.Count();
06524   if ((0 == numLeaves) || (aNode.mParent != (DR_FrameTreeNode*)mFrameTreeLeaves.ElementAt(numLeaves - 1))) {
06525     mFrameTreeLeaves.AppendElement(aNode.mParent);
06526   }
06527   // delete the tree node 
06528   delete &aNode;
06529 }
06530 
06531 static void
06532 CheckPixelError(nscoord aSize,
06533                 float   aPixelToTwips)
06534 {
06535   if (NS_UNCONSTRAINEDSIZE != aSize) {
06536     if ((aSize % NSToCoordRound(aPixelToTwips)) > 0) {
06537       printf("VALUE %d is not a whole pixel \n", aSize);
06538     }
06539   }
06540 }
06541 
06542 static void DisplayReflowEnterPrint(nsPresContext*          aPresContext,
06543                                     nsIFrame*                aFrame,
06544                                     const nsHTMLReflowState& aReflowState,
06545                                     DR_FrameTreeNode&        aTreeNode,
06546                                     PRBool                   aChanged)
06547 {
06548   if (aTreeNode.mDisplay) {
06549     DR_state->DisplayFrameTypeInfo(aFrame, aTreeNode.mIndent);
06550 
06551     char width[16];
06552     char height[16];
06553 
06554     DR_state->PrettyUC(aReflowState.availableWidth, width);
06555     DR_state->PrettyUC(aReflowState.availableHeight, height);
06556     if (aReflowState.path && aReflowState.path->mReflowCommand) {
06557       const char *incr_reason;
06558       switch(aReflowState.path->mReflowCommand->Type()) {
06559         case eReflowType_ContentChanged:
06560           incr_reason = "incr. (Content)";
06561           break;
06562         case eReflowType_StyleChanged:
06563           incr_reason = "incr. (Style)";
06564           break;
06565         case eReflowType_ReflowDirty:
06566           incr_reason = "incr. (Dirty)";
06567           break;
06568         default:
06569           incr_reason = "incr. (Unknown)";
06570       }
06571       printf("r=%d %s a=%s,%s ", aReflowState.reason, incr_reason, width, height);
06572     }
06573     else {
06574       printf("r=%d a=%s,%s ", aReflowState.reason, width, height);
06575     }
06576 
06577     DR_state->PrettyUC(aReflowState.mComputedWidth, width);
06578     DR_state->PrettyUC(aReflowState.mComputedHeight, height);
06579     printf("c=%s,%s ", width, height);
06580 
06581     nsIFrame* inFlow = aFrame->GetPrevInFlow();
06582     if (inFlow) {
06583       printf("pif=%p ", (void*)inFlow);
06584     }
06585     inFlow = aFrame->GetNextInFlow();
06586     if (inFlow) {
06587       printf("nif=%p ", (void*)inFlow);
06588     }
06589     if (aChanged) 
06590       printf("CHANGED \n");
06591     else 
06592       printf("cnt=%d \n", DR_state->mCount);
06593     if (DR_state->mDisplayPixelErrors) {
06594       float p2t = aPresContext->ScaledPixelsToTwips();
06595       CheckPixelError(aReflowState.availableWidth, p2t);
06596       CheckPixelError(aReflowState.availableHeight, p2t);
06597       CheckPixelError(aReflowState.mComputedWidth, p2t);
06598       CheckPixelError(aReflowState.mComputedHeight, p2t);
06599     }
06600   }
06601 }
06602 
06603 void* nsFrame::DisplayReflowEnter(nsPresContext*          aPresContext,
06604                                   nsIFrame*                aFrame,
06605                                   const nsHTMLReflowState& aReflowState)
06606 {
06607   if (!DR_state->mInited) DR_state->Init();
06608   if (!DR_state->mActive) return nsnull;
06609 
06610   NS_ASSERTION(aFrame, "invalid call");
06611 
06612   DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, aReflowState);
06613   if (treeNode) {
06614     DisplayReflowEnterPrint(aPresContext, aFrame, aReflowState, *treeNode, PR_FALSE);
06615   }
06616   return treeNode;
06617 }
06618 
06619 void nsFrame::DisplayReflowExit(nsPresContext*      aPresContext,
06620                                 nsIFrame*            aFrame,
06621                                 nsHTMLReflowMetrics& aMetrics,
06622                                 nsReflowStatus       aStatus,
06623                                 void*                aFrameTreeNode)
06624 {
06625   if (!DR_state->mActive) return;
06626 
06627   NS_ASSERTION(aFrame, "DisplayReflowExit - invalid call");
06628   if (!aFrameTreeNode) return;
06629 
06630   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
06631   if (treeNode->mDisplay) {
06632     DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
06633 
06634     char width[16];
06635     char height[16];
06636     char x[16];
06637     char y[16];
06638     DR_state->PrettyUC(aMetrics.width, width);
06639     DR_state->PrettyUC(aMetrics.height, height);
06640     printf("d=%s,%s ", width, height);
06641 
06642     if (aMetrics.mComputeMEW) {
06643       DR_state->PrettyUC(aMetrics.mMaxElementWidth, width);
06644       printf("me=%s ", width);
06645     }
06646     if (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH) {
06647       DR_state->PrettyUC(aMetrics.mMaximumWidth, width);
06648       printf("m=%s ", width);
06649     }
06650     if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
06651       printf("status=0x%x", aStatus);
06652     }
06653     if (aFrame->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) {
06654        DR_state->PrettyUC(aMetrics.mOverflowArea.x, x);
06655        DR_state->PrettyUC(aMetrics.mOverflowArea.y, y);
06656        DR_state->PrettyUC(aMetrics.mOverflowArea.width, width);
06657        DR_state->PrettyUC(aMetrics.mOverflowArea.height, height);
06658        printf("o=(%s,%s) %s x %s", x, y, width, height);
06659        nsRect* storedOverflow = aFrame->GetOverflowAreaProperty();
06660        if (storedOverflow) {
06661          if (aMetrics.mOverflowArea != *storedOverflow) {
06662            DR_state->PrettyUC(storedOverflow->x, x);
06663            DR_state->PrettyUC(storedOverflow->y, y);
06664            DR_state->PrettyUC(storedOverflow->width, width);
06665            DR_state->PrettyUC(storedOverflow->height, height);
06666            printf("sto=(%s,%s) %s x %s", x, y, width, height);
06667          }
06668        }
06669     }
06670     printf("\n");
06671     if (DR_state->mDisplayPixelErrors) {
06672       float p2t = aPresContext->ScaledPixelsToTwips();
06673       CheckPixelError(aMetrics.width, p2t);
06674       CheckPixelError(aMetrics.height, p2t);
06675       if (aMetrics.mComputeMEW) 
06676         CheckPixelError(aMetrics.mMaxElementWidth, p2t);
06677       if (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH) 
06678         CheckPixelError(aMetrics.mMaximumWidth, p2t);
06679     }
06680   }
06681   DR_state->DeleteTreeNode(*treeNode);
06682 }
06683 
06684 /* static */ void
06685 nsFrame::DisplayReflowStartup()
06686 {
06687   DR_state = new DR_State();
06688 }
06689 
06690 /* static */ void
06691 nsFrame::DisplayReflowShutdown()
06692 {
06693   delete DR_state;
06694   DR_state = nsnull;
06695 }
06696 
06697 void DR_cookie::Change() const
06698 {
06699   DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)mValue;
06700   if (treeNode && treeNode->mDisplay) {
06701     DisplayReflowEnterPrint(mPresContext, mFrame, mReflowState, *treeNode, PR_TRUE);
06702   }
06703 }
06704 
06705 #endif
06706 // End Display Reflow
06707 
06708 #endif