Back to index

lightning-sunbird  0.9+nobinonly
nsPresShell.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  * ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Steve Clark <buster@netscape.com>
00024  *   Håkan Waara <hwaara@chello.se>
00025  *   Dan Rosen <dr@netscape.com>
00026  *   Daniel Glazman <glazman@netscape.com>
00027  *   Mats Palmgren <mats.palmgren@bredband.net>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either of the GNU General Public License Version 2 or later (the "GPL"),
00031  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK *****
00042  *
00043  * This Original Code has been modified by IBM Corporation.
00044  * Modifications made by IBM described herein are
00045  * Copyright (c) International Business Machines
00046  * Corporation, 2000
00047  *
00048  * Modifications to Mozilla code or documentation
00049  * identified per MPL Section 3.3
00050  *
00051  * Date         Modified by     Description of modification
00052  * 05/03/2000   IBM Corp.       Observer events for reflow states
00053  */ 
00054 
00055 #define PL_ARENA_CONST_ALIGN_MASK 3
00056 
00057 #include "nsIPresShell.h"
00058 #include "nsPresContext.h"
00059 #include "nsIContent.h"
00060 #include "nsIDocument.h"
00061 #include "nsIDOMXULDocument.h"
00062 #include "nsStubDocumentObserver.h"
00063 #include "nsStyleSet.h"
00064 #include "nsICSSStyleSheet.h" // XXX for UA sheet loading hack, can this go away please?
00065 #include "nsIDOMCSSStyleSheet.h"  // for Pref-related rule management (bugs 22963,20760,31816)
00066 #include "nsINameSpaceManager.h"  // for Pref-related rule management (bugs 22963,20760,31816)
00067 #include "nsIServiceManager.h"
00068 #include "nsFrame.h"
00069 #include "nsHTMLReflowCommand.h"
00070 #include "nsIViewManager.h"
00071 #include "nsCRT.h"
00072 #include "prlog.h"
00073 #include "prmem.h"
00074 #include "prprf.h"
00075 #include "prinrval.h"
00076 #include "nsVoidArray.h"
00077 #include "nsCOMArray.h"
00078 #include "nsHashtable.h"
00079 #include "nsIViewObserver.h"
00080 #include "nsContainerFrame.h"
00081 #include "nsIDeviceContext.h"
00082 #include "nsEventStateManager.h"
00083 #include "nsDOMEvent.h"
00084 #include "nsGUIEvent.h"
00085 #include "nsHTMLParts.h"
00086 #include "nsContentUtils.h"
00087 #include "nsISelection.h"
00088 #include "nsISelectionController.h"
00089 #include "nsReflowPath.h"
00090 #include "nsLayoutCID.h"
00091 #include "nsLayoutAtoms.h"
00092 #include "nsIDOMRange.h"
00093 #include "nsIDOMDocument.h"
00094 #include "nsIDOMNode.h"
00095 #include "nsIDOM3Node.h"
00096 #include "nsIDOMNodeList.h"
00097 #include "nsIDOMElement.h"
00098 #include "nsHTMLAtoms.h"
00099 #include "nsCSSPseudoElements.h"
00100 #include "nsCOMPtr.h"
00101 #include "nsAutoPtr.h"
00102 #include "nsReadableUtils.h"
00103 #include "nsUnicharUtils.h"
00104 #include "nsWeakReference.h"
00105 #include "nsIPageSequenceFrame.h"
00106 #include "nsICaret.h"
00107 #include "nsIDOMHTMLDocument.h"
00108 #include "nsIXPointer.h"
00109 #include "nsIDOMXMLDocument.h"
00110 #include "nsIScrollableView.h"
00111 #include "nsIParser.h"
00112 #include "nsParserCIID.h"
00113 #include "nsIFrameSelection.h"
00114 #include "nsIDOMNSHTMLInputElement.h" //optimization for ::DoXXX commands
00115 #include "nsIDOMNSHTMLTextAreaElement.h"
00116 #include "nsViewsCID.h"
00117 #include "nsFrameManager.h"
00118 #include "nsXPCOM.h"
00119 #include "nsISupportsPrimitives.h"
00120 #include "nsILayoutHistoryState.h"
00121 #include "nsIScrollPositionListener.h"
00122 #include "nsICompositeListener.h"
00123 #include "nsILineIterator.h" // for ScrollFrameIntoView
00124 #include "nsTimer.h"
00125 #include "nsWeakPtr.h"
00126 #include "plarena.h"
00127 #include "pldhash.h"
00128 #include "nsIObserverService.h"
00129 #include "nsIObserver.h"
00130 #include "nsIDocShell.h"        // for reflow observation
00131 #include "nsIBaseWindow.h"
00132 #include "nsLayoutErrors.h"
00133 #include "nsLayoutUtils.h"
00134 #include "nsCSSRendering.h"
00135 #ifdef NS_DEBUG
00136 #include "nsIFrameDebug.h"
00137 #endif
00138   // for |#ifdef DEBUG| code
00139 #include "nsSpaceManager.h"
00140 #include "prenv.h"
00141 #include "nsIAttribute.h"
00142 #include "nsIGlobalHistory2.h"
00143 
00144 #ifdef MOZ_REFLOW_PERF_DSP
00145 #include "nsIRenderingContext.h"
00146 #include "nsIFontMetrics.h"
00147 #endif
00148 
00149 #include "nsIReflowCallback.h"
00150 
00151 #include "nsIScriptGlobalObject.h"
00152 #include "nsIDOMWindowInternal.h"
00153 #include "nsPIDOMWindow.h"
00154 #include "nsIFocusController.h"
00155 #include "nsIPluginInstance.h"
00156 #include "nsIObjectFrame.h"
00157 #include "nsIPluginHost.h"
00158 
00159 // Drag & Drop, Clipboard
00160 #include "nsWidgetsCID.h"
00161 #include "nsIClipboard.h"
00162 #include "nsIClipboardHelper.h"
00163 #include "nsIDocShellTreeItem.h"
00164 #include "nsIURI.h"
00165 #include "nsIEventQueue.h"
00166 #include "nsIEventQueueService.h"
00167 #include "nsIScrollableFrame.h"
00168 #include "prtime.h"
00169 #include "prlong.h"
00170 #include "nsIDragService.h"
00171 #include "nsCopySupport.h"
00172 #include "nsIDOMHTMLAnchorElement.h"
00173 #include "nsIDOMHTMLAreaElement.h"
00174 #include "nsIDOMHTMLLinkElement.h"
00175 #include "nsITimer.h"
00176 #include "nsITimerInternal.h"
00177 #ifdef ACCESSIBILITY
00178 #include "nsIAccessibilityService.h"
00179 #include "nsIAccessible.h"
00180 #include "nsIAccessibleEvent.h"
00181 #endif
00182 
00183 // For style data reconstruction
00184 #include "nsStyleChangeList.h"
00185 #include "nsCSSFrameConstructor.h"
00186 #include "nsIBindingManager.h"
00187 #ifdef MOZ_XUL
00188 #include "nsIMenuFrame.h"
00189 #include "nsITreeBoxObject.h"
00190 #endif
00191 #include "nsIMenuParent.h"
00192 #include "nsPlaceholderFrame.h"
00193 
00194 // Dummy layout request
00195 #include "nsDummyLayoutRequest.h"
00196 
00197 // Content viewer interfaces
00198 #include "nsIContentViewer.h"
00199 
00200 #ifdef IBMBIDI
00201 #include "nsIBidiKeyboard.h"
00202 #endif // IBMBIDI
00203 
00204 #include "nsContentCID.h"
00205 static NS_DEFINE_CID(kCSSStyleSheetCID, NS_CSS_STYLESHEET_CID);
00206 static NS_DEFINE_IID(kRangeCID,     NS_RANGE_CID);
00207 
00208 // convert a color value to a string, in the CSS format #RRGGBB
00209 // *  - initially created for bugs 31816, 20760, 22963
00210 static void ColorToString(nscolor aColor, nsAutoString &aString);
00211 
00212 // Class ID's
00213 static NS_DEFINE_CID(kFrameSelectionCID, NS_FRAMESELECTION_CID);
00214 static NS_DEFINE_CID(kEventQueueServiceCID,   NS_EVENTQUEUESERVICE_CID);
00215 
00216 #undef NOISY
00217 
00218 // ----------------------------------------------------------------------
00219 
00220 #ifdef NS_DEBUG
00221 // Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
00222 // more of the following flags (comma separated) for handy debug
00223 // output.
00224 static PRUint32 gVerifyReflowFlags;
00225 
00226 struct VerifyReflowFlags {
00227   const char*    name;
00228   PRUint32 bit;
00229 };
00230 
00231 static const VerifyReflowFlags gFlags[] = {
00232   { "verify",                VERIFY_REFLOW_ON },
00233   { "reflow",                VERIFY_REFLOW_NOISY },
00234   { "all",                   VERIFY_REFLOW_ALL },
00235   { "list-commands",         VERIFY_REFLOW_DUMP_COMMANDS },
00236   { "noisy-commands",        VERIFY_REFLOW_NOISY_RC },
00237   { "really-noisy-commands", VERIFY_REFLOW_REALLY_NOISY_RC },
00238   { "space-manager",         VERIFY_REFLOW_INCLUDE_SPACE_MANAGER },
00239   { "resize",                VERIFY_REFLOW_DURING_RESIZE_REFLOW },
00240 };
00241 
00242 #define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
00243 
00244 static void
00245 ShowVerifyReflowFlags()
00246 {
00247   printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n");
00248   const VerifyReflowFlags* flag = gFlags;
00249   const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
00250   while (flag < limit) {
00251     printf("  %s\n", flag->name);
00252     ++flag;
00253   }
00254   printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
00255   printf("names (no whitespace)\n");
00256 }
00257 #endif
00258 
00259 //========================================================================
00260 //========================================================================
00261 //========================================================================
00262 #ifdef MOZ_REFLOW_PERF
00263 class ReflowCountMgr;
00264 
00265 static const char kGrandTotalsStr[] = "Grand Totals";
00266 #define NUM_REFLOW_TYPES 5
00267 
00268 // Counting Class
00269 class ReflowCounter {
00270 public:
00271   ReflowCounter(ReflowCountMgr * aMgr = nsnull);
00272   ~ReflowCounter();
00273 
00274   void ClearTotals();
00275   void DisplayTotals(const char * aStr);
00276   void DisplayDiffTotals(const char * aStr);
00277   void DisplayHTMLTotals(const char * aStr);
00278 
00279   void Add(nsReflowReason aType)                  { mTotals[aType]++;         }
00280   void Add(nsReflowReason aType, PRUint32 aTotal) { mTotals[aType] += aTotal; }
00281 
00282   void CalcDiffInTotals();
00283   void SetTotalsCache();
00284 
00285   void SetMgr(ReflowCountMgr * aMgr) { mMgr = aMgr; }
00286 
00287   PRUint32 GetTotalByType(nsReflowReason aType) { if (aType >= eReflowReason_Initial && aType <= eReflowReason_Dirty) return mTotals[aType]; else return 0; }
00288   
00289 protected:
00290   void DisplayTotals(PRUint32 * aArray, const char * aTitle);
00291   void DisplayHTMLTotals(PRUint32 * aArray, const char * aTitle);
00292 
00293   PRUint32 mTotals[NUM_REFLOW_TYPES];
00294   PRUint32 mCacheTotals[NUM_REFLOW_TYPES];
00295 
00296   ReflowCountMgr * mMgr; // weak reference (don't delete)
00297 };
00298 
00299 // Counting Class
00300 class IndiReflowCounter {
00301 public:
00302   IndiReflowCounter(ReflowCountMgr * aMgr = nsnull)
00303     : mFrame(nsnull),
00304       mCount(0),
00305       mMgr(aMgr),
00306       mCounter(aMgr),
00307       mHasBeenOutput(PR_FALSE)
00308     {}
00309   virtual ~IndiReflowCounter() {}
00310 
00311   nsAutoString mName;
00312   nsIFrame *   mFrame;   // weak reference (don't delete)
00313   PRInt32      mCount;
00314 
00315   ReflowCountMgr * mMgr; // weak reference (don't delete)
00316 
00317   ReflowCounter mCounter;
00318   PRBool        mHasBeenOutput;
00319 
00320 };
00321 
00322 //--------------------
00323 // Manager Class
00324 //--------------------
00325 class ReflowCountMgr {
00326 public:
00327   ReflowCountMgr();
00328   virtual ~ReflowCountMgr();
00329 
00330   void ClearTotals();
00331   void ClearGrandTotals();
00332   void DisplayTotals(const char * aStr);
00333   void DisplayHTMLTotals(const char * aStr);
00334   void DisplayDiffsInTotals(const char * aStr);
00335 
00336   void Add(const char * aName, nsReflowReason aType, nsIFrame * aFrame);
00337   ReflowCounter * LookUp(const char * aName);
00338 
00339   void PaintCount(const char * aName, nsIRenderingContext* aRenderingContext, nsPresContext* aPresContext, nsIFrame * aFrame, PRUint32 aColor);
00340 
00341   FILE * GetOutFile() { return mFD; }
00342 
00343   PLHashTable * GetIndiFrameHT() { return mIndiFrameCounts; }
00344 
00345   void SetPresContext(nsPresContext * aPresContext) { mPresContext = aPresContext; } // weak reference
00346   void SetPresShell(nsIPresShell* aPresShell) { mPresShell= aPresShell; } // weak reference
00347 
00348   void SetDumpFrameCounts(PRBool aVal)         { mDumpFrameCounts = aVal; }
00349   void SetDumpFrameByFrameCounts(PRBool aVal)  { mDumpFrameByFrameCounts = aVal; }
00350   void SetPaintFrameCounts(PRBool aVal)        { mPaintFrameByFrameCounts = aVal; }
00351 
00352 protected:
00353   void DisplayTotals(PRUint32 * aArray, PRUint32 * aDupArray, char * aTitle);
00354   void DisplayHTMLTotals(PRUint32 * aArray, PRUint32 * aDupArray, char * aTitle);
00355 
00356   PR_STATIC_CALLBACK(PRIntn) RemoveItems(PLHashEntry *he, PRIntn i, void *arg);
00357   PR_STATIC_CALLBACK(PRIntn) RemoveIndiItems(PLHashEntry *he, PRIntn i, void *arg);
00358   void CleanUp();
00359 
00360   // stdout Output Methods
00361   PR_STATIC_CALLBACK(PRIntn) DoSingleTotal(PLHashEntry *he, PRIntn i, void *arg);
00362   PR_STATIC_CALLBACK(PRIntn) DoSingleIndi(PLHashEntry *he, PRIntn i, void *arg);
00363 
00364   void DoGrandTotals();
00365   void DoIndiTotalsTree();
00366 
00367   // HTML Output Methods
00368   PR_STATIC_CALLBACK(PRIntn) DoSingleHTMLTotal(PLHashEntry *he, PRIntn i, void *arg);
00369   void DoGrandHTMLTotals();
00370 
00371   // Zero Out the Totals
00372   PR_STATIC_CALLBACK(PRIntn) DoClearTotals(PLHashEntry *he, PRIntn i, void *arg);
00373 
00374   // Displays the Diff Totals
00375   PR_STATIC_CALLBACK(PRIntn) DoDisplayDiffTotals(PLHashEntry *he, PRIntn i, void *arg);
00376 
00377   PLHashTable * mCounts;
00378   PLHashTable * mIndiFrameCounts;
00379   FILE * mFD;
00380   
00381   PRBool mDumpFrameCounts;
00382   PRBool mDumpFrameByFrameCounts;
00383   PRBool mPaintFrameByFrameCounts;
00384 
00385   PRBool mCycledOnce;
00386 
00387   // Root Frame for Individual Tracking
00388   nsPresContext * mPresContext;
00389   nsIPresShell*    mPresShell;
00390 
00391   // ReflowCountMgr gReflowCountMgr;
00392 };
00393 #endif
00394 //========================================================================
00395 
00396 // comment out to hide caret
00397 #define SHOW_CARET
00398 
00399 // The upper bound on the amount of time to spend reflowing, in
00400 // microseconds.  When this bound is exceeded and reflow commands are
00401 // still queued up, a reflow event is posted.  The idea is for reflow
00402 // to not hog the processor beyond the time specifed in
00403 // gMaxRCProcessingTime.  This data member is initialized from the
00404 // layout.reflow.timeslice pref.
00405 #define NS_MAX_REFLOW_TIME    1000000
00406 static PRInt32 gMaxRCProcessingTime = -1;
00407 
00408 // Set to true to enable async reflow during document load.
00409 // This flag is initialized from the layout.reflow.async.duringDocLoad pref.
00410 static PRBool gAsyncReflowDuringDocLoad = PR_FALSE;
00411 
00412 // Largest chunk size we recycle
00413 static const size_t gMaxRecycledSize = 400;
00414 
00415 #define MARK_INCREMENT 50
00416 #define BLOCK_INCREMENT 4044 /* a bit under 4096, for malloc overhead */
00417 
00421 struct StackBlock {
00422    
00423    // a block of memory.  Note that this must be first so that it will
00424    // be aligned.
00425    char mBlock[BLOCK_INCREMENT];
00426 
00427    // another block of memory that would only be created
00428    // if our stack overflowed. Yes we have the ability
00429    // to grow on a stack overflow
00430    StackBlock* mNext;
00431 
00432    StackBlock() : mNext(nsnull) { }
00433    ~StackBlock() { }
00434 };
00435 
00436 /* we hold an array of marks. A push pushes a mark on the stack
00437  * a pop pops it off.
00438  */
00439 struct StackMark {
00440    // the block of memory we are currently handing out chunks of
00441    StackBlock* mBlock;
00442    
00443    // our current position in the memory
00444    size_t mPos;
00445 };
00446 
00447 
00448 /* A stack arena allows a stack based interface to a block of memory.
00449  * It should be used when you need to allocate some temporary memory that
00450  * you will immediately return.
00451  */
00452 class StackArena {
00453 public:
00454   StackArena();
00455   ~StackArena();
00456 
00457   // Memory management functions
00458   nsresult  Allocate(size_t aSize, void** aResult);
00459   nsresult  Push();
00460   nsresult  Pop();
00461 
00462 private:
00463   // our current position in memory
00464   size_t mPos;
00465 
00466   // a list of memory block. Usually there is only one
00467   // but if we overrun our stack size we can get more memory.
00468   StackBlock* mBlocks;
00469 
00470   // the current block of memory we are passing our chucks of
00471   StackBlock* mCurBlock;
00472 
00473   // our stack of mark where push has been called
00474   StackMark* mMarks;
00475 
00476   // the current top of the the mark list
00477   PRUint32 mStackTop;
00478 
00479   // the size of the mark array
00480   PRUint32 mMarkLength;
00481 };
00482 
00483 
00484 
00485 StackArena::StackArena()
00486 {
00487   // allocate the marks array
00488   mMarkLength = MARK_INCREMENT;
00489   mMarks = new StackMark[mMarkLength];
00490 
00491   // allocate our stack memory
00492   mBlocks = new StackBlock();
00493   mCurBlock = mBlocks;
00494 
00495   mStackTop = 0;
00496   mPos = 0;
00497 }
00498 
00499 StackArena::~StackArena()
00500 {
00501   // free up our data
00502   delete[] mMarks;
00503   while(mBlocks)
00504   {
00505     StackBlock* toDelete = mBlocks;
00506     mBlocks = mBlocks->mNext;
00507     delete toDelete;
00508   }
00509 } 
00510 
00511 nsresult
00512 StackArena::Push()
00513 {
00514   // if the we overrun our mark array. Resize it.
00515   if (mStackTop + 1 >= mMarkLength)
00516   {
00517     StackMark* oldMarks = mMarks;
00518     PRUint32 oldLength = mMarkLength;
00519     mMarkLength += MARK_INCREMENT;
00520     mMarks = new StackMark[mMarkLength];
00521     memcpy(mMarks, oldMarks, sizeof(StackMark)*oldLength);
00522 
00523     delete[] oldMarks;
00524   }
00525 
00526   // set a mark at the top
00527   mMarks[mStackTop].mBlock = mCurBlock;
00528   mMarks[mStackTop].mPos = mPos;
00529 
00530   mStackTop++;
00531 
00532   return NS_OK;
00533 }
00534 
00535 nsresult
00536 StackArena::Allocate(size_t aSize, void** aResult)
00537 {
00538   NS_ASSERTION(mStackTop > 0, "Error allocate called before push!!!");
00539 
00540   // make sure we are aligned. Beard said 8 was safer then 4. 
00541   // Round size to multiple of 8
00542   aSize = PR_ROUNDUP(aSize, 8);
00543 
00544   // if the size makes the stack overflow. Grab another block for the stack
00545   if (mPos + aSize >= BLOCK_INCREMENT)
00546   {
00547     NS_ASSERTION(aSize <= BLOCK_INCREMENT,"Requested memory is greater that our block size!!");
00548     if (mCurBlock->mNext == nsnull)
00549       mCurBlock->mNext = new StackBlock();
00550 
00551     mCurBlock =  mCurBlock->mNext;
00552     mPos = 0;
00553   }
00554 
00555   // return the chunk they need.
00556   *aResult = mCurBlock->mBlock + mPos;
00557   mPos += aSize;
00558 
00559   return NS_OK;
00560 }
00561 
00562 nsresult
00563 StackArena::Pop()
00564 {
00565   // pop off the mark
00566   NS_ASSERTION(mStackTop > 0, "Error Pop called 1 too many times");
00567   mStackTop--;
00568 
00569 #ifdef DEBUG
00570   // Mark the "freed" memory with 0xdd to help with debugging of memory
00571   // allocation problems.
00572   {
00573     StackBlock *block = mMarks[mStackTop].mBlock, *block_end = mCurBlock;
00574     size_t pos = mMarks[mStackTop].mPos;
00575     for (; block != block_end; block = block->mNext, pos = 0) {
00576       memset(block->mBlock + pos, 0xdd, sizeof(block->mBlock) - pos);
00577     }
00578     memset(block->mBlock + pos, 0xdd, mPos - pos);
00579   }
00580 #endif
00581 
00582   mCurBlock = mMarks[mStackTop].mBlock;
00583   mPos      = mMarks[mStackTop].mPos;
00584 
00585   return NS_OK;
00586 }
00587 
00588 // Uncomment this to disable the frame arena.
00589 //#define DEBUG_TRACEMALLOC_FRAMEARENA 1
00590 
00591 // Memory is allocated 4-byte aligned. We have recyclers for chunks up to
00592 // 200 bytes
00593 class FrameArena {
00594 public:
00595   FrameArena(PRUint32 aArenaSize = 4096);
00596   ~FrameArena();
00597 
00598   // Memory management functions
00599   NS_HIDDEN_(void*) AllocateFrame(size_t aSize);
00600   NS_HIDDEN_(void)  FreeFrame(size_t aSize, void* aPtr);
00601 
00602 private:
00603 #ifdef DEBUG
00604   // Number of frames in the pool
00605   PRUint32 mFrameCount;
00606 #endif
00607 
00608 #if !defined(DEBUG_TRACEMALLOC_FRAMEARENA)
00609   // Underlying arena pool
00610   PLArenaPool mPool;
00611 
00612   // The recycler array is sparse with the indices being multiples of 4,
00613   // i.e., 0, 4, 8, 12, 16, 20, ...
00614   void*       mRecyclers[gMaxRecycledSize >> 2];
00615 #endif
00616 };
00617 
00618 FrameArena::FrameArena(PRUint32 aArenaSize)
00619 #ifdef DEBUG
00620   : mFrameCount(0)
00621 #endif
00622 {
00623 #if !defined(DEBUG_TRACEMALLOC_FRAMEARENA)
00624   // Initialize the arena pool
00625   PL_INIT_ARENA_POOL(&mPool, "FrameArena", aArenaSize);
00626 
00627   // Zero out the recyclers array
00628   memset(mRecyclers, 0, sizeof(mRecyclers));
00629 #endif
00630 }
00631 
00632 FrameArena::~FrameArena()
00633 {
00634   NS_ASSERTION(mFrameCount == 0,
00635                "Some objects allocated with AllocateFrame were not freed");
00636  
00637 #if !defined(DEBUG_TRACEMALLOC_FRAMEARENA)
00638   // Free the arena in the pool and finish using it
00639   PL_FinishArenaPool(&mPool);
00640 #endif
00641 } 
00642 
00643 void*
00644 FrameArena::AllocateFrame(size_t aSize)
00645 {
00646   void* result = nsnull;
00647 #if defined(DEBUG_TRACEMALLOC_FRAMEARENA)
00648   result = PR_Malloc(aSize);
00649 #else
00650   
00651   // Ensure we have correct alignment for pointers.  Important for Tru64
00652   aSize = PR_ROUNDUP(aSize, sizeof(void*));
00653 
00654   // Check recyclers first
00655   if (aSize < gMaxRecycledSize) {
00656     const int   index = aSize >> 2;
00657 
00658     result = mRecyclers[index];
00659     if (result) {
00660       // Need to move to the next object
00661       void* next = *((void**)result);
00662       mRecyclers[index] = next;
00663     }
00664   }
00665 
00666   if (!result) {
00667     // Allocate a new chunk from the arena
00668     PL_ARENA_ALLOCATE(result, &mPool, aSize);
00669   }
00670 
00671 #endif
00672 
00673 #ifdef DEBUG
00674   if (result != nsnull)
00675     ++mFrameCount;
00676 #endif
00677 
00678   return result;
00679 }
00680 
00681 void
00682 FrameArena::FreeFrame(size_t aSize, void* aPtr)
00683 {
00684 #ifdef DEBUG
00685   --mFrameCount;
00686 
00687   // Mark the memory with 0xdd in DEBUG builds so that there will be
00688   // problems if someone tries to access memory that they've freed.
00689   memset(aPtr, 0xdd, aSize);
00690 #endif
00691 #if defined(DEBUG_TRACEMALLOC_FRAMEARENA)
00692   PR_Free(aPtr);
00693 #else
00694   // Ensure we have correct alignment for pointers.  Important for Tru64
00695   aSize = PR_ROUNDUP(aSize, sizeof(void*));
00696 
00697   // See if it's a size that we recycle
00698   if (aSize < gMaxRecycledSize) {
00699     const int   index = aSize >> 2;
00700     void*       currentTop = mRecyclers[index];
00701     mRecyclers[index] = aPtr;
00702     *((void**)aPtr) = currentTop;
00703   }
00704 #ifdef DEBUG_dbaron
00705   else {
00706     fprintf(stderr,
00707             "WARNING: FrameArena::FreeFrame leaking chunk of %d bytes.\n",
00708             aSize);
00709   }
00710 #endif
00711 #endif
00712 }
00713 
00714 class PresShellViewEventListener : public nsIScrollPositionListener,
00715                                    public nsICompositeListener
00716 {
00717 public:
00718   PresShellViewEventListener();
00719   virtual ~PresShellViewEventListener();
00720 
00721   NS_DECL_ISUPPORTS
00722 
00723   // nsIScrollPositionListener methods
00724   NS_IMETHOD ScrollPositionWillChange(nsIScrollableView *aView, nscoord aX, nscoord aY);
00725   NS_IMETHOD ScrollPositionDidChange(nsIScrollableView *aView, nscoord aX, nscoord aY);
00726 
00727   // nsICompositeListener methods
00728   NS_IMETHOD WillRefreshRegion(nsIViewManager *aViewManager,
00729                                nsIView *aView,
00730                                nsIRenderingContext *aContext,
00731                                nsIRegion *aRegion,
00732                                PRUint32 aUpdateFlags);
00733 
00734   NS_IMETHOD DidRefreshRegion(nsIViewManager *aViewManager,
00735                               nsIView *aView,
00736                               nsIRenderingContext *aContext,
00737                               nsIRegion *aRegion,
00738                               PRUint32 aUpdateFlags);
00739 
00740   NS_IMETHOD WillRefreshRect(nsIViewManager *aViewManager,
00741                              nsIView *aView,
00742                              nsIRenderingContext *aContext,
00743                              const nsRect *aRect,
00744                              PRUint32 aUpdateFlags);
00745 
00746   NS_IMETHOD DidRefreshRect(nsIViewManager *aViewManager,
00747                             nsIView *aView,
00748                             nsIRenderingContext *aContext,
00749                             const nsRect *aRect,
00750                             PRUint32 aUpdateFlags);
00751 
00752   nsresult SetPresShell(nsIPresShell *aPresShell);
00753 
00754 private:
00755 
00756   nsresult HideCaret();
00757   nsresult RestoreCaretVisibility();
00758 
00759   nsIPresShell *mPresShell;
00760   PRBool        mWasVisible;
00761   PRInt32       mCallCount;
00762 };
00763 
00764 struct nsDOMEventRequest 
00765 {
00766   nsIContent* content;
00767   nsEvent* event;
00768   nsDOMEventRequest* next;
00769 };
00770 
00771 struct nsAttributeChangeRequest 
00772 {
00773   nsIContent* content;
00774   PRInt32 nameSpaceID;
00775   nsIAtom* name;
00776   nsAutoString value;
00777   PRBool notify;
00778   nsAttributeChangeType type;
00779   nsAttributeChangeRequest* next;
00780 };
00781 
00782 struct nsCallbackEventRequest
00783 {
00784   nsIReflowCallback* callback;
00785   nsCallbackEventRequest* next;
00786 };
00787 
00788 
00789 PRInt32 nsDummyLayoutRequest::gRefCnt;
00790 nsIURI* nsDummyLayoutRequest::gURI;
00791 
00792 NS_IMPL_ADDREF(nsDummyLayoutRequest)
00793 NS_IMPL_RELEASE(nsDummyLayoutRequest)
00794 NS_IMPL_QUERY_INTERFACE2(nsDummyLayoutRequest, nsIRequest, nsIChannel)
00795 
00796 nsresult
00797 nsDummyLayoutRequest::Create(nsIRequest** aResult, nsIPresShell* aPresShell)
00798 {
00799   *aResult = new nsDummyLayoutRequest(aPresShell);
00800   if (!*aResult)
00801       return NS_ERROR_OUT_OF_MEMORY;
00802 
00803   NS_ADDREF(*aResult);
00804 
00805   return NS_OK; 
00806 }
00807 
00808 
00809 nsDummyLayoutRequest::nsDummyLayoutRequest(nsIPresShell* aPresShell)
00810 {
00811   if (gRefCnt++ == 0) {
00812       nsresult rv;
00813       rv = NS_NewURI(&gURI, "about:layout-dummy-request", nsnull);
00814       NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create about:layout-dummy-request");
00815   }
00816 
00817   mPresShell = do_GetWeakReference(aPresShell);
00818 }
00819 
00820 
00821 nsDummyLayoutRequest::~nsDummyLayoutRequest()
00822 {
00823   if (--gRefCnt == 0) {
00824       NS_IF_RELEASE(gURI);
00825   }
00826 }
00827 
00828 NS_IMETHODIMP
00829 nsDummyLayoutRequest::Cancel(nsresult status)
00830 {
00831   // Cancel layout
00832   nsresult rv = NS_OK;
00833   nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
00834   if (presShell) {
00835     rv = presShell->CancelAllReflowCommands();
00836   }
00837   return rv;
00838 }
00839 
00840 // ----------------------------------------------------------------------------
00841 
00846 class IncrementalReflow
00847 {
00848 public:
00849   ~IncrementalReflow();
00850 
00855   enum AddCommandResult {
00856     eEnqueued, // the command was successfully added
00857     eTryLater, // the command could not be added; try again
00858     eCancel,   // the command was not added; delete it
00859     eOOM       // Out of memory.
00860   };
00861   AddCommandResult
00862   AddCommand(nsPresContext      *aPresContext,
00863              nsHTMLReflowCommand *aCommand);
00864 
00868   void
00869   Dispatch(nsPresContext      *aPresContext,
00870            nsHTMLReflowMetrics &aDesiredSize,
00871            const nsSize        &aMaxSize,
00872            nsIRenderingContext &aRendContext);
00873 
00874 #ifdef NS_DEBUG
00875 
00878   void
00879   Dump(nsPresContext *aPresContext) const;
00880 #endif
00881 
00882 protected:
00886   nsAutoVoidArray mRoots;
00887 };
00888 
00889 IncrementalReflow::~IncrementalReflow()
00890 {
00891   for (PRInt32 i = mRoots.Count() - 1; i >= 0; --i)
00892     delete NS_STATIC_CAST(nsReflowPath *, mRoots[i]);
00893 }
00894 
00895 void
00896 IncrementalReflow::Dispatch(nsPresContext      *aPresContext,
00897                             nsHTMLReflowMetrics &aDesiredSize,
00898                             const nsSize        &aMaxSize,
00899                             nsIRenderingContext &aRendContext)
00900 {
00901   for (PRInt32 i = mRoots.Count() - 1; i >= 0; --i) {
00902     // Send an incremental reflow notification to the first frame in the
00903     // path.
00904     nsReflowPath *path = NS_STATIC_CAST(nsReflowPath *, mRoots[i]);
00905     nsIFrame *first = path->mFrame;
00906 
00907     nsIFrame* root = aPresContext->PresShell()->FrameManager()->GetRootFrame();
00908 
00909     first->WillReflow(aPresContext);
00910     nsContainerFrame::PositionFrameView(first);
00911 
00912     // If the first frame in the path is the root of the frame
00913     // hierarchy, then use all the available space. If it's simply a
00914     // `reflow root', then use the first frame's size as the available
00915     // space.
00916     nsSize size;
00917     if (first == root)
00918       size = aMaxSize;
00919     else
00920       size = first->GetSize();
00921 
00922     nsHTMLReflowState reflowState(aPresContext, first, path,
00923                                   &aRendContext, size);
00924 
00925     nsReflowStatus status;
00926     first->Reflow(aPresContext, aDesiredSize, reflowState, status);
00927 
00928     // If an incremental reflow is initiated at a frame other than the
00929     // root frame, then its desired size had better not change!
00930     NS_ASSERTION(first == root ||
00931                  (aDesiredSize.width == size.width && aDesiredSize.height == size.height),
00932                  "non-root frame's desired size changed during an incremental reflow");
00933 
00934     first->SetSize(nsSize(aDesiredSize.width, aDesiredSize.height));
00935 
00936     nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, first, first->GetView(),
00937                                                &aDesiredSize.mOverflowArea);
00938 
00939     first->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
00940   }
00941 }
00942 
00943 IncrementalReflow::AddCommandResult
00944 IncrementalReflow::AddCommand(nsPresContext      *aPresContext,
00945                               nsHTMLReflowCommand *aCommand)
00946 {
00947   nsIFrame *frame;
00948   aCommand->GetTarget(frame);
00949   NS_ASSERTION(frame != nsnull, "reflow command with no target");
00950 
00951   // Construct the reflow path by walking up the through the frames'
00952   // parent chain until we reach either a `reflow root' or the root
00953   // frame in the frame hierarchy.
00954   nsAutoVoidArray path;
00955   do {
00956     path.AppendElement(frame);
00957   } while (!(frame->GetStateBits() & NS_FRAME_REFLOW_ROOT) &&
00958            (frame = frame->GetParent()) != nsnull);
00959 
00960   // Pop off the root, add it to the set if it's not there already.
00961   PRInt32 lastIndex = path.Count() - 1;
00962   nsIFrame *rootFrame = NS_STATIC_CAST(nsIFrame *, path[lastIndex]);
00963   path.RemoveElementAt(lastIndex);
00964 
00965   // Prevent an incremental reflow from being posted inside a reflow
00966   // root if the reflow root's container has not yet been reflowed.
00967   // This can cause problems like bug 228156.
00968   if (rootFrame->GetParent() &&
00969       (rootFrame->GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
00970     return eCancel;
00971   }
00972 
00973   nsReflowPath *root = nsnull;
00974 
00975   PRInt32 i;
00976   for (i = mRoots.Count() - 1; i >= 0; --i) {
00977     nsReflowPath *r = NS_STATIC_CAST(nsReflowPath *, mRoots[i]);
00978     if (r->mFrame == rootFrame) {
00979       root = r;
00980       break;
00981     }
00982   }
00983 
00984   if (! root) {
00985     root = new nsReflowPath(rootFrame);
00986     if (! root)
00987       return eOOM;
00988 
00989     root->mReflowCommand = nsnull;
00990     mRoots.AppendElement(root);
00991   }
00992 
00993   // Now walk the path from the root to the leaf, adding to the reflow
00994   // tree as necessary.
00995   nsReflowPath *target = root;
00996   for (i = path.Count() - 1; i >= 0; --i) {
00997     nsIFrame *f = NS_STATIC_CAST(nsIFrame *, path[i]);
00998     target = target->EnsureSubtreeFor(f);
00999 
01000     // Out of memory. Ugh.
01001     if (! target)
01002       return eOOM;
01003   }
01004 
01005   // Place the reflow command in the leaf, if one isn't there already.
01006   if (target->mReflowCommand) {
01007     // XXXwaterson it's probably possible to have some notion of
01008     // `promotion' here that would avoid any re-queuing; for example,
01009     // promote a dirty reflow to a style changed. For now, let's punt
01010     // and not worry about it.
01011 #ifdef NS_DEBUG
01012     if (gVerifyReflowFlags & VERIFY_REFLOW_NOISY_RC)
01013       printf("requeuing command %p because %p was already scheduled "
01014              "for the same frame",
01015              (void*)aCommand, (void*)target->mReflowCommand);
01016 #endif
01017 
01018     return eTryLater;
01019   }
01020 
01021   target->mReflowCommand = aCommand;
01022   return eEnqueued;
01023 }
01024 
01025 
01026 #ifdef NS_DEBUG
01027 void
01028 IncrementalReflow::Dump(nsPresContext *aPresContext) const
01029 {
01030   for (PRInt32 i = mRoots.Count() - 1; i >= 0; --i)
01031     NS_STATIC_CAST(nsReflowPath *, mRoots[i])->Dump(aPresContext, stdout, 0);
01032 }
01033 #endif
01034 
01035 // ----------------------------------------------------------------------------
01036 
01037 struct ReflowCommandEntry : public PLDHashEntryHdr
01038 {
01039   nsHTMLReflowCommand* mCommand;
01040 };
01041 
01042 PR_STATIC_CALLBACK(const void *)
01043 ReflowCommandHashGetKey(PLDHashTable *table, PLDHashEntryHdr *entry)
01044 {
01045   ReflowCommandEntry *e = NS_STATIC_CAST(ReflowCommandEntry *, entry);
01046   
01047   return e->mCommand;
01048 }
01049 
01050 PR_STATIC_CALLBACK(PLDHashNumber)
01051 ReflowCommandHashHashKey(PLDHashTable *table, const void *key)
01052 {
01053   const nsHTMLReflowCommand* command =
01054     NS_STATIC_CAST(const nsHTMLReflowCommand*, key);
01055   
01056   // The target is going to be reasonably unique, if we shift out the
01057   // always-zero low-order bits, the type comes from an enum and we just don't
01058   // have that many types, and the child list name is either null or has the
01059   // same high-order bits as all the other child list names.
01060   return
01061     (NS_PTR_TO_INT32(command->GetTarget()) >> 2) ^
01062     (command->Type() << 17) ^
01063     (NS_PTR_TO_INT32(command->GetChildListName()) << 20);
01064 }
01065 
01066 PR_STATIC_CALLBACK(PRBool)
01067 ReflowCommandHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry,
01068                             const void *key)
01069 {
01070    const ReflowCommandEntry *e =
01071      NS_STATIC_CAST(const ReflowCommandEntry *, entry);
01072    const nsHTMLReflowCommand *command = e->mCommand;
01073    const nsHTMLReflowCommand *command2 =
01074      NS_STATIC_CAST(const nsHTMLReflowCommand *, key);
01075 
01076    return
01077      command->GetTarget() == command2->GetTarget() &&
01078      command->Type() == command2->Type() &&
01079      command->GetChildListName() == command2->GetChildListName();
01080 }
01081 
01082 // ----------------------------------------------------------------------------
01083 
01084 struct CantRenderReplacedElementEvent;
01085 
01086 class PresShell : public nsIPresShell_MOZILLA_1_8_BRANCH2, public nsIViewObserver,
01087                   public nsStubDocumentObserver,
01088                   public nsISelectionController, public nsIObserver,
01089                   public nsSupportsWeakReference
01090 {
01091 public:
01092   friend class nsIPresShell;
01093 
01094   PresShell();
01095 
01096   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
01097 
01098   // nsISupports
01099   NS_DECL_ISUPPORTS
01100 
01101   // nsIPresShell
01102   NS_IMETHOD Init(nsIDocument* aDocument,
01103                   nsPresContext* aPresContext,
01104                   nsIViewManager* aViewManager,
01105                   nsStyleSet* aStyleSet,
01106                   nsCompatibility aCompatMode);
01107   NS_IMETHOD Destroy();
01108 
01109   virtual NS_HIDDEN_(void*) AllocateFrame(size_t aSize);
01110   virtual NS_HIDDEN_(void)  FreeFrame(size_t aSize, void* aFreeChunk);
01111 
01112   // Dynamic stack memory allocation
01113   NS_IMETHOD PushStackMemory();
01114   NS_IMETHOD PopStackMemory();
01115   NS_IMETHOD AllocateStackMemory(size_t aSize, void** aResult);
01116 
01117   NS_IMETHOD GetActiveAlternateStyleSheet(nsString& aSheetTitle);
01118   NS_IMETHOD SelectAlternateStyleSheet(const nsString& aSheetTitle);
01119   NS_IMETHOD ListAlternateStyleSheets(nsStringArray& aTitleList);
01120   NS_IMETHOD SetPreferenceStyleRules(PRBool aForceReflow);
01121 
01122   NS_IMETHOD GetSelection(SelectionType aType, nsISelection** aSelection);
01123 
01124   NS_IMETHOD SetDisplaySelection(PRInt16 aToggle);
01125   NS_IMETHOD GetDisplaySelection(PRInt16 *aToggle);
01126   NS_IMETHOD ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion, PRBool aIsSynchronous);
01127   NS_IMETHOD RepaintSelection(SelectionType aType);
01128 
01129   NS_IMETHOD BeginObservingDocument();
01130   NS_IMETHOD EndObservingDocument();
01131   NS_IMETHOD GetDidInitialReflow(PRBool *aDidInitialReflow);
01132   NS_IMETHOD InitialReflow(nscoord aWidth, nscoord aHeight);
01133   NS_IMETHOD ResizeReflow(nscoord aWidth, nscoord aHeight);
01134   NS_IMETHOD StyleChangeReflow();
01135   NS_IMETHOD GetPageSequenceFrame(nsIPageSequenceFrame** aResult) const;
01136   NS_IMETHOD GetPrimaryFrameFor(nsIContent* aContent,
01137                                 nsIFrame**  aPrimaryFrame) const;
01138 
01139   NS_IMETHOD GetLayoutObjectFor(nsIContent*   aContent,
01140                                 nsISupports** aResult) const;
01141   NS_IMETHOD GetPlaceholderFrameFor(nsIFrame*  aFrame,
01142                                     nsIFrame** aPlaceholderFrame) const;
01143   NS_IMETHOD AppendReflowCommand(nsIFrame*    aTargetFrame,
01144                                  nsReflowType aReflowType,
01145                                  nsIAtom*     aChildListName);
01146   NS_IMETHOD CancelReflowCommand(nsIFrame*     aTargetFrame, 
01147                                  nsReflowType* aCmdType);  
01148   NS_IMETHOD CancelReflowCommandInternal(nsIFrame*     aTargetFrame, 
01149                                          nsReflowType* aCmdType,
01150                                          PRBool        aProcessDummyLayoutRequest = PR_TRUE);  
01151   NS_IMETHOD CancelAllReflowCommands();
01152   NS_IMETHOD IsSafeToFlush(PRBool& aIsSafeToFlush);
01153   NS_IMETHOD FlushPendingNotifications(mozFlushType aType);
01154 
01158   NS_IMETHOD RecreateFramesFor(nsIContent* aContent);
01159 
01163   NS_IMETHOD PostDOMEvent(nsIContent* aContent, nsEvent* aEvent);
01164 
01168   NS_IMETHOD PostAttributeChange(nsIContent* aContent,
01169                                  PRInt32 aNameSpaceID, 
01170                                  nsIAtom* aName,
01171                                  const nsString& aValue,
01172                                  PRBool aNotify,
01173                                  nsAttributeChangeType aType);
01174 
01178   NS_IMETHOD PostReflowCallback(nsIReflowCallback* aCallback);
01179   NS_IMETHOD CancelReflowCallback(nsIReflowCallback* aCallback);
01180 
01184   NS_IMETHOD BeginReflowBatching();
01185   NS_IMETHOD EndReflowBatching(PRBool aFlushPendingReflows);  
01186   NS_IMETHOD GetReflowBatchingStatus(PRBool* aBatch);
01187   
01188   NS_IMETHOD ClearFrameRefs(nsIFrame* aFrame);
01189   NS_IMETHOD CreateRenderingContext(nsIFrame *aFrame,
01190                                     nsIRenderingContext** aContext);
01191   NS_IMETHOD CantRenderReplacedElement(nsIFrame*       aFrame);
01192   NS_IMETHOD GoToAnchor(const nsAString& aAnchorName, PRBool aScroll);
01193 
01194   NS_IMETHOD ScrollFrameIntoView(nsIFrame *aFrame,
01195                                  PRIntn   aVPercent, 
01196                                  PRIntn   aHPercent) const;
01197 
01198   NS_IMETHOD SetIgnoreFrameDestruction(PRBool aIgnore);
01199   NS_IMETHOD NotifyDestroyingFrame(nsIFrame* aFrame);
01200   
01201   NS_IMETHOD DoCopy();
01202   NS_IMETHOD GetSelectionForCopy(nsISelection** outSelection);
01203 
01204   NS_IMETHOD GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocationString);
01205   NS_IMETHOD DoGetContents(const nsACString& aMimeType, PRUint32 aFlags, PRBool aSelectionOnly, nsAString& outValue);
01206 
01207   NS_IMETHOD CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState, PRBool aLeavingPage);
01208 
01209   NS_IMETHOD GetGeneratedContentIterator(nsIContent*          aContent,
01210                                          GeneratedContentType aType,
01211                                          nsIContentIterator** aIterator) const;
01212  
01213   NS_IMETHOD SetAnonymousContentFor(nsIContent* aContent, nsISupportsArray* aAnonymousElements);
01214   NS_IMETHOD GetAnonymousContentFor(nsIContent* aContent, nsISupportsArray** aAnonymousElements);
01215   NS_IMETHOD ReleaseAnonymousContent();
01216 
01217   NS_IMETHOD IsPaintingSuppressed(PRBool* aResult);
01218   NS_IMETHOD UnsuppressPainting();
01219   
01220   NS_IMETHOD DisableThemeSupport();
01221   virtual PRBool IsThemeSupportEnabled();
01222 
01223   virtual nsresult GetAgentStyleSheets(nsCOMArray<nsIStyleSheet>& aSheets);
01224   virtual nsresult SetAgentStyleSheets(const nsCOMArray<nsIStyleSheet>& aSheets);
01225 
01226   virtual nsresult AddOverrideStyleSheet(nsIStyleSheet *aSheet);
01227   virtual nsresult RemoveOverrideStyleSheet(nsIStyleSheet *aSheet);
01228 
01229   NS_IMETHOD HandleEventWithTarget(nsEvent* aEvent, nsIFrame* aFrame, nsIContent* aContent, PRUint32 aFlags, nsEventStatus* aStatus);
01230   NS_IMETHOD GetEventTargetFrame(nsIFrame** aFrame);
01231   NS_IMETHOD GetEventTargetContent(nsEvent* aEvent, nsIContent** aContent);
01232 
01233   NS_IMETHOD IsReflowLocked(PRBool* aIsLocked);  
01234 
01235   virtual nsresult ReconstructFrames(void);
01236   virtual void Freeze();
01237   virtual void Thaw();
01238 
01239 #ifdef IBMBIDI
01240   NS_IMETHOD SetCaretBidiLevel(PRUint8 aLevel);
01241   NS_IMETHOD GetCaretBidiLevel(PRUint8 *aOutLevel);
01242   NS_IMETHOD UndefineCaretBidiLevel();
01243   NS_IMETHOD BidiStyleChangeReflow();
01244 #endif
01245 
01246   virtual void HidePopups();
01247   virtual void BlockFlushing();
01248   virtual void UnblockFlushing();  
01249   virtual void AddObserver(nsIDocumentObserver* aObserver);
01250   virtual PRBool RemoveObserver(nsIDocumentObserver* aObserver);
01251 
01252   //nsIViewObserver interface
01253 
01254   NS_IMETHOD Paint(nsIView *aView,
01255                    nsIRenderingContext& aRenderingContext,
01256                    const nsRect&        aDirtyRect);
01257   NS_IMETHOD HandleEvent(nsIView*        aView,
01258                          nsGUIEvent*     aEvent,
01259                          nsEventStatus*  aEventStatus,
01260                          PRBool          aForceHandle,
01261                          PRBool&         aHandled);
01262   NS_IMETHOD HandleDOMEventWithTarget(nsIContent* aTargetContent,
01263                             nsEvent* aEvent,
01264                             nsEventStatus* aStatus);
01265   NS_IMETHOD ResizeReflow(nsIView *aView, nscoord aWidth, nscoord aHeight);
01266   NS_IMETHOD_(PRBool) IsVisible();
01267   NS_IMETHOD_(void) WillPaint();
01268 
01269   // caret handling
01270   NS_IMETHOD GetCaret(nsICaret **aOutCaret);
01271   NS_IMETHOD SetCaretEnabled(PRBool aInEnable);
01272   NS_IMETHOD SetCaretReadOnly(PRBool aReadOnly);
01273   NS_IMETHOD GetCaretEnabled(PRBool *aOutEnabled);
01274   NS_IMETHOD SetCaretVisibilityDuringSelection(PRBool aVisibility);
01275 
01276   NS_IMETHOD SetSelectionFlags(PRInt16 aInEnable);
01277   NS_IMETHOD GetSelectionFlags(PRInt16 *aOutEnable);
01278 
01279   // nsISelectionController
01280 
01281   NS_IMETHOD CharacterMove(PRBool aForward, PRBool aExtend);
01282   NS_IMETHOD WordMove(PRBool aForward, PRBool aExtend);
01283   NS_IMETHOD LineMove(PRBool aForward, PRBool aExtend);
01284   NS_IMETHOD IntraLineMove(PRBool aForward, PRBool aExtend);
01285   NS_IMETHOD PageMove(PRBool aForward, PRBool aExtend);
01286   NS_IMETHOD ScrollPage(PRBool aForward);
01287   NS_IMETHOD ScrollLine(PRBool aForward);
01288   NS_IMETHOD ScrollHorizontal(PRBool aLeft);
01289   NS_IMETHOD CompleteScroll(PRBool aForward);
01290   NS_IMETHOD CompleteMove(PRBool aForward, PRBool aExtend);
01291   NS_IMETHOD SelectAll();
01292   NS_IMETHOD CheckVisibility(nsIDOMNode *node, PRInt16 startOffset, PRInt16 EndOffset, PRBool *_retval);
01293 
01294   // nsIDocumentObserver
01295   virtual void BeginUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType);
01296   virtual void EndUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType);
01297   virtual void BeginLoad(nsIDocument* aDocument);
01298   virtual void EndLoad(nsIDocument* aDocument);
01299   virtual void CharacterDataChanged(nsIDocument* aDocument,
01300                                     nsIContent* aContent,
01301                                     PRBool aAppend);
01302   virtual void ContentStatesChanged(nsIDocument* aDocument,
01303                                     nsIContent* aContent1,
01304                                     nsIContent* aContent2,
01305                                     PRInt32 aStateMask);
01306   virtual void AttributeChanged(nsIDocument* aDocument, nsIContent* aContent,
01307                                 PRInt32 aNameSpaceID, nsIAtom* aAttribute,
01308                                 PRInt32 aModType);
01309   virtual void ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
01310                                PRInt32 aNewIndexInContainer);
01311   virtual void ContentInserted(nsIDocument* aDocument, nsIContent* aContainer,
01312                                nsIContent* aChild, PRInt32 aIndexInContainer);
01313   virtual void ContentRemoved(nsIDocument* aDocument, nsIContent* aContainer,
01314                               nsIContent* aChild, PRInt32 aIndexInContainer);
01315   virtual void StyleSheetAdded(nsIDocument* aDocument,
01316                                nsIStyleSheet* aStyleSheet,
01317                                PRBool aDocumentSheet);
01318   virtual void StyleSheetRemoved(nsIDocument* aDocument,
01319                                  nsIStyleSheet* aStyleSheet,
01320                                  PRBool aDocumentSheet);
01321   virtual void StyleSheetApplicableStateChanged(nsIDocument* aDocument,
01322                                                 nsIStyleSheet* aStyleSheet,
01323                                                 PRBool aApplicable);
01324   virtual void StyleRuleChanged(nsIDocument* aDocument,
01325                                 nsIStyleSheet* aStyleSheet,
01326                                 nsIStyleRule* aOldStyleRule,
01327                                 nsIStyleRule* aNewStyleRule);
01328   virtual void StyleRuleAdded(nsIDocument* aDocument,
01329                               nsIStyleSheet* aStyleSheet,
01330                               nsIStyleRule* aStyleRule);
01331   virtual void StyleRuleRemoved(nsIDocument* aDocument,
01332                                 nsIStyleSheet* aStyleSheet,
01333                                 nsIStyleRule* aStyleRule);
01334 
01335   NS_DECL_NSIOBSERVER
01336 
01337 #ifdef MOZ_REFLOW_PERF
01338   NS_IMETHOD DumpReflows();
01339   NS_IMETHOD CountReflows(const char * aName, PRUint32 aType, nsIFrame * aFrame);
01340   NS_IMETHOD PaintCount(const char * aName, nsIRenderingContext* aRenderingContext, nsPresContext* aPresContext, nsIFrame * aFrame, PRUint32 aColor);
01341 
01342   NS_IMETHOD SetPaintFrameCount(PRBool aOn);
01343   
01344 #endif
01345 
01346 #ifdef DEBUG
01347   virtual void ListStyleContexts(nsIFrame *aRootFrame, FILE *out,
01348                                  PRInt32 aIndent = 0);
01349 
01350   virtual void ListStyleSheets(FILE *out, PRInt32 aIndent = 0);
01351 #endif
01352 
01353 #ifdef PR_LOGGING
01354   static PRLogModuleInfo* gLog;
01355 #endif
01356 
01357 protected:
01358   virtual ~PresShell();
01359 
01360   void HandlePostedDOMEvents();
01361   void HandlePostedAttributeChanges();
01362   void HandlePostedReflowCallbacks();
01363 
01364   void UnsuppressAndInvalidate();
01365 
01366   nsresult ReflowCommandAdded(nsHTMLReflowCommand* aRC);
01367   nsresult ReflowCommandRemoved(nsHTMLReflowCommand* aRC);
01368 
01369   // This method should be called after a reflow commands have been
01370   // removed from the queue, but after the state in the presshell is
01371   // such that it's safe to flush (i.e. mIsReflowing == PR_FALSE)
01372   // If we are not reflowing and there are no load-crated reflow commands, then
01373   // the dummyLayoutRequest is removed
01374   void DoneRemovingReflowCommands();
01375 
01376   friend struct DummyLayoutRequestEvent;
01377   nsresult AddDummyLayoutRequest(void);
01378   nsresult RemoveDummyLayoutRequest();
01379 
01380   friend struct CantRenderReplacedElementEvent;
01381   NS_HIDDEN_(void) DequeuePostedEventFor(nsIFrame* aFrame);
01382   NS_HIDDEN_(CantRenderReplacedElementEvent**)
01383     FindPostedEventFor(nsIFrame* aFrame);
01384 
01385   void     WillCauseReflow() { ++mChangeNestCount; }
01386   nsresult DidCauseReflow();
01387   void     DidDoReflow();
01388   nsresult ProcessReflowCommands(PRBool aInterruptible);
01389   nsresult ClearReflowEventStatus();  
01390   void     PostReflowEvent();
01391 
01392   // Note: when PR_FALSE is returned, AlreadyInQueue assumes the command will
01393   // in fact be added to the queue.  If it's not, it needs to be removed from
01394   // mReflowCommandTable (AlreadyInQueue will insert it in that table).
01395   PRBool   AlreadyInQueue(nsHTMLReflowCommand* aReflowCommand);
01396   
01397   friend struct ReflowEvent;
01398 
01399   // Utility to determine if we're in the middle of a drag.
01400   PRBool IsDragInProgress ( ) const ;
01401 
01402   // Utility to find which view to scroll.
01403   nsIScrollableView* GetViewToScroll(nsLayoutUtils::Direction aDirection);
01404 
01405   PRBool mCaretEnabled;
01406 #ifdef IBMBIDI
01407   PRUint8   mBidiLevel; // The Bidi level of the cursor
01408   nsCOMPtr<nsIBidiKeyboard> mBidiKeyboard;
01409 #endif // IBMBIDI
01410 #ifdef NS_DEBUG
01411   nsresult CloneStyleSet(nsStyleSet* aSet, nsStyleSet** aResult);
01412   PRBool VerifyIncrementalReflow();
01413   PRBool mInVerifyReflow;
01414 #endif
01415 
01420   nsresult ClearPreferenceStyleRules(void);
01421   nsresult CreatePreferenceStyleSheet(void);
01422   nsresult SetPrefColorRules(void);
01423   nsresult SetPrefLinkRules(void);
01424   nsresult SetPrefFocusRules(void);
01425   nsresult SetPrefNoScriptRule();
01426   nsresult SetPrefNoFramesRule(void);
01427 
01428   // Hide a view if it is a popup
01429   void HideViewIfPopup(nsIView* aView);
01430 
01431   nsICSSStyleSheet*         mPrefStyleSheet; // mStyleSet owns it but we maintain a ref, may be null
01432 #ifdef DEBUG
01433   PRUint32                  mUpdateCount;
01434 #endif
01435   // normal reflow commands
01436   nsVoidArray               mReflowCommands;
01437   PLDHashTable              mReflowCommandTable;
01438 
01439   PRPackedBool mDocumentLoading;
01440   PRPackedBool mIsReflowing;
01441   PRPackedBool mIsDestroying;
01442   PRPackedBool mIsReleasingAnonymousContent;
01443 
01444   PRPackedBool mIgnoreFrameDestruction;
01445   PRPackedBool mHaveShutDown;
01446 
01447   // This is used to protect ourselves from triggering reflow while in the
01448   // middle of frame construction and the like... it really shouldn't be
01449   // needed, one hopes, but it is for now.
01450   PRUint32  mChangeNestCount;
01451   
01452   nsIFrame*   mCurrentEventFrame;
01453   nsCOMPtr<nsIContent> mCurrentEventContent;
01454   nsVoidArray mCurrentEventFrameStack;
01455   nsCOMArray<nsIContent> mCurrentEventContentStack;
01456   nsSupportsHashtable* mAnonymousContentTable;
01457 
01458 #ifdef NS_DEBUG
01459   nsRect mCurrentTargetRect;
01460   nsIView* mCurrentTargetView;
01461 #endif
01462   
01463   nsCOMPtr<nsICaret>            mCaret;
01464   PRInt16                       mSelectionFlags;
01465   PRPackedBool                  mBatchReflows;  // When set to true, the pres shell batches reflow commands.
01466   // When mDummyLayoutRequestEventPosted is true, we have an event
01467   // posted that will call RemoveDummyLayoutRequest when it fires.
01468   PRPackedBool                  mDummyLayoutRequestEventPosted;
01469   PresShellViewEventListener    *mViewEventListener;
01470   nsCOMPtr<nsIEventQueueService> mEventQueueService;
01471   nsCOMPtr<nsIEventQueue>       mReflowEventQueue;
01472   FrameArena                    mFrameArena;
01473   StackArena*                   mStackArena;
01474   nsCOMPtr<nsIDragService>      mDragService;
01475   PRInt32                       mRCCreatedDuringLoad; // Counter to keep track of reflow commands created during doc
01476   // The dummy layout request is used to prevent onload from firing
01477   // until after all the reflows that were posted during document load
01478   // have been processed.  The control flow here is the following:
01479   // 1)  Any time a reflow command is added while the document is loading, if
01480   //     we do not already have a dummy layout request we go ahead and create
01481   //     one.
01482   // 2)  Any time we've removed all reflow commands that were added during
01483   //     document load and have a mDummyLayoutRequest we post an event to
01484   //     remove this request.  The one exception is when we're destroying the
01485   //     presshell; then we don't post an event (see item #4).
01486   // 3)  While the event to remove the request is posted,
01487   //     mDummyLayoutRequestEventPosted is set to true.  It's set to false when
01488   //     the event fires, before removing the request.  While this boolean is
01489   //     set, additional events are _not_ posted.
01490   // 4)  Destroy() guarantees that the dummy layout request is removed by
01491   //     calling RemoveDummyLayoutRequest(), since we may already have no
01492   //     reflow commands around and we revoke our events.
01493   nsCOMPtr<nsIRequest>          mDummyLayoutRequest;
01494 
01495   CantRenderReplacedElementEvent* mPostedReplaces;
01496   
01497   // used for list of posted events and attribute changes. To be done
01498   // after reflow.
01499   nsDOMEventRequest* mFirstDOMEventRequest;
01500   nsDOMEventRequest* mLastDOMEventRequest;
01501   nsAttributeChangeRequest* mFirstAttributeRequest;
01502   nsAttributeChangeRequest* mLastAttributeRequest;
01503   nsCallbackEventRequest* mFirstCallbackEventRequest;
01504   nsCallbackEventRequest* mLastCallbackEventRequest;
01505 
01506   PRPackedBool      mIsThemeSupportDisabled;  // Whether or not form controls should use nsITheme in this shell.
01507 
01508   PRPackedBool      mIsDocumentGone;      // We've been disconnected from the document.
01509   PRPackedBool      mPaintingSuppressed;  // For all documents we initially lock down painting.
01510                                           // We will refuse to paint the document until either
01511                                           // (a) our timer fires or (b) all frames are constructed.
01512   PRPackedBool      mShouldUnsuppressPainting;  // Indicates that it is safe to unlock painting once all pending
01513                                                 // reflows have been processed.
01514   nsCOMPtr<nsITimer> mPaintSuppressionTimer; // This timer controls painting suppression.  Until it fires
01515                                              // or all frames are constructed, we won't paint anything but
01516                                              // our <body> background and scrollbars.
01517 #define PAINTLOCK_EVENT_DELAY 250 // 250ms.  This is actually
01518                                   // pref-controlled, but we use this
01519                                   // value if we fail to get the pref
01520                                   // for any reason.
01521 
01522   static void sPaintSuppressionCallback(nsITimer* aTimer, void* aPresShell); // A callback for the timer.
01523 
01524   MOZ_TIMER_DECLARE(mReflowWatch)  // Used for measuring time spent in reflow
01525   MOZ_TIMER_DECLARE(mFrameCreationWatch)  // Used for measuring time spent in frame creation 
01526 
01527 #ifdef MOZ_REFLOW_PERF
01528   ReflowCountMgr * mReflowCountMgr;
01529 #endif
01530 
01531   // Array of document observers that actually need to observe
01532   // the PresShell.  See bug 400421.
01533   // XXXdholbert: The PresShell only passes on document-observer notifications
01534   // for AttributeChanged, ContentAppended, ContentInserted, and
01535   // ContentRemoved.  If PresShell has observers with non-null implementations
01536   // of any other observer functions, we need to pass on notifications for
01537   // those, too.
01538   nsAutoVoidArray mObservers;
01539 
01540 private:
01541 
01542   PRBool InZombieDocument(nsIContent *aContent);
01543   nsresult RetargetEventToParent(nsIView *aView, nsGUIEvent* aEvent, 
01544                                  nsEventStatus*  aEventStatus, PRBool aForceHandle,
01545                                  PRBool& aHandled, nsIContent *aZombieFocusedContent);
01546 
01547   void FreeDynamicStack();
01548 
01549   //helper funcs for event handling
01550   nsIFrame* GetCurrentEventFrame();
01551   void PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent);
01552   void PopCurrentEventInfo();
01553   nsresult HandleEventInternal(nsEvent* aEvent, nsIView* aView, PRUint32 aFlags, nsEventStatus *aStatus);
01554 
01555   //help funcs for resize events
01556   void CreateResizeEventTimer();
01557   void KillResizeEventTimer();
01558   void FireResizeEvent();
01559   static void sResizeEventCallback(nsITimer* aTimer, void* aPresShell) ;
01560   nsCOMPtr<nsITimer> mResizeEventTimer;
01561 
01562   typedef void (*nsPluginEnumCallback)(PresShell*, nsIContent*);
01563   void EnumeratePlugins(nsIDOMDocument *aDocument,
01564                         const nsString &aPluginTag,
01565                         nsPluginEnumCallback aCallback);
01566 };
01567 
01568 // Based on NS_DOCUMENT_NOTIFY_OBSERVERS
01569 #define NS_PRESSHELL_NOTIFY_OBSERVERS(func_, params_)                          \
01570   do {                                                                        \
01571     for (PRInt32 i_ = 0; i_ < mObservers.Count(); ++i_) {                     \
01572       nsIDocumentObserver* obs_ = NS_STATIC_CAST(nsIDocumentObserver*,        \
01573                                                  mObservers[i_]);             \
01574       obs_ -> func_ params_ ;                                                 \
01575     }                                                                         \
01576   } while (0)
01577 
01578 #ifdef PR_LOGGING
01579 PRLogModuleInfo* PresShell::gLog;
01580 #endif
01581 
01582 #ifdef NS_DEBUG
01583 static void
01584 VerifyStyleTree(nsPresContext* aPresContext, nsFrameManager* aFrameManager)
01585 {
01586   if (nsIFrameDebug::GetVerifyStyleTreeEnable()) {
01587     nsIFrame* rootFrame = aFrameManager->GetRootFrame();
01588     aFrameManager->DebugVerifyStyleTree(rootFrame);
01589   }
01590 }
01591 #define VERIFY_STYLE_TREE VerifyStyleTree(mPresContext, FrameManager())
01592 #else
01593 #define VERIFY_STYLE_TREE
01594 #endif
01595 
01596 static PRBool gVerifyReflowEnabled;
01597 
01598 PRBool
01599 nsIPresShell::GetVerifyReflowEnable()
01600 {
01601 #ifdef NS_DEBUG
01602   static PRBool firstTime = PR_TRUE;
01603   if (firstTime) {
01604     firstTime = PR_FALSE;
01605     char* flags = PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
01606     if (flags) {
01607       PRBool error = PR_FALSE;
01608 
01609       for (;;) {
01610         char* comma = PL_strchr(flags, ',');
01611         if (comma)
01612           *comma = '\0';
01613 
01614         PRBool found = PR_FALSE;
01615         const VerifyReflowFlags* flag = gFlags;
01616         const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
01617         while (flag < limit) {
01618           if (PL_strcasecmp(flag->name, flags) == 0) {
01619             gVerifyReflowFlags |= flag->bit;
01620             found = PR_TRUE;
01621             break;
01622           }
01623           ++flag;
01624         }
01625 
01626         if (! found)
01627           error = PR_TRUE;
01628 
01629         if (! comma)
01630           break;
01631 
01632         *comma = ',';
01633         flags = comma + 1;
01634       }
01635 
01636       if (error)
01637         ShowVerifyReflowFlags();
01638     }
01639 
01640     if (VERIFY_REFLOW_ON & gVerifyReflowFlags) {
01641       gVerifyReflowEnabled = PR_TRUE;
01642     }
01643     printf("Note: verifyreflow is %sabled",
01644            gVerifyReflowEnabled ? "en" : "dis");
01645     if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
01646       printf(" (noisy)");
01647     }
01648     if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
01649       printf(" (all)");
01650     }
01651     if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
01652       printf(" (show reflow commands)");
01653     }
01654     if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
01655       printf(" (noisy reflow commands)");
01656       if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
01657         printf(" (REALLY noisy reflow commands)");
01658       }
01659     }
01660     printf("\n");
01661   }
01662 #endif
01663   return gVerifyReflowEnabled;
01664 }
01665 
01666 void
01667 nsIPresShell::SetVerifyReflowEnable(PRBool aEnabled)
01668 {
01669   gVerifyReflowEnabled = aEnabled;
01670 }
01671 
01672 PRInt32
01673 nsIPresShell::GetVerifyReflowFlags()
01674 {
01675 #ifdef NS_DEBUG
01676   return gVerifyReflowFlags;
01677 #else
01678   return 0;
01679 #endif
01680 }
01681 
01682 void
01683 nsIPresShell_MOZILLA_1_8_BRANCH::AddWeakFrame(nsWeakFrame* aWeakFrame)
01684 {
01685   if (aWeakFrame->GetFrame()) {
01686     aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
01687   }
01688   aWeakFrame->SetPreviousWeakFrame(mWeakFrames);
01689   mWeakFrames = aWeakFrame;
01690 }
01691 
01692 void
01693 nsIPresShell_MOZILLA_1_8_BRANCH::RemoveWeakFrame(nsWeakFrame* aWeakFrame)
01694 {
01695   if (mWeakFrames == aWeakFrame) {
01696     mWeakFrames = aWeakFrame->GetPreviousWeakFrame();
01697     return;
01698   }
01699   nsWeakFrame* nextWeak = mWeakFrames;
01700   while (nextWeak && nextWeak->GetPreviousWeakFrame() != aWeakFrame) {
01701     nextWeak = nextWeak->GetPreviousWeakFrame();
01702   }
01703   if (nextWeak) {
01704     nextWeak->SetPreviousWeakFrame(aWeakFrame->GetPreviousWeakFrame());
01705   }
01706 }
01707 
01708 //----------------------------------------------------------------------
01709 
01710 nsresult
01711 NS_NewPresShell(nsIPresShell** aInstancePtrResult)
01712 {
01713   NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
01714   if (nsnull == aInstancePtrResult) {
01715     return NS_ERROR_NULL_POINTER;
01716   }
01717   PresShell* it = new PresShell();
01718   if (nsnull == it) {
01719     return NS_ERROR_OUT_OF_MEMORY;
01720   }
01721   return it->QueryInterface(NS_GET_IID(nsIPresShell),
01722                             (void **) aInstancePtrResult);
01723 }
01724 
01725 PresShell::PresShell()
01726 #ifdef IBMBIDI
01727   : mBidiLevel(BIDI_LEVEL_UNDEFINED)
01728 #endif
01729 {
01730   mIsAccessibilityActive = PR_FALSE;
01731   mSelection = nsnull;
01732 #ifdef MOZ_REFLOW_PERF
01733   mReflowCountMgr = new ReflowCountMgr();
01734   mReflowCountMgr->SetPresContext(mPresContext);
01735   mReflowCountMgr->SetPresShell(this);
01736 #endif
01737 #ifdef IBMBIDI
01738   mBidiLevel = BIDI_LEVEL_UNDEFINED;
01739 #endif
01740 #ifdef PR_LOGGING
01741   if (! gLog)
01742     gLog = PR_NewLogModule("PresShell");
01743 #endif
01744   mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES;
01745   mIsThemeSupportDisabled = PR_FALSE;
01746   mIsReleasingAnonymousContent = PR_FALSE;
01747 
01748   new (this) nsFrameManager();
01749 }
01750 
01751 NS_IMPL_ISUPPORTS9(PresShell, nsIPresShell, nsIPresShell_MOZILLA_1_8_BRANCH,
01752                    nsIPresShell_MOZILLA_1_8_BRANCH2, nsIDocumentObserver,
01753                    nsIViewObserver, nsISelectionController,
01754                    nsISelectionDisplay, nsIObserver, nsISupportsWeakReference)
01755 
01756 PresShell::~PresShell()
01757 {
01758   if (!mHaveShutDown) {
01759     NS_NOTREACHED("Someone did not call nsIPresShell::destroy");
01760     Destroy();
01761   }
01762 
01763   NS_ASSERTION(mCurrentEventContentStack.Count() == 0,
01764                "Huh, event content left on the stack in pres shell dtor!");
01765   NS_ASSERTION(mFirstDOMEventRequest == nsnull &&
01766                mLastDOMEventRequest == nsnull &&
01767                mFirstAttributeRequest == nsnull &&
01768                mLastAttributeRequest == nsnull &&
01769                mFirstCallbackEventRequest == nsnull &&
01770                mLastCallbackEventRequest == nsnull,
01771                "post-reflow queues not empty.  This means we're leaking");
01772  
01773   delete mStyleSet;
01774   delete mFrameConstructor;
01775 
01776   mCurrentEventContent = nsnull;
01777 
01778   // if we allocated any stack memory free it.
01779   FreeDynamicStack();
01780 
01781   NS_IF_RELEASE(mPresContext);
01782   NS_IF_RELEASE(mDocument);
01783   NS_IF_RELEASE(mSelection);
01784 }
01785 
01790 NS_IMETHODIMP
01791 PresShell::Init(nsIDocument* aDocument,
01792                 nsPresContext* aPresContext,
01793                 nsIViewManager* aViewManager,
01794                 nsStyleSet* aStyleSet,
01795                 nsCompatibility aCompatMode)
01796 {
01797   NS_PRECONDITION(nsnull != aDocument, "null ptr");
01798   NS_PRECONDITION(nsnull != aPresContext, "null ptr");
01799   NS_PRECONDITION(nsnull != aViewManager, "null ptr");
01800 
01801   if ((nsnull == aDocument) || (nsnull == aPresContext) ||
01802       (nsnull == aViewManager)) {
01803     return NS_ERROR_NULL_POINTER;
01804   }
01805   if (mDocument) {
01806     return NS_ERROR_ALREADY_INITIALIZED;
01807   }
01808 
01809   mDocument = aDocument;
01810   NS_ADDREF(mDocument);
01811   mViewManager = aViewManager;
01812 
01813   // Create our frame constructor.
01814   mFrameConstructor = new nsCSSFrameConstructor(mDocument, this);
01815   NS_ENSURE_TRUE(mFrameConstructor, NS_ERROR_OUT_OF_MEMORY);
01816 
01817   // The document viewer owns both view manager and pres shell.
01818   mViewManager->SetViewObserver(this);
01819 
01820   // Bind the context to the presentation shell.
01821   mPresContext = aPresContext;
01822   NS_ADDREF(mPresContext);
01823   aPresContext->SetShell(this);
01824 
01825   // Create our reflow command hashtable
01826   static PLDHashTableOps reflowCommandOps =
01827     {
01828       PL_DHashAllocTable,
01829       PL_DHashFreeTable,
01830       ReflowCommandHashGetKey,
01831       ReflowCommandHashHashKey,
01832       ReflowCommandHashMatchEntry,
01833       PL_DHashMoveEntryStub,
01834       PL_DHashClearEntryStub,
01835       PL_DHashFinalizeStub
01836     };
01837 
01838   if (!PL_DHashTableInit(&mReflowCommandTable, &reflowCommandOps,
01839                          nsnull, sizeof(ReflowCommandEntry), 16)) {
01840     mReflowCommandTable.ops = nsnull;
01841     return NS_ERROR_OUT_OF_MEMORY;
01842   }
01843   
01844   // Now we can initialize the style set.
01845   nsresult result = aStyleSet->Init(aPresContext);
01846   NS_ENSURE_SUCCESS(result, result);
01847 
01848   // From this point on, any time we return an error we need to make
01849   // sure to null out mStyleSet first, since an error return from this
01850   // method will cause the caller to delete the style set, so we don't
01851   // want to delete it in our destructor.
01852   mStyleSet = aStyleSet;
01853 
01854   // Set the compatibility mode after attaching the pres context and
01855   // style set, but before creating any frames.
01856   mPresContext->SetCompatibilityMode(aCompatMode);
01857 
01858   // setup the preference style rules (no forced reflow), and do it
01859   // before creating any frames.
01860   SetPreferenceStyleRules(PR_FALSE);
01861 
01862   result = CallCreateInstance(kFrameSelectionCID, &mSelection);
01863   if (NS_FAILED(result)) {
01864     mStyleSet = nsnull;
01865     return result;
01866   }
01867 
01868   // Create and initialize the frame manager
01869   result = FrameManager()->Init(this, mStyleSet);
01870   if (NS_FAILED(result)) {
01871     NS_WARNING("Frame manager initialization failed");
01872     mStyleSet = nsnull;
01873     return result;
01874   }
01875 
01876   result = mSelection->Init(this, nsnull);
01877   if (NS_FAILED(result)) {
01878     mStyleSet = nsnull;
01879     return result;
01880   }
01881   // Important: this has to happen after the selection has been set up
01882 #ifdef SHOW_CARET
01883   // make the caret
01884   nsresult  err = NS_NewCaret(getter_AddRefs(mCaret));
01885   if (NS_SUCCEEDED(err))
01886   {
01887     mCaret->Init(this);
01888   }
01889 
01890   //SetCaretEnabled(PR_TRUE);       // make it show in browser windows
01891 #endif  
01892   //set up selection to be displayed in document
01893   SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
01894   
01895   mEventQueueService = do_GetService(kEventQueueServiceCID, &result);
01896 
01897   if (!mEventQueueService) {
01898     NS_WARNING("couldn't get event queue service");
01899     mStyleSet = nsnull;
01900     return NS_ERROR_FAILURE;
01901   }
01902 
01903   if (gMaxRCProcessingTime == -1) {
01904     gMaxRCProcessingTime =
01905       nsContentUtils::GetIntPref("layout.reflow.timeslice",
01906                                  NS_MAX_REFLOW_TIME);
01907 
01908     gAsyncReflowDuringDocLoad =
01909       nsContentUtils::GetBoolPref("layout.reflow.async.duringDocLoad",
01910                                   PR_TRUE);
01911   }
01912 
01913   {
01914     nsCOMPtr<nsIObserverService> os =
01915       do_GetService("@mozilla.org/observer-service;1", &result);
01916     if (os) {
01917       os->AddObserver(this, NS_LINK_VISITED_EVENT_TOPIC, PR_FALSE);
01918 #ifdef MOZ_XUL
01919       os->AddObserver(this, "chrome-flush-skin-caches", PR_FALSE);
01920 #endif
01921     }
01922   }
01923 
01924   // cache the drag service so we can check it during reflows
01925   mDragService = do_GetService("@mozilla.org/widget/dragservice;1");
01926 
01927 #ifdef IBMBIDI
01928   mBidiKeyboard = do_GetService("@mozilla.org/widget/bidikeyboard;1");
01929 #endif
01930 
01931 #ifdef MOZ_REFLOW_PERF
01932     if (mReflowCountMgr) {
01933       PRBool paintFrameCounts =
01934         nsContentUtils::GetBoolPref("layout.reflow.showframecounts");
01935 
01936       PRBool dumpFrameCounts =
01937         nsContentUtils::GetBoolPref("layout.reflow.dumpframecounts");
01938 
01939       PRBool dumpFrameByFrameCounts =
01940         nsContentUtils::GetBoolPref("layout.reflow.dumpframebyframecounts");
01941 
01942       mReflowCountMgr->SetDumpFrameCounts(dumpFrameCounts);
01943       mReflowCountMgr->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts);
01944       mReflowCountMgr->SetPaintFrameCounts(paintFrameCounts);
01945     }
01946 #endif
01947 
01948   return NS_OK;
01949 }
01950 
01951 NS_IMETHODIMP
01952 PresShell::Destroy()
01953 {
01954 #ifdef MOZ_REFLOW_PERF
01955   DumpReflows();
01956   if (mReflowCountMgr) {
01957     delete mReflowCountMgr;
01958     mReflowCountMgr = nsnull;
01959   }
01960 #endif
01961 
01962   if (mHaveShutDown)
01963     return NS_OK;
01964 
01965   {
01966     nsCOMPtr<nsIObserverService> os =
01967       do_GetService("@mozilla.org/observer-service;1");
01968     if (os) {
01969       os->RemoveObserver(this, NS_LINK_VISITED_EVENT_TOPIC);
01970 #ifdef MOZ_XUL
01971       os->RemoveObserver(this, "chrome-flush-skin-caches");
01972 #endif
01973     }
01974   }
01975 
01976   // If our paint suppression timer is still active, kill it.
01977   if (mPaintSuppressionTimer) {
01978     mPaintSuppressionTimer->Cancel();
01979     mPaintSuppressionTimer = nsnull;
01980   }
01981 
01982   if (mCaret) {
01983     mCaret->Terminate();
01984     mCaret = nsnull;
01985   }
01986   
01987   // release our pref style sheet, if we have one still
01988   ClearPreferenceStyleRules();
01989 
01990   // free our table of anonymous content
01991   ReleaseAnonymousContent();
01992 
01993   mIsDestroying = PR_TRUE;
01994 
01995   // We can't release all the event content in
01996   // mCurrentEventContentStack here since there might be code on the
01997   // stack that will release the event content too. Double release
01998   // bad!
01999 
02000   // The frames will be torn down, so remove them from the current
02001   // event frame stack (since they'd be dangling references if we'd
02002   // leave them in) and null out the mCurrentEventFrame pointer as
02003   // well.
02004 
02005   mCurrentEventFrame = nsnull;
02006 
02007   PRInt32 i, count = mCurrentEventFrameStack.Count();
02008   for (i = 0; i < count; i++) {
02009     mCurrentEventFrameStack.ReplaceElementAt(nsnull, i);
02010   }
02011 
02012   if (mViewManager) {
02013     // Clear the view manager's weak pointer back to |this| in case it
02014     // was leaked.
02015     mViewManager->SetViewObserver(nsnull);
02016     mViewManager = nsnull;
02017   }
02018 
02019   mStyleSet->BeginShutdown(mPresContext);
02020 
02021   // This shell must be removed from the document before the frame
02022   // hierarchy is torn down to avoid finding deleted frames through
02023   // this presshell while the frames are being torn down
02024   if (mDocument) {
02025     mDocument->DeleteShell(this);
02026   }
02027 
02028   // Revoke pending events.  We need to do this and cancel reflow commands
02029   // before we destroy the frame manager, since apparently frame destruction
02030   // sometimes spins the event queue when plug-ins are involved(!).
02031   mPostedReplaces = nsnull;
02032   mReflowEventQueue = nsnull;
02033   nsCOMPtr<nsIEventQueue> eventQueue;
02034   mEventQueueService->GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
02035                                            getter_AddRefs(eventQueue));
02036   eventQueue->RevokeEvents(this);
02037 
02038   CancelAllReflowCommands();
02039 
02040   // Destroy the frame manager. This will destroy the frame hierarchy
02041   mFrameConstructor->WillDestroyFrameTree();
02042   FrameManager()->Destroy();
02043 
02044   NS_WARN_IF_FALSE(!mWeakFrames, "Weak frames alive after destroying FrameManager");
02045   while (mWeakFrames) {
02046     mWeakFrames->Clear(this);
02047   }
02048 
02049   // Let the style set do its cleanup.
02050   mStyleSet->Shutdown(mPresContext);
02051 
02052   if (mPresContext) {
02053     // Clear out the prescontext's property table -- since our frame tree is
02054     // now dead, we shouldn't be looking up any more properties in that table.
02055     // We want to do this before we call SetShell() on the prescontext, so
02056     // property destructors can usefully call GetPresShell() on the
02057     // prescontext.
02058     mPresContext->PropertyTable()->DeleteAllProperties();
02059 
02060     // We hold a reference to the pres context, and it holds a weak link back
02061     // to us. To avoid the pres context having a dangling reference, set its 
02062     // pres shell to NULL
02063     mPresContext->SetShell(nsnull);
02064 
02065     // Clear the link handler (weak reference) as well
02066     mPresContext->SetLinkHandler(nsnull);
02067   }
02068 
02069   if (mViewEventListener) {
02070     mViewEventListener->SetPresShell((nsIPresShell*)nsnull);
02071     NS_RELEASE(mViewEventListener);
02072   }
02073 
02074   RemoveDummyLayoutRequest();
02075   
02076   KillResizeEventTimer();
02077 
02078   // Now that mReflowCommandTable won't be accessed anymore, finish it
02079   if (mReflowCommandTable.ops) {
02080     PL_DHashTableFinish(&mReflowCommandTable);
02081   }
02082   
02083   mHaveShutDown = PR_TRUE;
02084 
02085   return NS_OK;
02086 }
02087 
02088                   // Dynamic stack memory allocation
02089 NS_IMETHODIMP
02090 PresShell::PushStackMemory()
02091 {
02092   if (!mStackArena) {
02093     mStackArena = new StackArena();
02094     if (!mStackArena)
02095       return NS_ERROR_OUT_OF_MEMORY;
02096   }
02097 
02098   return mStackArena->Push();
02099 }
02100 
02101 NS_IMETHODIMP
02102 PresShell::PopStackMemory()
02103 {
02104   NS_ENSURE_TRUE(mStackArena, NS_ERROR_UNEXPECTED);
02105 
02106   return mStackArena->Pop();
02107 }
02108 
02109 NS_IMETHODIMP
02110 PresShell::AllocateStackMemory(size_t aSize, void** aResult)
02111 {
02112   if (!mStackArena) {
02113     mStackArena = new StackArena();
02114     if (!mStackArena)
02115       return NS_ERROR_OUT_OF_MEMORY;
02116   }
02117 
02118   return mStackArena->Allocate(aSize, aResult);
02119 }
02120 
02121 void
02122 PresShell::FreeDynamicStack()
02123 {
02124   if (mStackArena) {
02125     delete mStackArena;
02126     mStackArena = nsnull;
02127   }
02128 }
02129  
02130 
02131 void
02132 PresShell::FreeFrame(size_t aSize, void* aPtr)
02133 {
02134   mFrameArena.FreeFrame(aSize, aPtr);
02135 }
02136 
02137 void*
02138 PresShell::AllocateFrame(size_t aSize)
02139 {
02140   return mFrameArena.AllocateFrame(aSize);
02141 }
02142 
02143 NS_IMETHODIMP
02144 PresShell::GetActiveAlternateStyleSheet(nsString& aSheetTitle)
02145 { // first non-html sheet in style set that has title
02146   if (mStyleSet) {
02147     PRInt32 count = mStyleSet->SheetCount(nsStyleSet::eDocSheet);
02148     PRInt32 index;
02149     NS_NAMED_LITERAL_STRING(textHtml, "text/html");
02150     for (index = 0; index < count; index++) {
02151       nsIStyleSheet* sheet = mStyleSet->StyleSheetAt(nsStyleSet::eDocSheet,
02152                                                      index);
02153       if (nsnull != sheet) {
02154         nsAutoString type;
02155         sheet->GetType(type);
02156         if (PR_FALSE == type.Equals(textHtml)) {
02157           nsAutoString title;
02158           sheet->GetTitle(title);
02159           if (!title.IsEmpty()) {
02160             aSheetTitle = title;
02161             index = count;  // stop looking
02162           }
02163         }
02164       }
02165     }
02166   }
02167   return NS_OK;
02168 }
02169 
02170 NS_IMETHODIMP
02171 PresShell::SelectAlternateStyleSheet(const nsString& aSheetTitle)
02172 {
02173   if (mDocument && mStyleSet) {
02174     mStyleSet->BeginUpdate();
02175     PRInt32 count = mDocument->GetNumberOfStyleSheets();
02176     PRInt32 index;
02177     NS_NAMED_LITERAL_STRING(textHtml,"text/html");
02178     for (index = 0; index < count; index++) {
02179       nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(index);
02180       PRBool complete;
02181       sheet->GetComplete(complete);
02182       if (complete) {
02183         nsAutoString type;
02184         sheet->GetType(type);
02185         if (!type.Equals(textHtml)) {
02186           nsAutoString title;
02187           sheet->GetTitle(title);
02188           if (!title.IsEmpty()) {
02189             if (title.Equals(aSheetTitle)) {
02190               mStyleSet->AddDocStyleSheet(sheet, mDocument);
02191             }
02192             else {
02193               mStyleSet->RemoveStyleSheet(nsStyleSet::eDocSheet, sheet);
02194             }
02195           }
02196         }
02197       }
02198     }
02199 
02200     mStyleSet->EndUpdate();
02201     ReconstructStyleData();
02202   }
02203   return NS_OK;
02204 }
02205 
02206 NS_IMETHODIMP
02207 PresShell::ListAlternateStyleSheets(nsStringArray& aTitleList)
02208 {
02209   // XXX should this be returning incomplete sheets?  Probably.
02210   if (mDocument) {
02211     PRInt32 count = mDocument->GetNumberOfStyleSheets();
02212     PRInt32 index;
02213     NS_NAMED_LITERAL_STRING(textHtml,"text/html");
02214     for (index = 0; index < count; index++) {
02215       nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(index);
02216       if (sheet) {
02217         nsAutoString type;
02218         sheet->GetType(type);
02219         if (PR_FALSE == type.Equals(textHtml)) {
02220           nsAutoString  title;
02221           sheet->GetTitle(title);
02222           if (!title.IsEmpty()) {
02223             if (-1 == aTitleList.IndexOf(title)) {
02224               aTitleList.AppendString(title);
02225             }
02226           }
02227         }
02228       }
02229     }
02230   }
02231   return NS_OK;
02232 }
02233 
02234 void
02235 nsIPresShell::SetAuthorStyleDisabled(PRBool aStyleDisabled)
02236 {
02237   if (aStyleDisabled != mStyleSet->GetAuthorStyleDisabled()) {
02238     mStyleSet->SetAuthorStyleDisabled(aStyleDisabled);
02239     ReconstructStyleData();
02240   }
02241 }
02242 
02243 PRBool
02244 nsIPresShell::GetAuthorStyleDisabled()
02245 {
02246   return mStyleSet->GetAuthorStyleDisabled();
02247 }
02248 
02249 NS_IMETHODIMP
02250 PresShell::SetPreferenceStyleRules(PRBool aForceReflow)
02251 {
02252   if (!mDocument) {
02253     return NS_ERROR_NULL_POINTER;
02254   }
02255 
02256   nsIScriptGlobalObject *globalObj = mDocument->GetScriptGlobalObject();
02257 
02258   // If the document doesn't have a global object there's no need to
02259   // notify its presshell about changes to preferences since the
02260   // document is in a state where it doesn't matter any more (see
02261   // DocumentViewerImpl::Close()).
02262 
02263   if (!globalObj) {
02264     return NS_ERROR_NULL_POINTER;
02265   } 
02266 
02267   NS_PRECONDITION(mPresContext, "presContext cannot be null");
02268   if (mPresContext) {
02269     nsresult result = NS_OK;
02270 
02271     // first, make sure this is not a chrome shell 
02272     nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
02273     if (container) {
02274       nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryInterface(container, &result));
02275       if (NS_SUCCEEDED(result) && docShell){
02276         PRInt32 docShellType;
02277         result = docShell->GetItemType(&docShellType);
02278         if (NS_SUCCEEDED(result)){
02279           if (nsIDocShellTreeItem::typeChrome == docShellType){
02280             return NS_OK;
02281           }
02282         }      
02283       }
02284     }
02285     if (NS_SUCCEEDED(result)) {
02286     
02287 #ifdef DEBUG_attinasi
02288       printf("Setting Preference Style Rules:\n");
02289 #endif
02290       // if here, we need to create rules for the prefs
02291       // - this includes the background-color, the text-color,
02292       //   the link color, the visited link color and the link-underlining
02293     
02294       // first clear any exising rules
02295       result = ClearPreferenceStyleRules();
02296       
02297       // now do the color rules
02298       if (NS_SUCCEEDED(result)) {
02299         result = SetPrefColorRules();
02300       }
02301 
02302       // now the link rules (must come after the color rules, or links will not be correct color!)
02303       // XXX - when there is both an override and agent pref stylesheet this won't matter,
02304       //       as the color rules will be overrides and the links rules will be agent
02305       if (NS_SUCCEEDED(result)) {
02306         result = SetPrefLinkRules();
02307       }
02308       if (NS_SUCCEEDED(result)) {
02309         result = SetPrefFocusRules();
02310       }
02311       if (NS_SUCCEEDED(result)) {
02312         result = SetPrefNoScriptRule();
02313       }
02314       if (NS_SUCCEEDED(result)) {
02315         result = SetPrefNoFramesRule();
02316       }
02317     }
02318 #ifdef DEBUG_attinasi
02319     printf( "Preference Style Rules set: error=%ld\n", (long)result);
02320 #endif    
02321 
02322     if (aForceReflow){
02323       mPresContext->ClearStyleDataAndReflow();
02324     }
02325 
02326     return result;
02327   }
02328 
02329   return NS_ERROR_NULL_POINTER;
02330 }
02331 
02332 nsresult PresShell::ClearPreferenceStyleRules(void)
02333 {
02334   nsresult result = NS_OK;
02335   if (mPrefStyleSheet) {
02336     NS_ASSERTION(mStyleSet, "null styleset entirely unexpected!");
02337     if (mStyleSet) {
02338       // remove the sheet from the styleset: 
02339       // - note that we have to check for success by comparing the count before and after...
02340 #ifdef NS_DEBUG
02341       PRInt32 numBefore = mStyleSet->SheetCount(nsStyleSet::eUserSheet);
02342       NS_ASSERTION(numBefore > 0, "no user stylesheets in styleset, but we have one!");
02343 #endif
02344       mStyleSet->RemoveStyleSheet(nsStyleSet::eUserSheet, mPrefStyleSheet);
02345 
02346 #ifdef DEBUG_attinasi
02347       NS_ASSERTION((numBefore - 1) == mStyleSet->GetNumberOfUserStyleSheets(),
02348                    "Pref stylesheet was not removed");
02349       printf("PrefStyleSheet removed\n");
02350 #endif
02351       // clear the sheet pointer: it is strictly historical now
02352       NS_RELEASE(mPrefStyleSheet);
02353     }
02354   }
02355   return result;
02356 }
02357 
02358 nsresult PresShell::CreatePreferenceStyleSheet(void)
02359 {
02360   NS_ASSERTION(!mPrefStyleSheet, "prefStyleSheet already exists");
02361   nsresult result = CallCreateInstance(kCSSStyleSheetCID, &mPrefStyleSheet);
02362   if (NS_SUCCEEDED(result)) {
02363     NS_ASSERTION(mPrefStyleSheet, "null but no error");
02364     nsCOMPtr<nsIURI> uri;
02365     result = NS_NewURI(getter_AddRefs(uri), "about:PreferenceStyleSheet", nsnull);
02366     if (NS_SUCCEEDED(result)) {
02367       NS_ASSERTION(uri, "null but no error");
02368       nsCOMPtr<nsICSSStyleSheet_MOZILLA_1_8_BRANCH> sheet =
02369         do_QueryInterface(mPrefStyleSheet);
02370       result = sheet->SetURIs18(uri, uri, uri);
02371       if (NS_SUCCEEDED(result)) {
02372         mPrefStyleSheet->SetComplete();
02373         nsCOMPtr<nsIDOMCSSStyleSheet> sheet(do_QueryInterface(mPrefStyleSheet));
02374         if (sheet) {
02375           PRUint32 index;
02376           result = sheet->InsertRule(NS_LITERAL_STRING("@namespace url(http://www.w3.org/1999/xhtml);"),
02377                                      0, &index);
02378           NS_ENSURE_SUCCESS(result, result);
02379         }
02380         mStyleSet->AppendStyleSheet(nsStyleSet::eUserSheet, mPrefStyleSheet);
02381       }
02382     }
02383   } else {
02384     result = NS_ERROR_OUT_OF_MEMORY;
02385   }
02386 
02387 #ifdef DEBUG_attinasi
02388   printf("CreatePrefStyleSheet completed: error=%ld\n",(long)result);
02389 #endif
02390 
02391   return result;
02392 }
02393 
02394 // XXX We want these after the @namespace rule.  Does order matter
02395 // for these rules, or can we call nsICSSStyleRule::StyleRuleCount()
02396 // and just "append"?
02397 static PRUint32 sInsertPrefSheetRulesAt = 1;
02398 
02399 nsresult PresShell::SetPrefColorRules(void)
02400 {
02401   NS_ASSERTION(mPresContext,"null prescontext not allowed");
02402   if (mPresContext) {
02403     nsresult result = NS_OK;
02404 
02405     // see if we need to create the rules first
02406     PRBool useDocColors =
02407       mPresContext->GetCachedBoolPref(kPresContext_UseDocumentColors);
02408     if (!useDocColors) {
02409 
02410 #ifdef DEBUG_attinasi
02411       printf(" - Creating rules for document colors\n");
02412 #endif
02413 
02414       // OK, not using document colors, so we have to force the user's colors via style rules
02415       if (!mPrefStyleSheet) {
02416         result = CreatePreferenceStyleSheet();
02417       }
02418       if (NS_SUCCEEDED(result)) {
02419         NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null");
02420 
02421         nscolor bgColor = mPresContext->DefaultBackgroundColor();
02422         nscolor textColor = mPresContext->DefaultColor();
02423 
02424         // get the DOM interface to the stylesheet
02425         nsCOMPtr<nsIDOMCSSStyleSheet> sheet(do_QueryInterface(mPrefStyleSheet,&result));
02426         if (NS_SUCCEEDED(result)) {
02427           PRUint32 index = 0;
02428           nsAutoString strColor, strBackgroundColor;
02429 
02430           // create a rule for background and foreground color and
02431           // add it to the style sheet              
02432           // - the rule is !important so it overrides all but author
02433           //   important rules (when put into an agent stylesheet) and 
02434           //   all (even author important) when put into an override stylesheet
02435 
02437           // - default colors: ':root {color:#RRGGBB !important;
02438           //                           background: #RRGGBB !important;}'
02439           ColorToString(textColor,strColor);
02440           ColorToString(bgColor,strBackgroundColor);
02441           result = sheet->InsertRule(NS_LITERAL_STRING(":root {color:") +
02442                                      strColor +
02443                                      NS_LITERAL_STRING(" !important; ") +
02444                                      NS_LITERAL_STRING("border-color: -moz-use-text-color !important; ") +
02445                                      NS_LITERAL_STRING("background:") +
02446                                      strBackgroundColor +
02447                                      NS_LITERAL_STRING(" !important; }"),
02448                                      sInsertPrefSheetRulesAt, &index);
02449           NS_ENSURE_SUCCESS(result, result);
02450 
02452           // - everything else inherits the color, and has transparent background
02453           result = sheet->InsertRule(NS_LITERAL_STRING("* {color: inherit !important; border-color: -moz-use-text-color !important; background: transparent !important;} "),
02454                                      sInsertPrefSheetRulesAt, &index);
02455         }
02456       }
02457     }
02458     return result;
02459   } else {
02460     return NS_ERROR_FAILURE;
02461   }
02462 }
02463 
02464 nsresult
02465 PresShell::SetPrefNoScriptRule()
02466 {
02467   nsresult rv = NS_OK;
02468 
02469   // also handle the case where print is done from print preview
02470   // see bug #342439 for more details
02471   PRBool scriptEnabled = mDocument->IsScriptEnabled() ||
02472     ((mPresContext->Type() == nsPresContext::eContext_PrintPreview || 
02473       mPresContext->Type() == nsPresContext::eContext_Print) &&
02474      NS_PTR_TO_INT32(mDocument->GetProperty(
02475                        nsLayoutAtoms::scriptEnabledBeforePrintPreview)));
02476 
02477   if (scriptEnabled) {
02478     if (!mPrefStyleSheet) {
02479       rv = CreatePreferenceStyleSheet();
02480       NS_ENSURE_SUCCESS(rv, rv);
02481     }
02482     // get the DOM interface to the stylesheet
02483     nsCOMPtr<nsIDOMCSSStyleSheet> sheet(do_QueryInterface(mPrefStyleSheet, &rv));
02484     NS_ENSURE_SUCCESS(rv, rv);
02485     PRUint32 index = 0;
02486     rv = sheet->InsertRule(NS_LITERAL_STRING("noscript{display:none!important}"),
02487                            sInsertPrefSheetRulesAt, &index);
02488   }
02489 
02490   return rv;
02491 }
02492 
02493 nsresult PresShell::SetPrefNoFramesRule(void)
02494 {
02495   NS_ASSERTION(mPresContext,"null prescontext not allowed");
02496   if (!mPresContext) {
02497     return NS_ERROR_FAILURE;
02498   }
02499 
02500   nsresult rv = NS_OK;
02501   
02502   if (!mPrefStyleSheet) {
02503     rv = CreatePreferenceStyleSheet();
02504     NS_ENSURE_SUCCESS(rv, rv);
02505   }
02506   
02507   NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null");
02508   
02509   // get the DOM interface to the stylesheet
02510   nsCOMPtr<nsIDOMCSSStyleSheet> sheet(do_QueryInterface(mPrefStyleSheet, &rv));
02511   NS_ENSURE_SUCCESS(rv, rv);
02512 
02513   PRBool allowSubframes = PR_TRUE;
02514   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();     
02515   nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
02516   if (docShell) {
02517     docShell->GetAllowSubframes(&allowSubframes);
02518   }
02519   if (!allowSubframes) {
02520     PRUint32 index = 0;
02521     rv = sheet->InsertRule(NS_LITERAL_STRING("noframes{display:block}"),
02522                            sInsertPrefSheetRulesAt, &index);
02523     NS_ENSURE_SUCCESS(rv, rv);
02524     rv = sheet->InsertRule(NS_LITERAL_STRING("frame, frameset, iframe {display:none!important}"),
02525                            sInsertPrefSheetRulesAt, &index);
02526   }
02527   return rv;
02528 }
02529   
02530 nsresult PresShell::SetPrefLinkRules(void)
02531 {
02532   NS_ASSERTION(mPresContext,"null prescontext not allowed");
02533   if (!mPresContext) {
02534     return NS_ERROR_FAILURE;
02535   }
02536 
02537   nsresult rv = NS_OK;
02538   
02539   if (!mPrefStyleSheet) {
02540     rv = CreatePreferenceStyleSheet();
02541     NS_ENSURE_SUCCESS(rv, rv);
02542   }
02543   
02544   NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null");
02545   
02546   // get the DOM interface to the stylesheet
02547   nsCOMPtr<nsIDOMCSSStyleSheet> sheet(do_QueryInterface(mPrefStyleSheet, &rv));
02548   NS_ENSURE_SUCCESS(rv, rv);
02549   
02550   // support default link colors: 
02551   //   this means the link colors need to be overridable, 
02552   //   which they are if we put them in the agent stylesheet,
02553   //   though if using an override sheet this will cause authors grief still
02554   //   In the agent stylesheet, they are !important when we are ignoring document colors
02555   
02556   nscolor linkColor(mPresContext->DefaultLinkColor());
02557   nscolor activeColor(mPresContext->DefaultActiveLinkColor());
02558   nscolor visitedColor(mPresContext->DefaultVisitedLinkColor());
02559   
02560   PRBool useDocColors =
02561     mPresContext->GetCachedBoolPref(kPresContext_UseDocumentColors);
02562   NS_NAMED_LITERAL_STRING(notImportantStr, "}");
02563   NS_NAMED_LITERAL_STRING(importantStr, "!important}");
02564   const nsAString& ruleClose = useDocColors ? notImportantStr : importantStr;
02565   PRUint32 index = 0;
02566   nsAutoString strColor;
02567 
02568   // insert a rule to color links: '*|*:link {color: #RRGGBB [!important];}'
02569   ColorToString(linkColor, strColor);
02570   rv = sheet->InsertRule(NS_LITERAL_STRING("*|*:link{color:") +
02571                          strColor + ruleClose,
02572                          sInsertPrefSheetRulesAt, &index);
02573   NS_ENSURE_SUCCESS(rv, rv);
02574 
02575   // - visited links: '*|*:visited {color: #RRGGBB [!important];}'
02576   ColorToString(visitedColor, strColor);
02577   rv = sheet->InsertRule(NS_LITERAL_STRING("*|*:visited{color:") +
02578                          strColor + ruleClose,
02579                          sInsertPrefSheetRulesAt, &index);
02580   NS_ENSURE_SUCCESS(rv, rv);
02581 
02582   // - active links: '*|*:-moz-any-link:active {color: #RRGGBB [!important];}'
02583   ColorToString(activeColor, strColor);
02584   rv = sheet->InsertRule(NS_LITERAL_STRING("*|*:-moz-any-link:active{color:") +
02585                          strColor + ruleClose,
02586                          sInsertPrefSheetRulesAt, &index);
02587   NS_ENSURE_SUCCESS(rv, rv);
02588 
02589   PRBool underlineLinks =
02590     mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
02591 
02592   if (underlineLinks) {
02593     // create a rule to make underlining happen
02594     //  '*|*:-moz-any-link {text-decoration:[underline|none];}'
02595     // no need for important, we want these to be overridable
02596     // NOTE: these must go in the agent stylesheet or they cannot be
02597     //       overridden by authors
02598     rv = sheet->InsertRule(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:underline}"),
02599                            sInsertPrefSheetRulesAt, &index);
02600   } else {
02601     rv = sheet->InsertRule(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:none}"),
02602                            sInsertPrefSheetRulesAt, &index);
02603   }
02604 
02605   return rv;          
02606 }
02607 
02608 nsresult PresShell::SetPrefFocusRules(void)
02609 {
02610   NS_ASSERTION(mPresContext,"null prescontext not allowed");
02611   nsresult result = NS_OK;
02612 
02613   if (!mPresContext)
02614     result = NS_ERROR_FAILURE;
02615 
02616   if (NS_SUCCEEDED(result) && !mPrefStyleSheet)
02617     result = CreatePreferenceStyleSheet();
02618 
02619   if (NS_SUCCEEDED(result)) {
02620     NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null");
02621 
02622     // get the DOM interface to the stylesheet
02623     nsCOMPtr<nsIDOMCSSStyleSheet> sheet(do_QueryInterface(mPrefStyleSheet,&result));
02624     if (NS_SUCCEEDED(result)) {
02625       if (mPresContext->GetUseFocusColors()) {
02626         nscolor focusBackground(mPresContext->FocusBackgroundColor());
02627         nscolor focusText(mPresContext->FocusTextColor());
02628 
02629         // insert a rule to make focus the preferred color
02630         PRUint32 index = 0;
02631         nsAutoString strRule, strColor;
02632 
02634         // - focus: '*:focus
02635         ColorToString(focusText,strColor);
02636         strRule.AppendLiteral("*:focus,*:focus>font {color: ");
02637         strRule.Append(strColor);
02638         strRule.AppendLiteral(" !important; background-color: ");
02639         ColorToString(focusBackground,strColor);
02640         strRule.Append(strColor);
02641         strRule.AppendLiteral(" !important; } ");
02642         // insert the rules
02643         result = sheet->InsertRule(strRule, sInsertPrefSheetRulesAt, &index);
02644       }
02645       PRUint8 focusRingWidth = mPresContext->FocusRingWidth();
02646       PRBool focusRingOnAnything = mPresContext->GetFocusRingOnAnything();
02647 
02648       if ((NS_SUCCEEDED(result) && focusRingWidth != 1 && focusRingWidth <= 4 ) || focusRingOnAnything) {
02649         PRUint32 index = 0;
02650         nsAutoString strRule;
02651         if (!focusRingOnAnything)
02652           strRule.AppendLiteral("*|*:link:focus, *|*:visited");    // If we only want focus rings on the normal things like links
02653         strRule.AppendLiteral(":focus {outline: ");     // For example 3px dotted WindowText (maximum 4)
02654         strRule.AppendInt(focusRingWidth);
02655         strRule.AppendLiteral("px dotted WindowText !important; } ");     // For example 3px dotted WindowText
02656         // insert the rules
02657         result = sheet->InsertRule(strRule, sInsertPrefSheetRulesAt, &index);
02658         NS_ENSURE_SUCCESS(result, result);
02659         if (focusRingWidth != 1) {
02660           // If the focus ring width is different from the default, fix buttons with rings
02661           strRule.AssignLiteral("button::-moz-focus-inner, input[type=\"reset\"]::-moz-focus-inner,");
02662           strRule.AppendLiteral("input[type=\"button\"]::-moz-focus-inner, ");
02663           strRule.AppendLiteral("input[type=\"submit\"]::-moz-focus-inner { padding: 1px 2px 1px 2px; border: ");
02664           strRule.AppendInt(focusRingWidth);
02665           strRule.AppendLiteral("px dotted transparent !important; } ");
02666           result = sheet->InsertRule(strRule, sInsertPrefSheetRulesAt, &index);
02667           NS_ENSURE_SUCCESS(result, result);
02668           
02669           strRule.AssignLiteral("button:focus::-moz-focus-inner, input[type=\"reset\"]:focus::-moz-focus-inner,");
02670           strRule.AppendLiteral("input[type=\"button\"]:focus::-moz-focus-inner, input[type=\"submit\"]:focus::-moz-focus-inner {");
02671           strRule.AppendLiteral("border-color: ButtonText !important; }");
02672           result = sheet->InsertRule(strRule, sInsertPrefSheetRulesAt, &index);
02673         }
02674       }
02675     }
02676   }
02677   return result;
02678 }
02679 
02680 
02681 NS_IMETHODIMP
02682 PresShell::SetDisplaySelection(PRInt16 aToggle)
02683 {
02684   return mSelection->SetDisplaySelection(aToggle);
02685 }
02686 
02687 NS_IMETHODIMP
02688 PresShell::GetDisplaySelection(PRInt16 *aToggle)
02689 {
02690   return mSelection->GetDisplaySelection(aToggle);
02691 }
02692 
02693 NS_IMETHODIMP
02694 PresShell::GetSelection(SelectionType aType, nsISelection **aSelection)
02695 {
02696   if (!aSelection || !mSelection)
02697     return NS_ERROR_NULL_POINTER;
02698   return mSelection->GetSelection(aType, aSelection);
02699 }
02700 
02701 NS_IMETHODIMP
02702 PresShell::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion, PRBool aIsSynchronous)
02703 {
02704   if (!mSelection)
02705     return NS_ERROR_NULL_POINTER;
02706 
02707   return mSelection->ScrollSelectionIntoView(aType, aRegion, aIsSynchronous);
02708 }
02709 
02710 NS_IMETHODIMP
02711 PresShell::RepaintSelection(SelectionType aType)
02712 {
02713   if (!mSelection)
02714     return NS_ERROR_NULL_POINTER;
02715 
02716   return mSelection->RepaintSelection(mPresContext, aType);
02717 }
02718 
02719 // Make shell be a document observer
02720 NS_IMETHODIMP
02721 PresShell::BeginObservingDocument()
02722 {
02723   if (mDocument && !mIsDestroying) {
02724     mDocument->AddObserver(this);
02725     if (mIsDocumentGone) {
02726       NS_WARNING("Adding a presshell that was disconnected from the document "
02727                  "as a document observer?  Sounds wrong...");
02728       mIsDocumentGone = PR_FALSE;
02729     }
02730   }
02731   return NS_OK;
02732 }
02733 
02734 // Make shell stop being a document observer
02735 NS_IMETHODIMP
02736 PresShell::EndObservingDocument()
02737 {
02738   // XXXbz do we need to tell the frame constructor that the document
02739   // is gone, perhaps?  Except for printing it's NOT gone, sometimes.
02740   mIsDocumentGone = PR_TRUE;
02741   if (mDocument) {
02742     mDocument->RemoveObserver(this);
02743   }
02744   if (mSelection){
02745     nsCOMPtr<nsISelection> domselection;
02746     nsresult result;
02747     result = mSelection->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domselection));
02748     if (NS_FAILED(result))
02749       return result;
02750     if (!domselection)
02751       return NS_ERROR_UNEXPECTED;
02752     mSelection->ShutDown();
02753   }
02754 
02755   return NS_OK;
02756 }
02757 
02758 #ifdef DEBUG_kipp
02759 char* nsPresShell_ReflowStackPointerTop;
02760 #endif
02761 
02762 static void CheckForFocus(nsPIDOMWindow* aOurWindow,
02763                           nsIFocusController* aFocusController,
02764                           nsIDocument* aDocument)
02765 {
02766   NS_ASSERTION(aOurWindow->IsOuterWindow(),
02767                "Uh, our window has to be an outer window!");
02768 
02769   // Now that we have a root frame, we can set focus on the presshell.
02770   // We do this only if our DOM window is currently focused or is an
02771   // an ancestor of a previously focused window.
02772 
02773   if (!aFocusController)
02774     return;
02775 
02776   nsCOMPtr<nsIDOMWindowInternal> ourWin = do_QueryInterface(aOurWindow);
02777 
02778   nsCOMPtr<nsIDOMWindowInternal> focusedWindow;
02779   aFocusController->GetFocusedWindow(getter_AddRefs(focusedWindow));
02780   if (!focusedWindow) {
02781     // This should never really happen, but if it does, assume
02782     // we can focus ourself to keep the window from being keydead.
02783     focusedWindow = ourWin;
02784   }
02785 
02786   // Walk up the document chain, starting with focusedWindow's document.
02787   // We stop walking when we find a document that has a null DOMWindow
02788   // (meaning that the DOMWindow has a new document now) or find ourWin
02789   // as the document's window.  We also stop if we hit aDocument, since
02790   // that means there is a child document which loaded before us that's
02791   // already been given focus.
02792 
02793   nsCOMPtr<nsIDOMDocument> focusedDOMDoc;
02794   focusedWindow->GetDocument(getter_AddRefs(focusedDOMDoc));
02795 
02796   nsCOMPtr<nsIDocument> curDoc = do_QueryInterface(focusedDOMDoc);
02797   if (!curDoc) {
02798     // This can happen if the previously focused DOM window has been
02799     // unhooked from its document during document teardown.  We don't
02800     // really have any other information to help us determine where
02801     // focusedWindow fits into the DOM window hierarchy.  For now, we'll
02802     // go ahead and allow this window to take focus, so that something
02803     // ends up focused.
02804 
02805     curDoc = aDocument;
02806   }
02807 
02808   while (curDoc) {
02809     nsPIDOMWindow *curWin = curDoc->GetWindow();
02810 
02811     if (!curWin || curWin == ourWin)
02812       break;
02813 
02814     curDoc = curDoc->GetParentDocument();
02815     if (curDoc == aDocument)
02816       return;
02817   }
02818 
02819   if (!curDoc) {
02820     // We reached the top of the document chain, and did not encounter ourWin
02821     // or a windowless document. So, focus should be unaffected by this
02822     // document load.
02823     return;
02824   }
02825 
02826   PRBool active;
02827   aFocusController->GetActive(&active);
02828   if (active)
02829     ourWin->Focus();
02830 
02831   // We need to ensure that the focus controller is updated, since it may be
02832   // suppressed when this function is called.
02833   aFocusController->SetFocusedWindow(ourWin);
02834 }
02835 
02836 static nsIFrame*
02837 GetRootScrollFrame(nsIFrame* aRootFrame) {
02838   // Ensure root frame is a viewport frame
02839   if (aRootFrame && nsLayoutAtoms::viewportFrame == aRootFrame->GetType()) {
02840     nsIFrame* theFrame = aRootFrame->GetFirstChild(nsnull);
02841     if (theFrame && nsLayoutAtoms::scrollFrame == theFrame->GetType()) {
02842       return theFrame;
02843     }
02844   }
02845 
02846   return nsnull;
02847 }
02848 
02849 NS_IMETHODIMP
02850 PresShell::GetDidInitialReflow(PRBool *aDidInitialReflow)
02851 {
02852   if (!aDidInitialReflow)
02853     return NS_ERROR_FAILURE;
02854 
02855   *aDidInitialReflow = mDidInitialReflow;
02856 
02857   return NS_OK;
02858 }
02859 
02860 NS_IMETHODIMP
02861 PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
02862 {
02863   mDidInitialReflow = PR_TRUE;
02864 
02865 #ifdef NS_DEBUG
02866   if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
02867     if (mDocument) {
02868       nsIURI *uri = mDocument->GetDocumentURI();
02869       if (uri) {
02870         nsCAutoString url;
02871         uri->GetSpec(url);
02872         printf("*** PresShell::InitialReflow (this=%p, url='%s')\n", (void*)this, url.get());
02873       }
02874     }
02875   }
02876 #endif
02877 
02878   if (mCaret)
02879     mCaret->EraseCaret();
02880 
02881   NS_ASSERTION(mViewManager, "Should have view manager");
02882   // Painting should be suppressed for the initial reflow, so this won't
02883   // really do anything right now, but it will be useful when we
02884   // start batching widget changes
02885   mViewManager->BeginUpdateViewBatch();
02886 
02887   WillCauseReflow();
02888 
02889   if (mPresContext) {
02890     nsRect r(0, 0, aWidth, aHeight);
02891     mPresContext->SetVisibleArea(r);
02892   }
02893 
02894   nsIContent *root = mDocument ? mDocument->GetRootContent() : nsnull;
02895 
02896   // Get the root frame from the frame manager
02897   nsIFrame* rootFrame = FrameManager()->GetRootFrame();
02898   
02899   if (root) {
02900     MOZ_TIMER_DEBUGLOG(("Reset and start: Frame Creation: PresShell::InitialReflow(), this=%p\n",
02901                         (void*)this));
02902     MOZ_TIMER_RESET(mFrameCreationWatch);
02903     MOZ_TIMER_START(mFrameCreationWatch);
02904 
02905     if (!rootFrame) {
02906       // Have style sheet processor construct a frame for the
02907       // precursors to the root content object's frame
02908       mFrameConstructor->ConstructRootFrame(root, &rootFrame);
02909       FrameManager()->SetRootFrame(rootFrame);
02910     }
02911 
02912     // Have the style sheet processor construct frame for the root
02913     // content object down
02914     mFrameConstructor->ContentInserted(nsnull, nsnull, root, 0,
02915                                        nsnull, PR_FALSE);
02916     VERIFY_STYLE_TREE;
02917     MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::InitialReflow(), this=%p\n",
02918                         (void*)this));
02919     MOZ_TIMER_STOP(mFrameCreationWatch);
02920 
02921     NS_ENSURE_STATE(!mHaveShutDown);
02922 
02923     // Run the XBL binding constructors for any new frames we've constructed
02924     // Hold a strong ref to ourselves while we do that
02925     nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
02926     mDocument->BindingManager()->ProcessAttachedQueue();
02927 
02928     // Constructors may have killed us too
02929     NS_ENSURE_STATE(!mHaveShutDown);
02930 
02931     // Now flush out pending restyles before we actually reflow, in
02932     // case XBL constructors changed styles somewhere.
02933     mFrameConstructor->ProcessPendingRestyles();
02934 
02935     // And that might have run _more_ XBL constructors
02936     NS_ENSURE_STATE(!mHaveShutDown);
02937 
02938     // Now reget the root frame, since all that script might have affected it
02939     // somehow.  Currently that can't happen, as long as mHaveShutDown is
02940     // false, but let's not rely on that.
02941     rootFrame = FrameManager()->GetRootFrame();
02942   }
02943 
02944   if (rootFrame) {
02945     MOZ_TIMER_DEBUGLOG(("Reset and start: Reflow: PresShell::InitialReflow(), this=%p\n",
02946                         (void*)this));
02947     MOZ_TIMER_RESET(mReflowWatch);
02948     MOZ_TIMER_START(mReflowWatch);
02949     // Kick off a top-down reflow
02950     NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
02951                  ("enter nsPresShell::InitialReflow: %d,%d", aWidth, aHeight));
02952 #ifdef NS_DEBUG
02953     if (nsIFrameDebug::GetVerifyTreeEnable()) {
02954       nsIFrameDebug*  frameDebug;
02955 
02956       if (NS_SUCCEEDED(rootFrame->QueryInterface(NS_GET_IID(nsIFrameDebug),
02957                                                 (void**)&frameDebug))) {
02958         frameDebug->VerifyTree();
02959       }
02960     }
02961 #endif
02962 #ifdef DEBUG_kipp
02963     nsPresShell_ReflowStackPointerTop = (char*) &aWidth;
02964 #endif
02965     nsRect                bounds = mPresContext->GetVisibleArea();
02966     nsSize                maxSize(bounds.width, bounds.height);
02967     nsHTMLReflowMetrics   desiredSize(nsnull);
02968     nsReflowStatus        status;
02969     nsIRenderingContext*  rcx = nsnull;
02970 
02971     nsresult rv=CreateRenderingContext(rootFrame, &rcx);
02972     if (NS_FAILED(rv)) return rv;
02973 
02974     mIsReflowing = PR_TRUE;
02975 
02976     nsHTMLReflowState reflowState(mPresContext, rootFrame,
02977                                   eReflowReason_Initial, rcx, maxSize);
02978     rootFrame->WillReflow(mPresContext);
02979     nsContainerFrame::PositionFrameView(rootFrame);
02980     rootFrame->Reflow(mPresContext, desiredSize, reflowState, status);
02981     rootFrame->SetSize(nsSize(desiredSize.width, desiredSize.height));
02982     mPresContext->SetVisibleArea(nsRect(0,0,desiredSize.width,desiredSize.height));
02983 
02984     nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, rootFrame, rootFrame->GetView(),
02985                                                nsnull);
02986     rootFrame->DidReflow(mPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
02987       
02988 #ifdef NS_DEBUG
02989     if (nsIFrameDebug::GetVerifyTreeEnable()) {
02990       nsIFrameDebug*  frameDebug;
02991 
02992       if (NS_SUCCEEDED(rootFrame->QueryInterface(NS_GET_IID(nsIFrameDebug),
02993                                                  (void**)&frameDebug))) {
02994         frameDebug->VerifyTree();
02995       }
02996     }
02997 #endif
02998     VERIFY_STYLE_TREE;
02999     NS_IF_RELEASE(rcx);
03000     NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::InitialReflow"));
03001     MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::InitialReflow(), this=%p\n", (void*)this));
03002     MOZ_TIMER_STOP(mReflowWatch);
03003 
03004     mIsReflowing = PR_FALSE;
03005   }
03006 
03007   DidCauseReflow();
03008   DidDoReflow();
03009 
03010   mViewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
03011 
03012   if (mViewManager && mCaret && !mViewEventListener) {
03013     nsIScrollableView* scrollingView = nsnull;
03014     mViewManager->GetRootScrollableView(&scrollingView);
03015 
03016     if (scrollingView) {
03017       mViewEventListener = new PresShellViewEventListener;
03018 
03019       if (!mViewEventListener)
03020         return NS_ERROR_OUT_OF_MEMORY;
03021 
03022       NS_ADDREF(mViewEventListener);
03023       mViewEventListener->SetPresShell(this);
03024       scrollingView->AddScrollPositionListener((nsIScrollPositionListener *)mViewEventListener);
03025       mViewManager->AddCompositeListener((nsICompositeListener *)mViewEventListener);
03026     }
03027   }
03028 
03029   // For printing, we just immediately unsuppress.
03030   if (!mPresContext->IsPaginated()) {
03031     // Kick off a one-shot timer based off our pref value.  When this timer
03032     // fires, if painting is still locked down, then we will go ahead and
03033     // trigger a full invalidate and allow painting to proceed normally.
03034     mPaintingSuppressed = PR_TRUE;
03035     mPaintSuppressionTimer = do_CreateInstance("@mozilla.org/timer;1");
03036     if (!mPaintSuppressionTimer)
03037       // Uh-oh.  We must be out of memory.  No point in keeping painting locked down.
03038       mPaintingSuppressed = PR_FALSE;
03039     else {
03040       // Initialize the timer.
03041 
03042       // Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value.
03043       PRInt32 delay =
03044         nsContentUtils::GetIntPref("nglayout.initialpaint.delay",
03045                                    PAINTLOCK_EVENT_DELAY);
03046 
03047       nsCOMPtr<nsITimerInternal> ti = do_QueryInterface(mPaintSuppressionTimer);
03048       ti->SetIdle(PR_FALSE);
03049 
03050       mPaintSuppressionTimer->InitWithFuncCallback(sPaintSuppressionCallback,
03051                                                    this, delay, 
03052                                                    nsITimer::TYPE_ONE_SHOT);
03053     }
03054   }
03055 
03056   return NS_OK; //XXX this needs to be real. MMP
03057 }
03058 
03059 void
03060 PresShell::sPaintSuppressionCallback(nsITimer *aTimer, void* aPresShell)
03061 {
03062   PresShell* self = NS_STATIC_CAST(PresShell*, aPresShell);
03063   if (self)
03064     self->UnsuppressPainting();
03065 }
03066 
03067 NS_IMETHODIMP
03068 PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
03069 {
03070   PRBool firstReflow = PR_FALSE;
03071 
03072   NS_ASSERTION(mViewManager, "Must have view manager");
03073   mViewManager->BeginUpdateViewBatch();
03074 
03075   WillCauseReflow();
03076 
03077   if (mCaret)
03078     mCaret->EraseCaret();
03079 
03080   // If we don't have a root frame yet, that means we haven't had our initial
03081   // reflow... If that's the case, and aWidth or aHeight is unconstrained,
03082   // ignore them altogether.
03083   nsIFrame* rootFrame = FrameManager()->GetRootFrame();
03084 
03085   if (!rootFrame &&
03086       (aWidth == NS_UNCONSTRAINEDSIZE || aHeight == NS_UNCONSTRAINEDSIZE)) {
03087     return NS_ERROR_NOT_AVAILABLE;
03088   }
03089   
03090   if (mPresContext) {
03091     nsRect r(0, 0, aWidth, aHeight);
03092     mPresContext->SetVisibleArea(r);
03093   }
03094 
03095   if (rootFrame) {
03096     // Kick off a top-down reflow
03097     NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
03098                  ("enter nsPresShell::ResizeReflow: %d,%d", aWidth, aHeight));
03099 #ifdef NS_DEBUG
03100     if (nsIFrameDebug::GetVerifyTreeEnable()) {
03101       nsIFrameDebug*  frameDebug;
03102 
03103       if (NS_SUCCEEDED(rootFrame->QueryInterface(NS_GET_IID(nsIFrameDebug),
03104                                                  (void**)&frameDebug))) {
03105         frameDebug->VerifyTree();
03106       }
03107     }
03108 #endif
03109 #ifdef DEBUG_kipp
03110     nsPresShell_ReflowStackPointerTop = (char*) &aWidth;
03111 #endif
03112     nsRect                bounds = mPresContext->GetVisibleArea();
03113     nsSize                maxSize(bounds.width, bounds.height);
03114     nsHTMLReflowMetrics   desiredSize(nsnull);
03115     nsReflowStatus        status;
03116     nsIRenderingContext*  rcx = nsnull;
03117 
03118     nsresult rv=CreateRenderingContext(rootFrame, &rcx);
03119     if (NS_FAILED(rv)) return rv;
03120 
03121     nsHTMLReflowState reflowState(mPresContext, rootFrame,
03122                                   eReflowReason_Resize, rcx, maxSize);
03123 
03124     rootFrame->WillReflow(mPresContext);
03125     nsContainerFrame::PositionFrameView(rootFrame);
03126     rootFrame->Reflow(mPresContext, desiredSize, reflowState, status);
03127     rootFrame->SetSize(nsSize(desiredSize.width, desiredSize.height));
03128     mPresContext->SetVisibleArea(nsRect(0,0,desiredSize.width,desiredSize.height));
03129 
03130     nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, rootFrame, rootFrame->GetView(),
03131                                                nsnull);
03132     rootFrame->DidReflow(mPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
03133 #ifdef NS_DEBUG
03134     if (nsIFrameDebug::GetVerifyTreeEnable()) {
03135       nsIFrameDebug*  frameDebug;
03136 
03137       if (NS_SUCCEEDED(rootFrame->QueryInterface(NS_GET_IID(nsIFrameDebug),
03138                                                  (void**)&frameDebug))) {
03139         frameDebug->VerifyTree();
03140       }
03141     }
03142 #endif
03143     VERIFY_STYLE_TREE;
03144     NS_IF_RELEASE(rcx);
03145     NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::ResizeReflow"));
03146 
03147     // XXX if debugging then we should assert that the cache is empty
03148   } else {
03149     firstReflow = PR_TRUE;
03150 #ifdef NOISY
03151     printf("PresShell::ResizeReflow: null root frame\n");
03152 #endif
03153   }
03154   DidCauseReflow();
03155   // if the proper flag is set, VerifyReflow now
03156 #ifdef NS_DEBUG
03157   if (GetVerifyReflowEnable() && (VERIFY_REFLOW_DURING_RESIZE_REFLOW & gVerifyReflowFlags))
03158   {
03159     mInVerifyReflow = PR_TRUE;
03160     /*PRBool ok = */VerifyIncrementalReflow();
03161     mInVerifyReflow = PR_FALSE;
03162   }
03163 #endif
03164   
03165   DidDoReflow();
03166 
03167   mViewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
03168 
03169   if (!firstReflow) {
03170     //Set resize event timer
03171     CreateResizeEventTimer();
03172   }
03173   
03174   return NS_OK; //XXX this needs to be real. MMP
03175 }
03176 
03177 #define RESIZE_EVENT_DELAY 200
03178 
03179 void
03180 PresShell::CreateResizeEventTimer ()
03181 {
03182   KillResizeEventTimer();
03183 
03184   if (mIsDocumentGone)
03185     return;
03186 
03187   mResizeEventTimer = do_CreateInstance("@mozilla.org/timer;1");
03188   if (mResizeEventTimer) {
03189     mResizeEventTimer->InitWithFuncCallback(sResizeEventCallback, this, RESIZE_EVENT_DELAY, 
03190                                             nsITimer::TYPE_ONE_SHOT);
03191   }
03192 }
03193 
03194 void
03195 PresShell::KillResizeEventTimer()
03196 {
03197   if(mResizeEventTimer) {
03198     mResizeEventTimer->Cancel();
03199     mResizeEventTimer = nsnull;
03200   }
03201 }
03202 
03203 void
03204 PresShell::sResizeEventCallback(nsITimer *aTimer, void* aPresShell)
03205 {
03206   PresShell* self = NS_STATIC_CAST(PresShell*, aPresShell);
03207   if (self) {
03208     self->FireResizeEvent();  
03209   }
03210 }
03211 
03212 void
03213 PresShell::FireResizeEvent()
03214 {
03215   if (mIsDocumentGone)
03216     return;
03217 
03218   //Send resize event from here.
03219   nsEvent event(PR_TRUE, NS_RESIZE_EVENT);
03220   nsEventStatus status = nsEventStatus_eIgnore;
03221 
03222   nsCOMPtr<nsIScriptGlobalObject> globalObj = mDocument->GetScriptGlobalObject();
03223   if (globalObj) {
03224     globalObj->HandleDOMEvent(mPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
03225   }
03226 }
03227 
03228 NS_IMETHODIMP
03229 PresShell::SetIgnoreFrameDestruction(PRBool aIgnore)
03230 {
03231   mIgnoreFrameDestruction = aIgnore;
03232   return NS_OK;
03233 }
03234 
03235 NS_IMETHODIMP
03236 PresShell::NotifyDestroyingFrame(nsIFrame* aFrame)
03237 {
03238   if (!mIgnoreFrameDestruction) {
03239     mFrameConstructor->NotifyDestroyingFrame(aFrame);
03240 
03241     // Cancel any pending reflow commands targeted at this frame
03242     CancelReflowCommandInternal(aFrame, nsnull);
03243 
03244     DequeuePostedEventFor(aFrame);
03245     
03246     // Notify the frame manager
03247     FrameManager()->NotifyDestroyingFrame(aFrame);
03248 
03249     // Remove frame properties
03250     mPresContext->PropertyTable()->DeleteAllPropertiesFor(aFrame);
03251   }
03252 
03253   return NS_OK;
03254 }
03255 
03256 // note that this can return a null caret, but NS_OK
03257 NS_IMETHODIMP PresShell::GetCaret(nsICaret **outCaret)
03258 {
03259   NS_ENSURE_ARG_POINTER(outCaret);
03260   
03261   *outCaret = mCaret;
03262   NS_IF_ADDREF(*outCaret);
03263   return NS_OK;
03264 }
03265 
03266 NS_IMETHODIMP PresShell::SetCaretEnabled(PRBool aInEnable)
03267 {
03268   nsresult result = NS_OK;
03269   PRBool   oldEnabled = mCaretEnabled;
03270 
03271   mCaretEnabled = aInEnable;
03272 
03273   if (mCaret && (mCaretEnabled != oldEnabled))
03274   {
03275 /*  Don't change the caret's selection here! This was an evil side-effect of SetCaretEnabled()
03276     nsCOMPtr<nsIDOMSelection> domSel;
03277     if (NS_SUCCEEDED(GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel))) && domSel)
03278       mCaret->SetCaretDOMSelection(domSel);
03279 */
03280     result = mCaret->SetCaretVisible(mCaretEnabled);
03281   }
03282 
03283   return result;
03284 }
03285 
03286 NS_IMETHODIMP PresShell::SetCaretReadOnly(PRBool aReadOnly)
03287 {
03288   if (mCaret)
03289     mCaret->SetCaretReadOnly(aReadOnly);
03290   return NS_OK;
03291 }
03292 
03293 NS_IMETHODIMP PresShell::GetCaretEnabled(PRBool *aOutEnabled)
03294 {
03295   NS_ENSURE_ARG_POINTER(aOutEnabled);
03296   *aOutEnabled = mCaretEnabled;
03297   return NS_OK;
03298 }
03299 
03300 NS_IMETHODIMP PresShell::SetCaretVisibilityDuringSelection(PRBool aVisibility)
03301 {
03302   if (mCaret)
03303     mCaret->SetVisibilityDuringSelection(aVisibility);
03304   return NS_OK;
03305 }
03306 
03307 NS_IMETHODIMP PresShell::SetSelectionFlags(PRInt16 aInEnable)
03308 {
03309   mSelectionFlags = aInEnable;
03310   return NS_OK;
03311 }
03312 
03313 NS_IMETHODIMP PresShell::GetSelectionFlags(PRInt16 *aOutEnable)
03314 {
03315   if (!aOutEnable)
03316     return NS_ERROR_INVALID_ARG;
03317   *aOutEnable = mSelectionFlags;
03318   return NS_OK;
03319 }
03320 
03321 //implementation of nsISelectionController
03322 
03323 NS_IMETHODIMP 
03324 PresShell::CharacterMove(PRBool aForward, PRBool aExtend)
03325 {
03326   return mSelection->CharacterMove(aForward, aExtend);  
03327 }
03328 
03329 NS_IMETHODIMP 
03330 PresShell::WordMove(PRBool aForward, PRBool aExtend)
03331 {
03332   return mSelection->WordMove(aForward, aExtend);  
03333 }
03334 
03335 NS_IMETHODIMP 
03336 PresShell::LineMove(PRBool aForward, PRBool aExtend)
03337 {
03338   nsresult result = mSelection->LineMove(aForward, aExtend);  
03339 // if we cant go down/up any more we must then move caret completely to 
03340 // end/beginning respectively.
03341   if (NS_FAILED(result)) 
03342     result = CompleteMove(aForward,aExtend);
03343   return result;
03344 }
03345 
03346 NS_IMETHODIMP 
03347 PresShell::IntraLineMove(PRBool aForward, PRBool aExtend)
03348 {
03349   return mSelection->IntraLineMove(aForward, aExtend);  
03350 }
03351 
03352 
03353 
03354 NS_IMETHODIMP 
03355 PresShell::PageMove(PRBool aForward, PRBool aExtend)
03356 {
03357   nsresult result;
03358   nsIViewManager* viewManager = GetViewManager();
03359   nsIScrollableView *scrollableView;
03360   if (!viewManager) 
03361     return NS_ERROR_UNEXPECTED;
03362   result = viewManager->GetRootScrollableView(&scrollableView);
03363   if (NS_FAILED(result)) 
03364     return result;
03365   if (!scrollableView) 
03366     return NS_ERROR_UNEXPECTED;
03367   nsIView *scrolledView;
03368   result = scrollableView->GetScrolledView(scrolledView);
03369   mSelection->CommonPageMove(aForward, aExtend, scrollableView, mSelection);
03370   // do ScrollSelectionIntoView()
03371   return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_FOCUS_REGION, PR_TRUE);
03372 }
03373 
03374 
03375 
03376 NS_IMETHODIMP 
03377 PresShell::ScrollPage(PRBool aForward)
03378 {
03379   nsIScrollableView* scrollView = GetViewToScroll(nsLayoutUtils::eVertical);
03380   if (scrollView) {
03381     scrollView->ScrollByPages(0, aForward ? 1 : -1);
03382   }
03383   return NS_OK;
03384 }
03385 
03386 NS_IMETHODIMP
03387 PresShell::ScrollLine(PRBool aForward)
03388 {
03389   nsIScrollableView* scrollView = GetViewToScroll(nsLayoutUtils::eVertical);
03390   if (scrollView) {
03391 #ifdef MOZ_WIDGET_COCOA
03392     // Emulate the Mac IE behavior of scrolling a minimum of 2 lines
03393     // rather than 1.  This vastly improves scrolling speed.
03394     scrollView->ScrollByLines(0, aForward ? 2 : -2);
03395 #else
03396     scrollView->ScrollByLines(0, aForward ? 1 : -1);
03397 #endif
03398       
03399 //NEW FOR LINES    
03400     // force the update to happen now, otherwise multiple scrolls can
03401     // occur before the update is processed. (bug #7354)
03402 
03403   // I'd use Composite here, but it doesn't always work.
03404     // vm->Composite();
03405     nsIViewManager* viewManager = GetViewManager();
03406     if (viewManager) {
03407       viewManager->ForceUpdate();
03408     }
03409   }
03410   return NS_OK;
03411 }
03412 
03413 NS_IMETHODIMP
03414 PresShell::ScrollHorizontal(PRBool aLeft)
03415 {
03416   nsIScrollableView* scrollView = GetViewToScroll(nsLayoutUtils::eHorizontal);
03417   if (scrollView) {
03418     scrollView->ScrollByLines(aLeft ? -1 : 1, 0);
03419 //NEW FOR LINES    
03420     // force the update to happen now, otherwise multiple scrolls can
03421     // occur before the update is processed. (bug #7354)
03422 
03423   // I'd use Composite here, but it doesn't always work.
03424     // vm->Composite();
03425     nsIViewManager* viewManager = GetViewManager();
03426     if (viewManager) {
03427       viewManager->ForceUpdate();
03428     }
03429   }
03430   return NS_OK;
03431 }
03432 
03433 NS_IMETHODIMP
03434 PresShell::CompleteScroll(PRBool aForward)
03435 {
03436   nsIScrollableView* scrollView = GetViewToScroll(nsLayoutUtils::eVertical);
03437   if (scrollView) {
03438     scrollView->ScrollByWhole(!aForward);//TRUE = top, aForward TRUE=bottom
03439   }
03440   return NS_OK;
03441 }
03442 
03443 NS_IMETHODIMP
03444 PresShell::CompleteMove(PRBool aForward, PRBool aExtend)
03445 {
03446   nsIScrollableView *scrollableView;
03447   if (!mViewManager) 
03448     return NS_ERROR_UNEXPECTED;
03449   nsresult result = mViewManager->GetRootScrollableView(&scrollableView);
03450   if (NS_FAILED(result)) 
03451     return result;
03452   if (!scrollableView) 
03453     return NS_ERROR_UNEXPECTED;
03454   nsIView *scrolledView;
03455   result = scrollableView->GetScrolledView(scrolledView);
03456   // get a frame
03457   nsIFrame *frame = (nsIFrame*)scrolledView->GetClientData();
03458   if (!frame)
03459     return NS_ERROR_FAILURE;
03460   //we need to get to the area frame.
03461   nsIAtom* frameType;
03462   do 
03463   {
03464     frameType = frame->GetType();
03465     if (frameType != nsLayoutAtoms::areaFrame)
03466     {
03467       frame = frame->GetFirstChild(nsnull);
03468       if (!frame)
03469         break;
03470     }
03471   }while(frameType != nsLayoutAtoms::areaFrame);
03472   
03473   if (!frame)
03474     return NS_ERROR_FAILURE; //could not find an area frame.
03475 
03476   nsPeekOffsetStruct pos = frame->GetExtremeCaretPosition(!aForward);
03477 
03478   // we 'prefer left' (i.e. prefer the beginning of the next line)
03479   // iff we're moving to the end of the content
03480   pos.mPreferLeft = aForward;
03481   
03482   mSelection->HandleClick(pos.mResultContent ,pos.mContentOffset ,pos.mContentOffset/*End*/ ,aExtend, PR_FALSE, pos.mPreferLeft);
03483   return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_FOCUS_REGION, PR_TRUE);
03484 }
03485 
03486 NS_IMETHODIMP 
03487 PresShell::SelectAll()
03488 {
03489   return mSelection->SelectAll();
03490 }
03491 
03492 NS_IMETHODIMP
03493 PresShell::CheckVisibility(nsIDOMNode *node, PRInt16 startOffset, PRInt16 EndOffset, PRBool *_retval)
03494 {
03495   if (!node || startOffset>EndOffset || !_retval || startOffset<0 || EndOffset<0)
03496     return NS_ERROR_INVALID_ARG;
03497   *_retval = PR_FALSE; //initialize return parameter
03498   nsCOMPtr<nsIContent> content(do_QueryInterface(node));
03499   if (!content)
03500     return NS_ERROR_FAILURE;
03501   nsIFrame *frame;
03502   nsresult result = GetPrimaryFrameFor(content,&frame);
03503   if (NS_FAILED(result)) //failure is taken as a no.
03504     return result;
03505   if (!frame) //no frame to look at so it must not be visible
03506     return NS_OK;  
03507   //start process now to go through all frames to find startOffset. then check chars after that to see 
03508   //if anything until EndOffset is visible.
03509   PRBool finished = PR_FALSE;
03510   frame->CheckVisibility(mPresContext,startOffset,EndOffset,PR_TRUE,&finished, _retval);
03511   return NS_OK;//dont worry about other return val
03512 }
03513 
03514 //end implementations nsISelectionController
03515 
03516 
03517 static void UpdateViewProperties(nsPresContext* aPresContext, nsIViewManager* aVM,
03518                                  nsIView* aView) {
03519   nsIViewManager* thisVM = aView->GetViewManager();
03520   if (thisVM != aVM) {
03521     return;
03522   }
03523 
03524   nsIFrame* frame = NS_STATIC_CAST(nsIFrame*, aView->GetClientData());
03525   if (frame) {
03526     nsContainerFrame::SyncFrameViewProperties(aPresContext, frame, nsnull, aView);
03527   }
03528 
03529   for (nsIView* child = aView->GetFirstChild(); child;
03530        child = child->GetNextSibling()) {
03531     UpdateViewProperties(aPresContext, aVM, child);
03532   }
03533 }
03534 
03535 NS_IMETHODIMP
03536 PresShell::StyleChangeReflow()
03537 {
03538 
03539   WillCauseReflow();
03540 
03541   nsIFrame* rootFrame = FrameManager()->GetRootFrame();
03542   if (rootFrame) {
03543     // Kick off a top-down reflow
03544     NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
03545                  ("enter nsPresShell::StyleChangeReflow"));
03546 #ifdef NS_DEBUG
03547     if (nsIFrameDebug::GetVerifyTreeEnable()) {
03548       nsIFrameDebug*  frameDebug;
03549 
03550       if (NS_SUCCEEDED(rootFrame->QueryInterface(NS_GET_IID(nsIFrameDebug),
03551                                                  (void**)&frameDebug))) {
03552         frameDebug->VerifyTree();
03553       }
03554     }
03555 #endif
03556     nsRect                bounds = mPresContext->GetVisibleArea();
03557     nsSize                maxSize(bounds.width, bounds.height);
03558     nsHTMLReflowMetrics   desiredSize(nsnull);
03559     nsReflowStatus        status;
03560     nsIRenderingContext*  rcx = nsnull;
03561 
03562     nsresult rv=CreateRenderingContext(rootFrame, &rcx);
03563     if (NS_FAILED(rv)) return rv;
03564 
03565     nsHTMLReflowState reflowState(mPresContext, rootFrame,
03566                                   eReflowReason_StyleChange, rcx, maxSize);
03567 
03568     rootFrame->WillReflow(mPresContext);
03569     nsContainerFrame::PositionFrameView(rootFrame);
03570     rootFrame->Reflow(mPresContext, desiredSize, reflowState, status);
03571     rootFrame->SetSize(nsSize(desiredSize.width, desiredSize.height));
03572     mPresContext->SetVisibleArea(nsRect(0,0,desiredSize.width,desiredSize.height));
03573     nsIView* view = rootFrame->GetView();
03574     nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, rootFrame, view,
03575                                                nsnull);
03576     rootFrame->DidReflow(mPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
03577 #ifdef NS_DEBUG
03578     if (nsIFrameDebug::GetVerifyTreeEnable()) {
03579       nsIFrameDebug*  frameDebug;
03580 
03581       if (NS_SUCCEEDED(rootFrame->QueryInterface(NS_GET_IID(nsIFrameDebug),
03582                                                  (void**)&frameDebug))) {
03583         frameDebug->VerifyTree();
03584       }
03585     }
03586 #endif
03587     VERIFY_STYLE_TREE;
03588     NS_IF_RELEASE(rcx);
03589     NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::StyleChangeReflow"));
03590     
03591     // The following two calls are needed to make sure we reacquire any needed
03592     // style structs that were cleared by the caller
03593 
03594     // Update properties of all views to reflect style changes
03595     UpdateViewProperties(mPresContext, mViewManager, view);
03596 
03597     // Repaint everything just to be sure
03598     mViewManager->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
03599   }
03600 
03601   DidCauseReflow();
03602   DidDoReflow();
03603 
03604   return NS_OK; //XXX this needs to be real. MMP
03605 }
03606 
03607 nsIFrame*
03608 nsIPresShell::GetRootFrame() const
03609 {
03610   return FrameManager()->GetRootFrame();
03611 }
03612 
03613 NS_IMETHODIMP
03614 PresShell::GetPageSequenceFrame(nsIPageSequenceFrame** aResult) const
03615 {
03616   NS_PRECONDITION(nsnull != aResult, "null ptr");
03617   if (nsnull == aResult) {
03618     return NS_ERROR_NULL_POINTER;
03619   }
03620 
03621   *aResult = nsnull;
03622   nsIFrame* frame = mFrameConstructor->GetPageSequenceFrame();
03623   if (frame) {
03624     CallQueryInterface(frame, aResult);
03625   }
03626   return *aResult ? NS_OK : NS_ERROR_FAILURE;
03627 }
03628 
03629 void
03630 PresShell::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
03631 {
03632 #ifdef DEBUG
03633   mUpdateCount++;
03634 #endif
03635   mFrameConstructor->BeginUpdate();
03636 
03637   if (aUpdateType & UPDATE_STYLE)
03638     mStyleSet->BeginUpdate();
03639 }
03640 
03641 void
03642 PresShell::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
03643 {
03644 #ifdef DEBUG
03645   NS_PRECONDITION(0 != mUpdateCount, "too many EndUpdate's");
03646   --mUpdateCount;
03647 #endif
03648 
03649   if (aUpdateType & UPDATE_STYLE) {
03650     mStyleSet->EndUpdate();
03651     if (mStylesHaveChanged)
03652       ReconstructStyleData();
03653   }
03654 
03655   mFrameConstructor->EndUpdate();
03656 }
03657 
03658 void
03659 PresShell::BeginLoad(nsIDocument *aDocument)
03660 {  
03661 #ifdef MOZ_PERF_METRICS
03662   // Reset style resolution stopwatch maintained by style set
03663   MOZ_TIMER_DEBUGLOG(("Reset: Style Resolution: PresShell::BeginLoad(), this=%p\n", (void*)this));
03664 #endif  
03665   mDocumentLoading = PR_TRUE;
03666 }
03667 
03668 void
03669 PresShell::EndLoad(nsIDocument *aDocument)
03670 {
03671 
03672   // Restore frame state for the root scroll frame
03673   nsIFrame* rootFrame = FrameManager()->GetRootFrame();
03674   nsCOMPtr<nsILayoutHistoryState> historyState =
03675     aDocument->GetLayoutHistoryState();
03676   // Make sure we don't reenter reflow via the sync paint that happens while
03677   // we're scrolling to our restored position.  Entering reflow for the
03678   // scrollable frame will cause it to reenter ScrollToRestoredPosition(), and
03679   // it'll get all confused.
03680   ++mChangeNestCount;
03681 
03682   if (rootFrame && historyState) {
03683     nsIFrame* scrollFrame = GetRootScrollFrame(rootFrame);
03684     if (scrollFrame) {
03685       nsIScrollableFrame* scrollableFrame;
03686       CallQueryInterface(scrollFrame, &scrollableFrame);
03687       if (scrollableFrame) {
03688         FrameManager()->RestoreFrameStateFor(scrollFrame, historyState,
03689                                              nsIStatefulFrame::eDocumentScrollState);
03690         scrollableFrame->ScrollToRestoredPosition();
03691       }
03692     }
03693   }
03694 
03695   --mChangeNestCount;
03696   
03697 #ifdef MOZ_PERF_METRICS
03698   // Dump reflow, style resolution and frame construction times here.
03699   MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::EndLoad(), this=%p\n", this));
03700   MOZ_TIMER_STOP(mReflowWatch);
03701   MOZ_TIMER_LOG(("Reflow time (this=%p): ", this));
03702   MOZ_TIMER_PRINT(mReflowWatch);  
03703 
03704   MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::EndLoad(), this=%p\n", this));
03705   MOZ_TIMER_STOP(mFrameCreationWatch);
03706   MOZ_TIMER_LOG(("Frame construction plus style resolution time (this=%p): ", this));
03707   MOZ_TIMER_PRINT(mFrameCreationWatch);
03708 
03709   // Print style resolution stopwatch maintained by style set
03710   MOZ_TIMER_DEBUGLOG(("Stop: Style Resolution: PresShell::EndLoad(), this=%p\n", this));
03711 #endif  
03712   mDocumentLoading = PR_FALSE;
03713 }
03714 
03715 // aReflowCommand is considered to be already in the queue if the
03716 // frame it targets is targeted by a pre-existing reflow command in
03717 // the queue.
03718 PRBool
03719 PresShell::AlreadyInQueue(nsHTMLReflowCommand* aReflowCommand)
03720 {
03721   if (!mReflowCommandTable.ops) {
03722     // We're already destroyed
03723     NS_ERROR("We really shouldn't be posting reflow commands here");
03724   }
03725 
03726   ReflowCommandEntry* e =
03727     NS_STATIC_CAST(ReflowCommandEntry*,
03728                    PL_DHashTableOperate(&mReflowCommandTable, aReflowCommand,
03729                                         PL_DHASH_ADD));
03730 
03731   if (!e) {
03732     // We lie no matter what we say here
03733     return PR_FALSE;
03734   }
03735 
03736   // We're using the stub ClearEntry, which zeros out entries, so a
03737   // non-null mCommand means we're in the queue already.
03738   if (e->mCommand) {
03739 #ifdef DEBUG
03740     if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
03741       printf("*** PresShell::AlreadyInQueue(): Discarding reflow command: this=%p\n", (void*)this);
03742       aReflowCommand->List(stdout);
03743     }
03744 #endif
03745     return PR_TRUE;
03746   }
03747 
03748   e->mCommand = aReflowCommand;
03749   return PR_FALSE;
03750 }
03751 
03752 NS_IMETHODIMP
03753 PresShell::AppendReflowCommand(nsIFrame*    aTargetFrame,
03754                                nsReflowType aReflowType,
03755                                nsIAtom*     aChildListName)
03756 {
03757   // If we've not yet done the initial reflow, then don't bother
03758   // enqueuing a reflow command yet.
03759   if (! mDidInitialReflow)
03760     return NS_OK;
03761 
03762   // If we're already destroying, don't bother with this either.
03763   if (mIsDestroying)
03764     return NS_OK;
03765 
03766 #ifdef DEBUG
03767   //printf("gShellCounter: %d\n", gShellCounter++);
03768   if (mInVerifyReflow) {
03769     return NS_OK;
03770   }
03771 #endif
03772 
03773   nsHTMLReflowCommand* command = new nsHTMLReflowCommand(aTargetFrame,
03774                                                          aReflowType,
03775                                                          aChildListName);
03776   if (!command) {
03777     return NS_ERROR_OUT_OF_MEMORY;
03778   }
03779   
03780 #ifdef DEBUG
03781   if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
03782     printf("\nPresShell@%p: adding reflow command\n", (void*)this);
03783     command->List(stdout);
03784     if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
03785       printf("Current content model:\n");
03786       nsIContent *rootContent = mDocument->GetRootContent();
03787       if (rootContent) {
03788         rootContent->List(stdout, 0);
03789       }
03790     }
03791   }  
03792 #endif
03793 
03794   // Add the reflow command to the queue
03795   nsresult rv = NS_OK;
03796   if (!AlreadyInQueue(command)) {
03797     if (mReflowCommands.AppendElement(command)) {
03798       ReflowCommandAdded(command);
03799     } else {
03800       // Drop this command.... we're out of memory
03801       PL_DHashTableOperate(&mReflowCommandTable, command,
03802                            PL_DHASH_REMOVE);
03803       delete command;
03804       rv = NS_ERROR_OUT_OF_MEMORY;
03805     }
03806   }
03807   else {
03808     // We're not going to process this reflow command.
03809     delete command;
03810   }
03811 
03812   // For async reflow during doc load, post a reflow event if we are not batching reflow commands.
03813   // For sync reflow during doc load, post a reflow event if we are not batching reflow commands
03814   // and the document is not loading.
03815   if ((gAsyncReflowDuringDocLoad && !mBatchReflows) ||
03816       (!gAsyncReflowDuringDocLoad && !mBatchReflows && !mDocumentLoading)) {
03817     // If we're in the middle of a drag, process it right away (needed for mac,
03818     // might as well do it on all platforms just to keep the code paths the same).
03819     if ( !IsDragInProgress() )
03820       PostReflowEvent();
03821   }
03822 
03823   return rv;
03824 }
03825 
03826 
03827 //
03828 // IsDragInProgress
03829 //
03830 // Ask the drag service if we're in the middle of a drag
03831 //
03832 PRBool
03833 PresShell :: IsDragInProgress ( ) const
03834 {
03835   PRBool dragInProgress = PR_FALSE;
03836   if ( mDragService ) {
03837     nsCOMPtr<nsIDragSession> session;
03838     mDragService->GetCurrentSession ( getter_AddRefs(session) );
03839     if ( session )
03840       dragInProgress = PR_TRUE;
03841   }
03842   
03843   return dragInProgress;
03844 
03845 } // IsDragInProgress
03846 
03847 nsIScrollableView*
03848 PresShell::GetViewToScroll(nsLayoutUtils::Direction aDirection)
03849 {
03850   nsCOMPtr<nsIEventStateManager> esm = mPresContext->EventStateManager();
03851   nsIScrollableView* scrollView = nsnull;
03852   nsCOMPtr<nsIContent> focusedContent;
03853   esm->GetFocusedContent(getter_AddRefs(focusedContent));
03854   if (!focusedContent && mSelection) {
03855     nsCOMPtr<nsISelection> domSelection;
03856     mSelection->GetSelection(nsISelectionController::SELECTION_NORMAL,
03857                              getter_AddRefs(domSelection));
03858     if (domSelection) {
03859       nsCOMPtr<nsIDOMNode> focusedNode;
03860       domSelection->GetFocusNode(getter_AddRefs(focusedNode));
03861       focusedContent = do_QueryInterface(focusedNode);
03862     }
03863   }
03864   if (focusedContent) {
03865     nsIFrame* startFrame = nsnull;
03866     GetPrimaryFrameFor(focusedContent, &startFrame);
03867     if (startFrame) {
03868       nsCOMPtr<nsIScrollableViewProvider> svp = do_QueryInterface(startFrame);
03869       // If this very frame provides a scroll view, start there instead of frame's
03870       // closest view, because the scroll view may be inside a child frame.
03871       // For example, this happens in the case of overflow:scroll.
03872       // In that case we still use GetNearestScrollingView() because
03873       // we need a scrolling view that matches aDirection.
03874       nsIScrollableView* sv;
03875       nsIView* startView = svp && (sv = svp->GetScrollableView()) ? sv->View() : startFrame->GetClosestView();
03876       NS_ASSERTION(startView, "No view to start searching for scrollable view from");
03877       scrollView = nsLayoutUtils::GetNearestScrollingView(startView, aDirection);
03878     }
03879   }
03880   if (!scrollView) {
03881     nsIViewManager* viewManager = GetViewManager();
03882     if (viewManager) {
03883       viewManager->GetRootScrollableView(&scrollView);
03884     }
03885   }
03886   return scrollView;
03887 }
03888 
03889 NS_IMETHODIMP
03890 PresShell::CancelReflowCommandInternal(nsIFrame*     aTargetFrame, 
03891                                        nsReflowType* aCmdType,
03892                                        PRBool        aProcessDummyLayoutRequest)
03893 {
03894   PRInt32 i, n = mReflowCommands.Count();
03895   for (i = 0; i < n; i++) {
03896     nsHTMLReflowCommand* rc = (nsHTMLReflowCommand*) mReflowCommands.ElementAt(i);
03897     if (rc && rc->GetTarget() == aTargetFrame &&
03898         (!aCmdType || rc->Type() == *aCmdType)) {
03899 #ifdef DEBUG
03900       if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
03901         printf("PresShell: removing rc=%p for frame ", (void*)rc);
03902         nsFrame::ListTag(stdout, aTargetFrame);
03903         printf("\n");
03904       }
03905 #endif
03906       mReflowCommands.RemoveElementAt(i);
03907       ReflowCommandRemoved(rc);
03908       delete rc;
03909       n--;
03910       i--;
03911     }
03912   }
03913 
03914   if (aProcessDummyLayoutRequest) {
03915     DoneRemovingReflowCommands();
03916   }
03917 
03918   return NS_OK;
03919 }
03920 
03921 NS_IMETHODIMP
03922 PresShell::CancelReflowCommand(nsIFrame*     aTargetFrame, 
03923                                nsReflowType* aCmdType)
03924 {
03925   return CancelReflowCommandInternal(aTargetFrame, aCmdType);
03926 }
03927 
03928 
03929 NS_IMETHODIMP
03930 PresShell::CancelAllReflowCommands()
03931 {
03932   PRInt32 n = mReflowCommands.Count();
03933   nsHTMLReflowCommand* rc;
03934   PRInt32 i;
03935   for (i = 0; i < n; i++) {
03936     rc = NS_STATIC_CAST(nsHTMLReflowCommand*, mReflowCommands.ElementAt(i));
03937     ReflowCommandRemoved(rc);
03938     delete rc;
03939   }
03940   NS_ASSERTION(n == mReflowCommands.Count(),"reflow command list changed during cancel!");
03941   mReflowCommands.Clear();
03942 
03943   DoneRemovingReflowCommands();
03944 
03945   return NS_OK;
03946 }
03947 
03948 #ifdef ACCESSIBILITY
03949 void nsIPresShell::InvalidateAccessibleSubtree(nsIContent *aContent)
03950 {
03951   if (mIsAccessibilityActive) {
03952     nsCOMPtr<nsIAccessibilityService> accService = 
03953       do_GetService("@mozilla.org/accessibilityService;1");
03954     if (accService) {
03955       accService->InvalidateSubtreeFor(this, aContent,
03956                                        nsIAccessibleEvent::EVENT_REORDER);
03957     }
03958   }
03959 }
03960 #endif
03961 
03962 NS_IMETHODIMP
03963 PresShell::RecreateFramesFor(nsIContent* aContent)
03964 {
03965   NS_ENSURE_TRUE(mPresContext, NS_ERROR_FAILURE);
03966 
03967   // Don't call RecreateFramesForContent since that is not exported and we want
03968   // to keep the number of entrypoints down.
03969 
03970   nsStyleChangeList changeList;
03971   changeList.AppendChange(nsnull, aContent, nsChangeHint_ReconstructFrame);
03972 
03973   NS_ASSERTION(mViewManager, "Should have view manager");
03974   mViewManager->BeginUpdateViewBatch();
03975   nsresult rv = mFrameConstructor->ProcessRestyledFrames(changeList);
03976   mViewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
03977 #ifdef ACCESSIBILITY
03978   InvalidateAccessibleSubtree(aContent);
03979 #endif
03980   return rv;
03981 }
03982 
03983 NS_IMETHODIMP
03984 PresShell::ClearFrameRefs(nsIFrame* aFrame)
03985 {
03986   mPresContext->EventStateManager()->ClearFrameRefs(aFrame);
03987   
03988   if (aFrame == mCurrentEventFrame) {
03989     mCurrentEventContent = aFrame->GetContent();
03990     mCurrentEventFrame = nsnull;
03991   }
03992 
03993   for (int i=0; i<mCurrentEventFrameStack.Count(); i++) {
03994     if (aFrame == (nsIFrame*)mCurrentEventFrameStack.ElementAt(i)) {
03995       //One of our stack frames was deleted.  Get its content so that when we
03996       //pop it we can still get its new frame from its content
03997       nsIContent *currentEventContent = aFrame->GetContent();
03998       mCurrentEventContentStack.ReplaceObjectAt(currentEventContent, i);
03999       mCurrentEventFrameStack.ReplaceElementAt(nsnull, i);
04000     }
04001   }
04002 
04003   nsWeakFrame* weakFrame = mWeakFrames;
04004   while (weakFrame) {
04005     nsWeakFrame* prev = weakFrame->GetPreviousWeakFrame();
04006     if (weakFrame->GetFrame() == aFrame) {
04007       // This removes weakFrame from mWeakFrames.
04008       weakFrame->Clear(this);
04009     }
04010     weakFrame = prev;
04011   }
04012 
04013   return NS_OK;
04014 }
04015 
04016 NS_IMETHODIMP
04017 PresShell::CreateRenderingContext(nsIFrame *aFrame,
04018                                   nsIRenderingContext** aResult)
04019 {
04020   NS_PRECONDITION(nsnull != aResult, "null ptr");
04021   if (nsnull == aResult) {
04022     return NS_ERROR_NULL_POINTER;
04023   }
04024 
04025   nsresult  rv;
04026 
04027   nsIView *view = aFrame->GetClosestView();
04028 
04029   nsIWidget* widget = view ? view->GetNearestWidget(nsnull) : nsnull;
04030 
04031   nsIRenderingContext* result = nsnull;
04032   nsIDeviceContext *deviceContext = mPresContext->DeviceContext();
04033   if (widget) {
04034     rv = deviceContext->CreateRenderingContext(widget, result);
04035   }
04036   else {
04037     rv = deviceContext->CreateRenderingContext(result);
04038   }
04039   *aResult = result;
04040 
04041   return rv;
04042 }
04043 
04044 // A CantRenderReplacedElementEvent has a weak pointer to the presshell and the
04045 // presshell has a weak pointer to the event.  The event queue owns the event
04046 // and the presshell will delete the event if it's going to go away.
04047 struct CantRenderReplacedElementEvent : public PLEvent {
04048   CantRenderReplacedElementEvent(PresShell* aPresShell,
04049                                  nsIFrame* aFrame) NS_HIDDEN;
04050   ~CantRenderReplacedElementEvent() {
04051     RemoveLoadGroupRequest();
04052   }
04053   
04054   // XXXldb Should the pres shell maintain a reference count on a single
04055   // dummy layout request instead of doing creation of a separate one
04056   // here (and per-event!)?
04057   // XXXbz absolutely!  Should be a per-document counter, actually....
04058   NS_HIDDEN_(void) AddLoadGroupRequest();
04059   NS_HIDDEN_(void) RemoveLoadGroupRequest();
04060   NS_HIDDEN_(PresShell*) OurPresShell() {
04061     return NS_STATIC_CAST(PresShell*, owner);
04062   }
04063 
04064   void HandleEvent();
04065 
04066   nsIFrame*  mFrame;                     // the frame that can't be rendered
04067   CantRenderReplacedElementEvent* mNext; // next event in the list
04068   nsCOMPtr<nsIRequest> mDummyLayoutRequest; // load group request
04069 };
04070 
04071 PR_STATIC_CALLBACK(void*)
04072 HandleCantRenderReplacedElementEvent(PLEvent* aEvent)
04073 {
04074   CantRenderReplacedElementEvent* evt =
04075     NS_STATIC_CAST(CantRenderReplacedElementEvent*, aEvent);
04076   evt->HandleEvent();
04077   return nsnull;
04078 }
04079 
04080 PR_STATIC_CALLBACK(void)
04081 DestroyCantRenderReplacedElementEvent(PLEvent* aEvent)
04082 {
04083   CantRenderReplacedElementEvent* evt =
04084     NS_STATIC_CAST(CantRenderReplacedElementEvent*, aEvent);
04085 
04086   delete evt;
04087 }
04088 
04089 CantRenderReplacedElementEvent::CantRenderReplacedElementEvent(PresShell* aPresShell,
04090                                                                nsIFrame*  aFrame) :
04091   mFrame(aFrame)
04092 {
04093   PL_InitEvent(this, aPresShell,
04094                ::HandleCantRenderReplacedElementEvent,
04095                ::DestroyCantRenderReplacedElementEvent);
04096 
04097   // XXXbz why only for object frames?
04098   if (nsLayoutAtoms::objectFrame == aFrame->GetType()) {
04099     AddLoadGroupRequest();
04100   }
04101 }
04102 
04103 void
04104 PresShell::DequeuePostedEventFor(nsIFrame* aFrame)
04105 {
04106   // If there's a posted event for this frame, then remove it
04107   CantRenderReplacedElementEvent** event = FindPostedEventFor(aFrame);
04108   if (!*event) {
04109     return;
04110   }
04111 
04112   CantRenderReplacedElementEvent* tmp = *event;
04113 
04114   // Remove it from our linked list of posted events
04115   *event = (*event)->mNext;
04116     
04117   // Dequeue it from the event queue
04118   nsCOMPtr<nsIEventQueue> eventQueue;
04119   mEventQueueService->
04120     GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
04121                          getter_AddRefs(eventQueue));
04122   
04123   NS_ASSERTION(eventQueue,
04124                "will crash soon due to event holding dangling pointer to "
04125                "frame");
04126   if (eventQueue) {
04127     PLEventQueue* plqueue;
04128 
04129     eventQueue->GetPLEventQueue(&plqueue);
04130     NS_ASSERTION(plqueue,
04131                  "will crash soon due to event holding dangling pointer to "
04132                  "frame");
04133     if (plqueue) {
04134       // Remove the event and then destroy it
04135       PL_DequeueEvent(tmp, plqueue);
04136       PL_DestroyEvent(tmp);
04137     }
04138   }
04139 }
04140 
04141 // Add a load group request in order to delay the onLoad handler when we have
04142 // pending replacements
04143 void
04144 CantRenderReplacedElementEvent::AddLoadGroupRequest()
04145 {
04146   PresShell* presShell = OurPresShell();
04147   nsIDocument *doc = presShell->GetDocument();
04148   if (!doc) {
04149     return;
04150   }
04151 
04152   nsDummyLayoutRequest::Create(getter_AddRefs(mDummyLayoutRequest), presShell);
04153   if (!mDummyLayoutRequest) {
04154     return;
04155   }
04156 
04157   nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
04158   if (!loadGroup) {
04159     return;
04160   }
04161   
04162   nsresult rv = mDummyLayoutRequest->SetLoadGroup(loadGroup);
04163   if (NS_FAILED(rv)) {
04164     return;
04165   }
04166   
04167   loadGroup->AddRequest(mDummyLayoutRequest, nsnull);
04168 }
04169 
04170 // Remove the load group request added above
04171 void
04172 CantRenderReplacedElementEvent::RemoveLoadGroupRequest()
04173 {
04174   if (mDummyLayoutRequest) {
04175     nsCOMPtr<nsIRequest> request = mDummyLayoutRequest;
04176     mDummyLayoutRequest = nsnull;
04177 
04178     nsIDocument *doc = OurPresShell()->GetDocument();
04179     if (!doc) {
04180       return;
04181     }
04182 
04183     nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
04184     if (!loadGroup) {
04185       return;
04186     }
04187 
04188     loadGroup->RemoveRequest(request, nsnull, NS_OK);
04189   }
04190 }
04191 
04192 void
04193 CantRenderReplacedElementEvent::HandleEvent()
04194 {
04195   // Remove ourselves from the linked list
04196   PresShell* presShell = OurPresShell();
04197   CantRenderReplacedElementEvent** events = &presShell->mPostedReplaces;
04198   while (*events) {
04199     if (*events == this) {
04200       *events = (*events)->mNext;
04201       break;
04202     }
04203     events = &(*events)->mNext;
04204     NS_ASSERTION(*events, "event not in queue");
04205   }
04206 
04207   // Make sure to prevent reflow while we're messing with frames
04208   ++presShell->mChangeNestCount;
04209   presShell->FrameConstructor()->CantRenderReplacedElement(mFrame);
04210   --presShell->mChangeNestCount;
04211 }
04212 
04213 CantRenderReplacedElementEvent**
04214 PresShell::FindPostedEventFor(nsIFrame* aFrame)
04215 {
04216   CantRenderReplacedElementEvent** event = &mPostedReplaces;
04217 
04218   while (*event) {
04219     if ((*event)->mFrame == aFrame) {
04220       return event;
04221     }
04222     event = &(*event)->mNext;
04223   }
04224 
04225   return event;
04226 }
04227 
04228 NS_IMETHODIMP
04229 PresShell::CantRenderReplacedElement(nsIFrame* aFrame)
04230 {
04231   if (*FindPostedEventFor(aFrame))
04232     return NS_OK;
04233 
04234   // Handle this asynchronously
04235   nsCOMPtr<nsIEventQueue> eventQueue;
04236   nsresult rv = mEventQueueService->
04237     GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
04238                          getter_AddRefs(eventQueue));
04239 
04240   NS_ENSURE_SUCCESS(rv, rv);
04241   // Verify that there isn't already a posted event associated with
04242   // this frame.
04243   CantRenderReplacedElementEvent* ev;
04244 
04245   // Create a new event
04246   ev = new CantRenderReplacedElementEvent(this, aFrame);
04247   if (!ev) {
04248     return NS_ERROR_OUT_OF_MEMORY;
04249   }
04250 
04251   // Post the event
04252   rv = eventQueue->PostEvent(ev);
04253   if (NS_FAILED(rv)) {
04254     PL_DestroyEvent(ev);
04255   }
04256   else {
04257     // Add the event to our linked list of posted events
04258     ev->mNext = mPostedReplaces;
04259     mPostedReplaces = ev;
04260   }
04261 
04262   return rv;
04263 }
04264 
04265 NS_IMETHODIMP
04266 PresShell::GoToAnchor(const nsAString& aAnchorName, PRBool aScroll)
04267 {
04268   if (!mDocument) {
04269     return NS_ERROR_FAILURE;
04270   }
04271   
04272   // Hold a reference to the ESM in case event dispatch tears us down.
04273   nsCOMPtr<nsIEventStateManager> esm = mPresContext->EventStateManager();
04274 
04275   if (aAnchorName.IsEmpty()) {
04276     NS_ASSERTION(!aScroll, "can't scroll to empty anchor name");
04277     esm->SetContentState(nsnull, NS_EVENT_STATE_URLTARGET);
04278     return NS_OK;
04279   }
04280 
04281   nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(mDocument);
04282   nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
04283   nsresult rv = NS_OK;
04284   nsCOMPtr<nsIContent> content;
04285 
04286   // Search for an element with a matching "id" attribute
04287   if (doc) {    
04288     nsCOMPtr<nsIDOMElement> element;
04289     rv = doc->GetElementById(aAnchorName, getter_AddRefs(element));
04290     if (NS_SUCCEEDED(rv) && element) {
04291       // Get the nsIContent interface, because that's what we need to
04292       // get the primary frame
04293       content = do_QueryInterface(element);
04294     }
04295   }
04296 
04297   // Search for an anchor element with a matching "name" attribute
04298   if (!content && htmlDoc) {
04299     nsCOMPtr<nsIDOMNodeList> list;
04300     // Find a matching list of named nodes
04301     rv = htmlDoc->GetElementsByName(aAnchorName, getter_AddRefs(list));
04302     if (NS_SUCCEEDED(rv) && list) {
04303       PRUint32 i;
04304       // Loop through the named nodes looking for the first anchor
04305       for (i = 0; PR_TRUE; i++) {
04306         nsCOMPtr<nsIDOMNode> node;
04307         rv = list->Item(i, getter_AddRefs(node));
04308         if (!node) {  // End of list
04309           break;
04310         }
04311         // Ensure it's an anchor element
04312         content = do_QueryInterface(node);
04313         if (content) {
04314           if (content->Tag() == nsHTMLAtoms::a &&
04315               content->IsContentOfType(nsIContent::eHTML)) {
04316             break;
04317           }
04318           content = nsnull;
04319         }
04320       }
04321     }
04322   }
04323 
04324   // Search for anchor in the HTML namespace with a matching name
04325   if (!content && !htmlDoc)
04326   {
04327     nsCOMPtr<nsIDOMNodeList> list;
04328     NS_NAMED_LITERAL_STRING(nameSpace, "http://www.w3.org/1999/xhtml");
04329     // Get the list of anchor elements
04330     rv = doc->GetElementsByTagNameNS(nameSpace, NS_LITERAL_STRING("a"), getter_AddRefs(list));
04331     if (NS_SUCCEEDED(rv) && list) {
04332       PRUint32 i;
04333       // Loop through the named nodes looking for the first anchor
04334       for (i = 0; PR_TRUE; i++) {
04335         nsCOMPtr<nsIDOMNode> node;
04336         rv = list->Item(i, getter_AddRefs(node));
04337         if (!node) { // End of list
04338           break;
04339         }
04340         // Compare the name attribute
04341         nsCOMPtr<nsIDOMElement> element = do_QueryInterface(node);
04342         nsAutoString value;
04343         if (element && NS_SUCCEEDED(element->GetAttribute(NS_LITERAL_STRING("name"), value))) {
04344           if (value.Equals(aAnchorName)) {
04345             content = do_QueryInterface(element);
04346             break;
04347           }
04348         }
04349       }
04350     }
04351   }
04352 
04353   nsCOMPtr<nsIDOMRange> jumpToRange;
04354   nsCOMPtr<nsIXPointerResult> xpointerResult;
04355   if (!content) {
04356     nsCOMPtr<nsIDOMXMLDocument> xmldoc = do_QueryInterface(mDocument);
04357     if (xmldoc) {
04358       // Try XPointer
04359       xmldoc->EvaluateXPointer(aAnchorName, getter_AddRefs(xpointerResult));
04360       if (xpointerResult) {
04361         xpointerResult->Item(0, getter_AddRefs(jumpToRange));
04362         if (!jumpToRange) {
04363           // We know it was an XPointer, so there is no point in
04364           // trying any other pointer types, let's just return
04365           // an error.
04366           return NS_ERROR_FAILURE;
04367         }
04368       }
04369 
04370       // Finally try FIXptr
04371       if (!jumpToRange) {
04372         xmldoc->EvaluateFIXptr(aAnchorName,getter_AddRefs(jumpToRange));
04373       }
04374 
04375       if (jumpToRange) {
04376         nsCOMPtr<nsIDOMNode> node;
04377         jumpToRange->GetStartContainer(getter_AddRefs(node));
04378         if (node) {
04379           PRUint16 nodeType;
04380           node->GetNodeType(&nodeType);
04381           PRInt32 offset = -1;
04382           jumpToRange->GetStartOffset(&offset);
04383           switch (nodeType) {
04384             case nsIDOMNode::ATTRIBUTE_NODE:
04385             {
04386               // XXX Assuming jumping to the ownerElement is the sanest action.
04387               nsCOMPtr<nsIAttribute> attr = do_QueryInterface(node);
04388               content = attr->GetContent();
04389               break;
04390             }
04391             case nsIDOMNode::DOCUMENT_NODE:
04392             {
04393               if (offset >= 0) {
04394                 nsCOMPtr<nsIDocument> document = do_QueryInterface(node);
04395                 content = document->GetChildAt(offset);
04396               }
04397               break;
04398             }
04399             case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
04400             case nsIDOMNode::ELEMENT_NODE:
04401             case nsIDOMNode::ENTITY_REFERENCE_NODE:
04402             {
04403               if (offset >= 0) {
04404                 nsCOMPtr<nsIContent> parent = do_QueryInterface(node);
04405                 content = parent->GetChildAt(offset);
04406               }
04407               break;
04408             }
04409             case nsIDOMNode::CDATA_SECTION_NODE:
04410             case nsIDOMNode::COMMENT_NODE:
04411             case nsIDOMNode::TEXT_NODE:
04412             case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
04413             {
04414               // XXX This should scroll to a specific position in the text.
04415               content = do_QueryInterface(node);
04416               break;
04417             }
04418           }
04419         }
04420       }
04421     }
04422   }
04423 
04424   esm->SetContentState(content, NS_EVENT_STATE_URLTARGET);
04425 
04426   if (content) {
04427     // Flush notifications so we scroll to the right place
04428     if (aScroll) {
04429       mDocument->FlushPendingNotifications(Flush_Layout);   
04430       // Get the primary frame
04431       nsIFrame* frame = nsnull;
04432       GetPrimaryFrameFor(content, &frame);
04433       NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
04434       rv = ScrollFrameIntoView(frame, NS_PRESSHELL_SCROLL_TOP,
04435                                NS_PRESSHELL_SCROLL_ANYWHERE);
04436       NS_ENSURE_SUCCESS(rv, rv);
04437     }
04438 
04439     // Should we select the target? This action is controlled by a
04440     // preference: the default is to not select.
04441     PRBool selectAnchor = nsContentUtils::GetBoolPref("layout.selectanchor");
04442 
04443     // Even if select anchor pref is false, we must still move the
04444     // caret there. That way tabbing will start from the new
04445     // location
04446     if (!jumpToRange) {
04447       jumpToRange = do_CreateInstance(kRangeCID);
04448       if (jumpToRange) {
04449         while (content && content->GetChildCount() > 0) {
04450           content = content->GetChildAt(0);
04451         }
04452         nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
04453         NS_ASSERTION(node, "No nsIDOMNode for descendent of anchor");
04454         jumpToRange->SelectNodeContents(node);
04455       }
04456     }
04457     if (jumpToRange) {
04458       // Select the anchor
04459       nsCOMPtr<nsISelection> sel;
04460       if (NS_SUCCEEDED(
04461           GetSelection(nsISelectionController::SELECTION_NORMAL,
04462                         getter_AddRefs(sel))) &&
04463           sel) {
04464         sel->RemoveAllRanges();
04465         sel->AddRange(jumpToRange);
04466         if (!selectAnchor) {
04467           // Use a caret (collapsed selection) at the start of the anchor
04468           sel->CollapseToStart();
04469         }
04470       }  
04471 
04472       if (selectAnchor && xpointerResult) {
04473         // Select the rest (if any) of the ranges in XPointerResult
04474         PRUint32 count, i;
04475         xpointerResult->GetLength(&count);
04476         for (i = 1; i < count; i++) { // jumpToRange is i = 0
04477           nsCOMPtr<nsIDOMRange> range;
04478           xpointerResult->Item(i, getter_AddRefs(range));
04479           sel->AddRange(range);
04480         }
04481       }
04482       // Selection is at anchor.
04483       // Now focus the document itself if focus is on an element within it.
04484       nsPIDOMWindow *win = mDocument->GetWindow();
04485 
04486       if (win) {
04487         nsCOMPtr<nsIFocusController> focusController = win->GetRootFocusController();
04488         if (focusController) {
04489           nsCOMPtr<nsIDOMWindowInternal> focusedWin;
04490           focusController->GetFocusedWindow(getter_AddRefs(focusedWin));
04491           if (SameCOMIdentity(win, focusedWin)) {
04492             esm->ChangeFocusWith(nsnull, nsIEventStateManager::eEventFocusedByApplication);
04493           }
04494         }
04495       }
04496     }
04497   } else {
04498     rv = NS_ERROR_FAILURE; //changed to NS_OK in quirks mode if ScrollTo is called
04499     
04500     // Scroll to the top/left if the anchor can not be
04501     // found and it is labelled top (quirks mode only). @see bug 80784
04502     if ((NS_LossyConvertUCS2toASCII(aAnchorName).LowerCaseEqualsLiteral("top")) &&
04503         (mPresContext->CompatibilityMode() == eCompatibility_NavQuirks)) {
04504       rv = NS_OK;
04505       // Check |aScroll| after setting |rv| so we set |rv| to the same
04506       // thing whether or not |aScroll| is true.
04507       if (aScroll && mViewManager) {
04508         // Get the viewport scroller
04509         nsIScrollableView* scrollingView;
04510         mViewManager->GetRootScrollableView(&scrollingView);
04511         if (scrollingView) {
04512           // Scroll to the top of the page
04513           scrollingView->ScrollTo(0, 0, NS_VMREFRESH_IMMEDIATE);
04514         }
04515       }
04516     }
04517   }
04518 
04519   return rv;
04520 }
04521 
04527 static void ScrollViewToShowRect(nsIScrollableView* aScrollingView,
04528                                  nsRect &           aRect,
04529                                  PRIntn             aVPercent,
04530                                  PRIntn             aHPercent)
04531 {
04532   // Determine the visible rect in the scrolling view's coordinate space.
04533   // The size of the visible area is the clip view size
04534   nsRect visibleRect = aScrollingView->View()->GetBounds(); // get width and height
04535   aScrollingView->GetScrollPosition(visibleRect.x, visibleRect.y);
04536 
04537   // The actual scroll offsets
04538   nscoord scrollOffsetX = visibleRect.x;
04539   nscoord scrollOffsetY = visibleRect.y;
04540 
04541   nscoord lineHeight;
04542   aScrollingView->GetLineHeight(&lineHeight);
04543   
04544   // See how the rect should be positioned vertically
04545   if (NS_PRESSHELL_SCROLL_ANYWHERE == aVPercent) {
04546     // The caller doesn't care where the frame is positioned vertically,
04547     // so long as it's fully visible
04548     if (aRect.y < visibleRect.y) {
04549       // Scroll up so the frame's top edge is visible
04550       scrollOffsetY = aRect.y;
04551     } else if (aRect.YMost() > visibleRect.YMost()) {
04552       // Scroll down so the frame's bottom edge is visible. Make sure the
04553       // frame's top edge is still visible
04554       scrollOffsetY += aRect.YMost() - visibleRect.YMost();
04555       if (scrollOffsetY > aRect.y) {
04556         scrollOffsetY = aRect.y;
04557       }
04558     }
04559   } else if (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE == aVPercent) {
04560     // Scroll only if no part of the frame is visible in this view
04561     if (aRect.YMost() - lineHeight < visibleRect.y) {
04562       // Scroll up so the frame's top edge is visible
04563       scrollOffsetY = aRect.y;
04564     }  else if (aRect.y + lineHeight > visibleRect.YMost()) {
04565       // Scroll down so the frame's bottom edge is visible. Make sure the
04566       // frame's top edge is still visible
04567       scrollOffsetY += aRect.YMost() - visibleRect.YMost();
04568       if (scrollOffsetY > aRect.y) {
04569         scrollOffsetY = aRect.y;
04570       }
04571     }
04572   } else {
04573     // Align the frame edge according to the specified percentage
04574     nscoord frameAlignY =
04575       NSToCoordRound(aRect.y + aRect.height * (aVPercent / 100.0f));
04576     scrollOffsetY =
04577       NSToCoordRound(frameAlignY - visibleRect.height * (aVPercent / 100.0f));
04578   }
04579 
04580   // See how the frame should be positioned horizontally
04581   if (NS_PRESSHELL_SCROLL_ANYWHERE == aHPercent) {
04582     // The caller doesn't care where the frame is positioned horizontally,
04583     // so long as it's fully visible
04584     if (aRect.x < visibleRect.x) {
04585       // Scroll left so the frame's left edge is visible
04586       scrollOffsetX = aRect.x;
04587     } else if (aRect.XMost() > visibleRect.XMost()) {
04588       // Scroll right so the frame's right edge is visible. Make sure the
04589       // frame's left edge is still visible
04590       scrollOffsetX += aRect.XMost() - visibleRect.XMost();
04591       if (scrollOffsetX > aRect.x) {
04592         scrollOffsetX = aRect.x;
04593       }
04594     }
04595   } else if (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE == aHPercent) {
04596     // Scroll only if no part of the frame is visible in this view
04597     // XXXbz using the line height here is odd, but there are no
04598     // natural dimensions to use here, really....
04599     if (aRect.XMost() - lineHeight < visibleRect.x) {
04600       // Scroll left so the frame's left edge is visible
04601       scrollOffsetX = aRect.x;
04602     }  else if (aRect.x + lineHeight > visibleRect.XMost()) {
04603       // Scroll right so the frame's right edge is visible. Make sure the
04604       // frame's left edge is still visible
04605       scrollOffsetX += aRect.XMost() - visibleRect.XMost();
04606       if (scrollOffsetX > aRect.x) {
04607         scrollOffsetX = aRect.x;
04608       }
04609     }
04610   } else {
04611     // Align the frame edge according to the specified percentage
04612     nscoord frameAlignX =
04613       NSToCoordRound(aRect.x + (aRect.width) * (aHPercent / 100.0f));
04614     scrollOffsetX =
04615       NSToCoordRound(frameAlignX - visibleRect.width * (aHPercent / 100.0f));
04616   }
04617 
04618   aScrollingView->ScrollTo(scrollOffsetX, scrollOffsetY,
04619                            NS_VMREFRESH_IMMEDIATE);
04620 }
04621 
04622 NS_IMETHODIMP
04623 PresShell::ScrollFrameIntoView(nsIFrame *aFrame,
04624                                PRIntn   aVPercent, 
04625                                PRIntn   aHPercent) const
04626 {
04627   if (!aFrame) {
04628     return NS_ERROR_NULL_POINTER;
04629   }
04630 
04631   // Before we scroll the frame into view, ask the command dispatcher
04632   // if we're resetting focus because a window just got an activate
04633   // event. If we are, we do not want to scroll the frame into view.
04634   // Example: The user clicks on an anchor, and then deactivates the 
04635   // window. When they reactivate the window, the expected behavior
04636   // is not for the anchor link to scroll back into view. That is what
04637   // this check is preventing.
04638   // XXX: The dependency on the command dispatcher needs to be fixed.
04639   nsIContent* content = aFrame->GetContent();
04640   if (content) {
04641     nsIDocument* document = content->GetDocument();
04642     if (document){
04643       nsCOMPtr<nsPIDOMWindow> ourWindow = do_QueryInterface(document->GetScriptGlobalObject());
04644       if(ourWindow) {
04645         nsIFocusController *focusController =
04646           ourWindow->GetRootFocusController();
04647         if (focusController) {
04648           PRBool dontScroll;
04649           focusController->GetSuppressFocusScroll(&dontScroll);
04650           if(dontScroll)
04651             return NS_OK;
04652         }
04653       }
04654     }
04655   }
04656 
04657   // Flush out pending reflows to make sure we scroll to the right place
04658   mDocument->FlushPendingNotifications(Flush_OnlyReflow);
04659   
04660   // This is a two-step process.
04661   // Step 1: Find the bounds of the rect we want to scroll into view.  For
04662   //         example, for an inline frame we may want to scroll in the whole
04663   //         line.
04664   // Step 2: Walk the views that are parents of the frame and scroll them
04665   //         appropriately.
04666   
04667   nsRect  frameBounds = aFrame->GetRect();
04668   nsPoint offset;
04669   nsIView* closestView;
04670   aFrame->GetOffsetFromView(offset, &closestView);
04671   frameBounds.MoveTo(offset);
04672 
04673   // If this is an inline frame and either the bounds height is 0 (quirks
04674   // layout model) or aVPercent is not NS_PRESSHELL_SCROLL_ANYWHERE, we need to
04675   // change the top of the bounds to include the whole line.
04676   if (frameBounds.height == 0 || aVPercent != NS_PRESSHELL_SCROLL_ANYWHERE) {
04677     nsIAtom* frameType = NULL;
04678     nsIFrame *prevFrame = aFrame;
04679     nsIFrame *frame = aFrame;
04680 
04681     while (frame &&
04682            (frameType = frame->GetType()) == nsLayoutAtoms::inlineFrame) {
04683       prevFrame = frame;
04684       frame = prevFrame->GetParent();
04685     }
04686 
04687     if (frame != aFrame &&
04688         frame &&
04689         frameType == nsLayoutAtoms::blockFrame) {
04690       // find the line containing aFrame and increase the top of |offset|.
04691       nsCOMPtr<nsILineIterator> lines( do_QueryInterface(frame) );
04692 
04693       if (lines) {
04694         PRInt32 index = -1;
04695         lines->FindLineContaining(prevFrame, &index);
04696         if (index >= 0) {
04697           nsIFrame *trash1;
04698           PRInt32 trash2;
04699           nsRect lineBounds;
04700           PRUint32 trash3;
04701 
04702           if (NS_SUCCEEDED(lines->GetLine(index, &trash1, &trash2,
04703                                           lineBounds, &trash3))) {
04704             nsPoint blockOffset;
04705             nsIView* blockView;
04706             frame->GetOffsetFromView(blockOffset, &blockView);
04707 
04708             if (blockView == closestView) {
04709               // XXX If views not equal, this is hard.  Do we want to bother?
04710               nscoord newoffset = lineBounds.y + blockOffset.y;
04711 
04712               if (newoffset < frameBounds.y)
04713                 frameBounds.y = newoffset;
04714             }
04715           }
04716         }
04717       }
04718     }
04719   }
04720 
04721   NS_ASSERTION(closestView && !closestView->ToScrollableView(),
04722                "What happened to the scrolled view?  "
04723                "The frame should not be directly in the scrolling view!");
04724   
04725   // Walk up the view hierarchy.  Make sure to add the view's position
04726   // _after_ we get the parent and see whether it's scrollable.  We want to
04727   // make sure to get the scrolled view's position after it has been scrolled.
04728   nsIScrollableView* scrollingView = nsnull;
04729   while (closestView) {
04730     nsIView* parent = closestView->GetParent();
04731     if (parent) {
04732       scrollingView = parent->ToScrollableView();
04733       if (scrollingView) {
04734         ScrollViewToShowRect(scrollingView, frameBounds, aVPercent, aHPercent);
04735       }
04736     }
04737     frameBounds += closestView->GetPosition();;
04738     closestView = parent;
04739   }
04740 
04741   return NS_OK;
04742 }
04743 
04744 // GetLinkLocation: copy link location to clipboard
04745 NS_IMETHODIMP PresShell::GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocationString)
04746 {
04747 #ifdef DEBUG_dr
04748   printf("dr :: PresShell::GetLinkLocation\n");
04749 #endif
04750 
04751   NS_ENSURE_ARG_POINTER(aNode);
04752   nsresult rv;
04753   nsAutoString anchorText;
04754   static char strippedChars[] = {'\t','\r','\n'};
04755 
04756   // are we an anchor?
04757   nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(aNode));
04758   nsCOMPtr<nsIDOMHTMLAreaElement> area;
04759   nsCOMPtr<nsIDOMHTMLLinkElement> link;
04760   nsAutoString xlinkType;
04761   if (anchor) {
04762     rv = anchor->GetHref(anchorText);
04763     NS_ENSURE_SUCCESS(rv, rv);
04764   } else {
04765     // area?
04766     area = do_QueryInterface(aNode);
04767     if (area) {
04768       rv = area->GetHref(anchorText);
04769       NS_ENSURE_SUCCESS(rv, rv);
04770     } else {
04771       // link?
04772       link = do_QueryInterface(aNode);
04773       if (link) {
04774         rv = link->GetHref(anchorText);
04775         NS_ENSURE_SUCCESS(rv, rv);
04776       } else {
04777         // Xlink?
04778         nsCOMPtr<nsIDOMElement> element(do_QueryInterface(aNode));
04779         if (element) {
04780           NS_NAMED_LITERAL_STRING(xlinkNS,"http://www.w3.org/1999/xlink");
04781           element->GetAttributeNS(xlinkNS,NS_LITERAL_STRING("type"),xlinkType);
04782           if (xlinkType.EqualsLiteral("simple")) {
04783             element->GetAttributeNS(xlinkNS,NS_LITERAL_STRING("href"),anchorText);
04784             if (!anchorText.IsEmpty()) {
04785               // Resolve the full URI using baseURI property
04786 
04787               nsAutoString base;
04788               nsCOMPtr<nsIDOM3Node> node(do_QueryInterface(aNode,&rv));
04789               NS_ENSURE_SUCCESS(rv, rv);
04790               node->GetBaseURI(base);
04791 
04792               nsCOMPtr<nsIIOService>
04793                 ios(do_GetService("@mozilla.org/network/io-service;1", &rv));
04794               NS_ENSURE_SUCCESS(rv, rv);
04795 
04796               nsCOMPtr<nsIURI> baseURI;
04797               rv = ios->NewURI(NS_ConvertUCS2toUTF8(base),nsnull,nsnull,getter_AddRefs(baseURI));
04798               NS_ENSURE_SUCCESS(rv, rv);
04799 
04800               nsCAutoString spec;
04801               rv = baseURI->Resolve(NS_ConvertUCS2toUTF8(anchorText),spec);
04802               NS_ENSURE_SUCCESS(rv, rv);
04803 
04804               CopyUTF8toUTF16(spec, anchorText);
04805             }
04806           }
04807         }
04808       }
04809     }
04810   }
04811 
04812   if (anchor || area || link || xlinkType.EqualsLiteral("simple")) {
04813     //Remove all the '\t', '\r' and '\n' from 'anchorText'
04814     anchorText.StripChars(strippedChars);
04815 
04816     aLocationString = anchorText;
04817 
04818     return NS_OK;
04819   }
04820 
04821   // if no link, fail.
04822   return NS_ERROR_FAILURE;
04823 }
04824 
04825 NS_IMETHODIMP
04826 PresShell::GetSelectionForCopy(nsISelection** outSelection)
04827 {
04828   nsresult rv = NS_OK;
04829 
04830   *outSelection = nsnull;
04831 
04832   if (!mDocument) return NS_ERROR_FAILURE;
04833 
04834   nsCOMPtr<nsIContent> content;
04835   nsCOMPtr<nsPIDOMWindow> ourWindow = do_QueryInterface(mDocument->GetScriptGlobalObject());
04836   if (ourWindow) {
04837     nsIFocusController *focusController = ourWindow->GetRootFocusController();
04838     if (focusController) {
04839       nsCOMPtr<nsIDOMElement> focusedElement;
04840       focusController->GetFocusedElement(getter_AddRefs(focusedElement));
04841       content = do_QueryInterface(focusedElement);
04842     }
04843   }
04844 
04845   nsCOMPtr<nsISelection> sel;
04846   if (content)
04847   {
04848     //check to see if we need to get selection from frame
04849     //optimization that MAY need to be expanded as more things implement their own "selection"
04850     nsCOMPtr<nsIDOMNSHTMLInputElement>    htmlInputElement(do_QueryInterface(content));
04851     nsCOMPtr<nsIDOMNSHTMLTextAreaElement> htmlTextAreaElement(do_QueryInterface(content));
04852     if (htmlInputElement || htmlTextAreaElement)
04853     {
04854       nsIFrame *htmlInputFrame;
04855       rv = GetPrimaryFrameFor(content, &htmlInputFrame);
04856       if (NS_FAILED(rv))  return rv;
04857       if (!htmlInputFrame) return NS_ERROR_FAILURE;
04858 
04859       nsCOMPtr<nsISelectionController> selCon;
04860       rv = htmlInputFrame->GetSelectionController(mPresContext,getter_AddRefs(selCon));
04861       if (NS_FAILED(rv)) return rv;
04862       if (!selCon) return NS_ERROR_FAILURE;
04863 
04864       rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(sel));
04865     }
04866   }
04867   if (!sel) //get selection from this PresShell
04868     rv = GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(sel));
04869    
04870   *outSelection = sel;
04871   NS_IF_ADDREF(*outSelection);
04872   return rv;
04873 }
04874 
04875 
04876 NS_IMETHODIMP
04877 PresShell::DoGetContents(const nsACString& aMimeType, PRUint32 aFlags, PRBool aSelectionOnly, nsAString& aOutValue)
04878 {
04879   aOutValue.Truncate();
04880   
04881   if (!mDocument) return NS_ERROR_FAILURE;
04882 
04883   nsresult rv;
04884   nsCOMPtr<nsISelection> sel;
04885 
04886   // Now we have the selection.  Make sure it's nonzero:
04887   if (aSelectionOnly)
04888   {
04889     rv = GetSelectionForCopy(getter_AddRefs(sel));
04890     if (NS_FAILED(rv)) return rv;
04891     if (!sel) return NS_ERROR_FAILURE;
04892   
04893     PRBool isCollapsed;
04894     sel->GetIsCollapsed(&isCollapsed);
04895     if (isCollapsed)
04896       return NS_OK;
04897   }
04898   
04899   // call the copy code
04900   return nsCopySupport::GetContents(aMimeType, aFlags, sel,
04901                                     mDocument, aOutValue);
04902 }
04903 
04904 NS_IMETHODIMP
04905 PresShell::DoCopy()
04906 {
04907   if (!mDocument) return NS_ERROR_FAILURE;
04908 
04909   nsCOMPtr<nsISelection> sel;
04910   nsresult rv = GetSelectionForCopy(getter_AddRefs(sel));
04911   if (NS_FAILED(rv)) 
04912     return rv;
04913   if (!sel) 
04914     return NS_ERROR_FAILURE;
04915 
04916   // Now we have the selection.  Make sure it's nonzero:
04917   PRBool isCollapsed;
04918   sel->GetIsCollapsed(&isCollapsed);
04919   if (isCollapsed)
04920     return NS_OK;
04921 
04922   // call the copy code
04923   rv = nsCopySupport::HTMLCopy(sel, mDocument, nsIClipboard::kGlobalClipboard);
04924   if (NS_FAILED(rv))
04925     return rv;
04926 
04927   // Now that we have copied, update the Paste menu item
04928   nsCOMPtr<nsIDOMWindowInternal> domWindow =
04929     do_QueryInterface(mDocument->GetScriptGlobalObject());
04930   if (domWindow)
04931   {
04932     domWindow->UpdateCommands(NS_LITERAL_STRING("clipboard"));
04933   }
04934   
04935   return NS_OK;
04936 }
04937 
04938 NS_IMETHODIMP
04939 PresShell::CaptureHistoryState(nsILayoutHistoryState** aState, PRBool aLeavingPage)
04940 {
04941   nsresult rv = NS_OK;
04942 
04943   NS_PRECONDITION(nsnull != aState, "null state pointer");
04944 
04945   // We actually have to mess with the docshell here, since we want to
04946   // store the state back in it.
04947   // XXXbz this isn't really right, since this is being called in the
04948   // content viewer's Hide() method...  by that point the docshell's
04949   // state could be wrong.  We should sort out a better ownership
04950   // model for the layout history state.
04951   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
04952   if (!container)
04953     return NS_ERROR_FAILURE;
04954 
04955   nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
04956   if (!docShell)
04957     return NS_ERROR_FAILURE;
04958 
04959   nsCOMPtr<nsILayoutHistoryState> historyState;
04960   docShell->GetLayoutHistoryState(getter_AddRefs(historyState));
04961   if (!historyState) {
04962     // Create the document state object
04963     rv = NS_NewLayoutHistoryState(getter_AddRefs(historyState));
04964   
04965     if (NS_FAILED(rv)) { 
04966       *aState = nsnull;
04967       return rv;
04968     }    
04969 
04970     docShell->SetLayoutHistoryState(historyState);
04971   }
04972 
04973   *aState = historyState;
04974   NS_IF_ADDREF(*aState);
04975   
04976   // Capture frame state for the entire frame hierarchy
04977   nsIFrame* rootFrame = FrameManager()->GetRootFrame();
04978   if (!rootFrame) return NS_OK;
04979   // Capture frame state for the root scroll frame
04980   // Don't capture state when first creating doc element heirarchy
04981   // As the scroll position is 0 and this will cause us to loose
04982   // our previously saved place!
04983   if (aLeavingPage) {
04984     nsIFrame* scrollFrame = GetRootScrollFrame(rootFrame);
04985     if (scrollFrame) {
04986       FrameManager()->CaptureFrameStateFor(scrollFrame, historyState,
04987                                            nsIStatefulFrame::eDocumentScrollState);
04988     }
04989   }
04990 
04991   FrameManager()->CaptureFrameState(rootFrame, historyState);  
04992  
04993   return NS_OK;
04994 }
04995 
04996 NS_IMETHODIMP
04997 PresShell::GetGeneratedContentIterator(nsIContent*          aContent,
04998                                        GeneratedContentType aType,
04999                                        nsIContentIterator** aIterator) const
05000 {
05001   nsIFrame* primaryFrame;
05002   nsresult  rv = NS_OK;
05003 
05004   // Initialize OUT parameter
05005   *aIterator = nsnull;
05006 
05007   // Get the primary frame associated with the content object
05008   GetPrimaryFrameFor(aContent, &primaryFrame);
05009   if (primaryFrame) {
05010     // See whether it's a request for the before or after generated content
05011     if (Before == aType) {
05012       nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(primaryFrame);
05013       if (beforeFrame) {
05014         // Create an iterator
05015         rv = NS_NewFrameContentIterator(mPresContext, beforeFrame, aIterator);
05016       }
05017       
05018     } else {
05019       // Avoid finding the :after frame unless we need to (it's
05020       // expensive). Instead probe for the existence of the pseudo-element
05021       nsStyleContext *styleContext;
05022       
05023       styleContext = primaryFrame->GetStyleContext();
05024       if (nsLayoutUtils::HasPseudoStyle(aContent, styleContext,
05025                                         nsCSSPseudoElements::after,
05026                                         mPresContext)) {
05027         nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(primaryFrame);
05028         if (afterFrame)
05029         {
05030           NS_ASSERTION(afterFrame->IsGeneratedContentFrame(),
05031                        "can't find generated content frame");
05032           // Create an iterator
05033           rv = NS_NewFrameContentIterator(mPresContext, afterFrame, aIterator);
05034         }
05035       }
05036     }
05037   }
05038 
05039   return rv;
05040 }
05041 
05042 
05043 NS_IMETHODIMP
05044 PresShell::SetAnonymousContentFor(nsIContent* aContent, nsISupportsArray* aAnonymousElements)
05045 {
05046   NS_PRECONDITION(aContent != nsnull, "null ptr");
05047   if (! aContent)
05048     return NS_ERROR_NULL_POINTER;
05049 
05050   if (! mAnonymousContentTable) {
05051     mAnonymousContentTable = new nsSupportsHashtable;
05052     if (! mAnonymousContentTable)
05053       return NS_ERROR_OUT_OF_MEMORY;
05054   }
05055 
05056   nsISupportsKey key(aContent);
05057 
05058   nsCOMPtr<nsISupportsArray> oldAnonymousElements =
05059     getter_AddRefs(NS_STATIC_CAST(nsISupportsArray*, mAnonymousContentTable->Get(&key)));
05060 
05061   if (!oldAnonymousElements) {
05062     if (aAnonymousElements) {
05063       mAnonymousContentTable->Put(&key, aAnonymousElements);
05064     }
05065   } else {
05066     if (aAnonymousElements) {
05067       oldAnonymousElements->AppendElements(aAnonymousElements);
05068     } else {
05069       // If we're trying to clear anonymous content for an element that
05070       // already had anonymous content, then we need to be sure to clean
05071       // up after the old content. (This can happen, for example, when a
05072       // reframe occurs.)
05073       PRUint32 count;
05074       oldAnonymousElements->Count(&count);
05075       
05076       while (PRInt32(--count) >= 0) {
05077         nsCOMPtr<nsIContent> content = do_QueryElementAt(oldAnonymousElements,
05078                                                          count);
05079         NS_ASSERTION(content != nsnull, "not an nsIContent");
05080         if (! content)
05081           continue;
05082         
05083         content->UnbindFromTree();
05084       }
05085 
05086       if (!mIsReleasingAnonymousContent)
05087         mAnonymousContentTable->Remove(&key);
05088     }
05089   }
05090 
05091   return NS_OK;
05092 }
05093 
05094 
05095 NS_IMETHODIMP
05096 PresShell::GetAnonymousContentFor(nsIContent* aContent, nsISupportsArray** aAnonymousElements)
05097 {
05098   if (! mAnonymousContentTable) {
05099     *aAnonymousElements = nsnull;
05100     return NS_OK;
05101   }
05102 
05103   nsISupportsKey key(aContent);
05104   *aAnonymousElements =
05105     NS_REINTERPRET_CAST(nsISupportsArray*, mAnonymousContentTable->Get(&key)); // addrefs
05106 
05107   return NS_OK;
05108 }
05109 
05110 
05111 static PRBool PR_CALLBACK
05112 ClearDocumentEnumerator(nsHashKey* aKey, void* aData, void* aClosure)
05113 {
05114   nsISupportsArray* anonymousElements =
05115     NS_STATIC_CAST(nsISupportsArray*, aData);
05116 
05117   PRUint32 count;
05118   anonymousElements->Count(&count);
05119   while (PRInt32(--count) >= 0) {
05120     nsCOMPtr<nsIContent> content = do_QueryElementAt(anonymousElements, count);
05121     NS_ASSERTION(content != nsnull, "not an nsIContent");
05122     if (! content)
05123       continue;
05124 
05125     content->UnbindFromTree();
05126   }
05127 
05128   return PR_TRUE;
05129 }
05130 
05131 
05132 NS_IMETHODIMP
05133 PresShell::ReleaseAnonymousContent()
05134 {
05135   if (mAnonymousContentTable) {
05136     mIsReleasingAnonymousContent = PR_TRUE;
05137     mAnonymousContentTable->Enumerate(ClearDocumentEnumerator);
05138     delete mAnonymousContentTable;
05139     mAnonymousContentTable = nsnull;
05140   }
05141   return NS_OK;
05142 }
05143 
05144 NS_IMETHODIMP
05145 PresShell::IsPaintingSuppressed(PRBool* aResult)
05146 {
05147   *aResult = mPaintingSuppressed;
05148   return NS_OK;
05149 }
05150 
05151 void
05152 PresShell::UnsuppressAndInvalidate()
05153 {
05154   if (!mPresContext->EnsureVisible(PR_FALSE)) {
05155     // No point; we're about to be torn down anyway.
05156     return;
05157   }
05158   
05159   mPaintingSuppressed = PR_FALSE;
05160   nsIFrame* rootFrame = FrameManager()->GetRootFrame();
05161   if (rootFrame) {
05162     // let's assume that outline on a root frame is not supported
05163     nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
05164     rootFrame->Invalidate(rect, PR_FALSE);
05165   }
05166 
05167   // This makes sure to get the same thing that nsPresContext::EnsureVisible()
05168   // got.
05169   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
05170   nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(container);
05171   nsCOMPtr<nsIFocusController> focusController =
05172     ourWindow ? ourWindow->GetRootFocusController() : nsnull;
05173 
05174   if (ourWindow)
05175     CheckForFocus(ourWindow, focusController, mDocument);
05176 
05177   if (focusController) // Unsuppress now that we've shown the new window and focused it.
05178     focusController->SetSuppressFocus(PR_FALSE, "PresShell suppression on Web page loads");
05179 
05180   if (mViewManager)
05181     mViewManager->SynthesizeMouseMove(PR_FALSE);
05182 }
05183 
05184 NS_IMETHODIMP
05185 PresShell::UnsuppressPainting()
05186 {
05187   if (mPaintSuppressionTimer) {
05188     mPaintSuppressionTimer->Cancel();
05189     mPaintSuppressionTimer = nsnull;
05190   }
05191 
05192   if (mIsDocumentGone || !mPaintingSuppressed)
05193     return NS_OK;
05194 
05195   // If we have reflows pending, just wait until we process
05196   // the reflows and get all the frames where we want them
05197   // before actually unlocking the painting.  Otherwise
05198   // go ahead and unlock now.
05199   if (mReflowCommands.Count() > 0)
05200     mShouldUnsuppressPainting = PR_TRUE;
05201   else
05202     UnsuppressAndInvalidate();
05203   return NS_OK;
05204 }
05205 
05206 NS_IMETHODIMP
05207 PresShell::DisableThemeSupport()
05208 {
05209   // Doesn't have to be dynamic.  Just set the bool.
05210   mIsThemeSupportDisabled = PR_TRUE;
05211   return NS_OK;
05212 }
05213 
05214 PRBool 
05215 PresShell::IsThemeSupportEnabled()
05216 {
05217   return !mIsThemeSupportDisabled;
05218 }
05219 
05220 // Post a request to handle an arbitrary callback after reflow has finished.
05221 NS_IMETHODIMP
05222 PresShell::PostReflowCallback(nsIReflowCallback* aCallback)
05223 {
05224   nsCallbackEventRequest* request = nsnull;
05225   void* result = AllocateFrame(sizeof(nsCallbackEventRequest));
05226   request = (nsCallbackEventRequest*)result;
05227 
05228   request->callback = aCallback;
05229   NS_ADDREF(aCallback);
05230   request->next = nsnull;
05231 
05232   if (mLastCallbackEventRequest) {
05233     mLastCallbackEventRequest = mLastCallbackEventRequest->next = request;
05234   } else {
05235     mFirstCallbackEventRequest = request;
05236     mLastCallbackEventRequest = request;
05237   }
05238  
05239   return NS_OK;
05240 }
05241 
05242 NS_IMETHODIMP
05243 PresShell::CancelReflowCallback(nsIReflowCallback* aCallback)
05244 {
05245    nsCallbackEventRequest* before = nsnull;
05246    nsCallbackEventRequest* node = mFirstCallbackEventRequest;
05247    while(node)
05248    {
05249       nsIReflowCallback* callback = node->callback;
05250 
05251       if (callback == aCallback) 
05252       {
05253         nsCallbackEventRequest* toFree = node;
05254         if (node == mFirstCallbackEventRequest) {
05255           node = node->next;
05256           mFirstCallbackEventRequest = node;
05257           NS_ASSERTION(before == nsnull, "impossible");
05258         } else {
05259           node = node->next;
05260           before->next = node;
05261         }
05262 
05263         if (toFree == mLastCallbackEventRequest) {
05264           mLastCallbackEventRequest = before;
05265         }
05266 
05267         FreeFrame(sizeof(nsCallbackEventRequest), toFree);
05268         NS_RELEASE(callback);
05269       } else {
05270         before = node;
05271         node = node->next;
05272       }
05273    }
05274 
05275    return NS_OK;
05276 }
05277 
05282 NS_IMETHODIMP
05283 PresShell::PostDOMEvent(nsIContent* aContent, nsEvent* aEvent)
05284 {
05285  // ok we have a list of events to handle. Queue them up and handle them
05286  // after we finish reflow.
05287   nsDOMEventRequest* request = nsnull;
05288   void* result = AllocateFrame(sizeof(nsDOMEventRequest));
05289   request = (nsDOMEventRequest*)result;
05290 
05291   request->content = aContent;
05292   NS_ADDREF(aContent);
05293 
05294   request->event = aEvent;
05295   request->next = nsnull;
05296 
05297   if (mLastDOMEventRequest) {
05298     mLastDOMEventRequest = mLastDOMEventRequest->next = request;
05299   } else {
05300     mFirstDOMEventRequest = request;
05301     mLastDOMEventRequest = request;
05302   }
05303  
05304   return NS_OK;
05305 }
05306 
05307 
05311 NS_IMETHODIMP
05312 PresShell::PostAttributeChange(nsIContent* aContent,
05313                                PRInt32 aNameSpaceID, 
05314                                nsIAtom* aName,
05315                                const nsString& aValue,
05316                                PRBool aNotify,
05317                                nsAttributeChangeType aType)
05318 {
05319  // ok we have a list of events to handle. Queue them up and handle them
05320  // after we finish reflow.
05321   nsAttributeChangeRequest* request = nsnull;
05322 
05323   void* result = AllocateFrame(sizeof(nsAttributeChangeRequest));
05324   request = new (result) nsAttributeChangeRequest();
05325 
05326   request->content = aContent;
05327   NS_ADDREF(aContent);
05328 
05329   request->nameSpaceID = aNameSpaceID;
05330   request->name = aName;
05331   request->value = aValue;
05332   request->notify = aNotify;
05333   request->type = aType;
05334   request->next = nsnull;
05335 
05336   if (mLastAttributeRequest) {
05337     mLastAttributeRequest = mLastAttributeRequest->next = request;
05338   } else {
05339     mFirstAttributeRequest = request;
05340     mLastAttributeRequest = request;
05341   }
05342 
05343   return NS_OK;
05344 }
05345 
05346 
05347 void
05348 PresShell::HandlePostedReflowCallbacks()
05349 {
05350    PRBool shouldFlush = PR_FALSE;
05351 
05352    while (mFirstCallbackEventRequest) {
05353      nsCallbackEventRequest* node = mFirstCallbackEventRequest;
05354      mFirstCallbackEventRequest = node->next;
05355      if (!mFirstCallbackEventRequest) {
05356        mLastCallbackEventRequest = nsnull;
05357      }
05358      nsIReflowCallback* callback = node->callback;
05359      FreeFrame(sizeof(nsCallbackEventRequest), node);
05360      if (callback)
05361        callback->ReflowFinished(this, &shouldFlush);
05362      NS_IF_RELEASE(callback);
05363    }
05364 
05365    if (shouldFlush)
05366      FlushPendingNotifications(Flush_Layout);
05367 }
05368 
05369 void
05370 PresShell::HandlePostedDOMEvents()
05371 {
05372    while(mFirstDOMEventRequest)
05373    {
05374       /* pull the node from the event request list. Be prepared for reentrant access to the list
05375          from within HandleDOMEvent and its callees! */
05376       nsDOMEventRequest* node = mFirstDOMEventRequest;
05377       nsEventStatus status = nsEventStatus_eIgnore;
05378 
05379       mFirstDOMEventRequest = node->next;
05380       if (nsnull == mFirstDOMEventRequest) {
05381         mLastDOMEventRequest = nsnull;
05382       }
05383 
05384       node->content->HandleDOMEvent(mPresContext, node->event, nsnull, NS_EVENT_FLAG_INIT, &status);
05385       NS_RELEASE(node->content);
05386       delete node->event;
05387       node->nsDOMEventRequest::~nsDOMEventRequest(); // doesn't do anything, but just in case
05388       FreeFrame(sizeof(nsDOMEventRequest), node);
05389    }
05390 }
05391 
05392 void
05393 PresShell::HandlePostedAttributeChanges()
05394 {
05395    while(mFirstAttributeRequest)
05396    {
05397       /* pull the node from the request list. Be prepared for reentrant access to the list
05398          from within SetAttribute/UnsetAttribute and its callees! */
05399       nsAttributeChangeRequest* node = mFirstAttributeRequest;
05400 
05401       mFirstAttributeRequest = node->next;
05402       if (nsnull == mFirstAttributeRequest) {
05403         mLastAttributeRequest = nsnull;
05404       }
05405 
05406       if (node->type == eChangeType_Set)
05407          node->content->SetAttr(node->nameSpaceID, node->name, node->value, node->notify);   
05408       else
05409          node->content->UnsetAttr(node->nameSpaceID, node->name, node->notify);   
05410 
05411       NS_RELEASE(node->content);
05412       node->nsAttributeChangeRequest::~nsAttributeChangeRequest();
05413       FreeFrame(sizeof(nsAttributeChangeRequest), node);
05414    }
05415 }
05416 
05417 NS_IMETHODIMP 
05418 PresShell::IsSafeToFlush(PRBool& aIsSafeToFlush)
05419 {
05420   aIsSafeToFlush = PR_TRUE;
05421 
05422   if (mIsReflowing || mChangeNestCount) {
05423     // Not safe if we are reflowing or in the middle of frame construction
05424     aIsSafeToFlush = PR_FALSE;
05425   } else {
05426     // Not safe if we are painting
05427     nsIViewManager* viewManager = GetViewManager();
05428     if (viewManager) {
05429       PRBool isPainting = PR_FALSE;
05430       viewManager->IsPainting(isPainting);
05431       if (isPainting) {
05432         aIsSafeToFlush = PR_FALSE;
05433       }
05434     }
05435   }
05436   return NS_OK;
05437 }
05438 
05439 
05440 NS_IMETHODIMP 
05441 PresShell::FlushPendingNotifications(mozFlushType aType)
05442 {
05443   NS_ASSERTION(aType & (Flush_StyleReresolves | Flush_OnlyReflow |
05444                         Flush_OnlyPaint),
05445                "Why did we get called?");
05446   
05447   PRBool isSafeToFlush;
05448   IsSafeToFlush(isSafeToFlush);
05449 
05450   NS_ASSERTION(!isSafeToFlush || mViewManager, "Must have view manager");
05451   // Make sure the view manager stays alive while batching view updates.
05452   nsCOMPtr<nsIViewManager> viewManager = mViewManager;
05453   if (isSafeToFlush && viewManager) {
05454 
05455     // Style reresolves not in conjunction with reflows can't cause
05456     // painting or geometry changes, so don't bother with view update
05457     // batching if we only have style reresolve
05458     viewManager->BeginUpdateViewBatch();
05459 
05460     if (aType & Flush_StyleReresolves) {
05461       // Processing pending restyles can kill us, and some callers only
05462       // hold weak refs when calling FlushPendingNotifications().  :(
05463       nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
05464       mFrameConstructor->ProcessPendingRestyles();
05465       if (mIsDestroying) {
05466         // We no longer have a view manager and all that.
05467         // XXX FIXME: Except we're in the middle of a view update batch...  We
05468         // need to address that somehow.  See bug 369165.
05469         return NS_OK;
05470       }
05471 
05472       mDocument->BindingManager()->ProcessAttachedQueue();
05473       if (mIsDestroying) {
05474         // We no longer have a view manager and all that.
05475         // XXX FIXME: Except we're in the middle of a view update batch...  We
05476         // need to address that somehow.  See bug 369165.
05477         return NS_OK;
05478       }
05479     }
05480 
05481     if (aType & Flush_OnlyReflow) {
05482       mFrameConstructor->RecalcQuotesAndCounters();
05483       ProcessReflowCommands(PR_FALSE);
05484     }
05485 
05486     PRUint32 updateFlags = NS_VMREFRESH_NO_SYNC;
05487     if (aType & Flush_OnlyPaint) {
05488       // Flushing paints, so perform the invalidates and drawing
05489       // immediately
05490       updateFlags = NS_VMREFRESH_IMMEDIATE;
05491     }
05492     else if (!(aType & Flush_OnlyReflow)) {
05493       // Not flushing reflows, so do deferred invalidates.  This will keep us
05494       // from possibly flushing out reflows due to invalidates being processed
05495       // at the end of this view batch.
05496       updateFlags = NS_VMREFRESH_DEFERRED;
05497     }
05498     viewManager->EndUpdateViewBatch(updateFlags);
05499   }
05500 
05501   return NS_OK;
05502 }
05503 
05504 NS_IMETHODIMP
05505 PresShell::IsReflowLocked(PRBool* aIsReflowLocked) 
05506 {
05507   *aIsReflowLocked = mIsReflowing;
05508   return NS_OK;
05509 }
05510 
05511 NS_IMETHODIMP 
05512 PresShell::BeginReflowBatching()
05513 {  
05514   mBatchReflows = PR_TRUE;
05515   return NS_OK;
05516 }
05517 
05518 NS_IMETHODIMP 
05519 PresShell::EndReflowBatching(PRBool aFlushPendingReflows)
05520 {  
05521   nsresult rv = NS_OK;
05522   mBatchReflows = PR_FALSE;
05523   if (aFlushPendingReflows) {
05524     rv = FlushPendingNotifications(Flush_OnlyReflow);
05525   }
05526   else {
05527     PostReflowEvent();
05528   }
05529   return rv;
05530 }
05531 
05532 
05533 NS_IMETHODIMP
05534 PresShell::GetReflowBatchingStatus(PRBool* aIsBatching)
05535 {
05536   *aIsBatching = mBatchReflows;
05537   return NS_OK;
05538 }
05539 
05540 void
05541 PresShell::CharacterDataChanged(nsIDocument *aDocument,
05542                                 nsIContent*  aContent,
05543                                 PRBool aAppend)
05544 {
05545   NS_PRECONDITION(!mIsDocumentGone, "Unexpected CharacterDataChanged");
05546   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
05547 
05548   WillCauseReflow();
05549   mFrameConstructor->CharacterDataChanged(aContent, aAppend);
05550   VERIFY_STYLE_TREE;
05551   DidCauseReflow();
05552 }
05553 
05554 void
05555 PresShell::ContentStatesChanged(nsIDocument* aDocument,
05556                                 nsIContent* aContent1,
05557                                 nsIContent* aContent2,
05558                                 PRInt32 aStateMask)
05559 {
05560   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentStatesChanged");
05561   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
05562 
05563   WillCauseReflow();
05564   mFrameConstructor->ContentStatesChanged(aContent1, aContent2, aStateMask);
05565   VERIFY_STYLE_TREE;
05566   DidCauseReflow();
05567 }
05568 
05569 
05570 void
05571 PresShell::AttributeChanged(nsIDocument *aDocument,
05572                             nsIContent*  aContent,
05573                             PRInt32      aNameSpaceID,
05574                             nsIAtom*     aAttribute,
05575                             PRInt32      aModType)
05576 {
05577   NS_PRECONDITION(!mIsDocumentGone, "Unexpected AttributeChanged");
05578   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
05579 
05580   NS_PRESSHELL_NOTIFY_OBSERVERS(AttributeChanged, 
05581                                 (aDocument, aContent, aNameSpaceID,
05582                                  aAttribute, aModType));
05583 
05584   // XXXwaterson it might be more elegant to wait until after the
05585   // initial reflow to begin observing the document. That would
05586   // squelch any other inappropriate notifications as well.
05587   if (mDidInitialReflow) {
05588     WillCauseReflow();
05589     mFrameConstructor->AttributeChanged(aContent, aNameSpaceID,
05590                                         aAttribute, aModType);
05591     VERIFY_STYLE_TREE;
05592     DidCauseReflow();
05593   }
05594 }
05595 
05596 void
05597 PresShell::ContentAppended(nsIDocument *aDocument,
05598                            nsIContent* aContainer,
05599                            PRInt32     aNewIndexInContainer)
05600 {
05601   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentAppended");
05602   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
05603   
05604   NS_PRESSHELL_NOTIFY_OBSERVERS(ContentAppended,
05605                                 (aDocument, aContainer,
05606                                  aNewIndexInContainer));
05607 
05608   if (!mDidInitialReflow) {
05609     return;
05610   }
05611   
05612   WillCauseReflow();
05613   MOZ_TIMER_DEBUGLOG(("Start: Frame Creation: PresShell::ContentAppended(), this=%p\n", this));
05614   MOZ_TIMER_START(mFrameCreationWatch);
05615 
05616   mFrameConstructor->ContentAppended(aContainer, aNewIndexInContainer);
05617   VERIFY_STYLE_TREE;
05618 
05619   MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::ContentAppended(), this=%p\n", this));
05620   MOZ_TIMER_STOP(mFrameCreationWatch);
05621   DidCauseReflow();
05622 }
05623 
05624 void
05625 PresShell::ContentInserted(nsIDocument* aDocument,
05626                            nsIContent*  aContainer,
05627                            nsIContent*  aChild,
05628                            PRInt32      aIndexInContainer)
05629 {
05630   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentInserted");
05631   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
05632 
05633   NS_PRESSHELL_NOTIFY_OBSERVERS(ContentInserted,
05634                                 (aDocument, aContainer, aChild,
05635                                  aIndexInContainer));
05636   
05637   if (!mDidInitialReflow) {
05638     return;
05639   }
05640   
05641   WillCauseReflow();
05642   mFrameConstructor->ContentInserted(aContainer, nsnull, aChild,
05643                                      aIndexInContainer, nsnull, PR_FALSE);
05644   VERIFY_STYLE_TREE;
05645   DidCauseReflow();
05646 }
05647 
05648 void
05649 PresShell::ContentRemoved(nsIDocument *aDocument,
05650                           nsIContent* aContainer,
05651                           nsIContent* aChild,
05652                           PRInt32     aIndexInContainer)
05653 {
05654   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentRemoved");
05655   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
05656 
05657   NS_PRESSHELL_NOTIFY_OBSERVERS(ContentRemoved,
05658                                 (aDocument, aContainer, aChild, 
05659                                  aIndexInContainer));
05660 
05661   // XXX fix for bug 304383. Remove when bug 287813 is fixed?
05662   if (mCaret) {
05663     nsIFrame* frame = nsnull;
05664     GetPrimaryFrameFor(aChild, &frame);
05665     if (frame && (frame->GetStateBits() & NS_FRAME_EXTERNAL_REFERENCE)) {
05666       mCaret->EraseCaret();
05667     }
05668   }
05669 
05670   // Notify the ESM that the content has been removed, so that
05671   // it can clean up any state related to the content.
05672   mPresContext->EventStateManager()->ContentRemoved(aChild);
05673 
05674   WillCauseReflow();
05675   mFrameConstructor->ContentRemoved(aContainer, aChild,
05676                                     aIndexInContainer, PR_FALSE);
05677 
05678   // If we have no root content node at this point, be sure to reset
05679   // mDidInitialReflow to PR_FALSE, this will allow InitialReflow()
05680   // to be called again should a new root node be inserted for this
05681   // presShell. (Bug 167355)
05682 
05683   if (mDocument && !mDocument->GetRootContent())
05684     mDidInitialReflow = PR_FALSE;
05685 
05686   VERIFY_STYLE_TREE;
05687   DidCauseReflow();
05688 }
05689 
05690 nsresult
05691 PresShell::ReconstructFrames(void)
05692 {
05693   nsresult rv = NS_OK;
05694           
05695   WillCauseReflow();
05696   rv = mFrameConstructor->ReconstructDocElementHierarchy();
05697   VERIFY_STYLE_TREE;
05698   DidCauseReflow();
05699 
05700   return rv;
05701 }
05702 
05703 void
05704 nsIPresShell::ReconstructStyleDataInternal()
05705 {
05706   if (NS_UNLIKELY(NS_STATIC_CAST(PresShell*, this)->mIsDestroying))
05707     return;
05708 
05709   mStylesHaveChanged = PR_FALSE;
05710 
05711   if (!mDidInitialReflow) {
05712     // Nothing to do here, since we have no frames yet
05713     return;
05714   }
05715 
05716   nsIContent* root = mDocument->GetRootContent();
05717   if (!root) {
05718     // No content to restyle
05719     return;
05720   }
05721   
05722   mFrameConstructor->PostRestyleEvent(root, eReStyle_Self, NS_STYLE_HINT_NONE);
05723 
05724 #ifdef ACCESSIBILITY
05725   InvalidateAccessibleSubtree(nsnull);
05726 #endif
05727 }
05728 
05729 void
05730 nsIPresShell::ReconstructStyleDataExternal()
05731 {
05732   if (NS_UNLIKELY(NS_STATIC_CAST(PresShell*, this)->mIsDestroying))
05733     return;
05734 
05735   ReconstructStyleDataInternal();
05736   FlushPendingNotifications(Flush_Style);
05737 }
05738 
05739 void
05740 PresShell::StyleSheetAdded(nsIDocument *aDocument,
05741                            nsIStyleSheet* aStyleSheet,
05742                            PRBool aDocumentSheet)
05743 {
05744   // We only care when enabled sheets are added
05745   NS_PRECONDITION(aStyleSheet, "Must have a style sheet!");
05746   PRBool applicable;
05747   aStyleSheet->GetApplicable(applicable);
05748 
05749   if (applicable && aStyleSheet->HasRules()) {
05750     mStylesHaveChanged = PR_TRUE;
05751   }
05752 }
05753 
05754 void 
05755 PresShell::StyleSheetRemoved(nsIDocument *aDocument,
05756                              nsIStyleSheet* aStyleSheet,
05757                              PRBool aDocumentSheet)
05758 {
05759   // We only care when enabled sheets are removed
05760   NS_PRECONDITION(aStyleSheet, "Must have a style sheet!");
05761   PRBool applicable;
05762   aStyleSheet->GetApplicable(applicable);
05763   if (applicable && aStyleSheet->HasRules()) {
05764     mStylesHaveChanged = PR_TRUE;
05765   }
05766 }
05767 
05768 void
05769 PresShell::StyleSheetApplicableStateChanged(nsIDocument *aDocument,
05770                                             nsIStyleSheet* aStyleSheet,
05771                                             PRBool aApplicable)
05772 {
05773   if (aStyleSheet->HasRules()) {
05774     mStylesHaveChanged = PR_TRUE;
05775   }
05776 }
05777 
05778 void
05779 PresShell::StyleRuleChanged(nsIDocument *aDocument,
05780                             nsIStyleSheet* aStyleSheet,
05781                             nsIStyleRule* aOldStyleRule,
05782                             nsIStyleRule* aNewStyleRule)
05783 {
05784   mStylesHaveChanged = PR_TRUE;
05785 }
05786 
05787 void
05788 PresShell::StyleRuleAdded(nsIDocument *aDocument,
05789                           nsIStyleSheet* aStyleSheet,
05790                           nsIStyleRule* aStyleRule) 
05791 {
05792   mStylesHaveChanged = PR_TRUE;
05793 }
05794 
05795 void
05796 PresShell::StyleRuleRemoved(nsIDocument *aDocument,
05797                             nsIStyleSheet* aStyleSheet,
05798                             nsIStyleRule* aStyleRule) 
05799 {
05800   mStylesHaveChanged = PR_TRUE;
05801 }
05802 
05803 NS_IMETHODIMP
05804 PresShell::GetPrimaryFrameFor(nsIContent* aContent,
05805                               nsIFrame**  aResult) const
05806 {
05807   *aResult = FrameManager()->GetPrimaryFrameFor(aContent);
05808   return NS_OK;
05809 }
05810 
05811 NS_IMETHODIMP
05812 PresShell::GetLayoutObjectFor(nsIContent*   aContent,
05813                               nsISupports** aResult) const 
05814 {
05815   nsresult result = NS_ERROR_NULL_POINTER;
05816   if ((nsnull!=aResult) && (nsnull!=aContent))
05817   {
05818     *aResult = nsnull;
05819     nsIFrame *primaryFrame=nsnull;
05820     result = GetPrimaryFrameFor(aContent, &primaryFrame);
05821     if ((NS_SUCCEEDED(result)) && (nsnull!=primaryFrame))
05822     {
05823       result = primaryFrame->QueryInterface(NS_GET_IID(nsISupports),
05824                                             (void**)aResult);
05825     }
05826   }
05827   return result;
05828 }
05829 
05830 NS_IMETHODIMP
05831 PresShell::GetPlaceholderFrameFor(nsIFrame*  aFrame,
05832                                   nsIFrame** aResult) const
05833 {
05834   *aResult = FrameManager()->GetPlaceholderFrameFor(aFrame);
05835   return NS_OK;
05836 }
05837 
05838 #ifdef IBMBIDI
05839 NS_IMETHODIMP
05840 PresShell::SetCaretBidiLevel(PRUint8 aLevel)
05841 {
05842   // If the current level is undefined, we have just inserted new text.
05843   // In this case, we don't want to reset the keyboard language
05844   PRBool afterInsert = mBidiLevel & BIDI_LEVEL_UNDEFINED;
05845   mBidiLevel = aLevel;
05846 
05847 //  PRBool parityChange = ((mBidiLevel ^ aLevel) & 1); // is the parity of the new level different from the current level?
05848 //  if (parityChange)                                  // if so, change the keyboard language
05849   if (mBidiKeyboard && !afterInsert)
05850     mBidiKeyboard->SetLangFromBidiLevel(aLevel);
05851   return NS_OK;
05852 }
05853 
05854 NS_IMETHODIMP
05855 PresShell::GetCaretBidiLevel(PRUint8 *aOutLevel)
05856 {
05857   if (!aOutLevel) { return NS_ERROR_INVALID_ARG; }
05858   *aOutLevel = mBidiLevel;
05859   return NS_OK;    
05860 }
05861 
05862 NS_IMETHODIMP
05863 PresShell::UndefineCaretBidiLevel()
05864 {
05865   mBidiLevel |= BIDI_LEVEL_UNDEFINED;
05866   return NS_OK;
05867 }
05868 
05869 NS_IMETHODIMP
05870 PresShell::BidiStyleChangeReflow()
05871 {
05872   // Have the root frame's style context remap its style
05873   nsIFrame* rootFrame = FrameManager()->GetRootFrame();
05874   if (rootFrame) {
05875     mStyleSet->ClearStyleData(mPresContext);
05876     ReconstructFrames();
05877   }
05878   return NS_OK;
05879 }
05880 #endif // IBMBIDI
05881 
05882 //nsIViewObserver
05883 
05884 // Return TRUE if any clipping is to be done.
05885 static PRBool ComputeClipRect(nsIFrame* aFrame, nsRect& aResult) {
05886   const nsStyleDisplay* display = aFrame->GetStyleDisplay();
05887   
05888   // 'clip' only applies to absolutely positioned elements, and is
05889   // relative to the element's border edge. 'clip' applies to the entire
05890   // element: border, padding, and content areas, and even scrollbars if
05891   // there are any.
05892   if (display->IsAbsolutelyPositioned() && (display->mClipFlags & NS_STYLE_CLIP_RECT)) {
05893     nsSize  size = aFrame->GetSize();
05894 
05895     // Start with the 'auto' values and then factor in user specified values
05896     nsRect  clipRect(0, 0, size.width, size.height);
05897 
05898     if (display->mClipFlags & NS_STYLE_CLIP_RECT) {
05899       if (0 == (NS_STYLE_CLIP_TOP_AUTO & display->mClipFlags)) {
05900         clipRect.y = display->mClip.y;
05901       }
05902       if (0 == (NS_STYLE_CLIP_LEFT_AUTO & display->mClipFlags)) {
05903         clipRect.x = display->mClip.x;
05904       }
05905       if (0 == (NS_STYLE_CLIP_RIGHT_AUTO & display->mClipFlags)) {
05906         clipRect.width = display->mClip.width;
05907       }
05908       if (0 == (NS_STYLE_CLIP_BOTTOM_AUTO & display->mClipFlags)) {
05909         clipRect.height = display->mClip.height;
05910       }
05911     }
05912 
05913     aResult = clipRect;
05914 
05915     return PR_TRUE;
05916   }
05917 
05918   return PR_FALSE;
05919 }
05920 
05921 // If the element is absolutely positioned and has a specified clip rect
05922 // then it pushes the current rendering context and sets the clip rect.
05923 // Returns PR_TRUE if the clip rect is set and PR_FALSE otherwise
05924 static PRBool
05925 SetClipRect(nsIRenderingContext& aRenderingContext, nsIFrame* aFrame)
05926 {
05927   nsRect clipRect;
05928 
05929   if (ComputeClipRect(aFrame, clipRect)) {
05930     // Set updated clip-rect into the rendering context
05931     aRenderingContext.PushState();
05932     aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect);
05933     return PR_TRUE;
05934   }
05935 
05936   return PR_FALSE;
05937 }
05938 
05939 static PRBool
05940 InClipRect(nsIFrame* aFrame, nsPoint& aEventPoint)
05941 {
05942   nsRect clipRect;
05943 
05944   if (ComputeClipRect(aFrame, clipRect)) {
05945     return clipRect.Contains(aEventPoint);
05946   } else {
05947     return PR_TRUE;
05948   }
05949 }
05950 
05951 NS_IMETHODIMP
05952 PresShell::Paint(nsIView              *aView,
05953                  nsIRenderingContext& aRenderingContext,
05954                  const nsRect&        aDirtyRect)
05955 {
05956   nsIFrame* frame;
05957   nsresult  rv = NS_OK;
05958 
05959   if (mIsDestroying) {
05960     NS_ASSERTION(PR_FALSE, "A paint message was dispatched to a destroyed PresShell");
05961     return NS_OK;
05962   }
05963 
05964   NS_ASSERTION(!(nsnull == aView), "null view");
05965 
05966   frame = NS_STATIC_CAST(nsIFrame*, aView->GetClientData());
05967      
05968   if (nsnull != frame)
05969   {
05970     if (mCaret)
05971       mCaret->EraseCaret();
05972 
05973     // If the frame is absolutely positioned, then the 'clip' property
05974     // applies
05975     PRBool  setClipRect = SetClipRect(aRenderingContext, frame);
05976 
05977     rv = frame->Paint(mPresContext, aRenderingContext, aDirtyRect,
05978                       NS_FRAME_PAINT_LAYER_BACKGROUND);
05979     rv = frame->Paint(mPresContext, aRenderingContext, aDirtyRect,
05980                       NS_FRAME_PAINT_LAYER_FLOATS);
05981     rv = frame->Paint(mPresContext, aRenderingContext, aDirtyRect,
05982                       NS_FRAME_PAINT_LAYER_FOREGROUND);
05983                       
05984     if (setClipRect)
05985       aRenderingContext.PopState();
05986 
05987 #ifdef NS_DEBUG
05988     // Draw a border around the frame
05989     if (nsIFrameDebug::GetShowFrameBorders()) {
05990       nsRect r = frame->GetRect();
05991       aRenderingContext.SetColor(NS_RGB(0,0,255));
05992       aRenderingContext.DrawRect(0, 0, r.width, r.height);
05993     }
05994     // Draw a border around the current event target
05995     if ((nsIFrameDebug::GetShowEventTargetFrameBorder()) && (aView == mCurrentTargetView)) {
05996       aRenderingContext.SetColor(NS_RGB(128,0,128));
05997       aRenderingContext.DrawRect(mCurrentTargetRect.x, mCurrentTargetRect.y, mCurrentTargetRect.width, mCurrentTargetRect.height);
05998     }
05999 #endif
06000   }
06001 
06002   return rv;
06003 }
06004 
06005 nsIFrame*
06006 PresShell::GetCurrentEventFrame()
06007 {
06008   if (!mCurrentEventFrame && mCurrentEventContent) {
06009     // Make sure the content still has a document reference. If not,
06010     // then we assume it is no longer in the content tree and the
06011     // frame shouldn't get an event, nor should we even assume its
06012     // safe to try and find the frame.
06013     if (mCurrentEventContent->GetDocument()) {
06014       GetPrimaryFrameFor(mCurrentEventContent, &mCurrentEventFrame);
06015     }
06016   }
06017 
06018   return mCurrentEventFrame;
06019 }
06020 
06021 NS_IMETHODIMP
06022 PresShell::GetEventTargetFrame(nsIFrame** aFrame)
06023 {
06024   *aFrame = GetCurrentEventFrame();
06025   return NS_OK;
06026 }
06027 
06028 NS_IMETHODIMP
06029 PresShell::GetEventTargetContent(nsEvent* aEvent, nsIContent** aContent)
06030 {
06031   if (mCurrentEventContent) {
06032     *aContent = mCurrentEventContent;
06033     NS_IF_ADDREF(*aContent);
06034   } else {
06035     nsIFrame* currentEventFrame = GetCurrentEventFrame();
06036     if (currentEventFrame) {
06037       currentEventFrame->GetContentForEvent(mPresContext, aEvent, aContent);
06038     } else {
06039       *aContent = nsnull;
06040     }
06041   }
06042   return NS_OK;
06043 }
06044 
06045 void
06046 PresShell::PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent)
06047 {
06048   if (mCurrentEventFrame || mCurrentEventContent) {
06049     mCurrentEventFrameStack.InsertElementAt((void*)mCurrentEventFrame, 0);
06050     mCurrentEventContentStack.InsertObjectAt(mCurrentEventContent, 0);
06051   }
06052   mCurrentEventFrame = aFrame;
06053   mCurrentEventContent = aContent;
06054 }
06055 
06056 void
06057 PresShell::PopCurrentEventInfo()
06058 {
06059   mCurrentEventFrame = nsnull;
06060   mCurrentEventContent = nsnull;
06061 
06062   if (0 != mCurrentEventFrameStack.Count()) {
06063     mCurrentEventFrame = (nsIFrame*)mCurrentEventFrameStack.ElementAt(0);
06064     mCurrentEventFrameStack.RemoveElementAt(0);
06065     mCurrentEventContent = mCurrentEventContentStack.ObjectAt(0);
06066     mCurrentEventContentStack.RemoveObjectAt(0);
06067   }
06068 }
06069 
06070 PRBool PresShell::InZombieDocument(nsIContent *aContent)
06071 {
06072   // If a content node points to a null document, or the document is not
06073   // attached to a window, then it is possibly in a zombie document,
06074   // about to be replaced by a newly loading document.
06075   // Such documents cannot handle DOM events.
06076   // It might actually be in a node not attached to any document,
06077   // in which case there is not parent presshell to retarget it to.
06078   nsIDocument *doc = aContent->GetDocument();
06079   return !doc || !doc->GetScriptGlobalObject();
06080 }
06081 
06082 nsresult PresShell::RetargetEventToParent(nsIView         *aView,
06083                                           nsGUIEvent*     aEvent,
06084                                           nsEventStatus*  aEventStatus,
06085                                           PRBool          aForceHandle,
06086                                           PRBool&         aHandled,
06087                                           nsIContent*     aZombieFocusedContent)
06088 {
06089   // Send this events straight up to the parent pres shell.
06090   // We do this for non-mouse events in zombie documents.
06091   // That way at least the UI key bindings can work.
06092 
06093   // First, eliminate the focus ring in the current docshell, which 
06094   // is  now a zombie. If we key navigate, it won't be within this
06095   // docshell, until the newly loading document is displayed.
06096 
06097   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
06098   // hold a reference to the ESM across event dispatch
06099   nsCOMPtr<nsIEventStateManager> esm = mPresContext->EventStateManager();
06100 
06101   esm->SetContentState(nsnull, NS_EVENT_STATE_FOCUS);
06102   esm->SetFocusedContent(nsnull);
06103   ContentStatesChanged(mDocument, aZombieFocusedContent,
06104                        nsnull, NS_EVENT_STATE_FOCUS);
06105 
06106   // Next, update the display so the old focus ring is no longer visible
06107 
06108   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
06109   if (!container)
06110     container = do_QueryReferent(mForwardingContainer);
06111 
06112   nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
06113   if (!docShell) {
06114     // We don't have any place to send this event.
06115     NS_WARNING("dropping event, no forwarding shell");
06116     return NS_OK;
06117   }
06118 
06119   nsCOMPtr<nsIContentViewer> contentViewer;
06120   docShell->GetContentViewer(getter_AddRefs(contentViewer));
06121   if (contentViewer) {
06122     nsCOMPtr<nsIContentViewer> zombieViewer;
06123     contentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
06124     if (zombieViewer) {
06125       zombieViewer->Show();
06126     }
06127   }
06128 
06129   // Now, find the parent pres shell and send the event there
06130   nsCOMPtr<nsIDocShellTreeItem> treeItem = 
06131     do_QueryInterface(container);
06132   NS_ASSERTION(treeItem, "No tree item for container.");
06133   nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
06134   treeItem->GetParent(getter_AddRefs(parentTreeItem));
06135   nsCOMPtr<nsIDocShell> parentDocShell = 
06136     do_QueryInterface(parentTreeItem);
06137   if (!parentDocShell || treeItem == parentTreeItem) {
06138     return NS_ERROR_FAILURE;
06139   }
06140 
06141   nsCOMPtr<nsIPresShell> parentPresShell;
06142   parentDocShell->GetPresShell(getter_AddRefs(parentPresShell));
06143   nsCOMPtr<nsIViewObserver> parentViewObserver = 
06144     do_QueryInterface(parentPresShell);
06145   if (!parentViewObserver) {
06146     return NS_ERROR_FAILURE;
06147   }
06148 
06149   PopCurrentEventInfo();
06150   return parentViewObserver->HandleEvent(aView, aEvent, 
06151                                          aEventStatus,
06152                                          aForceHandle, 
06153                                          aHandled);
06154 }
06155 
06156 NS_IMETHODIMP
06157 PresShell::HandleEvent(nsIView         *aView,
06158                        nsGUIEvent*     aEvent,
06159                        nsEventStatus*  aEventStatus,
06160                        PRBool          aForceHandle,
06161                        PRBool&         aHandled)
06162 {
06163   NS_ASSERTION(aView, "null view");
06164   aHandled = PR_TRUE;
06165 
06166   if (mIsDestroying || mIsReflowing || mChangeNestCount) {
06167     return NS_OK;
06168   }
06169 
06170 #ifdef ACCESSIBILITY
06171   if (aEvent->eventStructType == NS_ACCESSIBLE_EVENT) {
06172     return HandleEventInternal(aEvent, aView,
06173                                NS_EVENT_FLAG_INIT, aEventStatus);
06174   }
06175 #endif
06176 
06177   // Check for a theme change up front, since the frame type is irrelevant
06178   if (aEvent->message == NS_THEMECHANGED && mPresContext) {
06179     mPresContext->ThemeChanged();
06180     return NS_OK;
06181   }
06182 
06183   // Check for a system color change up front, since the frame type is
06184   // irrelevant
06185   if ((aEvent->message == NS_SYSCOLORCHANGED) && mPresContext) {
06186     nsIViewManager* vm = GetViewManager();
06187     if (vm) {
06188       // Only dispatch system color change when the message originates from
06189       // from the root views widget. This is necessary to prevent us from 
06190       // dispatching the SysColorChanged notification for each child window 
06191       // which may be redundant.
06192       nsIView *view;
06193       vm->GetRootView(view);
06194       if (view == aView) {
06195         aHandled = PR_TRUE;
06196         *aEventStatus = nsEventStatus_eConsumeDoDefault;
06197         mPresContext->SysColorChanged();
06198         return NS_OK;
06199       }
06200     }
06201     return NS_OK;
06202   }
06203 
06204   nsIFrame* frame = NS_STATIC_CAST(nsIFrame*, aView->GetClientData());
06205 
06206   // if this event has no frame, we need to retarget it at a parent
06207   // view that has a frame.
06208   if (!frame &&
06209       ((NS_IS_KEY_EVENT(aEvent) || NS_IS_IME_EVENT(aEvent)))) {
06210     nsIView* targetView = aView;
06211     while (targetView && !targetView->GetClientData()) {
06212       targetView = targetView->GetParent();
06213     }
06214     
06215     if (targetView) {
06216       aEvent->point += aView->GetOffsetTo(targetView);
06217       aView = targetView;
06218       frame = NS_STATIC_CAST(nsIFrame*, aView->GetClientData());
06219     }
06220   }
06221 
06222   nsresult rv = NS_OK;
06223   
06224   if (frame) {
06225     PushCurrentEventInfo(nsnull, nsnull);
06226 
06227     // key and IME events go to the focused frame
06228     nsCOMPtr<nsIEventStateManager> manager;
06229     if ((NS_IS_KEY_EVENT(aEvent) || NS_IS_IME_EVENT(aEvent) ||
06230          aEvent->message == NS_CONTEXTMENU_KEY)) {
06231 
06232       nsIEventStateManager *esm = mPresContext->EventStateManager();
06233 
06234       esm->GetFocusedFrame(&mCurrentEventFrame);
06235       if (mCurrentEventFrame) {
06236         esm->GetFocusedContent(getter_AddRefs(mCurrentEventContent));
06237       }
06238       else {
06239 #if defined(MOZ_X11) || defined(XP_WIN)
06240 #if defined(MOZ_X11)
06241         if (NS_IS_IME_EVENT(aEvent)) {
06242           // bug 52416 (MOZ_X11)
06243           // Lookup region (candidate window) of UNIX IME grabs
06244           // input focus from Mozilla but wants to send IME event
06245           // to redraw pre-edit (composed) string
06246           // If Mozilla does not have input focus and event is IME,
06247           // sends IME event to pre-focused element
06248 #else
06249         if (NS_IS_KEY_EVENT(aEvent) || NS_IS_IME_EVENT(aEvent)) {
06250           // bug 292263 (XP_WIN)
06251           // If software keyboard has focus, it may send the key messages and
06252           // the IME messages to pre-focused window. Therefore, if Mozilla
06253           // doesn't have focus and event is key event or IME event, we should
06254           // send the events to pre-focused element.
06255 #endif /* defined(MOZ_X11) */
06256           nsCOMPtr<nsPIDOMWindow> ourWindow = do_QueryInterface(mDocument->GetScriptGlobalObject());
06257           if (ourWindow) {
06258             nsIFocusController *focusController =
06259               ourWindow->GetRootFocusController();
06260             if (focusController) {
06261               PRBool active = PR_FALSE;
06262               // check input focus is in Mozilla
06263               focusController->GetActive(&active);
06264               if (!active) {
06265                 // if not, search for pre-focused element
06266                 nsCOMPtr<nsIDOMElement> focusedElement;
06267                 focusController->GetFocusedElement(getter_AddRefs(focusedElement));
06268                 if (focusedElement) {
06269                   // get mCurrentEventContent from focusedElement
06270                   mCurrentEventContent = do_QueryInterface(focusedElement);
06271                 }
06272               }
06273             }
06274           }
06275         }
06276 #endif /* defined(MOZ_X11) || defined(XP_WIN) */
06277         if (!mCurrentEventContent) {
06278           mCurrentEventContent = mDocument->GetRootContent();
06279         }
06280         mCurrentEventFrame = nsnull; // XXXldb Isn't it already?
06281       }
06282       if (mCurrentEventContent && InZombieDocument(mCurrentEventContent)) {
06283         return RetargetEventToParent(aView, aEvent, aEventStatus, aForceHandle,
06284                                      aHandled, mCurrentEventContent);
06285       }
06286     }
06287     else if (!InClipRect(frame, aEvent->point)) {
06288       // we only check for the clip rect on this frame ... all frames with clip
06289       // have views so any viewless children of this frame cannot have clip. 
06290       // Furthermore if the event is not in the clip for this frame, then none
06291       // of the children can get it either.
06292       if (aForceHandle) {
06293         mCurrentEventFrame = frame;
06294       }
06295       else {
06296         mCurrentEventFrame = nsnull;
06297       }
06298       aHandled = PR_FALSE;
06299       rv = NS_OK;
06300     } else {
06301       // aEvent->point is relative to aView's upper left corner. We need
06302       // a point that is in the same coordinate system as frame's rect
06303       // so that the frame->mRect.Contains(aPoint) calls in 
06304       // GetFrameForPoint() work. The assumption here is that frame->GetView()
06305       // will return aView, and frame's parent view is aView's parent.
06306 
06307       nsPoint eventPoint = frame->GetPosition();
06308       eventPoint += aEvent->point;
06309 
06310       nsPoint originOffset;
06311       nsIView *view = nsnull;
06312       frame->GetOriginToViewOffset(originOffset, &view);
06313 
06314       NS_ASSERTION(view == aView, "view != aView");
06315       if (view == aView)
06316         eventPoint -= originOffset;
06317 
06318       rv = frame->GetFrameForPoint(eventPoint,
06319                                    NS_FRAME_PAINT_LAYER_FOREGROUND,
06320                                    &mCurrentEventFrame);
06321       if (NS_FAILED(rv)) {
06322         rv = frame->GetFrameForPoint(eventPoint,
06323                                      NS_FRAME_PAINT_LAYER_FLOATS,
06324                                      &mCurrentEventFrame);
06325         if (NS_FAILED(rv)) {
06326           rv = frame->GetFrameForPoint(eventPoint,
06327                                        NS_FRAME_PAINT_LAYER_BACKGROUND,
06328                                        &mCurrentEventFrame);
06329           if (NS_FAILED (rv)) {
06330             if (aForceHandle) {
06331               mCurrentEventFrame = frame;
06332             }
06333             else {
06334               mCurrentEventFrame = nsnull;
06335             }
06336             aHandled = PR_FALSE;
06337             rv = NS_OK;
06338           }
06339         }
06340       }
06341 
06342       if (mCurrentEventFrame) {
06343         nsCOMPtr<nsIContent> targetElement;
06344         mCurrentEventFrame->GetContentForEvent(mPresContext, aEvent,
06345                                                getter_AddRefs(targetElement));
06346 
06347         // If there is no content for this frame, target it anyway.  Some
06348         // frames can be targeted but do not have content, particularly
06349         // windows with scrolling off.
06350         if (targetElement) {
06351           // Bug 103055, bug 185889: mouse events apply to *elements*, not all
06352           // nodes.  Thus we get the nearest element parent here.
06353           // XXX we leave the frame the same even if we find an element
06354           // parent, so that the text frame will receive the event (selection
06355           // and friends are the ones who care about that anyway)
06356           //
06357           // We use weak pointers because during this tight loop, the node
06358           // will *not* go away.  And this happens on every mousemove.
06359           while (targetElement &&
06360                  !targetElement->IsContentOfType(nsIContent::eELEMENT)) {
06361             targetElement = targetElement->GetParent();
06362           }
06363 
06364           // If we found an element, target it.  Otherwise, target *nothing*.
06365           if (!targetElement) {
06366             mCurrentEventContent = nsnull;
06367             mCurrentEventFrame = nsnull;
06368           } else if (targetElement != mCurrentEventContent) {
06369             mCurrentEventContent = targetElement;
06370           }
06371         }
06372       }
06373 
06374     }
06375     if (GetCurrentEventFrame()) {
06376       rv = HandleEventInternal(aEvent, aView,
06377                                NS_EVENT_FLAG_INIT, aEventStatus);
06378     }
06379 
06380 #ifdef NS_DEBUG
06381     if ((nsIFrameDebug::GetShowEventTargetFrameBorder()) &&
06382         (GetCurrentEventFrame())) {
06383       nsIView *oldView = mCurrentTargetView;
06384       nsPoint offset(0,0);
06385       nsRect oldTargetRect(mCurrentTargetRect);
06386       mCurrentTargetRect = mCurrentEventFrame->GetRect();
06387       mCurrentTargetView = mCurrentEventFrame->GetView();
06388       if (!mCurrentTargetView ) {
06389         mCurrentEventFrame->GetOffsetFromView(offset, &mCurrentTargetView);
06390       }
06391       if (mCurrentTargetView) {
06392         mCurrentTargetRect.x = offset.x;
06393         mCurrentTargetRect.y = offset.y;
06394         // use aView or mCurrentTargetView??
06395         if ((mCurrentTargetRect != oldTargetRect) ||
06396             (mCurrentTargetView != oldView)) {
06397 
06398           nsIViewManager* vm = GetViewManager();
06399           if (vm) {
06400             vm->UpdateView(mCurrentTargetView,mCurrentTargetRect,0);
06401             if (oldView)
06402               vm->UpdateView(oldView,oldTargetRect,0);
06403           }
06404         }
06405       }
06406     }
06407 #endif
06408     PopCurrentEventInfo();
06409   }
06410   else {
06411     // Focus events need to be dispatched even if no frame was found, since
06412     // we don't want the focus controller to be out of sync.
06413 
06414     if (!NS_EVENT_NEEDS_FRAME(aEvent)) {
06415       mCurrentEventFrame = nsnull;
06416       return HandleEventInternal(aEvent, aView,
06417                                  NS_EVENT_FLAG_INIT, aEventStatus);
06418     }
06419     else if (NS_IS_KEY_EVENT(aEvent)) {
06420       // Keypress events in new blank tabs should not be completely thrown away.
06421       // Retarget them -- the parent chrome shell might make use of them.
06422       return RetargetEventToParent(aView, aEvent, aEventStatus, aForceHandle,
06423                                    aHandled, mCurrentEventContent);
06424     }
06425 
06426     aHandled = PR_FALSE;
06427   }
06428 
06429   return rv;
06430 }
06431 
06432 NS_IMETHODIMP
06433 PresShell::HandleEventWithTarget(nsEvent* aEvent, nsIFrame* aFrame, nsIContent* aContent, PRUint32 aFlags, nsEventStatus* aStatus)
06434 {
06435   nsresult ret;
06436 
06437   PushCurrentEventInfo(aFrame, aContent);
06438   ret = HandleEventInternal(aEvent, nsnull, aFlags, aStatus);
06439   PopCurrentEventInfo();
06440   return NS_OK;
06441 }
06442 
06443 inline PRBool
06444 IsSynthesizedMouseMove(nsEvent* aEvent)
06445 {
06446   return aEvent->eventStructType == NS_MOUSE_EVENT &&
06447          NS_STATIC_CAST(nsMouseEvent*, aEvent)->reason != nsMouseEvent::eReal;
06448 }
06449 
06450 nsresult
06451 PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView,
06452                                PRUint32 aFlags, nsEventStatus* aStatus)
06453 {
06454 #ifdef ACCESSIBILITY
06455   if (aEvent->eventStructType == NS_ACCESSIBLE_EVENT)
06456   {
06457     NS_STATIC_CAST(nsAccessibleEvent*, aEvent)->accessible = nsnull;
06458     nsCOMPtr<nsIAccessibilityService> accService = 
06459       do_GetService("@mozilla.org/accessibilityService;1");
06460     if (accService) {
06461       nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
06462       if (!container) {
06463         // This presshell is not active. This often happens when a
06464         // preshell is being held onto for fastback.
06465         return NS_OK;
06466       }
06467       nsIAccessible* acc;
06468       nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mDocument));
06469       NS_ASSERTION(domNode, "No dom node for doc");
06470       accService->GetAccessibleInShell(domNode, this, &acc);
06471       // Addref this - it's not a COM Ptr
06472       // We'll make sure the right number of Addref's occur before
06473       // handing this back to the accessibility client
06474       NS_STATIC_CAST(nsAccessibleEvent*, aEvent)->accessible = acc;
06475       mIsAccessibilityActive = PR_TRUE;
06476       return NS_OK;
06477     }
06478   }
06479 #endif
06480 
06481   nsCOMPtr<nsIEventStateManager> manager = mPresContext->EventStateManager();
06482   nsresult rv = NS_OK;
06483 
06484   // Grab the offset of aView from our root view.  We can use this to adjust
06485   // coordinates as needed.  Note that we can't just adjust them later, because
06486   // event dispatch can destroy aView.  Also note that at times aView is null
06487   // here.  When that happens, there isn't much we can do about getting
06488   // coordinates right....
06489   nsPoint offsetOfaView(0,0);
06490   if (aView) {
06491     nsIView* rootView;
06492     mViewManager->GetRootView(rootView);
06493     offsetOfaView = aView->GetOffsetTo(rootView);
06494   }
06495 
06496   if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame()) {
06497     PRBool isHandlingUserInput = PR_FALSE;
06498 
06499     if (aEvent->internalAppFlags & NS_APP_EVENT_FLAG_TRUSTED) {
06500       switch (aEvent->message) {
06501       case NS_GOTFOCUS:
06502       case NS_LOSTFOCUS:
06503       case NS_ACTIVATE:
06504       case NS_DEACTIVATE:
06505         // Treat focus/blur events as user input if they happen while
06506         // executing trusted script, or no script at all. If they
06507         // happen during execution of non-trusted script, then they
06508         // should not be considerd user input.
06509         if (!nsContentUtils::IsCallerChrome()) {
06510           break;
06511         }
06512       case NS_MOUSE_LEFT_BUTTON_DOWN:
06513       case NS_MOUSE_MIDDLE_BUTTON_DOWN:
06514       case NS_MOUSE_RIGHT_BUTTON_DOWN:
06515       case NS_MOUSE_LEFT_BUTTON_UP:
06516       case NS_MOUSE_RIGHT_BUTTON_UP:
06517       case NS_MOUSE_MIDDLE_BUTTON_UP:
06518       case NS_KEY_PRESS:
06519       case NS_KEY_DOWN:
06520       case NS_KEY_UP:
06521         isHandlingUserInput = PR_TRUE;
06522       }
06523     }
06524 
06525     nsAutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput);
06526 
06527     nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
06528 
06529     nsWeakView weakView(aView);
06530     // 1. Give event to event manager for pre event state changes and
06531     //    generation of synthetic events.
06532     rv = manager->PreHandleEvent(mPresContext, aEvent, mCurrentEventFrame,
06533                                  aStatus, aView);
06534 
06535     // 2. Give event to the DOM for third party and JS use.
06536     if ((GetCurrentEventFrame()) && NS_SUCCEEDED(rv)) {
06537       // We want synthesized mouse moves to cause mouseover and mouseout
06538       // DOM events (PreHandleEvent above), but not mousemove DOM events.
06539       if (!IsSynthesizedMouseMove(aEvent)) {
06540         if (mCurrentEventContent) {
06541           rv = mCurrentEventContent->HandleDOMEvent(mPresContext, aEvent, nsnull,
06542                                                     aFlags, aStatus);
06543         }
06544         else {
06545           nsCOMPtr<nsIContent> targetContent;
06546           rv = mCurrentEventFrame->GetContentForEvent(mPresContext, aEvent,
06547                                                       getter_AddRefs(targetContent));
06548           if (NS_SUCCEEDED(rv) && targetContent) {
06549             rv = targetContent->HandleDOMEvent(mPresContext, aEvent, nsnull, 
06550                                                aFlags, aStatus);
06551           }
06552         }
06553 
06554         // Stopping propagation in the default group does not affect
06555         // propagation in the system event group.
06556         // (see also section 1.2.2.6 of the DOM3 Events Working Draft)
06557 
06558         aEvent->flags &= ~NS_EVENT_FLAG_STOP_DISPATCH;
06559 
06560         // 3. Give event to the Frames for browser default processing.
06561         if (GetCurrentEventFrame() && NS_SUCCEEDED (rv) &&
06562             aEvent->eventStructType != NS_EVENT) {
06563           // If aView is non-null, adjust coordinates of aEvent to be in the
06564           // coordinate system of mCurrentEventFrame's closest view.  Don't use
06565           // aView here, since it may be dead by now.
06566           nsPoint offset(0,0);
06567           if (aView) {
06568             NS_ASSERTION(mViewManager,
06569                          "How did GetCurrentEventFrame() succeed?");
06570             nsIView* rootView;
06571             mViewManager->GetRootView(rootView);
06572             nsIView* frameView;
06573             nsPoint pt;
06574             mCurrentEventFrame->GetOffsetFromView(pt, &frameView);
06575             offset = frameView->GetOffsetTo(rootView) - offsetOfaView;
06576           }
06577   
06578           // Transform aEvent->point from aView's coordinate system to
06579           // that of mCurrentEventFrame's closest view
06580           aEvent->point -= offset;
06581   
06582           rv = mCurrentEventFrame->HandleEvent(mPresContext, (nsGUIEvent*)aEvent,
06583                                                aStatus);
06584           // Now transform back
06585           aEvent->point += offset;
06586         }
06587 
06588         // Continue with second dispatch to system event handlers.
06589 
06590         // Need to null check mCurrentEventContent and mCurrentEventFrame
06591         // since the previous dispatch could have nuked them.
06592         if (mCurrentEventContent) {
06593           rv = mCurrentEventContent->HandleDOMEvent(mPresContext, aEvent, nsnull,
06594                                                     aFlags | NS_EVENT_FLAG_SYSTEM_EVENT,
06595                                                     aStatus);
06596         }
06597         else if (mCurrentEventFrame) {
06598           nsCOMPtr<nsIContent> targetContent;
06599           rv = mCurrentEventFrame->GetContentForEvent(mPresContext, aEvent,
06600                                                       getter_AddRefs(targetContent));
06601           if (NS_SUCCEEDED(rv) && targetContent) {
06602             rv = targetContent->HandleDOMEvent(mPresContext, aEvent, nsnull, 
06603                                                aFlags | NS_EVENT_FLAG_SYSTEM_EVENT,
06604                                                aStatus);
06605           }
06606         }
06607       }
06608 
06609       // 4. Give event to event manager for post event state changes and
06610       //    generation of synthetic events.
06611       if (NS_SUCCEEDED (rv) &&
06612           (GetCurrentEventFrame() || !NS_EVENT_NEEDS_FRAME(aEvent))) {
06613         rv = manager->PostHandleEvent(mPresContext, aEvent, mCurrentEventFrame,
06614                                       aStatus, weakView.GetView());
06615       }
06616     }
06617   }
06618   return rv;
06619 }
06620 
06621 // Dispatch event to content only (NOT full processing)
06622 // See also HandleEventWithTarget which does full event processing.
06623 NS_IMETHODIMP
06624 PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent, nsEvent* aEvent, nsEventStatus* aStatus)
06625 {
06626   PushCurrentEventInfo(nsnull, aTargetContent);
06627 
06628   // Bug 41013: Check if the event should be dispatched to content.
06629   // It's possible that we are in the middle of destroying the window
06630   // and the js context is out of date. This check detects the case
06631   // that caused a crash in bug 41013, but there may be a better way
06632   // to handle this situation!
06633   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
06634   if (container) {
06635 
06636     // Dispatch event to content
06637     aTargetContent->HandleDOMEvent(mPresContext, aEvent, nsnull,
06638                                    NS_EVENT_FLAG_INIT, aStatus);
06639   }
06640 
06641   PopCurrentEventInfo();
06642   return NS_OK;
06643 }
06644 
06645 NS_IMETHODIMP
06646 PresShell::ResizeReflow(nsIView *aView, nscoord aWidth, nscoord aHeight)
06647 {
06648   return ResizeReflow(aWidth, aHeight);
06649 }
06650 
06651 NS_IMETHODIMP_(PRBool)
06652 PresShell::IsVisible()
06653 {
06654   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
06655   nsCOMPtr<nsIBaseWindow> bw = do_QueryInterface(container);
06656   if (!bw)
06657     return PR_FALSE;
06658   PRBool res = PR_TRUE;
06659   bw->GetVisibility(&res);
06660   return res;
06661 }
06662 
06663 NS_IMETHODIMP_(void)
06664 PresShell::WillPaint()
06665 {
06666   // Don't reenter reflow and don't reflow during frame construction.  Also
06667   // don't bother reflowing if some viewmanager in our tree is painting while
06668   // we still have painting suppressed.
06669   if (mIsReflowing || mChangeNestCount || mPaintingSuppressed) {
06670     return;
06671   }
06672   
06673   // Process reflows, if we have them, to reduce flicker due to invalidates and
06674   // reflow being interspersed.  Note that we _do_ allow this to be
06675   // interruptible; if we can't do all the reflows it's better to flicker a bit
06676   // than to freeze up.
06677   // XXXbz this update batch may not be strictly necessary, but it's good form.
06678   // XXXbz should we be flushing out style changes here?  Probably not, I'd say.
06679   NS_ASSERTION(mViewManager, "Something weird is going on");
06680   mViewManager->BeginUpdateViewBatch();
06681   ProcessReflowCommands(PR_TRUE);
06682   mViewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
06683 }
06684 
06685 nsresult
06686 PresShell::GetAgentStyleSheets(nsCOMArray<nsIStyleSheet>& aSheets)
06687 {
06688   aSheets.Clear();
06689   PRInt32 sheetCount = mStyleSet->SheetCount(nsStyleSet::eAgentSheet);
06690 
06691   for (PRInt32 i = 0; i < sheetCount; ++i) {
06692     nsIStyleSheet *sheet = mStyleSet->StyleSheetAt(nsStyleSet::eAgentSheet, i);
06693     if (!aSheets.AppendObject(sheet))
06694       return NS_ERROR_OUT_OF_MEMORY;
06695   }
06696 
06697   return NS_OK;
06698 }
06699 
06700 nsresult
06701 PresShell::SetAgentStyleSheets(const nsCOMArray<nsIStyleSheet>& aSheets)
06702 {
06703   return mStyleSet->ReplaceSheets(nsStyleSet::eAgentSheet, aSheets);
06704 }
06705 
06706 nsresult
06707 PresShell::AddOverrideStyleSheet(nsIStyleSheet *aSheet)
06708 {
06709   return mStyleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, aSheet);
06710 }
06711 
06712 nsresult
06713 PresShell::RemoveOverrideStyleSheet(nsIStyleSheet *aSheet)
06714 {
06715   return mStyleSet->RemoveStyleSheet(nsStyleSet::eOverrideSheet, aSheet);
06716 }
06717 
06718 static void
06719 StopPluginInstance(PresShell *aShell, nsIContent *aContent)
06720 {
06721   nsIFrame *frame = aShell->FrameManager()->GetPrimaryFrameFor(aContent);
06722 
06723   nsIObjectFrame *objectFrame = nsnull;
06724   if (frame)
06725     CallQueryInterface(frame, &objectFrame);
06726   if (!objectFrame)
06727     return;
06728 
06729   nsCOMPtr<nsIPluginInstance> instance;
06730   objectFrame->GetPluginInstance(*getter_AddRefs(instance));
06731   if (!instance)
06732     return;
06733 
06734   // Note on the frame that it used to have a plugin instance, since
06735   // we're about to make said instance go away
06736   frame->SetProperty(nsLayoutAtoms::objectFrame, NS_INT32_TO_PTR(1));
06737 
06738   // Check whether the plugin wants SetWindow to be called before or after
06739   // Stop/Destroy.  This is similar to nsObjectFrame::Destroy(), but we
06740   // don't want to destroy the frame just yet.
06741 
06742   PRBool callSetWindowLast = PR_FALSE;
06743   instance->GetValue(nsPluginInstanceVariable_CallSetWindowAfterDestroyBool,
06744                      (void *) &callSetWindowLast);
06745   if (callSetWindowLast) {
06746     instance->Stop();
06747     instance->Destroy();
06748     instance->SetWindow(nsnull);
06749   } else {
06750     instance->Stop();
06751     instance->SetWindow(nsnull);
06752     instance->Destroy();
06753   }
06754 
06755   // XXXbz have to use the plugin manager contract because the plugin host
06756   // registers for two different contracts with two difference CIDs!  We want
06757   // the plugin manager CID, since that's the one nsObjectFrame gets.
06758   nsCOMPtr<nsIPluginHost> pluginHost =
06759     do_GetService("@mozilla.org/plugin/manager;1");
06760   if (pluginHost)
06761     pluginHost->StopPluginInstance(instance);
06762 }
06763 
06764 PR_STATIC_CALLBACK(PRBool)
06765 FreezeSubDocument(nsIDocument *aDocument, void *aData)
06766 {
06767   nsIPresShell *shell = aDocument->GetShellAt(0);
06768   if (shell)
06769     shell->Freeze();
06770 
06771   return PR_TRUE;
06772 }
06773 
06774 void
06775 PresShell::Freeze()
06776 {
06777   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
06778   if (domDoc) {
06779     EnumeratePlugins(domDoc, NS_LITERAL_STRING("object"), StopPluginInstance);
06780     EnumeratePlugins(domDoc, NS_LITERAL_STRING("applet"), StopPluginInstance);
06781     EnumeratePlugins(domDoc, NS_LITERAL_STRING("embed"), StopPluginInstance);
06782   }
06783 
06784   if (mCaret)
06785     mCaret->SetCaretVisible(PR_FALSE);
06786 
06787   mPaintingSuppressed = PR_TRUE;
06788 
06789   if (mDocument)
06790     mDocument->EnumerateSubDocuments(FreezeSubDocument, nsnull);
06791 }
06792 
06793 static void
06794 StartPluginInstance(PresShell *aShell, nsIContent *aContent)
06795 {
06796   // For now we just reconstruct the frame, but only if the element
06797   // had a plugin instance before we stopped it.  Other types of
06798   // embedded content (eg SVG) become unhappy if we do a frame
06799   // reconstruct here.
06800   nsIFrame *frame = nsnull;
06801   aShell->GetPrimaryFrameFor(aContent, &frame);
06802   if (frame) {
06803     nsIObjectFrame *objFrame = nsnull;
06804     CallQueryInterface(frame, &objFrame);
06805     if (objFrame && frame->GetProperty(nsLayoutAtoms::objectFrame)) {
06806       // Note: no need to remove the property here, since we're about
06807       // to blow away the frame
06808       aShell->RecreateFramesFor(aContent);
06809     }
06810   }
06811 }
06812 
06813 PR_STATIC_CALLBACK(PRBool)
06814 ThawSubDocument(nsIDocument *aDocument, void *aData)
06815 {
06816   nsIPresShell *shell = aDocument->GetShellAt(0);
06817   if (shell)
06818     shell->Thaw();
06819 
06820   return PR_TRUE;
06821 }
06822 
06823 void
06824 PresShell::Thaw()
06825 {
06826   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
06827   if (domDoc) {
06828     EnumeratePlugins(domDoc, NS_LITERAL_STRING("object"), StartPluginInstance);
06829     EnumeratePlugins(domDoc, NS_LITERAL_STRING("applet"), StartPluginInstance);
06830     EnumeratePlugins(domDoc, NS_LITERAL_STRING("embed"), StartPluginInstance);
06831   }
06832 
06833   if (mDocument)
06834     mDocument->EnumerateSubDocuments(ThawSubDocument, nsnull);
06835 
06836   UnsuppressPainting();
06837 }
06838 
06839 void
06840 PresShell::HidePopups()
06841 {
06842   nsIViewManager *vm = GetViewManager();
06843   if (vm) {
06844     nsIView *rootView = nsnull;
06845     vm->GetRootView(rootView);
06846     if (rootView)
06847       HideViewIfPopup(rootView);
06848   }
06849 }
06850 
06851 void
06852 PresShell::BlockFlushing()
06853 {
06854   ++mChangeNestCount;
06855 }
06856 
06857 void
06858 PresShell::UnblockFlushing()
06859 {
06860   --mChangeNestCount;
06861 }
06862 
06863 // Based on nsDocument::AddObserver and nsDocumentObserverList::Contains
06864 void 
06865 PresShell::AddObserver(nsIDocumentObserver* aObserver)
06866 {
06867  if (mObservers.IndexOf(aObserver) == -1) {
06868     mObservers.AppendElement(aObserver);
06869   }
06870 }
06871 
06872 // Based on nsDocumentObserverList::RemoveElement
06873 PRBool
06874 PresShell::RemoveObserver(nsIDocumentObserver* aObserver)
06875 {
06876   PRInt32 index = mObservers.IndexOf(aObserver);
06877   if (index == -1) {
06878     return PR_FALSE;
06879   }
06880 
06881 #ifdef DEBUG
06882   PRBool removed =
06883 #endif
06884     mObservers.RemoveElementAt(index);
06885   NS_ASSERTION(removed, "How could we fail to remove by index?");
06886 
06887   return PR_TRUE;
06888 }
06889 
06890 //--------------------------------------------------------
06891 // Start of protected and private methods on the PresShell
06892 //--------------------------------------------------------
06893 
06894 //-------------- Begin Reflow Event Definition ------------------------
06895 
06896 struct ReflowEvent : public PLEvent {
06897   ReflowEvent(nsIPresShell* aPresShell);
06898   ~ReflowEvent() { }
06899 
06900   void HandleEvent() {    
06901     nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
06902     if (presShell) {
06903 #ifdef DEBUG
06904       if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
06905          printf("\n*** Handling reflow event: PresShell=%p, event=%p\n", (void*)presShell.get(), (void*)this);
06906       }
06907 #endif
06908       // XXX Statically cast the pres shell pointer so that we can call
06909       // protected methods on the pres shell. (the ReflowEvent struct
06910       // is a friend of the PresShell class)
06911       PresShell* ps = NS_REINTERPRET_CAST(PresShell*, presShell.get());
06912       PRBool isBatching;
06913       ps->ClearReflowEventStatus();
06914       ps->GetReflowBatchingStatus(&isBatching);
06915       if (!isBatching) {
06916         // Set a kung fu death grip on the view manager associated with the pres shell
06917         // before processing that pres shell's reflow commands.  Fixes bug 54868.
06918         nsCOMPtr<nsIViewManager> viewManager = presShell->GetViewManager();
06919 
06920         viewManager->BeginUpdateViewBatch();
06921         ps->ProcessReflowCommands(PR_TRUE);
06922         viewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
06923 
06924         // Now, explicitly release the pres shell before the view manager
06925         presShell = nsnull;
06926         viewManager = nsnull;
06927       }
06928     }
06929     else
06930       mPresShell = 0;
06931   }
06932   
06933   nsWeakPtr mPresShell;
06934 };
06935 
06936 static void PR_CALLBACK HandlePLEvent(ReflowEvent* aEvent)
06937 {
06938   aEvent->HandleEvent();
06939 }
06940 
06941 static void PR_CALLBACK DestroyPLEvent(ReflowEvent* aEvent)
06942 {
06943   delete aEvent;
06944 }
06945 
06946 
06947 ReflowEvent::ReflowEvent(nsIPresShell* aPresShell)
06948 {
06949   NS_ASSERTION(aPresShell, "Null parameters!");  
06950 
06951   mPresShell = do_GetWeakReference(aPresShell);
06952 
06953   PL_InitEvent(this, aPresShell,
06954                (PLHandleEventProc) ::HandlePLEvent,
06955                (PLDestroyEventProc) ::DestroyPLEvent);  
06956 }
06957 
06958 //-------------- End Reflow Event Definition ---------------------------
06959 
06960 
06961 void
06962 PresShell::PostReflowEvent()
06963 {
06964   nsCOMPtr<nsIEventQueue> eventQueue;
06965   mEventQueueService->GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
06966                                            getter_AddRefs(eventQueue));
06967 
06968   if (eventQueue != mReflowEventQueue && !mIsDestroying &&
06969       !mIsReflowing && mReflowCommands.Count() > 0) {
06970     ReflowEvent* ev = new ReflowEvent(NS_STATIC_CAST(nsIPresShell*, this));
06971     if (NS_FAILED(eventQueue->PostEvent(ev))) {
06972       NS_ERROR("failed to post reflow event");
06973       PL_DestroyEvent(ev);
06974     }
06975     else {
06976       mReflowEventQueue = eventQueue;
06977 #ifdef DEBUG
06978       if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
06979         printf("\n*** PresShell::PostReflowEvent(), this=%p, event=%p\n", (void*)this, (void*)ev);
06980       }
06981 #endif    
06982     }
06983   }
06984 }
06985 
06986 nsresult
06987 PresShell::DidCauseReflow()
06988 {
06989   NS_ASSERTION(mChangeNestCount != 0, "Unexpected call to DidCauseReflow()");
06990   if (--mChangeNestCount == 0) {
06991     // We may have had more reflow commands appended to the queue during
06992     // our reflow.  Make sure these get processed at some point.
06993     if (!gAsyncReflowDuringDocLoad && mDocumentLoading) {
06994       FlushPendingNotifications(Flush_Layout);
06995     } else {
06996       PostReflowEvent();
06997     }
06998   }
06999 
07000   return NS_OK;
07001 }
07002 
07003 void
07004 PresShell::DidDoReflow()
07005 {
07006   HandlePostedDOMEvents();
07007   HandlePostedAttributeChanges();
07008   HandlePostedReflowCallbacks();
07009   // Null-check mViewManager in case this happens during Destroy.  See
07010   // bugs 244435 and 238546.
07011   if (!mPaintingSuppressed && mViewManager)
07012     mViewManager->SynthesizeMouseMove(PR_FALSE);
07013 }
07014 
07015 nsresult
07016 PresShell::ProcessReflowCommands(PRBool aInterruptible)
07017 {
07018   MOZ_TIMER_DEBUGLOG(("Start: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this));
07019   MOZ_TIMER_START(mReflowWatch);  
07020 
07021   if (0 != mReflowCommands.Count()) {
07022     nsHTMLReflowMetrics   desiredSize(nsnull);
07023     nsCOMPtr<nsIRenderingContext> rcx;
07024     nsIFrame*             rootFrame = FrameManager()->GetRootFrame();
07025     nsSize          maxSize = rootFrame->GetSize();
07026 
07027     nsresult rv=CreateRenderingContext(rootFrame, getter_AddRefs(rcx));
07028     if (NS_FAILED(rv)) return rv;
07029 
07030 #ifdef DEBUG
07031     if (GetVerifyReflowEnable()) {
07032       if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
07033         printf("ProcessReflowCommands: begin incremental reflow\n");
07034       }
07035     }
07036     if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {   
07037       PRInt32 i, n = mReflowCommands.Count();
07038       printf("\nPresShell::ProcessReflowCommands: this=%p, count=%d\n", (void*)this, n);
07039       for (i = 0; i < n; i++) {
07040         nsHTMLReflowCommand* rc = (nsHTMLReflowCommand*)
07041           mReflowCommands.ElementAt(i);
07042         rc->List(stdout);
07043       }
07044     }
07045 #endif
07046 
07047     // If reflow is interruptible, then make a note of our deadline.
07048     const PRIntervalTime deadline = aInterruptible
07049         ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime)
07050         : (PRIntervalTime)0;
07051 
07052     // force flushing of any pending notifications
07053     mDocument->BeginUpdate(UPDATE_ALL);
07054     mDocument->EndUpdate(UPDATE_ALL);
07055 
07056     // That might have executed (via XBL binding constructors).  So we
07057     // may no longer have reflow commands.  In fact, we may have
07058     // gotten destroyed.
07059     if (!mIsDestroying && mReflowCommands.Count() != 0) {
07060       mIsReflowing = PR_TRUE;
07061 
07062       do {
07063         // Coalesce the reflow commands into a tree.
07064         IncrementalReflow reflow;
07065         for (PRInt32 i = mReflowCommands.Count() - 1; i >= 0; --i) {
07066           nsHTMLReflowCommand *command =
07067             NS_STATIC_CAST(nsHTMLReflowCommand *, mReflowCommands[i]);
07068 
07069           IncrementalReflow::AddCommandResult res =
07070             reflow.AddCommand(mPresContext, command);
07071           if (res == IncrementalReflow::eEnqueued ||
07072               res == IncrementalReflow::eCancel) {
07073             // Remove the command from the queue.
07074             mReflowCommands.RemoveElementAt(i);
07075             ReflowCommandRemoved(command);
07076             if (res == IncrementalReflow::eCancel)
07077               delete command;
07078           }
07079           else {
07080             // The reflow command couldn't be added to the tree; leave
07081             // it in the queue, and we'll handle it next time.
07082 #ifdef DEBUG
07083             printf("WARNING: Couldn't add reflow command, so splitting.\n");
07084 #endif
07085           }
07086         }
07087 
07088 #ifdef DEBUG
07089         if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
07090           printf("Incremental reflow tree:\n");
07091           reflow.Dump(mPresContext);
07092         }
07093 #endif
07094 
07095         // Dispatch an incremental reflow.
07096         reflow.Dispatch(mPresContext, desiredSize, maxSize, *rcx);
07097 
07098         // Keep going until we're out of reflow commands, or we've run
07099         // past our deadline.
07100       } while (mReflowCommands.Count() &&
07101                (!aInterruptible || PR_IntervalNow() < deadline));
07102 
07103       // XXXwaterson for interruptible reflow, examine the tree and
07104       // re-enqueue any unflowed reflow targets.
07105 
07106       mIsReflowing = PR_FALSE;
07107     }
07108     
07109     // If any new reflow commands were enqueued during the reflow,
07110     // schedule another reflow event to process them.
07111     if (mReflowCommands.Count())
07112       PostReflowEvent();
07113     
07114 #ifdef DEBUG
07115     if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
07116       printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n", (void*)this);
07117     }
07118 
07119     if (nsIFrameDebug::GetVerifyTreeEnable()) {
07120       nsIFrameDebug*  frameDebug;
07121 
07122       if (NS_SUCCEEDED(rootFrame->QueryInterface(NS_GET_IID(nsIFrameDebug),
07123                                                  (void**)&frameDebug))) {
07124         frameDebug->VerifyTree();
07125       }
07126     }
07127     if (GetVerifyReflowEnable()) {
07128       // First synchronously render what we have so far so that we can
07129       // see it.
07130       nsIView* rootView;
07131       mViewManager->GetRootView(rootView);
07132       mViewManager->UpdateView(rootView, NS_VMREFRESH_IMMEDIATE);
07133 
07134       mInVerifyReflow = PR_TRUE;
07135       PRBool ok = VerifyIncrementalReflow();
07136       mInVerifyReflow = PR_FALSE;
07137       if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
07138         printf("ProcessReflowCommands: finished (%s)\n",
07139                ok ? "ok" : "failed");
07140       }
07141 
07142       if (0 != mReflowCommands.Count()) {
07143         printf("XXX yikes! reflow commands queued during verify-reflow\n");
07144       }
07145     }
07146 #endif
07147 
07148     // If there are no more reflow commands in the queue, we'll want
07149     // to remove the ``dummy request''.
07150     DoneRemovingReflowCommands();
07151 
07152     DidDoReflow();
07153   }
07154   
07155   MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this));
07156   MOZ_TIMER_STOP(mReflowWatch);  
07157 
07158   if (mShouldUnsuppressPainting && mReflowCommands.Count() == 0) {
07159     // We only unlock if we're out of reflows.  It's pointless
07160     // to unlock if reflows are still pending, since reflows
07161     // are just going to thrash the frames around some more.  By
07162     // waiting we avoid an overeager "jitter" effect.
07163     mShouldUnsuppressPainting = PR_FALSE;
07164     UnsuppressAndInvalidate();
07165   }
07166 
07167   return NS_OK;
07168 }
07169 
07170 nsresult
07171 PresShell::ClearReflowEventStatus()
07172 {
07173   mReflowEventQueue = nsnull;
07174   return NS_OK;
07175 }
07176 
07177 nsresult
07178 PresShell::ReflowCommandAdded(nsHTMLReflowCommand* aRC)
07179 {
07180 
07181   if (gAsyncReflowDuringDocLoad) {
07182     NS_PRECONDITION(mRCCreatedDuringLoad >= 0, "PresShell's reflow command queue is in a bad state.");
07183     if (mDocumentLoading) {
07184       aRC->AddFlagBits(NS_RC_CREATED_DURING_DOCUMENT_LOAD);
07185       mRCCreatedDuringLoad++;
07186 
07187 #ifdef PR_LOGGING
07188       if (PR_LOG_TEST(gLog, PR_LOG_DEBUG)) {
07189         nsIFrame* target;
07190         aRC->GetTarget(target);
07191 
07192         nsIAtom* type = target->GetType();
07193         NS_ASSERTION(type, "frame didn't override GetType()");
07194 
07195         nsAutoString typeStr(NS_LITERAL_STRING("unknown"));
07196         if (type)
07197           type->ToString(typeStr);
07198 
07199         PR_LOG(gLog, PR_LOG_DEBUG,
07200                ("presshell=%p, ReflowCommandAdded(%p) target=%p[%s] mRCCreatedDuringLoad=%d\n",
07201                 this, aRC, target, NS_ConvertUCS2toUTF8(typeStr).get(), mRCCreatedDuringLoad));
07202       }
07203 #endif
07204 
07205       if (!mDummyLayoutRequest) {
07206         AddDummyLayoutRequest();
07207       }
07208     }
07209   }
07210   return NS_OK;
07211 }
07212 
07213 nsresult
07214 PresShell::ReflowCommandRemoved(nsHTMLReflowCommand* aRC)
07215 {
07216   NS_PRECONDITION(mReflowCommandTable.ops, "How did that happen?");
07217   
07218   PL_DHashTableOperate(&mReflowCommandTable, aRC, PL_DHASH_REMOVE);
07219   
07220   if (gAsyncReflowDuringDocLoad) {
07221     NS_PRECONDITION(mRCCreatedDuringLoad >= 0, "PresShell's reflow command queue is in a bad state.");  
07222     if (aRC->GetFlagBits() & NS_RC_CREATED_DURING_DOCUMENT_LOAD) {
07223       mRCCreatedDuringLoad--;
07224 
07225       PR_LOG(gLog, PR_LOG_DEBUG,
07226              ("presshell=%p, ReflowCommandRemoved(%p) mRCCreatedDuringLoad=%d\n",
07227               this, aRC, mRCCreatedDuringLoad));
07228     }
07229   }
07230   return NS_OK;
07231 }
07232 
07233 struct DummyLayoutRequestEvent : public PLEvent {
07234   DummyLayoutRequestEvent(PresShell* aPresShell) NS_HIDDEN;
07235   ~DummyLayoutRequestEvent() { }
07236 
07237   void HandleEvent() {
07238     // Hold a ref here, just in case, since we can trigger DOM event dispatch
07239     nsRefPtr<PresShell> presShell = NS_STATIC_CAST(PresShell*, owner);
07240     presShell->mDummyLayoutRequestEventPosted = PR_FALSE;
07241     presShell->RemoveDummyLayoutRequest();
07242   }
07243 };
07244 
07245 PR_STATIC_CALLBACK(void*)
07246 HandleDummyLayoutRequestPLEvent(PLEvent* aEvent)
07247 {
07248   DummyLayoutRequestEvent* evt = NS_STATIC_CAST(DummyLayoutRequestEvent*,
07249                                                 aEvent);
07250   evt->HandleEvent();
07251   return nsnull;
07252 }
07253 
07254 PR_STATIC_CALLBACK(void)
07255 DestroyDummyLayoutRequestPLEvent(PLEvent* aEvent)
07256 {
07257   DummyLayoutRequestEvent* evt = NS_STATIC_CAST(DummyLayoutRequestEvent*,
07258                                                 aEvent);
07259 
07260   delete evt;
07261 }
07262 
07263 DummyLayoutRequestEvent::DummyLayoutRequestEvent(PresShell* aPresShell)
07264 {
07265   NS_PRECONDITION(aPresShell, "Must have a presshell");
07266   NS_PRECONDITION(aPresShell->mDummyLayoutRequest, "No layout request?");
07267 
07268   PL_InitEvent(this, aPresShell, ::HandleDummyLayoutRequestPLEvent,
07269                ::DestroyDummyLayoutRequestPLEvent);
07270 }
07271 
07272 void
07273 PresShell::DoneRemovingReflowCommands()
07274 {
07275   if (mRCCreatedDuringLoad == 0 && mDummyLayoutRequest && !mIsReflowing &&
07276       !mIsDestroying && !mDummyLayoutRequestEventPosted) {
07277     // Post an event to remove mDummyLayoutRequest from the loadgroup
07278     nsCOMPtr<nsIEventQueue> eventQueue;
07279     mEventQueueService->
07280       GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
07281                            getter_AddRefs(eventQueue));
07282     if (!eventQueue) {
07283       NS_WARNING("onload won't fire, due to failure to get event queue.");
07284       return;
07285     }
07286 
07287     DummyLayoutRequestEvent* evt = new DummyLayoutRequestEvent(this);
07288     if (!evt) {
07289       NS_WARNING("onload won't fire, due to failure to create event.");
07290       return;
07291     }
07292 
07293     nsresult rv = eventQueue->PostEvent(evt);
07294     if (NS_FAILED(rv)) {
07295       NS_WARNING("onload won't fire, due to failure to post dummy layout "
07296                  "request event");
07297       PL_DestroyEvent(evt);
07298       return;
07299     }
07300 
07301     mDummyLayoutRequestEventPosted = PR_TRUE;
07302   }
07303 }
07304 
07305 nsresult
07306 PresShell::AddDummyLayoutRequest(void)
07307 { 
07308   nsresult rv = NS_OK;
07309 
07310   if (gAsyncReflowDuringDocLoad && !mIsReflowing) {
07311     rv = nsDummyLayoutRequest::Create(getter_AddRefs(mDummyLayoutRequest), this);
07312     if (NS_FAILED(rv)) return rv;
07313 
07314     nsCOMPtr<nsILoadGroup> loadGroup;
07315     if (mDocument)
07316       loadGroup = mDocument->GetDocumentLoadGroup();
07317 
07318     if (loadGroup) {
07319       rv = mDummyLayoutRequest->SetLoadGroup(loadGroup);
07320       if (NS_FAILED(rv)) return rv;
07321       rv = loadGroup->AddRequest(mDummyLayoutRequest, nsnull);
07322       if (NS_FAILED(rv)) return rv;
07323 
07324       PR_LOG(gLog, PR_LOG_ALWAYS,
07325              ("presshell=%p, Added dummy layout request %p", this, mDummyLayoutRequest.get()));
07326     }
07327   }
07328   return rv;
07329 }
07330 
07331 nsresult
07332 PresShell::RemoveDummyLayoutRequest()
07333 {
07334   nsresult rv = NS_OK;
07335 
07336   if (gAsyncReflowDuringDocLoad) {
07337     nsCOMPtr<nsILoadGroup> loadGroup;
07338     if (mDocument)
07339       loadGroup = mDocument->GetDocumentLoadGroup();
07340 
07341     if (loadGroup && mDummyLayoutRequest) {
07342       rv = loadGroup->RemoveRequest(mDummyLayoutRequest, nsnull, NS_OK);
07343       NS_ENSURE_SUCCESS(rv, rv);
07344 
07345       PR_LOG(gLog, PR_LOG_ALWAYS,
07346              ("presshell=%p, Removed dummy layout request %p", this,
07347               mDummyLayoutRequest.get()));
07348 
07349       mDummyLayoutRequest = nsnull;
07350     }
07351   }
07352   return rv;
07353 }
07354 
07355 #ifdef MOZ_XUL
07356 /*
07357  * It's better to add stuff to the |DidSetStyleContext| method of the
07358  * relevant frames than adding it here.  These methods should (ideally,
07359  * anyway) go away.
07360  */
07361 
07362 // Return value says whether to walk children.
07363 typedef PRBool (* PR_CALLBACK frameWalkerFn)(nsIFrame *aFrame, void *aClosure);
07364    
07365 PR_STATIC_CALLBACK(PRBool)
07366 ReResolveMenusAndTrees(nsIFrame *aFrame, void *aClosure)
07367 {
07368   // Trees have a special style cache that needs to be flushed when
07369   // the theme changes.
07370   nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(aFrame));
07371   if (treeBox)
07372     treeBox->ClearStyleAndImageCaches();
07373 
07374   // We deliberately don't re-resolve style on a menu's popup
07375   // sub-content, since doing so slows menus to a crawl.  That means we
07376   // have to special-case them on a skin switch, and ensure that the
07377   // popup frames just get destroyed completely.
07378   nsCOMPtr<nsIMenuFrame> menuFrame(do_QueryInterface(aFrame));
07379   if (menuFrame) {
07380     menuFrame->UngenerateMenu();  
07381     menuFrame->OpenMenu(PR_FALSE);
07382   }
07383   return PR_TRUE;
07384 }
07385 
07386 PR_STATIC_CALLBACK(PRBool)
07387 ReframeImageBoxes(nsIFrame *aFrame, void *aClosure)
07388 {
07389   nsStyleChangeList *list = NS_STATIC_CAST(nsStyleChangeList*, aClosure);
07390   if (aFrame->GetType() == nsLayoutAtoms::imageBoxFrame) {
07391     list->AppendChange(aFrame, aFrame->GetContent(),
07392                        NS_STYLE_HINT_FRAMECHANGE);
07393     return PR_FALSE; // don't walk descendants
07394   }
07395   return PR_TRUE; // walk descendants
07396 }
07397 
07398 static void
07399 WalkFramesThroughPlaceholders(nsPresContext *aPresContext, nsIFrame *aFrame,
07400                               frameWalkerFn aFunc, void *aClosure)
07401 {
07402   PRBool walkChildren = (*aFunc)(aFrame, aClosure);
07403   if (!walkChildren)
07404     return;
07405 
07406   PRInt32 listIndex = 0;
07407   nsIAtom* childList = nsnull;
07408 
07409   do {
07410     nsIFrame *child = aFrame->GetFirstChild(childList);
07411     while (child) {
07412       if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
07413         // only do frames that are in flow, and recur through the
07414         // out-of-flows of placeholders.
07415         WalkFramesThroughPlaceholders(aPresContext,
07416                                       nsPlaceholderFrame::GetRealFrameFor(child),
07417                                       aFunc, aClosure);
07418       }
07419       child = child->GetNextSibling();
07420     }
07421 
07422     childList = aFrame->GetAdditionalChildListName(listIndex++);
07423   } while (childList);
07424 }
07425 #endif
07426 
07427 NS_IMETHODIMP
07428 PresShell::Observe(nsISupports* aSubject, 
07429                    const char* aTopic,
07430                    const PRUnichar* aData)
07431 {
07432 #ifdef MOZ_XUL
07433   if (!nsCRT::strcmp(aTopic, "chrome-flush-skin-caches")) {
07434     nsIFrame *rootFrame = FrameManager()->GetRootFrame();
07435     // Need to null-check because "chrome-flush-skin-caches" can happen
07436     // at interesting times during startup.
07437     if (rootFrame) {
07438       NS_ASSERTION(mViewManager, "View manager must exist");
07439       mViewManager->BeginUpdateViewBatch();
07440 
07441       WalkFramesThroughPlaceholders(mPresContext, rootFrame,
07442                                     &ReResolveMenusAndTrees, nsnull);
07443 
07444       // Because "chrome:" URL equality is messy, reframe image box
07445       // frames (hack!).
07446       nsStyleChangeList changeList;
07447       WalkFramesThroughPlaceholders(mPresContext, rootFrame,
07448                                     ReframeImageBoxes, &changeList);
07449       mFrameConstructor->ProcessRestyledFrames(changeList);
07450 
07451       mViewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
07452 #ifdef ACCESSIBILITY
07453       InvalidateAccessibleSubtree(nsnull);
07454 #endif
07455     }
07456     return NS_OK;
07457   }
07458 #endif
07459 
07460   if (!nsCRT::strcmp(aTopic, NS_LINK_VISITED_EVENT_TOPIC)) {
07461     nsCOMPtr<nsIURI> uri = do_QueryInterface(aSubject);
07462     if (uri && mDocument) {
07463       mDocument->NotifyURIVisitednessChanged(uri);
07464     }
07465     return NS_OK;
07466   }
07467 
07468   NS_WARNING("unrecognized topic in PresShell::Observe");
07469   return NS_ERROR_FAILURE;
07470 }
07471 
07472 void
07473 PresShell::EnumeratePlugins(nsIDOMDocument *aDocument,
07474                             const nsString &aPluginTag,
07475                             nsPluginEnumCallback aCallback)
07476 {
07477   nsCOMPtr<nsIDOMNodeList> nodes;
07478   aDocument->GetElementsByTagName(aPluginTag, getter_AddRefs(nodes));
07479   if (!nodes)
07480     return;
07481 
07482   PRUint32 length;
07483   nodes->GetLength(&length);
07484 
07485   for (PRUint32 i = 0; i < length; ++i) {
07486     nsCOMPtr<nsIDOMNode> node;
07487     nodes->Item(i, getter_AddRefs(node));
07488 
07489     nsCOMPtr<nsIContent> content = do_QueryInterface(node);
07490     if (content)
07491       aCallback(this, content);
07492   }
07493 }
07494 
07495 void
07496 PresShell::HideViewIfPopup(nsIView* aView)
07497 {
07498   nsIFrame* frame = NS_STATIC_CAST(nsIFrame*, aView->GetClientData());
07499   if (frame) {
07500     nsIMenuParent* parent;
07501     CallQueryInterface(frame, &parent);
07502     if (parent) {
07503       parent->HideChain();
07504       // really make sure the view is hidden
07505       mViewManager->SetViewVisibility(aView, nsViewVisibility_kHide);
07506     }
07507   }
07508 
07509   nsIView* child = aView->GetFirstChild();
07510   while (child) {
07511     HideViewIfPopup(child);
07512     child = child->GetNextSibling();
07513   }
07514 }
07515 
07516 //------------------------------------------------------
07517 // End of protected and private methods on the PresShell
07518 //------------------------------------------------------
07519 
07520 // Start of DEBUG only code
07521 
07522 #ifdef NS_DEBUG
07523 #include "nsViewsCID.h"
07524 #include "nsWidgetsCID.h"
07525 #include "nsIDeviceContext.h"
07526 #include "nsIURL.h"
07527 #include "nsILinkHandler.h"
07528 
07529 static NS_DEFINE_CID(kViewManagerCID, NS_VIEW_MANAGER_CID);
07530 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
07531 
07532 static void
07533 LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg)
07534 {
07535   printf("verifyreflow: ");
07536   nsAutoString name;
07537   if (nsnull != k1) {
07538     nsIFrameDebug*  frameDebug;
07539 
07540     if (NS_SUCCEEDED(k1->QueryInterface(NS_GET_IID(nsIFrameDebug),
07541                                         (void**)&frameDebug))) {
07542      frameDebug->GetFrameName(name);
07543     }
07544   }
07545   else {
07546     name.Assign(NS_LITERAL_STRING("(null)"));
07547   }
07548   fputs(NS_LossyConvertUCS2toASCII(name).get(), stdout);
07549 
07550   printf(" != ");
07551 
07552   if (nsnull != k2) {
07553     nsIFrameDebug*  frameDebug;
07554 
07555     if (NS_SUCCEEDED(k2->QueryInterface(NS_GET_IID(nsIFrameDebug),
07556                                         (void**)&frameDebug))) {
07557       frameDebug->GetFrameName(name);
07558     }
07559   }
07560   else {
07561     name.Assign(NS_LITERAL_STRING("(null)"));
07562   }
07563   fputs(NS_LossyConvertUCS2toASCII(name).get(), stdout);
07564 
07565   printf(" %s", aMsg);
07566 }
07567 
07568 static void
07569 LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
07570                  const nsRect& r1, const nsRect& r2)
07571 {
07572   printf("VerifyReflow Error:\n");
07573   nsAutoString name;
07574   nsIFrameDebug*  frameDebug;
07575 
07576   if (NS_SUCCEEDED(k1->QueryInterface(NS_GET_IID(nsIFrameDebug),
07577                                       (void**)&frameDebug))) {
07578     fprintf(stdout, "  ");
07579     frameDebug->GetFrameName(name);
07580     fputs(NS_LossyConvertUCS2toASCII(name).get(), stdout);
07581     fprintf(stdout, " %p ", (void*)k1);
07582   }
07583   printf("{%d, %d, %d, %d}", r1.x, r1.y, r1.width, r1.height);
07584 
07585   printf(" != \n");
07586 
07587   if (NS_SUCCEEDED(k2->QueryInterface(NS_GET_IID(nsIFrameDebug),
07588                                       (void**)&frameDebug))) {
07589     fprintf(stdout, "  ");
07590     frameDebug->GetFrameName(name);
07591     fputs(NS_LossyConvertUCS2toASCII(name).get(), stdout);
07592     fprintf(stdout, " %p ", (void*)k2);
07593   }
07594   printf("{%d, %d, %d, %d}\n", r2.x, r2.y, r2.width, r2.height);
07595 
07596   printf("  %s\n", aMsg);
07597 }
07598 
07599 static PRBool
07600 CompareTrees(nsPresContext* aFirstPresContext, nsIFrame* aFirstFrame, 
07601              nsPresContext* aSecondPresContext, nsIFrame* aSecondFrame)
07602 {
07603   if (!aFirstPresContext || !aFirstFrame || !aSecondPresContext || !aSecondFrame)
07604     return PR_TRUE;
07605   PRBool ok = PR_TRUE;
07606   nsIAtom* listName = nsnull;
07607   PRInt32 listIndex = 0;
07608   do {
07609     nsIFrame* k1 = aFirstFrame->GetFirstChild(listName);
07610     nsIFrame* k2 = aSecondFrame->GetFirstChild(listName);
07611     PRInt32 l1 = nsContainerFrame::LengthOf(k1);
07612     PRInt32 l2 = nsContainerFrame::LengthOf(k2);
07613     if (l1 != l2) {
07614       ok = PR_FALSE;
07615       LogVerifyMessage(k1, k2, "child counts don't match: ");
07616       printf("%d != %d\n", l1, l2);
07617       if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
07618         break;
07619       }
07620     }
07621 
07622     nsRect r1, r2;
07623     nsIView* v1, *v2;
07624     for (;;) {
07625       if (((nsnull == k1) && (nsnull != k2)) ||
07626           ((nsnull != k1) && (nsnull == k2))) {
07627         ok = PR_FALSE;
07628         LogVerifyMessage(k1, k2, "child lists are different\n");
07629         break;
07630       }
07631       else if (nsnull != k1) {
07632         // Verify that the frames are the same size
07633         if (k1->GetRect() != k2->GetRect()) {
07634           ok = PR_FALSE;
07635           LogVerifyMessage(k1, k2, "(frame rects)", k1->GetRect(), k2->GetRect());
07636         }
07637 
07638         // Make sure either both have views or neither have views; if they
07639         // do have views, make sure the views are the same size. If the
07640         // views have widgets, make sure they both do or neither does. If
07641         // they do, make sure the widgets are the same size.
07642         v1 = k1->GetView();
07643         v2 = k2->GetView();
07644         if (((nsnull == v1) && (nsnull != v2)) ||
07645             ((nsnull != v1) && (nsnull == v2))) {
07646           ok = PR_FALSE;
07647           LogVerifyMessage(k1, k2, "child views are not matched\n");
07648         }
07649         else if (nsnull != v1) {
07650           if (v1->GetBounds() != v2->GetBounds()) {
07651             LogVerifyMessage(k1, k2, "(view rects)", v1->GetBounds(), v2->GetBounds());
07652           }
07653 
07654           nsIWidget* w1 = v1->GetWidget();
07655           nsIWidget* w2 = v2->GetWidget();
07656           if (((nsnull == w1) && (nsnull != w2)) ||
07657               ((nsnull != w1) && (nsnull == w2))) {
07658             ok = PR_FALSE;
07659             LogVerifyMessage(k1, k2, "child widgets are not matched\n");
07660           }
07661           else if (nsnull != w1) {
07662             w1->GetBounds(r1);
07663             w2->GetBounds(r2);
07664             if (r1 != r2) {
07665               LogVerifyMessage(k1, k2, "(widget rects)", r1, r2);
07666             }
07667           }
07668         }
07669         if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
07670           break;
07671         }
07672 
07673         // verify that neither frame has a space manager,
07674         // or they both do and the space managers are equivalent
07675         nsSpaceManager *sm1 = NS_STATIC_CAST(nsSpaceManager*,
07676                          k1->GetProperty(nsLayoutAtoms::spaceManagerProperty));
07677 
07678         // look at the test frame
07679         nsSpaceManager *sm2 = NS_STATIC_CAST(nsSpaceManager*,
07680                          k2->GetProperty(nsLayoutAtoms::spaceManagerProperty));
07681 
07682         // now compare the space managers
07683         if (((nsnull == sm1) && (nsnull != sm2)) ||
07684             ((nsnull != sm1) && (nsnull == sm2))) {   // one is null, and the other is not
07685           ok = PR_FALSE;
07686           LogVerifyMessage(k1, k2, "space managers are not matched\n");
07687         }
07688         else if (sm1 && sm2) {  // both are not null, compare them
07689           // first, compare yMost
07690           nscoord yMost1, yMost2;
07691           nsresult smresult = sm1->YMost(yMost1);
07692           if (NS_ERROR_ABORT != smresult)
07693           {
07694             NS_ASSERTION(NS_SUCCEEDED(smresult), "bad result");
07695             smresult = sm2->YMost(yMost2);
07696             NS_ASSERTION(NS_SUCCEEDED(smresult), "bad result");
07697             if (yMost1 != yMost2) {
07698               LogVerifyMessage(k1, k2, "yMost of space managers differs\n");
07699             }
07700             // now compare bands by sampling
07701             PRInt32 yIncrement = yMost1/100;
07702             if (0==yIncrement) {
07703               yIncrement = 1;   // guarantee we make progress in the loop below
07704             }
07705             nscoord yOffset = 0;
07706             for ( ; ok && yOffset < yMost1; yOffset += yIncrement)
07707             {
07708               nscoord small=5, large=100;
07709               nsBandData band1, band2;
07710               nsBandTrapezoid trap1[20], trap2[20];
07711               band1.mSize = band2.mSize = 20;
07712               band1.mTrapezoids = trap1;  
07713               band2.mTrapezoids = trap2;
07714               sm1->GetBandData(yOffset,