LCOV - app.info - layout/base/nsPresShell.cpp

LCOV - code coverage report
| Current view: | directory - layout/base - nsPresShell.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 3826 | 10 | 0.3 %
| Date: | 2012-07-07 | Functions: | 322 | 4 | 1.2 %

           1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
           2                 :  * vim: set ts=2 sw=2 et tw=78:
           3                 :  * ***** BEGIN LICENSE BLOCK *****
           4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           5                 :  *
           6                 :  * The contents of this file are subject to the Mozilla Public License Version
           7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           8                 :  * the License. You may obtain a copy of the License at
           9                 :  * http://www.mozilla.org/MPL/
          10                 :  *
          11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          13                 :  * for the specific language governing rights and limitations under the
          14                 :  * License.
          15                 :  *
          16                 :  * The Original Code is mozilla.org code.
          17                 :  *
          18                 :  * The Initial Developer of the Original Code is
          19                 :  * Netscape Communications Corporation.
          20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
          21                 :  * the Initial Developer. All Rights Reserved.
          22                 :  *
          23                 :  * Contributor(s):
          24                 :  *   Steve Clark <buster@netscape.com>
          25                 :  *   Håkan Waara <hwaara@chello.se>
          26                 :  *   Dan Rosen <dr@netscape.com>
          27                 :  *   Daniel Glazman <glazman@netscape.com>
          28                 :  *   Mats Palmgren <matspal@gmail.com>
          29                 :  *   Mihai Sucan <mihai.sucan@gmail.com>
          30                 :  *
          31                 :  * Alternatively, the contents of this file may be used under the terms of
          32                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          33                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          34                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          35                 :  * of those above. If you wish to allow use of your version of this file only
          36                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          37                 :  * use your version of this file under the terms of the MPL, indicate your
          38                 :  * decision by deleting the provisions above and replace them with the notice
          39                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          40                 :  * the provisions above, a recipient may use your version of this file under
          41                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          42                 :  *
          43                 :  * ***** END LICENSE BLOCK *****
          44                 :  *
          45                 :  * This Original Code has been modified by IBM Corporation.
          46                 :  * Modifications made by IBM described herein are
          47                 :  * Copyright (c) International Business Machines
          48                 :  * Corporation, 2000
          49                 :  *
          50                 :  * Modifications to Mozilla code or documentation
          51                 :  * identified per MPL Section 3.3
          52                 :  *
          53                 :  * Date         Modified by     Description of modification
          54                 :  * 05/03/2000   IBM Corp.       Observer events for reflow states
          55                 :  */
          56                 :
          57                 : /* a presentation of a document, part 2 */
          58                 :
          59                 : #include "mozilla/dom/PBrowserChild.h"
          60                 : #include "mozilla/dom/TabChild.h"
          61                 : #include "mozilla/Util.h"
          62                 :
          63                 : #ifdef XP_WIN
          64                 : #include "winuser.h"
          65                 : #endif
          66                 :
          67                 : #include "nsPresShell.h"
          68                 : #include "nsPresContext.h"
          69                 : #include "nsIContent.h"
          70                 : #include "mozilla/dom/Element.h"
          71                 : #include "nsIDocument.h"
          72                 : #include "nsIDOMXULDocument.h"
          73                 : #include "nsCSSStyleSheet.h" // XXX for UA sheet loading hack, can this go away please?
          74                 : #include "nsIDOMCSSStyleSheet.h"  // for Pref-related rule management (bugs 22963,20760,31816)
          75                 : #include "nsAnimationManager.h"
          76                 : #include "nsINameSpaceManager.h"  // for Pref-related rule management (bugs 22963,20760,31816)
          77                 : #include "nsIServiceManager.h"
          78                 : #include "nsFrame.h"
          79                 : #include "nsViewManager.h"
          80                 : #include "nsView.h"
          81                 : #include "nsCRTGlue.h"
          82                 : #include "prlog.h"
          83                 : #include "prmem.h"
          84                 : #include "prprf.h"
          85                 : #include "prinrval.h"
          86                 : #include "nsTArray.h"
          87                 : #include "nsCOMArray.h"
          88                 : #include "nsHashtable.h"
          89                 : #include "nsContainerFrame.h"
          90                 : #include "nsDOMEvent.h"
          91                 : #include "nsHTMLParts.h"
          92                 : #include "nsISelection.h"
          93                 : #include "nsISelectionPrivate.h"
          94                 : #include "nsLayoutCID.h"
          95                 : #include "nsGkAtoms.h"
          96                 : #include "nsIDOMRange.h"
          97                 : #include "nsIDOMDocument.h"
          98                 : #include "nsIDOMNode.h"
          99                 : #include "nsIDOMNodeList.h"
         100                 : #include "nsIDOMElement.h"
         101                 : #include "nsRange.h"
         102                 : #include "nsCSSPseudoElements.h"
         103                 : #include "nsCOMPtr.h"
         104                 : #include "nsAutoPtr.h"
         105                 : #include "nsReadableUtils.h"
         106                 : #include "nsUnicharUtils.h"
         107                 : #include "nsIPageSequenceFrame.h"
         108                 : #include "nsCaret.h"
         109                 : #include "nsIDOMHTMLDocument.h"
         110                 : #include "nsIDOMXMLDocument.h"
         111                 : #include "nsIParser.h"
         112                 : #include "nsParserCIID.h"
         113                 : #include "nsViewsCID.h"
         114                 : #include "nsFrameManager.h"
         115                 : #include "nsEventStateManager.h"
         116                 : #include "nsXPCOM.h"
         117                 : #include "nsISupportsPrimitives.h"
         118                 : #include "nsILayoutHistoryState.h"
         119                 : #include "nsILineIterator.h" // for ScrollContentIntoView
         120                 : #include "nsWeakPtr.h"
         121                 : #include "pldhash.h"
         122                 : #include "nsDOMTouchEvent.h"
         123                 : #include "nsIObserverService.h"
         124                 : #include "nsIDocShell.h"        // for reflow observation
         125                 : #include "nsIBaseWindow.h"
         126                 : #include "nsLayoutErrors.h"
         127                 : #include "nsLayoutUtils.h"
         128                 : #include "nsCSSRendering.h"
         129                 :   // for |#ifdef DEBUG| code
         130                 : #include "prenv.h"
         131                 : #include "nsAlgorithm.h"
         132                 : #include "nsIAttribute.h"
         133                 : #include "nsIGlobalHistory2.h"
         134                 : #include "nsDisplayList.h"
         135                 : #include "nsRegion.h"
         136                 : #include "nsRenderingContext.h"
         137                 : #include "nsAutoLayoutPhase.h"
         138                 : #ifdef MOZ_REFLOW_PERF
         139                 : #include "nsFontMetrics.h"
         140                 : #endif
         141                 :
         142                 : #include "nsIReflowCallback.h"
         143                 :
         144                 : #include "nsPIDOMWindow.h"
         145                 : #include "nsFocusManager.h"
         146                 : #include "nsNPAPIPluginInstance.h"
         147                 : #include "nsIObjectFrame.h"
         148                 : #include "nsIObjectLoadingContent.h"
         149                 : #include "nsNetUtil.h"
         150                 : #include "nsEventDispatcher.h"
         151                 : #include "nsThreadUtils.h"
         152                 : #include "nsStyleSheetService.h"
         153                 : #include "gfxImageSurface.h"
         154                 : #include "gfxContext.h"
         155                 : #ifdef MOZ_MEDIA
         156                 : #include "nsHTMLMediaElement.h"
         157                 : #endif
         158                 : #include "nsSMILAnimationController.h"
         159                 :
         160                 : #include "nsRefreshDriver.h"
         161                 :
         162                 : // Drag & Drop, Clipboard
         163                 : #include "nsWidgetsCID.h"
         164                 : #include "nsIClipboard.h"
         165                 : #include "nsIClipboardHelper.h"
         166                 : #include "nsIDocShellTreeItem.h"
         167                 : #include "nsIURI.h"
         168                 : #include "nsIScrollableFrame.h"
         169                 : #include "prtime.h"
         170                 : #include "prlong.h"
         171                 : #include "nsIDragService.h"
         172                 : #include "nsCopySupport.h"
         173                 : #include "nsIDOMHTMLAnchorElement.h"
         174                 : #include "nsIDOMHTMLAreaElement.h"
         175                 : #include "nsIDOMHTMLLinkElement.h"
         176                 : #include "nsITimer.h"
         177                 : #ifdef ACCESSIBILITY
         178                 : #include "nsAccessibilityService.h"
         179                 : #endif
         180                 :
         181                 : // For style data reconstruction
         182                 : #include "nsStyleChangeList.h"
         183                 : #include "nsCSSFrameConstructor.h"
         184                 : #ifdef MOZ_XUL
         185                 : #include "nsMenuFrame.h"
         186                 : #include "nsTreeBodyFrame.h"
         187                 : #include "nsIBoxObject.h"
         188                 : #include "nsITreeBoxObject.h"
         189                 : #include "nsMenuPopupFrame.h"
         190                 : #include "nsITreeColumns.h"
         191                 : #include "nsIDOMXULMultSelectCntrlEl.h"
         192                 : #include "nsIDOMXULSelectCntrlItemEl.h"
         193                 : #include "nsIDOMXULMenuListElement.h"
         194                 :
         195                 : #endif
         196                 : #include "nsPlaceholderFrame.h"
         197                 : #include "nsCanvasFrame.h"
         198                 :
         199                 : // Content viewer interfaces
         200                 : #include "nsIContentViewer.h"
         201                 : #include "imgIEncoder.h"
         202                 : #include "gfxPlatform.h"
         203                 :
         204                 : #include "mozilla/FunctionTimer.h"
         205                 : #include "mozilla/Preferences.h"
         206                 : #include "mozilla/Telemetry.h"
         207                 : #include "sampler.h"
         208                 :
         209                 : #include "Layers.h"
         210                 : #include "nsAsyncDOMEvent.h"
         211                 :
         212                 : #ifdef NS_FUNCTION_TIMER
         213                 : #define NS_TIME_FUNCTION_DECLARE_DOCURL                \
         214                 :   nsCAutoString docURL__("N/A");                       \
         215                 :   nsIURI *uri__ = mDocument->GetDocumentURI();         \
         216                 :   if (uri__) uri__->GetSpec(docURL__);
         217                 : #define NS_TIME_FUNCTION_WITH_DOCURL                   \
         218                 :   NS_TIME_FUNCTION_DECLARE_DOCURL                      \
         219                 :   NS_TIME_FUNCTION_MIN_FMT(1.0,                        \
         220                 :      "%s (line %d) (document: %s)", MOZ_FUNCTION_NAME, \
         221                 :      __LINE__, docURL__.get())
         222                 : #else
         223                 : #define NS_TIME_FUNCTION_WITH_DOCURL do{} while(0)
         224                 : #endif
         225                 :
         226                 : #define ANCHOR_SCROLL_FLAGS (SCROLL_OVERFLOW_HIDDEN | SCROLL_NO_PARENT_FRAMES)
         227                 :
         228                 : using namespace mozilla;
         229                 : using namespace mozilla::dom;
         230                 : using namespace mozilla::layers;
         231                 :
         232                 : CapturingContentInfo nsIPresShell::gCaptureInfo =
         233                 :   { false /* mAllowed */,     false /* mRetargetToElement */,
         234                 :     false /* mPreventDrag */, nsnull /* mContent */ };
         235                 : nsIContent* nsIPresShell::gKeyDownTarget;
         236            1464 : nsInterfaceHashtable<nsUint32HashKey, nsIDOMTouch> nsIPresShell::gCaptureTouchList;
         237                 : bool nsIPresShell::gPreventMouseEvents = false;
         238                 :
         239                 : static PRUint32
         240               0 : ChangeFlag(PRUint32 aFlags, bool aOnOff, PRUint32 aFlag)
         241                 : {
         242                 :   PRUint32 flags;
         243               0 :   if (aOnOff) {
         244               0 :     flags = (aFlags | aFlag);
         245                 :   } else {
         246               0 :     flags = (aFlag & ~aFlag);
         247                 :   }
         248               0 :   return flags;
         249                 : }
         250                 :
         251                 : // convert a color value to a string, in the CSS format #RRGGBB
         252                 : // *  - initially created for bugs 31816, 20760, 22963
         253                 : static void ColorToString(nscolor aColor, nsAutoString &aString);
         254                 :
         255                 : // RangePaintInfo is used to paint ranges to offscreen buffers
         256                 : struct RangePaintInfo {
         257                 :   nsRefPtr<nsRange> mRange;
         258                 :   nsDisplayListBuilder mBuilder;
         259                 :   nsDisplayList mList;
         260                 :
         261                 :   // offset of builder's reference frame to the root frame
         262                 :   nsPoint mRootOffset;
         263                 :
         264               0 :   RangePaintInfo(nsRange* aRange, nsIFrame* aFrame)
         265               0 :     : mRange(aRange), mBuilder(aFrame, nsDisplayListBuilder::PAINTING, false)
         266                 :   {
         267               0 :     MOZ_COUNT_CTOR(RangePaintInfo);
         268               0 :   }
         269                 :
         270               0 :   ~RangePaintInfo()
         271               0 :   {
         272               0 :     mList.DeleteAll();
         273               0 :     MOZ_COUNT_DTOR(RangePaintInfo);
         274               0 :   }
         275                 : };
         276                 :
         277                 : #undef NOISY
         278                 :
         279                 : // ----------------------------------------------------------------------
         280                 :
         281                 : #ifdef NS_DEBUG
         282                 : // Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
         283                 : // more of the following flags (comma separated) for handy debug
         284                 : // output.
         285                 : static PRUint32 gVerifyReflowFlags;
         286                 :
         287                 : struct VerifyReflowFlags {
         288                 :   const char*    name;
         289                 :   PRUint32 bit;
         290                 : };
         291                 :
         292                 : static const VerifyReflowFlags gFlags[] = {
         293                 :   { "verify",                VERIFY_REFLOW_ON },
         294                 :   { "reflow",                VERIFY_REFLOW_NOISY },
         295                 :   { "all",                   VERIFY_REFLOW_ALL },
         296                 :   { "list-commands",         VERIFY_REFLOW_DUMP_COMMANDS },
         297                 :   { "noisy-commands",        VERIFY_REFLOW_NOISY_RC },
         298                 :   { "really-noisy-commands", VERIFY_REFLOW_REALLY_NOISY_RC },
         299                 :   { "resize",                VERIFY_REFLOW_DURING_RESIZE_REFLOW },
         300                 : };
         301                 :
         302                 : #define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
         303                 :
         304                 : static void
         305               0 : ShowVerifyReflowFlags()
         306                 : {
         307               0 :   printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n");
         308               0 :   const VerifyReflowFlags* flag = gFlags;
         309               0 :   const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
         310               0 :   while (flag < limit) {
         311               0 :     printf("  %s\n", flag->name);
         312               0 :     ++flag;
         313                 :   }
         314               0 :   printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
         315               0 :   printf("names (no whitespace)\n");
         316               0 : }
         317                 : #endif
         318                 :
         319                 : //========================================================================
         320                 : //========================================================================
         321                 : //========================================================================
         322                 : #ifdef MOZ_REFLOW_PERF
         323                 : class ReflowCountMgr;
         324                 :
         325                 : static const char kGrandTotalsStr[] = "Grand Totals";
         326                 :
         327                 : // Counting Class
         328                 : class ReflowCounter {
         329                 : public:
         330                 :   ReflowCounter(ReflowCountMgr * aMgr = nsnull);
         331                 :   ~ReflowCounter();
         332                 :
         333                 :   void ClearTotals();
         334                 :   void DisplayTotals(const char * aStr);
         335                 :   void DisplayDiffTotals(const char * aStr);
         336                 :   void DisplayHTMLTotals(const char * aStr);
         337                 :
         338               0 :   void Add()                { mTotal++;         }
         339               0 :   void Add(PRUint32 aTotal) { mTotal += aTotal; }
         340                 :
         341                 :   void CalcDiffInTotals();
         342                 :   void SetTotalsCache();
         343                 :
         344                 :   void SetMgr(ReflowCountMgr * aMgr) { mMgr = aMgr; }
         345                 :
         346               0 :   PRUint32 GetTotal() { return mTotal; }
         347                 :
         348                 : protected:
         349                 :   void DisplayTotals(PRUint32 aTotal, const char * aTitle);
         350                 :   void DisplayHTMLTotals(PRUint32 aTotal, const char * aTitle);
         351                 :
         352                 :   PRUint32 mTotal;
         353                 :   PRUint32 mCacheTotal;
         354                 :
         355                 :   ReflowCountMgr * mMgr; // weak reference (don't delete)
         356                 : };
         357                 :
         358                 : // Counting Class
         359                 : class IndiReflowCounter {
         360                 : public:
         361               0 :   IndiReflowCounter(ReflowCountMgr * aMgr = nsnull)
         362                 :     : mFrame(nsnull),
         363                 :       mCount(0),
         364                 :       mMgr(aMgr),
         365                 :       mCounter(aMgr),
         366               0 :       mHasBeenOutput(false)
         367               0 :     {}
         368               0 :   virtual ~IndiReflowCounter() {}
         369                 :
         370                 :   nsAutoString mName;
         371                 :   nsIFrame *   mFrame;   // weak reference (don't delete)
         372                 :   PRInt32      mCount;
         373                 :
         374                 :   ReflowCountMgr * mMgr; // weak reference (don't delete)
         375                 :
         376                 :   ReflowCounter mCounter;
         377                 :   bool          mHasBeenOutput;
         378                 :
         379                 : };
         380                 :
         381                 : //--------------------
         382                 : // Manager Class
         383                 : //--------------------
         384                 : class ReflowCountMgr {
         385                 : public:
         386                 :   ReflowCountMgr();
         387                 :   virtual ~ReflowCountMgr();
         388                 :
         389                 :   void ClearTotals();
         390                 :   void ClearGrandTotals();
         391                 :   void DisplayTotals(const char * aStr);
         392                 :   void DisplayHTMLTotals(const char * aStr);
         393                 :   void DisplayDiffsInTotals(const char * aStr);
         394                 :
         395                 :   void Add(const char * aName, nsIFrame * aFrame);
         396                 :   ReflowCounter * LookUp(const char * aName);
         397                 :
         398                 :   void PaintCount(const char *aName, nsRenderingContext* aRenderingContext,
         399                 :                   nsPresContext *aPresContext, nsIFrame *aFrame,
         400                 :                   const nsPoint &aOffset, PRUint32 aColor);
         401                 :
         402               0 :   FILE * GetOutFile() { return mFD; }
         403                 :
         404                 :   PLHashTable * GetIndiFrameHT() { return mIndiFrameCounts; }
         405                 :
         406               0 :   void SetPresContext(nsPresContext * aPresContext) { mPresContext = aPresContext; } // weak reference
         407               0 :   void SetPresShell(nsIPresShell* aPresShell) { mPresShell= aPresShell; } // weak reference
         408                 :
         409               0 :   void SetDumpFrameCounts(bool aVal)         { mDumpFrameCounts = aVal; }
         410               0 :   void SetDumpFrameByFrameCounts(bool aVal)  { mDumpFrameByFrameCounts = aVal; }
         411               0 :   void SetPaintFrameCounts(bool aVal)        { mPaintFrameByFrameCounts = aVal; }
         412                 :
         413               0 :   bool IsPaintingFrameCounts() { return mPaintFrameByFrameCounts; }
         414                 :
         415                 : protected:
         416                 :   void DisplayTotals(PRUint32 aTotal, PRUint32 * aDupArray, char * aTitle);
         417                 :   void DisplayHTMLTotals(PRUint32 aTotal, PRUint32 * aDupArray, char * aTitle);
         418                 :
         419                 :   static PRIntn RemoveItems(PLHashEntry *he, PRIntn i, void *arg);
         420                 :   static PRIntn RemoveIndiItems(PLHashEntry *he, PRIntn i, void *arg);
         421                 :   void CleanUp();
         422                 :
         423                 :   // stdout Output Methods
         424                 :   static PRIntn DoSingleTotal(PLHashEntry *he, PRIntn i, void *arg);
         425                 :   static PRIntn DoSingleIndi(PLHashEntry *he, PRIntn i, void *arg);
         426                 :
         427                 :   void DoGrandTotals();
         428                 :   void DoIndiTotalsTree();
         429                 :
         430                 :   // HTML Output Methods
         431                 :   static PRIntn DoSingleHTMLTotal(PLHashEntry *he, PRIntn i, void *arg);
         432                 :   void DoGrandHTMLTotals();
         433                 :
         434                 :   // Zero Out the Totals
         435                 :   static PRIntn DoClearTotals(PLHashEntry *he, PRIntn i, void *arg);
         436                 :
         437                 :   // Displays the Diff Totals
         438                 :   static PRIntn DoDisplayDiffTotals(PLHashEntry *he, PRIntn i, void *arg);
         439                 :
         440                 :   PLHashTable * mCounts;
         441                 :   PLHashTable * mIndiFrameCounts;
         442                 :   FILE * mFD;
         443                 :
         444                 :   bool mDumpFrameCounts;
         445                 :   bool mDumpFrameByFrameCounts;
         446                 :   bool mPaintFrameByFrameCounts;
         447                 :
         448                 :   bool mCycledOnce;
         449                 :
         450                 :   // Root Frame for Individual Tracking
         451                 :   nsPresContext * mPresContext;
         452                 :   nsIPresShell*    mPresShell;
         453                 :
         454                 :   // ReflowCountMgr gReflowCountMgr;
         455                 : };
         456                 : #endif
         457                 : //========================================================================
         458                 :
         459                 : // comment out to hide caret
         460                 : #define SHOW_CARET
         461                 :
         462                 : // The upper bound on the amount of time to spend reflowing, in
         463                 : // microseconds.  When this bound is exceeded and reflow commands are
         464                 : // still queued up, a reflow event is posted.  The idea is for reflow
         465                 : // to not hog the processor beyond the time specifed in
         466                 : // gMaxRCProcessingTime.  This data member is initialized from the
         467                 : // layout.reflow.timeslice pref.
         468                 : #define NS_MAX_REFLOW_TIME    1000000
         469                 : static PRInt32 gMaxRCProcessingTime = -1;
         470                 :
         471               0 : StackArena::StackArena()
         472                 : {
         473               0 :   mMarkLength = 0;
         474               0 :   mMarks = nsnull;
         475                 :
         476                 :   // allocate our stack memory
         477               0 :   mBlocks = new StackBlock();
         478               0 :   mCurBlock = mBlocks;
         479                 :
         480               0 :   mStackTop = 0;
         481               0 :   mPos = 0;
         482               0 : }
         483                 :
         484               0 : StackArena::~StackArena()
         485                 : {
         486                 :   // free up our data
         487               0 :   delete[] mMarks;
         488               0 :   while(mBlocks)
         489                 :   {
         490               0 :     StackBlock* toDelete = mBlocks;
         491               0 :     mBlocks = mBlocks->mNext;
         492               0 :     delete toDelete;
         493                 :   }
         494               0 : }
         495                 :
         496                 : void
         497               0 : StackArena::Push()
         498                 : {
         499                 :   // Resize the mark array if we overrun it.  Failure to allocate the
         500                 :   // mark array is not fatal; we just won't free to that mark.  This
         501                 :   // allows callers not to worry about error checking.
         502               0 :   if (mStackTop >= mMarkLength)
         503                 :   {
         504               0 :     PRUint32 newLength = mStackTop + STACK_ARENA_MARK_INCREMENT;
         505               0 :     StackMark* newMarks = new StackMark[newLength];
         506               0 :     if (newMarks) {
         507               0 :       if (mMarkLength)
         508               0 :         memcpy(newMarks, mMarks, sizeof(StackMark)*mMarkLength);
         509                 :       // Fill in any marks that we couldn't allocate during a prior call
         510                 :       // to Push().
         511               0 :       for (; mMarkLength < mStackTop; ++mMarkLength) {
         512               0 :         NS_NOTREACHED("should only hit this on out-of-memory");
         513               0 :         newMarks[mMarkLength].mBlock = mCurBlock;
         514               0 :         newMarks[mMarkLength].mPos = mPos;
         515                 :       }
         516               0 :       delete [] mMarks;
         517               0 :       mMarks = newMarks;
         518               0 :       mMarkLength = newLength;
         519                 :     }
         520                 :   }
         521                 :
         522                 :   // set a mark at the top (if we can)
         523               0 :   NS_ASSERTION(mStackTop < mMarkLength, "out of memory");
         524               0 :   if (mStackTop < mMarkLength) {
         525               0 :     mMarks[mStackTop].mBlock = mCurBlock;
         526               0 :     mMarks[mStackTop].mPos = mPos;
         527                 :   }
         528                 :
         529               0 :   mStackTop++;
         530               0 : }
         531                 :
         532                 : void*
         533               0 : StackArena::Allocate(size_t aSize)
         534                 : {
         535               0 :   NS_ASSERTION(mStackTop > 0, "Allocate called without Push");
         536                 :
         537                 :   // make sure we are aligned. Beard said 8 was safer then 4.
         538                 :   // Round size to multiple of 8
         539               0 :   aSize = NS_ROUNDUP<size_t>(aSize, 8);
         540                 :
         541                 :   // if the size makes the stack overflow. Grab another block for the stack
         542               0 :   if (mPos + aSize >= STACK_ARENA_BLOCK_INCREMENT)
         543                 :   {
         544               0 :     NS_ASSERTION(aSize <= STACK_ARENA_BLOCK_INCREMENT,
         545                 :                  "Requested memory is greater that our block size!!");
         546               0 :     if (mCurBlock->mNext == nsnull)
         547               0 :       mCurBlock->mNext = new StackBlock();
         548                 :
         549               0 :     mCurBlock =  mCurBlock->mNext;
         550               0 :     mPos = 0;
         551                 :   }
         552                 :
         553                 :   // return the chunk they need.
         554               0 :   void *result = mCurBlock->mBlock + mPos;
         555               0 :   mPos += aSize;
         556                 :
         557               0 :   return result;
         558                 : }
         559                 :
         560                 : void
         561               0 : StackArena::Pop()
         562                 : {
         563                 :   // pop off the mark
         564               0 :   NS_ASSERTION(mStackTop > 0, "unmatched pop");
         565               0 :   mStackTop--;
         566                 :
         567               0 :   if (mStackTop >= mMarkLength) {
         568                 :     // We couldn't allocate the marks array at the time of the push, so
         569                 :     // we don't know where we're freeing to.
         570               0 :     NS_NOTREACHED("out of memory");
         571               0 :     if (mStackTop == 0) {
         572                 :       // But we do know if we've completely pushed the stack.
         573               0 :       mCurBlock = mBlocks;
         574               0 :       mPos = 0;
         575                 :     }
         576               0 :     return;
         577                 :   }
         578                 :
         579                 : #ifdef DEBUG
         580                 :   // Mark the "freed" memory with 0xdd to help with debugging of memory
         581                 :   // allocation problems.
         582                 :   {
         583               0 :     StackBlock *block = mMarks[mStackTop].mBlock, *block_end = mCurBlock;
         584               0 :     size_t pos = mMarks[mStackTop].mPos;
         585               0 :     for (; block != block_end; block = block->mNext, pos = 0) {
         586               0 :       memset(block->mBlock + pos, 0xdd, sizeof(block->mBlock) - pos);
         587                 :     }
         588               0 :     memset(block->mBlock + pos, 0xdd, mPos - pos);
         589                 :   }
         590                 : #endif
         591                 :
         592               0 :   mCurBlock = mMarks[mStackTop].mBlock;
         593               0 :   mPos      = mMarks[mStackTop].mPos;
         594                 : }
         595                 :
         596                 : struct nsCallbackEventRequest
         597                 : {
         598                 :   nsIReflowCallback* callback;
         599                 :   nsCallbackEventRequest* next;
         600                 : };
         601                 :
         602                 : // ----------------------------------------------------------------------------
         603                 : #define ASSERT_REFLOW_SCHEDULED_STATE()                                       \
         604                 :   NS_ASSERTION(mReflowScheduled ==                                            \
         605                 :                  GetPresContext()->RefreshDriver()->                          \
         606                 :                    IsLayoutFlushObserver(this), "Unexpected state")
         607                 :
         608                 : class nsAutoCauseReflowNotifier
         609                 : {
         610                 : public:
         611               0 :   nsAutoCauseReflowNotifier(PresShell* aShell)
         612               0 :     : mShell(aShell)
         613                 :   {
         614               0 :     mShell->WillCauseReflow();
         615               0 :   }
         616               0 :   ~nsAutoCauseReflowNotifier()
         617                 :   {
         618                 :     // This check should not be needed. Currently the only place that seem
         619                 :     // to need it is the code that deals with bug 337586.
         620               0 :     if (!mShell->mHaveShutDown) {
         621               0 :       mShell->DidCauseReflow();
         622                 :     }
         623                 :     else {
         624               0 :       nsContentUtils::RemoveScriptBlocker();
         625                 :     }
         626               0 :   }
         627                 :
         628                 :   PresShell* mShell;
         629                 : };
         630                 :
         631                 : class NS_STACK_CLASS nsPresShellEventCB : public nsDispatchingCallback
         632               0 : {
         633                 : public:
         634               0 :   nsPresShellEventCB(PresShell* aPresShell) : mPresShell(aPresShell) {}
         635                 :
         636               0 :   virtual void HandleEvent(nsEventChainPostVisitor& aVisitor)
         637                 :   {
         638               0 :     if (aVisitor.mPresContext && aVisitor.mEvent->eventStructType != NS_EVENT) {
         639               0 :       nsIFrame* frame = mPresShell->GetCurrentEventFrame();
         640               0 :       if (frame) {
         641                 :         frame->HandleEvent(aVisitor.mPresContext,
         642                 :                            (nsGUIEvent*) aVisitor.mEvent,
         643               0 :                            &aVisitor.mEventStatus);
         644                 :       }
         645                 :     }
         646               0 :   }
         647                 :
         648                 :   nsRefPtr<PresShell> mPresShell;
         649                 : };
         650                 :
         651                 : bool PresShell::sDisableNonTestMouseEvents = false;
         652                 :
         653                 : #ifdef PR_LOGGING
         654                 : PRLogModuleInfo* PresShell::gLog;
         655                 : #endif
         656                 :
         657                 : #ifdef NS_DEBUG
         658                 : static void
         659               0 : VerifyStyleTree(nsPresContext* aPresContext, nsFrameManager* aFrameManager)
         660                 : {
         661               0 :   if (nsFrame::GetVerifyStyleTreeEnable()) {
         662               0 :     nsIFrame* rootFrame = aFrameManager->GetRootFrame();
         663               0 :     aFrameManager->DebugVerifyStyleTree(rootFrame);
         664                 :   }
         665               0 : }
         666                 : #define VERIFY_STYLE_TREE ::VerifyStyleTree(mPresContext, mFrameConstructor)
         667                 : #else
         668                 : #define VERIFY_STYLE_TREE
         669                 : #endif
         670                 :
         671                 : static bool gVerifyReflowEnabled;
         672                 :
         673                 : bool
         674               0 : nsIPresShell::GetVerifyReflowEnable()
         675                 : {
         676                 : #ifdef NS_DEBUG
         677                 :   static bool firstTime = true;
         678               0 :   if (firstTime) {
         679               0 :     firstTime = false;
         680               0 :     char* flags = PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
         681               0 :     if (flags) {
         682               0 :       bool error = false;
         683                 :
         684               0 :       for (;;) {
         685               0 :         char* comma = PL_strchr(flags, ',');
         686               0 :         if (comma)
         687               0 :           *comma = '\0';
         688                 :
         689               0 :         bool found = false;
         690               0 :         const VerifyReflowFlags* flag = gFlags;
         691               0 :         const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
         692               0 :         while (flag < limit) {
         693               0 :           if (PL_strcasecmp(flag->name, flags) == 0) {
         694               0 :             gVerifyReflowFlags |= flag->bit;
         695               0 :             found = true;
         696               0 :             break;
         697                 :           }
         698               0 :           ++flag;
         699                 :         }
         700                 :
         701               0 :         if (! found)
         702               0 :           error = true;
         703                 :
         704               0 :         if (! comma)
         705                 :           break;
         706                 :
         707               0 :         *comma = ',';
         708               0 :         flags = comma + 1;
         709                 :       }
         710                 :
         711               0 :       if (error)
         712               0 :         ShowVerifyReflowFlags();
         713                 :     }
         714                 :
         715               0 :     if (VERIFY_REFLOW_ON & gVerifyReflowFlags) {
         716               0 :       gVerifyReflowEnabled = true;
         717                 :
         718               0 :       printf("Note: verifyreflow is enabled");
         719               0 :       if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
         720               0 :         printf(" (noisy)");
         721                 :       }
         722               0 :       if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
         723               0 :         printf(" (all)");
         724                 :       }
         725               0 :       if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
         726               0 :         printf(" (show reflow commands)");
         727                 :       }
         728               0 :       if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
         729               0 :         printf(" (noisy reflow commands)");
         730               0 :         if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
         731               0 :           printf(" (REALLY noisy reflow commands)");
         732                 :         }
         733                 :       }
         734               0 :       printf("\n");
         735                 :     }
         736                 :   }
         737                 : #endif
         738               0 :   return gVerifyReflowEnabled;
         739                 : }
         740                 :
         741                 : void
         742               0 : nsIPresShell::SetVerifyReflowEnable(bool aEnabled)
         743                 : {
         744               0 :   gVerifyReflowEnabled = aEnabled;
         745               0 : }
         746                 :
         747                 : /* virtual */ void
         748               0 : nsIPresShell::AddWeakFrameExternal(nsWeakFrame* aWeakFrame)
         749                 : {
         750               0 :   AddWeakFrameInternal(aWeakFrame);
         751               0 : }
         752                 :
         753                 : void
         754               0 : nsIPresShell::AddWeakFrameInternal(nsWeakFrame* aWeakFrame)
         755                 : {
         756               0 :   if (aWeakFrame->GetFrame()) {
         757               0 :     aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
         758                 :   }
         759               0 :   aWeakFrame->SetPreviousWeakFrame(mWeakFrames);
         760               0 :   mWeakFrames = aWeakFrame;
         761               0 : }
         762                 :
         763                 : /* virtual */ void
         764               0 : nsIPresShell::RemoveWeakFrameExternal(nsWeakFrame* aWeakFrame)
         765                 : {
         766               0 :   RemoveWeakFrameInternal(aWeakFrame);
         767               0 : }
         768                 :
         769                 : void
         770               0 : nsIPresShell::RemoveWeakFrameInternal(nsWeakFrame* aWeakFrame)
         771                 : {
         772               0 :   if (mWeakFrames == aWeakFrame) {
         773               0 :     mWeakFrames = aWeakFrame->GetPreviousWeakFrame();
         774               0 :     return;
         775                 :   }
         776               0 :   nsWeakFrame* nextWeak = mWeakFrames;
         777               0 :   while (nextWeak && nextWeak->GetPreviousWeakFrame() != aWeakFrame) {
         778               0 :     nextWeak = nextWeak->GetPreviousWeakFrame();
         779                 :   }
         780               0 :   if (nextWeak) {
         781               0 :     nextWeak->SetPreviousWeakFrame(aWeakFrame->GetPreviousWeakFrame());
         782                 :   }
         783                 : }
         784                 :
         785                 : already_AddRefed<nsFrameSelection>
         786               0 : nsIPresShell::FrameSelection()
         787                 : {
         788               0 :   NS_IF_ADDREF(mSelection);
         789               0 :   return mSelection;
         790                 : }
         791                 :
         792                 : //----------------------------------------------------------------------
         793                 :
         794                 : nsresult
         795               0 : NS_NewPresShell(nsIPresShell** aInstancePtrResult)
         796                 : {
         797               0 :   NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
         798                 :
         799               0 :   if (!aInstancePtrResult)
         800               0 :     return NS_ERROR_NULL_POINTER;
         801                 :
         802               0 :   *aInstancePtrResult = new PresShell();
         803                 :
         804               0 :   NS_ADDREF(*aInstancePtrResult);
         805               0 :   return NS_OK;
         806                 : }
         807                 :
         808                 : static bool sSynthMouseMove = true;
         809                 :
         810               0 : PresShell::PresShell()
         811               0 :   : mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
         812                 : {
         813               0 :   mSelection = nsnull;
         814                 : #ifdef MOZ_REFLOW_PERF
         815               0 :   mReflowCountMgr = new ReflowCountMgr();
         816               0 :   mReflowCountMgr->SetPresContext(mPresContext);
         817               0 :   mReflowCountMgr->SetPresShell(this);
         818                 : #endif
         819                 : #ifdef PR_LOGGING
         820               0 :   if (! gLog)
         821               0 :     gLog = PR_NewLogModule("PresShell");
         822                 : #endif
         823               0 :   mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES;
         824               0 :   mIsThemeSupportDisabled = false;
         825               0 :   mIsActive = true;
         826               0 :   mFrozen = false;
         827                 : #ifdef DEBUG
         828               0 :   mPresArenaAllocCount = 0;
         829                 : #endif
         830               0 :   mRenderFlags = 0;
         831               0 :   mXResolution = 1.0;
         832               0 :   mYResolution = 1.0;
         833               0 :   mViewportOverridden = false;
         834                 :
         835                 :   static bool addedSynthMouseMove = false;
         836               0 :   if (!addedSynthMouseMove) {
         837                 :     Preferences::AddBoolVarCache(&sSynthMouseMove,
         838               0 :                                  "layout.reflow.synthMouseMove", true);
         839               0 :     addedSynthMouseMove = true;
         840                 :   }
         841               0 : }
         842                 :
         843               0 : NS_IMPL_ISUPPORTS7(PresShell, nsIPresShell, nsIDocumentObserver,
         844                 :                    nsISelectionController,
         845                 :                    nsISelectionDisplay, nsIObserver, nsISupportsWeakReference,
         846                 :                    nsIMutationObserver)
         847                 :
         848               0 : PresShell::~PresShell()
         849                 : {
         850               0 :   if (!mHaveShutDown) {
         851               0 :     NS_NOTREACHED("Someone did not call nsIPresShell::destroy");
         852               0 :     Destroy();
         853                 :   }
         854                 :
         855               0 :   NS_ASSERTION(mCurrentEventContentStack.Count() == 0,
         856                 :                "Huh, event content left on the stack in pres shell dtor!");
         857               0 :   NS_ASSERTION(mFirstCallbackEventRequest == nsnull &&
         858                 :                mLastCallbackEventRequest == nsnull,
         859                 :                "post-reflow queues not empty.  This means we're leaking");
         860                 :
         861                 : #ifdef DEBUG
         862               0 :   MOZ_ASSERT(mPresArenaAllocCount == 0,
         863               0 :              "Some pres arena objects were not freed");
         864                 : #endif
         865                 :
         866               0 :   delete mStyleSet;
         867               0 :   delete mFrameConstructor;
         868                 :
         869               0 :   mCurrentEventContent = nsnull;
         870                 :
         871               0 :   NS_IF_RELEASE(mPresContext);
         872               0 :   NS_IF_RELEASE(mDocument);
         873               0 :   NS_IF_RELEASE(mSelection);
         874               0 : }
         875                 :
         876                 : /**
         877                 :  * Initialize the presentation shell. Create view manager and style
         878                 :  * manager.
         879                 :  */
         880                 : nsresult
         881               0 : PresShell::Init(nsIDocument* aDocument,
         882                 :                 nsPresContext* aPresContext,
         883                 :                 nsIViewManager* aViewManager,
         884                 :                 nsStyleSet* aStyleSet,
         885                 :                 nsCompatibility aCompatMode)
         886                 : {
         887                 :   NS_TIME_FUNCTION_MIN(1.0);
         888                 :
         889               0 :   NS_PRECONDITION(nsnull != aDocument, "null ptr");
         890               0 :   NS_PRECONDITION(nsnull != aPresContext, "null ptr");
         891               0 :   NS_PRECONDITION(nsnull != aViewManager, "null ptr");
         892                 :   nsresult result;
         893                 :
         894               0 :   if ((nsnull == aDocument) || (nsnull == aPresContext) ||
         895                 :       (nsnull == aViewManager)) {
         896               0 :     return NS_ERROR_NULL_POINTER;
         897                 :   }
         898               0 :   if (mDocument) {
         899               0 :     NS_WARNING("PresShell double init'ed");
         900               0 :     return NS_ERROR_ALREADY_INITIALIZED;
         901                 :   }
         902               0 :   result = mStackArena.Init();
         903               0 :   NS_ENSURE_SUCCESS(result, result);
         904                 :
         905               0 :   if (!mFramesToDirty.Init()) {
         906               0 :     return NS_ERROR_OUT_OF_MEMORY;
         907                 :   }
         908                 :
         909               0 :   mDocument = aDocument;
         910               0 :   NS_ADDREF(mDocument);
         911               0 :   mViewManager = aViewManager;
         912                 :
         913                 :   // Create our frame constructor.
         914               0 :   mFrameConstructor = new nsCSSFrameConstructor(mDocument, this);
         915                 :
         916               0 :   mFrameManager = mFrameConstructor;
         917                 :
         918                 :   // The document viewer owns both view manager and pres shell.
         919               0 :   mViewManager->SetPresShell(this);
         920                 :
         921                 :   // Bind the context to the presentation shell.
         922               0 :   mPresContext = aPresContext;
         923               0 :   NS_ADDREF(mPresContext);
         924               0 :   aPresContext->SetShell(this);
         925                 :
         926                 :   // Now we can initialize the style set.
         927               0 :   result = aStyleSet->Init(aPresContext);
         928               0 :   NS_ENSURE_SUCCESS(result, result);
         929                 :
         930                 :   // From this point on, any time we return an error we need to make
         931                 :   // sure to null out mStyleSet first, since an error return from this
         932                 :   // method will cause the caller to delete the style set, so we don't
         933                 :   // want to delete it in our destructor.
         934               0 :   mStyleSet = aStyleSet;
         935                 :
         936                 :   // Notify our prescontext that it now has a compatibility mode.  Note that
         937                 :   // this MUST happen after we set up our style set but before we create any
         938                 :   // frames.
         939               0 :   mPresContext->CompatibilityModeChanged();
         940                 :
         941                 :   // setup the preference style rules (no forced reflow), and do it
         942                 :   // before creating any frames.
         943               0 :   SetPreferenceStyleRules(false);
         944                 :
         945               0 :   NS_ADDREF(mSelection = new nsFrameSelection());
         946                 :
         947                 :   // Create and initialize the frame manager
         948                 :   // XXXjwatt it would be better if we did this right after creating
         949                 :   // mFrameConstructor, since the frame constructor and frame manager
         950                 :   // are now the same object.
         951               0 :   result =  mFrameConstructor->Init(mStyleSet);
         952               0 :   if (NS_FAILED(result)) {
         953               0 :     NS_WARNING("Frame manager initialization failed");
         954               0 :     mStyleSet = nsnull;
         955               0 :     return result;
         956                 :   }
         957                 :
         958               0 :   mSelection->Init(this, nsnull);
         959                 :
         960                 :   // Important: this has to happen after the selection has been set up
         961                 : #ifdef SHOW_CARET
         962                 :   // make the caret
         963               0 :   mCaret = new nsCaret();
         964               0 :   mCaret->Init(this);
         965               0 :   mOriginalCaret = mCaret;
         966                 :
         967                 :   //SetCaretEnabled(true);       // make it show in browser windows
         968                 : #endif
         969                 :   //set up selection to be displayed in document
         970                 :   // Don't enable selection for print media
         971               0 :   nsPresContext::nsPresContextType type = aPresContext->Type();
         972               0 :   if (type != nsPresContext::eContext_PrintPreview &&
         973                 :       type != nsPresContext::eContext_Print)
         974               0 :     SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
         975                 :
         976               0 :   if (gMaxRCProcessingTime == -1) {
         977                 :     gMaxRCProcessingTime =
         978               0 :       Preferences::GetInt("layout.reflow.timeslice", NS_MAX_REFLOW_TIME);
         979                 :   }
         980                 :
         981                 :   {
         982               0 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
         983               0 :     if (os) {
         984               0 :       os->AddObserver(this, "agent-sheet-added", false);
         985               0 :       os->AddObserver(this, "user-sheet-added", false);
         986               0 :       os->AddObserver(this, "agent-sheet-removed", false);
         987               0 :       os->AddObserver(this, "user-sheet-removed", false);
         988                 : #ifdef MOZ_XUL
         989               0 :       os->AddObserver(this, "chrome-flush-skin-caches", false);
         990                 : #endif
         991                 :     }
         992                 :   }
         993                 :
         994                 :   // cache the drag service so we can check it during reflows
         995               0 :   mDragService = do_GetService("@mozilla.org/widget/dragservice;1");
         996                 :
         997                 : #ifdef MOZ_REFLOW_PERF
         998               0 :     if (mReflowCountMgr) {
         999                 :       bool paintFrameCounts =
        1000               0 :         Preferences::GetBool("layout.reflow.showframecounts");
        1001                 :
        1002                 :       bool dumpFrameCounts =
        1003               0 :         Preferences::GetBool("layout.reflow.dumpframecounts");
        1004                 :
        1005                 :       bool dumpFrameByFrameCounts =
        1006               0 :         Preferences::GetBool("layout.reflow.dumpframebyframecounts");
        1007                 :
        1008               0 :       mReflowCountMgr->SetDumpFrameCounts(dumpFrameCounts);
        1009               0 :       mReflowCountMgr->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts);
        1010               0 :       mReflowCountMgr->SetPaintFrameCounts(paintFrameCounts);
        1011                 :     }
        1012                 : #endif
        1013                 :
        1014               0 :   if (mDocument->HasAnimationController()) {
        1015               0 :     nsSMILAnimationController* animCtrl = mDocument->GetAnimationController();
        1016               0 :     animCtrl->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
        1017                 :   }
        1018                 :
        1019                 :   // Get our activeness from the docShell.
        1020               0 :   QueryIsActive();
        1021                 :
        1022               0 :   return NS_OK;
        1023                 : }
        1024                 :
        1025                 : void
        1026               0 : PresShell::Destroy()
        1027                 : {
        1028                 :   NS_TIME_FUNCTION_MIN(1.0);
        1029                 :
        1030               0 :   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
        1031                 :     "destroy called on presshell while scripts not blocked");
        1032                 :
        1033                 : #ifdef MOZ_REFLOW_PERF
        1034               0 :   DumpReflows();
        1035               0 :   if (mReflowCountMgr) {
        1036               0 :     delete mReflowCountMgr;
        1037               0 :     mReflowCountMgr = nsnull;
        1038                 :   }
        1039                 : #endif
        1040                 :
        1041               0 :   if (mHaveShutDown)
        1042               0 :     return;
        1043                 :
        1044                 : #ifdef ACCESSIBILITY
        1045               0 :   nsAccessibilityService* accService = AccService();
        1046               0 :   if (accService) {
        1047               0 :     accService->PresShellDestroyed(this);
        1048                 :   }
        1049                 : #endif // ACCESSIBILITY
        1050                 :
        1051               0 :   MaybeReleaseCapturingContent();
        1052                 :
        1053               0 :   if (gKeyDownTarget && gKeyDownTarget->OwnerDoc() == mDocument) {
        1054               0 :     NS_RELEASE(gKeyDownTarget);
        1055                 :   }
        1056                 :
        1057               0 :   mContentToScrollTo = nsnull;
        1058                 :
        1059               0 :   if (mPresContext) {
        1060                 :     // We need to notify the destroying the nsPresContext to ESM for
        1061                 :     // suppressing to use from ESM.
        1062               0 :     mPresContext->EventStateManager()->NotifyDestroyPresContext(mPresContext);
        1063                 :   }
        1064                 :
        1065                 :   {
        1066               0 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
        1067               0 :     if (os) {
        1068               0 :       os->RemoveObserver(this, "agent-sheet-added");
        1069               0 :       os->RemoveObserver(this, "user-sheet-added");
        1070               0 :       os->RemoveObserver(this, "agent-sheet-removed");
        1071               0 :       os->RemoveObserver(this, "user-sheet-removed");
        1072                 : #ifdef MOZ_XUL
        1073               0 :       os->RemoveObserver(this, "chrome-flush-skin-caches");
        1074                 : #endif
        1075                 :     }
        1076                 :   }
        1077                 :
        1078                 :   // If our paint suppression timer is still active, kill it.
        1079               0 :   if (mPaintSuppressionTimer) {
        1080               0 :     mPaintSuppressionTimer->Cancel();
        1081               0 :     mPaintSuppressionTimer = nsnull;
        1082                 :   }
        1083                 :
        1084                 :   // Same for our reflow continuation timer
        1085               0 :   if (mReflowContinueTimer) {
        1086               0 :     mReflowContinueTimer->Cancel();
        1087               0 :     mReflowContinueTimer = nsnull;
        1088                 :   }
        1089                 :
        1090               0 :   mSynthMouseMoveEvent.Revoke();
        1091                 :
        1092               0 :   if (mCaret) {
        1093               0 :     mCaret->Terminate();
        1094               0 :     mCaret = nsnull;
        1095                 :   }
        1096                 :
        1097               0 :   if (mSelection) {
        1098               0 :     mSelection->DisconnectFromPresShell();
        1099                 :   }
        1100                 :
        1101                 :   // release our pref style sheet, if we have one still
        1102               0 :   ClearPreferenceStyleRules();
        1103                 :
        1104               0 :   mIsDestroying = true;
        1105                 :
        1106                 :   // We can't release all the event content in
        1107                 :   // mCurrentEventContentStack here since there might be code on the
        1108                 :   // stack that will release the event content too. Double release
        1109                 :   // bad!
        1110                 :
        1111                 :   // The frames will be torn down, so remove them from the current
        1112                 :   // event frame stack (since they'd be dangling references if we'd
        1113                 :   // leave them in) and null out the mCurrentEventFrame pointer as
        1114                 :   // well.
        1115                 :
        1116               0 :   mCurrentEventFrame = nsnull;
        1117                 :
        1118               0 :   PRInt32 i, count = mCurrentEventFrameStack.Length();
        1119               0 :   for (i = 0; i < count; i++) {
        1120               0 :     mCurrentEventFrameStack[i] = nsnull;
        1121                 :   }
        1122                 :
        1123               0 :   mFramesToDirty.Clear();
        1124                 :
        1125               0 :   if (mViewManager) {
        1126                 :     // Clear the view manager's weak pointer back to |this| in case it
        1127                 :     // was leaked.
        1128               0 :     mViewManager->SetPresShell(nsnull);
        1129               0 :     mViewManager = nsnull;
        1130                 :   }
        1131                 :
        1132               0 :   mStyleSet->BeginShutdown(mPresContext);
        1133               0 :   nsRefreshDriver* rd = GetPresContext()->RefreshDriver();
        1134                 :
        1135                 :   // This shell must be removed from the document before the frame
        1136                 :   // hierarchy is torn down to avoid finding deleted frames through
        1137                 :   // this presshell while the frames are being torn down
        1138               0 :   if (mDocument) {
        1139               0 :     NS_ASSERTION(mDocument->GetShell() == this, "Wrong shell?");
        1140               0 :     mDocument->DeleteShell();
        1141                 :
        1142               0 :     if (mDocument->HasAnimationController()) {
        1143               0 :       mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
        1144                 :     }
        1145                 :   }
        1146                 :
        1147                 :   // Revoke any pending events.  We need to do this and cancel pending reflows
        1148                 :   // before we destroy the frame manager, since apparently frame destruction
        1149                 :   // sometimes spins the event queue when plug-ins are involved(!).
        1150               0 :   rd->RemoveLayoutFlushObserver(this);
        1151               0 :   rd->RevokeViewManagerFlush();
        1152                 :
        1153               0 :   mResizeEvent.Revoke();
        1154               0 :   if (mAsyncResizeTimerIsActive) {
        1155               0 :     mAsyncResizeEventTimer->Cancel();
        1156               0 :     mAsyncResizeTimerIsActive = false;
        1157                 :   }
        1158                 :
        1159               0 :   CancelAllPendingReflows();
        1160               0 :   CancelPostedReflowCallbacks();
        1161                 :
        1162                 :   // Destroy the frame manager. This will destroy the frame hierarchy
        1163               0 :   mFrameConstructor->WillDestroyFrameTree();
        1164                 :
        1165                 :   // Destroy all frame properties (whose destruction was suppressed
        1166                 :   // while destroying the frame tree, but which might contain more
        1167                 :   // frames within the properties.
        1168               0 :   if (mPresContext) {
        1169                 :     // Clear out the prescontext's property table -- since our frame tree is
        1170                 :     // now dead, we shouldn't be looking up any more properties in that table.
        1171                 :     // We want to do this before we call SetShell() on the prescontext, so
        1172                 :     // property destructors can usefully call GetPresShell() on the
        1173                 :     // prescontext.
        1174               0 :     mPresContext->PropertyTable()->DeleteAll();
        1175                 :   }
        1176                 :
        1177                 :
        1178               0 :   NS_WARN_IF_FALSE(!mWeakFrames, "Weak frames alive after destroying FrameManager");
        1179               0 :   while (mWeakFrames) {
        1180               0 :     mWeakFrames->Clear(this);
        1181                 :   }
        1182                 :
        1183                 :   // Let the style set do its cleanup.
        1184               0 :   mStyleSet->Shutdown(mPresContext);
        1185                 :
        1186               0 :   if (mPresContext) {
        1187                 :     // We hold a reference to the pres context, and it holds a weak link back
        1188                 :     // to us. To avoid the pres context having a dangling reference, set its
        1189                 :     // pres shell to NULL
        1190               0 :     mPresContext->SetShell(nsnull);
        1191                 :
        1192                 :     // Clear the link handler (weak reference) as well
        1193               0 :     mPresContext->SetLinkHandler(nsnull);
        1194                 :   }
        1195                 :
        1196               0 :   mHaveShutDown = true;
        1197                 : }
        1198                 :
        1199                 :                   // Dynamic stack memory allocation
        1200                 : /* virtual */ void
        1201               0 : PresShell::PushStackMemory()
        1202                 : {
        1203               0 :   mStackArena.Push();
        1204               0 : }
        1205                 :
        1206                 : /* virtual */ void
        1207               0 : PresShell::PopStackMemory()
        1208                 : {
        1209               0 :   mStackArena.Pop();
        1210               0 : }
        1211                 :
        1212                 : /* virtual */ void*
        1213               0 : PresShell::AllocateStackMemory(size_t aSize)
        1214                 : {
        1215               0 :   return mStackArena.Allocate(aSize);
        1216                 : }
        1217                 :
        1218                 : void
        1219               0 : PresShell::FreeFrame(nsQueryFrame::FrameIID aCode, void* aPtr)
        1220                 : {
        1221                 : #ifdef DEBUG
        1222               0 :   mPresArenaAllocCount--;
        1223                 : #endif
        1224               0 :   if (PRESARENA_MUST_FREE_DURING_DESTROY || !mIsDestroying)
        1225               0 :     mFrameArena.FreeByCode(aCode, aPtr);
        1226               0 : }
        1227                 :
        1228                 : void*
        1229               0 : PresShell::AllocateFrame(nsQueryFrame::FrameIID aCode, size_t aSize)
        1230                 : {
        1231                 : #ifdef DEBUG
        1232               0 :   mPresArenaAllocCount++;
        1233                 : #endif
        1234               0 :   void* result = mFrameArena.AllocateByCode(aCode, aSize);
        1235                 :
        1236               0 :   if (result) {
        1237               0 :     memset(result, 0, aSize);
        1238                 :   }
        1239               0 :   return result;
        1240                 : }
        1241                 :
        1242                 : void
        1243               0 : PresShell::FreeMisc(size_t aSize, void* aPtr)
        1244                 : {
        1245                 : #ifdef DEBUG
        1246               0 :   mPresArenaAllocCount--;
        1247                 : #endif
        1248               0 :   if (PRESARENA_MUST_FREE_DURING_DESTROY || !mIsDestroying)
        1249               0 :     mFrameArena.FreeBySize(aSize, aPtr);
        1250               0 : }
        1251                 :
        1252                 : void*
        1253               0 : PresShell::AllocateMisc(size_t aSize)
        1254                 : {
        1255                 : #ifdef DEBUG
        1256               0 :   mPresArenaAllocCount++;
        1257                 : #endif
        1258               0 :   return mFrameArena.AllocateBySize(aSize);
        1259                 : }
        1260                 :
        1261                 : void
        1262               0 : nsIPresShell::SetAuthorStyleDisabled(bool aStyleDisabled)
        1263                 : {
        1264               0 :   if (aStyleDisabled != mStyleSet->GetAuthorStyleDisabled()) {
        1265               0 :     mStyleSet->SetAuthorStyleDisabled(aStyleDisabled);
        1266               0 :     ReconstructStyleData();
        1267                 :   }
        1268               0 : }
        1269                 :
        1270                 : bool
        1271               0 : nsIPresShell::GetAuthorStyleDisabled() const
        1272                 : {
        1273               0 :   return mStyleSet->GetAuthorStyleDisabled();
        1274                 : }
        1275                 :
        1276                 : nsresult
        1277               0 : PresShell::SetPreferenceStyleRules(bool aForceReflow)
        1278                 : {
        1279                 :   NS_TIME_FUNCTION_MIN(1.0);
        1280                 :
        1281               0 :   if (!mDocument) {
        1282               0 :     return NS_ERROR_NULL_POINTER;
        1283                 :   }
        1284                 :
        1285               0 :   nsPIDOMWindow *window = mDocument->GetWindow();
        1286                 :
        1287                 :   // If the document doesn't have a window there's no need to notify
        1288                 :   // its presshell about changes to preferences since the document is
        1289                 :   // in a state where it doesn't matter any more (see
        1290                 :   // DocumentViewerImpl::Close()).
        1291                 :
        1292               0 :   if (!window) {
        1293               0 :     return NS_ERROR_NULL_POINTER;
        1294                 :   }
        1295                 :
        1296               0 :   NS_PRECONDITION(mPresContext, "presContext cannot be null");
        1297               0 :   if (mPresContext) {
        1298                 :     // first, make sure this is not a chrome shell
        1299               0 :     if (nsContentUtils::IsInChromeDocshell(mDocument)) {
        1300               0 :       return NS_OK;
        1301                 :     }
        1302                 :
        1303                 : #ifdef DEBUG_attinasi
        1304                 :     printf("Setting Preference Style Rules:\n");
        1305                 : #endif
        1306                 :     // if here, we need to create rules for the prefs
        1307                 :     // - this includes the background-color, the text-color,
        1308                 :     //   the link color, the visited link color and the link-underlining
        1309                 :
        1310                 :     // first clear any exising rules
        1311               0 :     nsresult result = ClearPreferenceStyleRules();
        1312                 :
        1313                 :     // now the link rules (must come after the color rules, or links will not be correct color!)
        1314                 :     // XXX - when there is both an override and agent pref stylesheet this won't matter,
        1315                 :     //       as the color rules will be overrides and the links rules will be agent
        1316               0 :     if (NS_SUCCEEDED(result)) {
        1317               0 :       result = SetPrefLinkRules();
        1318                 :     }
        1319               0 :     if (NS_SUCCEEDED(result)) {
        1320               0 :       result = SetPrefFocusRules();
        1321                 :     }
        1322               0 :     if (NS_SUCCEEDED(result)) {
        1323               0 :       result = SetPrefNoScriptRule();
        1324                 :     }
        1325               0 :     if (NS_SUCCEEDED(result)) {
        1326               0 :       result = SetPrefNoFramesRule();
        1327                 :     }
        1328                 : #ifdef DEBUG_attinasi
        1329                 :     printf( "Preference Style Rules set: error=%ld\n", (long)result);
        1330                 : #endif
        1331                 :
        1332                 :     // Note that this method never needs to force any calculation; the caller
        1333                 :     // will recalculate style if needed
        1334                 :
        1335               0 :     return result;
        1336                 :   }
        1337                 :
        1338               0 :   return NS_ERROR_NULL_POINTER;
        1339                 : }
        1340                 :
        1341               0 : nsresult PresShell::ClearPreferenceStyleRules(void)
        1342                 : {
        1343               0 :   nsresult result = NS_OK;
        1344               0 :   if (mPrefStyleSheet) {
        1345               0 :     NS_ASSERTION(mStyleSet, "null styleset entirely unexpected!");
        1346               0 :     if (mStyleSet) {
        1347                 :       // remove the sheet from the styleset:
        1348                 :       // - note that we have to check for success by comparing the count before and after...
        1349                 : #ifdef NS_DEBUG
        1350               0 :       PRInt32 numBefore = mStyleSet->SheetCount(nsStyleSet::eUserSheet);
        1351               0 :       NS_ASSERTION(numBefore > 0, "no user stylesheets in styleset, but we have one!");
        1352                 : #endif
        1353               0 :       mStyleSet->RemoveStyleSheet(nsStyleSet::eUserSheet, mPrefStyleSheet);
        1354                 :
        1355                 : #ifdef DEBUG_attinasi
        1356                 :       NS_ASSERTION((numBefore - 1) == mStyleSet->GetNumberOfUserStyleSheets(),
        1357                 :                    "Pref stylesheet was not removed");
        1358                 :       printf("PrefStyleSheet removed\n");
        1359                 : #endif
        1360                 :       // clear the sheet pointer: it is strictly historical now
        1361               0 :       mPrefStyleSheet = nsnull;
        1362                 :     }
        1363                 :   }
        1364               0 :   return result;
        1365                 : }
        1366                 :
        1367               0 : nsresult PresShell::CreatePreferenceStyleSheet(void)
        1368                 : {
        1369                 :   NS_TIME_FUNCTION_MIN(1.0);
        1370                 :
        1371               0 :   NS_ASSERTION(!mPrefStyleSheet, "prefStyleSheet already exists");
        1372               0 :   nsresult result = NS_NewCSSStyleSheet(getter_AddRefs(mPrefStyleSheet));
        1373               0 :   if (NS_SUCCEEDED(result)) {
        1374               0 :     NS_ASSERTION(mPrefStyleSheet, "null but no error");
        1375               0 :     nsCOMPtr<nsIURI> uri;
        1376               0 :     result = NS_NewURI(getter_AddRefs(uri), "about:PreferenceStyleSheet", nsnull);
        1377               0 :     if (NS_SUCCEEDED(result)) {
        1378               0 :       NS_ASSERTION(uri, "null but no error");
        1379               0 :       mPrefStyleSheet->SetURIs(uri, uri, uri);
        1380               0 :       mPrefStyleSheet->SetComplete();
        1381                 :       PRUint32 index;
        1382                 :       result =
        1383               0 :         mPrefStyleSheet->InsertRuleInternal(NS_LITERAL_STRING("@namespace url(http://www.w3.org/1999/xhtml);"),
        1384               0 :                                             0, &index);
        1385               0 :       if (NS_SUCCEEDED(result)) {
        1386               0 :         mStyleSet->AppendStyleSheet(nsStyleSet::eUserSheet, mPrefStyleSheet);
        1387                 :       }
        1388                 :     }
        1389                 :   }
        1390                 :
        1391                 : #ifdef DEBUG_attinasi
        1392                 :   printf("CreatePrefStyleSheet completed: error=%ld\n",(long)result);
        1393                 : #endif
        1394                 :
        1395               0 :   if (NS_FAILED(result)) {
        1396               0 :     mPrefStyleSheet = nsnull;
        1397                 :   }
        1398                 :
        1399               0 :   return result;
        1400                 : }
        1401                 :
        1402                 : // XXX We want these after the @namespace rule.  Does order matter
        1403                 : // for these rules, or can we call StyleRule::StyleRuleCount()
        1404                 : // and just "append"?
        1405                 : static PRUint32 sInsertPrefSheetRulesAt = 1;
        1406                 :
        1407                 : nsresult
        1408               0 : PresShell::SetPrefNoScriptRule()
        1409                 : {
        1410                 :   NS_TIME_FUNCTION_MIN(1.0);
        1411                 :
        1412               0 :   nsresult rv = NS_OK;
        1413                 :
        1414                 :   // also handle the case where print is done from print preview
        1415                 :   // see bug #342439 for more details
        1416               0 :   nsIDocument* doc = mDocument;
        1417               0 :   if (doc->IsStaticDocument()) {
        1418               0 :     doc = doc->GetOriginalDocument();
        1419                 :   }
        1420                 :
        1421               0 :   bool scriptEnabled = doc->IsScriptEnabled();
        1422               0 :   if (scriptEnabled) {
        1423               0 :     if (!mPrefStyleSheet) {
        1424               0 :       rv = CreatePreferenceStyleSheet();
        1425               0 :       NS_ENSURE_SUCCESS(rv, rv);
        1426                 :     }
        1427                 :
        1428               0 :     PRUint32 index = 0;
        1429                 :     mPrefStyleSheet->
        1430               0 :       InsertRuleInternal(NS_LITERAL_STRING("noscript{display:none!important}"),
        1431               0 :                          sInsertPrefSheetRulesAt, &index);
        1432                 :   }
        1433                 :
        1434               0 :   return rv;
        1435                 : }
        1436                 :
        1437               0 : nsresult PresShell::SetPrefNoFramesRule(void)
        1438                 : {
        1439                 :   NS_TIME_FUNCTION_MIN(1.0);
        1440                 :
        1441               0 :   NS_ASSERTION(mPresContext,"null prescontext not allowed");
        1442               0 :   if (!mPresContext) {
        1443               0 :     return NS_ERROR_FAILURE;
        1444                 :   }
        1445                 :
        1446               0 :   nsresult rv = NS_OK;
        1447                 :
        1448               0 :   if (!mPrefStyleSheet) {
        1449               0 :     rv = CreatePreferenceStyleSheet();
        1450               0 :     NS_ENSURE_SUCCESS(rv, rv);
        1451                 :   }
        1452                 :
        1453               0 :   NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null");
        1454                 :
        1455               0 :   bool allowSubframes = true;
        1456               0 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
        1457               0 :   nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
        1458               0 :   if (docShell) {
        1459               0 :     docShell->GetAllowSubframes(&allowSubframes);
        1460                 :   }
        1461               0 :   if (!allowSubframes) {
        1462               0 :     PRUint32 index = 0;
        1463                 :     rv = mPrefStyleSheet->
        1464               0 :       InsertRuleInternal(NS_LITERAL_STRING("noframes{display:block}"),
        1465               0 :                          sInsertPrefSheetRulesAt, &index);
        1466               0 :     NS_ENSURE_SUCCESS(rv, rv);
        1467                 :     rv = mPrefStyleSheet->
        1468               0 :       InsertRuleInternal(NS_LITERAL_STRING("frame, frameset, iframe {display:none!important}"),
        1469               0 :                          sInsertPrefSheetRulesAt, &index);
        1470                 :   }
        1471               0 :   return rv;
        1472                 : }
        1473                 :
        1474               0 : nsresult PresShell::SetPrefLinkRules(void)
        1475                 : {
        1476                 :   NS_TIME_FUNCTION_MIN(1.0);
        1477                 :
        1478               0 :   NS_ASSERTION(mPresContext,"null prescontext not allowed");
        1479               0 :   if (!mPresContext) {
        1480               0 :     return NS_ERROR_FAILURE;
        1481                 :   }
        1482                 :
        1483               0 :   nsresult rv = NS_OK;
        1484                 :
        1485               0 :   if (!mPrefStyleSheet) {
        1486               0 :     rv = CreatePreferenceStyleSheet();
        1487               0 :     NS_ENSURE_SUCCESS(rv, rv);
        1488                 :   }
        1489                 :
        1490               0 :   NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null");
        1491                 :
        1492                 :   // support default link colors:
        1493                 :   //   this means the link colors need to be overridable,
        1494                 :   //   which they are if we put them in the agent stylesheet,
        1495                 :   //   though if using an override sheet this will cause authors grief still
        1496                 :   //   In the agent stylesheet, they are !important when we are ignoring document colors
        1497                 :
        1498               0 :   nscolor linkColor(mPresContext->DefaultLinkColor());
        1499               0 :   nscolor activeColor(mPresContext->DefaultActiveLinkColor());
        1500               0 :   nscolor visitedColor(mPresContext->DefaultVisitedLinkColor());
        1501                 :
        1502               0 :   NS_NAMED_LITERAL_STRING(ruleClose, "}");
        1503               0 :   PRUint32 index = 0;
        1504               0 :   nsAutoString strColor;
        1505                 :
        1506                 :   // insert a rule to color links: '*|*:link {color: #RRGGBB [!important];}'
        1507               0 :   ColorToString(linkColor, strColor);
        1508                 :   rv = mPrefStyleSheet->
        1509               0 :     InsertRuleInternal(NS_LITERAL_STRING("*|*:link{color:") +
        1510               0 :                        strColor + ruleClose,
        1511               0 :                        sInsertPrefSheetRulesAt, &index);
        1512               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1513                 :
        1514                 :   // - visited links: '*|*:visited {color: #RRGGBB [!important];}'
        1515               0 :   ColorToString(visitedColor, strColor);
        1516                 :   rv = mPrefStyleSheet->
        1517               0 :     InsertRuleInternal(NS_LITERAL_STRING("*|*:visited{color:") +
        1518               0 :                        strColor + ruleClose,
        1519               0 :                        sInsertPrefSheetRulesAt, &index);
        1520               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1521                 :
        1522                 :   // - active links: '*|*:-moz-any-link:active {color: #RRGGBB [!important];}'
        1523               0 :   ColorToString(activeColor, strColor);
        1524                 :   rv = mPrefStyleSheet->
        1525               0 :     InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link:active{color:") +
        1526               0 :                        strColor + ruleClose,
        1527               0 :                        sInsertPrefSheetRulesAt, &index);
        1528               0 :   NS_ENSURE_SUCCESS(rv, rv);
        1529                 :
        1530                 :   bool underlineLinks =
        1531               0 :     mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
        1532                 :
        1533               0 :   if (underlineLinks) {
        1534                 :     // create a rule to make underlining happen
        1535                 :     //  '*|*:-moz-any-link {text-decoration:[underline|none];}'
        1536                 :     // no need for important, we want these to be overridable
        1537                 :     // NOTE: these must go in the agent stylesheet or they cannot be
        1538                 :     //       overridden by authors
        1539                 :     rv = mPrefStyleSheet->
        1540               0 :       InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:underline}"),
        1541               0 :                          sInsertPrefSheetRulesAt, &index);
        1542                 :   } else {
        1543                 :     rv = mPrefStyleSheet->
        1544               0 :       InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:none}"),
        1545               0 :                          sInsertPrefSheetRulesAt, &index);
        1546                 :   }
        1547                 :
        1548               0 :   return rv;
        1549                 : }
        1550                 :
        1551               0 : nsresult PresShell::SetPrefFocusRules(void)
        1552                 : {
        1553                 :   NS_TIME_FUNCTION_MIN(1.0);
        1554                 :
        1555               0 :   NS_ASSERTION(mPresContext,"null prescontext not allowed");
        1556               0 :   nsresult result = NS_OK;
        1557                 :
        1558               0 :   if (!mPresContext)
        1559               0 :     result = NS_ERROR_FAILURE;
        1560                 :
        1561               0 :   if (NS_SUCCEEDED(result) && !mPrefStyleSheet)
        1562               0 :     result = CreatePreferenceStyleSheet();
        1563                 :
        1564               0 :   if (NS_SUCCEEDED(result)) {
        1565               0 :     NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null");
        1566                 :
        1567               0 :     if (mPresContext->GetUseFocusColors()) {
        1568               0 :       nscolor focusBackground(mPresContext->FocusBackgroundColor());
        1569               0 :       nscolor focusText(mPresContext->FocusTextColor());
        1570                 :
        1571                 :       // insert a rule to make focus the preferred color
        1572               0 :       PRUint32 index = 0;
        1573               0 :       nsAutoString strRule, strColor;
        1574                 :
        1575                 :       ///////////////////////////////////////////////////////////////
        1576                 :       // - focus: '*:focus
        1577               0 :       ColorToString(focusText,strColor);
        1578               0 :       strRule.AppendLiteral("*:focus,*:focus>font {color: ");
        1579               0 :       strRule.Append(strColor);
        1580               0 :       strRule.AppendLiteral(" !important; background-color: ");
        1581               0 :       ColorToString(focusBackground,strColor);
        1582               0 :       strRule.Append(strColor);
        1583               0 :       strRule.AppendLiteral(" !important; } ");
        1584                 :       // insert the rules
        1585                 :       result = mPrefStyleSheet->
        1586               0 :         InsertRuleInternal(strRule, sInsertPrefSheetRulesAt, &index);
        1587                 :     }
        1588               0 :     PRUint8 focusRingWidth = mPresContext->FocusRingWidth();
        1589               0 :     bool focusRingOnAnything = mPresContext->GetFocusRingOnAnything();
        1590               0 :     PRUint8 focusRingStyle = mPresContext->GetFocusRingStyle();
        1591                 :
        1592               0 :     if ((NS_SUCCEEDED(result) && focusRingWidth != 1 && focusRingWidth <= 4 ) || focusRingOnAnything) {
        1593               0 :       PRUint32 index = 0;
        1594               0 :       nsAutoString strRule;
        1595               0 :       if (!focusRingOnAnything)
        1596               0 :         strRule.AppendLiteral("*|*:link:focus, *|*:visited");    // If we only want focus rings on the normal things like links
        1597               0 :       strRule.AppendLiteral(":focus {outline: ");     // For example 3px dotted WindowText (maximum 4)
        1598               0 :       strRule.AppendInt(focusRingWidth);
        1599               0 :       if (focusRingStyle == 0) // solid
        1600               0 :         strRule.AppendLiteral("px solid -moz-mac-focusring !important; -moz-outline-radius: 3px; outline-offset: 1px; } ");
        1601                 :       else // dotted
        1602               0 :         strRule.AppendLiteral("px dotted WindowText !important; } ");
        1603                 :       // insert the rules
        1604                 :       result = mPrefStyleSheet->
        1605               0 :         InsertRuleInternal(strRule, sInsertPrefSheetRulesAt, &index);
        1606               0 :       NS_ENSURE_SUCCESS(result, result);
        1607               0 :       if (focusRingWidth != 1) {
        1608                 :         // If the focus ring width is different from the default, fix buttons with rings
        1609               0 :         strRule.AssignLiteral("button::-moz-focus-inner, input[type=\"reset\"]::-moz-focus-inner,");
        1610               0 :         strRule.AppendLiteral("input[type=\"button\"]::-moz-focus-inner, ");
        1611               0 :         strRule.AppendLiteral("input[type=\"submit\"]::-moz-focus-inner { padding: 1px 2px 1px 2px; border: ");
        1612               0 :         strRule.AppendInt(focusRingWidth);
        1613               0 :         if (focusRingStyle == 0) // solid
        1614               0 :           strRule.AppendLiteral("px solid transparent !important; } ");
        1615                 :         else
        1616               0 :           strRule.AppendLiteral("px dotted transparent !important; } ");
        1617                 :         result = mPrefStyleSheet->
        1618               0 :           InsertRuleInternal(strRule, sInsertPrefSheetRulesAt, &index);
        1619               0 :         NS_ENSURE_SUCCESS(result, result);
        1620                 :
        1621               0 :         strRule.AssignLiteral("button:focus::-moz-focus-inner, input[type=\"reset\"]:focus::-moz-focus-inner,");
        1622               0 :         strRule.AppendLiteral("input[type=\"button\"]:focus::-moz-focus-inner, input[type=\"submit\"]:focus::-moz-focus-inner {");
        1623               0 :         strRule.AppendLiteral("border-color: ButtonText !important; }");
        1624                 :         result = mPrefStyleSheet->
        1625               0 :           InsertRuleInternal(strRule, sInsertPrefSheetRulesAt, &index);
        1626                 :       }
        1627                 :     }
        1628                 :   }
        1629               0 :   return result;
        1630                 : }
        1631                 :
        1632                 : void
        1633               0 : PresShell::AddUserSheet(nsISupports* aSheet)
        1634                 : {
        1635                 :   // Make sure this does what DocumentViewerImpl::CreateStyleSet does wrt
        1636                 :   // ordering. We want this new sheet to come after all the existing stylesheet
        1637                 :   // service sheets, but before other user sheets; see nsIStyleSheetService.idl
        1638                 :   // for the ordering.  Just remove and readd all the nsStyleSheetService
        1639                 :   // sheets.
        1640                 :   nsCOMPtr<nsIStyleSheetService> dummy =
        1641               0 :     do_GetService(NS_STYLESHEETSERVICE_CONTRACTID);
        1642                 :
        1643               0 :   mStyleSet->BeginUpdate();
        1644                 :
        1645               0 :   nsStyleSheetService *sheetService = nsStyleSheetService::gInstance;
        1646               0 :   nsCOMArray<nsIStyleSheet> & userSheets = *sheetService->UserStyleSheets();
        1647                 :   PRInt32 i;
        1648                 :   // Iterate forwards when removing so the searches for RemoveStyleSheet are as
        1649                 :   // short as possible.
        1650               0 :   for (i = 0; i < userSheets.Count(); ++i) {
        1651               0 :     mStyleSet->RemoveStyleSheet(nsStyleSet::eUserSheet, userSheets[i]);
        1652                 :   }
        1653                 :
        1654                 :   // Now iterate backwards, so that the order of userSheets will be the same as
        1655                 :   // the order of sheets from it in the style set.
        1656               0 :   for (i = userSheets.Count() - 1; i >= 0; --i) {
        1657               0 :     mStyleSet->PrependStyleSheet(nsStyleSet::eUserSheet, userSheets[i]);
        1658                 :   }
        1659                 :
        1660               0 :   mStyleSet->EndUpdate();
        1661                 :
        1662               0 :   ReconstructStyleData();
        1663               0 : }
        1664                 :
        1665                 : void
        1666               0 : PresShell::AddAgentSheet(nsISupports* aSheet)
        1667                 : {
        1668                 :   // Make sure this does what DocumentViewerImpl::CreateStyleSet does
        1669                 :   // wrt ordering.
        1670               0 :   nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet);
        1671               0 :   if (!sheet) {
        1672                 :     return;
        1673                 :   }
        1674                 :
        1675               0 :   mStyleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, sheet);
        1676               0 :   ReconstructStyleData();
        1677                 : }
        1678                 :
        1679                 : void
        1680               0 : PresShell::RemoveSheet(nsStyleSet::sheetType aType, nsISupports* aSheet)
        1681                 : {
        1682               0 :   nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet);
        1683               0 :   if (!sheet) {
        1684                 :     return;
        1685                 :   }
        1686                 :
        1687               0 :   mStyleSet->RemoveStyleSheet(aType, sheet);
        1688               0 :   ReconstructStyleData();
        1689                 : }
        1690                 :
        1691                 : NS_IMETHODIMP
        1692               0 : PresShell::SetDisplaySelection(PRInt16 aToggle)
        1693                 : {
        1694               0 :   mSelection->SetDisplaySelection(aToggle);
        1695               0 :   return NS_OK;
        1696                 : }
        1697                 :
        1698                 : NS_IMETHODIMP
        1699               0 : PresShell::GetDisplaySelection(PRInt16 *aToggle)
        1700                 : {
        1701               0 :   *aToggle = mSelection->GetDisplaySelection();
        1702               0 :   return NS_OK;
        1703                 : }
        1704                 :
        1705                 : NS_IMETHODIMP
        1706               0 : PresShell::GetSelection(SelectionType aType, nsISelection **aSelection)
        1707                 : {
        1708               0 :   if (!aSelection || !mSelection)
        1709               0 :     return NS_ERROR_NULL_POINTER;
        1710                 :
        1711               0 :   *aSelection = mSelection->GetSelection(aType);
        1712                 :
        1713               0 :   if (!(*aSelection))
        1714               0 :     return NS_ERROR_INVALID_ARG;
        1715                 :
        1716               0 :   NS_ADDREF(*aSelection);
        1717                 :
        1718               0 :   return NS_OK;
        1719                 : }
        1720                 :
        1721                 : nsISelection*
        1722               0 : PresShell::GetCurrentSelection(SelectionType aType)
        1723                 : {
        1724               0 :   if (!mSelection)
        1725               0 :     return nsnull;
        1726                 :
        1727               0 :   return mSelection->GetSelection(aType);
        1728                 : }
        1729                 :
        1730                 : NS_IMETHODIMP
        1731               0 : PresShell::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion,
        1732                 :                                    PRInt16 aFlags)
        1733                 : {
        1734               0 :   if (!mSelection)
        1735               0 :     return NS_ERROR_NULL_POINTER;
        1736                 :
        1737               0 :   return mSelection->ScrollSelectionIntoView(aType, aRegion, aFlags);
        1738                 : }
        1739                 :
        1740                 : NS_IMETHODIMP
        1741               0 : PresShell::RepaintSelection(SelectionType aType)
        1742                 : {
        1743               0 :   if (!mSelection)
        1744               0 :     return NS_ERROR_NULL_POINTER;
        1745                 :
        1746               0 :   return mSelection->RepaintSelection(aType);
        1747                 : }
        1748                 :
        1749                 : // Make shell be a document observer
        1750                 : void
        1751               0 : PresShell::BeginObservingDocument()
        1752                 : {
        1753               0 :   if (mDocument && !mIsDestroying) {
        1754               0 :     mDocument->AddObserver(this);
        1755               0 :     if (mIsDocumentGone) {
        1756                 :       NS_WARNING("Adding a presshell that was disconnected from the document "
        1757               0 :                  "as a document observer?  Sounds wrong...");
        1758               0 :       mIsDocumentGone = false;
        1759                 :     }
        1760                 :   }
        1761               0 : }
        1762                 :
        1763                 : // Make shell stop being a document observer
        1764                 : void
        1765               0 : PresShell::EndObservingDocument()
        1766                 : {
        1767                 :   // XXXbz do we need to tell the frame constructor that the document
        1768                 :   // is gone, perhaps?  Except for printing it's NOT gone, sometimes.
        1769               0 :   mIsDocumentGone = true;
        1770               0 :   if (mDocument) {
        1771               0 :     mDocument->RemoveObserver(this);
        1772                 :   }
        1773               0 : }
        1774                 :
        1775                 : #ifdef DEBUG_kipp
        1776                 : char* nsPresShell_ReflowStackPointerTop;
        1777                 : #endif
        1778                 :
        1779                 : nsresult
        1780               0 : PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
        1781                 : {
        1782               0 :   if (mIsDestroying) {
        1783               0 :     return NS_OK;
        1784                 :   }
        1785                 :
        1786               0 :   if (!mDocument) {
        1787                 :     // Nothing to do
        1788               0 :     return NS_OK;
        1789                 :   }
        1790                 :
        1791                 :   NS_TIME_FUNCTION_WITH_DOCURL;
        1792               0 :   mozilla::TimeStamp timerStart = mozilla::TimeStamp::Now();
        1793                 :
        1794               0 :   NS_ASSERTION(!mDidInitialReflow, "Why are we being called?");
        1795                 :
        1796               0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
        1797               0 :   mDidInitialReflow = true;
        1798                 :
        1799                 : #ifdef NS_DEBUG
        1800               0 :   if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
        1801               0 :     if (mDocument) {
        1802               0 :       nsIURI *uri = mDocument->GetDocumentURI();
        1803               0 :       if (uri) {
        1804               0 :         nsCAutoString url;
        1805               0 :         uri->GetSpec(url);
        1806               0 :         printf("*** PresShell::InitialReflow (this=%p, url='%s')\n", (void*)this, url.get());
        1807                 :       }
        1808                 :     }
        1809                 :   }
        1810                 : #endif
        1811                 :
        1812               0 :   if (mCaret)
        1813               0 :     mCaret->EraseCaret();
        1814                 :
        1815                 :   // XXX Do a full invalidate at the beginning so that invalidates along
        1816                 :   // the way don't have region accumulation issues?
        1817                 :
        1818               0 :   mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
        1819                 :
        1820                 :   // Get the root frame from the frame manager
        1821                 :   // XXXbz it would be nice to move this somewhere else... like frame manager
        1822                 :   // Init(), say.  But we need to make sure our views are all set up by the
        1823                 :   // time we do this!
        1824               0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
        1825               0 :   NS_ASSERTION(!rootFrame, "How did that happen, exactly?");
        1826               0 :   if (!rootFrame) {
        1827               0 :     nsAutoScriptBlocker scriptBlocker;
        1828               0 :     mFrameConstructor->BeginUpdate();
        1829               0 :     mFrameConstructor->ConstructRootFrame(&rootFrame);
        1830               0 :     mFrameConstructor->SetRootFrame(rootFrame);
        1831               0 :     mFrameConstructor->EndUpdate();
        1832                 :   }
        1833                 :
        1834               0 :   NS_ENSURE_STATE(!mHaveShutDown);
        1835                 :
        1836               0 :   if (!rootFrame) {
        1837               0 :     return NS_ERROR_OUT_OF_MEMORY;
        1838                 :   }
        1839                 :
        1840               0 :   Element *root = mDocument->GetRootElement();
        1841                 :
        1842               0 :   if (root) {
        1843                 :     {
        1844               0 :       nsAutoCauseReflowNotifier reflowNotifier(this);
        1845               0 :       mFrameConstructor->BeginUpdate();
        1846                 :
        1847                 :       // Have the style sheet processor construct frame for the root
        1848                 :       // content object down
        1849               0 :       mFrameConstructor->ContentInserted(nsnull, root, nsnull, false);
        1850               0 :       VERIFY_STYLE_TREE;
        1851                 :
        1852                 :       // Something in mFrameConstructor->ContentInserted may have caused
        1853                 :       // Destroy() to get called, bug 337586.
        1854               0 :       NS_ENSURE_STATE(!mHaveShutDown);
        1855                 :
        1856               0 :       mFrameConstructor->EndUpdate();
        1857                 :     }
        1858                 :
        1859                 :     // nsAutoScriptBlocker going out of scope may have killed us too
        1860               0 :     NS_ENSURE_STATE(!mHaveShutDown);
        1861                 :
        1862                 :     // Run the XBL binding constructors for any new frames we've constructed
        1863               0 :     mDocument->BindingManager()->ProcessAttachedQueue();
        1864                 :
        1865                 :     NS_TIME_FUNCTION_MARK("XBL binding constructors fired");
        1866                 :
        1867                 :     // Constructors may have killed us too
        1868               0 :     NS_ENSURE_STATE(!mHaveShutDown);
        1869                 :
        1870                 :     // Now flush out pending restyles before we actually reflow, in
        1871                 :     // case XBL constructors changed styles somewhere.
        1872                 :     {
        1873               0 :       nsAutoScriptBlocker scriptBlocker;
        1874               0 :       mFrameConstructor->CreateNeededFrames();
        1875               0 :       mFrameConstructor->ProcessPendingRestyles();
        1876                 :     }
        1877                 :
        1878                 :     // And that might have run _more_ XBL constructors
        1879               0 :     NS_ENSURE_STATE(!mHaveShutDown);
        1880                 :   }
        1881                 :
        1882               0 :   NS_ASSERTION(rootFrame, "How did that happen?");
        1883                 :
        1884                 :   // Note: when the frame was created above it had the NS_FRAME_IS_DIRTY bit
        1885                 :   // set, but XBL processing could have caused a reflow which clears it.
        1886               0 :   if (NS_LIKELY(rootFrame->GetStateBits() & NS_FRAME_IS_DIRTY)) {
        1887                 :     // Unset the DIRTY bits so that FrameNeedsReflow() will work right.
        1888                 :     rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY |
        1889               0 :                                NS_FRAME_HAS_DIRTY_CHILDREN);
        1890               0 :     NS_ASSERTION(!mDirtyRoots.Contains(rootFrame),
        1891                 :                  "Why is the root in mDirtyRoots already?");
        1892               0 :     FrameNeedsReflow(rootFrame, eResize, NS_FRAME_IS_DIRTY);
        1893               0 :     NS_ASSERTION(mDirtyRoots.Contains(rootFrame),
        1894                 :                  "Should be in mDirtyRoots now");
        1895               0 :     NS_ASSERTION(mReflowScheduled, "Why no reflow scheduled?");
        1896                 :   }
        1897                 :
        1898                 :   // Restore our root scroll position now if we're getting here after EndLoad
        1899                 :   // got called, since this is our one chance to do it.  Note that we need not
        1900                 :   // have reflowed for this to work; when the scrollframe is finally reflowed
        1901                 :   // it'll pick up the position we store in it here.
        1902               0 :   if (!mDocumentLoading) {
        1903               0 :     RestoreRootScrollPosition();
        1904                 :   }
        1905                 :
        1906                 :   // For printing, we just immediately unsuppress.
        1907               0 :   if (!mPresContext->IsPaginated()) {
        1908                 :     // Kick off a one-shot timer based off our pref value.  When this timer
        1909                 :     // fires, if painting is still locked down, then we will go ahead and
        1910                 :     // trigger a full invalidate and allow painting to proceed normally.
        1911               0 :     mPaintingSuppressed = true;
        1912                 :     // Don't suppress painting if the document isn't loading.
        1913               0 :     nsIDocument::ReadyState readyState = mDocument->GetReadyStateEnum();
        1914               0 :     if (readyState != nsIDocument::READYSTATE_COMPLETE) {
        1915               0 :       mPaintSuppressionTimer = do_CreateInstance("@mozilla.org/timer;1");
        1916                 :     }
        1917               0 :     if (!mPaintSuppressionTimer) {
        1918               0 :       mPaintingSuppressed = false;
        1919                 :     } else {
        1920                 :       // Initialize the timer.
        1921                 :
        1922                 :       // Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value.
        1923                 :       PRInt32 delay =
        1924                 :         Preferences::GetInt("nglayout.initialpaint.delay",
        1925               0 :                             PAINTLOCK_EVENT_DELAY);
        1926                 :
        1927               0 :       mPaintSuppressionTimer->InitWithFuncCallback(sPaintSuppressionCallback,
        1928                 :                                                    this, delay,
        1929               0 :                                                    nsITimer::TYPE_ONE_SHOT);
        1930                 :     }
        1931                 :   }
        1932                 :
        1933               0 :   if (root && root->IsXUL()) {
        1934                 :     mozilla::Telemetry::AccumulateTimeDelta(Telemetry::XUL_INITIAL_FRAME_CONSTRUCTION,
        1935               0 :                                             timerStart);
        1936                 :   }
        1937                 :
        1938               0 :   return NS_OK; //XXX this needs to be real. MMP
        1939                 : }
        1940                 :
        1941                 : void
        1942               0 : PresShell::sPaintSuppressionCallback(nsITimer *aTimer, void* aPresShell)
        1943                 : {
        1944               0 :   nsRefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
        1945               0 :   if (self)
        1946               0 :     self->UnsuppressPainting();
        1947               0 : }
        1948                 :
        1949                 : void
        1950               0 : PresShell::AsyncResizeEventCallback(nsITimer* aTimer, void* aPresShell)
        1951                 : {
        1952               0 :   static_cast<PresShell*>(aPresShell)->FireResizeEvent();
        1953               0 : }
        1954                 :
        1955                 : nsresult
        1956               0 : PresShell::ResizeReflowOverride(nscoord aWidth, nscoord aHeight)
        1957                 : {
        1958               0 :   mViewportOverridden = true;
        1959               0 :   return ResizeReflowIgnoreOverride(aWidth, aHeight);
        1960                 : }
        1961                 :
        1962                 : nsresult
        1963               0 : PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
        1964                 : {
        1965               0 :   if (mViewportOverridden) {
        1966                 :     // The viewport has been overridden, and this reflow request
        1967                 :     // didn't ask to ignore the override.  Pretend it didn't happen.
        1968               0 :     return NS_OK;
        1969                 :   }
        1970               0 :   return ResizeReflowIgnoreOverride(aWidth, aHeight);
        1971                 : }
        1972                 :
        1973                 : nsresult
        1974               0 : PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight)
        1975                 : {
        1976               0 :   NS_PRECONDITION(!mIsReflowing, "Shouldn't be in reflow here!");
        1977               0 :   NS_PRECONDITION(aWidth != NS_UNCONSTRAINEDSIZE,
        1978                 :                   "shouldn't use unconstrained widths anymore");
        1979                 :
        1980                 :   // If we don't have a root frame yet, that means we haven't had our initial
        1981                 :   // reflow... If that's the case, and aWidth or aHeight is unconstrained,
        1982                 :   // ignore them altogether.
        1983               0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
        1984                 :
        1985               0 :   if (!rootFrame && aHeight == NS_UNCONSTRAINEDSIZE) {
        1986                 :     // We can't do the work needed for SizeToContent without a root
        1987                 :     // frame, and we want to return before setting the visible area.
        1988               0 :     return NS_ERROR_NOT_AVAILABLE;
        1989                 :   }
        1990                 :
        1991               0 :   nsCOMPtr<nsIViewManager> viewManagerDeathGrip = mViewManager;
        1992                 :   // Take this ref after viewManager so it'll make sure to go away first
        1993               0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
        1994                 :
        1995               0 :   if (!mIsDestroying && !mResizeEvent.IsPending() &&
        1996               0 :       !mAsyncResizeTimerIsActive) {
        1997               0 :     FireBeforeResizeEvent();
        1998                 :   }
        1999                 :
        2000               0 :   mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
        2001                 :
        2002                 :   // There isn't anything useful we can do if the initial reflow hasn't happened
        2003               0 :   rootFrame = mFrameConstructor->GetRootFrame();
        2004               0 :   if (!rootFrame)
        2005               0 :     return NS_OK;
        2006                 :
        2007               0 :   if (!GetPresContext()->SupressingResizeReflow())
        2008                 :   {
        2009                 :     // Have to make sure that the content notifications are flushed before we
        2010                 :     // start messing with the frame model; otherwise we can get content doubling.
        2011               0 :     mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
        2012                 :
        2013                 :     // Make sure style is up to date
        2014                 :     {
        2015               0 :       nsAutoScriptBlocker scriptBlocker;
        2016               0 :       mFrameConstructor->CreateNeededFrames();
        2017               0 :       mFrameConstructor->ProcessPendingRestyles();
        2018                 :     }
        2019                 :
        2020               0 :     rootFrame = mFrameConstructor->GetRootFrame();
        2021               0 :     if (!mIsDestroying && rootFrame) {
        2022                 :       // XXX Do a full invalidate at the beginning so that invalidates along
        2023                 :       // the way don't have region accumulation issues?
        2024                 :
        2025                 :       {
        2026               0 :         nsAutoCauseReflowNotifier crNotifier(this);
        2027               0 :         WillDoReflow();
        2028                 :
        2029                 :         // Kick off a top-down reflow
        2030               0 :         AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
        2031               0 :         nsIViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
        2032                 :
        2033               0 :         mDirtyRoots.RemoveElement(rootFrame);
        2034               0 :         DoReflow(rootFrame, true);
        2035                 :       }
        2036                 :
        2037               0 :       DidDoReflow(true);
        2038                 :     }
        2039                 :   }
        2040                 :
        2041               0 :   rootFrame = mFrameConstructor->GetRootFrame();
        2042               0 :   if (aHeight == NS_UNCONSTRAINEDSIZE && rootFrame) {
        2043                 :     mPresContext->SetVisibleArea(
        2044               0 :       nsRect(0, 0, aWidth, rootFrame->GetRect().height));
        2045                 :   }
        2046                 :
        2047               0 :   if (!mIsDestroying && !mResizeEvent.IsPending() &&
        2048               0 :       !mAsyncResizeTimerIsActive) {
        2049               0 :     if (mInResize) {
        2050               0 :       if (!mAsyncResizeEventTimer) {
        2051               0 :         mAsyncResizeEventTimer = do_CreateInstance("@mozilla.org/timer;1");
        2052                 :       }
        2053               0 :       if (mAsyncResizeEventTimer) {
        2054               0 :         mAsyncResizeTimerIsActive = true;
        2055               0 :         mAsyncResizeEventTimer->InitWithFuncCallback(AsyncResizeEventCallback,
        2056                 :                                                      this, 15,
        2057               0 :                                                      nsITimer::TYPE_ONE_SHOT);
        2058                 :       }
        2059                 :     } else {
        2060                 :       nsRefPtr<nsRunnableMethod<PresShell> > resizeEvent =
        2061               0 :         NS_NewRunnableMethod(this, &PresShell::FireResizeEvent);
        2062               0 :       if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent))) {
        2063               0 :         mResizeEvent = resizeEvent;
        2064               0 :         mDocument->SetNeedStyleFlush();
        2065                 :       }
        2066                 :     }
        2067                 :   }
        2068                 :
        2069               0 :   return NS_OK; //XXX this needs to be real. MMP
        2070                 : }
        2071                 :
        2072                 : void
        2073               0 : PresShell::FireBeforeResizeEvent()
        2074                 : {
        2075               0 :   if (mIsDocumentGone)
        2076               0 :     return;
        2077                 :
        2078                 :   // Send beforeresize event from here.
        2079               0 :   nsEvent event(true, NS_BEFORERESIZE_EVENT);
        2080                 :
        2081               0 :   nsPIDOMWindow *window = mDocument->GetWindow();
        2082               0 :   if (window) {
        2083               0 :     nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
        2084               0 :     nsEventDispatcher::Dispatch(window, mPresContext, &event);
        2085                 :   }
        2086                 : }
        2087                 :
        2088                 : void
        2089               0 : PresShell::FireResizeEvent()
        2090                 : {
        2091               0 :   if (mAsyncResizeTimerIsActive) {
        2092               0 :     mAsyncResizeTimerIsActive = false;
        2093               0 :     mAsyncResizeEventTimer->Cancel();
        2094                 :   }
        2095               0 :   mResizeEvent.Revoke();
        2096                 :
        2097               0 :   if (mIsDocumentGone)
        2098               0 :     return;
        2099                 :
        2100                 :   //Send resize event from here.
        2101               0 :   nsEvent event(true, NS_RESIZE_EVENT);
        2102               0 :   nsEventStatus status = nsEventStatus_eIgnore;
        2103                 :
        2104               0 :   nsPIDOMWindow *window = mDocument->GetWindow();
        2105               0 :   if (window) {
        2106               0 :     nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
        2107               0 :     mInResize = true;
        2108               0 :     nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull, &status);
        2109               0 :     mInResize = false;
        2110                 :   }
        2111                 : }
        2112                 :
        2113                 : void
        2114               0 : PresShell::SetIgnoreFrameDestruction(bool aIgnore)
        2115                 : {
        2116               0 :   if (mPresContext) {
        2117                 :     // We need to destroy the image loaders first, as they won't be
        2118                 :     // notified when frames are destroyed once this setting takes effect.
        2119                 :     // (See bug 673984)
        2120               0 :     mPresContext->DestroyImageLoaders();
        2121                 :   }
        2122               0 :   mIgnoreFrameDestruction = aIgnore;
        2123               0 : }
        2124                 :
        2125                 : void
        2126               0 : PresShell::NotifyDestroyingFrame(nsIFrame* aFrame)
        2127                 : {
        2128                 :   NS_TIME_FUNCTION_MIN(1.0);
        2129                 :
        2130               0 :   mPresContext->ForgetUpdatePluginGeometryFrame(aFrame);
        2131                 :
        2132               0 :   if (!mIgnoreFrameDestruction) {
        2133               0 :     mPresContext->StopImagesFor(aFrame);
        2134                 :
        2135               0 :     mFrameConstructor->NotifyDestroyingFrame(aFrame);
        2136                 :
        2137               0 :     for (PRInt32 idx = mDirtyRoots.Length(); idx; ) {
        2138               0 :       --idx;
        2139               0 :       if (mDirtyRoots[idx] == aFrame) {
        2140               0 :         mDirtyRoots.RemoveElementAt(idx);
        2141                 :       }
        2142                 :     }
        2143                 :
        2144                 :     // Remove frame properties
        2145               0 :     mPresContext->NotifyDestroyingFrame(aFrame);
        2146                 :
        2147               0 :     if (aFrame == mCurrentEventFrame) {
        2148               0 :       mCurrentEventContent = aFrame->GetContent();
        2149               0 :       mCurrentEventFrame = nsnull;
        2150                 :     }
        2151                 :
        2152                 :   #ifdef NS_DEBUG
        2153               0 :     if (aFrame == mDrawEventTargetFrame) {
        2154               0 :       mDrawEventTargetFrame = nsnull;
        2155                 :     }
        2156                 :   #endif
        2157                 :
        2158               0 :     for (unsigned int i=0; i < mCurrentEventFrameStack.Length(); i++) {
        2159               0 :       if (aFrame == mCurrentEventFrameStack.ElementAt(i)) {
        2160                 :         //One of our stack frames was deleted.  Get its content so that when we
        2161                 :         //pop it we can still get its new frame from its content
        2162               0 :         nsIContent *currentEventContent = aFrame->GetContent();
        2163               0 :         mCurrentEventContentStack.ReplaceObjectAt(currentEventContent, i);
        2164               0 :         mCurrentEventFrameStack[i] = nsnull;
        2165                 :       }
        2166                 :     }
        2167                 :
        2168               0 :     mFramesToDirty.RemoveEntry(aFrame);
        2169                 :   }
        2170               0 : }
        2171                 :
        2172               0 : already_AddRefed<nsCaret> PresShell::GetCaret() const
        2173                 : {
        2174               0 :   nsCaret* caret = mCaret;
        2175               0 :   NS_IF_ADDREF(caret);
        2176               0 :   return caret;
        2177                 : }
        2178                 :
        2179               0 : void PresShell::MaybeInvalidateCaretPosition()
        2180                 : {
        2181               0 :   if (mCaret) {
        2182               0 :     mCaret->InvalidateOutsideCaret();
        2183                 :   }
        2184               0 : }
        2185                 :
        2186               0 : void PresShell::SetCaret(nsCaret *aNewCaret)
        2187                 : {
        2188               0 :   mCaret = aNewCaret;
        2189               0 : }
        2190                 :
        2191               0 : void PresShell::RestoreCaret()
        2192                 : {
        2193               0 :   mCaret = mOriginalCaret;
        2194               0 : }
        2195                 :
        2196               0 : NS_IMETHODIMP PresShell::SetCaretEnabled(bool aInEnable)
        2197                 : {
        2198               0 :   bool oldEnabled = mCaretEnabled;
        2199                 :
        2200               0 :   mCaretEnabled = aInEnable;
        2201                 :
        2202               0 :   if (mCaret && (mCaretEnabled != oldEnabled))
        2203                 :   {
        2204                 : /*  Don't change the caret's selection here! This was an evil side-effect of SetCaretEnabled()
        2205                 :     nsCOMPtr<nsIDOMSelection> domSel;
        2206                 :     if (NS_SUCCEEDED(GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel))) && domSel)
        2207                 :       mCaret->SetCaretDOMSelection(domSel);
        2208                 : */
        2209               0 :     mCaret->SetCaretVisible(mCaretEnabled);
        2210                 :   }
        2211                 :
        2212               0 :   return NS_OK;
        2213                 : }
        2214                 :
        2215               0 : NS_IMETHODIMP PresShell::SetCaretReadOnly(bool aReadOnly)
        2216                 : {
        2217               0 :   if (mCaret)
        2218               0 :     mCaret->SetCaretReadOnly(aReadOnly);
        2219               0 :   return NS_OK;
        2220                 : }
        2221                 :
        2222               0 : NS_IMETHODIMP PresShell::GetCaretEnabled(bool *aOutEnabled)
        2223                 : {
        2224               0 :   NS_ENSURE_ARG_POINTER(aOutEnabled);
        2225               0 :   *aOutEnabled = mCaretEnabled;
        2226               0 :   return NS_OK;
        2227                 : }
        2228                 :
        2229               0 : NS_IMETHODIMP PresShell::SetCaretVisibilityDuringSelection(bool aVisibility)
        2230                 : {
        2231               0 :   if (mCaret)
        2232               0 :     mCaret->SetVisibilityDuringSelection(aVisibility);
        2233               0 :   return NS_OK;
        2234                 : }
        2235                 :
        2236               0 : NS_IMETHODIMP PresShell::GetCaretVisible(bool *aOutIsVisible)
        2237                 : {
        2238               0 :   *aOutIsVisible = false;
        2239               0 :   if (mCaret) {
        2240               0 :     nsresult rv = mCaret->GetCaretVisible(aOutIsVisible);
        2241               0 :     NS_ENSURE_SUCCESS(rv,rv);
        2242                 :   }
        2243               0 :   return NS_OK;
        2244                 : }
        2245                 :
        2246               0 : NS_IMETHODIMP PresShell::SetSelectionFlags(PRInt16 aInEnable)
        2247                 : {
        2248               0 :   mSelectionFlags = aInEnable;
        2249               0 :   return NS_OK;
        2250                 : }
        2251                 :
        2252               0 : NS_IMETHODIMP PresShell::GetSelectionFlags(PRInt16 *aOutEnable)
        2253                 : {
        2254               0 :   if (!aOutEnable)
        2255               0 :     return NS_ERROR_INVALID_ARG;
        2256               0 :   *aOutEnable = mSelectionFlags;
        2257               0 :   return NS_OK;
        2258                 : }
        2259                 :
        2260                 : //implementation of nsISelectionController
        2261                 :
        2262                 : NS_IMETHODIMP
        2263               0 : PresShell::CharacterMove(bool aForward, bool aExtend)
        2264                 : {
        2265               0 :   return mSelection->CharacterMove(aForward, aExtend);
        2266                 : }
        2267                 :
        2268                 : NS_IMETHODIMP
        2269               0 : PresShell::CharacterExtendForDelete()
        2270                 : {
        2271               0 :   return mSelection->CharacterExtendForDelete();
        2272                 : }
        2273                 :
        2274                 : NS_IMETHODIMP
        2275               0 : PresShell::CharacterExtendForBackspace()
        2276                 : {
        2277               0 :   return mSelection->CharacterExtendForBackspace();
        2278                 : }
        2279                 :
        2280                 : NS_IMETHODIMP
        2281               0 : PresShell::WordMove(bool aForward, bool aExtend)
        2282                 : {
        2283               0 :   nsresult result = mSelection->WordMove(aForward, aExtend);
        2284                 : // if we can't go down/up any more we must then move caret completely to
        2285                 : // end/beginning respectively.
        2286               0 :   if (NS_FAILED(result))
        2287               0 :     result = CompleteMove(aForward, aExtend);
        2288               0 :   return result;
        2289                 : }
        2290                 :
        2291                 : NS_IMETHODIMP
        2292               0 : PresShell::WordExtendForDelete(bool aForward)
        2293                 : {
        2294               0 :   return mSelection->WordExtendForDelete(aForward);
        2295                 : }
        2296                 :
        2297                 : NS_IMETHODIMP
        2298               0 : PresShell::LineMove(bool aForward, bool aExtend)
        2299                 : {
        2300               0 :   nsresult result = mSelection->LineMove(aForward, aExtend);
        2301                 : // if we can't go down/up any more we must then move caret completely to
        2302                 : // end/beginning respectively.
        2303               0 :   if (NS_FAILED(result))
        2304               0 :     result = CompleteMove(aForward,aExtend);
        2305               0 :   return result;
        2306                 : }
        2307                 :
        2308                 : NS_IMETHODIMP
        2309               0 : PresShell::IntraLineMove(bool aForward, bool aExtend)
        2310                 : {
        2311               0 :   return mSelection->IntraLineMove(aForward, aExtend);
        2312                 : }
        2313                 :
        2314                 :
        2315                 :
        2316                 : NS_IMETHODIMP
        2317               0 : PresShell::PageMove(bool aForward, bool aExtend)
        2318                 : {
        2319                 :   nsIScrollableFrame *scrollableFrame =
        2320               0 :     GetFrameToScrollAsScrollable(nsIPresShell::eVertical);
        2321               0 :   if (!scrollableFrame)
        2322               0 :     return NS_OK;
        2323                 :
        2324               0 :   mSelection->CommonPageMove(aForward, aExtend, scrollableFrame);
        2325                 :   // After ScrollSelectionIntoView(), the pending notifications might be
        2326                 :   // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
        2327                 :   return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
        2328                 :                                  nsISelectionController::SELECTION_FOCUS_REGION,
        2329               0 :                                  nsISelectionController::SCROLL_SYNCHRONOUS);
        2330                 : }
        2331                 :
        2332                 :
        2333                 :
        2334                 : NS_IMETHODIMP
        2335               0 : PresShell::ScrollPage(bool aForward)
        2336                 : {
        2337                 :   nsIScrollableFrame* scrollFrame =
        2338               0 :     GetFrameToScrollAsScrollable(nsIPresShell::eVertical);
        2339               0 :   if (scrollFrame) {
        2340                 :     scrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
        2341                 :                           nsIScrollableFrame::PAGES,
        2342               0 :                           nsIScrollableFrame::SMOOTH);
        2343                 :   }
        2344               0 :   return NS_OK;
        2345                 : }
        2346                 :
        2347                 : NS_IMETHODIMP
        2348               0 : PresShell::ScrollLine(bool aForward)
        2349                 : {
        2350                 :   nsIScrollableFrame* scrollFrame =
        2351               0 :     GetFrameToScrollAsScrollable(nsIPresShell::eVertical);
        2352               0 :   if (scrollFrame) {
        2353                 :     PRInt32 lineCount = Preferences::GetInt("toolkit.scrollbox.verticalScrollDistance",
        2354               0 :                                             NS_DEFAULT_VERTICAL_SCROLL_DISTANCE);
        2355                 :     scrollFrame->ScrollBy(nsIntPoint(0, aForward ? lineCount : -lineCount),
        2356                 :                           nsIScrollableFrame::LINES,
        2357               0 :                           nsIScrollableFrame::SMOOTH);
        2358                 :   }
        2359               0 :   return NS_OK;
        2360                 : }
        2361                 :
        2362                 : NS_IMETHODIMP
        2363               0 : PresShell::ScrollCharacter(bool aRight)
        2364                 : {
        2365                 :   nsIScrollableFrame* scrollFrame =
        2366               0 :     GetFrameToScrollAsScrollable(nsIPresShell::eHorizontal);
        2367               0 :   if (scrollFrame) {
        2368                 :     scrollFrame->ScrollBy(nsIntPoint(aRight ? 1 : -1, 0),
        2369                 :                           nsIScrollableFrame::LINES,
        2370               0 :                           nsIScrollableFrame::SMOOTH);
        2371                 :   }
        2372               0 :   return NS_OK;
        2373                 : }
        2374                 :
        2375                 : NS_IMETHODIMP
        2376               0 : PresShell::CompleteScroll(bool aForward)
        2377                 : {
        2378                 :   nsIScrollableFrame* scrollFrame =
        2379               0 :     GetFrameToScrollAsScrollable(nsIPresShell::eVertical);
        2380               0 :   if (scrollFrame) {
        2381                 :     scrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
        2382                 :                           nsIScrollableFrame::WHOLE,
        2383               0 :                           nsIScrollableFrame::INSTANT);
        2384                 :   }
        2385               0 :   return NS_OK;
        2386                 : }
        2387                 :
        2388                 : NS_IMETHODIMP
        2389               0 : PresShell::CompleteMove(bool aForward, bool aExtend)
        2390                 : {
        2391                 :   // Beware! This may flush notifications via synchronous
        2392                 :   // ScrollSelectionIntoView.
        2393               0 :   nsIContent* limiter = mSelection->GetAncestorLimiter();
        2394                 :   nsIFrame* frame = limiter ? limiter->GetPrimaryFrame()
        2395               0 :                             : FrameConstructor()->GetRootElementFrame();
        2396               0 :   if (!frame)
        2397               0 :     return NS_ERROR_FAILURE;
        2398               0 :   nsPeekOffsetStruct pos = frame->GetExtremeCaretPosition(!aForward);
        2399                 :   mSelection->HandleClick(pos.mResultContent, pos.mContentOffset,
        2400               0 :                           pos.mContentOffset, aExtend, false, aForward);
        2401               0 :   if (limiter) {
        2402                 :     // HandleClick resets ancestorLimiter, so set it again.
        2403               0 :     mSelection->SetAncestorLimiter(limiter);
        2404                 :   }
        2405                 :
        2406                 :   // After ScrollSelectionIntoView(), the pending notifications might be
        2407                 :   // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
        2408                 :   return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
        2409                 :                                  nsISelectionController::SELECTION_FOCUS_REGION,
        2410               0 :                                  nsISelectionController::SCROLL_SYNCHRONOUS);
        2411                 : }
        2412                 :
        2413                 : NS_IMETHODIMP
        2414               0 : PresShell::SelectAll()
        2415                 : {
        2416               0 :   return mSelection->SelectAll();
        2417                 : }
        2418                 :
        2419                 : static void
        2420               0 : DoCheckVisibility(nsPresContext* aPresContext,
        2421                 :                   nsIContent* aNode,
        2422                 :                   PRInt16 aStartOffset,
        2423                 :                   PRInt16 aEndOffset,
        2424                 :                   bool* aRetval)
        2425                 : {
        2426               0 :   nsIFrame* frame = aNode->GetPrimaryFrame();
        2427               0 :   if (!frame) {
        2428                 :     // No frame to look at so it must not be visible.
        2429               0 :     return;
        2430                 :   }
        2431                 :
        2432                 :   // Start process now to go through all frames to find startOffset. Then check
        2433                 :   // chars after that to see if anything until EndOffset is visible.
        2434               0 :   bool finished = false;
        2435                 :   frame->CheckVisibility(aPresContext, aStartOffset, aEndOffset, true,
        2436               0 :                          &finished, aRetval);
        2437                 :   // Don't worry about other return value.
        2438                 : }
        2439                 :
        2440                 : NS_IMETHODIMP
        2441               0 : PresShell::CheckVisibility(nsIDOMNode *node, PRInt16 startOffset, PRInt16 EndOffset, bool *_retval)
        2442                 : {
        2443               0 :   if (!node || startOffset>EndOffset || !_retval || startOffset<0 || EndOffset<0)
        2444               0 :     return NS_ERROR_INVALID_ARG;
        2445               0 :   *_retval = false; //initialize return parameter
        2446               0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(node));
        2447               0 :   if (!content)
        2448               0 :     return NS_ERROR_FAILURE;
        2449                 :
        2450               0 :   DoCheckVisibility(mPresContext, content, startOffset, EndOffset, _retval);
        2451               0 :   return NS_OK;
        2452                 : }
        2453                 :
        2454                 : nsresult
        2455               0 : PresShell::CheckVisibilityContent(nsIContent* aNode, PRInt16 aStartOffset,
        2456                 :                                   PRInt16 aEndOffset, bool* aRetval)
        2457                 : {
        2458               0 :   if (!aNode || aStartOffset > aEndOffset || !aRetval ||
        2459                 :       aStartOffset < 0 || aEndOffset < 0) {
        2460               0 :     return NS_ERROR_INVALID_ARG;
        2461                 :   }
        2462                 :
        2463               0 :   *aRetval = false;
        2464               0 :   DoCheckVisibility(mPresContext, aNode, aStartOffset, aEndOffset, aRetval);
        2465               0 :   return NS_OK;
        2466                 : }
        2467                 :
        2468                 : //end implementations nsISelectionController
        2469                 :
        2470                 :
        2471                 : void
        2472               0 : PresShell::StyleChangeReflow()
        2473                 : {
        2474               0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
        2475                 :   // At the moment at least, we don't have a root frame before the initial
        2476                 :   // reflow; it's safe to just ignore the request in that case
        2477               0 :   if (!rootFrame)
        2478               0 :     return;
        2479                 :
        2480               0 :   FrameNeedsReflow(rootFrame, eStyleChange, NS_FRAME_IS_DIRTY);
        2481                 : }
        2482                 :
        2483                 : nsIFrame*
        2484               0 : nsIPresShell::GetRootFrameExternal() const
        2485                 : {
        2486               0 :   return mFrameConstructor->GetRootFrame();
        2487                 : }
        2488                 :
        2489                 : nsIFrame*
        2490               0 : nsIPresShell::GetRootScrollFrame() const
        2491                 : {
        2492               0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
        2493                 :   // Ensure root frame is a viewport frame
        2494               0 :   if (!rootFrame || nsGkAtoms::viewportFrame != rootFrame->GetType())
        2495               0 :     return nsnull;
        2496               0 :   nsIFrame* theFrame = rootFrame->GetFirstPrincipalChild();
        2497               0 :   if (!theFrame || nsGkAtoms::scrollFrame != theFrame->GetType())
        2498               0 :     return nsnull;
        2499               0 :   return theFrame;
        2500                 : }
        2501                 :
        2502                 : nsIScrollableFrame*
        2503               0 : nsIPresShell::GetRootScrollFrameAsScrollable() const
        2504                 : {
        2505               0 :   nsIFrame* frame = GetRootScrollFrame();
        2506               0 :   if (!frame)
        2507               0 :     return nsnull;
        2508               0 :   nsIScrollableFrame* scrollableFrame = do_QueryFrame(frame);
        2509               0 :   NS_ASSERTION(scrollableFrame,
        2510                 :                "All scroll frames must implement nsIScrollableFrame");
        2511               0 :   return scrollableFrame;
        2512                 : }
        2513                 :
        2514                 : nsIScrollableFrame*
        2515               0 : nsIPresShell::GetRootScrollFrameAsScrollableExternal() const
        2516                 : {
        2517               0 :   return GetRootScrollFrameAsScrollable();
        2518                 : }
        2519                 :
        2520                 : nsIPageSequenceFrame*
        2521               0 : PresShell::GetPageSequenceFrame() const
        2522                 : {
        2523               0 :   nsIFrame* frame = mFrameConstructor->GetPageSequenceFrame();
        2524               0 :   return do_QueryFrame(frame);
        2525                 : }
        2526                 :
        2527                 : nsIFrame*
        2528               0 : PresShell::GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt)
        2529                 : {
        2530               0 :   return nsLayoutUtils::GetFrameForPoint(aFrame, aPt);
        2531                 : }
        2532                 :
        2533                 : void
        2534               0 : PresShell::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
        2535                 : {
        2536                 : #ifdef DEBUG
        2537               0 :   mUpdateCount++;
        2538                 : #endif
        2539               0 :   mFrameConstructor->BeginUpdate();
        2540                 :
        2541               0 :   if (aUpdateType & UPDATE_STYLE)
        2542               0 :     mStyleSet->BeginUpdate();
        2543               0 : }
        2544                 :
        2545                 : void
        2546               0 : PresShell::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
        2547                 : {
        2548                 : #ifdef DEBUG
        2549               0 :   NS_PRECONDITION(0 != mUpdateCount, "too many EndUpdate's");
        2550               0 :   --mUpdateCount;
        2551                 : #endif
        2552                 :
        2553               0 :   if (aUpdateType & UPDATE_STYLE) {
        2554               0 :     mStyleSet->EndUpdate();
        2555               0 :     if (mStylesHaveChanged)
        2556               0 :       ReconstructStyleData();
        2557                 :   }
        2558                 :
        2559               0 :   mFrameConstructor->EndUpdate();
        2560               0 : }
        2561                 :
        2562                 : void
        2563               0 : PresShell::RestoreRootScrollPosition()
        2564                 : {
        2565                 :   // Restore frame state for the root scroll frame
        2566                 :   nsCOMPtr<nsILayoutHistoryState> historyState =
        2567               0 :     mDocument->GetLayoutHistoryState();
        2568                 :   // Make sure we don't reenter reflow via the sync paint that happens while
        2569                 :   // we're scrolling to our restored position.  Entering reflow for the
        2570                 :   // scrollable frame will cause it to reenter ScrollToRestoredPosition(), and
        2571                 :   // it'll get all confused.
        2572               0 :   nsAutoScriptBlocker scriptBlocker;
        2573               0 :   ++mChangeNestCount;
        2574                 :
        2575               0 :   if (historyState) {
        2576               0 :     nsIFrame* scrollFrame = GetRootScrollFrame();
        2577               0 :     if (scrollFrame) {
        2578               0 :       nsIScrollableFrame* scrollableFrame = do_QueryFrame(scrollFrame);
        2579               0 :       if (scrollableFrame) {
        2580                 :         mFrameConstructor->RestoreFrameStateFor(scrollFrame, historyState,
        2581               0 :                                                 nsIStatefulFrame::eDocumentScrollState);
        2582               0 :         scrollableFrame->ScrollToRestoredPosition();
        2583                 :       }
        2584                 :     }
        2585                 :   }
        2586                 :
        2587               0 :   --mChangeNestCount;
        2588               0 : }
        2589                 :
        2590                 : void
        2591               0 : PresShell::BeginLoad(nsIDocument *aDocument)
        2592                 : {
        2593               0 :   mDocumentLoading = true;
        2594               0 : }
        2595                 :
        2596                 : void
        2597               0 : PresShell::EndLoad(nsIDocument *aDocument)
        2598                 : {
        2599               0 :   NS_PRECONDITION(aDocument == mDocument, "Wrong document");
        2600                 :
        2601               0 :   RestoreRootScrollPosition();
        2602                 :
        2603               0 :   mDocumentLoading = false;
        2604               0 : }
        2605                 :
        2606                 : #ifdef DEBUG
        2607                 : void
        2608               0 : PresShell::VerifyHasDirtyRootAncestor(nsIFrame* aFrame)
        2609                 : {
        2610                 :   // XXXbz due to bug 372769, can't actually assert anything here...
        2611                 :   return;
        2612                 :
        2613                 :   // XXXbz shouldn't need this part; remove it once FrameNeedsReflow
        2614                 :   // handles the root frame correctly.
        2615                 :   if (!aFrame->GetParent()) {
        2616                 :     return;
        2617                 :   }
        2618                 :
        2619                 :   // Make sure that there is a reflow root ancestor of |aFrame| that's
        2620                 :   // in mDirtyRoots already.
        2621                 :   while (aFrame && (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)) {
        2622                 :     if (((aFrame->GetStateBits() & NS_FRAME_REFLOW_ROOT) ||
        2623                 :          !aFrame->GetParent()) &&
        2624                 :         mDirtyRoots.Contains(aFrame)) {
        2625                 :       return;
        2626                 :     }
        2627                 :
        2628                 :     aFrame = aFrame->GetParent();
        2629                 :   }
        2630                 :   NS_NOTREACHED("Frame has dirty bits set but isn't scheduled to be "
        2631                 :                 "reflowed?");
        2632                 : }
        2633                 : #endif
        2634                 :
        2635                 : void
        2636               0 : PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
        2637                 :                             nsFrameState aBitToAdd)
        2638                 : {
        2639                 : #ifdef NS_FUNCTION_TIMER
        2640                 :   NS_TIME_FUNCTION_DECLARE_DOCURL;
        2641                 :   nsCAutoString frameType__("N/A");
        2642                 :   nsIAtom *atomType__ = aFrame ? aFrame->GetType() : nsnull;
        2643                 :   if (atomType__) atomType__->ToUTF8String(frameType__);
        2644                 :   NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, frame type: %s)", MOZ_FUNCTION_NAME,
        2645                 :                            __LINE__, docURL__.get(), frameType__.get());
        2646                 : #endif
        2647                 :
        2648               0 :   NS_PRECONDITION(aBitToAdd == NS_FRAME_IS_DIRTY ||
        2649                 :                   aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN,
        2650                 :                   "Unexpected bits being added");
        2651               0 :   NS_PRECONDITION(aIntrinsicDirty != eStyleChange ||
        2652                 :                   aBitToAdd == NS_FRAME_IS_DIRTY,
        2653                 :                   "bits don't correspond to style change reason");
        2654                 :
        2655               0 :   NS_ASSERTION(!mIsReflowing, "can't mark frame dirty during reflow");
        2656                 :
        2657                 :   // If we've not yet done the initial reflow, then don't bother
        2658                 :   // enqueuing a reflow command yet.
        2659               0 :   if (! mDidInitialReflow)
        2660               0 :     return;
        2661                 :
        2662                 :   // If we're already destroying, don't bother with this either.
        2663               0 :   if (mIsDestroying)
        2664               0 :     return;
        2665                 :
        2666                 : #ifdef DEBUG
        2667                 :   //printf("gShellCounter: %d\n", gShellCounter++);
        2668               0 :   if (mInVerifyReflow)
        2669               0 :     return;
        2670                 :
        2671               0 :   if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
        2672               0 :     printf("\nPresShell@%p: frame %p needs reflow\n", (void*)this, (void*)aFrame);
        2673               0 :     if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
        2674               0 :       printf("Current content model:\n");
        2675               0 :       Element *rootElement = mDocument->GetRootElement();
        2676               0 :       if (rootElement) {
        2677               0 :         rootElement->List(stdout, 0);
        2678                 :       }
        2679                 :     }
        2680                 :   }
        2681                 : #endif
        2682                 :
        2683               0 :   nsAutoTArray<nsIFrame*, 4> subtrees;
        2684               0 :   subtrees.AppendElement(aFrame);
        2685                 :
        2686               0 :   do {
        2687               0 :     nsIFrame *subtreeRoot = subtrees.ElementAt(subtrees.Length() - 1);
        2688               0 :     subtrees.RemoveElementAt(subtrees.Length() - 1);
        2689                 :
        2690                 :     // Grab |wasDirty| now so we can go ahead and update the bits on
        2691                 :     // subtreeRoot.
        2692               0 :     bool wasDirty = NS_SUBTREE_DIRTY(subtreeRoot);
        2693               0 :     subtreeRoot->AddStateBits(aBitToAdd);
        2694                 :
        2695                 :     // Now if subtreeRoot is a reflow root we can cut off this reflow at it if
        2696                 :     // the bit being added is NS_FRAME_HAS_DIRTY_CHILDREN.
        2697               0 :     bool targetFrameDirty = (aBitToAdd == NS_FRAME_IS_DIRTY);
        2698                 :
        2699                 : #define FRAME_IS_REFLOW_ROOT(_f)                   \
        2700                 :   ((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) &&  \
        2701                 :    (_f != subtreeRoot || !targetFrameDirty))
        2702                 :
        2703                 :
        2704                 :     // Mark the intrinsic widths as dirty on the frame, all of its ancestors,
        2705                 :     // and all of its descendants, if needed:
        2706                 :
        2707               0 :     if (aIntrinsicDirty != eResize) {
        2708                 :       // Mark argument and all ancestors dirty. (Unless we hit a reflow
        2709                 :       // root that should contain the reflow.  That root could be
        2710                 :       // subtreeRoot itself if it's not dirty, or it could be some
        2711                 :       // ancestor of subtreeRoot.)
        2712               0 :       for (nsIFrame *a = subtreeRoot;
        2713               0 :            a && !FRAME_IS_REFLOW_ROOT(a);
        2714                 :            a = a->GetParent())
        2715               0 :         a->MarkIntrinsicWidthsDirty();
        2716                 :     }
        2717                 :
        2718               0 :     if (aIntrinsicDirty == eStyleChange) {
        2719                 :       // Mark all descendants dirty (using an nsTArray stack rather than
        2720                 :       // recursion).
        2721               0 :       nsAutoTArray<nsIFrame*, 32> stack;
        2722               0 :       stack.AppendElement(subtreeRoot);
        2723                 :
        2724               0 :       do {
        2725               0 :         nsIFrame *f = stack.ElementAt(stack.Length() - 1);
        2726               0 :         stack.RemoveElementAt(stack.Length() - 1);
        2727                 :
        2728               0 :         if (f->GetType() == nsGkAtoms::placeholderFrame) {
        2729               0 :           nsIFrame *oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
        2730               0 :           if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) {
        2731                 :             // We have another distinct subtree we need to mark.
        2732               0 :             subtrees.AppendElement(oof);
        2733                 :           }
        2734                 :         }
        2735                 :
        2736               0 :         nsIFrame::ChildListIterator lists(f);
        2737               0 :         for (; !lists.IsDone(); lists.Next()) {
        2738               0 :           nsFrameList::Enumerator childFrames(lists.CurrentList());
        2739               0 :           for (; !childFrames.AtEnd(); childFrames.Next()) {
        2740               0 :             nsIFrame* kid = childFrames.get();
        2741               0 :             kid->MarkIntrinsicWidthsDirty();
        2742               0 :             stack.AppendElement(kid);
        2743                 :           }
        2744                 :         }
        2745               0 :       } while (stack.Length() != 0);
        2746                 :     }
        2747                 :
        2748                 :     // Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty)
        2749                 :     // up the tree until we reach either a frame that's already dirty or
        2750                 :     // a reflow root.
        2751               0 :     nsIFrame *f = subtreeRoot;
        2752               0 :     for (;;) {
        2753               0 :       if (FRAME_IS_REFLOW_ROOT(f) || !f->GetParent()) {
        2754                 :         // we've hit a reflow root or the root frame
        2755               0 :         if (!wasDirty) {
        2756               0 :           mDirtyRoots.AppendElement(f);
        2757               0 :           mDocument->SetNeedLayoutFlush();
        2758                 :         }
        2759                 : #ifdef DEBUG
        2760                 :         else {
        2761               0 :           VerifyHasDirtyRootAncestor(f);
        2762                 :         }
        2763                 : #endif
        2764                 :
        2765               0 :         break;
        2766                 :       }
        2767                 :
        2768               0 :       nsIFrame *child = f;
        2769               0 :       f = f->GetParent();
        2770               0 :       wasDirty = NS_SUBTREE_DIRTY(f);
        2771               0 :       f->ChildIsDirty(child);
        2772               0 :       NS_ASSERTION(f->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN,
        2773                 :                    "ChildIsDirty didn't do its job");
        2774               0 :       if (wasDirty) {
        2775                 :         // This frame was already marked dirty.
        2776                 : #ifdef DEBUG
        2777               0 :         VerifyHasDirtyRootAncestor(f);
        2778                 : #endif
        2779               0 :         break;
        2780                 :       }
        2781                 :     }
        2782               0 :   } while (subtrees.Length() != 0);
        2783                 :
        2784               0 :   MaybeScheduleReflow();
        2785                 : }
        2786                 :
        2787                 : void
        2788               0 : PresShell::FrameNeedsToContinueReflow(nsIFrame *aFrame)
        2789                 : {
        2790               0 :   NS_ASSERTION(mIsReflowing, "Must be in reflow when marking path dirty.");
        2791               0 :   NS_PRECONDITION(mCurrentReflowRoot, "Must have a current reflow root here");
        2792               0 :   NS_ASSERTION(aFrame == mCurrentReflowRoot ||
        2793                 :                nsLayoutUtils::IsProperAncestorFrame(mCurrentReflowRoot, aFrame),
        2794                 :                "Frame passed in is not the descendant of mCurrentReflowRoot");
        2795               0 :   NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_IN_REFLOW,
        2796                 :                "Frame passed in not in reflow?");
        2797                 :
        2798               0 :   mFramesToDirty.PutEntry(aFrame);
        2799               0 : }
        2800                 :
        2801                 : nsIScrollableFrame*
        2802               0 : nsIPresShell::GetFrameToScrollAsScrollable(
        2803                 :                 nsIPresShell::ScrollDirection aDirection)
        2804                 : {
        2805               0 :   nsIScrollableFrame* scrollFrame = nsnull;
        2806                 :
        2807               0 :   nsCOMPtr<nsIContent> focusedContent;
        2808               0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
        2809               0 :   if (fm && mDocument) {
        2810               0 :     nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(mDocument->GetWindow());
        2811                 :
        2812               0 :     nsCOMPtr<nsIDOMElement> focusedElement;
        2813               0 :     fm->GetFocusedElementForWindow(window, false, nsnull, getter_AddRefs(focusedElement));
        2814               0 :     focusedContent = do_QueryInterface(focusedElement);
        2815                 :   }
        2816               0 :   if (!focusedContent && mSelection) {
        2817                 :     nsISelection* domSelection = mSelection->
        2818               0 :       GetSelection(nsISelectionController::SELECTION_NORMAL);
        2819               0 :     if (domSelection) {
        2820               0 :       nsCOMPtr<nsIDOMNode> focusedNode;
        2821               0 :       domSelection->GetFocusNode(getter_AddRefs(focusedNode));
        2822               0 :       focusedContent = do_QueryInterface(focusedNode);
        2823                 :     }
        2824                 :   }
        2825               0 :   if (focusedContent) {
        2826               0 :     nsIFrame* startFrame = focusedContent->GetPrimaryFrame();
        2827               0 :     if (startFrame) {
        2828               0 :       scrollFrame = startFrame->GetScrollTargetFrame();
        2829               0 :       if (scrollFrame) {
        2830               0 :         startFrame = scrollFrame->GetScrolledFrame();
        2831                 :       }
        2832               0 :       if (aDirection == nsIPresShell::eEither) {
        2833                 :         scrollFrame =
        2834               0 :           nsLayoutUtils::GetNearestScrollableFrame(startFrame);
        2835                 :       } else {
        2836                 :         scrollFrame =
        2837                 :           nsLayoutUtils::GetNearestScrollableFrameForDirection(startFrame,
        2838                 :             aDirection == eVertical ? nsLayoutUtils::eVertical :
        2839               0 :                                       nsLayoutUtils::eHorizontal);
        2840                 :       }
        2841                 :     }
        2842                 :   }
        2843               0 :   if (!scrollFrame) {
        2844               0 :     scrollFrame = GetRootScrollFrameAsScrollable();
        2845                 :   }
        2846               0 :   return scrollFrame;
        2847                 : }
        2848                 :
        2849                 : void
        2850               0 : PresShell::CancelAllPendingReflows()
        2851                 : {
        2852               0 :   mDirtyRoots.Clear();
        2853                 :
        2854               0 :   if (mReflowScheduled) {
        2855               0 :     GetPresContext()->RefreshDriver()->RemoveLayoutFlushObserver(this);
        2856               0 :     mReflowScheduled = false;
        2857                 :   }
        2858                 :
        2859               0 :   ASSERT_REFLOW_SCHEDULED_STATE();
        2860               0 : }
        2861                 :
        2862                 : nsresult
        2863               0 : PresShell::RecreateFramesFor(nsIContent* aContent)
        2864                 : {
        2865                 :   NS_TIME_FUNCTION_MIN(1.0);
        2866                 :
        2867               0 :   NS_ENSURE_TRUE(mPresContext, NS_ERROR_FAILURE);
        2868               0 :   if (!mDidInitialReflow) {
        2869                 :     // Nothing to do here.  In fact, if we proceed and aContent is the
        2870                 :     // root we will crash.
        2871               0 :     return NS_OK;
        2872                 :   }
        2873                 :
        2874                 :   // Don't call RecreateFramesForContent since that is not exported and we want
        2875                 :   // to keep the number of entrypoints down.
        2876                 :
        2877               0 :   NS_ASSERTION(mViewManager, "Should have view manager");
        2878                 :
        2879                 :   // Have to make sure that the content notifications are flushed before we
        2880                 :   // start messing with the frame model; otherwise we can get content doubling.
        2881               0 :   mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
        2882                 :
        2883               0 :   nsAutoScriptBlocker scriptBlocker;
        2884                 :
        2885               0 :   nsStyleChangeList changeList;
        2886               0 :   changeList.AppendChange(nsnull, aContent, nsChangeHint_ReconstructFrame);
        2887                 :
        2888                 :   // Mark ourselves as not safe to flush while we're doing frame construction.
        2889               0 :   ++mChangeNestCount;
        2890               0 :   nsresult rv = mFrameConstructor->ProcessRestyledFrames(changeList);
        2891               0 :   --mChangeNestCount;
        2892                 :
        2893               0 :   return rv;
        2894                 : }
        2895                 :
        2896                 : void
        2897               0 : nsIPresShell::PostRecreateFramesFor(Element* aElement)
        2898                 : {
        2899                 :   FrameConstructor()->PostRestyleEvent(aElement, nsRestyleHint(0),
        2900               0 :                                        nsChangeHint_ReconstructFrame);
        2901               0 : }
        2902                 :
        2903                 : void
        2904               0 : nsIPresShell::RestyleForAnimation(Element* aElement, nsRestyleHint aHint)
        2905                 : {
        2906                 :   FrameConstructor()->PostAnimationRestyleEvent(aElement, aHint,
        2907               0 :                                                 NS_STYLE_HINT_NONE);
        2908               0 : }
        2909                 :
        2910                 : void
        2911               0 : PresShell::ClearFrameRefs(nsIFrame* aFrame)
        2912                 : {
        2913               0 :   mPresContext->EventStateManager()->ClearFrameRefs(aFrame);
        2914                 :
        2915               0 :   nsWeakFrame* weakFrame = mWeakFrames;
        2916               0 :   while (weakFrame) {
        2917               0 :     nsWeakFrame* prev = weakFrame->GetPreviousWeakFrame();
        2918               0 :     if (weakFrame->GetFrame() == aFrame) {
        2919                 :       // This removes weakFrame from mWeakFrames.
        2920               0 :       weakFrame->Clear(this);
        2921                 :     }
        2922               0 :     weakFrame = prev;
        2923                 :   }
        2924               0 : }
        2925                 :
        2926                 : already_AddRefed<nsRenderingContext>
        2927               0 : PresShell::GetReferenceRenderingContext()
        2928                 : {
        2929                 :   NS_TIME_FUNCTION_MIN(1.0);
        2930                 :
        2931               0 :   nsDeviceContext* devCtx = mPresContext->DeviceContext();
        2932               0 :   nsRefPtr<nsRenderingContext> rc;
        2933               0 :   if (mPresContext->IsScreen()) {
        2934               0 :     rc = new nsRenderingContext();
        2935               0 :     rc->Init(devCtx, gfxPlatform::GetPlatform()->ScreenReferenceSurface());
        2936                 :   } else {
        2937               0 :     devCtx->CreateRenderingContext(*getter_AddRefs(rc));
        2938                 :   }
        2939               0 :   return rc.forget();
        2940                 : }
        2941                 :
        2942                 : nsresult
        2943               0 : PresShell::GoToAnchor(const nsAString& aAnchorName, bool aScroll)
        2944                 : {
        2945               0 :   if (!mDocument) {
        2946               0 :     return NS_ERROR_FAILURE;
        2947                 :   }
        2948                 :
        2949                 :   // Hold a reference to the ESM in case event dispatch tears us down.
        2950               0 :   nsRefPtr<nsEventStateManager> esm = mPresContext->EventStateManager();
        2951                 :
        2952               0 :   if (aAnchorName.IsEmpty()) {
        2953               0 :     NS_ASSERTION(!aScroll, "can't scroll to empty anchor name");
        2954               0 :     esm->SetContentState(nsnull, NS_EVENT_STATE_URLTARGET);
        2955               0 :     return NS_OK;
        2956                 :   }
        2957                 :
        2958               0 :   nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
        2959               0 :   nsresult rv = NS_OK;
        2960               0 :   nsCOMPtr<nsIContent> content;
        2961                 :
        2962                 :   // Search for an element with a matching "id" attribute
        2963               0 :   if (mDocument) {
        2964               0 :     content = mDocument->GetElementById(aAnchorName);
        2965                 :   }
        2966                 :
        2967                 :   // Search for an anchor element with a matching "name" attribute
        2968               0 :   if (!content && htmlDoc) {
        2969               0 :     nsCOMPtr<nsIDOMNodeList> list;
        2970                 :     // Find a matching list of named nodes
        2971               0 :     rv = htmlDoc->GetElementsByName(aAnchorName, getter_AddRefs(list));
        2972               0 :     if (NS_SUCCEEDED(rv) && list) {
        2973                 :       PRUint32 i;
        2974                 :       // Loop through the named nodes looking for the first anchor
        2975               0 :       for (i = 0; true; i++) {
        2976               0 :         nsCOMPtr<nsIDOMNode> node;
        2977               0 :         rv = list->Item(i, getter_AddRefs(node));
        2978               0 :         if (!node) {  // End of list
        2979                 :           break;
        2980                 :         }
        2981                 :         // Ensure it's an anchor element
        2982               0 :         content = do_QueryInterface(node);
        2983               0 :         if (content) {
        2984               0 :           if (content->Tag() == nsGkAtoms::a && content->IsHTML()) {
        2985                 :             break;
        2986                 :           }
        2987               0 :           content = nsnull;
        2988                 :         }
        2989                 :       }
        2990                 :     }
        2991                 :   }
        2992                 :
        2993                 :   // Search for anchor in the HTML namespace with a matching name
        2994               0 :   if (!content && !htmlDoc)
        2995                 :   {
        2996               0 :     nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(mDocument);
        2997               0 :     nsCOMPtr<nsIDOMNodeList> list;
        2998               0 :     NS_NAMED_LITERAL_STRING(nameSpace, "http://www.w3.org/1999/xhtml");
        2999                 :     // Get the list of anchor elements
        3000               0 :     rv = doc->GetElementsByTagNameNS(nameSpace, NS_LITERAL_STRING("a"), getter_AddRefs(list));
        3001               0 :     if (NS_SUCCEEDED(rv) && list) {
        3002                 :       PRUint32 i;
        3003                 :       // Loop through the named nodes looking for the first anchor
        3004               0 :       for (i = 0; true; i++) {
        3005               0 :         nsCOMPtr<nsIDOMNode> node;
        3006               0 :         rv = list->Item(i, getter_AddRefs(node));
        3007               0 :         if (!node) { // End of list
        3008                 :           break;
        3009                 :         }
        3010                 :         // Compare the name attribute
        3011               0 :         nsCOMPtr<nsIDOMElement> element = do_QueryInterface(node);
        3012               0 :         nsAutoString value;
        3013               0 :         if (element && NS_SUCCEEDED(element->GetAttribute(NS_LITERAL_STRING("name"), value))) {
        3014               0 :           if (value.Equals(aAnchorName)) {
        3015               0 :             content = do_QueryInterface(element);
        3016                 :             break;
        3017                 :           }
        3018                 :         }
        3019                 :       }
        3020                 :     }
        3021                 :   }
        3022                 :
        3023               0 :   esm->SetContentState(content, NS_EVENT_STATE_URLTARGET);
        3024                 :
        3025                 : #ifdef ACCESSIBILITY
        3026               0 :   nsIContent *anchorTarget = content;
        3027                 : #endif
        3028                 :
        3029               0 :   if (content) {
        3030               0 :     if (aScroll) {
        3031                 :       rv = ScrollContentIntoView(content, NS_PRESSHELL_SCROLL_TOP,
        3032                 :                                  NS_PRESSHELL_SCROLL_ANYWHERE,
        3033               0 :                                  ANCHOR_SCROLL_FLAGS);
        3034               0 :       NS_ENSURE_SUCCESS(rv, rv);
        3035                 :
        3036               0 :       nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
        3037               0 :       if (rootScroll) {
        3038               0 :         mLastAnchorScrolledTo = content;
        3039               0 :         mLastAnchorScrollPositionY = rootScroll->GetScrollPosition().y;
        3040                 :       }
        3041                 :     }
        3042                 :
        3043                 :     // Should we select the target? This action is controlled by a
        3044                 :     // preference: the default is to not select.
        3045               0 :     bool selectAnchor = Preferences::GetBool("layout.selectanchor");
        3046                 :
        3047                 :     // Even if select anchor pref is false, we must still move the
        3048                 :     // caret there. That way tabbing will start from the new
        3049                 :     // location
        3050               0 :     nsRefPtr<nsIDOMRange> jumpToRange = new nsRange();
        3051               0 :     while (content && content->GetFirstChild()) {
        3052               0 :       content = content->GetFirstChild();
        3053                 :     }
        3054               0 :     nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
        3055               0 :     NS_ASSERTION(node, "No nsIDOMNode for descendant of anchor");
        3056               0 :     jumpToRange->SelectNodeContents(node);
        3057                 :     // Select the anchor
        3058                 :     nsISelection* sel = mSelection->
        3059               0 :       GetSelection(nsISelectionController::SELECTION_NORMAL);
        3060               0 :     if (sel) {
        3061               0 :       sel->RemoveAllRanges();
        3062               0 :       sel->AddRange(jumpToRange);
        3063               0 :       if (!selectAnchor) {
        3064                 :         // Use a caret (collapsed selection) at the start of the anchor
        3065               0 :         sel->CollapseToStart();
        3066                 :       }
        3067                 :     }
        3068                 :     // Selection is at anchor.
        3069                 :     // Now focus the document itself if focus is on an element within it.
        3070               0 :     nsPIDOMWindow *win = mDocument->GetWindow();
        3071                 :
        3072               0 :     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
        3073               0 :     if (fm && win) {
        3074               0 :       nsCOMPtr<nsIDOMWindow> focusedWindow;
        3075               0 :       fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
        3076               0 :       if (SameCOMIdentity(win, focusedWindow)) {
        3077               0 :         fm->ClearFocus(focusedWindow);
        3078                 :       }
        3079                 :     }
        3080                 :   } else {
        3081               0 :     rv = NS_ERROR_FAILURE;
        3082               0 :     NS_NAMED_LITERAL_STRING(top, "top");
        3083               0 :     if (nsContentUtils::EqualsIgnoreASCIICase(aAnchorName, top)) {
        3084                 :       // Scroll to the top/left if aAnchorName is "top" and there is no element
        3085                 :       // with such a name or id.
        3086               0 :       rv = NS_OK;
        3087               0 :       nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable();
        3088                 :       // Check |aScroll| after setting |rv| so we set |rv| to the same
        3089                 :       // thing whether or not |aScroll| is true.
        3090               0 :       if (aScroll && sf) {
        3091                 :         // Scroll to the top of the page
        3092               0 :         sf->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT);
        3093                 :       }
        3094                 :     }
        3095                 :   }
        3096                 :
        3097                 : #ifdef ACCESSIBILITY
        3098               0 :   if (anchorTarget) {
        3099               0 :     nsAccessibilityService* accService = AccService();
        3100               0 :     if (accService)
        3101               0 :       accService->NotifyOfAnchorJumpTo(anchorTarget);
        3102                 :   }
        3103                 : #endif
        3104                 :
        3105               0 :   return rv;
        3106                 : }
        3107                 :
        3108                 : nsresult
        3109               0 : PresShell::ScrollToAnchor()
        3110                 : {
        3111               0 :   if (!mLastAnchorScrolledTo)
        3112               0 :     return NS_OK;
        3113                 :
        3114               0 :   NS_ASSERTION(mDidInitialReflow, "should have done initial reflow by now");
        3115                 :
        3116               0 :   nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
        3117               0 :   if (!rootScroll ||
        3118               0 :       mLastAnchorScrollPositionY != rootScroll->GetScrollPosition().y)
        3119               0 :     return NS_OK;
        3120                 :
        3121                 :   nsresult rv = ScrollContentIntoView(mLastAnchorScrolledTo, NS_PRESSHELL_SCROLL_TOP,
        3122                 :                                       NS_PRESSHELL_SCROLL_ANYWHERE,
        3123               0 :                                       ANCHOR_SCROLL_FLAGS);
        3124               0 :   mLastAnchorScrolledTo = nsnull;
        3125               0 :   return rv;
        3126                 : }
        3127                 :
        3128                 : /*
        3129                 :  * Helper (per-continuation) for ScrollContentIntoView.
        3130                 :  *
        3131                 :  * @param aContainerFrame [in] the frame which aRect is relative to
        3132                 :  * @param aFrame [in] Frame whose bounds should be unioned
        3133                 :  * @param aUseWholeLineHeightForInlines [in] if true, then for inline frames
        3134                 :  * we should include the top of the line in the added rectangle
        3135                 :  * @param aRect [inout] rect into which its bounds should be unioned
        3136                 :  * @param aHaveRect [inout] whether aRect contains data yet
        3137                 :  * @param aPrevBlock [inout] the block aLines is a line iterator for
        3138                 :  * @param aLines [inout] the line iterator we're using
        3139                 :  * @param aCurLine [inout] the line to start looking from in this iterator
        3140                 :  */
        3141                 : static void
        3142               0 : AccumulateFrameBounds(nsIFrame* aContainerFrame,
        3143                 :                       nsIFrame* aFrame,
        3144                 :                       bool aUseWholeLineHeightForInlines,
        3145                 :                       nsRect& aRect,
        3146                 :                       bool& aHaveRect,
        3147                 :                       nsIFrame*& aPrevBlock,
        3148                 :                       nsAutoLineIterator& aLines,
        3149                 :                       PRInt32& aCurLine)
        3150                 : {
        3151               0 :   nsRect frameBounds = aFrame->GetRect() +
        3152               0 :     aFrame->GetParent()->GetOffsetTo(aContainerFrame);
        3153                 :
        3154                 :   // If this is an inline frame and either the bounds height is 0 (quirks
        3155                 :   // layout model) or aUseWholeLineHeightForInlines is set, we need to
        3156                 :   // change the top of the bounds to include the whole line.
        3157               0 :   if (frameBounds.height == 0 || aUseWholeLineHeightForInlines) {
        3158               0 :     nsIAtom* frameType = NULL;
        3159               0 :     nsIFrame *prevFrame = aFrame;
        3160               0 :     nsIFrame *f = aFrame;
        3161                 :
        3162               0 :     while (f &&
        3163               0 :            (frameType = f->GetType()) == nsGkAtoms::inlineFrame) {
        3164               0 :       prevFrame = f;
        3165               0 :       f = prevFrame->GetParent();
        3166                 :     }
        3167                 :
        3168               0 :     if (f != aFrame &&
        3169                 :         f &&
        3170                 :         frameType == nsGkAtoms::blockFrame) {
        3171                 :       // find the line containing aFrame and increase the top of |offset|.
        3172               0 :       if (f != aPrevBlock) {
        3173               0 :         aLines = f->GetLineIterator();
        3174               0 :         aPrevBlock = f;
        3175               0 :         aCurLine = 0;
        3176                 :       }
        3177               0 :       if (aLines) {
        3178               0 :         PRInt32 index = aLines->FindLineContaining(prevFrame, aCurLine);
        3179               0 :         if (index >= 0) {
        3180               0 :           aCurLine = index;
        3181                 :           nsIFrame *trash1;
        3182                 :           PRInt32 trash2;
        3183               0 :           nsRect lineBounds;
        3184                 :           PRUint32 trash3;
        3185                 :
        3186               0 :           if (NS_SUCCEEDED(aLines->GetLine(index, &trash1, &trash2,
        3187                 :                                            lineBounds, &trash3))) {
        3188               0 :             lineBounds += f->GetOffsetTo(aContainerFrame);
        3189               0 :             if (lineBounds.y < frameBounds.y) {
        3190               0 :               frameBounds.height = frameBounds.YMost() - lineBounds.y;
        3191               0 :               frameBounds.y = lineBounds.y;
        3192                 :             }
        3193                 :           }
        3194                 :         }
        3195                 :       }
        3196                 :     }
        3197                 :   }
        3198                 :
        3199               0 :   if (aHaveRect) {
        3200                 :     // We can't use nsRect::UnionRect since it drops empty rects on
        3201                 :     // the floor, and we need to include them.  (Thus we need
        3202                 :     // aHaveRect to know when to drop the initial value on the floor.)
        3203               0 :     aRect.UnionRectEdges(aRect, frameBounds);
        3204                 :   } else {
        3205               0 :     aHaveRect = true;
        3206               0 :     aRect = frameBounds;
        3207                 :   }
        3208               0 : }
        3209                 :
        3210                 : /**
        3211                 :  * This function takes a scrollable frame, a rect in the coordinate system
        3212                 :  * of the scrolled frame, and a desired percentage-based scroll
        3213                 :  * position and attempts to scroll the rect to that position in the
        3214                 :  * scrollport.
        3215                 :  *
        3216                 :  * This needs to work even if aRect has a width or height of zero.
        3217                 :  */
        3218               0 : static void ScrollToShowRect(nsIScrollableFrame* aScrollFrame,
        3219                 :                              const nsRect&       aRect,
        3220                 :                              PRIntn              aVPercent,
        3221                 :                              PRIntn              aHPercent,
        3222                 :                              PRUint32            aFlags)
        3223                 : {
        3224               0 :   nsPoint scrollPt = aScrollFrame->GetScrollPosition();
        3225               0 :   nsRect visibleRect(scrollPt, aScrollFrame->GetScrollPortRect().Size());
        3226               0 :   nsSize lineSize = aScrollFrame->GetLineScrollAmount();
        3227               0 :   nsPresContext::ScrollbarStyles ss = aScrollFrame->GetScrollbarStyles();
        3228                 :
        3229               0 :   if ((aFlags & nsIPresShell::SCROLL_OVERFLOW_HIDDEN) ||
        3230                 :       ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN) {
        3231                 :     // See how the rect should be positioned vertically
        3232               0 :     if (NS_PRESSHELL_SCROLL_ANYWHERE == aVPercent ||
        3233                 :         (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE == aVPercent &&
        3234                 :          aRect.height < lineSize.height)) {
        3235                 :       // The caller doesn't care where the frame is positioned vertically,
        3236                 :       // so long as it's fully visible
        3237               0 :       if (aRect.y < visibleRect.y) {
        3238                 :         // Scroll up so the frame's top edge is visible
        3239               0 :         scrollPt.y = aRect.y;
        3240               0 :       } else if (aRect.YMost() > visibleRect.YMost()) {
        3241                 :         // Scroll down so the frame's bottom edge is visible. Make sure the
        3242                 :         // frame's top edge is still visible
        3243               0 :         scrollPt.y += aRect.YMost() - visibleRect.YMost();
        3244               0 :         if (scrollPt.y > aRect.y) {
        3245               0 :           scrollPt.y = aRect.y;
        3246                 :         }
        3247                 :       }
        3248               0 :     } else if (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE == aVPercent) {
        3249                 :       // Scroll only if no part of the frame is visible in this view
        3250               0 :       if (aRect.YMost() - lineSize.height < visibleRect.y) {
        3251                 :         // Scroll up so the frame's top edge is visible
        3252               0 :         scrollPt.y = aRect.y;
        3253               0 :       }  else if (aRect.y + lineSize.height > visibleRect.YMost()) {
        3254                 :         // Scroll down so the frame's bottom edge is visible. Make sure the
        3255                 :         // frame's top edge is still visible
        3256               0 :         scrollPt.y += aRect.YMost() - visibleRect.YMost();
        3257               0 :         if (scrollPt.y > aRect.y) {
        3258               0 :           scrollPt.y = aRect.y;
        3259                 :         }
        3260                 :       }
        3261                 :     } else {
        3262                 :       // Align the frame edge according to the specified percentage
        3263                 :       nscoord frameAlignY =
        3264               0 :         NSToCoordRound(aRect.y + aRect.height * (aVPercent / 100.0f));
        3265                 :       scrollPt.y =
        3266               0 :         NSToCoordRound(frameAlignY - visibleRect.height * (aVPercent / 100.0f));
        3267                 :     }
        3268                 :   }
        3269                 :
        3270               0 :   if ((aFlags & nsIPresShell::SCROLL_OVERFLOW_HIDDEN) ||
        3271                 :       ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN) {
        3272                 :     // See how the frame should be positioned horizontally
        3273               0 :     if (NS_PRESSHELL_SCROLL_ANYWHERE == aHPercent ||
        3274                 :         (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE == aHPercent &&
        3275                 :          aRect.width < lineSize.width)) {
        3276                 :       // The caller doesn't care where the frame is positioned horizontally,
        3277                 :       // so long as it's fully visible
        3278               0 :       if (aRect.x < visibleRect.x) {
        3279                 :         // Scroll left so the frame's left edge is visible
        3280               0 :         scrollPt.x = aRect.x;
        3281               0 :       } else if (aRect.XMost() > visibleRect.XMost()) {
        3282                 :         // Scroll right so the frame's right edge is visible. Make sure the
        3283                 :         // frame's left edge is still visible
        3284               0 :         scrollPt.x += aRect.XMost() - visibleRect.XMost();
        3285               0 :         if (scrollPt.x > aRect.x) {
        3286               0 :           scrollPt.x = aRect.x;
        3287                 :         }
        3288                 :       }
        3289               0 :     } else if (NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE == aHPercent) {
        3290                 :       // Scroll only if no part of the frame is visible in this view
        3291               0 :       if (aRect.XMost() - lineSize.width < visibleRect.x) {
        3292                 :         // Scroll left so the frame's left edge is visible
        3293               0 :         scrollPt.x = aRect.x;
        3294               0 :       }  else if (aRect.x + lineSize.width > visibleRect.XMost()) {
        3295                 :         // Scroll right so the frame's right edge is visible. Make sure the
        3296                 :         // frame's left edge is still visible
        3297               0 :         scrollPt.x += aRect.XMost() - visibleRect.XMost();
        3298               0 :         if (scrollPt.x > aRect.x) {
        3299               0 :           scrollPt.x = aRect.x;
        3300                 :         }
        3301                 :       }
        3302                 :     } else {
        3303                 :       // Align the frame edge according to the specified percentage
        3304                 :       nscoord frameAlignX =
        3305               0 :         NSToCoordRound(aRect.x + (aRect.width) * (aHPercent / 100.0f));
        3306                 :       scrollPt.x =
        3307               0 :         NSToCoordRound(frameAlignX - visibleRect.width * (aHPercent / 100.0f));
        3308                 :     }
        3309                 :   }
        3310                 :
        3311               0 :   aScrollFrame->ScrollTo(scrollPt, nsIScrollableFrame::INSTANT);
        3312               0 : }
        3313                 :
        3314                 : nsresult
        3315               0 : PresShell::ScrollContentIntoView(nsIContent* aContent,
        3316                 :                                  PRIntn      aVPercent,
        3317                 :                                  PRIntn      aHPercent,
        3318                 :                                  PRUint32    aFlags)
        3319                 : {
        3320               0 :   nsCOMPtr<nsIContent> content = aContent; // Keep content alive while flushing.
        3321               0 :   NS_ENSURE_TRUE(content, NS_ERROR_NULL_POINTER);
        3322               0 :   nsCOMPtr<nsIDocument> currentDoc = content->GetCurrentDoc();
        3323               0 :   NS_ENSURE_STATE(currentDoc);
        3324                 :
        3325               0 :   NS_ASSERTION(mDidInitialReflow, "should have done initial reflow by now");
        3326                 :
        3327               0 :   mContentToScrollTo = aContent;
        3328               0 :   mContentScrollVPosition = aVPercent;
        3329               0 :   mContentScrollHPosition = aHPercent;
        3330               0 :   mContentToScrollToFlags = aFlags;
        3331                 :
        3332                 :   // Flush layout and attempt to scroll in the process.
        3333               0 :   currentDoc->SetNeedLayoutFlush();
        3334               0 :   currentDoc->FlushPendingNotifications(Flush_InterruptibleLayout);
        3335                 :
        3336                 :   // If mContentToScrollTo is non-null, that means we interrupted the reflow
        3337                 :   // (or suppressed it altogether because we're suppressing interruptible
        3338                 :   // flushes right now) and won't necessarily get the position correct, but do
        3339                 :   // a best-effort scroll here.  The other option would be to do this inside
        3340                 :   // FlushPendingNotifications, but I'm not sure the repeated scrolling that
        3341                 :   // could trigger if reflows keep getting interrupted would be more desirable
        3342                 :   // than a single best-effort scroll followed by one final scroll on the first
        3343                 :   // completed reflow.
        3344               0 :   if (mContentToScrollTo) {
        3345               0 :     DoScrollContentIntoView(content, aVPercent, aHPercent, aFlags);
        3346                 :   }
        3347               0 :   return NS_OK;
        3348                 : }
        3349                 :
        3350                 : void
        3351               0 : PresShell::DoScrollContentIntoView(nsIContent* aContent,
        3352                 :                                    PRIntn      aVPercent,
        3353                 :                                    PRIntn      aHPercent,
        3354                 :                                    PRUint32    aFlags)
        3355                 : {
        3356               0 :   NS_ASSERTION(mDidInitialReflow, "should have done initial reflow by now");
        3357                 :
        3358               0 :   nsIFrame* frame = aContent->GetPrimaryFrame();
        3359               0 :   if (!frame) {
        3360               0 :     mContentToScrollTo = nsnull;
        3361               0 :     return;
        3362                 :   }
        3363                 :
        3364               0 :   if (frame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
        3365                 :     // The reflow flush before this scroll got interrupted, and this frame's
        3366                 :     // coords and size are all zero, and it has no content showing anyway.
        3367                 :     // Don't bother scrolling to it.  We'll try again when we finish up layout.
        3368               0 :     return;
        3369                 :   }
        3370                 :
        3371                 :   nsIFrame* container =
        3372               0 :     nsLayoutUtils::GetClosestFrameOfType(frame, nsGkAtoms::scrollFrame);
        3373               0 :   if (!container) {
        3374                 :     // nothing can be scrolled
        3375               0 :     return;
        3376                 :   }
        3377                 :
        3378                 :   // This is a two-step process.
        3379                 :   // Step 1: Find the bounds of the rect we want to scroll into view.  For
        3380                 :   //         example, for an inline frame we may want to scroll in the whole
        3381                 :   //         line, or we may want to scroll multiple lines into view.
        3382                 :   // Step 2: Walk container frame and its ancestors and scroll them
        3383                 :   //         appropriately.
        3384                 :   // frameBounds is relative to container. We're assuming
        3385                 :   // that scrollframes don't split so every continuation of frame will
        3386                 :   // be a descendant of container. (Things would still mostly work
        3387                 :   // even if that assumption was false.)
        3388               0 :   nsRect frameBounds;
        3389               0 :   bool haveRect = false;
        3390               0 :   bool useWholeLineHeightForInlines = aVPercent != NS_PRESSHELL_SCROLL_ANYWHERE;
        3391                 :   // Reuse the same line iterator across calls to AccumulateFrameBounds.  We set
        3392                 :   // it every time we detect a new block (stored in prevBlock).
        3393               0 :   nsIFrame* prevBlock = nsnull;
        3394               0 :   nsAutoLineIterator lines;
        3395                 :   // The last line we found a continuation on in |lines|.  We assume that later
        3396                 :   // continuations cannot come on earlier lines.
        3397               0 :   PRInt32 curLine = 0;
        3398               0 :   do {
        3399                 :     AccumulateFrameBounds(container, frame, useWholeLineHeightForInlines,
        3400               0 :                           frameBounds, haveRect, prevBlock, lines, curLine);
        3401               0 :   } while ((frame = frame->GetNextContinuation()));
        3402                 :
        3403                 :   ScrollFrameRectIntoView(container, frameBounds, aVPercent, aHPercent,
        3404               0 :                           aFlags);
        3405                 : }
        3406                 :
        3407                 : bool
        3408               0 : PresShell::ScrollFrameRectIntoView(nsIFrame*     aFrame,
        3409                 :                                    const nsRect& aRect,
        3410                 :                                    PRIntn        aVPercent,
        3411                 :                                    PRIntn        aHPercent,
        3412                 :                                    PRUint32      aFlags)
        3413                 : {
        3414               0 :   bool didScroll = false;
        3415                 :   // This function needs to work even if rect has a width or height of 0.
        3416               0 :   nsRect rect = aRect;
        3417               0 :   nsIFrame* container = aFrame;
        3418                 :   // Walk up the frame hierarchy scrolling the rect into view and
        3419                 :   // keeping rect relative to container
        3420               0 :   do {
        3421               0 :     nsIScrollableFrame* sf = do_QueryFrame(container);
        3422               0 :     if (sf) {
        3423               0 :       nsPoint oldPosition = sf->GetScrollPosition();
        3424               0 :       ScrollToShowRect(sf, rect - sf->GetScrolledFrame()->GetPosition(),
        3425               0 :                        aVPercent, aHPercent, aFlags);
        3426               0 :       nsPoint newPosition = sf->GetScrollPosition();
        3427                 :       // If the scroll position increased, that means our content moved up,
        3428                 :       // so our rect's offset should decrease
        3429               0 :       rect += oldPosition - newPosition;
        3430                 :
        3431               0 :       if (oldPosition != newPosition) {
        3432               0 :         didScroll = true;
        3433                 :       }
        3434                 :
        3435                 :       // only scroll one container when this flag is set
        3436               0 :       if (aFlags & nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY) {
        3437               0 :         break;
        3438                 :       }
        3439                 :     }
        3440               0 :     rect += container->GetPosition();
        3441               0 :     nsIFrame* parent = container->GetParent();
        3442               0 :     if (!parent && !(aFlags & nsIPresShell::SCROLL_NO_PARENT_FRAMES)) {
        3443               0 :       nsPoint extraOffset(0,0);
        3444               0 :       parent = nsLayoutUtils::GetCrossDocParentFrame(container, &extraOffset);
        3445               0 :       if (parent) {
        3446               0 :         PRInt32 APD = container->PresContext()->AppUnitsPerDevPixel();
        3447               0 :         PRInt32 parentAPD = parent->PresContext()->AppUnitsPerDevPixel();
        3448               0 :         rect = rect.ConvertAppUnitsRoundOut(APD, parentAPD);
        3449               0 :         rect += extraOffset;
        3450                 :       }
        3451                 :     }
        3452               0 :     container = parent;
        3453                 :   } while (container);
        3454                 :
        3455               0 :   return didScroll;
        3456                 : }
        3457                 :
        3458                 : nsRectVisibility
        3459               0 : PresShell::GetRectVisibility(nsIFrame* aFrame,
        3460                 :                              const nsRect &aRect,
        3461                 :                              nscoord aMinTwips) const
        3462                 : {
        3463               0 :   NS_ASSERTION(aFrame->PresContext() == GetPresContext(),
        3464                 :                "prescontext mismatch?");
        3465               0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
        3466               0 :   NS_ASSERTION(rootFrame,
        3467                 :                "How can someone have a frame for this presshell when there's no root?");
        3468               0 :   nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable();
        3469               0 :   nsRect scrollPortRect;
        3470               0 :   if (sf) {
        3471               0 :     scrollPortRect = sf->GetScrollPortRect();
        3472               0 :     nsIFrame* f = do_QueryFrame(sf);
        3473               0 :     scrollPortRect += f->GetOffsetTo(rootFrame);
        3474                 :   } else {
        3475               0 :     scrollPortRect = nsRect(nsPoint(0,0), rootFrame->GetSize());
        3476                 :   }
        3477                 :
        3478               0 :   nsRect r = aRect + aFrame->GetOffsetTo(rootFrame);
        3479                 :   // If aRect is entirely visible then we don't need to ensure that
        3480                 :   // at least aMinTwips of it is visible
        3481               0 :   if (scrollPortRect.Contains(r))
        3482               0 :     return nsRectVisibility_kVisible;
        3483                 :
        3484               0 :   nsRect insetRect = scrollPortRect;
        3485               0 :   insetRect.Deflate(aMinTwips, aMinTwips);
        3486               0 :   if (r.YMost() <= insetRect.y)
        3487               0 :     return nsRectVisibility_kAboveViewport;
        3488               0 :   if (r.y >= insetRect.YMost())
        3489               0 :     return nsRectVisibility_kBelowViewport;
        3490               0 :   if (r.XMost() <= insetRect.x)
        3491               0 :     return nsRectVisibility_kLeftOfViewport;
        3492               0 :   if (r.x >= insetRect.XMost())
        3493               0 :     return nsRectVisibility_kRightOfViewport;
        3494                 :
        3495               0 :   return nsRectVisibility_kVisible;
        3496                 : }
        3497                 :
        3498                 : // GetLinkLocation: copy link location to clipboard
        3499               0 : nsresult PresShell::GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocationString) const
        3500                 : {
        3501                 : #ifdef DEBUG_dr
        3502                 :   printf("dr :: PresShell::GetLinkLocation\n");
        3503                 : #endif
        3504                 :
        3505               0 :   NS_ENSURE_ARG_POINTER(aNode);
        3506                 :
        3507               0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
        3508               0 :   if (content) {
        3509               0 :     nsCOMPtr<nsIURI> hrefURI = content->GetHrefURI();
        3510               0 :     if (hrefURI) {
        3511               0 :       nsCAutoString specUTF8;
        3512               0 :       nsresult rv = hrefURI->GetSpec(specUTF8);
        3513               0 :       NS_ENSURE_SUCCESS(rv, rv);
        3514                 :
        3515               0 :       nsAutoString anchorText;
        3516               0 :       CopyUTF8toUTF16(specUTF8, anchorText);
        3517                 :
        3518                 :       // Remove all the '\t', '\r' and '\n' from 'anchorText'
        3519                 :       static const char strippedChars[] = "\t\r\n";
        3520               0 :       anchorText.StripChars(strippedChars);
        3521               0 :       aLocationString = anchorText;
        3522               0 :       return NS_OK;
        3523                 :     }
        3524                 :   }
        3525                 :
        3526                 :   // if no link, fail.
        3527               0 :   return NS_ERROR_FAILURE;
        3528                 : }
        3529                 :
        3530                 : void
        3531               0 : PresShell::ScheduleViewManagerFlush()
        3532                 : {
        3533               0 :   nsPresContext* presContext = GetPresContext();
        3534               0 :   if (presContext) {
        3535               0 :     presContext->RefreshDriver()->ScheduleViewManagerFlush();
        3536                 :   }
        3537               0 :   if (mDocument) {
        3538               0 :     mDocument->SetNeedLayoutFlush();
        3539                 :   }
        3540               0 : }
        3541                 :
        3542                 : void
        3543               0 : PresShell::DispatchSynthMouseMove(nsGUIEvent *aEvent,
        3544                 :                                   bool aFlushOnHoverChange)
        3545                 : {
        3546               0 :   PRUint32 hoverGenerationBefore = mFrameConstructor->GetHoverGeneration();
        3547                 :   nsEventStatus status;
        3548               0 :   nsIView* targetView = nsIView::GetViewFor(aEvent->widget);
        3549               0 :   targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
        3550               0 :   if (aFlushOnHoverChange &&
        3551               0 :       hoverGenerationBefore != mFrameConstructor->GetHoverGeneration()) {
        3552                 :     // Flush so that the resulting reflow happens now so that our caller
        3553                 :     // can suppress any synthesized mouse moves caused by that reflow.
        3554               0 :     FlushPendingNotifications(Flush_Layout);
        3555                 :   }
        3556               0 : }
        3557                 :
        3558                 : void
        3559               0 : PresShell::ClearMouseCaptureOnView(nsIView* aView)
        3560                 : {
        3561               0 :   if (gCaptureInfo.mContent) {
        3562               0 :     if (aView) {
        3563                 :       // if a view was specified, ensure that the captured content is within
        3564                 :       // this view.
        3565               0 :       nsIFrame* frame = gCaptureInfo.mContent->GetPrimaryFrame();
        3566               0 :       if (frame) {
        3567               0 :         nsIView* view = frame->GetClosestView();
        3568                 :         // if there is no view, capturing won't be handled any more, so
        3569                 :         // just release the capture.
        3570               0 :         if (view) {
        3571               0 :           do {
        3572               0 :             if (view == aView) {
        3573               0 :               NS_RELEASE(gCaptureInfo.mContent);
        3574                 :               // the view containing the captured content likely disappeared so
        3575                 :               // disable capture for now.
        3576               0 :               gCaptureInfo.mAllowed = false;
        3577               0 :               break;
        3578                 :             }
        3579                 :
        3580               0 :             view = view->GetParent();
        3581                 :           } while (view);
        3582                 :           // return if the view wasn't found
        3583               0 :           return;
        3584                 :         }
        3585                 :       }
        3586                 :     }
        3587                 :
        3588               0 :     NS_RELEASE(gCaptureInfo.mContent);
        3589                 :   }
        3590                 :
        3591                 :   // disable mouse capture until the next mousedown as a dialog has opened
        3592                 :   // or a drag has started. Otherwise, someone could start capture during
        3593                 :   // the modal dialog or drag.
        3594               0 :   gCaptureInfo.mAllowed = false;
        3595                 : }
        3596                 :
        3597                 : void
        3598               0 : nsIPresShell::ClearMouseCapture(nsIFrame* aFrame)
        3599                 : {
        3600               0 :   if (!gCaptureInfo.mContent) {
        3601               0 :     gCaptureInfo.mAllowed = false;
        3602               0 :     return;
        3603                 :   }
        3604                 :
        3605                 :   // null frame argument means clear the capture
        3606               0 :   if (!aFrame) {
        3607               0 :     NS_RELEASE(gCaptureInfo.mContent);
        3608               0 :     gCaptureInfo.mAllowed = false;
        3609               0 :     return;
        3610                 :   }
        3611                 :
        3612               0 :   nsIFrame* capturingFrame = gCaptureInfo.mContent->GetPrimaryFrame();
        3613               0 :   if (!capturingFrame) {
        3614               0 :     NS_RELEASE(gCaptureInfo.mContent);
        3615               0 :     gCaptureInfo.mAllowed = false;
        3616               0 :     return;
        3617                 :   }
        3618                 :
        3619               0 :   if (nsLayoutUtils::IsAncestorFrameCrossDoc(aFrame, capturingFrame)) {
        3620               0 :     NS_RELEASE(gCaptureInfo.mContent);
        3621               0 :     gCaptureInfo.mAllowed = false;
        3622                 :   }
        3623                 : }
        3624                 :
        3625                 : nsresult
        3626               0 : PresShell::CaptureHistoryState(nsILayoutHistoryState** aState, bool aLeavingPage)
        3627                 : {
        3628                 :   NS_TIME_FUNCTION_MIN(1.0);
        3629                 :
        3630               0 :   nsresult rv = NS_OK;
        3631                 :
        3632               0 :   NS_PRECONDITION(nsnull != aState, "null state pointer");
        3633                 :
        3634                 :   // We actually have to mess with the docshell here, since we want to
        3635                 :   // store the state back in it.
        3636                 :   // XXXbz this isn't really right, since this is being called in the
        3637                 :   // content viewer's Hide() method...  by that point the docshell's
        3638                 :   // state could be wrong.  We should sort out a better ownership
        3639                 :   // model for the layout history state.
        3640               0 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
        3641               0 :   if (!container)
        3642               0 :     return NS_ERROR_FAILURE;
        3643                 :
        3644               0 :   nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
        3645               0 :   if (!docShell)
        3646               0 :     return NS_ERROR_FAILURE;
        3647                 :
        3648               0 :   nsCOMPtr<nsILayoutHistoryState> historyState;
        3649               0 :   docShell->GetLayoutHistoryState(getter_AddRefs(historyState));
        3650               0 :   if (!historyState) {
        3651                 :     // Create the document state object
        3652               0 :     rv = NS_NewLayoutHistoryState(getter_AddRefs(historyState));
        3653                 :
        3654               0 :     if (NS_FAILED(rv)) {
        3655               0 :       *aState = nsnull;
        3656               0 :       return rv;
        3657                 :     }
        3658                 :
        3659               0 :     docShell->SetLayoutHistoryState(historyState);
        3660                 :   }
        3661                 :
        3662               0 :   *aState = historyState;
        3663               0 :   NS_IF_ADDREF(*aState);
        3664                 :
        3665                 :   // Capture frame state for the entire frame hierarchy
        3666               0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
        3667               0 :   if (!rootFrame) return NS_OK;
        3668                 :   // Capture frame state for the root scroll frame
        3669                 :   // Don't capture state when first creating doc element hierarchy
        3670                 :   // As the scroll position is 0 and this will cause us to lose
        3671                 :   // our previously saved place!
        3672               0 :   if (aLeavingPage) {
        3673               0 :     nsIFrame* scrollFrame = GetRootScrollFrame();
        3674               0 :     if (scrollFrame) {
        3675                 :       mFrameConstructor->CaptureFrameStateFor(scrollFrame, historyState,
        3676               0 :                                               nsIStatefulFrame::eDocumentScrollState);
        3677                 :     }
        3678                 :   }
        3679                 :
        3680               0 :   mFrameConstructor->CaptureFrameState(rootFrame, historyState);
        3681                 :
        3682               0 :   return NS_OK;
        3683                 : }
        3684                 :
        3685                 : void
        3686               0 : PresShell::UnsuppressAndInvalidate()
        3687                 : {
        3688                 :   // Note: We ignore the EnsureVisible check for resource documents, because
        3689                 :   // they won't have a docshell, so they'll always fail EnsureVisible.
        3690               0 :   if ((!mDocument->IsResourceDoc() && !mPresContext->EnsureVisible()) ||
        3691                 :       mHaveShutDown) {
        3692                 :     // No point; we're about to be torn down anyway.
        3693               0 :     return;
        3694                 :   }
        3695                 :
        3696               0 :   mPaintingSuppressed = false;
        3697               0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
        3698               0 :   if (rootFrame) {
        3699                 :     // let's assume that outline on a root frame is not supported
        3700               0 :     nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
        3701               0 :     rootFrame->Invalidate(rect);
        3702                 :
        3703               0 :     if (mCaretEnabled && mCaret) {
        3704               0 :       mCaret->CheckCaretDrawingState();
        3705                 :     }
        3706                 :
        3707               0 :     nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
        3708               0 :     if (rootPC) {
        3709               0 :       rootPC->RequestUpdatePluginGeometry(rootFrame);
        3710                 :     }
        3711                 :   }
        3712                 :
        3713                 :   // now that painting is unsuppressed, focus may be set on the document
        3714               0 :   nsPIDOMWindow *win = mDocument->GetWindow();
        3715               0 :   if (win)
        3716               0 :     win->SetReadyForFocus();
        3717                 :
        3718               0 :   if (!mHaveShutDown)
        3719               0 :     SynthesizeMouseMove(false);
        3720                 : }
        3721                 :
        3722                 : void
        3723               0 : PresShell::UnsuppressPainting()
        3724                 : {
        3725               0 :   if (mPaintSuppressionTimer) {
        3726               0 :     mPaintSuppressionTimer->Cancel();
        3727               0 :     mPaintSuppressionTimer = nsnull;
        3728                 :   }
        3729                 :
        3730               0 :   if (mIsDocumentGone || !mPaintingSuppressed)
        3731               0 :     return;
        3732                 :
        3733                 :   // If we have reflows pending, just wait until we process
        3734                 :   // the reflows and get all the frames where we want them
        3735                 :   // before actually unlocking the painting.  Otherwise
        3736                 :   // go ahead and unlock now.
        3737               0 :   if (!mDirtyRoots.IsEmpty())
        3738               0 :     mShouldUnsuppressPainting = true;
        3739                 :   else
        3740               0 :     UnsuppressAndInvalidate();
        3741                 : }
        3742                 :
        3743                 : // Post a request to handle an arbitrary callback after reflow has finished.
        3744                 : nsresult
        3745               0 : PresShell::PostReflowCallback(nsIReflowCallback* aCallback)
        3746                 : {
        3747               0 :   void* result = AllocateMisc(sizeof(nsCallbackEventRequest));
        3748               0 :   if (NS_UNLIKELY(!result)) {
        3749               0 :     return NS_ERROR_OUT_OF_MEMORY;
        3750                 :   }
        3751               0 :   nsCallbackEventRequest* request = (nsCallbackEventRequest*)result;
        3752                 :
        3753               0 :   request->callback = aCallback;
        3754               0 :   request->next = nsnull;
        3755                 :
        3756               0 :   if (mLastCallbackEventRequest) {
        3757               0 :     mLastCallbackEventRequest = mLastCallbackEventRequest->next = request;
        3758                 :   } else {
        3759               0 :     mFirstCallbackEventRequest = request;
        3760               0 :     mLastCallbackEventRequest = request;
        3761                 :   }
        3762                 :
        3763               0 :   return NS_OK;
        3764                 : }
        3765                 :
        3766                 : void
        3767               0 : PresShell::CancelReflowCallback(nsIReflowCallback* aCallback)
        3768                 : {
        3769               0 :    nsCallbackEventRequest* before = nsnull;
        3770               0 :    nsCallbackEventRequest* node = mFirstCallbackEventRequest;
        3771               0 :    while(node)
        3772                 :    {
        3773               0 :       nsIReflowCallback* callback = node->callback;
        3774                 :
        3775               0 :       if (callback == aCallback)
        3776                 :       {
        3777               0 :         nsCallbackEventRequest* toFree = node;
        3778               0 :         if (node == mFirstCallbackEventRequest) {
        3779               0 :           node = node->next;
        3780               0 :           mFirstCallbackEventRequest = node;
        3781               0 :           NS_ASSERTION(before == nsnull, "impossible");
        3782                 :         } else {
        3783               0 :           node = node->next;
        3784               0 :           before->next = node;
        3785                 :         }
        3786                 :
        3787               0 :         if (toFree == mLastCallbackEventRequest) {
        3788               0 :           mLastCallbackEventRequest = before;
        3789                 :         }
        3790                 :
        3791               0 :         FreeMisc(sizeof(nsCallbackEventRequest), toFree);
        3792                 :       } else {
        3793               0 :         before = node;
        3794               0 :         node = node->next;
        3795                 :       }
        3796                 :    }
        3797               0 : }
        3798                 :
        3799                 : void
        3800               0 : PresShell::CancelPostedReflowCallbacks()
        3801                 : {
        3802               0 :   while (mFirstCallbackEventRequest) {
        3803               0 :     nsCallbackEventRequest* node = mFirstCallbackEventRequest;
        3804               0 :     mFirstCallbackEventRequest = node->next;
        3805               0 :     if (!mFirstCallbackEventRequest) {
        3806               0 :       mLastCallbackEventRequest = nsnull;
        3807                 :     }
        3808               0 :     nsIReflowCallback* callback = node->callback;
        3809               0 :     FreeMisc(sizeof(nsCallbackEventRequest), node);
        3810               0 :     if (callback) {
        3811               0 :       callback->ReflowCallbackCanceled();
        3812                 :     }
        3813                 :   }
        3814               0 : }
        3815                 :
        3816                 : void
        3817               0 : PresShell::HandlePostedReflowCallbacks(bool aInterruptible)
        3818                 : {
        3819               0 :    bool shouldFlush = false;
        3820                 :
        3821               0 :    while (mFirstCallbackEventRequest) {
        3822               0 :      nsCallbackEventRequest* node = mFirstCallbackEventRequest;
        3823               0 :      mFirstCallbackEventRequest = node->next;
        3824               0 :      if (!mFirstCallbackEventRequest) {
        3825               0 :        mLastCallbackEventRequest = nsnull;
        3826                 :      }
        3827               0 :      nsIReflowCallback* callback = node->callback;
        3828               0 :      FreeMisc(sizeof(nsCallbackEventRequest), node);
        3829               0 :      if (callback) {
        3830               0 :        if (callback->ReflowFinished()) {
        3831               0 :          shouldFlush = true;
        3832                 :        }
        3833                 :      }
        3834                 :    }
        3835                 :
        3836                 :    mozFlushType flushType =
        3837               0 :      aInterruptible ? Flush_InterruptibleLayout : Flush_Layout;
        3838               0 :    if (shouldFlush)
        3839               0 :      FlushPendingNotifications(flushType);
        3840               0 : }
        3841                 :
        3842                 : bool
        3843               0 : PresShell::IsSafeToFlush() const
        3844                 : {
        3845                 :   // Not safe if we are reflowing or in the middle of frame construction
        3846               0 :   bool isSafeToFlush = !mIsReflowing &&
        3847               0 :                          !mChangeNestCount;
        3848                 :
        3849               0 :   if (isSafeToFlush) {
        3850                 :     // Not safe if we are painting
        3851               0 :     nsIViewManager* viewManager = GetViewManager();
        3852               0 :     if (viewManager) {
        3853               0 :       bool isPainting = false;
        3854               0 :       viewManager->IsPainting(isPainting);
        3855               0 :       if (isPainting) {
        3856               0 :         isSafeToFlush = false;
        3857                 :       }
        3858                 :     }
        3859                 :   }
        3860                 :
        3861               0 :   return isSafeToFlush;
        3862                 : }
        3863                 :
        3864                 :
        3865                 : void
        3866               0 : PresShell::FlushPendingNotifications(mozFlushType aType)
        3867                 : {
        3868                 :   /**
        3869                 :    * VERY IMPORTANT: If you add some sort of new flushing to this
        3870                 :    * method, make sure to add the relevant SetNeedLayoutFlush or
        3871                 :    * SetNeedStyleFlush calls on the document.
        3872                 :    */
        3873                 :
        3874                 : #ifdef NS_FUNCTION_TIMER
        3875                 :   NS_TIME_FUNCTION_DECLARE_DOCURL;
        3876                 :   static const char *flushTypeNames[] = {
        3877                 :     "Flush_Content",
        3878                 :     "Flush_ContentAndNotify",
        3879                 :     "Flush_Styles",
        3880                 :     "Flush_InterruptibleLayout",
        3881                 :     "Flush_Layout",
        3882                 :     "Flush_Display"
        3883                 :   };
        3884                 :   NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, type: %s)", MOZ_FUNCTION_NAME,
        3885                 :                            __LINE__, docURL__.get(), flushTypeNames[aType - 1]);
        3886                 : #endif
        3887               0 :   SAMPLE_LABEL("layout", "FlushPendingNotifications");
        3888                 :
        3889                 : #ifdef ACCESSIBILITY
        3890                 : #ifdef DEBUG
        3891               0 :   nsAccessibilityService* accService = GetAccService();
        3892               0 :   if (accService) {
        3893               0 :     NS_ASSERTION(!accService->IsProcessingRefreshDriverNotification(),
        3894                 :                  "Flush during accessible tree update!");
        3895                 :   }
        3896                 : #endif
        3897                 : #endif
        3898                 :
        3899               0 :   NS_ASSERTION(aType >= Flush_Frames, "Why did we get called?");
        3900                 :
        3901               0 :   bool isSafeToFlush = IsSafeToFlush();
        3902                 :
        3903                 :   // If layout could possibly trigger scripts, then it's only safe to flush if
        3904                 :   // it's safe to run script.
        3905                 :   bool hasHadScriptObject;
        3906               0 :   if (mDocument->GetScriptHandlingObject(hasHadScriptObject) ||
        3907                 :       hasHadScriptObject) {
        3908               0 :     isSafeToFlush = isSafeToFlush && nsContentUtils::IsSafeToRunScript();
        3909                 :   }
        3910                 :
        3911               0 :   NS_ASSERTION(!isSafeToFlush || mViewManager, "Must have view manager");
        3912                 :   // Make sure the view manager stays alive.
        3913               0 :   nsCOMPtr<nsIViewManager> viewManagerDeathGrip = mViewManager;
        3914               0 :   if (isSafeToFlush && mViewManager) {
        3915                 :     // Processing pending notifications can kill us, and some callers only
        3916                 :     // hold weak refs when calling FlushPendingNotifications().  :(
        3917               0 :     nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
        3918                 :
        3919               0 :     if (mResizeEvent.IsPending()) {
        3920               0 :       FireResizeEvent();
        3921               0 :       if (mIsDestroying) {
        3922                 :         return;
        3923                 :       }
        3924                 :     }
        3925                 :
        3926                 :     // We need to make sure external resource documents are flushed too (for
        3927                 :     // example, svg filters that reference a filter in an external document
        3928                 :     // need the frames in the external document to be constructed for the
        3929                 :     // filter to work). We only need external resources to be flushed when the
        3930                 :     // main document is flushing >= Flush_Frames, so we flush external
        3931                 :     // resources here instead of nsDocument::FlushPendingNotifications.
        3932               0 :     mDocument->FlushExternalResources(aType);
        3933                 :
        3934                 :     // Force flushing of any pending content notifications that might have
        3935                 :     // queued up while our event was pending.  That will ensure that we don't
        3936                 :     // construct frames for content right now that's still waiting to be
        3937                 :     // notified on,
        3938               0 :     mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
        3939                 :
        3940                 :     // Process pending restyles, since any flush of the presshell wants
        3941                 :     // up-to-date style data.
        3942               0 :     if (!mIsDestroying) {
        3943               0 :       mViewManager->FlushDelayedResize(false);
        3944               0 :       mPresContext->FlushPendingMediaFeatureValuesChanged();
        3945                 :
        3946                 :       // Flush any pending update of the user font set, since that could
        3947                 :       // cause style changes (for updating ex/ch units, and to cause a
        3948                 :       // reflow).
        3949               0 :       mPresContext->FlushUserFontSet();
        3950                 :
        3951                 :       // Flush any requested SMIL samples.
        3952               0 :       if (mDocument->HasAnimationController()) {
        3953               0 :         mDocument->GetAnimationController()->FlushResampleRequests();
        3954                 :       }
        3955                 :
        3956                 :       // The FlushResampleRequests() above flushed style changes.
        3957               0 :       if (!mIsDestroying) {
        3958               0 :         nsAutoScriptBlocker scriptBlocker;
        3959               0 :         mFrameConstructor->CreateNeededFrames();
        3960               0 :         mFrameConstructor->ProcessPendingRestyles();
        3961                 :       }
        3962                 :     }
        3963                 :
        3964                 :     // Dispatch any 'animationstart' events those (or earlier) restyles
        3965                 :     // queued up.
        3966               0 :     if (!mIsDestroying) {
        3967               0 :       mPresContext->AnimationManager()->DispatchEvents();
        3968                 :     }
        3969                 :
        3970                 :     // Process whatever XBL constructors those restyles queued up.  This
        3971                 :     // ensures that onload doesn't fire too early and that we won't do extra
        3972                 :     // reflows after those constructors run.
        3973               0 :     if (!mIsDestroying) {
        3974               0 :       mDocument->BindingManager()->ProcessAttachedQueue();
        3975                 :     }
        3976                 :
        3977                 :     // Now those constructors or events might have posted restyle
        3978                 :     // events.  At the same time, we still need up-to-date style data.
        3979                 :     // In particular, reflow depends on style being completely up to
        3980                 :     // date.  If it's not, then style context reparenting, which can
        3981                 :     // happen during reflow, might suddenly pick up the new rules and
        3982                 :     // we'll end up with frames whose style doesn't match the frame
        3983                 :     // type.
        3984               0 :     if (!mIsDestroying) {
        3985               0 :       nsAutoScriptBlocker scriptBlocker;
        3986               0 :       mFrameConstructor->CreateNeededFrames();
        3987               0 :       mFrameConstructor->ProcessPendingRestyles();
        3988                 :     }
        3989                 :
        3990                 :
        3991                 :     // There might be more pending constructors now, but we're not going to
        3992                 :     // worry about them.  They can't be triggered during reflow, so we should
        3993                 :     // be good.
        3994                 :
        3995               0 :     if (aType >= (mSuppressInterruptibleReflows ? Flush_Layout : Flush_InterruptibleLayout) &&
        3996               0 :         !mIsDestroying) {
        3997               0 :       mFrameConstructor->RecalcQuotesAndCounters();
        3998               0 :       mViewManager->FlushDelayedResize(true);
        3999               0 :       if (ProcessReflowCommands(aType < Flush_Layout) && mContentToScrollTo) {
        4000                 :         // We didn't get interrupted.  Go ahead and scroll to our content
        4001                 :         DoScrollContentIntoView(mContentToScrollTo, mContentScrollVPosition,
        4002                 :                                 mContentScrollHPosition,
        4003               0 :                                 mContentToScrollToFlags);
        4004               0 :         mContentToScrollTo = nsnull;
        4005                 :       }
        4006               0 :     } else if (!mIsDestroying && mSuppressInterruptibleReflows &&
        4007                 :                aType == Flush_InterruptibleLayout) {
        4008                 :       // We suppressed this flush, but the document thinks it doesn't
        4009                 :       // need to flush anymore.  Let it know what's really going on.
        4010               0 :       mDocument->SetNeedLayoutFlush();
        4011                 :     }
        4012                 :
        4013               0 :     if (aType >= Flush_Layout) {
        4014                 :       // Flush plugin geometry. Don't flush plugin geometry for
        4015                 :       // interruptible layouts, since WillPaint does an interruptible
        4016                 :       // layout.
        4017               0 :       nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
        4018               0 :       if (rootPresContext) {
        4019               0 :         rootPresContext->UpdatePluginGeometry();
        4020                 :       }
        4021                 :
        4022               0 :       if (!mIsDestroying) {
        4023               0 :         mViewManager->UpdateWidgetGeometry();
        4024                 :       }
        4025                 :     }
        4026                 :   }
        4027                 : }
        4028                 :
        4029                 : void
        4030               0 : PresShell::CharacterDataChanged(nsIDocument *aDocument,
        4031                 :                                 nsIContent*  aContent,
        4032                 :                                 CharacterDataChangeInfo* aInfo)
        4033                 : {
        4034               0 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected CharacterDataChanged");
        4035               0 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
        4036                 :
        4037               0 :   nsAutoCauseReflowNotifier crNotifier(this);
        4038                 :
        4039               0 :   if (mCaret) {
        4040                 :     // Invalidate the caret's current location before we call into the frame
        4041                 :     // constructor. It is important to do this now, and not wait until the
        4042                 :     // resulting reflow, because this call causes continuation frames of the
        4043                 :     // text frame the caret is in to forget what part of the content they
        4044                 :     // refer to, making it hard for them to return the correct continuation
        4045                 :     // frame to the caret.
        4046               0 :     mCaret->InvalidateOutsideCaret();
        4047                 :   }
        4048                 :
        4049                 :   // Call this here so it only happens for real content mutations and
        4050                 :   // not cases when the frame constructor calls its own methods to force
        4051                 :   // frame reconstruction.
        4052               0 :   nsIContent *container = aContent->GetParent();
        4053                 :   PRUint32 selectorFlags =
        4054               0 :     container ? (container->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
        4055               0 :   if (selectorFlags != 0 && !aContent->IsRootOfAnonymousSubtree()) {
        4056               0 :     Element* element = container->AsElement();
        4057               0 :     if (aInfo->mAppend && !aContent->GetNextSibling())
        4058               0 :       mFrameConstructor->RestyleForAppend(element, aContent);
        4059                 :     else
        4060               0 :       mFrameConstructor->RestyleForInsertOrChange(element, aContent);
        4061                 :   }
        4062                 :
        4063               0 :   mFrameConstructor->CharacterDataChanged(aContent, aInfo);
        4064               0 :   VERIFY_STYLE_TREE;
        4065               0 : }
        4066                 :
        4067                 : void
        4068               0 : PresShell::ContentStateChanged(nsIDocument* aDocument,
        4069                 :                                nsIContent* aContent,
        4070                 :                                nsEventStates aStateMask)
        4071                 : {
        4072               0 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentStateChanged");
        4073               0 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
        4074                 :
        4075               0 :   if (mDidInitialReflow) {
        4076               0 :     nsAutoCauseReflowNotifier crNotifier(this);
        4077               0 :     mFrameConstructor->ContentStateChanged(aContent, aStateMask);
        4078               0 :     VERIFY_STYLE_TREE;
        4079                 :   }
        4080               0 : }
        4081                 :
        4082                 : void
        4083               0 : PresShell::DocumentStatesChanged(nsIDocument* aDocument,
        4084                 :                                  nsEventStates aStateMask)
        4085                 : {
        4086               0 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected DocumentStatesChanged");
        4087               0 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
        4088                 :
        4089               0 :   if (mDidInitialReflow &&
        4090                 :       mStyleSet->HasDocumentStateDependentStyle(mPresContext,
        4091               0 :                                                 mDocument->GetRootElement(),
        4092               0 :                                                 aStateMask)) {
        4093                 :     mFrameConstructor->PostRestyleEvent(mDocument->GetRootElement(),
        4094               0 :                                         eRestyle_Subtree, NS_STYLE_HINT_NONE);
        4095               0 :     VERIFY_STYLE_TREE;
        4096                 :   }
        4097                 :
        4098               0 :   if (aStateMask.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
        4099               0 :     nsIFrame* root = mFrameConstructor->GetRootFrame();
        4100               0 :     if (root) {
        4101               0 :       root->InvalidateFrameSubtree();
        4102                 :     }
        4103                 :   }
        4104               0 : }
        4105                 :
        4106                 : void
        4107               0 : PresShell::AttributeWillChange(nsIDocument* aDocument,
        4108                 :                                Element*     aElement,
        4109                 :                                PRInt32      aNameSpaceID,
        4110                 :                                nsIAtom*     aAttribute,
        4111                 :                                PRInt32      aModType)
        4112                 : {
        4113               0 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected AttributeWillChange");
        4114               0 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
        4115                 :
        4116                 :   // XXXwaterson it might be more elegant to wait until after the
        4117                 :   // initial reflow to begin observing the document. That would
        4118                 :   // squelch any other inappropriate notifications as well.
        4119               0 :   if (mDidInitialReflow) {
        4120               0 :     nsAutoCauseReflowNotifier crNotifier(this);
        4121                 :     mFrameConstructor->AttributeWillChange(aElement, aNameSpaceID,
        4122               0 :                                            aAttribute, aModType);
        4123               0 :     VERIFY_STYLE_TREE;
        4124                 :   }
        4125               0 : }
        4126                 :
        4127                 : void
        4128               0 : PresShell::AttributeChanged(nsIDocument* aDocument,
        4129                 :                             Element*     aElement,
        4130                 :                             PRInt32      aNameSpaceID,
        4131                 :                             nsIAtom*     aAttribute,
        4132                 :                             PRInt32      aModType)
        4133                 : {
        4134               0 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected AttributeChanged");
        4135               0 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
        4136                 :
        4137                 :   // XXXwaterson it might be more elegant to wait until after the
        4138                 :   // initial reflow to begin observing the document. That would
        4139                 :   // squelch any other inappropriate notifications as well.
        4140               0 :   if (mDidInitialReflow) {
        4141               0 :     nsAutoCauseReflowNotifier crNotifier(this);
        4142                 :     mFrameConstructor->AttributeChanged(aElement, aNameSpaceID,
        4143               0 :                                         aAttribute, aModType);
        4144               0 :     VERIFY_STYLE_TREE;
        4145                 :   }
        4146               0 : }
        4147                 :
        4148                 : void
        4149               0 : PresShell::ContentAppended(nsIDocument *aDocument,
        4150                 :                            nsIContent* aContainer,
        4151                 :                            nsIContent* aFirstNewContent,
        4152                 :                            PRInt32     aNewIndexInContainer)
        4153                 : {
        4154               0 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentAppended");
        4155               0 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
        4156               0 :   NS_PRECONDITION(aContainer, "must have container");
        4157                 :
        4158               0 :   if (!mDidInitialReflow) {
        4159               0 :     return;
        4160                 :   }
        4161                 :
        4162               0 :   nsAutoCauseReflowNotifier crNotifier(this);
        4163                 :
        4164                 :   // Call this here so it only happens for real content mutations and
        4165                 :   // not cases when the frame constructor calls its own methods to force
        4166                 :   // frame reconstruction.
        4167               0 :   mFrameConstructor->RestyleForAppend(aContainer->AsElement(), aFirstNewContent);
        4168                 :
        4169               0 :   mFrameConstructor->ContentAppended(aContainer, aFirstNewContent, true);
        4170               0 :   VERIFY_STYLE_TREE;
        4171                 : }
        4172                 :
        4173                 : void
        4174               0 : PresShell::ContentInserted(nsIDocument* aDocument,
        4175                 :                            nsIContent*  aContainer,
        4176                 :                            nsIContent*  aChild,
        4177                 :                            PRInt32      aIndexInContainer)
        4178                 : {
        4179               0 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentInserted");
        4180               0 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
        4181                 :
        4182               0 :   if (!mDidInitialReflow) {
        4183               0 :     return;
        4184                 :   }
        4185                 :
        4186               0 :   nsAutoCauseReflowNotifier crNotifier(this);
        4187                 :
        4188                 :   // Call this here so it only happens for real content mutations and
        4189                 :   // not cases when the frame constructor calls its own methods to force
        4190                 :   // frame reconstruction.
        4191               0 :   if (aContainer)
        4192               0 :     mFrameConstructor->RestyleForInsertOrChange(aContainer->AsElement(), aChild);
        4193                 :
        4194               0 :   mFrameConstructor->ContentInserted(aContainer, aChild, nsnull, true);
        4195               0 :   VERIFY_STYLE_TREE;
        4196                 : }
        4197                 :
        4198                 : void
        4199               0 : PresShell::ContentRemoved(nsIDocument *aDocument,
        4200                 :                           nsIContent* aContainer,
        4201                 :                           nsIContent* aChild,
        4202                 :                           PRInt32     aIndexInContainer,
        4203                 :                           nsIContent* aPreviousSibling)
        4204                 : {
        4205               0 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentRemoved");
        4206               0 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
        4207                 :
        4208                 :   // Make sure that the caret doesn't leave a turd where the child used to be.
        4209               0 :   if (mCaret) {
        4210               0 :     mCaret->InvalidateOutsideCaret();
        4211                 :   }
        4212                 :
        4213                 :   // Notify the ESM that the content has been removed, so that
        4214                 :   // it can clean up any state related to the content.
        4215               0 :   mPresContext->EventStateManager()->ContentRemoved(aDocument, aChild);
        4216                 :
        4217               0 :   nsAutoCauseReflowNotifier crNotifier(this);
        4218                 :
        4219                 :   // Call this here so it only happens for real content mutations and
        4220                 :   // not cases when the frame constructor calls its own methods to force
        4221                 :   // frame reconstruction.
        4222                 :   nsIContent* oldNextSibling;
        4223               0 :   if (aContainer) {
        4224               0 :     oldNextSibling = aContainer->GetChildAt(aIndexInContainer);
        4225                 :   } else {
        4226               0 :     oldNextSibling = nsnull;
        4227                 :   }
        4228                 :
        4229               0 :   if (aContainer)
        4230                 :     mFrameConstructor->RestyleForRemove(aContainer->AsElement(), aChild,
        4231               0 :                                         oldNextSibling);
        4232                 :
        4233                 :   bool didReconstruct;
        4234                 :   mFrameConstructor->ContentRemoved(aContainer, aChild, oldNextSibling,
        4235                 :                                     nsCSSFrameConstructor::REMOVE_CONTENT,
        4236               0 :                                     &didReconstruct);
        4237                 :
        4238               0 :   VERIFY_STYLE_TREE;
        4239               0 : }
        4240                 :
        4241                 : nsresult
        4242               0 : PresShell::ReconstructFrames(void)
        4243                 : {
        4244               0 :   NS_PRECONDITION(!mFrameConstructor->GetRootFrame() || mDidInitialReflow,
        4245                 :                   "Must not have root frame before initial reflow");
        4246               0 :   if (!mDidInitialReflow) {
        4247                 :     // Nothing to do here
        4248               0 :     return NS_OK;
        4249                 :   }
        4250                 :
        4251               0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
        4252                 :
        4253                 :   // Have to make sure that the content notifications are flushed before we
        4254                 :   // start messing with the frame model; otherwise we can get content doubling.
        4255               0 :   mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
        4256                 :
        4257               0 :   nsAutoCauseReflowNotifier crNotifier(this);
        4258               0 :   mFrameConstructor->BeginUpdate();
        4259               0 :   nsresult rv = mFrameConstructor->ReconstructDocElementHierarchy();
        4260               0 :   VERIFY_STYLE_TREE;
        4261               0 :   mFrameConstructor->EndUpdate();
        4262                 :
        4263               0 :   return rv;
        4264                 : }
        4265                 :
        4266                 : void
        4267               0 : nsIPresShell::ReconstructStyleDataInternal()
        4268                 : {
        4269               0 :   mStylesHaveChanged = false;
        4270                 :
        4271               0 :   if (mIsDestroying) {
        4272                 :     // We don't want to mess with restyles at this point
        4273               0 :     return;
        4274                 :   }
        4275                 :
        4276               0 :   if (mPresContext) {
        4277               0 :     mPresContext->RebuildUserFontSet();
        4278               0 :     mPresContext->AnimationManager()->KeyframesListIsDirty();
        4279                 :   }
        4280                 :
        4281               0 :   Element* root = mDocument->GetRootElement();
        4282               0 :   if (!mDidInitialReflow) {
        4283                 :     // Nothing to do here, since we have no frames yet
        4284               0 :     return;
        4285                 :   }
        4286                 :
        4287               0 :   if (!root) {
        4288                 :     // No content to restyle
        4289               0 :     return;
        4290                 :   }
        4291                 :
        4292               0 :   mFrameConstructor->PostRestyleEvent(root, eRestyle_Subtree, NS_STYLE_HINT_NONE);
        4293                 : }
        4294                 :
        4295                 : void
        4296               0 : nsIPresShell::ReconstructStyleDataExternal()
        4297                 : {
        4298               0 :   ReconstructStyleDataInternal();
        4299               0 : }
        4300                 :
        4301                 : void
        4302               0 : PresShell::StyleSheetAdded(nsIDocument *aDocument,
        4303                 :                            nsIStyleSheet* aStyleSheet,
        4304                 :                            bool aDocumentSheet)
        4305                 : {
        4306                 :   // We only care when enabled sheets are added
        4307               0 :   NS_PRECONDITION(aStyleSheet, "Must have a style sheet!");
        4308                 :
        4309               0 :   if (aStyleSheet->IsApplicable() && aStyleSheet->HasRules()) {
        4310               0 :     mStylesHaveChanged = true;
        4311                 :   }
        4312               0 : }
        4313                 :
        4314                 : void
        4315               0 : PresShell::StyleSheetRemoved(nsIDocument *aDocument,
        4316                 :                              nsIStyleSheet* aStyleSheet,
        4317                 :                              bool aDocumentSheet)
        4318                 : {
        4319                 :   // We only care when enabled sheets are removed
        4320               0 :   NS_PRECONDITION(aStyleSheet, "Must have a style sheet!");
        4321                 :
        4322               0 :   if (aStyleSheet->IsApplicable() && aStyleSheet->HasRules()) {
        4323               0 :     mStylesHaveChanged = true;
        4324                 :   }
        4325               0 : }
        4326                 :
        4327                 : void
        4328               0 : PresShell::StyleSheetApplicableStateChanged(nsIDocument *aDocument,
        4329                 :                                             nsIStyleSheet* aStyleSheet,
        4330                 :                                             bool aApplicable)
        4331                 : {
        4332               0 :   if (aStyleSheet->HasRules()) {
        4333               0 :     mStylesHaveChanged = true;
        4334                 :   }
        4335               0 : }
        4336                 :
        4337                 : void
        4338               0 : PresShell::StyleRuleChanged(nsIDocument *aDocument,
        4339                 :                             nsIStyleSheet* aStyleSheet,
        4340                 :                             nsIStyleRule* aOldStyleRule,
        4341                 :                             nsIStyleRule* aNewStyleRule)
        4342                 : {
        4343               0 :   mStylesHaveChanged = true;
        4344               0 : }
        4345                 :
        4346                 : void
        4347               0 : PresShell::StyleRuleAdded(nsIDocument *aDocument,
        4348                 :                           nsIStyleSheet* aStyleSheet,
        4349                 :                           nsIStyleRule* aStyleRule)
        4350                 : {
        4351               0 :   mStylesHaveChanged = true;
        4352               0 : }
        4353                 :
        4354                 : void
        4355               0 : PresShell::StyleRuleRemoved(nsIDocument *aDocument,
        4356                 :                             nsIStyleSheet* aStyleSheet,
        4357                 :                             nsIStyleRule* aStyleRule)
        4358                 : {
        4359               0 :   mStylesHaveChanged = true;
        4360               0 : }
        4361                 :
        4362                 : nsIFrame*
        4363               0 : PresShell::GetRealPrimaryFrameFor(nsIContent* aContent) const
        4364                 : {
        4365               0 :   if (aContent->GetDocument() != GetDocument()) {
        4366               0 :     return nsnull;
        4367                 :   }
        4368               0 :   nsIFrame *primaryFrame = aContent->GetPrimaryFrame();
        4369               0 :   if (!primaryFrame)
        4370               0 :     return nsnull;
        4371               0 :   return nsPlaceholderFrame::GetRealFrameFor(primaryFrame);
        4372                 : }
        4373                 :
        4374                 : nsIFrame*
        4375               0 : PresShell::GetPlaceholderFrameFor(nsIFrame* aFrame) const
        4376                 : {
        4377               0 :   return mFrameConstructor->GetPlaceholderFrameFor(aFrame);
        4378                 : }
        4379                 :
        4380                 : nsresult
        4381               0 : PresShell::RenderDocument(const nsRect& aRect, PRUint32 aFlags,
        4382                 :                           nscolor aBackgroundColor,
        4383                 :                           gfxContext* aThebesContext)
        4384                 : {
        4385                 :   NS_TIME_FUNCTION_WITH_DOCURL;
        4386                 :
        4387               0 :   NS_ENSURE_TRUE(!(aFlags & RENDER_IS_UNTRUSTED), NS_ERROR_NOT_IMPLEMENTED);
        4388                 :
        4389               0 :   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
        4390               0 :   if (rootPresContext) {
        4391               0 :     rootPresContext->FlushWillPaintObservers();
        4392               0 :     if (mIsDestroying)
        4393               0 :       return NS_OK;
        4394                 :   }
        4395                 :
        4396               0 :   nsAutoScriptBlocker blockScripts;
        4397                 :
        4398                 :   // Set up the rectangle as the path in aThebesContext
        4399                 :   gfxRect r(0, 0,
        4400               0 :             nsPresContext::AppUnitsToFloatCSSPixels(aRect.width),
        4401               0 :             nsPresContext::AppUnitsToFloatCSSPixels(aRect.height));
        4402               0 :   aThebesContext->NewPath();
        4403                 : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
        4404                 :   aThebesContext->Rectangle(r, true);
        4405                 : #else
        4406               0 :   aThebesContext->Rectangle(r);
        4407                 : #endif
        4408                 :
        4409               0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
        4410               0 :   if (!rootFrame) {
        4411                 :     // Nothing to paint, just fill the rect
        4412               0 :     aThebesContext->SetColor(gfxRGBA(aBackgroundColor));
        4413               0 :     aThebesContext->Fill();
        4414               0 :     return NS_OK;
        4415                 :   }
        4416                 :
        4417               0 :   gfxContextAutoSaveRestore save(aThebesContext);
        4418                 :
        4419               0 :   gfxContext::GraphicsOperator oldOperator = aThebesContext->CurrentOperator();
        4420               0 :   if (oldOperator == gfxContext::OPERATOR_OVER) {
        4421                 :     // Clip to the destination rectangle before we push the group,
        4422                 :     // to limit the size of the temporary surface
        4423               0 :     aThebesContext->Clip();
        4424                 :   }
        4425                 :
        4426                 :   // we want the window to be composited as a single image using
        4427                 :   // whatever operator was set; set OPERATOR_OVER here, which is
        4428                 :   // either already the case, or overrides the operator in a group.
        4429                 :   // the original operator will be present when we PopGroup.
        4430                 :   // we can avoid using a temporary surface if we're using OPERATOR_OVER
        4431                 :   // and our background color has no alpha (so we'll be compositing on top
        4432                 :   // of a fully opaque solid color region)
        4433                 :   bool needsGroup = NS_GET_A(aBackgroundColor) < 0xff ||
        4434               0 :     oldOperator != gfxContext::OPERATOR_OVER;
        4435                 :
        4436               0 :   if (needsGroup) {
        4437                 :     aThebesContext->PushGroup(NS_GET_A(aBackgroundColor) == 0xff ?
        4438                 :                               gfxASurface::CONTENT_COLOR :
        4439               0 :                               gfxASurface::CONTENT_COLOR_ALPHA);
        4440               0 :     aThebesContext->Save();
        4441                 :
        4442               0 :     if (oldOperator != gfxContext::OPERATOR_OVER) {
        4443                 :       // Clip now while we paint to the temporary surface. For
        4444                 :       // non-source-bounded operators (e.g., SOURCE), we need to do clip
        4445                 :       // here after we've pushed the group, so that eventually popping
        4446                 :       // the group and painting it will be able to clear the entire
        4447                 :       // destination surface.
        4448               0 :       aThebesContext->Clip();
        4449               0 :       aThebesContext->SetOperator(gfxContext::OPERATOR_OVER);
        4450                 :     }
        4451                 :   }
        4452                 :
        4453               0 :   aThebesContext->Translate(gfxPoint(-nsPresContext::AppUnitsToFloatCSSPixels(aRect.x),
        4454               0 :                                      -nsPresContext::AppUnitsToFloatCSSPixels(aRect.y)));
        4455                 :
        4456               0 :   nsDeviceContext* devCtx = mPresContext->DeviceContext();
        4457               0 :   gfxFloat scale = gfxFloat(devCtx->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel();
        4458               0 :   aThebesContext->Scale(scale, scale);
        4459                 :
        4460                 :   // Since canvas APIs use floats to set up their matrices, we may have
        4461                 :   // some slight inaccuracy here. Adjust matrix components that are
        4462                 :   // integers up to the accuracy of floats to be those integers.
        4463               0 :   aThebesContext->NudgeCurrentMatrixToIntegers();
        4464                 :
        4465               0 :   AutoSaveRestoreRenderingState _(this);
        4466                 :
        4467               0 :   nsRefPtr<nsRenderingContext> rc = new nsRenderingContext();
        4468               0 :   rc->Init(devCtx, aThebesContext);
        4469                 :
        4470               0 :   bool wouldFlushRetainedLayers = false;
        4471               0 :   PRUint32 flags = nsLayoutUtils::PAINT_IGNORE_SUPPRESSION;
        4472               0 :   if (aThebesContext->CurrentMatrix().HasNonIntegerTranslation()) {
        4473               0 :     flags |= nsLayoutUtils::PAINT_IN_TRANSFORM;
        4474                 :   }
        4475               0 :   if (!(aFlags & RENDER_ASYNC_DECODE_IMAGES)) {
        4476               0 :     flags |= nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES;
        4477                 :   }
        4478               0 :   if (aFlags & RENDER_USE_WIDGET_LAYERS) {
        4479                 :     // We only support using widget layers on display root's with widgets.
        4480               0 :     nsIView* view = rootFrame->GetView();
        4481               0 :     if (view && view->GetWidget() &&
        4482               0 :         nsLayoutUtils::GetDisplayRootFrame(rootFrame) == rootFrame) {
        4483               0 :       flags |= nsLayoutUtils::PAINT_WIDGET_LAYERS;
        4484                 :     }
        4485                 :   }
        4486               0 :   if (!(aFlags & RENDER_CARET)) {
        4487               0 :     wouldFlushRetainedLayers = true;
        4488               0 :     flags |= nsLayoutUtils::PAINT_HIDE_CARET;
        4489                 :   }
        4490               0 :   if (aFlags & RENDER_IGNORE_VIEWPORT_SCROLLING) {
        4491               0 :     wouldFlushRetainedLayers = !IgnoringViewportScrolling();
        4492               0 :     mRenderFlags = ChangeFlag(mRenderFlags, true, STATE_IGNORING_VIEWPORT_SCROLLING);
        4493                 :   }
        4494               0 :   if (aFlags & RENDER_DOCUMENT_RELATIVE) {
        4495                 :     // XXX be smarter about this ... drawWindow might want a rect
        4496                 :     // that's "pretty close" to what our retained layer tree covers.
        4497                 :     // In that case, it wouldn't disturb normal rendering too much,
        4498                 :     // and we should allow it.
        4499               0 :     wouldFlushRetainedLayers = true;
        4500               0 :     flags |= nsLayoutUtils::PAINT_DOCUMENT_RELATIVE;
        4501                 :   }
        4502                 :
        4503                 :   // Don't let drawWindow blow away our retained layer tree
        4504               0 :   if ((flags & nsLayoutUtils::PAINT_WIDGET_LAYERS) && wouldFlushRetainedLayers) {
        4505               0 :     flags &= ~nsLayoutUtils::PAINT_WIDGET_LAYERS;
        4506                 :   }
        4507                 :
        4508               0 :   nsLayoutUtils::PaintFrame(rc, rootFrame, nsRegion(aRect),
        4509               0 :                             aBackgroundColor, flags);
        4510                 :
        4511                 :   // if we had to use a group, paint it to the destination now
        4512               0 :   if (needsGroup) {
        4513               0 :     aThebesContext->Restore();
        4514               0 :     aThebesContext->PopGroupToSource();
        4515               0 :     aThebesContext->Paint();
        4516                 :   }
        4517                 :
        4518               0 :   return NS_OK;
        4519                 : }
        4520                 :
        4521                 : /*
        4522                 :  * Clip the display list aList to a range. Returns the clipped
        4523                 :  * rectangle surrounding the range.
        4524                 :  */
        4525                 : nsRect
        4526               0 : PresShell::ClipListToRange(nsDisplayListBuilder *aBuilder,
        4527                 :                            nsDisplayList* aList,
        4528                 :                            nsRange* aRange)
        4529                 : {
        4530                 :   NS_TIME_FUNCTION_WITH_DOCURL;
        4531                 :
        4532                 :   // iterate though the display items and add up the bounding boxes of each.
        4533                 :   // This will allow the total area of the frames within the range to be
        4534                 :   // determined. To do this, remove an item from the bottom of the list, check
        4535                 :   // whether it should be part of the range, and if so, append it to the top
        4536                 :   // of the temporary list tmpList. If the item is a text frame at the end of
        4537                 :   // the selection range, wrap it in an nsDisplayClip to clip the display to
        4538                 :   // the portion of the text frame that is part of the selection. Then, append
        4539                 :   // the wrapper to the top of the list. Otherwise, just delete the item and
        4540                 :   // don't append it.
        4541               0 :   nsRect surfaceRect;
        4542               0 :   nsDisplayList tmpList;
        4543                 :
        4544                 :   nsDisplayItem* i;
        4545               0 :   while ((i = aList->RemoveBottom())) {
        4546                 :     // itemToInsert indiciates the item that should be inserted into the
        4547                 :     // temporary list. If null, no item should be inserted.
        4548               0 :     nsDisplayItem* itemToInsert = nsnull;
        4549               0 :     nsIFrame* frame = i->GetUnderlyingFrame();
        4550               0 :     if (frame) {
        4551               0 :       nsIContent* content = frame->GetContent();
        4552               0 :       if (content) {
        4553               0 :         bool atStart = (content == aRange->GetStartParent());
        4554               0 :         bool atEnd = (content == aRange->GetEndParent());
        4555               0 :         if ((atStart || atEnd) && frame->GetType() == nsGkAtoms::textFrame) {
        4556                 :           PRInt32 frameStartOffset, frameEndOffset;
        4557               0 :           frame->GetOffsets(frameStartOffset, frameEndOffset);
        4558                 :
        4559                 :           PRInt32 hilightStart =
        4560               0 :             atStart ? NS_MAX(aRange->StartOffset(), frameStartOffset) : frameStartOffset;
        4561                 :           PRInt32 hilightEnd =
        4562               0 :             atEnd ? NS_MIN(aRange->EndOffset(), frameEndOffset) : frameEndOffset;
        4563               0 :           if (hilightStart < hilightEnd) {
        4564                 :             // determine the location of the start and end edges of the range.
        4565               0 :             nsPoint startPoint, endPoint;
        4566               0 :             frame->GetPointFromOffset(hilightStart, &startPoint);
        4567               0 :             frame->GetPointFromOffset(hilightEnd, &endPoint);
        4568                 :
        4569                 :             // the clip rectangle is determined by taking the the start and
        4570                 :             // end points of the range, offset from the reference frame.
        4571                 :             // Because of rtl, the end point may be to the left of the
        4572                 :             // start point, so x is set to the lowest value
        4573               0 :             nsRect textRect(aBuilder->ToReferenceFrame(frame), frame->GetSize());
        4574               0 :             nscoord x = NS_MIN(startPoint.x, endPoint.x);
        4575               0 :             textRect.x += x;
        4576               0 :             textRect.width = NS_MAX(startPoint.x, endPoint.x) - x;
        4577               0 :             surfaceRect.UnionRect(surfaceRect, textRect);
        4578                 :
        4579                 :             // wrap the item in an nsDisplayClip so that it can be clipped to
        4580                 :             // the selection. If the allocation fails, fall through and delete
        4581                 :             // the item below.
        4582                 :             itemToInsert = new (aBuilder)
        4583               0 :                 nsDisplayClip(aBuilder, frame, i, textRect);
        4584                 :           }
        4585                 :         }
        4586                 :         // Don't try to descend into subdocuments.
        4587                 :         // If this ever changes we'd need to add handling for subdocuments with
        4588                 :         // different zoom levels.
        4589               0 :         else if (content->GetCurrentDoc() ==
        4590               0 :                    aRange->GetStartParent()->GetCurrentDoc()) {
        4591                 :           // if the node is within the range, append it to the temporary list
        4592                 :           bool before, after;
        4593                 :           nsresult rv =
        4594               0 :             nsRange::CompareNodeToRange(content, aRange, &before, &after);
        4595               0 :           if (NS_SUCCEEDED(rv) && !before && !after) {
        4596               0 :             itemToInsert = i;
        4597               0 :             surfaceRect.UnionRect(surfaceRect, i->GetBounds(aBuilder));
        4598                 :           }
        4599                 :         }
        4600                 :       }
        4601                 :     }
        4602                 :
        4603                 :     // insert the item into the list if necessary. If the item has a child
        4604                 :     // list, insert that as well
        4605               0 :     nsDisplayList* sublist = i->GetList();
        4606               0 :     if (itemToInsert || sublist) {
        4607               0 :       tmpList.AppendToTop(itemToInsert ? itemToInsert : i);
        4608                 :       // if the item is a list, iterate over it as well
        4609               0 :       if (sublist)
        4610                 :         surfaceRect.UnionRect(surfaceRect,
        4611               0 :           ClipListToRange(aBuilder, sublist, aRange));
        4612                 :     }
        4613                 :     else {
        4614                 :       // otherwise, just delete the item and don't readd it to the list
        4615               0 :       i->~nsDisplayItem();
        4616                 :     }
        4617                 :   }
        4618                 :
        4619                 :   // now add all the items back onto the original list again
        4620               0 :   aList->AppendToTop(&tmpList);
        4621                 :
        4622                 :   return surfaceRect;
        4623                 : }
        4624                 :
        4625                 : #ifdef DEBUG
        4626                 : #include <stdio.h>
        4627                 :
        4628                 : static bool gDumpRangePaintList = false;
        4629                 : #endif
        4630                 :
        4631                 : RangePaintInfo*
        4632               0 : PresShell::CreateRangePaintInfo(nsIDOMRange* aRange,
        4633                 :                                 nsRect& aSurfaceRect,
        4634                 :                                 bool aForPrimarySelection)
        4635                 : {
        4636                 :   NS_TIME_FUNCTION_WITH_DOCURL;
        4637                 :
        4638               0 :   RangePaintInfo* info = nsnull;
        4639                 :
        4640               0 :   nsRange* range = static_cast<nsRange*>(aRange);
        4641                 :
        4642                 :   nsIFrame* ancestorFrame;
        4643               0 :   nsIFrame* rootFrame = GetRootFrame();
        4644                 :
        4645                 :   // If the start or end of the range is the document, just use the root
        4646                 :   // frame, otherwise get the common ancestor of the two endpoints of the
        4647                 :   // range.
        4648               0 :   nsINode* startParent = range->GetStartParent();
        4649               0 :   nsINode* endParent = range->GetEndParent();
        4650               0 :   nsIDocument* doc = startParent->GetCurrentDoc();
        4651               0 :   if (startParent == doc || endParent == doc) {
        4652               0 :     ancestorFrame = rootFrame;
        4653                 :   }
        4654                 :   else {
        4655               0 :     nsINode* ancestor = nsContentUtils::GetCommonAncestor(startParent, endParent);
        4656               0 :     NS_ASSERTION(!ancestor || ancestor->IsNodeOfType(nsINode::eCONTENT),
        4657                 :                  "common ancestor is not content");
        4658               0 :     if (!ancestor || !ancestor->IsNodeOfType(nsINode::eCONTENT))
        4659               0 :       return nsnull;
        4660                 :
        4661               0 :     nsIContent* ancestorContent = static_cast<nsIContent*>(ancestor);
        4662               0 :     ancestorFrame = ancestorContent->GetPrimaryFrame();
        4663                 :
        4664                 :     // use the nearest ancestor frame that includes all continuations as the
        4665                 :     // root for building the display list
        4666               0 :     while (ancestorFrame &&
        4667               0 :            nsLayoutUtils::GetNextContinuationOrSpecialSibling(ancestorFrame))
        4668               0 :       ancestorFrame = ancestorFrame->GetParent();
        4669                 :   }
        4670                 :
        4671               0 :   if (!ancestorFrame)
        4672               0 :     return nsnull;
        4673                 :
        4674               0 :   info = new RangePaintInfo(range, ancestorFrame);
        4675                 :
        4676               0 :   nsRect ancestorRect = ancestorFrame->GetVisualOverflowRect();
        4677                 :
        4678                 :   // get a display list containing the range
        4679               0 :   info->mBuilder.SetIncludeAllOutOfFlows();
        4680               0 :   if (aForPrimarySelection) {
        4681               0 :     info->mBuilder.SetSelectedFramesOnly();
        4682                 :   }
        4683               0 :   info->mBuilder.EnterPresShell(ancestorFrame, ancestorRect);
        4684                 :   ancestorFrame->BuildDisplayListForStackingContext(&info->mBuilder,
        4685               0 :                                                     ancestorRect, &info->mList);
        4686                 :
        4687                 : #ifdef DEBUG
        4688               0 :   if (gDumpRangePaintList) {
        4689               0 :     fprintf(stderr, "CreateRangePaintInfo --- before ClipListToRange:\n");
        4690               0 :     nsFrame::PrintDisplayList(&(info->mBuilder), info->mList);
        4691                 :   }
        4692                 : #endif
        4693                 :
        4694               0 :   nsRect rangeRect = ClipListToRange(&info->mBuilder, &info->mList, range);
        4695                 :
        4696               0 :   info->mBuilder.LeavePresShell(ancestorFrame, ancestorRect);
        4697                 :
        4698                 : #ifdef DEBUG
        4699               0 :   if (gDumpRangePaintList) {
        4700               0 :     fprintf(stderr, "CreateRangePaintInfo --- after ClipListToRange:\n");
        4701               0 :     nsFrame::PrintDisplayList(&(info->mBuilder), info->mList);
        4702                 :   }
        4703                 : #endif
        4704                 :
        4705                 :   // determine the offset of the reference frame for the display list
        4706                 :   // to the root frame. This will allow the coordinates used when painting
        4707                 :   // to all be offset from the same point
        4708               0 :   info->mRootOffset = ancestorFrame->GetOffsetTo(rootFrame);
        4709               0 :   rangeRect.MoveBy(info->mRootOffset);
        4710               0 :   aSurfaceRect.UnionRect(aSurfaceRect, rangeRect);
        4711                 :
        4712               0 :   return info;
        4713                 : }
        4714                 :
        4715                 : already_AddRefed<gfxASurface>
        4716               0 : PresShell::PaintRangePaintInfo(nsTArray<nsAutoPtr<RangePaintInfo> >* aItems,
        4717                 :                                nsISelection* aSelection,
        4718                 :                                nsIntRegion* aRegion,
        4719                 :                                nsRect aArea,
        4720                 :                                nsIntPoint& aPoint,
        4721                 :                                nsIntRect* aScreenRect)
        4722                 : {
        4723                 :   NS_TIME_FUNCTION_WITH_DOCURL;
        4724                 :
        4725               0 :   nsPresContext* pc = GetPresContext();
        4726               0 :   if (!pc || aArea.width == 0 || aArea.height == 0)
        4727               0 :     return nsnull;
        4728                 :
        4729               0 :   nsDeviceContext* deviceContext = pc->DeviceContext();
        4730                 :
        4731                 :   // use the rectangle to create the surface
        4732               0 :   nsIntRect pixelArea = aArea.ToOutsidePixels(pc->AppUnitsPerDevPixel());
        4733                 :
        4734                 :   // if the area of the image is larger than the maximum area, scale it down
        4735               0 :   float scale = 0.0;
        4736                 :   nsIntRect rootScreenRect =
        4737               0 :     GetRootFrame()->GetScreenRectInAppUnits().ToNearestPixels(
        4738               0 :       pc->AppUnitsPerDevPixel());
        4739                 :
        4740                 :   // if the image is larger in one or both directions than half the size of
        4741                 :   // the available screen area, scale the image down to that size.
        4742               0 :   nsRect maxSize;
        4743               0 :   deviceContext->GetClientRect(maxSize);
        4744               0 :   nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width >> 1);
        4745               0 :   nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height >> 1);
        4746               0 :   bool resize = (pixelArea.width > maxWidth || pixelArea.height > maxHeight);
        4747               0 :   if (resize) {
        4748               0 :     scale = 1.0;
        4749                 :     // divide the maximum size by the image size in both directions. Whichever
        4750                 :     // direction produces the smallest result determines how much should be
        4751                 :     // scaled.
        4752               0 :     if (pixelArea.width > maxWidth)
        4753               0 :       scale = NS_MIN(scale, float(maxWidth) / pixelArea.width);
        4754               0 :     if (pixelArea.height > maxHeight)
        4755               0 :       scale = NS_MIN(scale, float(maxHeight) / pixelArea.height);
        4756                 :
        4757               0 :     pixelArea.width = NSToIntFloor(float(pixelArea.width) * scale);
        4758               0 :     pixelArea.height = NSToIntFloor(float(pixelArea.height) * scale);
        4759                 :
        4760                 :     // adjust the screen position based on the rescaled size
        4761               0 :     nscoord left = rootScreenRect.x + pixelArea.x;
        4762               0 :     nscoord top = rootScreenRect.y + pixelArea.y;
        4763               0 :     aScreenRect->x = NSToIntFloor(aPoint.x - float(aPoint.x - left) * scale);
        4764               0 :     aScreenRect->y = NSToIntFloor(aPoint.y - float(aPoint.y - top) * scale);
        4765                 :   }
        4766                 :   else {
        4767                 :     // move aScreenRect to the position of the surface in screen coordinates
        4768               0 :     aScreenRect->MoveTo(rootScreenRect.x + pixelArea.x, rootScreenRect.y + pixelArea.y);
        4769                 :   }
        4770               0 :   aScreenRect->width = pixelArea.width;
        4771               0 :   aScreenRect->height = pixelArea.height;
        4772                 :
        4773                 :   gfxImageSurface* surface =
        4774                 :     new gfxImageSurface(gfxIntSize(pixelArea.width, pixelArea.height),
        4775               0 :                         gfxImageSurface::ImageFormatARGB32);
        4776               0 :   if (surface->CairoStatus()) {
        4777               0 :     delete surface;
        4778               0 :     return nsnull;
        4779                 :   }
        4780                 :
        4781                 :   // clear the image
        4782               0 :   gfxContext context(surface);
        4783               0 :   context.SetOperator(gfxContext::OPERATOR_CLEAR);
        4784               0 :   context.Rectangle(gfxRect(0, 0, pixelArea.width, pixelArea.height));
        4785               0 :   context.Fill();
        4786                 :
        4787               0 :   nsRefPtr<nsRenderingContext> rc = new nsRenderingContext();
        4788               0 :   rc->Init(deviceContext, surface);
        4789                 :
        4790               0 :   if (aRegion) {
        4791                 :     // Convert aRegion from CSS pixels to dev pixels
        4792                 :     nsIntRegion region =
        4793               0 :       aRegion->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel())
        4794               0 :         .ToOutsidePixels(pc->AppUnitsPerDevPixel());
        4795               0 :     rc->SetClip(region);
        4796                 :   }
        4797                 :
        4798               0 :   if (resize)
        4799               0 :     rc->Scale(scale, scale);
        4800                 :
        4801                 :   // translate so that points are relative to the surface area
        4802               0 :   rc->Translate(-aArea.TopLeft());
        4803                 :
        4804                 :   // temporarily hide the selection so that text is drawn normally. If a
        4805                 :   // selection is being rendered, use that, otherwise use the presshell's
        4806                 :   // selection.
        4807               0 :   nsRefPtr<nsFrameSelection> frameSelection;
        4808               0 :   if (aSelection) {
        4809               0 :     nsCOMPtr<nsISelectionPrivate> selpriv = do_QueryInterface(aSelection);
        4810               0 :     selpriv->GetFrameSelection(getter_AddRefs(frameSelection));
        4811                 :   }
        4812                 :   else {
        4813               0 :     frameSelection = FrameSelection();
        4814                 :   }
        4815               0 :   PRInt16 oldDisplaySelection = frameSelection->GetDisplaySelection();
        4816               0 :   frameSelection->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
        4817                 :
        4818                 :   // next, paint each range in the selection
        4819               0 :   PRInt32 count = aItems->Length();
        4820               0 :   for (PRInt32 i = 0; i < count; i++) {
        4821               0 :     RangePaintInfo* rangeInfo = (*aItems)[i];
        4822                 :     // the display lists paint relative to the offset from the reference
        4823                 :     // frame, so translate the rendering context
        4824                 :     nsRenderingContext::AutoPushTranslation
        4825               0 :       translate(rc, rangeInfo->mRootOffset);
        4826                 :
        4827               0 :     aArea.MoveBy(-rangeInfo->mRootOffset.x, -rangeInfo->mRootOffset.y);
        4828               0 :     nsRegion visible(aArea);
        4829               0 :     rangeInfo->mList.ComputeVisibilityForRoot(&rangeInfo->mBuilder, &visible);
        4830               0 :     rangeInfo->mList.PaintRoot(&rangeInfo->mBuilder, rc, nsDisplayList::PAINT_DEFAULT);
        4831               0 :     aArea.MoveBy(rangeInfo->mRootOffset.x, rangeInfo->mRootOffset.y);
        4832                 :   }
        4833                 :
        4834                 :   // restore the old selection display state
        4835               0 :   frameSelection->SetDisplaySelection(oldDisplaySelection);
        4836                 :
        4837               0 :   NS_ADDREF(surface);
        4838               0 :   return surface;
        4839                 : }
        4840                 :
        4841                 : already_AddRefed<gfxASurface>
        4842               0 : PresShell::RenderNode(nsIDOMNode* aNode,
        4843                 :                       nsIntRegion* aRegion,
        4844                 :                       nsIntPoint& aPoint,
        4845                 :                       nsIntRect* aScreenRect)
        4846                 : {
        4847                 :   // area will hold the size of the surface needed to draw the node, measured
        4848                 :   // from the root frame.
        4849               0 :   nsRect area;
        4850               0 :   nsTArray<nsAutoPtr<RangePaintInfo> > rangeItems;
        4851                 :
        4852                 :   // nothing to draw if the node isn't in a document
        4853               0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
        4854               0 :   if (!node->IsInDoc())
        4855               0 :     return nsnull;
        4856                 :
        4857               0 :   nsRefPtr<nsRange> range = new nsRange();
        4858               0 :   if (NS_FAILED(range->SelectNode(aNode)))
        4859               0 :     return nsnull;
        4860                 :
        4861               0 :   RangePaintInfo* info = CreateRangePaintInfo(range, area, false);
        4862               0 :   if (info && !rangeItems.AppendElement(info)) {
        4863               0 :     delete info;
        4864               0 :     return nsnull;
        4865                 :   }
        4866                 :
        4867               0 :   if (aRegion) {
        4868                 :     // combine the area with the supplied region
        4869               0 :     nsIntRect rrectPixels = aRegion->GetBounds();
        4870                 :
        4871               0 :     nsRect rrect = rrectPixels.ToAppUnits(nsPresContext::AppUnitsPerCSSPixel());
        4872               0 :     area.IntersectRect(area, rrect);
        4873                 :
        4874               0 :     nsPresContext* pc = GetPresContext();
        4875               0 :     if (!pc)
        4876               0 :       return nsnull;
        4877                 :
        4878                 :     // move the region so that it is offset from the topleft corner of the surface
        4879               0 :     aRegion->MoveBy(-pc->AppUnitsToDevPixels(area.x),
        4880               0 :                     -pc->AppUnitsToDevPixels(area.y));
        4881                 :   }
        4882                 :
        4883                 :   return PaintRangePaintInfo(&rangeItems, nsnull, aRegion, area, aPoint,
        4884               0 :                              aScreenRect);
        4885                 : }
        4886                 :
        4887                 : already_AddRefed<gfxASurface>
        4888               0 : PresShell::RenderSelection(nsISelection* aSelection,
        4889                 :                            nsIntPoint& aPoint,
        4890                 :                            nsIntRect* aScreenRect)
        4891                 : {
        4892                 :   // area will hold the size of the surface needed to draw the selection,
        4893                 :   // measured from the root frame.
        4894               0 :   nsRect area;
        4895               0 :   nsTArray<nsAutoPtr<RangePaintInfo> > rangeItems;
        4896                 :
        4897                 :   // iterate over each range and collect them into the rangeItems array.
        4898                 :   // This is done so that the size of selection can be determined so as
        4899                 :   // to allocate a surface area
        4900                 :   PRInt32 numRanges;
        4901               0 :   aSelection->GetRangeCount(&numRanges);
        4902               0 :   NS_ASSERTION(numRanges > 0, "RenderSelection called with no selection");
        4903                 :
        4904               0 :   for (PRInt32 r = 0; r < numRanges; r++)
        4905                 :   {
        4906               0 :     nsCOMPtr<nsIDOMRange> range;
        4907               0 :     aSelection->GetRangeAt(r, getter_AddRefs(range));
        4908                 :
        4909               0 :     RangePaintInfo* info = CreateRangePaintInfo(range, area, true);
        4910               0 :     if (info && !rangeItems.AppendElement(info)) {
        4911               0 :       delete info;
        4912               0 :       return nsnull;
        4913                 :     }
        4914                 :   }
        4915                 :
        4916                 :   return PaintRangePaintInfo(&rangeItems, aSelection, nsnull, area, aPoint,
        4917               0 :                              aScreenRect);
        4918                 : }
        4919                 :
        4920                 : nsresult
        4921               0 : PresShell::AddPrintPreviewBackgroundItem(nsDisplayListBuilder& aBuilder,
        4922                 :                                          nsDisplayList&        aList,
        4923                 :                                          nsIFrame*             aFrame,
        4924                 :                                          const nsRect&         aBounds)
        4925                 : {
        4926                 :   return aList.AppendNewToBottom(new (&aBuilder)
        4927               0 :     nsDisplaySolidColor(&aBuilder, aFrame, aBounds, NS_RGB(115, 115, 115)));
        4928                 : }
        4929                 :
        4930                 : static bool
        4931               0 : AddCanvasBackgroundColor(const nsDisplayList& aList, nsIFrame* aCanvasFrame,
        4932                 :                          nscolor aColor)
        4933                 : {
        4934               0 :   for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
        4935               0 :     if (i->GetUnderlyingFrame() == aCanvasFrame &&
        4936               0 :         i->GetType() == nsDisplayItem::TYPE_CANVAS_BACKGROUND) {
        4937               0 :       nsDisplayCanvasBackground* bg = static_cast<nsDisplayCanvasBackground*>(i);
        4938               0 :       bg->SetExtraBackgroundColor(aColor);
        4939               0 :       return true;
        4940                 :     }
        4941               0 :     nsDisplayList* sublist = i->GetList();
        4942               0 :     if (sublist && AddCanvasBackgroundColor(*sublist, aCanvasFrame, aColor))
        4943               0 :       return true;
        4944                 :   }
        4945               0 :   return false;
        4946                 : }
        4947                 :
        4948               0 : nsresult PresShell::AddCanvasBackgroundColorItem(nsDisplayListBuilder& aBuilder,
        4949                 :                                                  nsDisplayList&        aList,
        4950                 :                                                  nsIFrame*             aFrame,
        4951                 :                                                  const nsRect&         aBounds,
        4952                 :                                                  nscolor               aBackstopColor,
        4953                 :                                                  PRUint32              aFlags)
        4954                 : {
        4955               0 :   if (aBounds.IsEmpty()) {
        4956               0 :     return NS_OK;
        4957                 :   }
        4958                 :   // We don't want to add an item for the canvas background color if the frame
        4959                 :   // (sub)tree we are painting doesn't include any canvas frames. There isn't
        4960                 :   // an easy way to check this directly, but if we check if the root of the
        4961                 :   // (sub)tree we are painting is a canvas frame that should cover us in all
        4962                 :   // cases (it will usually be a viewport frame when we have a canvas frame in
        4963                 :   // the (sub)tree).
        4964               0 :   if (!(aFlags & nsIPresShell::FORCE_DRAW) &&
        4965               0 :       !nsCSSRendering::IsCanvasFrame(aFrame)) {
        4966               0 :     return NS_OK;
        4967                 :   }
        4968                 :
        4969               0 :   nscolor bgcolor = NS_ComposeColors(aBackstopColor, mCanvasBackgroundColor);
        4970               0 :   if (NS_GET_A(bgcolor) == 0)
        4971               0 :     return NS_OK;
        4972                 :
        4973                 :   // To make layers work better, we want to avoid having a big non-scrolled
        4974                 :   // color background behind a scrolled transparent background. Instead,
        4975                 :   // we'll try to move the color background into the scrolled content
        4976                 :   // by making nsDisplayCanvasBackground paint it.
        4977               0 :   if (!aFrame->GetParent()) {
        4978                 :     nsIScrollableFrame* sf =
        4979               0 :       aFrame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
        4980               0 :     if (sf) {
        4981               0 :       nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame());
        4982               0 :       if (canvasFrame && canvasFrame->IsVisibleForPainting(&aBuilder)) {
        4983               0 :         if (AddCanvasBackgroundColor(aList, canvasFrame, bgcolor))
        4984               0 :           return NS_OK;
        4985                 :       }
        4986                 :     }
        4987                 :   }
        4988                 :
        4989                 :   return aList.AppendNewToBottom(
        4990               0 :       new (&aBuilder) nsDisplaySolidColor(&aBuilder, aFrame, aBounds, bgcolor));
        4991                 : }
        4992                 :
        4993               0 : static bool IsTransparentContainerElement(nsPresContext* aPresContext)
        4994                 : {
        4995               0 :   nsCOMPtr<nsISupports> container = aPresContext->GetContainerInternal();
        4996               0 :   nsCOMPtr<nsIDocShellTreeItem> docShellItem = do_QueryInterface(container);
        4997               0 :   nsCOMPtr<nsPIDOMWindow> pwin(do_GetInterface(docShellItem));
        4998               0 :   if (!pwin)
        4999               0 :     return false;
        5000                 :   nsCOMPtr<nsIContent> containerElement =
        5001               0 :     do_QueryInterface(pwin->GetFrameElementInternal());
        5002                 :   return containerElement &&
        5003               0 :          containerElement->HasAttr(kNameSpaceID_None, nsGkAtoms::transparent);
        5004                 : }
        5005                 :
        5006               0 : nscolor PresShell::GetDefaultBackgroundColorToDraw()
        5007                 : {
        5008               0 :   if (!mPresContext || !mPresContext->GetBackgroundColorDraw()) {
        5009               0 :     return NS_RGB(255,255,255);
        5010                 :   }
        5011               0 :   return mPresContext->DefaultBackgroundColor();
        5012                 : }
        5013                 :
        5014               0 : void PresShell::UpdateCanvasBackground()
        5015                 : {
        5016                 :   // If we have a frame tree and it has style information that
        5017                 :   // specifies the background color of the canvas, update our local
        5018                 :   // cache of that color.
        5019               0 :   nsIFrame* rootStyleFrame = FrameConstructor()->GetRootElementStyleFrame();
        5020               0 :   if (rootStyleFrame) {
        5021                 :     nsStyleContext* bgStyle =
        5022               0 :       nsCSSRendering::FindRootFrameBackground(rootStyleFrame);
        5023                 :     // XXX We should really be passing the canvasframe, not the root element
        5024                 :     // style frame but we don't have access to the canvasframe here. It isn't
        5025                 :     // a problem because only a few frames can return something other than true
        5026                 :     // and none of them would be a canvas frame or root element style frame.
        5027                 :     mCanvasBackgroundColor =
        5028                 :       nsCSSRendering::DetermineBackgroundColor(mPresContext, bgStyle,
        5029               0 :                                                rootStyleFrame);
        5030               0 :     if (GetPresContext()->IsRootContentDocument() &&
        5031               0 :         !IsTransparentContainerElement(mPresContext)) {
        5032                 :       mCanvasBackgroundColor =
        5033               0 :         NS_ComposeColors(GetDefaultBackgroundColorToDraw(), mCanvasBackgroundColor);
        5034                 :     }
        5035                 :   }
        5036                 :
        5037                 :   // If the root element of the document (ie html) has style 'display: none'
        5038                 :   // then the document's background color does not get drawn; cache the
        5039                 :   // color we actually draw.
        5040               0 :   if (!FrameConstructor()->GetRootElementFrame()) {
        5041               0 :     mCanvasBackgroundColor = GetDefaultBackgroundColorToDraw();
        5042                 :   }
        5043               0 :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
        5044               0 :     if (TabChild* tabChild = GetTabChildFrom(this)) {
        5045               0 :       tabChild->SetBackgroundColor(mCanvasBackgroundColor);
        5046                 :     }
        5047                 :   }
        5048               0 : }
        5049                 :
        5050               0 : nscolor PresShell::ComputeBackstopColor(nsIView* aDisplayRoot)
        5051                 : {
        5052               0 :   nsIWidget* widget = aDisplayRoot->GetWidget();
        5053               0 :   if (widget && widget->GetTransparencyMode() != eTransparencyOpaque) {
        5054                 :     // Within a transparent widget, so the backstop color must be
        5055                 :     // totally transparent.
        5056               0 :     return NS_RGBA(0,0,0,0);
        5057                 :   }
        5058                 :   // Within an opaque widget (or no widget at all), so the backstop
        5059                 :   // color must be totally opaque. The user's default background
        5060                 :   // as reported by the prescontext is guaranteed to be opaque.
        5061               0 :   return GetDefaultBackgroundColorToDraw();
        5062                 : }
        5063                 :
        5064                 : struct PaintParams {
        5065                 :   nscolor mBackgroundColor;
        5066                 : };
        5067                 :
        5068               0 : LayerManager* PresShell::GetLayerManager()
        5069                 : {
        5070               0 :   NS_ASSERTION(mViewManager, "Should have view manager");
        5071                 :
        5072               0 :   nsIView* rootView = mViewManager->GetRootView();
        5073               0 :   if (rootView) {
        5074               0 :     if (nsIWidget* widget = rootView->GetWidget()) {
        5075               0 :       return widget->GetLayerManager();
        5076                 :     }
        5077                 :   }
        5078               0 :   return nsnull;
        5079                 : }
        5080                 :
        5081               0 : void PresShell::SetIgnoreViewportScrolling(bool aIgnore)
        5082                 : {
        5083               0 :   if (IgnoringViewportScrolling() == aIgnore) {
        5084               0 :     return;
        5085                 :   }
        5086               0 :   RenderingState state(this);
        5087                 :   state.mRenderFlags = ChangeFlag(state.mRenderFlags, aIgnore,
        5088               0 :                                   STATE_IGNORING_VIEWPORT_SCROLLING);
        5089               0 :   SetRenderingState(state);
        5090                 : }
        5091                 :
        5092               0 : void PresShell::SetDisplayPort(const nsRect& aDisplayPort)
        5093                 : {
        5094               0 :   NS_ABORT_IF_FALSE(false, "SetDisplayPort is deprecated");
        5095               0 : }
        5096                 :
        5097               0 : nsresult PresShell::SetResolution(float aXResolution, float aYResolution)
        5098                 : {
        5099               0 :   if (!(aXResolution > 0.0 && aYResolution > 0.0)) {
        5100               0 :     return NS_ERROR_ILLEGAL_VALUE;
        5101                 :   }
        5102               0 :   if (aXResolution == mXResolution && aYResolution == mYResolution) {
        5103               0 :     return NS_OK;
        5104                 :   }
        5105               0 :   RenderingState state(this);
        5106               0 :   state.mXResolution = aXResolution;
        5107               0 :   state.mYResolution = aYResolution;
        5108               0 :   SetRenderingState(state);
        5109               0 :   return NS_OK;
        5110                 :  }
        5111                 :
        5112               0 : void PresShell::SetRenderingState(const RenderingState& aState)
        5113                 : {
        5114               0 :   if (mRenderFlags != aState.mRenderFlags) {
        5115                 :     // Rendering state changed in a way that forces us to flush any
        5116                 :     // retained layers we might already have.
        5117               0 :     LayerManager* manager = GetLayerManager();
        5118               0 :     if (manager) {
        5119               0 :       FrameLayerBuilder::InvalidateAllLayers(manager);
        5120                 :     }
        5121                 :   }
        5122                 :
        5123               0 :   mRenderFlags = aState.mRenderFlags;
        5124               0 :   mXResolution = aState.mXResolution;
        5125               0 :   mYResolution = aState.mYResolution;
        5126               0 : }
        5127                 :
        5128               0 : void PresShell::SynthesizeMouseMove(bool aFromScroll)
        5129                 : {
        5130               0 :   if (!sSynthMouseMove)
        5131               0 :     return;
        5132                 :
        5133               0 :   if (mPaintingSuppressed || !mIsActive || !mPresContext) {
        5134               0 :     return;
        5135                 :   }
        5136                 :
        5137               0 :   if (!mPresContext->IsRoot()) {
        5138               0 :     nsIPresShell* rootPresShell = GetRootPresShell();
        5139               0 :     if (rootPresShell) {
        5140               0 :       rootPresShell->SynthesizeMouseMove(aFromScroll);
        5141                 :     }
        5142               0 :     return;
        5143                 :   }
        5144                 :
        5145               0 :   if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE))
        5146               0 :     return;
        5147                 :
        5148               0 :   if (!mSynthMouseMoveEvent.IsPending()) {
        5149                 :     nsRefPtr<nsSynthMouseMoveEvent> ev =
        5150               0 :         new nsSynthMouseMoveEvent(this, aFromScroll);
        5151                 :
        5152               0 :     if (!GetPresContext()->RefreshDriver()->AddRefreshObserver(ev,
        5153               0 :                                                                Flush_Display)) {
        5154               0 :       NS_WARNING("failed to dispatch nsSynthMouseMoveEvent");
        5155                 :       return;
        5156                 :     }
        5157                 :
        5158               0 :     mSynthMouseMoveEvent = ev;
        5159                 :   }
        5160                 : }
        5161                 :
        5162                 : /**
        5163                 :  * Find the first floating view with a widget in a postorder traversal of the
        5164                 :  * view tree that contains the point. Thus more deeply nested floating views
        5165                 :  * are preferred over their ancestors, and floating views earlier in the
        5166                 :  * view hierarchy (i.e., added later) are preferred over their siblings.
        5167                 :  * This is adequate for finding the "topmost" floating view under a point,
        5168                 :  * given that floating views don't supporting having a specific z-index.
        5169                 :  *
        5170                 :  * We cannot exit early when aPt is outside the view bounds, because floating
        5171                 :  * views aren't necessarily included in their parent's bounds, so this could
        5172                 :  * traverse the entire view hierarchy --- use carefully.
        5173                 :  */
        5174               0 : static nsIView* FindFloatingViewContaining(nsIView* aView, nsPoint aPt)
        5175                 : {
        5176               0 :   if (aView->GetVisibility() == nsViewVisibility_kHide)
        5177                 :     // No need to look into descendants.
        5178               0 :     return nsnull;
        5179                 :
        5180               0 :   nsIFrame* frame = aView->GetFrame();
        5181               0 :   if (frame) {
        5182               0 :     if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
        5183               0 :         !frame->PresContext()->PresShell()->IsActive()) {
        5184               0 :       return nsnull;
        5185                 :     }
        5186                 :   }
        5187                 :
        5188               0 :   for (nsIView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
        5189               0 :     nsIView* r = FindFloatingViewContaining(v, v->ConvertFromParentCoords(aPt));
        5190               0 :     if (r)
        5191               0 :       return r;
        5192                 :   }
        5193                 :
        5194               0 :   if (aView->GetFloating() && aView->HasWidget() &&
        5195               0 :       aView->GetDimensions().Contains(aPt))
        5196               0 :     return aView;
        5197                 :
        5198               0 :   return nsnull;
        5199                 : }
        5200                 :
        5201                 : /*
        5202                 :  * This finds the first view containing the given point in a postorder
        5203                 :  * traversal of the view tree that contains the point, assuming that the
        5204                 :  * point is not in a floating view.  It assumes that only floating views
        5205                 :  * extend outside the bounds of their parents.
        5206                 :  *
        5207                 :  * This methods should only be called if FindFloatingViewContaining
        5208                 :  * returns null.
        5209                 :  */
        5210               0 : static nsIView* FindViewContaining(nsIView* aView, nsPoint aPt)
        5211                 : {
        5212               0 :   if (!aView->GetDimensions().Contains(aPt) ||
        5213               0 :       aView->GetVisibility() == nsViewVisibility_kHide) {
        5214               0 :     return nsnull;
        5215                 :   }
        5216                 :
        5217               0 :   nsIFrame* frame = aView->GetFrame();
        5218               0 :   if (frame) {
        5219               0 :     if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
        5220               0 :         !frame->PresContext()->PresShell()->IsActive()) {
        5221               0 :       return nsnull;
        5222                 :     }
        5223                 :   }
        5224                 :
        5225               0 :   for (nsIView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
        5226               0 :     nsIView* r = FindViewContaining(v, v->ConvertFromParentCoords(aPt));
        5227               0 :     if (r)
        5228               0 :       return r;
        5229                 :   }
        5230                 :
        5231               0 :   return aView;
        5232                 : }
        5233                 :
        5234                 : void
        5235               0 : PresShell::ProcessSynthMouseMoveEvent(bool aFromScroll)
        5236                 : {
        5237                 :   // If drag session has started, we shouldn't synthesize mousemove event.
        5238               0 :   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
        5239               0 :   if (dragSession) {
        5240               0 :     mSynthMouseMoveEvent.Forget();
        5241                 :     return;
        5242                 :   }
        5243                 :
        5244                 :   // allow new event to be posted while handling this one only if the
        5245                 :   // source of the event is a scroll (to prevent infinite reflow loops)
        5246               0 :   if (aFromScroll) {
        5247               0 :     mSynthMouseMoveEvent.Forget();
        5248                 :   }
        5249                 :
        5250               0 :   nsIView* rootView = mViewManager ? mViewManager->GetRootView() : nsnull;
        5251               0 :   if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) ||
        5252               0 :       !rootView || !rootView->HasWidget() || !mPresContext) {
        5253               0 :     mSynthMouseMoveEvent.Forget();
        5254                 :     return;
        5255                 :   }
        5256                 :
        5257               0 :   NS_ASSERTION(mPresContext->IsRoot(), "Only a root pres shell should be here");
        5258                 :
        5259                 :   // Hold a ref to ourselves so DispatchEvent won't destroy us (since
        5260                 :   // we need to access members after we call DispatchEvent).
        5261               0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
        5262                 :
        5263                 : #ifdef DEBUG_MOUSE_LOCATION
        5264                 :   printf("[ps=%p]synthesizing mouse move to (%d,%d)\n",
        5265                 :          this, mMouseLocation.x, mMouseLocation.y);
        5266                 : #endif
        5267                 :
        5268               0 :   PRInt32 APD = mPresContext->AppUnitsPerDevPixel();
        5269                 :
        5270                 :   // We need a widget to put in the event we are going to dispatch so we look
        5271                 :   // for a view that has a widget and the mouse location is over. We first look
        5272                 :   // for floating views, if there isn't one we use the root view. |view| holds
        5273                 :   // that view.
        5274               0 :   nsIView* view = nsnull;
        5275                 :
        5276                 :   // The appunits per devpixel ratio of |view|.
        5277                 :   PRInt32 viewAPD;
        5278                 :
        5279                 :   // refPoint will be mMouseLocation relative to the widget of |view|, the
        5280                 :   // widget we will put in the event we dispatch, in viewAPD appunits
        5281               0 :   nsPoint refpoint(0, 0);
        5282                 :
        5283                 :   // We always dispatch the event to the pres shell that contains the view that
        5284                 :   // the mouse is over. pointVM is the VM of that pres shell.
        5285               0 :   nsIViewManager *pointVM = nsnull;
        5286                 :
        5287                 :   // This could be a bit slow (traverses entire view hierarchy)
        5288                 :   // but it's OK to do it once per synthetic mouse event
        5289               0 :   view = FindFloatingViewContaining(rootView, mMouseLocation);
        5290               0 :   if (!view) {
        5291               0 :     view = rootView;
        5292               0 :     nsIView *pointView = FindViewContaining(rootView, mMouseLocation);
        5293                 :     // pointView can be null in situations related to mouse capture
        5294               0 :     pointVM = (pointView ? pointView : view)->GetViewManager();
        5295               0 :     refpoint = mMouseLocation + rootView->ViewToWidgetOffset();
        5296               0 :     viewAPD = APD;
        5297                 :   } else {
        5298               0 :     pointVM = view->GetViewManager();
        5299               0 :     nsIFrame* frame = view->GetFrame();
        5300               0 :     NS_ASSERTION(frame, "floating views can't be anonymous");
        5301               0 :     viewAPD = frame->PresContext()->AppUnitsPerDevPixel();
        5302               0 :     refpoint = mMouseLocation.ConvertAppUnits(APD, viewAPD);
        5303               0 :     refpoint -= view->GetOffsetTo(rootView);
        5304               0 :     refpoint += view->ViewToWidgetOffset();
        5305                 :   }
        5306               0 :   NS_ASSERTION(view->GetWidget(), "view should have a widget here");
        5307                 :   nsMouseEvent event(true, NS_MOUSE_MOVE, view->GetWidget(),
        5308               0 :                      nsMouseEvent::eSynthesized);
        5309               0 :   event.refPoint = refpoint.ToNearestPixels(viewAPD);
        5310               0 :   event.time = PR_IntervalNow();
        5311                 :   // XXX set event.isShift, event.isControl, event.isAlt, event.isMeta ?
        5312                 :
        5313               0 :   nsCOMPtr<nsIPresShell> shell = pointVM->GetPresShell();
        5314               0 :   if (shell) {
        5315               0 :     shell->DispatchSynthMouseMove(&event, !aFromScroll);
        5316                 :   }
        5317                 :
        5318               0 :   if (!aFromScroll) {
        5319               0 :     mSynthMouseMoveEvent.Forget();
        5320                 :   }
        5321                 : }
        5322                 :
        5323                 : class nsAutoNotifyDidPaint
        5324                 : {
        5325                 : public:
        5326               0 :   nsAutoNotifyDidPaint(bool aWillSendDidPaint)
        5327               0 :     : mWillSendDidPaint(aWillSendDidPaint)
        5328                 :   {
        5329               0 :   }
        5330               0 :   ~nsAutoNotifyDidPaint()
        5331                 :   {
        5332               0 :     if (!mWillSendDidPaint && nsContentUtils::XPConnect()) {
        5333               0 :       nsContentUtils::XPConnect()->NotifyDidPaint();
        5334                 :     }
        5335               0 :   }
        5336                 :
        5337                 : private:
        5338                 :   bool mWillSendDidPaint;
        5339                 : };
        5340                 :
        5341                 : void
        5342               0 : PresShell::Paint(nsIView*           aViewToPaint,
        5343                 :                  nsIWidget*         aWidgetToPaint,
        5344                 :                  const nsRegion&    aDirtyRegion,
        5345                 :                  const nsIntRegion& aIntDirtyRegion,
        5346                 :                  bool               aWillSendDidPaint)
        5347                 : {
        5348                 : #ifdef NS_FUNCTION_TIMER
        5349                 :   NS_TIME_FUNCTION_DECLARE_DOCURL;
        5350                 :   const nsRect& bounds__ = aDirtyRegion.GetBounds();
        5351                 :   NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, dirty rect: (<%f, %f>, <%f, %f>)",
        5352                 :                            MOZ_FUNCTION_NAME, __LINE__, docURL__.get(),
        5353                 :                            NSCoordToFloat(bounds__.x),
        5354                 :                            NSCoordToFloat(bounds__.y),
        5355                 :                            NSCoordToFloat(bounds__.XMost()),
        5356                 :                            NSCoordToFloat(bounds__.YMost()));
        5357                 : #endif
        5358                 :
        5359               0 :   SAMPLE_LABEL("Paint", "PresShell::Paint");
        5360               0 :   NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
        5361               0 :   NS_ASSERTION(aViewToPaint, "null view");
        5362               0 :   NS_ASSERTION(aWidgetToPaint, "Can't paint without a widget");
        5363                 :
        5364               0 :   nsAutoNotifyDidPaint notifyDidPaint(aWillSendDidPaint);
        5365                 :
        5366               0 :   nsPresContext* presContext = GetPresContext();
        5367               0 :   AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
        5368                 :
        5369               0 :   nsIFrame* frame = aViewToPaint->GetFrame();
        5370                 :
        5371                 :   bool isRetainingManager;
        5372                 :   LayerManager* layerManager =
        5373               0 :     aWidgetToPaint->GetLayerManager(&isRetainingManager);
        5374               0 :   NS_ASSERTION(layerManager, "Must be in paint event");
        5375               0 :   layerManager->BeginTransaction();
        5376                 :
        5377               0 :   if (frame && isRetainingManager) {
        5378                 :     // Try to do an empty transaction, if the frame tree does not
        5379                 :     // need to be updated. Do not try to do an empty transaction on
        5380                 :     // a non-retained layer manager (like the BasicLayerManager that
        5381                 :     // draws the window title bar on Mac), because a) it won't work
        5382                 :     // and b) below we don't want to clear NS_FRAME_UPDATE_LAYER_TREE,
        5383                 :     // that will cause us to forget to update the real layer manager!
        5384               0 :     if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE)) {
        5385               0 :       if (layerManager->EndEmptyTransaction()) {
        5386               0 :         frame->UpdatePaintCountForPaintedPresShells();
        5387               0 :         presContext->NotifyDidPaintForSubtree();
        5388                 :         return;
        5389                 :       }
        5390                 :     }
        5391                 :
        5392               0 :     frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE);
        5393                 :   }
        5394               0 :   if (frame) {
        5395               0 :     frame->ClearPresShellsFromLastPaint();
        5396                 :   }
        5397                 :
        5398               0 :   nscolor bgcolor = ComputeBackstopColor(aViewToPaint);
        5399                 :
        5400               0 :   if (frame) {
        5401                 :     // Defer invalidates that are triggered during painting, and discard
        5402                 :     // invalidates of areas that are already being repainted.
        5403                 :     // The layer system can trigger invalidates during painting
        5404                 :     // (see FrameLayerBuilder).
        5405               0 :     frame->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion);
        5406                 :
        5407                 :     // We can paint directly into the widget using its layer manager.
        5408                 :     nsLayoutUtils::PaintFrame(nsnull, frame, aDirtyRegion, bgcolor,
        5409                 :                               nsLayoutUtils::PAINT_WIDGET_LAYERS |
        5410               0 :                               nsLayoutUtils::PAINT_EXISTING_TRANSACTION);
        5411                 :
        5412               0 :     frame->EndDeferringInvalidatesForDisplayRoot();
        5413               0 :     presContext->NotifyDidPaintForSubtree();
        5414                 :     return;
        5415                 :   }
        5416                 :
        5417               0 :   nsRefPtr<ColorLayer> root = layerManager->CreateColorLayer();
        5418               0 :   if (root) {
        5419               0 :     nsPresContext* pc = GetPresContext();
        5420                 :     nsIntRect bounds =
        5421               0 :       pc->GetVisibleArea().ToOutsidePixels(pc->AppUnitsPerDevPixel());
        5422               0 :     bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
        5423               0 :     root->SetColor(bgcolor);
        5424               0 :     root->SetVisibleRegion(bounds);
        5425               0 :     layerManager->SetRoot(root);
        5426                 :   }
        5427               0 :   layerManager->EndTransaction(NULL, NULL);
        5428                 :
        5429               0 :   presContext->NotifyDidPaintForSubtree();
        5430                 : }
        5431                 :
        5432                 : // static
        5433                 : void
        5434               0 : nsIPresShell::SetCapturingContent(nsIContent* aContent, PRUint8 aFlags)
        5435                 : {
        5436               0 :   NS_IF_RELEASE(gCaptureInfo.mContent);
        5437                 :
        5438                 :   // only set capturing content if allowed or the CAPTURE_IGNOREALLOWED flag
        5439                 :   // is used
        5440               0 :   if ((aFlags & CAPTURE_IGNOREALLOWED) || gCaptureInfo.mAllowed) {
        5441               0 :     if (aContent) {
        5442               0 :       NS_ADDREF(gCaptureInfo.mContent = aContent);
        5443                 :     }
        5444               0 :     gCaptureInfo.mRetargetToElement = (aFlags & CAPTURE_RETARGETTOELEMENT) != 0;
        5445               0 :     gCaptureInfo.mPreventDrag = (aFlags & CAPTURE_PREVENTDRAG) != 0;
        5446                 :   }
        5447               0 : }
        5448                 :
        5449                 : nsIFrame*
        5450               0 : PresShell::GetCurrentEventFrame()
        5451                 : {
        5452               0 :   if (NS_UNLIKELY(mIsDestroying)) {
        5453               0 :     return nsnull;
        5454                 :   }
        5455                 :
        5456               0 :   if (!mCurrentEventFrame && mCurrentEventContent) {
        5457                 :     // Make sure the content still has a document reference. If not,
        5458                 :     // then we assume it is no longer in the content tree and the
        5459                 :     // frame shouldn't get an event, nor should we even assume its
        5460                 :     // safe to try and find the frame.
        5461               0 :     if (mCurrentEventContent->GetDocument()) {
        5462               0 :       mCurrentEventFrame = mCurrentEventContent->GetPrimaryFrame();
        5463                 :     }
        5464                 :   }
        5465                 :
        5466               0 :   return mCurrentEventFrame;
        5467                 : }
        5468                 :
        5469                 : nsIFrame*
        5470               0 : PresShell::GetEventTargetFrame()
        5471                 : {
        5472               0 :   return GetCurrentEventFrame();
        5473                 : }
        5474                 :
        5475                 : already_AddRefed<nsIContent>
        5476               0 : PresShell::GetEventTargetContent(nsEvent* aEvent)
        5477                 : {
        5478               0 :   nsIContent* content = nsnull;
        5479                 :
        5480               0 :   if (mCurrentEventContent) {
        5481               0 :     content = mCurrentEventContent;
        5482               0 :     NS_IF_ADDREF(content);
        5483                 :   } else {
        5484               0 :     nsIFrame* currentEventFrame = GetCurrentEventFrame();
        5485               0 :     if (currentEventFrame) {
        5486               0 :       currentEventFrame->GetContentForEvent(aEvent, &content);
        5487                 :     } else {
        5488               0 :       content = nsnull;
        5489                 :     }
        5490                 :   }
        5491               0 :   return content;
        5492                 : }
        5493                 :
        5494                 : void
        5495               0 : PresShell::PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent)
        5496                 : {
        5497               0 :   if (mCurrentEventFrame || mCurrentEventContent) {
        5498               0 :     mCurrentEventFrameStack.InsertElementAt(0, mCurrentEventFrame);
        5499               0 :     mCurrentEventContentStack.InsertObjectAt(mCurrentEventContent, 0);
        5500                 :   }
        5501               0 :   mCurrentEventFrame = aFrame;
        5502               0 :   mCurrentEventContent = aContent;
        5503               0 : }
        5504                 :
        5505                 : void
        5506               0 : PresShell::PopCurrentEventInfo()
        5507                 : {
        5508               0 :   mCurrentEventFrame = nsnull;
        5509               0 :   mCurrentEventContent = nsnull;
        5510                 :
        5511               0 :   if (0 != mCurrentEventFrameStack.Length()) {
        5512               0 :     mCurrentEventFrame = mCurrentEventFrameStack.ElementAt(0);
        5513               0 :     mCurrentEventFrameStack.RemoveElementAt(0);
        5514               0 :     mCurrentEventContent = mCurrentEventContentStack.ObjectAt(0);
        5515               0 :     mCurrentEventContentStack.RemoveObjectAt(0);
        5516                 :   }
        5517               0 : }
        5518                 :
        5519               0 : bool PresShell::InZombieDocument(nsIContent *aContent)
        5520                 : {
        5521                 :   // If a content node points to a null document, or the document is not
        5522                 :   // attached to a window, then it is possibly in a zombie document,
        5523                 :   // about to be replaced by a newly loading document.
        5524                 :   // Such documents cannot handle DOM events.
        5525                 :   // It might actually be in a node not attached to any document,
        5526                 :   // in which case there is not parent presshell to retarget it to.
        5527               0 :   nsIDocument *doc = aContent->GetDocument();
        5528               0 :   return !doc || !doc->GetWindow();
        5529                 : }
        5530                 :
        5531                 : already_AddRefed<nsPIDOMWindow>
        5532               0 : PresShell::GetRootWindow()
        5533                 : {
        5534                 :   nsCOMPtr<nsPIDOMWindow> window =
        5535               0 :     do_QueryInterface(mDocument->GetWindow());
        5536               0 :   if (window) {
        5537               0 :     nsCOMPtr<nsPIDOMWindow> rootWindow = window->GetPrivateRoot();
        5538               0 :     NS_ASSERTION(rootWindow, "nsPIDOMWindow::GetPrivateRoot() returns NULL");
        5539               0 :     return rootWindow.forget();
        5540                 :   }
        5541                 :
        5542                 :   // If we don't have DOM window, we're zombie, we should find the root window
        5543                 :   // with our parent shell.
        5544               0 :   nsCOMPtr<nsIPresShell> parent = GetParentPresShell();
        5545               0 :   NS_ENSURE_TRUE(parent, nsnull);
        5546               0 :   return parent->GetRootWindow();
        5547                 : }
        5548                 :
        5549                 : already_AddRefed<nsIPresShell>
        5550               0 : PresShell::GetParentPresShell()
        5551                 : {
        5552               0 :   NS_ENSURE_TRUE(mPresContext, nsnull);
        5553               0 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
        5554               0 :   if (!container) {
        5555               0 :     container = do_QueryReferent(mForwardingContainer);
        5556                 :   }
        5557                 :
        5558                 :   // Now, find the parent pres shell and send the event there
        5559               0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
        5560                 :   // Might have gone away, or never been around to start with
        5561               0 :   NS_ENSURE_TRUE(treeItem, nsnull);
        5562                 :
        5563               0 :   nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
        5564               0 :   treeItem->GetParent(getter_AddRefs(parentTreeItem));
        5565               0 :   nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentTreeItem);
        5566               0 :   NS_ENSURE_TRUE(parentDocShell && treeItem != parentTreeItem, nsnull);
        5567                 :
        5568               0 :   nsIPresShell* parentPresShell = nsnull;
        5569               0 :   parentDocShell->GetPresShell(&parentPresShell);
        5570               0 :   return parentPresShell;
        5571                 : }
        5572                 :
        5573                 : nsresult
        5574               0 : PresShell::RetargetEventToParent(nsGUIEvent*     aEvent,
        5575                 :                                  nsEventStatus*  aEventStatus)
        5576                 : {
        5577                 :   // Send this events straight up to the parent pres shell.
        5578                 :   // We do this for keystroke events in zombie documents or if either a frame
        5579                 :   // or a root content is not present.
        5580                 :   // That way at least the UI key bindings can work.
        5581                 :
        5582               0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
        5583               0 :   nsCOMPtr<nsIPresShell> parentPresShell = GetParentPresShell();
        5584               0 :   NS_ENSURE_TRUE(parentPresShell, NS_ERROR_FAILURE);
        5585                 :
        5586                 :   // Fake the event as though it's from the parent pres shell's root frame.
        5587               0 :   return parentPresShell->HandleEvent(parentPresShell->GetRootFrame(), aEvent, true, aEventStatus);
        5588                 : }
        5589                 :
        5590                 : void
        5591               0 : PresShell::DisableNonTestMouseEvents(bool aDisable)
        5592                 : {
        5593               0 :   sDisableNonTestMouseEvents = aDisable;
        5594               0 : }
        5595                 :
        5596                 : already_AddRefed<nsPIDOMWindow>
        5597               0 : PresShell::GetFocusedDOMWindowInOurWindow()
        5598                 : {
        5599               0 :   nsCOMPtr<nsPIDOMWindow> rootWindow = GetRootWindow();
        5600               0 :   NS_ENSURE_TRUE(rootWindow, nsnull);
        5601                 :   nsPIDOMWindow* focusedWindow;
        5602               0 :   nsFocusManager::GetFocusedDescendant(rootWindow, true, &focusedWindow);
        5603               0 :   return focusedWindow;
        5604                 : }
        5605                 :
        5606                 : void
        5607               0 : PresShell::RecordMouseLocation(nsGUIEvent* aEvent)
        5608                 : {
        5609               0 :   if (!mPresContext)
        5610               0 :     return;
        5611                 :
        5612               0 :   if (!mPresContext->IsRoot()) {
        5613               0 :     PresShell* rootPresShell = GetRootPresShell();
        5614               0 :     if (rootPresShell) {
        5615               0 :       rootPresShell->RecordMouseLocation(aEvent);
        5616                 :     }
        5617               0 :     return;
        5618                 :   }
        5619                 :
        5620               0 :   if ((aEvent->message == NS_MOUSE_MOVE &&
        5621                 :        static_cast<nsMouseEvent*>(aEvent)->reason == nsMouseEvent::eReal) ||
        5622                 :       aEvent->message == NS_MOUSE_ENTER ||
        5623                 :       aEvent->message == NS_MOUSE_BUTTON_DOWN ||
        5624                 :       aEvent->message == NS_MOUSE_BUTTON_UP) {
        5625               0 :     nsIFrame* rootFrame = GetRootFrame();
        5626               0 :     if (!rootFrame) {
        5627               0 :       nsIView* rootView = mViewManager->GetRootView();
        5628                 :       mMouseLocation = nsLayoutUtils::TranslateWidgetToView(mPresContext,
        5629               0 :         aEvent->widget, aEvent->refPoint, rootView);
        5630                 :     } else {
        5631                 :       mMouseLocation =
        5632               0 :         nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
        5633                 :     }
        5634                 : #ifdef DEBUG_MOUSE_LOCATION
        5635                 :     if (aEvent->message == NS_MOUSE_ENTER)
        5636                 :       printf("[ps=%p]got mouse enter for %p\n",
        5637                 :              this, aEvent->widget);
        5638                 :     printf("[ps=%p]setting mouse location to (%d,%d)\n",
        5639                 :            this, mMouseLocation.x, mMouseLocation.y);
        5640                 : #endif
        5641               0 :     if (aEvent->message == NS_MOUSE_ENTER)
        5642               0 :       SynthesizeMouseMove(false);
        5643               0 :   } else if (aEvent->message == NS_MOUSE_EXIT) {
        5644                 :     // Although we only care about the mouse moving into an area for which this
        5645                 :     // pres shell doesn't receive mouse move events, we don't check which widget
        5646                 :     // the mouse exit was for since this seems to vary by platform.  Hopefully
        5647                 :     // this won't matter at all since we'll get the mouse move or enter after
        5648                 :     // the mouse exit when the mouse moves from one of our widgets into another.
        5649               0 :     mMouseLocation = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
        5650                 : #ifdef DEBUG_MOUSE_LOCATION
        5651                 :     printf("[ps=%p]got mouse exit for %p\n",
        5652                 :            this, aEvent->widget);
        5653                 :     printf("[ps=%p]clearing mouse location\n",
        5654                 :            this);
        5655                 : #endif
        5656                 :   }
        5657                 : }
        5658                 :
        5659                 : #ifdef MOZ_TOUCH
        5660                 : static void
        5661                 : EvictTouchPoint(nsCOMPtr<nsIDOMTouch>& aTouch)
        5662                 : {
        5663                 :   nsIWidget *widget = nsnull;
        5664                 :   // is there an easier/better way to dig out the widget?
        5665                 :   nsCOMPtr<nsINode> node(do_QueryInterface(aTouch->GetTarget()));
        5666                 :   if (!node) {
        5667                 :     return;
        5668                 :   }
        5669                 :   nsIDocument* doc = node->GetCurrentDoc();
        5670                 :   if (!doc) {
        5671                 :     return;
        5672                 :   }
        5673                 :   nsIPresShell *presShell = doc->GetShell();
        5674                 :   if (!presShell) {
        5675                 :     return;
        5676                 :   }
        5677                 :   nsIFrame* frame = presShell->GetRootFrame();
        5678                 :   if (!frame) {
        5679                 :     return;
        5680                 :   }
        5681                 :   nsPoint *pt = new nsPoint(aTouch->mRefPoint.x, aTouch->mRefPoint.y);
        5682                 :   widget = frame->GetView()->GetNearestWidget(pt);
        5683                 :   if (!widget) {
        5684                 :     return;
        5685                 :   }
        5686                 :   nsTouchEvent event(true, NS_TOUCH_END, widget);
        5687                 :   event.isShift = false;
        5688                 :   event.isControl = false;
        5689                 :   event.isAlt = false;
        5690                 :   event.isMeta = false;
        5691                 :   event.widget = widget;
        5692                 :   event.time = PR_IntervalNow();
        5693                 :   event.touches.AppendElement(aTouch);
        5694                 :
        5695                 :   nsEventStatus status;
        5696                 :   widget->DispatchEvent(&event, status);
        5697                 : }
        5698                 :
        5699                 : static PLDHashOperator
        5700                 : AppendToTouchList(const PRUint32& aKey, nsCOMPtr<nsIDOMTouch>& aData, void *aTouchList)
        5701                 : {
        5702                 :   nsTArray<nsCOMPtr<nsIDOMTouch> > *touches = static_cast<nsTArray<nsCOMPtr<nsIDOMTouch> > *>(aTouchList);
        5703                 :   aData->mChanged = false;
        5704                 :   touches->AppendElement(aData);
        5705                 :   return PL_DHASH_NEXT;
        5706                 : }
        5707                 : #endif // MOZ_TOUCH
        5708                 :
        5709                 : nsresult
        5710               0 : PresShell::HandleEvent(nsIFrame        *aFrame,
        5711                 :                        nsGUIEvent*     aEvent,
        5712                 :                        bool            aDontRetargetEvents,
        5713                 :                        nsEventStatus*  aEventStatus)
        5714                 : {
        5715               0 :   NS_ASSERTION(aFrame, "null frame");
        5716                 :
        5717               0 :   if (mIsDestroying ||
        5718                 :       (sDisableNonTestMouseEvents && NS_IS_MOUSE_EVENT(aEvent) &&
        5719               0 :        !(aEvent->flags & NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT))) {
        5720               0 :     return NS_OK;
        5721                 :   }
        5722                 :
        5723               0 :   RecordMouseLocation(aEvent);
        5724                 :
        5725                 : #ifdef ACCESSIBILITY
        5726               0 :   if (aEvent->eventStructType == NS_ACCESSIBLE_EVENT) {
        5727                 :     NS_TIME_FUNCTION_MIN(1.0);
        5728                 :
        5729                 :     // Accessibility events come through OS requests and not from scripts,
        5730                 :     // so it is safe to handle here
        5731               0 :     return HandleEventInternal(aEvent, aEventStatus);
        5732                 :   }
        5733                 : #endif
        5734                 :
        5735               0 :   if (!nsContentUtils::IsSafeToRunScript())
        5736               0 :     return NS_OK;
        5737                 :
        5738                 :   NS_TIME_FUNCTION_MIN(1.0);
        5739                 :
        5740                 :   nsIContent* capturingContent =
        5741               0 :     NS_IS_MOUSE_EVENT(aEvent) ? GetCapturingContent() : nsnull;
        5742                 :
        5743               0 :   nsCOMPtr<nsIDocument> retargetEventDoc;
        5744               0 :   if (!aDontRetargetEvents) {
        5745                 :     // key and IME related events should not cross top level window boundary.
        5746                 :     // Basically, such input events should be fired only on focused widget.
        5747                 :     // However, some IMEs might need to clean up composition after focused
        5748                 :     // window is deactivated.  And also some tests on MozMill want to test key
        5749                 :     // handling on deactivated window because MozMill window can be activated
        5750                 :     // during tests.  So, there is no merit the events should be redirected to
        5751                 :     // active window.  So, the events should be handled on the last focused
        5752                 :     // content in the last focused DOM window in same top level window.
        5753                 :     // Note, if no DOM window has been focused yet, we can discard the events.
        5754               0 :     if (NS_IsEventTargetedAtFocusedWindow(aEvent)) {
        5755               0 :       nsCOMPtr<nsPIDOMWindow> window = GetFocusedDOMWindowInOurWindow();
        5756                 :       // No DOM window in same top level window has not been focused yet,
        5757                 :       // discard the events.
        5758               0 :       if (!window) {
        5759               0 :         return NS_OK;
        5760                 :       }
        5761                 :
        5762               0 :       retargetEventDoc = do_QueryInterface(window->GetExtantDocument());
        5763               0 :       if (!retargetEventDoc)
        5764               0 :         return NS_OK;
        5765               0 :     } else if (capturingContent) {
        5766                 :       // if the mouse is being captured then retarget the mouse event at the
        5767                 :       // document that is being captured.
        5768               0 :       retargetEventDoc = capturingContent->GetCurrentDoc();
        5769                 :     }
        5770                 :
        5771               0 :     if (retargetEventDoc) {
        5772               0 :       nsCOMPtr<nsIPresShell> presShell = retargetEventDoc->GetShell();
        5773               0 :       if (!presShell)
        5774               0 :         return NS_OK;
        5775                 :
        5776               0 :       if (presShell != this) {
        5777               0 :         nsIFrame* frame = presShell->GetRootFrame();
        5778               0 :         if (!frame) {
        5779               0 :           if (aEvent->message == NS_QUERY_TEXT_CONTENT ||
        5780                 :               NS_IS_CONTENT_COMMAND_EVENT(aEvent)) {
        5781               0 :             return NS_OK;
        5782                 :           }
        5783                 :
        5784               0 :           nsIView* view = presShell->GetViewManager()->GetRootView();
        5785               0 :           while (view && !view->GetFrame()) {
        5786               0 :             view = view->GetParent();
        5787                 :           }
        5788                 :
        5789               0 :           if (view) {
        5790               0 :             frame = view->GetFrame();
        5791                 :           }
        5792                 :         }
        5793                 :
        5794               0 :         if (!frame)
        5795               0 :           return NS_OK;
        5796                 :
        5797               0 :         nsCOMPtr<nsIPresShell> shell = frame->PresContext()->GetPresShell();
        5798               0 :         return shell->HandleEvent(frame, aEvent, true, aEventStatus);
        5799                 :       }
        5800                 :     }
        5801                 :   }
        5802                 :
        5803                 :   // Check for a theme change up front, since the frame type is irrelevant
        5804               0 :   if (aEvent->message == NS_THEMECHANGED && mPresContext) {
        5805               0 :     mPresContext->ThemeChanged();
        5806               0 :     return NS_OK;
        5807                 :   }
        5808                 :
        5809               0 :   if (aEvent->message == NS_UISTATECHANGED && mDocument) {
        5810               0 :     nsPIDOMWindow* win = mDocument->GetWindow();
        5811               0 :     if (win) {
        5812               0 :       nsUIStateChangeEvent* event = (nsUIStateChangeEvent*)aEvent;
        5813               0 :       win->SetKeyboardIndicators(event->showAccelerators, event->showFocusRings);
        5814                 :     }
        5815               0 :     return NS_OK;
        5816                 :   }
        5817                 :
        5818                 :   // Check for a system color change up front, since the frame type is
        5819                 :   // irrelevant
        5820               0 :   if ((aEvent->message == NS_SYSCOLORCHANGED) && mPresContext &&
        5821               0 :       aFrame == mFrameConstructor->GetRootFrame()) {
        5822               0 :     *aEventStatus = nsEventStatus_eConsumeDoDefault;
        5823               0 :     mPresContext->SysColorChanged();
        5824               0 :     return NS_OK;
        5825                 :   }
        5826                 :
        5827               0 :   if (aEvent->eventStructType == NS_KEY_EVENT &&
        5828               0 :       mDocument && mDocument->EventHandlingSuppressed()) {
        5829               0 :     if (aEvent->message == NS_KEY_DOWN) {
        5830               0 :       mNoDelayedKeyEvents = true;
        5831               0 :     } else if (!mNoDelayedKeyEvents) {
        5832                 :       nsDelayedEvent* event =
        5833               0 :         new nsDelayedKeyEvent(static_cast<nsKeyEvent*>(aEvent));
        5834               0 :       if (!mDelayedEvents.AppendElement(event)) {
        5835               0 :         delete event;
        5836                 :       }
        5837                 :     }
        5838               0 :     return NS_OK;
        5839                 :   }
        5840                 :
        5841               0 :   nsIFrame* frame = aFrame;
        5842               0 :   bool dispatchUsingCoordinates = NS_IsEventUsingCoordinates(aEvent);
        5843               0 :   if (dispatchUsingCoordinates) {
        5844               0 :     NS_WARN_IF_FALSE(frame, "Nothing to handle this event!");
        5845               0 :     if (!frame)
        5846               0 :       return NS_OK;
        5847                 :
        5848               0 :     nsPresContext* framePresContext = frame->PresContext();
        5849               0 :     nsPresContext* rootPresContext = framePresContext->GetRootPresContext();
        5850               0 :     NS_ASSERTION(rootPresContext == mPresContext->GetRootPresContext(),
        5851                 :                  "How did we end up outside the connected prescontext/viewmanager hierarchy?");
        5852                 :     // If we aren't starting our event dispatch from the root frame of the root prescontext,
        5853                 :     // then someone must be capturing the mouse. In that case we don't want to search the popup
        5854                 :     // list.
        5855               0 :     if (framePresContext == rootPresContext &&
        5856               0 :         frame == mFrameConstructor->GetRootFrame()) {
        5857                 :       nsIFrame* popupFrame =
        5858               0 :         nsLayoutUtils::GetPopupFrameForEventCoordinates(rootPresContext, aEvent);
        5859                 :       // If the popupFrame is an ancestor of the 'frame', the frame should
        5860                 :       // handle the event, otherwise, the popup should handle it.
        5861               0 :       if (popupFrame &&
        5862                 :           !nsContentUtils::ContentIsCrossDocDescendantOf(
        5863               0 :              framePresContext->GetPresShell()->GetDocument(),
        5864               0 :              popupFrame->GetContent())) {
        5865               0 :         frame = popupFrame;
        5866                 :       }
        5867                 :     }
        5868                 :
        5869               0 :     bool captureRetarget = false;
        5870               0 :     if (capturingContent) {
        5871                 :       // If a capture is active, determine if the docshell is visible. If not,
        5872                 :       // clear the capture and target the mouse event normally instead. This
        5873                 :       // would occur if the mouse button is held down while a tab change occurs.
        5874                 :       // If the docshell is visible, look for a scrolling container.
        5875                 :       bool vis;
        5876               0 :       nsCOMPtr<nsISupports> supports = mPresContext->GetContainer();
        5877               0 :       nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supports));
        5878               0 :       if (baseWin && NS_SUCCEEDED(baseWin->GetVisibility(&vis)) && vis) {
        5879               0 :         captureRetarget = gCaptureInfo.mRetargetToElement;
        5880               0 :         if (!captureRetarget) {
        5881                 :           // A check was already done above to ensure that capturingContent is
        5882                 :           // in this presshell.
        5883               0 :           NS_ASSERTION(capturingContent->GetCurrentDoc() == GetDocument(),
        5884                 :                        "Unexpected document");
        5885               0 :           nsIFrame* captureFrame = capturingContent->GetPrimaryFrame();
        5886               0 :           if (captureFrame) {
        5887               0 :             if (capturingContent->Tag() == nsGkAtoms::select &&
        5888               0 :                 capturingContent->IsHTML()) {
        5889                 :               // a dropdown <select> has a child in its selectPopupList and we should
        5890                 :               // capture on that instead.
        5891               0 :               nsIFrame* childFrame = captureFrame->GetChildList(nsIFrame::kSelectPopupList).FirstChild();
        5892               0 :               if (childFrame) {
        5893               0 :                 captureFrame = childFrame;
        5894                 :               }
        5895                 :             }
        5896                 :
        5897                 :             // scrollable frames should use the scrolling container as
        5898                 :             // the root instead of the document
        5899               0 :             nsIScrollableFrame* scrollFrame = do_QueryFrame(captureFrame);
        5900               0 :             if (scrollFrame) {
        5901               0 :               frame = scrollFrame->GetScrolledFrame();
        5902                 :             }
        5903                 :           }
        5904                 :         }
        5905                 :       }
        5906                 :       else {
        5907               0 :         ClearMouseCapture(nsnull);
        5908               0 :         capturingContent = nsnull;
        5909                 :       }
        5910                 :     }
        5911                 :
        5912                 :     bool isWindowLevelMouseExit = (aEvent->message == NS_MOUSE_EXIT) &&
        5913               0 :       (static_cast<nsMouseEvent*>(aEvent)->exit == nsMouseEvent::eTopLevel);
        5914                 :
        5915                 :     // Get the frame at the event point. However, don't do this if we're
        5916                 :     // capturing and retargeting the event because the captured frame will
        5917                 :     // be used instead below. Also keep using the root frame if we're dealing
        5918                 :     // with a window-level mouse exit event since we want to start sending
        5919                 :     // mouse out events at the root EventStateManager.
        5920               0 :     if (!captureRetarget && !isWindowLevelMouseExit) {
        5921                 : #ifdef MOZ_TOUCH
        5922                 :       nsPoint eventPoint;
        5923                 :       if (aEvent->message == NS_TOUCH_START) {
        5924                 :         // Add any new touches to the queue
        5925                 :         nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
        5926                 :         // if there is only one touch in this touchstart event, assume that it is
        5927                 :         // the start of a new touch session and evict any old touches in the
        5928                 :         // queue
        5929                 :         if (touchEvent->touches.Length() == 1) {
        5930                 :           nsTArray<nsCOMPtr<nsIDOMTouch> > touches;
        5931                 :           gCaptureTouchList.Enumerate(&AppendToTouchList, (void *)&touches);
        5932                 :           for (PRUint32 i = 0; i < touches.Length(); ++i) {
        5933                 :             EvictTouchPoint(touches[i]);
        5934                 :           }
        5935                 :         }
        5936                 :         for (PRUint32 i = 0; i < touchEvent->touches.Length(); ++i) {
        5937                 :           nsIDOMTouch *touch = touchEvent->touches[i];
        5938                 :           nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
        5939                 :           touch->mMessage = aEvent->message;
        5940                 :
        5941                 :           PRInt32 id = 0;
        5942                 :           touch->GetIdentifier(&id);
        5943                 :           if (!gCaptureTouchList.Get(id, nsnull)) {
        5944                 :             // This event is a new touch. Mark it as a changedTouch and
        5945                 :             // add it to the queue.
        5946                 :             touch->mChanged = true;
        5947                 :             gCaptureTouchList.Put(id, touch);
        5948                 :
        5949                 :             eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, touch->mRefPoint, frame);
        5950                 :           } else {
        5951                 :             // This touch is an old touch, we need to ensure that is not
        5952                 :             // marked as changed and set its target correctly
        5953                 :             touch->mChanged = false;
        5954                 :             PRInt32 id;
        5955                 :             touch->GetIdentifier(&id);
        5956                 :
        5957                 :             nsCOMPtr<nsIDOMTouch> oldTouch;
        5958                 :             gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
        5959                 :             if (oldTouch) {
        5960                 :               nsCOMPtr<nsPIDOMEventTarget> targetPtr;
        5961                 :               oldTouch->GetTarget(getter_AddRefs(targetPtr));
        5962                 :               domtouch->SetTarget(targetPtr);
        5963                 :               gCaptureTouchList.Put(id, touch);
        5964                 :             }
        5965                 :           }
        5966                 :         }
        5967                 :       } else {
        5968                 :         eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
        5969                 :       }
        5970                 : #else
        5971                 :       nsPoint eventPoint
        5972               0 :           = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
        5973                 : #endif
        5974                 :       {
        5975               0 :         bool ignoreRootScrollFrame = false;
        5976               0 :         if (aEvent->eventStructType == NS_MOUSE_EVENT) {
        5977               0 :           ignoreRootScrollFrame = static_cast<nsMouseEvent*>(aEvent)->ignoreRootScrollFrame;
        5978                 :         }
        5979                 :         nsIFrame* target = nsLayoutUtils::GetFrameForPoint(frame, eventPoint,
        5980               0 :                                                            false, ignoreRootScrollFrame);
        5981               0 :         if (target) {
        5982               0 :           frame = target;
        5983                 :         }
        5984                 :       }
        5985                 :     }
        5986                 :
        5987                 :     // if a node is capturing the mouse, check if the event needs to be
        5988                 :     // retargeted at the capturing content instead. This will be the case when
        5989                 :     // capture retargeting is being used, no frame was found or the frame's
        5990                 :     // content is not a descendant of the capturing content.
        5991               0 :     if (capturingContent &&
        5992               0 :         (gCaptureInfo.mRetargetToElement || !frame->GetContent() ||
        5993               0 :          !nsContentUtils::ContentIsCrossDocDescendantOf(frame->GetContent(),
        5994               0 :                                                         capturingContent))) {
        5995                 :       // A check was already done above to ensure that capturingContent is
        5996                 :       // in this presshell.
        5997               0 :       NS_ASSERTION(capturingContent->GetCurrentDoc() == GetDocument(),
        5998                 :                    "Unexpected document");
        5999               0 :       nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame();
        6000               0 :       if (capturingFrame) {
        6001               0 :         frame = capturingFrame;
        6002                 :       }
        6003                 :     }
        6004                 :
        6005                 :     // Suppress mouse event if it's being targeted at an element inside
        6006                 :     // a document which needs events suppressed
        6007               0 :     if (aEvent->eventStructType == NS_MOUSE_EVENT &&
        6008               0 :         frame->PresContext()->Document()->EventHandlingSuppressed()) {
        6009               0 :       if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
        6010               0 :         mNoDelayedMouseEvents = true;
        6011               0 :       } else if (!mNoDelayedMouseEvents && aEvent->message == NS_MOUSE_BUTTON_UP) {
        6012                 :         nsDelayedEvent* event =
        6013               0 :           new nsDelayedMouseEvent(static_cast<nsMouseEvent*>(aEvent));
        6014               0 :         if (!mDelayedEvents.AppendElement(event)) {
        6015               0 :           delete event;
        6016                 :         }
        6017                 :       }
        6018                 :
        6019               0 :       return NS_OK;
        6020                 :     }
        6021                 :
        6022                 :     PresShell* shell =
        6023               0 :         static_cast<PresShell*>(frame->PresContext()->PresShell());
        6024                 :
        6025                 :     // Check if we have an active EventStateManager which isn't the
        6026                 :     // EventStateManager of the current PresContext.
        6027                 :     // If that is the case, and mouse is over some ancestor document,
        6028                 :     // forward event handling to the active document.
        6029                 :     // This way content can get mouse events even when
        6030                 :     // mouse is over the chrome or outside the window.
        6031                 :     //
        6032                 :     // Note, currently for backwards compatibility we don't forward mouse events
        6033                 :     // to the active document when mouse is over some subdocument.
        6034                 :     nsEventStateManager* activeESM =
        6035               0 :       nsEventStateManager::GetActiveEventStateManager();
        6036               0 :     if (activeESM && NS_IS_MOUSE_EVENT(aEvent) &&
        6037               0 :         activeESM != shell->GetPresContext()->EventStateManager() &&
        6038               0 :         static_cast<nsEventStateManager*>(activeESM)->GetPresContext()) {
        6039                 :       nsIPresShell* activeShell =
        6040               0 :         static_cast<nsEventStateManager*>(activeESM)->GetPresContext()->GetPresShell();
        6041               0 :       if (activeShell &&
        6042               0 :           nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(),
        6043               0 :                                                         shell->GetDocument())) {
        6044               0 :         shell = static_cast<PresShell*>(activeShell);
        6045               0 :         frame = shell->GetRootFrame();
        6046                 :       }
        6047                 :     }
        6048                 :
        6049               0 :     if (shell != this) {
        6050                 :       // Handle the event in the correct shell.
        6051                 :       // Prevent deletion until we're done with event handling (bug 336582).
        6052               0 :       nsCOMPtr<nsIPresShell> kungFuDeathGrip(shell);
        6053                 :       // We pass the subshell's root frame as the frame to start from. This is
        6054                 :       // the only correct alternative; if the event was captured then it
        6055                 :       // must have been captured by us or some ancestor shell and we
        6056                 :       // now ask the subshell to dispatch it normally.
        6057               0 :       return shell->HandlePositionedEvent(frame, aEvent, aEventStatus);
        6058                 :     }
        6059                 :
        6060               0 :     return HandlePositionedEvent(frame, aEvent, aEventStatus);
        6061                 :   }
        6062                 :
        6063               0 :   nsresult rv = NS_OK;
        6064                 :
        6065               0 :   if (frame) {
        6066               0 :     PushCurrentEventInfo(nsnull, nsnull);
        6067                 :
        6068                 :     // key and IME related events go to the focused frame in this DOM window.
        6069               0 :     if (NS_IsEventTargetedAtFocusedContent(aEvent)) {
        6070               0 :       mCurrentEventContent = nsnull;
        6071                 :
        6072                 :       nsCOMPtr<nsPIDOMWindow> window =
        6073               0 :         do_QueryInterface(mDocument->GetWindow());
        6074               0 :       nsCOMPtr<nsPIDOMWindow> focusedWindow;
        6075                 :       nsCOMPtr<nsIContent> eventTarget =
        6076                 :         nsFocusManager::GetFocusedDescendant(window, false,
        6077               0 :                                              getter_AddRefs(focusedWindow));
        6078                 :
        6079                 :       // otherwise, if there is no focused content or the focused content has
        6080                 :       // no frame, just use the root content. This ensures that key events
        6081                 :       // still get sent to the window properly if nothing is focused or if a
        6082                 :       // frame goes away while it is focused.
        6083               0 :       if (!eventTarget || !eventTarget->GetPrimaryFrame()) {
        6084               0 :         nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
        6085               0 :         if (htmlDoc) {
        6086               0 :           nsCOMPtr<nsIDOMHTMLElement> body;
        6087               0 :           htmlDoc->GetBody(getter_AddRefs(body));
        6088               0 :           eventTarget = do_QueryInterface(body);
        6089               0 :           if (!eventTarget) {
        6090               0 :             eventTarget = mDocument->GetRootElement();
        6091                 :           }
        6092                 :         } else {
        6093               0 :           eventTarget = mDocument->GetRootElement();
        6094                 :         }
        6095                 :       }
        6096                 :
        6097               0 :       if (aEvent->message == NS_KEY_DOWN) {
        6098               0 :         NS_IF_RELEASE(gKeyDownTarget);
        6099               0 :         NS_IF_ADDREF(gKeyDownTarget = eventTarget);
        6100                 :       }
        6101               0 :       else if ((aEvent->message == NS_KEY_PRESS || aEvent->message == NS_KEY_UP) &&
        6102                 :                gKeyDownTarget) {
        6103                 :         // If a different element is now focused for the keypress/keyup event
        6104                 :         // than what was focused during the keydown event, check if the new
        6105                 :         // focused element is not in a chrome document any more, and if so,
        6106                 :         // retarget the event back at the keydown target. This prevents a
        6107                 :         // content area from grabbing the focus from chrome in-between key
        6108                 :         // events.
        6109               0 :         if (eventTarget &&
        6110               0 :             nsContentUtils::IsChromeDoc(gKeyDownTarget->GetCurrentDoc()) !=
        6111               0 :             nsContentUtils::IsChromeDoc(eventTarget->GetCurrentDoc())) {
        6112               0 :           eventTarget = gKeyDownTarget;
        6113                 :         }
        6114                 :
        6115               0 :         if (aEvent->message == NS_KEY_UP) {
        6116               0 :           NS_RELEASE(gKeyDownTarget);
        6117                 :         }
        6118                 :       }
        6119                 :
        6120               0 :       mCurrentEventFrame = nsnull;
        6121               0 :       nsIDocument* targetDoc = eventTarget ? eventTarget->OwnerDoc() : nsnull;
        6122               0 :       if (targetDoc && targetDoc != mDocument) {
        6123               0 :         PopCurrentEventInfo();
        6124               0 :         nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell();
        6125               0 :         if (shell) {
        6126               0 :           rv = static_cast<PresShell*>(shell.get())->
        6127               0 :             HandleRetargetedEvent(aEvent, aEventStatus, eventTarget);
        6128                 :         }
        6129               0 :         return rv;
        6130                 :       } else {
        6131               0 :         mCurrentEventContent = eventTarget;
        6132                 :       }
        6133                 :
        6134               0 :       if (!mCurrentEventContent || !GetCurrentEventFrame() ||
        6135               0 :           InZombieDocument(mCurrentEventContent)) {
        6136               0 :         rv = RetargetEventToParent(aEvent, aEventStatus);
        6137               0 :         PopCurrentEventInfo();
        6138               0 :         return rv;
        6139                 :       }
        6140                 :     } else {
        6141               0 :       mCurrentEventFrame = frame;
        6142                 :     }
        6143               0 :     if (GetCurrentEventFrame()) {
        6144               0 :       rv = HandleEventInternal(aEvent, aEventStatus);
        6145                 :     }
        6146                 :
        6147                 : #ifdef NS_DEBUG
        6148               0 :     ShowEventTargetDebug();
        6149                 : #endif
        6150               0 :     PopCurrentEventInfo();
        6151                 :   } else {
        6152                 :     // Activation events need to be dispatched even if no frame was found, since
        6153                 :     // we don't want the focus to be out of sync.
        6154                 :
        6155               0 :     if (!NS_EVENT_NEEDS_FRAME(aEvent)) {
        6156               0 :       mCurrentEventFrame = nsnull;
        6157               0 :       return HandleEventInternal(aEvent, aEventStatus);
        6158                 :     }
        6159               0 :     else if (NS_IS_KEY_EVENT(aEvent)) {
        6160                 :       // Keypress events in new blank tabs should not be completely thrown away.
        6161                 :       // Retarget them -- the parent chrome shell might make use of them.
        6162               0 :       return RetargetEventToParent(aEvent, aEventStatus);
        6163                 :     }
        6164                 :   }
        6165                 :
        6166               0 :   return rv;
        6167                 : }
        6168                 :
        6169                 : #ifdef NS_DEBUG
        6170                 : void
        6171               0 : PresShell::ShowEventTargetDebug()
        6172                 : {
        6173               0 :   if (nsFrame::GetShowEventTargetFrameBorder() &&
        6174               0 :       GetCurrentEventFrame()) {
        6175               0 :     if (mDrawEventTargetFrame) {
        6176                 :       mDrawEventTargetFrame->Invalidate(
        6177               0 :           nsRect(nsPoint(0, 0), mDrawEventTargetFrame->GetSize()));
        6178                 :     }
        6179                 :
        6180               0 :     mDrawEventTargetFrame = mCurrentEventFrame;
        6181                 :     mDrawEventTargetFrame->Invalidate(
        6182               0 :         nsRect(nsPoint(0, 0), mDrawEventTargetFrame->GetSize()));
        6183                 :   }
        6184               0 : }
        6185                 : #endif
        6186                 :
        6187                 : nsresult
        6188               0 : PresShell::HandlePositionedEvent(nsIFrame*      aTargetFrame,
        6189                 :                                  nsGUIEvent*    aEvent,
        6190                 :                                  nsEventStatus* aEventStatus)
        6191                 : {
        6192               0 :   nsresult rv = NS_OK;
        6193                 :
        6194               0 :   PushCurrentEventInfo(nsnull, nsnull);
        6195                 :
        6196               0 :   mCurrentEventFrame = aTargetFrame;
        6197                 :
        6198               0 :   if (mCurrentEventFrame) {
        6199               0 :     nsCOMPtr<nsIContent> targetElement;
        6200                 :     mCurrentEventFrame->GetContentForEvent(aEvent,
        6201               0 :                                            getter_AddRefs(targetElement));
        6202                 :
        6203                 :     // If there is no content for this frame, target it anyway.  Some
        6204                 :     // frames can be targeted but do not have content, particularly
        6205                 :     // windows with scrolling off.
        6206               0 :     if (targetElement) {
        6207                 :       // Bug 103055, bug 185889: mouse events apply to *elements*, not all
        6208                 :       // nodes.  Thus we get the nearest element parent here.
        6209                 :       // XXX we leave the frame the same even if we find an element
        6210                 :       // parent, so that the text frame will receive the event (selection
        6211                 :       // and friends are the ones who care about that anyway)
        6212                 :       //
        6213                 :       // We use weak pointers because during this tight loop, the node
        6214                 :       // will *not* go away.  And this happens on every mousemove.
        6215               0 :       while (targetElement && !targetElement->IsElement()) {
        6216               0 :         targetElement = targetElement->GetParent();
        6217                 :       }
        6218                 :
        6219                 :       // If we found an element, target it.  Otherwise, target *nothing*.
        6220               0 :       if (!targetElement) {
        6221               0 :         mCurrentEventContent = nsnull;
        6222               0 :         mCurrentEventFrame = nsnull;
        6223               0 :       } else if (targetElement != mCurrentEventContent) {
        6224               0 :         mCurrentEventContent = targetElement;
        6225                 :       }
        6226                 :     }
        6227                 :   }
        6228                 :
        6229               0 :   if (GetCurrentEventFrame()) {
        6230               0 :     rv = HandleEventInternal(aEvent, aEventStatus);
        6231                 :   }
        6232                 :
        6233                 : #ifdef NS_DEBUG
        6234               0 :   ShowEventTargetDebug();
        6235                 : #endif
        6236               0 :   PopCurrentEventInfo();
        6237               0 :   return rv;
        6238                 : }
        6239                 :
        6240                 : nsresult
        6241               0 : PresShell::HandleEventWithTarget(nsEvent* aEvent, nsIFrame* aFrame,
        6242                 :                                  nsIContent* aContent, nsEventStatus* aStatus)
        6243                 : {
        6244               0 :   PushCurrentEventInfo(aFrame, aContent);
        6245               0 :   nsresult rv = HandleEventInternal(aEvent, aStatus);
        6246               0 :   PopCurrentEventInfo();
        6247               0 :   return rv;
        6248                 : }
        6249                 :
        6250                 : static inline bool
        6251               0 : IsSynthesizedMouseEvent(nsEvent* aEvent)
        6252                 : {
        6253                 :   return aEvent->eventStructType == NS_MOUSE_EVENT &&
        6254               0 :          static_cast<nsMouseEvent*>(aEvent)->reason != nsMouseEvent::eReal;
        6255                 : }
        6256                 :
        6257               0 : static bool CanHandleContextMenuEvent(nsMouseEvent* aMouseEvent,
        6258                 :                                         nsIFrame* aFrame)
        6259                 : {
        6260                 : #if defined(XP_MACOSX) && defined(MOZ_XUL)
        6261                 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
        6262                 :   if (pm) {
        6263                 :     nsIFrame* popupFrame = pm->GetTopPopup(ePopupTypeMenu);
        6264                 :     if (popupFrame) {
        6265                 :       // context menus should not be opened while another menu is open on Mac,
        6266                 :       // so return false so that the event is not fired.
        6267                 :       if (aMouseEvent->context == nsMouseEvent::eContextMenuKey) {
        6268                 :         return false;
        6269                 :       } else if (aMouseEvent->widget) {
        6270                 :          nsWindowType windowType;
        6271                 :          aMouseEvent->widget->GetWindowType(windowType);
        6272                 :          if (windowType == eWindowType_popup) {
        6273                 :            for (nsIFrame* current = aFrame; current;
        6274                 :                 current = nsLayoutUtils::GetCrossDocParentFrame(current)) {
        6275                 :              if (current->GetType() == nsGkAtoms::menuPopupFrame) {
        6276                 :                return false;
        6277                 :              }
        6278                 :            }
        6279                 :          }
        6280                 :       }
        6281                 :     }
        6282                 :   }
        6283                 : #endif
        6284               0 :   return true;
        6285                 : }
        6286                 :
        6287                 : static bool
        6288               0 : IsFullScreenAndRestrictedKeyEvent(nsIContent* aTarget, const nsEvent* aEvent)
        6289                 : {
        6290               0 :   NS_ABORT_IF_FALSE(aEvent, "Must have an event to check.");
        6291                 :
        6292                 :   // Bail out if the event is not a key event, or the target's document is
        6293                 :   // not in DOM full screen mode, or full-screen key input is not restricted.
        6294               0 :   nsIDocument *root = nsnull;
        6295               0 :   if (!aTarget ||
        6296                 :       (aEvent->message != NS_KEY_DOWN &&
        6297                 :       aEvent->message != NS_KEY_UP &&
        6298                 :       aEvent->message != NS_KEY_PRESS) ||
        6299               0 :       !(root = nsContentUtils::GetRootDocument(aTarget->OwnerDoc())) ||
        6300               0 :       !root->IsFullScreenDoc() ||
        6301               0 :       !nsContentUtils::IsFullScreenKeyInputRestricted()) {
        6302               0 :     return false;
        6303                 :   }
        6304                 :
        6305                 :   // We're in full-screen mode. We whitelist key codes, and we will
        6306                 :   // show a warning when keys not in this list are pressed.
        6307               0 :   const nsKeyEvent* keyEvent = static_cast<const nsKeyEvent*>(aEvent);
        6308               0 :   int key = keyEvent->keyCode ? keyEvent->keyCode : keyEvent->charCode;
        6309               0 :   switch (key) {
        6310                 :     case NS_VK_TAB:
        6311                 :     case NS_VK_SPACE:
        6312                 :     case NS_VK_PAGE_UP:
        6313                 :     case NS_VK_PAGE_DOWN:
        6314                 :     case NS_VK_END:
        6315                 :     case NS_VK_HOME:
        6316                 :     case NS_VK_LEFT:
        6317                 :     case NS_VK_UP:
        6318                 :     case NS_VK_RIGHT:
        6319                 :     case NS_VK_DOWN:
        6320                 :     case NS_VK_SHIFT:
        6321                 :     case NS_VK_CONTROL:
        6322                 :     case NS_VK_ALT:
        6323                 :     case NS_VK_META:
        6324                 : #ifdef XP_WIN
        6325                 :     case VK_VOLUME_MUTE:
        6326                 :     case VK_VOLUME_DOWN:
        6327                 :     case VK_VOLUME_UP:
        6328                 : #endif
        6329                 :       // Unrestricted key code.
        6330               0 :       return false;
        6331                 :     default:
        6332                 :       // Otherwise, fullscreen is enabled, key input is restricted, and the key
        6333                 :       // code is not an allowed key code.
        6334               0 :       return true;
        6335                 :   }
        6336                 : }
        6337                 :
        6338                 : nsresult
        6339               0 : PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
        6340                 : {
        6341                 :   NS_TIME_FUNCTION_MIN(1.0);
        6342                 :
        6343                 : #ifdef ACCESSIBILITY
        6344               0 :   if (aEvent->eventStructType == NS_ACCESSIBLE_EVENT)
        6345                 :   {
        6346               0 :     nsAccessibleEvent *accEvent = static_cast<nsAccessibleEvent*>(aEvent);
        6347               0 :     accEvent->mAccessible = nsnull;
        6348                 :
        6349                 :     nsCOMPtr<nsIAccessibilityService> accService =
        6350               0 :       do_GetService("@mozilla.org/accessibilityService;1");
        6351               0 :     if (accService) {
        6352               0 :       nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
        6353               0 :       if (!container) {
        6354                 :         // This presshell is not active. This often happens when a
        6355                 :         // preshell is being held onto for fastback.
        6356               0 :         return NS_OK;
        6357                 :       }
        6358                 :
        6359                 :       // Accessible creation might be not safe so we make sure it's not created
        6360                 :       // at unsafe times.
        6361                 :       accEvent->mAccessible =
        6362               0 :         accService->GetRootDocumentAccessible(this, nsContentUtils::IsSafeToRunScript());
        6363                 :
        6364               0 :       return NS_OK;
        6365                 :     }
        6366                 :   }
        6367                 : #endif
        6368                 :
        6369               0 :   nsRefPtr<nsEventStateManager> manager = mPresContext->EventStateManager();
        6370               0 :   nsresult rv = NS_OK;
        6371                 :
        6372               0 :   if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame()) {
        6373                 : #ifdef MOZ_TOUCH
        6374                 :     bool touchIsNew = false;
        6375                 : #endif
        6376               0 :     bool isHandlingUserInput = false;
        6377                 :
        6378                 :     // XXX How about IME events and input events for plugins?
        6379               0 :     if (NS_IS_TRUSTED_EVENT(aEvent)) {
        6380               0 :       switch (aEvent->message) {
        6381                 :       case NS_KEY_PRESS:
        6382                 :       case NS_KEY_DOWN:
        6383                 :       case NS_KEY_UP: {
        6384                 :         nsIDocument *doc = mCurrentEventContent ?
        6385               0 :                            mCurrentEventContent->OwnerDoc() : nsnull;
        6386               0 :         nsIDocument* root = nsnull;
        6387               0 :         if (static_cast<const nsKeyEvent*>(aEvent)->keyCode == NS_VK_ESCAPE &&
        6388                 :             (root = nsContentUtils::GetRootDocument(doc)) &&
        6389               0 :             root->IsFullScreenDoc()) {
        6390                 :           // Prevent default action on ESC key press when exiting
        6391                 :           // DOM full-screen mode. This prevents the browser ESC key
        6392                 :           // handler from stopping all loads in the document, which
        6393                 :           // would cause <video> loads to stop.
        6394                 :           aEvent->flags |= (NS_EVENT_FLAG_NO_DEFAULT |
        6395               0 :                             NS_EVENT_FLAG_ONLY_CHROME_DISPATCH);
        6396                 :
        6397               0 :           if (aEvent->message == NS_KEY_UP) {
        6398                 :            // ESC key released while in DOM full-screen mode.
        6399                 :            // Exit full-screen mode.
        6400               0 :             nsIDocument::ExitFullScreen(true);
        6401                 :           }
        6402               0 :         } else if (IsFullScreenAndRestrictedKeyEvent(mCurrentEventContent, aEvent)) {
        6403                 :           // Restricted key press while in DOM full-screen mode. Dispatch
        6404                 :           // an event to chrome so it knows to show a warning message
        6405                 :           // informing the user how to exit full-screen.
        6406                 :           nsRefPtr<nsAsyncDOMEvent> e =
        6407               0 :             new nsAsyncDOMEvent(doc, NS_LITERAL_STRING("MozShowFullScreenWarning"),
        6408               0 :                                 true, true);
        6409               0 :           e->PostDOMEvent();
        6410                 :         }
        6411                 :         // Else not full-screen mode or key code is unrestricted, fall
        6412                 :         // through to normal handling.
        6413                 :       }
        6414                 :       case NS_MOUSE_BUTTON_DOWN:
        6415                 :       case NS_MOUSE_BUTTON_UP:
        6416               0 :         isHandlingUserInput = true;
        6417               0 :         break;
        6418                 : #ifdef MOZ_TOUCH
        6419                 :       case NS_TOUCH_CANCEL:
        6420                 :       case NS_TOUCH_END: {
        6421                 :         // Remove the changed touches
        6422                 :         // need to make sure we only remove touches that are ending here
        6423                 :         nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
        6424                 :         nsTArray<nsCOMPtr<nsIDOMTouch> >  &touches = touchEvent->touches;
        6425                 :         for (PRUint32 i = 0; i < touches.Length(); ++i) {
        6426                 :           nsIDOMTouch *touch = touches[i];
        6427                 :           nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
        6428                 :           if (!touch) {
        6429                 :             continue;
        6430                 :           }
        6431                 :           touch->mMessage = aEvent->message;
        6432                 :           touch->mChanged = true;
        6433                 :           nsCOMPtr<nsIDOMTouch> oldTouch;
        6434                 :
        6435                 :           PRInt32 id;
        6436                 :           touch->GetIdentifier(&id);
        6437                 :
        6438                 :           gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
        6439                 :           if (!oldTouch) {
        6440                 :             continue;
        6441                 :           }
        6442                 :           nsCOMPtr<nsPIDOMEventTarget> targetPtr;
        6443                 :           oldTouch->GetTarget(getter_AddRefs(targetPtr));
        6444                 :
        6445                 :           mCurrentEventContent = do_QueryInterface(targetPtr);
        6446                 :           domtouch->SetTarget(targetPtr);
        6447                 :           gCaptureTouchList.Remove(id);
        6448                 :         }
        6449                 :         // add any touches left in the touch list, but ensure changed=false
        6450                 :         gCaptureTouchList.Enumerate(&AppendToTouchList, (void *)&touches);
        6451                 :         break;
        6452                 :       }
        6453                 :       case NS_TOUCH_MOVE: {
        6454                 :         // Check for touches that changed. Mark them add to queue
        6455                 :         nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
        6456                 :         nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
        6457                 :         bool haveChanged = false;
        6458                 :         for (PRUint32 i = 0; i < touches.Length(); ++i) {
        6459                 :           nsIDOMTouch *touch = touches[i];
        6460                 :           nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
        6461                 :           if (!touch) {
        6462                 :             continue;
        6463                 :           }
        6464                 :           PRInt32 id;
        6465                 :           touch->GetIdentifier(&id);
        6466                 :           touch->mMessage = aEvent->message;
        6467                 :
        6468                 :           nsCOMPtr<nsIDOMTouch> oldTouch;
        6469                 :           gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
        6470                 :           if (!oldTouch) {
        6471                 :             continue;
        6472                 :           }
        6473                 :           if(domtouch->Equals(oldTouch)) {
        6474                 :             touch->mChanged = true;
        6475                 :             haveChanged = true;
        6476                 :           }
        6477                 :
        6478                 :           nsCOMPtr<nsPIDOMEventTarget> targetPtr;
        6479                 :           oldTouch->GetTarget(getter_AddRefs(targetPtr));
        6480                 :           domtouch->SetTarget(targetPtr);
        6481                 :
        6482                 :           gCaptureTouchList.Put(id, touch);
        6483                 :           // if we're moving from touchstart to touchmove for this touch
        6484                 :           // we allow preventDefault to prevent mouse events
        6485                 :           if (oldTouch->mMessage != touch->mMessage) {
        6486                 :             touchIsNew = true;
        6487                 :           }
        6488                 :         }
        6489                 :         // is nothing has changed, we should just return
        6490                 :         if (!haveChanged) {
        6491                 :           if (gPreventMouseEvents) {
        6492                 :               *aStatus = nsEventStatus_eConsumeNoDefault;
        6493                 :           }
        6494                 :           return NS_OK;
        6495                 :         }
        6496                 :         break;
        6497                 :       }
        6498                 : #endif
        6499                 :       case NS_DRAGDROP_DROP:
        6500               0 :         nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession();
        6501               0 :         if (session) {
        6502               0 :           bool onlyChromeDrop = false;
        6503               0 :           session->GetOnlyChromeDrop(&onlyChromeDrop);
        6504               0 :           if (onlyChromeDrop) {
        6505               0 :             aEvent->flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
        6506                 :           }
        6507                 :         }
        6508                 :         break;
        6509                 :       }
        6510                 :     }
        6511                 :
        6512               0 :     if (aEvent->message == NS_CONTEXTMENU) {
        6513               0 :       nsMouseEvent* me = static_cast<nsMouseEvent*>(aEvent);
        6514               0 :       if (!CanHandleContextMenuEvent(me, GetCurrentEventFrame())) {
        6515               0 :         return NS_OK;
        6516                 :       }
        6517               0 :       if (me->context == nsMouseEvent::eContextMenuKey &&
        6518               0 :           !AdjustContextMenuKeyEvent(me)) {
        6519               0 :         return NS_OK;
        6520                 :       }
        6521               0 :       if (me->isShift)
        6522                 :         aEvent->flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH |
        6523               0 :                          NS_EVENT_RETARGET_TO_NON_NATIVE_ANONYMOUS;
        6524                 :     }
        6525                 :
        6526                 :     nsAutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput,
        6527               0 :                                                           aEvent, mDocument);
        6528                 :
        6529               0 :     if (NS_IS_TRUSTED_EVENT(aEvent) && aEvent->message == NS_MOUSE_MOVE) {
        6530                 :       nsIPresShell::AllowMouseCapture(
        6531               0 :         nsEventStateManager::GetActiveEventStateManager() == manager);
        6532                 :     }
        6533                 :
        6534               0 :     nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
        6535                 :
        6536                 :     // FIXME. If the event was reused, we need to clear the old target,
        6537                 :     // bug 329430
        6538               0 :     aEvent->target = nsnull;
        6539                 :
        6540                 :     // 1. Give event to event manager for pre event state changes and
        6541                 :     //    generation of synthetic events.
        6542               0 :     rv = manager->PreHandleEvent(mPresContext, aEvent, mCurrentEventFrame, aStatus);
        6543                 :
        6544                 :     // 2. Give event to the DOM for third party and JS use.
        6545               0 :     if (GetCurrentEventFrame() && NS_SUCCEEDED(rv)) {
        6546                 :       bool wasHandlingKeyBoardEvent =
        6547               0 :         nsContentUtils::IsHandlingKeyBoardEvent();
        6548               0 :       if (aEvent->eventStructType == NS_KEY_EVENT) {
        6549               0 :         nsContentUtils::SetIsHandlingKeyBoardEvent(true);
        6550                 :       }
        6551                 :       // We want synthesized mouse moves to cause mouseover and mouseout
        6552                 :       // DOM events (PreHandleEvent above), but not mousemove DOM events.
        6553                 :       // Synthesized button up events also do not cause DOM events
        6554                 :       // because they do not have a reliable refPoint.
        6555               0 :       if (!IsSynthesizedMouseEvent(aEvent)) {
        6556               0 :         nsPresShellEventCB eventCB(this);
        6557                 : #ifdef MOZ_TOUCH
        6558                 :         if (aEvent->eventStructType == NS_TOUCH_EVENT) {
        6559                 :           DispatchTouchEvent(aEvent, aStatus, &eventCB, touchIsNew);
        6560                 :         }
        6561                 :         else if (mCurrentEventContent) {
        6562                 : #else
        6563               0 :         if (mCurrentEventContent) {
        6564                 : #endif
        6565                 :           nsEventDispatcher::Dispatch(mCurrentEventContent, mPresContext,
        6566               0 :                                       aEvent, nsnull, aStatus, &eventCB);
        6567                 :         }
        6568                 :         else {
        6569               0 :           nsCOMPtr<nsIContent> targetContent;
        6570                 :           rv = mCurrentEventFrame->GetContentForEvent(aEvent,
        6571               0 :                                                       getter_AddRefs(targetContent));
        6572               0 :           if (NS_SUCCEEDED(rv) && targetContent) {
        6573                 :             nsEventDispatcher::Dispatch(targetContent, mPresContext, aEvent,
        6574               0 :                                         nsnull, aStatus, &eventCB);
        6575               0 :           } else if (mDocument) {
        6576                 :             nsEventDispatcher::Dispatch(mDocument, mPresContext, aEvent,
        6577               0 :                                         nsnull, aStatus, nsnull);
        6578                 :           }
        6579                 :         }
        6580                 :       }
        6581                 :
        6582               0 :       nsContentUtils::SetIsHandlingKeyBoardEvent(wasHandlingKeyBoardEvent);
        6583                 :
        6584                 :       // 3. Give event to event manager for post event state changes and
        6585                 :       //    generation of synthetic events.
        6586               0 :       if (!mIsDestroying && NS_SUCCEEDED(rv)) {
        6587                 :         rv = manager->PostHandleEvent(mPresContext, aEvent,
        6588               0 :                                       GetCurrentEventFrame(), aStatus);
        6589                 :       }
        6590                 :     }
        6591                 :
        6592               0 :     if (aEvent->message == NS_MOUSE_BUTTON_UP) {
        6593                 :       // reset the capturing content now that the mouse button is up
        6594               0 :       SetCapturingContent(nsnull, 0);
        6595               0 :     } else if (aEvent->message == NS_MOUSE_MOVE) {
        6596               0 :       nsIPresShell::AllowMouseCapture(false);
        6597                 :     }
        6598                 :   }
        6599               0 :   return rv;
        6600                 : }
        6601                 :
        6602                 : void
        6603               0 : PresShell::DispatchTouchEvent(nsEvent *aEvent,
        6604                 :                               nsEventStatus* aStatus,
        6605                 :                               nsPresShellEventCB* aEventCB,
        6606                 :                               bool aTouchIsNew)
        6607                 : {
        6608               0 :   nsresult rv = NS_OK;
        6609                 :   // calling preventDefault on touchstart or the first touchmove for a
        6610                 :   // point prevents mouse events
        6611                 :   bool canPrevent = aEvent->message == NS_TOUCH_START ||
        6612               0 :               (aEvent->message == NS_TOUCH_MOVE && aTouchIsNew);
        6613               0 :   bool preventDefault = false;
        6614               0 :   nsEventStatus tmpStatus = nsEventStatus_eIgnore;
        6615               0 :   nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
        6616                 :   // touch events should fire on all targets
        6617               0 :   if (aEvent->message != NS_TOUCH_START) {
        6618               0 :     nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
        6619               0 :     for (PRUint32 i = 0; i < touches.Length(); ++i) {
        6620               0 :       nsIDOMTouch *touch = touches[i];
        6621               0 :       if (!touch || !touch->mChanged) {
        6622               0 :         continue;
        6623                 :       }
        6624                 :       // copy the event
        6625               0 :       nsCOMPtr<nsPIDOMEventTarget> targetPtr;
        6626               0 :       touch->GetTarget(getter_AddRefs(targetPtr));
        6627               0 :       if (!targetPtr) {
        6628               0 :         continue;
        6629                 :       }
        6630                 :
        6631               0 :       nsTouchEvent newEvent(touchEvent);
        6632               0 :       newEvent.target = targetPtr;
        6633                 :
        6634               0 :       nsCOMPtr<nsIContent> content(do_QueryInterface(targetPtr));
        6635               0 :       nsPresContext *context = nsContentUtils::GetContextForContent(content);
        6636               0 :       if (!context) {
        6637               0 :         context = mPresContext;
        6638                 :       }
        6639               0 :       tmpStatus = nsEventStatus_eIgnore;
        6640                 :       nsEventDispatcher::Dispatch(targetPtr, context,
        6641               0 :                                   &newEvent, nsnull, &tmpStatus, aEventCB);
        6642               0 :       if (nsEventStatus_eConsumeNoDefault == tmpStatus) {
        6643               0 :         preventDefault = true;
        6644                 :       }
        6645                 :     }
        6646                 :   } else {
        6647                 :     // touchevents need to have the target attribute set on each touch
        6648               0 :     nsTArray<nsCOMPtr<nsIDOMTouch> >  touches = touchEvent->touches;
        6649               0 :     for (PRUint32 i = 0; i < touches.Length(); ++i) {
        6650               0 :       nsIDOMTouch *touch = touches[i];
        6651               0 :       if (touch->mChanged) {
        6652               0 :         touch->SetTarget(mCurrentEventContent);
        6653                 :       }
        6654                 :     }
        6655                 :
        6656               0 :     if (mCurrentEventContent) {
        6657                 :       nsEventDispatcher::Dispatch(mCurrentEventContent, mPresContext,
        6658               0 :                                   aEvent, nsnull, &tmpStatus, aEventCB);
        6659                 :     } else {
        6660               0 :       nsCOMPtr<nsIContent> targetContent;
        6661                 :       rv = mCurrentEventFrame->GetContentForEvent(aEvent,
        6662               0 :                                                   getter_AddRefs(targetContent));
        6663               0 :       if (NS_SUCCEEDED(rv) && targetContent) {
        6664                 :         nsEventDispatcher::Dispatch(targetContent, mPresContext, aEvent,
        6665               0 :                                     nsnull, &tmpStatus, aEventCB);
        6666               0 :       } else if (mDocument) {
        6667                 :         nsEventDispatcher::Dispatch(mDocument, mPresContext, aEvent,
        6668               0 :                                     nsnull, &tmpStatus, nsnull);
        6669                 :       }
        6670                 :     }
        6671               0 :     if (nsEventStatus_eConsumeNoDefault == tmpStatus) {
        6672               0 :       preventDefault = true;
        6673                 :     }
        6674                 :
        6675               0 :     if (touchEvent->touches.Length() == 1) {
        6676               0 :       gPreventMouseEvents = false;
        6677                 :     }
        6678                 :   }
        6679                 :
        6680                 :   // if preventDefault was called on any of the events dispatched
        6681                 :   // and this is touchstart, or the first touchmove, widget should consume
        6682                 :   // other events that would be associated with this touch session
        6683               0 :   if (preventDefault && canPrevent) {
        6684               0 :     gPreventMouseEvents = true;
        6685                 :   }
        6686                 :
        6687               0 :   if (gPreventMouseEvents) {
        6688               0 :     *aStatus = nsEventStatus_eConsumeNoDefault;
        6689                 :   } else {
        6690               0 :     *aStatus = nsEventStatus_eIgnore;
        6691                 :   }
        6692               0 : }
        6693                 :
        6694                 : // Dispatch event to content only (NOT full processing)
        6695                 : // See also HandleEventWithTarget which does full event processing.
        6696                 : nsresult
        6697               0 : PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent, nsEvent* aEvent,
        6698                 :                                     nsEventStatus* aStatus)
        6699                 : {
        6700               0 :   nsresult rv = NS_OK;
        6701                 :
        6702               0 :   PushCurrentEventInfo(nsnull, aTargetContent);
        6703                 :
        6704                 :   // Bug 41013: Check if the event should be dispatched to content.
        6705                 :   // It's possible that we are in the middle of destroying the window
        6706                 :   // and the js context is out of date. This check detects the case
        6707                 :   // that caused a crash in bug 41013, but there may be a better way
        6708                 :   // to handle this situation!
        6709               0 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
        6710               0 :   if (container) {
        6711                 :
        6712                 :     // Dispatch event to content
        6713                 :     rv = nsEventDispatcher::Dispatch(aTargetContent, mPresContext, aEvent, nsnull,
        6714               0 :                                      aStatus);
        6715                 :   }
        6716                 :
        6717               0 :   PopCurrentEventInfo();
        6718               0 :   return rv;
        6719                 : }
        6720                 :
        6721                 : // See the method above.
        6722                 : nsresult
        6723               0 : PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent,
        6724                 :                                     nsIDOMEvent* aEvent,
        6725                 :                                     nsEventStatus* aStatus)
        6726                 : {
        6727               0 :   nsresult rv = NS_OK;
        6728                 :
        6729               0 :   PushCurrentEventInfo(nsnull, aTargetContent);
        6730               0 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
        6731               0 :   if (container) {
        6732                 :     rv = nsEventDispatcher::DispatchDOMEvent(aTargetContent, nsnull, aEvent,
        6733               0 :                                              mPresContext, aStatus);
        6734                 :   }
        6735                 :
        6736               0 :   PopCurrentEventInfo();
        6737               0 :   return rv;
        6738                 : }
        6739                 :
        6740                 : bool
        6741               0 : PresShell::AdjustContextMenuKeyEvent(nsMouseEvent* aEvent)
        6742                 : {
        6743                 : #ifdef MOZ_XUL
        6744                 :   // if a menu is open, open the context menu relative to the active item on the menu.
        6745               0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
        6746               0 :   if (pm) {
        6747               0 :     nsIFrame* popupFrame = pm->GetTopPopup(ePopupTypeMenu);
        6748               0 :     if (popupFrame) {
        6749                 :       nsIFrame* itemFrame =
        6750               0 :         (static_cast<nsMenuPopupFrame *>(popupFrame))->GetCurrentMenuItem();
        6751               0 :       if (!itemFrame)
        6752               0 :         itemFrame = popupFrame;
        6753                 :
        6754               0 :       nsCOMPtr<nsIWidget> widget = popupFrame->GetNearestWidget();
        6755               0 :       aEvent->widget = widget;
        6756               0 :       nsIntPoint widgetPoint = widget->WidgetToScreenOffset();
        6757               0 :       aEvent->refPoint = itemFrame->GetScreenRect().BottomLeft() - widgetPoint;
        6758                 :
        6759               0 :       mCurrentEventContent = itemFrame->GetContent();
        6760               0 :       mCurrentEventFrame = itemFrame;
        6761                 :
        6762               0 :       return true;
        6763                 :     }
        6764                 :   }
        6765                 : #endif
        6766                 :
        6767                 :   // If we're here because of the key-equiv for showing context menus, we
        6768                 :   // have to twiddle with the NS event to make sure the context menu comes
        6769                 :   // up in the upper left of the relevant content area before we create
        6770                 :   // the DOM event. Since we never call InitMouseEvent() on the event,
        6771                 :   // the client X/Y will be 0,0. We can make use of that if the widget is null.
        6772                 :   // Use the root view manager's widget since it's most likely to have one,
        6773                 :   // and the coordinates returned by GetCurrentItemAndPositionForElement
        6774                 :   // are relative to the widget of the root of the root view manager.
        6775               0 :   nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
        6776               0 :   aEvent->refPoint.x = 0;
        6777               0 :   aEvent->refPoint.y = 0;
        6778               0 :   if (rootPC) {
        6779               0 :     rootPC->PresShell()->GetViewManager()->
        6780               0 :       GetRootWidget(getter_AddRefs(aEvent->widget));
        6781                 :
        6782               0 :     if (aEvent->widget) {
        6783                 :       // default the refpoint to the topleft of our document
        6784               0 :       nsPoint offset(0, 0);
        6785               0 :       nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
        6786               0 :       if (rootFrame) {
        6787               0 :         nsIView* view = rootFrame->GetClosestView(&offset);
        6788               0 :         offset += view->GetOffsetToWidget(aEvent->widget);
        6789                 :         aEvent->refPoint =
        6790               0 :           offset.ToNearestPixels(mPresContext->AppUnitsPerDevPixel());
        6791                 :       }
        6792                 :     }
        6793                 :   } else {
        6794               0 :     aEvent->widget = nsnull;
        6795                 :   }
        6796                 :
        6797                 :   // see if we should use the caret position for the popup
        6798               0 :   nsIntPoint caretPoint;
        6799                 :   // Beware! This may flush notifications via synchronous
        6800                 :   // ScrollSelectionIntoView.
        6801               0 :   if (PrepareToUseCaretPosition(aEvent->widget, caretPoint)) {
        6802                 :     // caret position is good
        6803               0 :     aEvent->refPoint = caretPoint;
        6804               0 :     return true;
        6805                 :   }
        6806                 :
        6807                 :   // If we're here because of the key-equiv for showing context menus, we
        6808                 :   // have to reset the event target to the currently focused element. Get it
        6809                 :   // from the focus controller.
        6810               0 :   nsCOMPtr<nsIDOMElement> currentFocus;
        6811               0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
        6812               0 :   if (fm)
        6813               0 :     fm->GetFocusedElement(getter_AddRefs(currentFocus));
        6814                 :
        6815                 :   // Reset event coordinates relative to focused frame in view
        6816               0 :   if (currentFocus) {
        6817               0 :     nsCOMPtr<nsIContent> currentPointElement;
        6818                 :     GetCurrentItemAndPositionForElement(currentFocus,
        6819               0 :                                         getter_AddRefs(currentPointElement),
        6820                 :                                         aEvent->refPoint,
        6821               0 :                                         aEvent->widget);
        6822               0 :     if (currentPointElement) {
        6823               0 :       mCurrentEventContent = currentPointElement;
        6824               0 :       mCurrentEventFrame = nsnull;
        6825               0 :       GetCurrentEventFrame();
        6826                 :     }
        6827                 :   }
        6828                 :
        6829               0 :   return true;
        6830                 : }
        6831                 :
        6832                 : // PresShell::PrepareToUseCaretPosition
        6833                 : //
        6834                 : //    This checks to see if we should use the caret position for popup context
        6835                 : //    menus. Returns true if the caret position should be used, and the
        6836                 : //    coordinates of that position is returned in aTargetPt. This function
        6837                 : //    will also scroll the window as needed to make the caret visible.
        6838                 : //
        6839                 : //    The event widget should be the widget that generated the event, and
        6840                 : //    whose coordinate system the resulting event's refPoint should be
        6841                 : //    relative to.  The returned point is in device pixels realtive to the
        6842                 : //    widget passed in.
        6843                 : bool
        6844               0 : PresShell::PrepareToUseCaretPosition(nsIWidget* aEventWidget, nsIntPoint& aTargetPt)
        6845                 : {
        6846                 :   nsresult rv;
        6847                 :
        6848                 :   // check caret visibility
        6849               0 :   nsRefPtr<nsCaret> caret = GetCaret();
        6850               0 :   NS_ENSURE_TRUE(caret, false);
        6851                 :
        6852               0 :   bool caretVisible = false;
        6853               0 :   rv = caret->GetCaretVisible(&caretVisible);
        6854               0 :   if (NS_FAILED(rv) || ! caretVisible)
        6855               0 :     return false;
        6856                 :
        6857                 :   // caret selection, this is a temporary weak reference, so no refcounting is
        6858                 :   // needed
        6859               0 :   nsISelection* domSelection = caret->GetCaretDOMSelection();
        6860               0 :   NS_ENSURE_TRUE(domSelection, false);
        6861                 :
        6862                 :   // since the match could be an anonymous textnode inside a
        6863                 :   // <textarea> or text <input>, we need to get the outer frame
        6864                 :   // note: frames are not refcounted
        6865               0 :   nsIFrame* frame = nsnull; // may be NULL
        6866               0 :   nsCOMPtr<nsIDOMNode> node;
        6867               0 :   rv = domSelection->GetFocusNode(getter_AddRefs(node));
        6868               0 :   NS_ENSURE_SUCCESS(rv, false);
        6869               0 :   NS_ENSURE_TRUE(node, false);
        6870               0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(node));
        6871               0 :   if (content) {
        6872               0 :     nsIContent* nonNative = content->FindFirstNonNativeAnonymous();
        6873               0 :     content = nonNative;
        6874                 :   }
        6875                 :
        6876               0 :   if (content) {
        6877                 :     // It seems like ScrollSelectionIntoView should be enough, but it's
        6878                 :     // not. The problem is that scrolling the selection into view when it is
        6879                 :     // below the current viewport will align the top line of the frame exactly
        6880                 :     // with the bottom of the window. This is fine, BUT, the popup event causes
        6881                 :     // the control to be re-focused which does this exact call to
        6882                 :     // ScrollContentIntoView, which has a one-pixel disagreement of whether the
        6883                 :     // frame is actually in view. The result is that the frame is aligned with
        6884                 :     // the top of the window, but the menu is still at the bottom.
        6885                 :     //
        6886                 :     // Doing this call first forces the frame to be in view, eliminating the
        6887                 :     // problem. The only difference in the result is that if your cursor is in
        6888                 :     // an edit box below the current view, you'll get the edit box aligned with
        6889                 :     // the top of the window. This is arguably better behavior anyway.
        6890                 :     rv = ScrollContentIntoView(content, NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
        6891                 :                                         NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
        6892               0 :                                         SCROLL_OVERFLOW_HIDDEN);
        6893               0 :     NS_ENSURE_SUCCESS(rv, false);
        6894               0 :     frame = content->GetPrimaryFrame();
        6895               0 :     NS_WARN_IF_FALSE(frame, "No frame for focused content?");
        6896                 :   }
        6897                 :
        6898                 :   // Actually scroll the selection (ie caret) into view. Note that this must
        6899                 :   // be synchronous since we will be checking the caret position on the screen.
        6900                 :   //
        6901                 :   // Be easy about errors, and just don't scroll in those cases. Better to have
        6902                 :   // the correct menu at a weird place than the wrong menu.
        6903                 :   // After ScrollSelectionIntoView(), the pending notifications might be
        6904                 :   // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
        6905               0 :   nsCOMPtr<nsISelectionController> selCon;
        6906               0 :   if (frame)
        6907               0 :     frame->GetSelectionController(GetPresContext(), getter_AddRefs(selCon));
        6908                 :   else
        6909               0 :     selCon = static_cast<nsISelectionController *>(this);
        6910               0 :   if (selCon) {
        6911               0 :     rv = selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
        6912                 :                                          nsISelectionController::SELECTION_FOCUS_REGION,
        6913               0 :                                          nsISelectionController::SCROLL_SYNCHRONOUS);
        6914               0 :     NS_ENSURE_SUCCESS(rv, false);
        6915                 :   }
        6916                 :
        6917               0 :   nsPresContext* presContext = GetPresContext();
        6918                 :
        6919                 :   // get caret position relative to the closest view
        6920               0 :   nsRect caretCoords;
        6921               0 :   nsIFrame* caretFrame = caret->GetGeometry(domSelection, &caretCoords);
        6922               0 :   if (!caretFrame)
        6923               0 :     return false;
        6924               0 :   nsPoint viewOffset;
        6925               0 :   nsIView* view = caretFrame->GetClosestView(&viewOffset);
        6926               0 :   if (!view)
        6927               0 :     return false;
        6928                 :   // and then get the caret coords relative to the event widget
        6929               0 :   if (aEventWidget) {
        6930               0 :     viewOffset += view->GetOffsetToWidget(aEventWidget);
        6931                 :   }
        6932               0 :   caretCoords.MoveBy(viewOffset);
        6933                 :
        6934                 :   // caret coordinates are in app units, convert to pixels
        6935                 :   aTargetPt.x =
        6936               0 :     presContext->AppUnitsToDevPixels(caretCoords.x + caretCoords.width);
        6937                 :   aTargetPt.y =
        6938               0 :     presContext->AppUnitsToDevPixels(caretCoords.y + caretCoords.height);
        6939                 :
        6940                 :   // make sure rounding doesn't return a pixel which is outside the caret
        6941                 :   // (e.g. one line lower)
        6942               0 :   aTargetPt.y -= 1;
        6943                 :
        6944               0 :   return true;
        6945                 : }
        6946                 :
        6947                 : void
        6948               0 : PresShell::GetCurrentItemAndPositionForElement(nsIDOMElement *aCurrentEl,
        6949                 :                                                nsIContent** aTargetToUse,
        6950                 :                                                nsIntPoint& aTargetPt,
        6951                 :                                                nsIWidget *aRootWidget)
        6952                 : {
        6953               0 :   nsCOMPtr<nsIContent> focusedContent(do_QueryInterface(aCurrentEl));
        6954                 :   ScrollContentIntoView(focusedContent, NS_PRESSHELL_SCROLL_ANYWHERE,
        6955                 :                                         NS_PRESSHELL_SCROLL_ANYWHERE,
        6956               0 :                                         SCROLL_OVERFLOW_HIDDEN);
        6957                 :
        6958               0 :   nsPresContext* presContext = GetPresContext();
        6959                 :
        6960               0 :   bool istree = false, checkLineHeight = true;
        6961               0 :   nscoord extraTreeY = 0;
        6962                 :
        6963                 : #ifdef MOZ_XUL
        6964                 :   // Set the position to just underneath the current item for multi-select
        6965                 :   // lists or just underneath the selected item for single-select lists. If
        6966                 :   // the element is not a list, or there is no selection, leave the position
        6967                 :   // as is.
        6968               0 :   nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
        6969                 :   nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
        6970               0 :     do_QueryInterface(aCurrentEl);
        6971               0 :   if (multiSelect) {
        6972               0 :     checkLineHeight = false;
        6973                 :
        6974                 :     PRInt32 currentIndex;
        6975               0 :     multiSelect->GetCurrentIndex(&currentIndex);
        6976               0 :     if (currentIndex >= 0) {
        6977               0 :       nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(aCurrentEl));
        6978               0 :       if (xulElement) {
        6979               0 :         nsCOMPtr<nsIBoxObject> box;
        6980               0 :         xulElement->GetBoxObject(getter_AddRefs(box));
        6981               0 :         nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box));
        6982                 :         // Tree view special case (tree items have no frames)
        6983                 :         // Get the focused row and add its coordinates, which are already in pixels
        6984                 :         // XXX Boris, should we create a new interface so that this doesn't
        6985                 :         // need to know about trees? Something like nsINodelessChildCreator which
        6986                 :         // could provide the current focus coordinates?
        6987               0 :         if (treeBox) {
        6988               0 :           treeBox->EnsureRowIsVisible(currentIndex);
        6989                 :           PRInt32 firstVisibleRow, rowHeight;
        6990               0 :           treeBox->GetFirstVisibleRow(&firstVisibleRow);
        6991               0 :           treeBox->GetRowHeight(&rowHeight);
        6992                 :
        6993                 :           extraTreeY += presContext->CSSPixelsToAppUnits(
        6994               0 :                           (currentIndex - firstVisibleRow + 1) * rowHeight);
        6995               0 :           istree = true;
        6996                 :
        6997               0 :           nsCOMPtr<nsITreeColumns> cols;
        6998               0 :           treeBox->GetColumns(getter_AddRefs(cols));
        6999               0 :           if (cols) {
        7000               0 :             nsCOMPtr<nsITreeColumn> col;
        7001               0 :             cols->GetFirstColumn(getter_AddRefs(col));
        7002               0 :             if (col) {
        7003               0 :               nsCOMPtr<nsIDOMElement> colElement;
        7004               0 :               col->GetElement(getter_AddRefs(colElement));
        7005               0 :               nsCOMPtr<nsIContent> colContent(do_QueryInterface(colElement));
        7006               0 :               if (colContent) {
        7007               0 :                 nsIFrame* frame = colContent->GetPrimaryFrame();
        7008               0 :                 if (frame) {
        7009               0 :                   extraTreeY += frame->GetSize().height;
        7010                 :                 }
        7011                 :               }
        7012                 :             }
        7013                 :           }
        7014                 :         }
        7015                 :         else {
        7016               0 :           multiSelect->GetCurrentItem(getter_AddRefs(item));
        7017                 :         }
        7018                 :       }
        7019                 :     }
        7020                 :   }
        7021                 :   else {
        7022                 :     // don't check menulists as the selected item will be inside a popup.
        7023               0 :     nsCOMPtr<nsIDOMXULMenuListElement> menulist = do_QueryInterface(aCurrentEl);
        7024               0 :     if (!menulist) {
        7025                 :       nsCOMPtr<nsIDOMXULSelectControlElement> select =
        7026               0 :         do_QueryInterface(aCurrentEl);
        7027               0 :       if (select) {
        7028               0 :         checkLineHeight = false;
        7029               0 :         select->GetSelectedItem(getter_AddRefs(item));
        7030                 :       }
        7031                 :     }
        7032                 :   }
        7033                 :
        7034               0 :   if (item)
        7035               0 :     focusedContent = do_QueryInterface(item);
        7036                 : #endif
        7037                 :
        7038               0 :   nsIFrame *frame = focusedContent->GetPrimaryFrame();
        7039               0 :   if (frame) {
        7040               0 :     NS_ASSERTION(frame->PresContext() == GetPresContext(),
        7041                 :       "handling event for focused content that is not in our document?");
        7042                 :
        7043               0 :     nsPoint frameOrigin(0, 0);
        7044                 :
        7045                 :     // Get the frame's origin within its view
        7046               0 :     nsIView *view = frame->GetClosestView(&frameOrigin);
        7047               0 :     NS_ASSERTION(view, "No view for frame");
        7048                 :
        7049                 :     // View's origin relative the widget
        7050               0 :     if (aRootWidget) {
        7051               0 :       frameOrigin += view->GetOffsetToWidget(aRootWidget);
        7052                 :     }
        7053                 :
        7054                 :     // Start context menu down and to the right from top left of frame
        7055                 :     // use the lineheight. This is a good distance to move the context
        7056                 :     // menu away from the top left corner of the frame. If we always
        7057                 :     // used the frame height, the context menu could end up far away,
        7058                 :     // for example when we're focused on linked images.
        7059                 :     // On the other hand, we want to use the frame height if it's less
        7060                 :     // than the current line height, so that the context menu appears
        7061                 :     // associated with the correct frame.
        7062               0 :     nscoord extra = 0;
        7063               0 :     if (!istree) {
        7064               0 :       extra = frame->GetSize().height;
        7065               0 :       if (checkLineHeight) {
        7066                 :         nsIScrollableFrame *scrollFrame =
        7067               0 :           nsLayoutUtils::GetNearestScrollableFrame(frame);
        7068               0 :         if (scrollFrame) {
        7069               0 :           nsSize scrollAmount = scrollFrame->GetLineScrollAmount();
        7070               0 :           nsIFrame* f = do_QueryFrame(scrollFrame);
        7071               0 :           PRInt32 APD = presContext->AppUnitsPerDevPixel();
        7072               0 :           PRInt32 scrollAPD = f->PresContext()->AppUnitsPerDevPixel();
        7073               0 :           scrollAmount = scrollAmount.ConvertAppUnits(scrollAPD, APD);
        7074               0 :           if (extra > scrollAmount.height) {
        7075               0 :             extra = scrollAmount.height;
        7076                 :           }
        7077                 :         }
        7078                 :       }
        7079                 :     }
        7080                 :
        7081               0 :     aTargetPt.x = presContext->AppUnitsToDevPixels(frameOrigin.x);
        7082                 :     aTargetPt.y = presContext->AppUnitsToDevPixels(
        7083               0 :                     frameOrigin.y + extra + extraTreeY);
        7084                 :   }
        7085                 :
        7086               0 :   NS_IF_ADDREF(*aTargetToUse = focusedContent);
        7087               0 : }
        7088                 :
        7089                 : bool
        7090               0 : PresShell::ShouldIgnoreInvalidation()
        7091                 : {
        7092               0 :   return mPaintingSuppressed || !mIsActive;
        7093                 : }
        7094                 :
        7095                 : void
        7096               0 : PresShell::WillPaint(bool aWillSendDidPaint)
        7097                 : {
        7098                 :   // Don't bother doing anything if some viewmanager in our tree is painting
        7099                 :   // while we still have painting suppressed or we are not active.
        7100               0 :   if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
        7101               0 :     return;
        7102                 :   }
        7103                 :
        7104               0 :   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
        7105               0 :   if (!rootPresContext) {
        7106               0 :     return;
        7107                 :   }
        7108                 :
        7109               0 :   if (!aWillSendDidPaint && rootPresContext == mPresContext) {
        7110               0 :     rootPresContext->UpdatePluginGeometry();
        7111                 :   }
        7112               0 :   rootPresContext->FlushWillPaintObservers();
        7113               0 :   if (mIsDestroying)
        7114               0 :     return;
        7115                 :
        7116                 :   // Process reflows, if we have them, to reduce flicker due to invalidates and
        7117                 :   // reflow being interspersed.  Note that we _do_ allow this to be
        7118                 :   // interruptible; if we can't do all the reflows it's better to flicker a bit
        7119                 :   // than to freeze up.
        7120               0 :   FlushPendingNotifications(Flush_InterruptibleLayout);
        7121                 : }
        7122                 :
        7123                 : void
        7124               0 : PresShell::DidPaint()
        7125                 : {
        7126               0 :   if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
        7127               0 :     return;
        7128                 :   }
        7129                 :
        7130               0 :   NS_ASSERTION(mPresContext->IsRoot(), "Should only call DidPaint on root presshells");
        7131                 :
        7132               0 :   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
        7133                 :   // This should only be called on root presshells, but maybe if a document
        7134                 :   // tree is torn down we might not be a root presshell...
        7135               0 :   if (rootPresContext == mPresContext) {
        7136               0 :     rootPresContext->UpdatePluginGeometry();
        7137                 :   }
        7138                 :
        7139               0 :   if (nsContentUtils::XPConnect()) {
        7140               0 :     nsContentUtils::XPConnect()->NotifyDidPaint();
        7141                 :   }
        7142                 : }
        7143                 :
        7144                 : bool
        7145               0 : PresShell::IsVisible()
        7146                 : {
        7147               0 :   if (!mViewManager)
        7148               0 :     return false;
        7149                 :
        7150               0 :   nsIView* view = mViewManager->GetRootView();
        7151               0 :   if (!view)
        7152               0 :     return true;
        7153                 :
        7154                 :   // inner view of subdoc frame
        7155               0 :   view = view->GetParent();
        7156               0 :   if (!view)
        7157               0 :     return true;
        7158                 :
        7159                 :   // subdoc view
        7160               0 :   view = view->GetParent();
        7161               0 :   if (!view)
        7162               0 :     return true;
        7163                 :
        7164               0 :   nsIFrame* frame = view->GetFrame();
        7165               0 :   if (!frame)
        7166               0 :     return true;
        7167                 :
        7168               0 :   return frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY);
        7169                 : }
        7170                 :
        7171                 : nsresult
        7172               0 : PresShell::GetAgentStyleSheets(nsCOMArray<nsIStyleSheet>& aSheets)
        7173                 : {
        7174               0 :   aSheets.Clear();
        7175               0 :   PRInt32 sheetCount = mStyleSet->SheetCount(nsStyleSet::eAgentSheet);
        7176                 :
        7177               0 :   for (PRInt32 i = 0; i < sheetCount; ++i) {
        7178               0 :     nsIStyleSheet *sheet = mStyleSet->StyleSheetAt(nsStyleSet::eAgentSheet, i);
        7179               0 :     if (!aSheets.AppendObject(sheet))
        7180               0 :       return NS_ERROR_OUT_OF_MEMORY;
        7181                 :   }
        7182                 :
        7183               0 :   return NS_OK;
        7184                 : }
        7185                 :
        7186                 : nsresult
        7187               0 : PresShell::SetAgentStyleSheets(const nsCOMArray<nsIStyleSheet>& aSheets)
        7188                 : {
        7189               0 :   return mStyleSet->ReplaceSheets(nsStyleSet::eAgentSheet, aSheets);
        7190                 : }
        7191                 :
        7192                 : nsresult
        7193               0 : PresShell::AddOverrideStyleSheet(nsIStyleSheet *aSheet)
        7194                 : {
        7195               0 :   return mStyleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, aSheet);
        7196                 : }
        7197                 :
        7198                 : nsresult
        7199               0 : PresShell::RemoveOverrideStyleSheet(nsIStyleSheet *aSheet)
        7200                 : {
        7201               0 :   return mStyleSet->RemoveStyleSheet(nsStyleSet::eOverrideSheet, aSheet);
        7202                 : }
        7203                 :
        7204                 : static void
        7205               0 : FreezeElement(nsIContent *aContent, void * /* unused */)
        7206                 : {
        7207               0 :   nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent));
        7208               0 :   if (olc) {
        7209               0 :     olc->StopPluginInstance();
        7210                 :   }
        7211               0 : }
        7212                 :
        7213                 : static bool
        7214               0 : FreezeSubDocument(nsIDocument *aDocument, void *aData)
        7215                 : {
        7216               0 :   nsIPresShell *shell = aDocument->GetShell();
        7217               0 :   if (shell)
        7218               0 :     shell->Freeze();
        7219                 :
        7220               0 :   return true;
        7221                 : }
        7222                 :
        7223                 : void
        7224               0 : PresShell::Freeze()
        7225                 : {
        7226               0 :   MaybeReleaseCapturingContent();
        7227                 :
        7228               0 :   mDocument->EnumerateFreezableElements(FreezeElement, nsnull);
        7229                 :
        7230               0 :   if (mCaret) {
        7231               0 :     mCaret->SetCaretVisible(false);
        7232                 :   }
        7233                 :
        7234               0 :   mPaintingSuppressed = true;
        7235                 :
        7236               0 :   if (mDocument) {
        7237               0 :     mDocument->EnumerateSubDocuments(FreezeSubDocument, nsnull);
        7238                 :   }
        7239                 :
        7240               0 :   nsPresContext* presContext = GetPresContext();
        7241               0 :   if (presContext &&
        7242               0 :       presContext->RefreshDriver()->PresContext() == presContext) {
        7243               0 :     presContext->RefreshDriver()->Freeze();
        7244                 :   }
        7245                 :
        7246               0 :   if (presContext) {
        7247               0 :     nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
        7248               0 :     if (rootPresContext) {
        7249                 :       rootPresContext->
        7250               0 :         RootForgetUpdatePluginGeometryFrameForPresContext(mPresContext);
        7251                 :     }
        7252                 :   }
        7253                 :
        7254               0 :   mFrozen = true;
        7255               0 :   if (mDocument) {
        7256               0 :     UpdateImageLockingState();
        7257                 :   }
        7258               0 : }
        7259                 :
        7260                 : void
        7261               0 : PresShell::FireOrClearDelayedEvents(bool aFireEvents)
        7262                 : {
        7263               0 :   mNoDelayedMouseEvents = false;
        7264               0 :   mNoDelayedKeyEvents = false;
        7265               0 :   if (!aFireEvents) {
        7266               0 :     mDelayedEvents.Clear();
        7267               0 :     return;
        7268                 :   }
        7269                 :
        7270               0 :   if (mDocument) {
        7271               0 :     nsCOMPtr<nsIDocument> doc = mDocument;
        7272               0 :     while (!mIsDestroying && mDelayedEvents.Length() &&
        7273               0 :            !doc->EventHandlingSuppressed()) {
        7274               0 :       nsAutoPtr<nsDelayedEvent> ev(mDelayedEvents[0].forget());
        7275               0 :       mDelayedEvents.RemoveElementAt(0);
        7276               0 :       ev->Dispatch(this);
        7277                 :     }
        7278               0 :     if (!doc->EventHandlingSuppressed()) {
        7279               0 :       mDelayedEvents.Clear();
        7280                 :     }
        7281                 :   }
        7282                 : }
        7283                 :
        7284                 : static void
        7285               0 : ThawElement(nsIContent *aContent, void *aShell)
        7286                 : {
        7287               0 :   nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent));
        7288               0 :   if (olc) {
        7289               0 :     olc->AsyncStartPluginInstance();
        7290                 :   }
        7291               0 : }
        7292                 :
        7293                 : static bool
        7294               0 : ThawSubDocument(nsIDocument *aDocument, void *aData)
        7295                 : {
        7296               0 :   nsIPresShell *shell = aDocument->GetShell();
        7297               0 :   if (shell)
        7298               0 :     shell->Thaw();
        7299                 :
        7300               0 :   return true;
        7301                 : }
        7302                 :
        7303                 : void
        7304               0 : PresShell::Thaw()
        7305                 : {
        7306               0 :   nsPresContext* presContext = GetPresContext();
        7307               0 :   if (presContext &&
        7308               0 :       presContext->RefreshDriver()->PresContext() == presContext) {
        7309               0 :     presContext->RefreshDriver()->Thaw();
        7310                 :   }
        7311                 :
        7312               0 :   mDocument->EnumerateFreezableElements(ThawElement, this);
        7313                 :
        7314               0 :   if (mDocument)
        7315               0 :     mDocument->EnumerateSubDocuments(ThawSubDocument, nsnull);
        7316                 :
        7317                 :   // Get the activeness of our presshell, as this might have changed
        7318                 :   // while we were in the bfcache
        7319               0 :   QueryIsActive();
        7320                 :
        7321                 :   // We're now unfrozen
        7322               0 :   mFrozen = false;
        7323               0 :   UpdateImageLockingState();
        7324                 :
        7325               0 :   UnsuppressPainting();
        7326               0 : }
        7327                 :
        7328                 : //--------------------------------------------------------
        7329                 : // Start of protected and private methods on the PresShell
        7330                 : //--------------------------------------------------------
        7331                 :
        7332                 : void
        7333               0 : PresShell::MaybeScheduleReflow()
        7334                 : {
        7335               0 :   ASSERT_REFLOW_SCHEDULED_STATE();
        7336               0 :   if (mReflowScheduled || mIsDestroying || mIsReflowing ||
        7337               0 :       mDirtyRoots.Length() == 0)
        7338               0 :     return;
        7339                 :
        7340               0 :   if (!mPresContext->HasPendingInterrupt() || !ScheduleReflowOffTimer()) {
        7341               0 :     ScheduleReflow();
        7342                 :   }
        7343                 :
        7344               0 :   ASSERT_REFLOW_SCHEDULED_STATE();
        7345                 : }
        7346                 :
        7347                 : void
        7348               0 : PresShell::ScheduleReflow()
        7349                 : {
        7350               0 :   NS_PRECONDITION(!mReflowScheduled, "Why are we trying to schedule a reflow?");
        7351               0 :   ASSERT_REFLOW_SCHEDULED_STATE();
        7352                 :
        7353               0 :   if (GetPresContext()->RefreshDriver()->AddLayoutFlushObserver(this)) {
        7354               0 :     mReflowScheduled = true;
        7355                 :   }
        7356                 :
        7357               0 :   ASSERT_REFLOW_SCHEDULED_STATE();
        7358               0 : }
        7359                 :
        7360                 : nsresult
        7361               0 : PresShell::DidCauseReflow()
        7362                 : {
        7363               0 :   NS_ASSERTION(mChangeNestCount != 0, "Unexpected call to DidCauseReflow()");
        7364               0 :   --mChangeNestCount;
        7365               0 :   nsContentUtils::RemoveScriptBlocker();
        7366                 :
        7367               0 :   return NS_OK;
        7368                 : }
        7369                 :
        7370                 : void
        7371               0 : PresShell::WillDoReflow()
        7372                 : {
        7373                 :   // We just reflowed, tell the caret that its frame might have moved.
        7374                 :   // XXXbz that comment makes no sense
        7375               0 :   if (mCaret) {
        7376               0 :     mCaret->InvalidateOutsideCaret();
        7377                 :   }
        7378                 :
        7379               0 :   mPresContext->FlushUserFontSet();
        7380                 :
        7381               0 :   mFrameConstructor->BeginUpdate();
        7382               0 : }
        7383                 :
        7384                 : void
        7385               0 : PresShell::DidDoReflow(bool aInterruptible)
        7386                 : {
        7387               0 :   mFrameConstructor->EndUpdate();
        7388                 :
        7389               0 :   HandlePostedReflowCallbacks(aInterruptible);
        7390               0 :   if (sSynthMouseMove) {
        7391               0 :     SynthesizeMouseMove(false);
        7392                 :   }
        7393               0 :   if (mCaret) {
        7394                 :     // Update the caret's position now to account for any changes created by
        7395                 :     // the reflow.
        7396               0 :     mCaret->InvalidateOutsideCaret();
        7397               0 :     mCaret->UpdateCaretPosition();
        7398                 :   }
        7399               0 : }
        7400                 :
        7401                 : static PLDHashOperator
        7402               0 : MarkFramesDirtyToRoot(nsPtrHashKey<nsIFrame>* p, void* closure)
        7403                 : {
        7404               0 :   nsIFrame* target = static_cast<nsIFrame*>(closure);
        7405               0 :   for (nsIFrame* f = p->GetKey(); f && !NS_SUBTREE_DIRTY(f);
        7406                 :        f = f->GetParent()) {
        7407               0 :     f->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
        7408                 :
        7409               0 :     if (f == target) {
        7410               0 :       break;
        7411                 :     }
        7412                 :   }
        7413                 :
        7414               0 :   return PL_DHASH_NEXT;
        7415                 : }
        7416                 :
        7417                 : void
        7418               0 : PresShell::sReflowContinueCallback(nsITimer* aTimer, void* aPresShell)
        7419                 : {
        7420               0 :   nsRefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
        7421                 :
        7422               0 :   NS_PRECONDITION(aTimer == self->mReflowContinueTimer, "Unexpected timer");
        7423               0 :   self->mReflowContinueTimer = nsnull;
        7424               0 :   self->ScheduleReflow();
        7425               0 : }
        7426                 :
        7427                 : bool
        7428               0 : PresShell::ScheduleReflowOffTimer()
        7429                 : {
        7430               0 :   NS_PRECONDITION(!mReflowScheduled, "Shouldn't get here");
        7431               0 :   ASSERT_REFLOW_SCHEDULED_STATE();
        7432                 :
        7433               0 :   if (!mReflowContinueTimer) {
        7434               0 :     mReflowContinueTimer = do_CreateInstance("@mozilla.org/timer;1");
        7435               0 :     if (!mReflowContinueTimer ||
        7436               0 :         NS_FAILED(mReflowContinueTimer->
        7437                 :                     InitWithFuncCallback(sReflowContinueCallback, this, 30,
        7438                 :                                          nsITimer::TYPE_ONE_SHOT))) {
        7439               0 :       return false;
        7440                 :     }
        7441                 :   }
        7442               0 :   return true;
        7443                 : }
        7444                 :
        7445                 : bool
        7446               0 : PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
        7447                 : {
        7448                 :   NS_TIME_FUNCTION_WITH_DOCURL;
        7449               0 :   SAMPLE_LABEL("layout", "DoReflow");
        7450                 :
        7451               0 :   if (mReflowContinueTimer) {
        7452               0 :     mReflowContinueTimer->Cancel();
        7453               0 :     mReflowContinueTimer = nsnull;
        7454                 :   }
        7455                 :
        7456               0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
        7457                 :
        7458               0 :   nsRefPtr<nsRenderingContext> rcx = GetReferenceRenderingContext();
        7459               0 :   if (!rcx) {
        7460               0 :     NS_NOTREACHED("CreateRenderingContext failure");
        7461               0 :     return false;
        7462                 :   }
        7463                 :
        7464               0 :   NS_ASSERTION(!mPresContext->mCurrentInflationContainer,
        7465                 :                "current inflation container should be null");
        7466                 :   AutoRestore<nsIFrame*> restoreInflationContainer(mPresContext->
        7467               0 :                            mCurrentInflationContainer);
        7468               0 :   for (nsIFrame *f = target->GetParent(); f; f = f->GetParent()) {
        7469               0 :     if (nsLayoutUtils::IsContainerForFontSizeInflation(f)) {
        7470               0 :       NS_ASSERTION(!(f->GetStateBits() & NS_FRAME_IN_REFLOW),
        7471                 :                    "a frame outside should not be in reflow");
        7472               0 :       mPresContext->mCurrentInflationContainer = f;
        7473               0 :       mPresContext->mCurrentInflationContainerWidth = f->GetContentRect().width;
        7474               0 :       break;
        7475                 :     }
        7476                 :   }
        7477                 :
        7478                 : #ifdef DEBUG
        7479               0 :   mCurrentReflowRoot = target;
        7480                 : #endif
        7481                 :
        7482               0 :   target->WillReflow(mPresContext);
        7483                 :
        7484                 :   // If the target frame is the root of the frame hierarchy, then
        7485                 :   // use all the available space. If it's simply a `reflow root',
        7486                 :   // then use the target frame's size as the available space.
        7487               0 :   nsSize size;
        7488               0 :   if (target == rootFrame) {
        7489               0 :      size = mPresContext->GetVisibleArea().Size();
        7490                 :
        7491                 :      // target->GetRect() has the old size of the frame,
        7492                 :      // mPresContext->GetVisibleArea() has the new size.
        7493               0 :      target->InvalidateRectDifference(mPresContext->GetVisibleArea(),
        7494               0 :                                       target->GetRect());
        7495                 :   } else {
        7496               0 :      size = target->GetSize();
        7497                 :   }
        7498                 :
        7499               0 :   NS_ASSERTION(!target->GetNextInFlow() && !target->GetPrevInFlow(),
        7500                 :                "reflow roots should never split");
        7501                 :
        7502                 :   // Don't pass size directly to the reflow state, since a
        7503                 :   // constrained height implies page/column breaking.
        7504               0 :   nsSize reflowSize(size.width, NS_UNCONSTRAINEDSIZE);
        7505               0 :   nsHTMLReflowState reflowState(mPresContext, target, rcx, reflowSize);
        7506                 :
        7507               0 :   if (rootFrame == target) {
        7508                 :     // When the root frame is being reflowed with unconstrained height
        7509                 :     // (which happens when we're called from
        7510                 :     // DocumentViewerImpl::SizeToContent), we're effectively doing a
        7511                 :     // vertical resize, since it changes the meaning of percentage
        7512                 :     // heights even if no heights actually changed.  The same applies
        7513                 :     // when we reflow again after that computation.  This is an unusual
        7514                 :     // case, and isn't caught by nsHTMLReflowState::InitResizeFlags.
        7515               0 :     bool hasUnconstrainedHeight = size.height == NS_UNCONSTRAINEDSIZE;
        7516                 :
        7517               0 :     if (hasUnconstrainedHeight || mLastRootReflowHadUnconstrainedHeight) {
        7518               0 :       reflowState.mFlags.mVResize = true;
        7519                 :     }
        7520                 :
        7521               0 :     mLastRootReflowHadUnconstrainedHeight = hasUnconstrainedHeight;
        7522                 :   }
        7523                 :
        7524                 :   // fix the computed height
        7525               0 :   NS_ASSERTION(reflowState.mComputedMargin == nsMargin(0, 0, 0, 0),
        7526                 :                "reflow state should not set margin for reflow roots");
        7527               0 :   if (size.height != NS_UNCONSTRAINEDSIZE) {
        7528                 :     nscoord computedHeight =
        7529               0 :       size.height - reflowState.mComputedBorderPadding.TopBottom();
        7530               0 :     computedHeight = NS_MAX(computedHeight, 0);
        7531               0 :     reflowState.SetComputedHeight(computedHeight);
        7532                 :   }
        7533               0 :   NS_ASSERTION(reflowState.ComputedWidth() ==
        7534                 :                  size.width -
        7535                 :                    reflowState.mComputedBorderPadding.LeftRight(),
        7536                 :                "reflow state computed incorrect width");
        7537                 :
        7538               0 :   mPresContext->ReflowStarted(aInterruptible);
        7539               0 :   mIsReflowing = true;
        7540                 :
        7541                 :   nsReflowStatus status;
        7542               0 :   nsHTMLReflowMetrics desiredSize;
        7543               0 :   target->Reflow(mPresContext, desiredSize, reflowState, status);
        7544                 :
        7545                 :   // If an incremental reflow is initiated at a frame other than the
        7546                 :   // root frame, then its desired size had better not change!  If it's
        7547                 :   // initiated at the root, then the size better not change unless its
        7548                 :   // height was unconstrained to start with.
        7549               0 :   nsRect boundsRelativeToTarget = nsRect(0, 0, desiredSize.width, desiredSize.height);
        7550               0 :   NS_ASSERTION((target == rootFrame && size.height == NS_UNCONSTRAINEDSIZE) ||
        7551                 :                (desiredSize.width == size.width &&
        7552                 :                 desiredSize.height == size.height),
        7553                 :                "non-root frame's desired size changed during an "
        7554                 :                "incremental reflow");
        7555               0 :   NS_ASSERTION(target == rootFrame ||
        7556                 :                desiredSize.VisualOverflow().IsEqualInterior(boundsRelativeToTarget),
        7557                 :                "non-root reflow roots must not have visible overflow");
        7558               0 :   NS_ASSERTION(target == rootFrame ||
        7559                 :                desiredSize.ScrollableOverflow().IsEqualEdges(boundsRelativeToTarget),
        7560                 :                "non-root reflow roots must not have scrollable overflow");
        7561               0 :   NS_ASSERTION(status == NS_FRAME_COMPLETE,
        7562                 :                "reflow roots should never split");
        7563                 :
        7564               0 :   target->SetSize(boundsRelativeToTarget.Size());
        7565                 :
        7566                 :   // Always use boundsRelativeToTarget here, not desiredSize.GetVisualOverflowArea(),
        7567                 :   // because for root frames (where they could be different, since root frames
        7568                 :   // are allowed to have overflow) the root view bounds need to match the
        7569                 :   // viewport bounds; the view manager "window dimensions" code depends on it.
        7570                 :   nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, target,
        7571                 :                                              target->GetView(),
        7572               0 :                                              boundsRelativeToTarget);
        7573                 :   nsContainerFrame::SyncWindowProperties(mPresContext, target,
        7574               0 :                                          target->GetView());
        7575                 :
        7576               0 :   target->DidReflow(mPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
        7577               0 :   if (target == rootFrame && size.height == NS_UNCONSTRAINEDSIZE) {
        7578               0 :     mPresContext->SetVisibleArea(boundsRelativeToTarget);
        7579                 :   }
        7580                 :
        7581                 : #ifdef DEBUG
        7582               0 :   mCurrentReflowRoot = nsnull;
        7583                 : #endif
        7584                 :
        7585               0 :   NS_ASSERTION(mPresContext->HasPendingInterrupt() ||
        7586                 :                mFramesToDirty.Count() == 0,
        7587                 :                "Why do we need to dirty anything if not interrupted?");
        7588                 :
        7589               0 :   mIsReflowing = false;
        7590               0 :   bool interrupted = mPresContext->HasPendingInterrupt();
        7591               0 :   if (interrupted) {
        7592                 :     // Make sure target gets reflowed again.
        7593               0 :     mFramesToDirty.EnumerateEntries(&MarkFramesDirtyToRoot, target);
        7594               0 :     NS_ASSERTION(NS_SUBTREE_DIRTY(target), "Why is the target not dirty?");
        7595               0 :     mDirtyRoots.AppendElement(target);
        7596               0 :     mDocument->SetNeedLayoutFlush();
        7597                 :
        7598                 :     // Clear mFramesToDirty after we've done the NS_SUBTREE_DIRTY(target)
        7599                 :     // assertion so that if it fails it's easier to see what's going on.
        7600                 : #ifdef NOISY_INTERRUPTIBLE_REFLOW
        7601                 :     printf("mFramesToDirty.Count() == %u\n", mFramesToDirty.Count());
        7602                 : #endif /* NOISY_INTERRUPTIBLE_REFLOW */
        7603               0 :     mFramesToDirty.Clear();
        7604                 :
        7605                 :     // Any FlushPendingNotifications with interruptible reflows
        7606                 :     // should be suppressed now. We don't want to do extra reflow work
        7607                 :     // before our reflow event happens.
        7608               0 :     mSuppressInterruptibleReflows = true;
        7609               0 :     MaybeScheduleReflow();
        7610                 :   }
        7611                 :
        7612               0 :   nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
        7613               0 :   if (rootPC) {
        7614               0 :     rootPC->RequestUpdatePluginGeometry(target);
        7615                 :   }
        7616                 :
        7617               0 :   return !interrupted;
        7618                 : }
        7619                 :
        7620                 : #ifdef DEBUG
        7621                 : void
        7622               0 : PresShell::DoVerifyReflow()
        7623                 : {
        7624               0 :   if (GetVerifyReflowEnable()) {
        7625                 :     // First synchronously render what we have so far so that we can
        7626                 :     // see it.
        7627               0 :     nsIView* rootView = mViewManager->GetRootView();
        7628               0 :     mViewManager->InvalidateView(rootView);
        7629                 :
        7630               0 :     FlushPendingNotifications(Flush_Layout);
        7631               0 :     mInVerifyReflow = true;
        7632               0 :     bool ok = VerifyIncrementalReflow();
        7633               0 :     mInVerifyReflow = false;
        7634               0 :     if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
        7635                 :       printf("ProcessReflowCommands: finished (%s)\n",
        7636               0 :              ok ? "ok" : "failed");
        7637                 :     }
        7638                 :
        7639               0 :     if (!mDirtyRoots.IsEmpty()) {
        7640               0 :       printf("XXX yikes! reflow commands queued during verify-reflow\n");
        7641                 :     }
        7642                 :   }
        7643               0 : }
        7644                 : #endif
        7645                 :
        7646                 : bool
        7647               0 : PresShell::ProcessReflowCommands(bool aInterruptible)
        7648                 : {
        7649               0 :   if (mDirtyRoots.IsEmpty() && !mShouldUnsuppressPainting) {
        7650                 :     // Nothing to do; bail out
        7651               0 :     return true;
        7652                 :   }
        7653                 :
        7654                 :   NS_TIME_FUNCTION_WITH_DOCURL;
        7655               0 :   mozilla::TimeStamp timerStart = mozilla::TimeStamp::Now();
        7656               0 :   bool interrupted = false;
        7657               0 :   if (!mDirtyRoots.IsEmpty()) {
        7658                 :
        7659                 : #ifdef DEBUG
        7660               0 :     if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
        7661               0 :       printf("ProcessReflowCommands: begin incremental reflow\n");
        7662                 :     }
        7663                 : #endif
        7664                 :
        7665                 :     // If reflow is interruptible, then make a note of our deadline.
        7666                 :     const PRIntervalTime deadline = aInterruptible
        7667               0 :         ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime)
        7668               0 :         : (PRIntervalTime)0;
        7669                 :
        7670                 :     // Scope for the reflow entry point
        7671                 :     {
        7672               0 :       nsAutoScriptBlocker scriptBlocker;
        7673               0 :       WillDoReflow();
        7674               0 :       AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
        7675               0 :       nsIViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
        7676                 :
        7677               0 :       do {
        7678                 :         // Send an incremental reflow notification to the target frame.
        7679               0 :         PRInt32 idx = mDirtyRoots.Length() - 1;
        7680               0 :         nsIFrame *target = mDirtyRoots[idx];
        7681               0 :         mDirtyRoots.RemoveElementAt(idx);
        7682                 :
        7683               0 :         if (!NS_SUBTREE_DIRTY(target)) {
        7684                 :           // It's not dirty anymore, which probably means the notification
        7685                 :           // was posted in the middle of a reflow (perhaps with a reflow
        7686                 :           // root in the middle).  Don't do anything.
        7687               0 :           continue;
        7688                 :         }
        7689                 :
        7690               0 :         interrupted = !DoReflow(target, aInterruptible);
        7691                 :
        7692                 :         // Keep going until we're out of reflow commands, or we've run
        7693                 :         // past our deadline, or we're interrupted.
        7694               0 :       } while (!interrupted && !mDirtyRoots.IsEmpty() &&
        7695               0 :                (!aInterruptible || PR_IntervalNow() < deadline));
        7696                 :
        7697               0 :       interrupted = !mDirtyRoots.IsEmpty();
        7698                 :     }
        7699                 :
        7700                 :     // Exiting the scriptblocker might have killed us
        7701               0 :     if (!mIsDestroying) {
        7702               0 :       DidDoReflow(aInterruptible);
        7703                 :     }
        7704                 :
        7705                 :     // DidDoReflow might have killed us
        7706               0 :     if (!mIsDestroying) {
        7707                 : #ifdef DEBUG
        7708               0 :       if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
        7709                 :         printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n",
        7710               0 :                (void*)this);
        7711                 :       }
        7712               0 :       DoVerifyReflow();
        7713                 : #endif
        7714                 :
        7715                 :       // If any new reflow commands were enqueued during the reflow, schedule
        7716                 :       // another reflow event to process them.  Note that we want to do this
        7717                 :       // after DidDoReflow(), since that method can change whether there are
        7718                 :       // dirty roots around by flushing, and there's no point in posting a
        7719                 :       // reflow event just to have the flush revoke it.
        7720               0 :       if (!mDirtyRoots.IsEmpty()) {
        7721               0 :         MaybeScheduleReflow();
        7722                 :         // And tell our document that we might need flushing
        7723               0 :         mDocument->SetNeedLayoutFlush();
        7724                 :       }
        7725                 :     }
        7726                 :   }
        7727                 :
        7728               0 :   if (!mIsDestroying && mShouldUnsuppressPainting &&
        7729               0 :       mDirtyRoots.IsEmpty()) {
        7730                 :     // We only unlock if we're out of reflows.  It's pointless
        7731                 :     // to unlock if reflows are still pending, since reflows
        7732                 :     // are just going to thrash the frames around some more.  By
        7733                 :     // waiting we avoid an overeager "jitter" effect.
        7734               0 :     mShouldUnsuppressPainting = false;
        7735               0 :     UnsuppressAndInvalidate();
        7736                 :   }
        7737                 :
        7738               0 :   if (mDocument->GetRootElement()) {
        7739                 :     Telemetry::ID id;
        7740               0 :     if (mDocument->GetRootElement()->IsXUL()) {
        7741                 :       id = mIsActive
        7742                 :         ? Telemetry::XUL_FOREGROUND_REFLOW_MS
        7743               0 :         : Telemetry::XUL_BACKGROUND_REFLOW_MS;
        7744                 :     } else {
        7745                 :       id = mIsActive
        7746                 :         ? Telemetry::HTML_FOREGROUND_REFLOW_MS
        7747               0 :         : Telemetry::HTML_BACKGROUND_REFLOW_MS;
        7748                 :     }
        7749               0 :     Telemetry::AccumulateTimeDelta(id, timerStart);
        7750                 :   }
        7751                 :
        7752               0 :   return !interrupted;
        7753                 : }
        7754                 :
        7755                 : #ifdef MOZ_XUL
        7756                 : /*
        7757                 :  * It's better to add stuff to the |DidSetStyleContext| method of the
        7758                 :  * relevant frames than adding it here.  These methods should (ideally,
        7759                 :  * anyway) go away.
        7760                 :  */
        7761                 :
        7762                 : // Return value says whether to walk children.
        7763                 : typedef bool (* frameWalkerFn)(nsIFrame *aFrame, void *aClosure);
        7764                 :
        7765                 : static bool
        7766               0 : ReResolveMenusAndTrees(nsIFrame *aFrame, void *aClosure)
        7767                 : {
        7768                 :   // Trees have a special style cache that needs to be flushed when
        7769                 :   // the theme changes.
        7770               0 :   nsTreeBodyFrame *treeBody = do_QueryFrame(aFrame);
        7771               0 :   if (treeBody)
        7772               0 :     treeBody->ClearStyleAndImageCaches();
        7773                 :
        7774                 :   // We deliberately don't re-resolve style on a menu's popup
        7775                 :   // sub-content, since doing so slows menus to a crawl.  That means we
        7776                 :   // have to special-case them on a skin switch, and ensure that the
        7777                 :   // popup frames just get destroyed completely.
        7778               0 :   if (aFrame && aFrame->GetType() == nsGkAtoms::menuFrame)
        7779               0 :     (static_cast<nsMenuFrame *>(aFrame))->CloseMenu(true);
        7780               0 :   return true;
        7781                 : }
        7782                 :
        7783                 : static bool
        7784               0 : ReframeImageBoxes(nsIFrame *aFrame, void *aClosure)
        7785                 : {
        7786               0 :   nsStyleChangeList *list = static_cast<nsStyleChangeList*>(aClosure);
        7787               0 :   if (aFrame->GetType() == nsGkAtoms::imageBoxFrame) {
        7788                 :     list->AppendChange(aFrame, aFrame->GetContent(),
        7789               0 :                        NS_STYLE_HINT_FRAMECHANGE);
        7790               0 :     return false; // don't walk descendants
        7791                 :   }
        7792               0 :   return true; // walk descendants
        7793                 : }
        7794                 :
        7795                 : static void
        7796               0 : WalkFramesThroughPlaceholders(nsPresContext *aPresContext, nsIFrame *aFrame,
        7797                 :                               frameWalkerFn aFunc, void *aClosure)
        7798                 : {
        7799               0 :   bool walkChildren = (*aFunc)(aFrame, aClosure);
        7800               0 :   if (!walkChildren)
        7801               0 :     return;
        7802                 :
        7803               0 :   nsIFrame::ChildListIterator lists(aFrame);
        7804               0 :   for (; !lists.IsDone(); lists.Next()) {
        7805               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
        7806               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
        7807               0 :       nsIFrame* child = childFrames.get();
        7808               0 :       if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
        7809                 :         // only do frames that are in flow, and recur through the
        7810                 :         // out-of-flows of placeholders.
        7811                 :         WalkFramesThroughPlaceholders(aPresContext,
        7812                 :                                       nsPlaceholderFrame::GetRealFrameFor(child),
        7813               0 :                                       aFunc, aClosure);
        7814                 :       }
        7815                 :     }
        7816                 :   }
        7817                 : }
        7818                 : #endif
        7819                 :
        7820                 : NS_IMETHODIMP
        7821               0 : PresShell::Observe(nsISupports* aSubject,
        7822                 :                    const char* aTopic,
        7823                 :                    const PRUnichar* aData)
        7824                 : {
        7825                 : #ifdef MOZ_XUL
        7826               0 :   if (!nsCRT::strcmp(aTopic, "chrome-flush-skin-caches")) {
        7827               0 :     nsIFrame *rootFrame = mFrameConstructor->GetRootFrame();
        7828                 :     // Need to null-check because "chrome-flush-skin-caches" can happen
        7829                 :     // at interesting times during startup.
        7830               0 :     if (rootFrame) {
        7831               0 :       NS_ASSERTION(mViewManager, "View manager must exist");
        7832                 :
        7833               0 :       nsWeakFrame weakRoot(rootFrame);
        7834                 :       // Have to make sure that the content notifications are flushed before we
        7835                 :       // start messing with the frame model; otherwise we can get content doubling.
        7836               0 :       mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
        7837                 :
        7838               0 :       if (weakRoot.IsAlive()) {
        7839                 :         WalkFramesThroughPlaceholders(mPresContext, rootFrame,
        7840               0 :                                       &ReResolveMenusAndTrees, nsnull);
        7841                 :
        7842                 :         // Because "chrome:" URL equality is messy, reframe image box
        7843                 :         // frames (hack!).
        7844               0 :         nsStyleChangeList changeList;
        7845                 :         WalkFramesThroughPlaceholders(mPresContext, rootFrame,
        7846               0 :                                       ReframeImageBoxes, &changeList);
        7847                 :         // Mark ourselves as not safe to flush while we're doing frame
        7848                 :         // construction.
        7849                 :         {
        7850               0 :           nsAutoScriptBlocker scriptBlocker;
        7851               0 :           ++mChangeNestCount;
        7852               0 :           mFrameConstructor->ProcessRestyledFrames(changeList);
        7853               0 :           --mChangeNestCount;
        7854                 :         }
        7855                 :       }
        7856                 :     }
        7857               0 :     return NS_OK;
        7858                 :   }
        7859                 : #endif
        7860                 :
        7861               0 :   if (!nsCRT::strcmp(aTopic, "agent-sheet-added") && mStyleSet) {
        7862               0 :     AddAgentSheet(aSubject);
        7863               0 :     return NS_OK;
        7864                 :   }
        7865                 :
        7866               0 :   if (!nsCRT::strcmp(aTopic, "user-sheet-added") && mStyleSet) {
        7867               0 :     AddUserSheet(aSubject);
        7868               0 :     return NS_OK;
        7869                 :   }
        7870                 :
        7871               0 :   if (!nsCRT::strcmp(aTopic, "agent-sheet-removed") && mStyleSet) {
        7872               0 :     RemoveSheet(nsStyleSet::eAgentSheet, aSubject);
        7873               0 :     return NS_OK;
        7874                 :   }
        7875                 :
        7876               0 :   if (!nsCRT::strcmp(aTopic, "user-sheet-removed") && mStyleSet) {
        7877               0 :     RemoveSheet(nsStyleSet::eUserSheet, aSubject);
        7878               0 :     return NS_OK;
        7879                 :   }
        7880                 :
        7881               0 :   NS_WARNING("unrecognized topic in PresShell::Observe");
        7882               0 :   return NS_ERROR_FAILURE;
        7883                 : }
        7884                 :
        7885                 : bool
        7886               0 : nsIPresShell::AddRefreshObserverInternal(nsARefreshObserver* aObserver,
        7887                 :                                          mozFlushType aFlushType)
        7888                 : {
        7889               0 :   nsPresContext* presContext = GetPresContext();
        7890                 :   return presContext ? presContext->RefreshDriver()->
        7891               0 :     AddRefreshObserver(aObserver, aFlushType) : false;
        7892                 : }
        7893                 :
        7894                 : /* virtual */ bool
        7895               0 : nsIPresShell::AddRefreshObserverExternal(nsARefreshObserver* aObserver,
        7896                 :                                          mozFlushType aFlushType)
        7897                 : {
        7898               0 :   return AddRefreshObserverInternal(aObserver, aFlushType);
        7899                 : }
        7900                 :
        7901                 : bool
        7902               0 : nsIPresShell::RemoveRefreshObserverInternal(nsARefreshObserver* aObserver,
        7903                 :                                             mozFlushType aFlushType)
        7904                 : {
        7905               0 :   nsPresContext* presContext = GetPresContext();
        7906                 :   return presContext ? presContext->RefreshDriver()->
        7907               0 :     RemoveRefreshObserver(aObserver, aFlushType) : false;
        7908                 : }
        7909                 :
        7910                 : /* virtual */ bool
        7911               0 : nsIPresShell::RemoveRefreshObserverExternal(nsARefreshObserver* aObserver,
        7912                 :                                             mozFlushType aFlushType)
        7913                 : {
        7914               0 :   return RemoveRefreshObserverInternal(aObserver, aFlushType);
        7915                 : }
        7916                 :
        7917                 : //------------------------------------------------------
        7918                 : // End of protected and private methods on the PresShell
        7919                 : //------------------------------------------------------
        7920                 :
        7921                 : // Start of DEBUG only code
        7922                 :
        7923                 : #ifdef NS_DEBUG
        7924                 : #include "nsIURL.h"
        7925                 : #include "nsILinkHandler.h"
        7926                 :
        7927                 : static NS_DEFINE_CID(kViewManagerCID, NS_VIEW_MANAGER_CID);
        7928                 :
        7929                 : static void
        7930               0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg)
        7931                 : {
        7932               0 :   nsAutoString n1, n2;
        7933               0 :   if (k1) {
        7934               0 :     k1->GetFrameName(n1);
        7935                 :   } else {
        7936               0 :     n1.Assign(NS_LITERAL_STRING("(null)"));
        7937                 :   }
        7938                 :
        7939               0 :   if (k2) {
        7940               0 :     k2->GetFrameName(n2);
        7941                 :   } else {
        7942               0 :     n2.Assign(NS_LITERAL_STRING("(null)"));
        7943                 :   }
        7944                 :
        7945                 :   printf("verifyreflow: %s %p != %s %p  %s\n",
        7946               0 :          NS_LossyConvertUTF16toASCII(n1).get(), (void*)k1,
        7947               0 :          NS_LossyConvertUTF16toASCII(n2).get(), (void*)k2, aMsg);
        7948               0 : }
        7949                 :
        7950                 : static void
        7951               0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
        7952                 :                  const nsRect& r1, const nsRect& r2)
        7953                 : {
        7954               0 :   printf("VerifyReflow Error:\n");
        7955               0 :   nsAutoString name;
        7956                 :
        7957               0 :   if (k1) {
        7958               0 :     k1->GetFrameName(name);
        7959               0 :     printf("  %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k1);
        7960                 :   }
        7961               0 :   printf("{%d, %d, %d, %d} != \n", r1.x, r1.y, r1.width, r1.height);
        7962                 :
        7963               0 :   if (k2) {
        7964               0 :     k2->GetFrameName(name);
        7965               0 :     printf("  %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k2);
        7966                 :   }
        7967                 :   printf("{%d, %d, %d, %d}\n  %s\n",
        7968               0 :          r2.x, r2.y, r2.width, r2.height, aMsg);
        7969               0 : }
        7970                 :
        7971                 : static void
        7972               0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
        7973                 :                  const nsIntRect& r1, const nsIntRect& r2)
        7974                 : {
        7975               0 :   printf("VerifyReflow Error:\n");
        7976               0 :   nsAutoString name;
        7977                 :
        7978               0 :   if (k1) {
        7979               0 :     k1->GetFrameName(name);
        7980               0 :     printf("  %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k1);
        7981                 :   }
        7982               0 :   printf("{%d, %d, %d, %d} != \n", r1.x, r1.y, r1.width, r1.height);
        7983                 :
        7984               0 :   if (k2) {
        7985               0 :     k2->GetFrameName(name);
        7986               0 :     printf("  %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k2);
        7987                 :   }
        7988                 :   printf("{%d, %d, %d, %d}\n  %s\n",
        7989               0 :          r2.x, r2.y, r2.width, r2.height, aMsg);
        7990               0 : }
        7991                 :
        7992                 : static bool
        7993               0 : CompareTrees(nsPresContext* aFirstPresContext, nsIFrame* aFirstFrame,
        7994                 :              nsPresContext* aSecondPresContext, nsIFrame* aSecondFrame)
        7995                 : {
        7996               0 :   if (!aFirstPresContext || !aFirstFrame || !aSecondPresContext || !aSecondFrame)
        7997               0 :     return true;
        7998                 :   // XXX Evil hack to reduce false positives; I can't seem to figure
        7999                 :   // out how to flush scrollbar changes correctly
        8000                 :   //if (aFirstFrame->GetType() == nsGkAtoms::scrollbarFrame)
        8001                 :   //  return true;
        8002               0 :   bool ok = true;
        8003               0 :   nsIFrame::ChildListIterator lists1(aFirstFrame);
        8004               0 :   nsIFrame::ChildListIterator lists2(aSecondFrame);
        8005               0 :   do {
        8006               0 :     const nsFrameList& kids1 = !lists1.IsDone() ? lists1.CurrentList() : nsFrameList();
        8007               0 :     const nsFrameList& kids2 = !lists2.IsDone() ? lists2.CurrentList() : nsFrameList();
        8008               0 :     PRInt32 l1 = kids1.GetLength();
        8009               0 :     PRInt32 l2 = kids2.GetLength();;
        8010               0 :     if (l1 != l2) {
        8011               0 :       ok = false;
        8012                 :       LogVerifyMessage(kids1.FirstChild(), kids2.FirstChild(),
        8013               0 :                        "child counts don't match: ");
        8014               0 :       printf("%d != %d\n", l1, l2);
        8015               0 :       if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
        8016                 :         break;
        8017                 :       }
        8018                 :     }
        8019                 :
        8020               0 :     nsIntRect r1, r2;
        8021                 :     nsIView* v1, *v2;
        8022               0 :     for (nsFrameList::Enumerator e1(kids1), e2(kids2);
        8023                 :          ;
        8024               0 :          e1.Next(), e2.Next()) {
        8025               0 :       nsIFrame* k1 = e1.get();
        8026               0 :       nsIFrame* k2 = e2.get();
        8027               0 :       if (((nsnull == k1) && (nsnull != k2)) ||
        8028                 :           ((nsnull != k1) && (nsnull == k2))) {
        8029               0 :         ok = false;
        8030               0 :         LogVerifyMessage(k1, k2, "child lists are different\n");
        8031               0 :         break;
        8032                 :       }
        8033               0 :       else if (nsnull != k1) {
        8034                 :         // Verify that the frames are the same size
        8035               0 :         if (!k1->GetRect().IsEqualInterior(k2->GetRect())) {
        8036               0 :           ok = false;
        8037               0 :           LogVerifyMessage(k1, k2, "(frame rects)", k1->GetRect(), k2->GetRect());
        8038                 :         }
        8039                 :
        8040                 :         // Make sure either both have views or neither have views; if they
        8041                 :         // do have views, make sure the views are the same size. If the
        8042                 :         // views have widgets, make sure they both do or neither does. If
        8043                 :         // they do, make sure the widgets are the same size.
        8044               0 :         v1 = k1->GetView();
        8045               0 :         v2 = k2->GetView();
        8046               0 :         if (((nsnull == v1) && (nsnull != v2)) ||
        8047                 :             ((nsnull != v1) && (nsnull == v2))) {
        8048               0 :           ok = false;
        8049               0 :           LogVerifyMessage(k1, k2, "child views are not matched\n");
        8050                 :         }
        8051               0 :         else if (nsnull != v1) {
        8052               0 :           if (!v1->GetBounds().IsEqualInterior(v2->GetBounds())) {
        8053               0 :             LogVerifyMessage(k1, k2, "(view rects)", v1->GetBounds(), v2->GetBounds());
        8054                 :           }
        8055                 :
        8056               0 :           nsIWidget* w1 = v1->GetWidget();
        8057               0 :           nsIWidget* w2 = v2->GetWidget();
        8058               0 :           if (((nsnull == w1) && (nsnull != w2)) ||
        8059                 :               ((nsnull != w1) && (nsnull == w2))) {
        8060               0 :             ok = false;
        8061               0 :             LogVerifyMessage(k1, k2, "child widgets are not matched\n");
        8062                 :           }
        8063               0 :           else if (nsnull != w1) {
        8064               0 :             w1->GetBounds(r1);
        8065               0 :             w2->GetBounds(r2);
        8066               0 :             if (!r1.IsEqualEdges(r2)) {
        8067               0 :               LogVerifyMessage(k1, k2, "(widget rects)", r1, r2);
        8068                 :             }
        8069                 :           }
        8070                 :         }
        8071               0 :         if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
        8072               0 :           break;
        8073                 :         }
        8074                 :
        8075                 :         // XXX Should perhaps compare their float managers.
        8076                 :
        8077                 :         // Compare the sub-trees too
        8078               0 :         if (!CompareTrees(aFirstPresContext, k1, aSecondPresContext, k2)) {
        8079               0 :           ok = false;
        8080               0 :           if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
        8081               0 :             break;
        8082                 :           }
        8083                 :         }
        8084                 :       }
        8085                 :       else {
        8086               0 :         break;
        8087                 :       }
        8088                 :     }
        8089               0 :     if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
        8090                 :       break;
        8091                 :     }
        8092                 :
        8093               0 :     lists1.Next();
        8094               0 :     lists2.Next();
        8095               0 :     if (lists1.IsDone() != lists2.IsDone() ||
        8096               0 :         (!lists1.IsDone() && lists1.CurrentID() != lists2.CurrentID())) {
        8097               0 :       if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
        8098               0 :         ok = false;
        8099                 :       }
        8100                 :       LogVerifyMessage(kids1.FirstChild(), kids2.FirstChild(),
        8101               0 :                        "child list names are not matched: ");
        8102                 :       fprintf(stdout, "%s != %s\n",
        8103               0 :               !lists1.IsDone() ? mozilla::layout::ChildListName(lists1.CurrentID()) : "(null)",
        8104               0 :               !lists2.IsDone() ? mozilla::layout::ChildListName(lists2.CurrentID()) : "(null)");
        8105                 :       break;
        8106                 :     }
        8107               0 :   } while (ok && !lists1.IsDone());
        8108                 :
        8109               0 :   return ok;
        8110                 : }
        8111                 : #endif
        8112                 :
        8113                 : #if 0
        8114                 : static nsIFrame*
        8115                 : FindTopFrame(nsIFrame* aRoot)
        8116                 : {
        8117                 :   if (aRoot) {
        8118                 :     nsIContent* content = aRoot->GetContent();
        8119                 :     if (content) {
        8120                 :       nsIAtom* tag;
        8121                 :       content->GetTag(tag);
        8122                 :       if (nsnull != tag) {
        8123                 :         NS_RELEASE(tag);
        8124                 :         return aRoot;
        8125                 :       }
        8126                 :     }
        8127                 :
        8128                 :     // Try one of the children
        8129                 :     nsIFrame* kid = aRoot->GetFirstPrincipalChild();
        8130                 :     while (nsnull != kid) {
        8131                 :       nsIFrame* result = FindTopFrame(kid);
        8132                 :       if (nsnull != result) {
        8133                 :         return result;
        8134                 :       }
        8135                 :       kid = kid->GetNextSibling();
        8136                 :     }
        8137                 :   }
        8138                 :   return nsnull;
        8139                 : }
        8140                 : #endif
        8141                 :
        8142                 :
        8143                 : #ifdef DEBUG
        8144                 :
        8145                 : nsStyleSet*
        8146               0 : PresShell::CloneStyleSet(nsStyleSet* aSet)
        8147                 : {
        8148               0 :   nsStyleSet *clone = new nsStyleSet();
        8149                 :
        8150               0 :   PRInt32 i, n = aSet->SheetCount(nsStyleSet::eOverrideSheet);
        8151               0 :   for (i = 0; i < n; i++) {
        8152               0 :     nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eOverrideSheet, i);
        8153               0 :     if (ss)
        8154               0 :       clone->AppendStyleSheet(nsStyleSet::eOverrideSheet, ss);
        8155                 :   }
        8156                 :
        8157                 :   // The document expects to insert document stylesheets itself
        8158                 : #if 0
        8159                 :   n = aSet->SheetCount(nsStyleSet::eDocSheet);
        8160                 :   for (i = 0; i < n; i++) {
        8161                 :     nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eDocSheet, i);
        8162                 :     if (ss)
        8163                 :       clone->AddDocStyleSheet(ss, mDocument);
        8164                 :   }
        8165                 : #endif
        8166                 :
        8167               0 :   n = aSet->SheetCount(nsStyleSet::eUserSheet);
        8168               0 :   for (i = 0; i < n; i++) {
        8169               0 :     nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eUserSheet, i);
        8170               0 :     if (ss)
        8171               0 :       clone->AppendStyleSheet(nsStyleSet::eUserSheet, ss);
        8172                 :   }
        8173                 :
        8174               0 :   n = aSet->SheetCount(nsStyleSet::eAgentSheet);
        8175               0 :   for (i = 0; i < n; i++) {
        8176               0 :     nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eAgentSheet, i);
        8177               0 :     if (ss)
        8178               0 :       clone->AppendStyleSheet(nsStyleSet::eAgentSheet, ss);
        8179                 :   }
        8180               0 :   return clone;
        8181                 : }
        8182                 :
        8183                 : #ifdef DEBUG_Eli
        8184                 : static nsresult
        8185                 : DumpToPNG(nsIPresShell* shell, nsAString& name) {
        8186                 :   PRInt32 width=1000, height=1000;
        8187                 :   nsRect r(0, 0, shell->GetPresContext()->DevPixelsToAppUnits(width),
        8188                 :                  shell->GetPresContext()->DevPixelsToAppUnits(height));
        8189                 :
        8190                 :   nsRefPtr<gfxImageSurface> imgSurface =
        8191                 :      new gfxImageSurface(gfxIntSize(width, height),
        8192                 :                          gfxImageSurface::ImageFormatARGB32);
        8193                 :
        8194                 :   nsRefPtr<gfxContext> imgContext = new gfxContext(imgSurface);
        8195                 :
        8196                 :   nsRefPtr<gfxASurface> surface =
        8197                 :     gfxPlatform::GetPlatform()->
        8198                 :     CreateOffscreenSurface(gfxIntSize(width, height),
        8199                 :       gfxASurface::ContentFromFormat(gfxASurface::ImageFormatARGB32));
        8200                 :   NS_ENSURE_TRUE(surface, NS_ERROR_OUT_OF_MEMORY);
        8201                 :
        8202                 :   nsRefPtr<gfxContext> context = new gfxContext(surface);
        8203                 :
        8204                 :   shell->RenderDocument(r, 0, NS_RGB(255, 255, 0), context);
        8205                 :
        8206                 :   imgContext->DrawSurface(surface, gfxSize(width, height));
        8207                 :
        8208                 :   nsCOMPtr<imgIEncoder> encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png");
        8209                 :   NS_ENSURE_TRUE(encoder, NS_ERROR_FAILURE);
        8210                 :   encoder->InitFromData(imgSurface->Data(), imgSurface->Stride() * height,
        8211                 :                         width, height, imgSurface->Stride(),
        8212                 :                         imgIEncoder::INPUT_FORMAT_HOSTARGB, EmptyString());
        8213                 :
        8214                 :   // XXX not sure if this is the right way to write to a file
        8215                 :   nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
        8216                 :   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
        8217                 :   rv = file->InitWithPath(name);
        8218                 :   NS_ENSURE_SUCCESS(rv, rv);
        8219                 :
        8220                 :   PRUint32 length;
        8221                 :   encoder->Available(&length);
        8222                 :
        8223                 :   nsCOMPtr<nsIOutputStream> outputStream;
        8224                 :   rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file);
        8225                 :   NS_ENSURE_SUCCESS(rv, rv);
        8226                 :
        8227                 :   nsCOMPtr<nsIOutputStream> bufferedOutputStream;
        8228                 :   rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
        8229                 :                                   outputStream, length);
        8230                 :
        8231                 :   PRUint32 numWritten;
        8232                 :   rv = bufferedOutputStream->WriteFrom(encoder, length, &numWritten);
        8233                 :   NS_ENSURE_SUCCESS(rv, rv);
        8234                 :
        8235                 :   return NS_OK;
        8236                 : }
        8237                 : #endif
        8238                 :
        8239                 : // After an incremental reflow, we verify the correctness by doing a
        8240                 : // full reflow into a fresh frame tree.
        8241                 : bool
        8242               0 : PresShell::VerifyIncrementalReflow()
        8243                 : {
        8244               0 :    if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
        8245               0 :      printf("Building Verification Tree...\n");
        8246                 :    }
        8247                 :
        8248                 :   // Create a presentation context to view the new frame tree
        8249                 :   nsRefPtr<nsPresContext> cx =
        8250               0 :        new nsRootPresContext(mDocument, mPresContext->IsPaginated() ?
        8251                 :                                         nsPresContext::eContext_PrintPreview :
        8252               0 :                                         nsPresContext::eContext_Galley);
        8253               0 :   NS_ENSURE_TRUE(cx, false);
        8254                 :
        8255               0 :   nsDeviceContext *dc = mPresContext->DeviceContext();
        8256               0 :   nsresult rv = cx->Init(dc);
        8257               0 :   NS_ENSURE_SUCCESS(rv, false);
        8258                 :
        8259                 :   // Get our scrolling preference
        8260               0 :   nsIView* rootView = mViewManager->GetRootView();
        8261               0 :   NS_ENSURE_TRUE(rootView->HasWidget(), false);
        8262               0 :   nsIWidget* parentWidget = rootView->GetWidget();
        8263                 :
        8264                 :   // Create a new view manager.
        8265               0 :   nsCOMPtr<nsIViewManager> vm = do_CreateInstance(kViewManagerCID);
        8266               0 :   NS_ENSURE_TRUE(vm, false);
        8267               0 :   rv = vm->Init(dc);
        8268               0 :   NS_ENSURE_SUCCESS(rv, false);
        8269                 :
        8270                 :   // Create a child window of the parent that is our "root view/window"
        8271                 :   // Create a view
        8272               0 :   nsRect tbounds = mPresContext->GetVisibleArea();
        8273               0 :   nsIView* view = vm->CreateView(tbounds, nsnull);
        8274               0 :   NS_ENSURE_TRUE(view, false);
        8275                 :
        8276                 :   //now create the widget for the view
        8277               0 :   rv = view->CreateWidgetForParent(parentWidget, nsnull, true);
        8278               0 :   NS_ENSURE_SUCCESS(rv, false);
        8279                 :
        8280                 :   // Setup hierarchical relationship in view manager
        8281               0 :   vm->SetRootView(view);
        8282                 :
        8283                 :   // Make the new presentation context the same size as our
        8284                 :   // presentation context.
        8285               0 :   nsRect r = mPresContext->GetVisibleArea();
        8286               0 :   cx->SetVisibleArea(r);
        8287                 :
        8288                 :   // Create a new presentation shell to view the document. Use the
        8289                 :   // exact same style information that this document has.
        8290               0 :   nsAutoPtr<nsStyleSet> newSet(CloneStyleSet(mStyleSet));
        8291               0 :   nsCOMPtr<nsIPresShell> sh;
        8292               0 :   rv = mDocument->CreateShell(cx, vm, newSet, getter_AddRefs(sh));
        8293               0 :   NS_ENSURE_SUCCESS(rv, false);
        8294               0 :   newSet.forget();
        8295                 :   // Note that after we create the shell, we must make sure to destroy it
        8296               0 :   sh->SetVerifyReflowEnable(false); // turn off verify reflow while we're reflowing the test frame tree
        8297               0 :   vm->SetPresShell(sh);
        8298                 :   {
        8299               0 :     nsAutoCauseReflowNotifier crNotifier(this);
        8300               0 :     sh->InitialReflow(r.width, r.height);
        8301                 :   }
        8302               0 :   mDocument->BindingManager()->ProcessAttachedQueue();
        8303               0 :   sh->FlushPendingNotifications(Flush_Layout);
        8304               0 :   sh->SetVerifyReflowEnable(true);  // turn on verify reflow again now that we're done reflowing the test frame tree
        8305                 :   // Force the non-primary presshell to unsuppress; it doesn't want to normally
        8306                 :   // because it thinks it's hidden
        8307               0 :   ((PresShell*)sh.get())->mPaintingSuppressed = false;
        8308               0 :   if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
        8309               0 :      printf("Verification Tree built, comparing...\n");
        8310                 :   }
        8311                 :
        8312                 :   // Now that the document has been reflowed, use its frame tree to
        8313                 :   // compare against our frame tree.
        8314               0 :   nsIFrame* root1 = mFrameConstructor->GetRootFrame();
        8315               0 :   nsIFrame* root2 = sh->GetRootFrame();
        8316               0 :   bool ok = CompareTrees(mPresContext, root1, cx, root2);
        8317               0 :   if (!ok && (VERIFY_REFLOW_NOISY & gVerifyReflowFlags)) {
        8318               0 :     printf("Verify reflow failed, primary tree:\n");
        8319               0 :     root1->List(stdout, 0);
        8320               0 :     printf("Verification tree:\n");
        8321               0 :     root2->List(stdout, 0);
        8322                 :   }
        8323                 :
        8324                 : #ifdef DEBUG_Eli
        8325                 :   // Sample code for dumping page to png
        8326                 :   // XXX Needs to be made more flexible
        8327                 :   if (!ok) {
        8328                 :     nsString stra;
        8329                 :     static int num = 0;
        8330                 :     stra.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea");
        8331                 :     stra.AppendInt(num);
        8332                 :     stra.AppendLiteral(".png");
        8333                 :     DumpToPNG(sh, stra);
        8334                 :     nsString strb;
        8335                 :     strb.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb");
        8336                 :     strb.AppendInt(num);
        8337                 :     strb.AppendLiteral(".png");
        8338                 :     DumpToPNG(this, strb);
        8339                 :     ++num;
        8340                 :   }
        8341                 : #endif
        8342                 :
        8343               0 :   sh->EndObservingDocument();
        8344               0 :   sh->Destroy();
        8345               0 :   if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
        8346               0 :     printf("Finished Verifying Reflow...\n");
        8347                 :   }
        8348                 :
        8349               0 :   return ok;
        8350                 : }
        8351                 :
        8352                 : // Layout debugging hooks
        8353                 : void
        8354               0 : PresShell::ListStyleContexts(nsIFrame *aRootFrame, FILE *out, PRInt32 aIndent)
        8355                 : {
        8356               0 :   nsStyleContext *sc = aRootFrame->GetStyleContext();
        8357               0 :   if (sc)
        8358               0 :     sc->List(out, aIndent);
        8359               0 : }
        8360                 :
        8361                 : void
        8362               0 : PresShell::ListStyleSheets(FILE *out, PRInt32 aIndent)
        8363                 : {
        8364               0 :   PRInt32 sheetCount = mStyleSet->SheetCount(nsStyleSet::eDocSheet);
        8365               0 :   for (PRInt32 i = 0; i < sheetCount; ++i) {
        8366               0 :     mStyleSet->StyleSheetAt(nsStyleSet::eDocSheet, i)->List(out, aIndent);
        8367               0 :     fputs("\n", out);
        8368                 :   }
        8369               0 : }
        8370                 :
        8371                 : void
        8372               0 : PresShell::VerifyStyleTree()
        8373                 : {
        8374               0 :   VERIFY_STYLE_TREE;
        8375               0 : }
        8376                 : #endif
        8377                 :
        8378                 : //=============================================================
        8379                 : //=============================================================
        8380                 : //-- Debug Reflow Counts
        8381                 : //=============================================================
        8382                 : //=============================================================
        8383                 : #ifdef MOZ_REFLOW_PERF
        8384                 : //-------------------------------------------------------------
        8385                 : void
        8386               0 : PresShell::DumpReflows()
        8387                 : {
        8388               0 :   if (mReflowCountMgr) {
        8389               0 :     nsCAutoString uriStr;
        8390               0 :     if (mDocument) {
        8391               0 :       nsIURI *uri = mDocument->GetDocumentURI();
        8392               0 :       if (uri) {
        8393               0 :         uri->GetPath(uriStr);
        8394                 :       }
        8395                 :     }
        8396               0 :     mReflowCountMgr->DisplayTotals(uriStr.get());
        8397               0 :     mReflowCountMgr->DisplayHTMLTotals(uriStr.get());
        8398               0 :     mReflowCountMgr->DisplayDiffsInTotals("Differences");
        8399                 :   }
        8400               0 : }
        8401                 :
        8402                 : //-------------------------------------------------------------
        8403                 : void
        8404               0 : PresShell::CountReflows(const char * aName, nsIFrame * aFrame)
        8405                 : {
        8406               0 :   if (mReflowCountMgr) {
        8407               0 :     mReflowCountMgr->Add(aName, aFrame);
        8408                 :   }
        8409               0 : }
        8410                 :
        8411                 : //-------------------------------------------------------------
        8412                 : void
        8413               0 : PresShell::PaintCount(const char * aName,
        8414                 :                       nsRenderingContext* aRenderingContext,
        8415                 :                       nsPresContext* aPresContext,
        8416                 :                       nsIFrame * aFrame,
        8417                 :                       const nsPoint& aOffset,
        8418                 :                       PRUint32 aColor)
        8419                 : {
        8420               0 :   if (mReflowCountMgr) {
        8421                 :     mReflowCountMgr->PaintCount(aName, aRenderingContext, aPresContext,
        8422               0 :                                 aFrame, aOffset, aColor);
        8423                 :   }
        8424               0 : }
        8425                 :
        8426                 : //-------------------------------------------------------------
        8427                 : void
        8428               0 : PresShell::SetPaintFrameCount(bool aPaintFrameCounts)
        8429                 : {
        8430               0 :   if (mReflowCountMgr) {
        8431               0 :     mReflowCountMgr->SetPaintFrameCounts(aPaintFrameCounts);
        8432                 :   }
        8433               0 : }
        8434                 :
        8435                 : bool
        8436               0 : PresShell::IsPaintingFrameCounts()
        8437                 : {
        8438               0 :   if (mReflowCountMgr)
        8439               0 :     return mReflowCountMgr->IsPaintingFrameCounts();
        8440               0 :   return false;
        8441                 : }
        8442                 :
        8443                 : //------------------------------------------------------------------
        8444                 : //-- Reflow Counter Classes Impls
        8445                 : //------------------------------------------------------------------
        8446                 :
        8447                 : //------------------------------------------------------------------
        8448               0 : ReflowCounter::ReflowCounter(ReflowCountMgr * aMgr) :
        8449               0 :   mMgr(aMgr)
        8450                 : {
        8451               0 :   ClearTotals();
        8452               0 :   SetTotalsCache();
        8453               0 : }
        8454                 :
        8455                 : //------------------------------------------------------------------
        8456               0 : ReflowCounter::~ReflowCounter()
        8457                 : {
        8458                 :
        8459               0 : }
        8460                 :
        8461                 : //------------------------------------------------------------------
        8462               0 : void ReflowCounter::ClearTotals()
        8463                 : {
        8464               0 :   mTotal = 0;
        8465               0 : }
        8466                 :
        8467                 : //------------------------------------------------------------------
        8468               0 : void ReflowCounter::SetTotalsCache()
        8469                 : {
        8470               0 :   mCacheTotal = mTotal;
        8471               0 : }
        8472                 :
        8473                 : //------------------------------------------------------------------
        8474               0 : void ReflowCounter::CalcDiffInTotals()
        8475                 : {
        8476               0 :   mCacheTotal = mTotal - mCacheTotal;
        8477               0 : }
        8478                 :
        8479                 : //------------------------------------------------------------------
        8480               0 : void ReflowCounter::DisplayTotals(const char * aStr)
        8481                 : {
        8482               0 :   DisplayTotals(mTotal, aStr?aStr:"Totals");
        8483               0 : }
        8484                 :
        8485                 : //------------------------------------------------------------------
        8486               0 : void ReflowCounter::DisplayDiffTotals(const char * aStr)
        8487                 : {
        8488               0 :   DisplayTotals(mCacheTotal, aStr?aStr:"Diff Totals");
        8489               0 : }
        8490                 :
        8491                 : //------------------------------------------------------------------
        8492               0 : void ReflowCounter::DisplayHTMLTotals(const char * aStr)
        8493                 : {
        8494               0 :   DisplayHTMLTotals(mTotal, aStr?aStr:"Totals");
        8495               0 : }
        8496                 :
        8497                 : //------------------------------------------------------------------
        8498               0 : void ReflowCounter::DisplayTotals(PRUint32 aTotal, const char * aTitle)
        8499                 : {
        8500                 :   // figure total
        8501               0 :   if (aTotal == 0) {
        8502               0 :     return;
        8503                 :   }
        8504               0 :   ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr);
        8505                 :
        8506               0 :   printf("%25s\t", aTitle);
        8507               0 :   printf("%d\t", aTotal);
        8508               0 :   if (gTots != this && aTotal > 0) {
        8509               0 :     gTots->Add(aTotal);
        8510                 :   }
        8511                 : }
        8512                 :
        8513                 : //------------------------------------------------------------------
        8514               0 : void ReflowCounter::DisplayHTMLTotals(PRUint32 aTotal, const char * aTitle)
        8515                 : {
        8516               0 :   if (aTotal == 0) {
        8517               0 :     return;
        8518                 :   }
        8519                 :
        8520               0 :   ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr);
        8521               0 :   FILE * fd = mMgr->GetOutFile();
        8522               0 :   if (!fd) {
        8523               0 :     return;
        8524                 :   }
        8525                 :
        8526               0 :   fprintf(fd, "<tr><td><center>%s</center></td>", aTitle);
        8527               0 :   fprintf(fd, "<td><center>%d</center></td></tr>\n", aTotal);
        8528                 :
        8529               0 :   if (gTots != this && aTotal > 0) {
        8530               0 :     gTots->Add(aTotal);
        8531                 :   }
        8532                 : }
        8533                 :
        8534                 : //------------------------------------------------------------------
        8535                 : //-- ReflowCountMgr
        8536                 : //------------------------------------------------------------------
        8537               0 : ReflowCountMgr::ReflowCountMgr()
        8538                 : {
        8539                 :   mCounts = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
        8540               0 :                                 PL_CompareValues, nsnull, nsnull);
        8541                 :   mIndiFrameCounts = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
        8542               0 :                                      PL_CompareValues, nsnull, nsnull);
        8543               0 :   mCycledOnce              = false;
        8544               0 :   mDumpFrameCounts         = false;
        8545               0 :   mDumpFrameByFrameCounts  = false;
        8546               0 :   mPaintFrameByFrameCounts = false;
        8547               0 : }
        8548                 :
        8549                 : //------------------------------------------------------------------
        8550               0 : ReflowCountMgr::~ReflowCountMgr()
        8551                 : {
        8552               0 :   CleanUp();
        8553               0 : }
        8554                 :
        8555                 : //------------------------------------------------------------------
        8556               0 : ReflowCounter * ReflowCountMgr::LookUp(const char * aName)
        8557                 : {
        8558               0 :   if (nsnull != mCounts) {
        8559               0 :     ReflowCounter * counter = (ReflowCounter *)PL_HashTableLookup(mCounts, aName);
        8560               0 :     return counter;
        8561                 :   }
        8562               0 :   return nsnull;
        8563                 :
        8564                 : }
        8565                 :
        8566                 : //------------------------------------------------------------------
        8567               0 : void ReflowCountMgr::Add(const char * aName, nsIFrame * aFrame)
        8568                 : {
        8569               0 :   NS_ASSERTION(aName != nsnull, "Name shouldn't be null!");
        8570                 :
        8571               0 :   if (mDumpFrameCounts && nsnull != mCounts) {
        8572               0 :     ReflowCounter * counter = (ReflowCounter *)PL_HashTableLookup(mCounts, aName);
        8573               0 :     if (counter == nsnull) {
        8574               0 :       counter = new ReflowCounter(this);
        8575               0 :       char * name = NS_strdup(aName);
        8576               0 :       NS_ASSERTION(name != nsnull, "null ptr");
        8577               0 :       PL_HashTableAdd(mCounts, name, counter);
        8578                 :     }
        8579               0 :     counter->Add();
        8580                 :   }
        8581                 :
        8582               0 :   if ((mDumpFrameByFrameCounts || mPaintFrameByFrameCounts) &&
        8583                 :       nsnull != mIndiFrameCounts &&
        8584                 :       aFrame != nsnull) {
        8585               0 :     char * key = new char[16];
        8586               0 :     sprintf(key, "%p", (void*)aFrame);
        8587               0 :     IndiReflowCounter * counter = (IndiReflowCounter *)PL_HashTableLookup(mIndiFrameCounts, key);
        8588               0 :     if (counter == nsnull) {
        8589               0 :       counter = new IndiReflowCounter(this);
        8590               0 :       counter->mFrame = aFrame;
        8591               0 :       counter->mName.AssignASCII(aName);
        8592               0 :       PL_HashTableAdd(mIndiFrameCounts, key, counter);
        8593                 :     }
        8594                 :     // this eliminates extra counts from super classes
        8595               0 :     if (counter != nsnull && counter->mName.EqualsASCII(aName)) {
        8596               0 :       counter->mCount++;
        8597               0 :       counter->mCounter.Add(1);
        8598                 :     }
        8599                 :   }
        8600               0 : }
        8601                 :
        8602                 : //------------------------------------------------------------------
        8603               0 : void ReflowCountMgr::PaintCount(const char*     aName,
        8604                 :                                 nsRenderingContext* aRenderingContext,
        8605                 :                                 nsPresContext*  aPresContext,
        8606                 :                                 nsIFrame*       aFrame,
        8607                 :                                 const nsPoint&  aOffset,
        8608                 :                                 PRUint32        aColor)
        8609                 : {
        8610               0 :   if (mPaintFrameByFrameCounts &&
        8611                 :       nsnull != mIndiFrameCounts &&
        8612                 :       aFrame != nsnull) {
        8613               0 :     char * key = new char[16];
        8614               0 :     sprintf(key, "%p", (void*)aFrame);
        8615                 :     IndiReflowCounter * counter =
        8616               0 :       (IndiReflowCounter *)PL_HashTableLookup(mIndiFrameCounts, key);
        8617               0 :     if (counter != nsnull && counter->mName.EqualsASCII(aName)) {
        8618               0 :       aRenderingContext->PushState();
        8619               0 :       aRenderingContext->Translate(aOffset);
        8620                 :       nsFont font("Times", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
        8621                 :                   NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0,
        8622               0 :                   nsPresContext::CSSPixelsToAppUnits(11));
        8623                 :
        8624               0 :       nsRefPtr<nsFontMetrics> fm;
        8625                 :       aPresContext->DeviceContext()->GetMetricsFor(font,
        8626                 :         // We have one frame, therefore we must have a root...
        8627                 :         aPresContext->GetPresShell()->GetRootFrame()->
        8628               0 :           GetStyleFont()->mLanguage,
        8629               0 :         aPresContext->GetUserFontSet(), *getter_AddRefs(fm));
        8630                 :
        8631               0 :       aRenderingContext->SetFont(fm);
        8632                 :       char buf[16];
        8633               0 :       sprintf(buf, "%d", counter->mCount);
        8634               0 :       nscoord x = 0, y = fm->MaxAscent();
        8635               0 :       nscoord width, height = fm->MaxHeight();
        8636               0 :       aRenderingContext->SetTextRunRTL(false);
        8637               0 :       width = aRenderingContext->GetWidth(buf);
        8638                 :
        8639                 :       PRUint32 color;
        8640                 :       PRUint32 color2;
        8641               0 :       if (aColor != 0) {
        8642               0 :         color  = aColor;
        8643               0 :         color2 = NS_RGB(0,0,0);
        8644                 :       } else {
        8645               0 :         PRUint8 rc = 0, gc = 0, bc = 0;
        8646               0 :         if (counter->mCount < 5) {
        8647               0 :           rc = 255;
        8648               0 :           gc = 255;
        8649               0 :         } else if ( counter->mCount < 11) {
        8650               0 :           gc = 255;
        8651                 :         } else {
        8652               0 :           rc = 255;
        8653                 :         }
        8654               0 :         color  = NS_RGB(rc,gc,bc);
        8655               0 :         color2 = NS_RGB(rc/2,gc/2,bc/2);
        8656                 :       }
        8657                 :
        8658               0 :       nsRect rect(0,0, width+15, height+15);
        8659               0 :       aRenderingContext->SetColor(NS_RGB(0,0,0));
        8660               0 :       aRenderingContext->FillRect(rect);
        8661               0 :       aRenderingContext->SetColor(color2);
        8662               0 :       aRenderingContext->DrawString(buf, strlen(buf), x+15,y+15);
        8663               0 :       aRenderingContext->SetColor(color);
        8664               0 :       aRenderingContext->DrawString(buf, strlen(buf), x,y);
        8665                 :
        8666               0 :       aRenderingContext->PopState();
        8667                 :     }
        8668                 :   }
        8669               0 : }
        8670                 :
        8671                 : //------------------------------------------------------------------
        8672               0 : PRIntn ReflowCountMgr::RemoveItems(PLHashEntry *he, PRIntn i, void *arg)
        8673                 : {
        8674               0 :   char *str = (char *)he->key;
        8675               0 :   ReflowCounter * counter = (ReflowCounter *)he->value;
        8676               0 :   delete counter;
        8677               0 :   NS_Free(str);
        8678                 :
        8679               0 :   return HT_ENUMERATE_REMOVE;
        8680                 : }
        8681                 :
        8682                 : //------------------------------------------------------------------
        8683               0 : PRIntn ReflowCountMgr::RemoveIndiItems(PLHashEntry *he, PRIntn i, void *arg)
        8684                 : {
        8685               0 :   char *str = (char *)he->key;
        8686               0 :   IndiReflowCounter * counter = (IndiReflowCounter *)he->value;
        8687               0 :   delete counter;
        8688               0 :   NS_Free(str);
        8689                 :
        8690               0 :   return HT_ENUMERATE_REMOVE;
        8691                 : }
        8692                 :
        8693                 : //------------------------------------------------------------------
        8694               0 : void ReflowCountMgr::CleanUp()
        8695                 : {
        8696               0 :   if (nsnull != mCounts) {
        8697               0 :     PL_HashTableEnumerateEntries(mCounts, RemoveItems, nsnull);
        8698               0 :     PL_HashTableDestroy(mCounts);
        8699               0 :     mCounts = nsnull;
        8700                 :   }
        8701                 :
        8702               0 :   if (nsnull != mIndiFrameCounts) {
        8703               0 :     PL_HashTableEnumerateEntries(mIndiFrameCounts, RemoveIndiItems, nsnull);
        8704               0 :     PL_HashTableDestroy(mIndiFrameCounts);
        8705               0 :     mIndiFrameCounts = nsnull;
        8706                 :   }
        8707               0 : }
        8708                 :
        8709                 : //------------------------------------------------------------------
        8710               0 : PRIntn ReflowCountMgr::DoSingleTotal(PLHashEntry *he, PRIntn i, void *arg)
        8711                 : {
        8712               0 :   char *str = (char *)he->key;
        8713               0 :   ReflowCounter * counter = (ReflowCounter *)he->value;
        8714                 :
        8715               0 :   counter->DisplayTotals(str);
        8716                 :
        8717               0 :   return HT_ENUMERATE_NEXT;
        8718                 : }
        8719                 :
        8720                 : //------------------------------------------------------------------
        8721               0 : void ReflowCountMgr::DoGrandTotals()
        8722                 : {
        8723               0 :   if (nsnull != mCounts) {
        8724               0 :     ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr);
        8725               0 :     if (gTots == nsnull) {
        8726               0 :       gTots = new ReflowCounter(this);
        8727               0 :       PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots);
        8728                 :     } else {
        8729               0 :       gTots->ClearTotals();
        8730                 :     }
        8731                 :
        8732               0 :     printf("\t\t\t\tTotal\n");
        8733               0 :     for (PRUint32 i=0;i<78;i++) {
        8734               0 :       printf("-");
        8735                 :     }
        8736               0 :     printf("\n");
        8737               0 :     PL_HashTableEnumerateEntries(mCounts, DoSingleTotal, this);
        8738                 :   }
        8739               0 : }
        8740                 :
        8741               0 : static void RecurseIndiTotals(nsPresContext* aPresContext,
        8742                 :                               PLHashTable *   aHT,
        8743                 :                               nsIFrame *      aParentFrame,
        8744                 :                               PRInt32         aLevel)
        8745                 : {
        8746               0 :   if (aParentFrame == nsnull) {
        8747               0 :     return;
        8748                 :   }
        8749                 :
        8750                 :   char key[16];
        8751               0 :   sprintf(key, "%p", (void*)aParentFrame);
        8752               0 :   IndiReflowCounter * counter = (IndiReflowCounter *)PL_HashTableLookup(aHT, key);
        8753               0 :   if (counter) {
        8754               0 :     counter->mHasBeenOutput = true;
        8755               0 :     char * name = ToNewCString(counter->mName);
        8756               0 :     for (PRInt32 i=0;i<aLevel;i++) printf(" ");
        8757               0 :     printf("%s - %p   [%d][", name, (void*)aParentFrame, counter->mCount);
        8758               0 :     printf("%d", counter->mCounter.GetTotal());
        8759               0 :     printf("]\n");
        8760               0 :     nsMemory::Free(name);
        8761                 :   }
        8762                 :
        8763               0 :   nsIFrame* child = aParentFrame->GetFirstPrincipalChild();
        8764               0 :   while (child) {
        8765               0 :     RecurseIndiTotals(aPresContext, aHT, child, aLevel+1);
        8766               0 :     child = child->GetNextSibling();
        8767                 :   }
        8768                 :
        8769                 : }
        8770                 :
        8771                 : //------------------------------------------------------------------
        8772               0 : PRIntn ReflowCountMgr::DoSingleIndi(PLHashEntry *he, PRIntn i, void *arg)
        8773                 : {
        8774               0 :   IndiReflowCounter * counter = (IndiReflowCounter *)he->value;
        8775               0 :   if (counter && !counter->mHasBeenOutput) {
        8776               0 :     char * name = ToNewCString(counter->mName);
        8777               0 :     printf("%s - %p   [%d][", name, (void*)counter->mFrame, counter->mCount);
        8778               0 :     printf("%d", counter->mCounter.GetTotal());
        8779               0 :     printf("]\n");
        8780               0 :     nsMemory::Free(name);
        8781                 :   }
        8782               0 :   return HT_ENUMERATE_NEXT;
        8783                 : }
        8784                 :
        8785                 : //------------------------------------------------------------------
        8786               0 : void ReflowCountMgr::DoIndiTotalsTree()
        8787                 : {
        8788               0 :   if (nsnull != mCounts) {
        8789               0 :     printf("\n------------------------------------------------\n");
        8790               0 :     printf("-- Individual Frame Counts\n");
        8791               0 :     printf("------------------------------------------------\n");
        8792                 :
        8793               0 :     if (mPresShell) {
        8794               0 :       nsIFrame * rootFrame = mPresShell->FrameManager()->GetRootFrame();
        8795               0 :       RecurseIndiTotals(mPresContext, mIndiFrameCounts, rootFrame, 0);
        8796               0 :       printf("------------------------------------------------\n");
        8797               0 :       printf("-- Individual Counts of Frames not in Root Tree\n");
        8798               0 :       printf("------------------------------------------------\n");
        8799               0 :       PL_HashTableEnumerateEntries(mIndiFrameCounts, DoSingleIndi, this);
        8800                 :     }
        8801                 :   }
        8802               0 : }
        8803                 :
        8804                 : //------------------------------------------------------------------
        8805               0 : PRIntn ReflowCountMgr::DoSingleHTMLTotal(PLHashEntry *he, PRIntn i, void *arg)
        8806                 : {
        8807               0 :   char *str = (char *)he->key;
        8808               0 :   ReflowCounter * counter = (ReflowCounter *)he->value;
        8809                 :
        8810               0 :   counter->DisplayHTMLTotals(str);
        8811                 :
        8812               0 :   return HT_ENUMERATE_NEXT;
        8813                 : }
        8814                 :
        8815                 : //------------------------------------------------------------------
        8816               0 : void ReflowCountMgr::DoGrandHTMLTotals()
        8817                 : {
        8818               0 :   if (nsnull != mCounts) {
        8819               0 :     ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr);
        8820               0 :     if (gTots == nsnull) {
        8821               0 :       gTots = new ReflowCounter(this);
        8822               0 :       PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots);
        8823                 :     } else {
        8824               0 :       gTots->ClearTotals();
        8825                 :     }
        8826                 :
        8827                 :     static const char * title[] = {"Class", "Reflows"};
        8828               0 :     fprintf(mFD, "<tr>");
        8829               0 :     for (PRUint32 i=0; i < ArrayLength(title); i++) {
        8830               0 :       fprintf(mFD, "<td><center><b>%s<b></center></td>", title[i]);
        8831                 :     }
        8832               0 :     fprintf(mFD, "</tr>\n");
        8833               0 :     PL_HashTableEnumerateEntries(mCounts, DoSingleHTMLTotal, this);
        8834                 :   }
        8835               0 : }
        8836                 :
        8837                 : //------------------------------------
        8838               0 : void ReflowCountMgr::DisplayTotals(const char * aStr)
        8839                 : {
        8840                 : #ifdef DEBUG_rods
        8841                 :   printf("%s\n", aStr?aStr:"No name");
        8842                 : #endif
        8843               0 :   if (mDumpFrameCounts) {
        8844               0 :     DoGrandTotals();
        8845                 :   }
        8846               0 :   if (mDumpFrameByFrameCounts) {
        8847               0 :     DoIndiTotalsTree();
        8848                 :   }
        8849                 :
        8850               0 : }
        8851                 : //------------------------------------
        8852               0 : void ReflowCountMgr::DisplayHTMLTotals(const char * aStr)
        8853                 : {
        8854                 : #ifdef WIN32x // XXX NOT XP!
        8855                 :   char name[1024];
        8856                 :
        8857                 :   char * sptr = strrchr(aStr, '/');
        8858                 :   if (sptr) {
        8859                 :     sptr++;
        8860                 :     strcpy(name, sptr);
        8861                 :     char * eptr = strrchr(name, '.');
        8862                 :     if (eptr) {
        8863                 :       *eptr = 0;
        8864                 :     }
        8865                 :     strcat(name, "_stats.html");
        8866                 :   }
        8867                 :   mFD = fopen(name, "w");
        8868                 :   if (mFD) {
        8869                 :     fprintf(mFD, "<html><head><title>Reflow Stats</title></head><body>\n");
        8870                 :     const char * title = aStr?aStr:"No name";
        8871                 :     fprintf(mFD, "<center><b>%s</b><br><table border=1 style=\"background-color:#e0e0e0\">", title);
        8872                 :     DoGrandHTMLTotals();
        8873                 :     fprintf(mFD, "</center></table>\n");
        8874                 :     fprintf(mFD, "</body></html>\n");
        8875                 :     fclose(mFD);
        8876                 :     mFD = nsnull;
        8877                 :   }
        8878                 : #endif // not XP!
        8879               0 : }
        8880                 :
        8881                 : //------------------------------------------------------------------
        8882               0 : PRIntn ReflowCountMgr::DoClearTotals(PLHashEntry *he, PRIntn i, void *arg)
        8883                 : {
        8884               0 :   ReflowCounter * counter = (ReflowCounter *)he->value;
        8885               0 :   counter->ClearTotals();
        8886                 :
        8887               0 :   return HT_ENUMERATE_NEXT;
        8888                 : }
        8889                 :
        8890                 : //------------------------------------------------------------------
        8891               0 : void ReflowCountMgr::ClearTotals()
        8892                 : {
        8893               0 :   PL_HashTableEnumerateEntries(mCounts, DoClearTotals, this);
        8894               0 : }
        8895                 :
        8896                 : //------------------------------------------------------------------
        8897               0 : void ReflowCountMgr::ClearGrandTotals()
        8898                 : {
        8899               0 :   if (nsnull != mCounts) {
        8900               0 :     ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr);
        8901               0 :     if (gTots == nsnull) {
        8902               0 :       gTots = new ReflowCounter(this);
        8903               0 :       PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots);
        8904                 :     } else {
        8905               0 :       gTots->ClearTotals();
        8906               0 :       gTots->SetTotalsCache();
        8907                 :     }
        8908                 :   }
        8909               0 : }
        8910                 :
        8911                 : //------------------------------------------------------------------
        8912               0 : PRIntn ReflowCountMgr::DoDisplayDiffTotals(PLHashEntry *he, PRIntn i, void *arg)
        8913                 : {
        8914               0 :   bool cycledOnce = (arg != 0);
        8915                 :
        8916               0 :   char *str = (char *)he->key;
        8917               0 :   ReflowCounter * counter = (ReflowCounter *)he->value;
        8918                 :
        8919               0 :   if (cycledOnce) {
        8920               0 :     counter->CalcDiffInTotals();
        8921               0 :     counter->DisplayDiffTotals(str);
        8922                 :   }
        8923               0 :   counter->SetTotalsCache();
        8924                 :
        8925               0 :   return HT_ENUMERATE_NEXT;
        8926                 : }
        8927                 :
        8928                 : //------------------------------------------------------------------
        8929               0 : void ReflowCountMgr::DisplayDiffsInTotals(const char * aStr)
        8930                 : {
        8931               0 :   if (mCycledOnce) {
        8932               0 :     printf("Differences\n");
        8933               0 :     for (PRInt32 i=0;i<78;i++) {
        8934               0 :       printf("-");
        8935                 :     }
        8936               0 :     printf("\n");
        8937               0 :     ClearGrandTotals();
        8938                 :   }
        8939               0 :   PL_HashTableEnumerateEntries(mCounts, DoDisplayDiffTotals, (void *)mCycledOnce);
        8940                 :
        8941               0 :   mCycledOnce = true;
        8942               0 : }
        8943                 :
        8944                 : #endif // MOZ_REFLOW_PERF
        8945                 :
        8946                 : // make a color string like #RRGGBB
        8947               0 : void ColorToString(nscolor aColor, nsAutoString &aString)
        8948                 : {
        8949                 :   char buf[8];
        8950                 :
        8951                 :   PR_snprintf(buf, sizeof(buf), "#%02x%02x%02x",
        8952               0 :               NS_GET_R(aColor), NS_GET_G(aColor), NS_GET_B(aColor));
        8953               0 :   CopyASCIItoUTF16(buf, aString);
        8954               0 : }
        8955                 :
        8956               0 : nsIFrame* nsIPresShell::GetAbsoluteContainingBlock(nsIFrame *aFrame)
        8957                 : {
        8958               0 :   return FrameConstructor()->GetAbsoluteContainingBlock(aFrame);
        8959                 : }
        8960                 :
        8961                 : #ifdef ACCESSIBILITY
        8962                 : bool
        8963               0 : nsIPresShell::IsAccessibilityActive()
        8964                 : {
        8965               0 :   return GetAccService() != nsnull;
        8966                 : }
        8967                 :
        8968                 : nsAccessibilityService*
        8969               0 : nsIPresShell::AccService()
        8970                 : {
        8971               0 :   return GetAccService();
        8972                 : }
        8973                 : #endif
        8974                 :
        8975                 : static bool inited = false;
        8976                 :
        8977            1404 : void nsIPresShell::InitializeStatics()
        8978                 : {
        8979            1404 :   NS_ASSERTION(!inited, "InitializeStatics called multiple times!");
        8980            1404 :   gCaptureTouchList.Init();
        8981            1404 :   inited = true;
        8982            1404 : }
        8983                 :
        8984            1403 : void nsIPresShell::ReleaseStatics()
        8985                 : {
        8986            1403 :   NS_ASSERTION(inited, "ReleaseStatics called without Initialize!");
        8987            1403 : }
        8988                 :
        8989                 : // Asks our docshell whether we're active.
        8990               0 : void PresShell::QueryIsActive()
        8991                 : {
        8992               0 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
        8993               0 :   if (mDocument) {
        8994               0 :     nsIDocument* displayDoc = mDocument->GetDisplayDocument();
        8995               0 :     if (displayDoc) {
        8996                 :       // Ok, we're an external resource document -- we need to use our display
        8997                 :       // document's docshell to determine "IsActive" status, since we lack
        8998                 :       // a container.
        8999               0 :       NS_ABORT_IF_FALSE(!container,
        9000                 :                         "external resource doc shouldn't have "
        9001                 :                         "its own container");
        9002                 :
        9003               0 :       nsIPresShell* displayPresShell = displayDoc->GetShell();
        9004               0 :       if (displayPresShell) {
        9005               0 :         container = displayPresShell->GetPresContext()->GetContainer();
        9006                 :       }
        9007                 :     }
        9008                 :   }
        9009                 :
        9010               0 :   nsCOMPtr<nsIDocShell> docshell(do_QueryInterface(container));
        9011               0 :   if (docshell) {
        9012                 :     bool isActive;
        9013               0 :     nsresult rv = docshell->GetIsActive(&isActive);
        9014               0 :     if (NS_SUCCEEDED(rv))
        9015               0 :       SetIsActive(isActive);
        9016                 :   }
        9017               0 : }
        9018                 :
        9019                 : // Helper for propagating mIsActive changes to external resources
        9020                 : static bool
        9021               0 : SetExternalResourceIsActive(nsIDocument* aDocument, void* aClosure)
        9022                 : {
        9023               0 :   nsIPresShell* shell = aDocument->GetShell();
        9024               0 :   if (shell) {
        9025               0 :     shell->SetIsActive(*static_cast<bool*>(aClosure));
        9026                 :   }
        9027               0 :   return true;
        9028                 : }
        9029                 :
        9030                 : static void
        9031               0 : SetPluginIsActive(nsIContent* aContent, void* aClosure)
        9032                 : {
        9033               0 :   nsIFrame *frame = aContent->GetPrimaryFrame();
        9034               0 :   nsIObjectFrame *objectFrame = do_QueryFrame(frame);
        9035               0 :   if (objectFrame) {
        9036               0 :     objectFrame->SetIsDocumentActive(*static_cast<bool*>(aClosure));
        9037                 :   }
        9038               0 : }
        9039                 :
        9040                 : nsresult
        9041               0 : PresShell::SetIsActive(bool aIsActive)
        9042                 : {
        9043               0 :   NS_PRECONDITION(mDocument, "should only be called with a document");
        9044                 :
        9045               0 :   mIsActive = aIsActive;
        9046               0 :   nsPresContext* presContext = GetPresContext();
        9047               0 :   if (presContext &&
        9048               0 :       presContext->RefreshDriver()->PresContext() == presContext) {
        9049               0 :     presContext->RefreshDriver()->SetThrottled(!mIsActive);
        9050                 :   }
        9051                 :
        9052                 :   // Propagate state-change to my resource documents' PresShells
        9053                 :   mDocument->EnumerateExternalResources(SetExternalResourceIsActive,
        9054               0 :                                         &aIsActive);
        9055                 :   mDocument->EnumerateFreezableElements(SetPluginIsActive,
        9056               0 :                                         &aIsActive);
        9057               0 :   nsresult rv = UpdateImageLockingState();
        9058                 : #ifdef ACCESSIBILITY
        9059               0 :   if (aIsActive) {
        9060               0 :     nsAccessibilityService* accService = AccService();
        9061               0 :     if (accService) {
        9062               0 :       accService->PresShellActivated(this);
        9063                 :     }
        9064                 :   }
        9065                 : #endif
        9066               0 :   return rv;
        9067                 : }
        9068                 :
        9069                 : /*
        9070                 :  * Determines the current image locking state. Called when one of the
        9071                 :  * dependent factors changes.
        9072                 :  */
        9073                 : nsresult
        9074               0 : PresShell::UpdateImageLockingState()
        9075                 : {
        9076                 :   // We're locked if we're both thawed and active.
        9077               0 :   return mDocument->SetImageLockingState(!mFrozen && mIsActive);
        9078                 : }
        9079                 :
        9080                 : PresShell*
        9081               0 : PresShell::GetRootPresShell()
        9082                 : {
        9083               0 :   if (mPresContext) {
        9084               0 :     nsPresContext* rootPresContext = mPresContext->GetRootPresContext();
        9085               0 :     if (rootPresContext) {
        9086               0 :       return static_cast<PresShell*>(rootPresContext->PresShell());
        9087                 :     }
        9088                 :   }
        9089               0 :   return nsnull;
        9090                 : }
        9091                 :
        9092                 : void
        9093               0 : PresShell::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
        9094                 :                                size_t *aArenasSize,
        9095                 :                                size_t *aStyleSetsSize,
        9096                 :                                size_t *aTextRunsSize) const
        9097                 : {
        9098               0 :   *aArenasSize = aMallocSizeOf(this);
        9099               0 :   *aArenasSize += mStackArena.SizeOfExcludingThis(aMallocSizeOf);
        9100               0 :   *aArenasSize += mFrameArena.SizeOfExcludingThis(aMallocSizeOf);
        9101                 :
        9102               0 :   *aStyleSetsSize = StyleSet()->SizeOfIncludingThis(aMallocSizeOf);
        9103                 :
        9104               0 :   *aTextRunsSize = SizeOfTextRuns(aMallocSizeOf);
        9105               0 : }
        9106                 :
        9107                 : size_t
        9108               0 : PresShell::SizeOfTextRuns(nsMallocSizeOfFun aMallocSizeOf) const
        9109                 : {
        9110               0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
        9111               0 :   if (!rootFrame) {
        9112               0 :     return 0;
        9113                 :   }
        9114                 :
        9115                 :   // clear the TEXT_RUN_MEMORY_ACCOUNTED flags
        9116                 :   nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, nsnull,
        9117               0 :                                          /* clear = */true);
        9118                 :
        9119                 :   // collect the total memory in use for textruns
        9120                 :   return nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, aMallocSizeOf,
        9121               0 :                                                 /* clear = */false);
        9122            4392 : }
        9123                 :

Generated by: LCOV version 1.7