LCOV - code coverage report
Current view: top level - layout/base - PresShell.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 2093 5127 40.8 %
Date: 2017-07-14 16:53:18 Functions: 200 396 50.5 %
Legend: Lines: hit not hit

          Line data    Source code
       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             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       6             :  *
       7             :  * This Original Code has been modified by IBM Corporation.
       8             :  * Modifications made by IBM described herein are
       9             :  * Copyright (c) International Business Machines
      10             :  * Corporation, 2000
      11             :  *
      12             :  * Modifications to Mozilla code or documentation
      13             :  * identified per MPL Section 3.3
      14             :  *
      15             :  * Date         Modified by     Description of modification
      16             :  * 05/03/2000   IBM Corp.       Observer events for reflow states
      17             :  */
      18             : 
      19             : /* a presentation of a document, part 2 */
      20             : 
      21             : #include "mozilla/PresShell.h"
      22             : 
      23             : #include "mozilla/ArrayUtils.h"
      24             : #include "mozilla/Attributes.h"
      25             : #include "mozilla/StyleSheetInlines.h"
      26             : #include "mozilla/EventDispatcher.h"
      27             : #include "mozilla/EventStateManager.h"
      28             : #include "mozilla/EventStates.h"
      29             : #include "mozilla/IMEStateManager.h"
      30             : #include "mozilla/MemoryReporting.h"
      31             : #include "mozilla/dom/TabChild.h"
      32             : #include "mozilla/Likely.h"
      33             : #include "mozilla/Logging.h"
      34             : #include "mozilla/MouseEvents.h"
      35             : #include "mozilla/Sprintf.h"
      36             : #include "mozilla/TextEvents.h"
      37             : #include "mozilla/TimeStamp.h"
      38             : #include "mozilla/TouchEvents.h"
      39             : #include "mozilla/UniquePtr.h"
      40             : #include "mozilla/Unused.h"
      41             : #include "mozilla/StyleBackendType.h"
      42             : #include <algorithm>
      43             : 
      44             : #ifdef XP_WIN
      45             : #include "winuser.h"
      46             : #endif
      47             : 
      48             : #include "gfxContext.h"
      49             : #include "gfxPrefs.h"
      50             : #include "gfxUserFontSet.h"
      51             : #include "nsPresContext.h"
      52             : #include "nsIContent.h"
      53             : #include "nsIContentIterator.h"
      54             : #include "mozilla/dom/Element.h"
      55             : #include "mozilla/dom/Event.h" // for Event::GetEventPopupControlState()
      56             : #include "mozilla/dom/PointerEvent.h"
      57             : #include "nsIDocument.h"
      58             : #include "nsAnimationManager.h"
      59             : #include "nsNameSpaceManager.h"  // for Pref-related rule management (bugs 22963,20760,31816)
      60             : #include "nsFrame.h"
      61             : #include "FrameLayerBuilder.h"
      62             : #include "nsViewManager.h"
      63             : #include "nsView.h"
      64             : #include "nsCRTGlue.h"
      65             : #include "prinrval.h"
      66             : #include "nsTArray.h"
      67             : #include "nsCOMArray.h"
      68             : #include "nsContainerFrame.h"
      69             : #include "nsISelection.h"
      70             : #include "mozilla/dom/Selection.h"
      71             : #include "nsGkAtoms.h"
      72             : #include "nsIDOMRange.h"
      73             : #include "nsIDOMDocument.h"
      74             : #include "nsIDOMNode.h"
      75             : #include "nsIDOMNodeList.h"
      76             : #include "nsIDOMElement.h"
      77             : #include "nsRange.h"
      78             : #include "nsCOMPtr.h"
      79             : #include "nsAutoPtr.h"
      80             : #include "nsReadableUtils.h"
      81             : #include "nsIPageSequenceFrame.h"
      82             : #include "nsIPermissionManager.h"
      83             : #include "nsIMozBrowserFrame.h"
      84             : #include "nsCaret.h"
      85             : #include "AccessibleCaretEventHub.h"
      86             : #include "nsIDOMHTMLDocument.h"
      87             : #include "nsFrameManager.h"
      88             : #include "nsXPCOM.h"
      89             : #include "nsILayoutHistoryState.h"
      90             : #include "nsILineIterator.h" // for ScrollContentIntoView
      91             : #include "PLDHashTable.h"
      92             : #include "mozilla/dom/Touch.h"
      93             : #include "mozilla/dom/TouchEvent.h"
      94             : #include "mozilla/dom/PointerEventBinding.h"
      95             : #include "nsIObserverService.h"
      96             : #include "nsDocShell.h"        // for reflow observation
      97             : #include "nsIBaseWindow.h"
      98             : #include "nsError.h"
      99             : #include "nsLayoutUtils.h"
     100             : #include "nsViewportInfo.h"
     101             : #include "nsCSSRendering.h"
     102             :   // for |#ifdef DEBUG| code
     103             : #include "prenv.h"
     104             : #include "nsDisplayList.h"
     105             : #include "nsRegion.h"
     106             : #include "nsAutoLayoutPhase.h"
     107             : #ifdef MOZ_REFLOW_PERF
     108             : #include "nsFontMetrics.h"
     109             : #endif
     110             : #include "PositionedEventTargeting.h"
     111             : 
     112             : #include "nsIReflowCallback.h"
     113             : 
     114             : #include "nsPIDOMWindow.h"
     115             : #include "nsFocusManager.h"
     116             : #include "nsIObjectFrame.h"
     117             : #include "nsIObjectLoadingContent.h"
     118             : #include "nsNetUtil.h"
     119             : #include "nsThreadUtils.h"
     120             : #include "nsStyleSheetService.h"
     121             : #include "gfxUtils.h"
     122             : #include "nsSMILAnimationController.h"
     123             : #include "SVGContentUtils.h"
     124             : #include "nsSVGEffects.h"
     125             : #include "SVGFragmentIdentifier.h"
     126             : #include "nsArenaMemoryStats.h"
     127             : #include "nsFrameSelection.h"
     128             : 
     129             : #include "mozilla/dom/Performance.h"
     130             : #include "nsRefreshDriver.h"
     131             : #include "nsDOMNavigationTiming.h"
     132             : 
     133             : // Drag & Drop, Clipboard
     134             : #include "nsIDocShellTreeItem.h"
     135             : #include "nsIURI.h"
     136             : #include "nsIScrollableFrame.h"
     137             : #include "nsITimer.h"
     138             : #ifdef ACCESSIBILITY
     139             : #include "nsAccessibilityService.h"
     140             : #include "mozilla/a11y/DocAccessible.h"
     141             : #ifdef DEBUG
     142             : #include "mozilla/a11y/Logging.h"
     143             : #endif
     144             : #endif
     145             : 
     146             : // For style data reconstruction
     147             : #include "nsStyleChangeList.h"
     148             : #include "nsCSSFrameConstructor.h"
     149             : #ifdef MOZ_XUL
     150             : #include "nsMenuFrame.h"
     151             : #include "nsTreeBodyFrame.h"
     152             : #include "nsIBoxObject.h"
     153             : #include "nsITreeBoxObject.h"
     154             : #include "nsMenuPopupFrame.h"
     155             : #include "nsITreeColumns.h"
     156             : #include "nsIDOMXULMultSelectCntrlEl.h"
     157             : #include "nsIDOMXULSelectCntrlItemEl.h"
     158             : #include "nsIDOMXULMenuListElement.h"
     159             : #include "nsXULElement.h"
     160             : #include "mozilla/dom/BoxObject.h"
     161             : #endif // MOZ_XUL
     162             : 
     163             : #include "mozilla/layers/CompositorBridgeChild.h"
     164             : #include "ClientLayerManager.h"
     165             : #include "GeckoProfiler.h"
     166             : #include "gfxPlatform.h"
     167             : #include "Layers.h"
     168             : #include "LayerTreeInvalidation.h"
     169             : #include "mozilla/css/ImageLoader.h"
     170             : #include "mozilla/dom/DocumentTimeline.h"
     171             : #include "mozilla/dom/ScriptSettings.h"
     172             : #include "mozilla/ErrorResult.h"
     173             : #include "mozilla/Preferences.h"
     174             : #include "mozilla/Telemetry.h"
     175             : #include "nsCanvasFrame.h"
     176             : #include "nsIImageLoadingContent.h"
     177             : #include "nsImageFrame.h"
     178             : #include "nsIScreen.h"
     179             : #include "nsIScreenManager.h"
     180             : #include "nsPlaceholderFrame.h"
     181             : #include "nsTransitionManager.h"
     182             : #include "ChildIterator.h"
     183             : #include "mozilla/RestyleManager.h"
     184             : #include "mozilla/RestyleManagerInlines.h"
     185             : #include "nsIDOMHTMLElement.h"
     186             : #include "nsIDragSession.h"
     187             : #include "nsIFrameInlines.h"
     188             : #include "mozilla/gfx/2D.h"
     189             : #include "nsSubDocumentFrame.h"
     190             : #include "nsQueryObject.h"
     191             : #include "nsLayoutStylesheetCache.h"
     192             : #include "mozilla/layers/InputAPZContext.h"
     193             : #include "mozilla/layers/ScrollInputMethods.h"
     194             : #include "mozilla/layers/FocusTarget.h"
     195             : #include "nsStyleSet.h"
     196             : #include "mozilla/StyleSetHandle.h"
     197             : #include "mozilla/StyleSetHandleInlines.h"
     198             : #include "mozilla/StyleSheet.h"
     199             : #include "mozilla/StyleSheetInlines.h"
     200             : #include "mozilla/dom/ImageTracker.h"
     201             : #include "nsIDocShellTreeOwner.h"
     202             : 
     203             : #ifdef MOZ_TASK_TRACER
     204             : #include "GeckoTaskTracer.h"
     205             : using namespace mozilla::tasktracer;
     206             : #endif
     207             : 
     208             : #define ANCHOR_SCROLL_FLAGS \
     209             :   (nsIPresShell::SCROLL_OVERFLOW_HIDDEN | nsIPresShell::SCROLL_NO_PARENT_FRAMES)
     210             : 
     211             :   // define the scalfactor of drag and drop images
     212             :   // relative to the max screen height/width
     213             : #define RELATIVE_SCALEFACTOR 0.0925f
     214             : 
     215             : using namespace mozilla;
     216             : using namespace mozilla::css;
     217             : using namespace mozilla::dom;
     218             : using namespace mozilla::gfx;
     219             : using namespace mozilla::layers;
     220             : using namespace mozilla::gfx;
     221             : using namespace mozilla::layout;
     222             : using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
     223             : typedef FrameMetrics::ViewID ViewID;
     224             : 
     225             : CapturingContentInfo nsIPresShell::gCaptureInfo =
     226             :   { false /* mAllowed */, false /* mPointerLock */, false /* mRetargetToElement */,
     227           3 :     false /* mPreventDrag */ };
     228             : nsIContent* nsIPresShell::gKeyDownTarget;
     229             : 
     230             : // Keeps a map between pointerId and element that currently capturing pointer
     231             : // with such pointerId. If pointerId is absent in this map then nobody is
     232             : // capturing it. Additionally keep information about pending capturing content.
     233             : static nsClassHashtable<nsUint32HashKey,
     234             :                         nsIPresShell::PointerCaptureInfo>* sPointerCaptureList;
     235             : 
     236             : // Keeps information about pointers such as pointerId, activeState, pointerType,
     237             : // primaryState
     238             : static nsClassHashtable<nsUint32HashKey,
     239             :                         nsIPresShell::PointerInfo>* sActivePointersIds;
     240             : 
     241             : // RangePaintInfo is used to paint ranges to offscreen buffers
     242             : struct RangePaintInfo {
     243             :   RefPtr<nsRange> mRange;
     244             :   nsDisplayListBuilder mBuilder;
     245             :   nsDisplayList mList;
     246             : 
     247             :   // offset of builder's reference frame to the root frame
     248             :   nsPoint mRootOffset;
     249             : 
     250           0 :   RangePaintInfo(nsRange* aRange, nsIFrame* aFrame)
     251           0 :     : mRange(aRange), mBuilder(aFrame, nsDisplayListBuilderMode::PAINTING, false)
     252             :   {
     253           0 :     MOZ_COUNT_CTOR(RangePaintInfo);
     254           0 :   }
     255             : 
     256           0 :   ~RangePaintInfo()
     257           0 :   {
     258           0 :     mList.DeleteAll();
     259           0 :     MOZ_COUNT_DTOR(RangePaintInfo);
     260           0 :   }
     261             : };
     262             : 
     263             : #undef NOISY
     264             : 
     265             : // ----------------------------------------------------------------------
     266             : 
     267             : #ifdef DEBUG
     268             : // Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
     269             : // more of the following flags (comma separated) for handy debug
     270             : // output.
     271             : static uint32_t gVerifyReflowFlags;
     272             : 
     273             : struct VerifyReflowFlags {
     274             :   const char*    name;
     275             :   uint32_t bit;
     276             : };
     277             : 
     278             : static const VerifyReflowFlags gFlags[] = {
     279             :   { "verify",                VERIFY_REFLOW_ON },
     280             :   { "reflow",                VERIFY_REFLOW_NOISY },
     281             :   { "all",                   VERIFY_REFLOW_ALL },
     282             :   { "list-commands",         VERIFY_REFLOW_DUMP_COMMANDS },
     283             :   { "noisy-commands",        VERIFY_REFLOW_NOISY_RC },
     284             :   { "really-noisy-commands", VERIFY_REFLOW_REALLY_NOISY_RC },
     285             :   { "resize",                VERIFY_REFLOW_DURING_RESIZE_REFLOW },
     286             : };
     287             : 
     288             : #define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
     289             : 
     290             : static void
     291           0 : ShowVerifyReflowFlags()
     292             : {
     293           0 :   printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n");
     294           0 :   const VerifyReflowFlags* flag = gFlags;
     295           0 :   const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
     296           0 :   while (flag < limit) {
     297           0 :     printf("  %s\n", flag->name);
     298           0 :     ++flag;
     299             :   }
     300           0 :   printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
     301           0 :   printf("names (no whitespace)\n");
     302           0 : }
     303             : #endif
     304             : 
     305             : //========================================================================
     306             : //========================================================================
     307             : //========================================================================
     308             : #ifdef MOZ_REFLOW_PERF
     309             : class ReflowCountMgr;
     310             : 
     311             : static const char kGrandTotalsStr[] = "Grand Totals";
     312             : 
     313             : // Counting Class
     314             : class ReflowCounter {
     315             : public:
     316             :   explicit ReflowCounter(ReflowCountMgr * aMgr = nullptr);
     317             :   ~ReflowCounter();
     318             : 
     319             :   void ClearTotals();
     320             :   void DisplayTotals(const char * aStr);
     321             :   void DisplayDiffTotals(const char * aStr);
     322             :   void DisplayHTMLTotals(const char * aStr);
     323             : 
     324           0 :   void Add()                { mTotal++;         }
     325           0 :   void Add(uint32_t aTotal) { mTotal += aTotal; }
     326             : 
     327             :   void CalcDiffInTotals();
     328             :   void SetTotalsCache();
     329             : 
     330             :   void SetMgr(ReflowCountMgr * aMgr) { mMgr = aMgr; }
     331             : 
     332           0 :   uint32_t GetTotal() { return mTotal; }
     333             : 
     334             : protected:
     335             :   void DisplayTotals(uint32_t aTotal, const char * aTitle);
     336             :   void DisplayHTMLTotals(uint32_t aTotal, const char * aTitle);
     337             : 
     338             :   uint32_t mTotal;
     339             :   uint32_t mCacheTotal;
     340             : 
     341             :   ReflowCountMgr * mMgr; // weak reference (don't delete)
     342             : };
     343             : 
     344             : // Counting Class
     345             : class IndiReflowCounter {
     346             : public:
     347           0 :   explicit IndiReflowCounter(ReflowCountMgr * aMgr = nullptr)
     348           0 :     : mFrame(nullptr),
     349             :       mCount(0),
     350             :       mMgr(aMgr),
     351             :       mCounter(aMgr),
     352           0 :       mHasBeenOutput(false)
     353           0 :     {}
     354           0 :   virtual ~IndiReflowCounter() {}
     355             : 
     356             :   nsAutoString mName;
     357             :   nsIFrame *   mFrame;   // weak reference (don't delete)
     358             :   int32_t      mCount;
     359             : 
     360             :   ReflowCountMgr * mMgr; // weak reference (don't delete)
     361             : 
     362             :   ReflowCounter mCounter;
     363             :   bool          mHasBeenOutput;
     364             : 
     365             : };
     366             : 
     367             : //--------------------
     368             : // Manager Class
     369             : //--------------------
     370             : class ReflowCountMgr {
     371             : public:
     372             :   ReflowCountMgr();
     373             :   virtual ~ReflowCountMgr();
     374             : 
     375             :   void ClearTotals();
     376             :   void ClearGrandTotals();
     377             :   void DisplayTotals(const char * aStr);
     378             :   void DisplayHTMLTotals(const char * aStr);
     379             :   void DisplayDiffsInTotals();
     380             : 
     381             :   void Add(const char * aName, nsIFrame * aFrame);
     382             :   ReflowCounter * LookUp(const char * aName);
     383             : 
     384             :   void PaintCount(const char *aName, gfxContext* aRenderingContext,
     385             :                   nsPresContext *aPresContext, nsIFrame *aFrame,
     386             :                   const nsPoint &aOffset, uint32_t aColor);
     387             : 
     388           0 :   FILE * GetOutFile() { return mFD; }
     389             : 
     390             :   PLHashTable * GetIndiFrameHT() { return mIndiFrameCounts; }
     391             : 
     392          28 :   void SetPresContext(nsPresContext * aPresContext) { mPresContext = aPresContext; } // weak reference
     393          28 :   void SetPresShell(nsIPresShell* aPresShell) { mPresShell= aPresShell; } // weak reference
     394             : 
     395          28 :   void SetDumpFrameCounts(bool aVal)         { mDumpFrameCounts = aVal; }
     396          28 :   void SetDumpFrameByFrameCounts(bool aVal)  { mDumpFrameByFrameCounts = aVal; }
     397          28 :   void SetPaintFrameCounts(bool aVal)        { mPaintFrameByFrameCounts = aVal; }
     398             : 
     399         121 :   bool IsPaintingFrameCounts() { return mPaintFrameByFrameCounts; }
     400             : 
     401             : protected:
     402             :   void DisplayTotals(uint32_t aTotal, uint32_t * aDupArray, char * aTitle);
     403             :   void DisplayHTMLTotals(uint32_t aTotal, uint32_t * aDupArray, char * aTitle);
     404             : 
     405             :   static int RemoveItems(PLHashEntry *he, int i, void *arg);
     406             :   static int RemoveIndiItems(PLHashEntry *he, int i, void *arg);
     407             :   void CleanUp();
     408             : 
     409             :   // stdout Output Methods
     410             :   static int DoSingleTotal(PLHashEntry *he, int i, void *arg);
     411             :   static int DoSingleIndi(PLHashEntry *he, int i, void *arg);
     412             : 
     413             :   void DoGrandTotals();
     414             :   void DoIndiTotalsTree();
     415             : 
     416             :   // HTML Output Methods
     417             :   static int DoSingleHTMLTotal(PLHashEntry *he, int i, void *arg);
     418             :   void DoGrandHTMLTotals();
     419             : 
     420             :   // Zero Out the Totals
     421             :   static int DoClearTotals(PLHashEntry *he, int i, void *arg);
     422             : 
     423             :   // Displays the Diff Totals
     424             :   static int DoDisplayDiffTotals(PLHashEntry *he, int i, void *arg);
     425             : 
     426             :   PLHashTable * mCounts;
     427             :   PLHashTable * mIndiFrameCounts;
     428             :   FILE * mFD;
     429             : 
     430             :   bool mDumpFrameCounts;
     431             :   bool mDumpFrameByFrameCounts;
     432             :   bool mPaintFrameByFrameCounts;
     433             : 
     434             :   bool mCycledOnce;
     435             : 
     436             :   // Root Frame for Individual Tracking
     437             :   nsPresContext * mPresContext;
     438             :   nsIPresShell*    mPresShell;
     439             : 
     440             :   // ReflowCountMgr gReflowCountMgr;
     441             : };
     442             : #endif
     443             : //========================================================================
     444             : 
     445             : // comment out to hide caret
     446             : #define SHOW_CARET
     447             : 
     448             : // The upper bound on the amount of time to spend reflowing, in
     449             : // microseconds.  When this bound is exceeded and reflow commands are
     450             : // still queued up, a reflow event is posted.  The idea is for reflow
     451             : // to not hog the processor beyond the time specifed in
     452             : // gMaxRCProcessingTime.  This data member is initialized from the
     453             : // layout.reflow.timeslice pref.
     454             : #define NS_MAX_REFLOW_TIME    1000000
     455             : static int32_t gMaxRCProcessingTime = -1;
     456             : 
     457             : struct nsCallbackEventRequest
     458             : {
     459             :   nsIReflowCallback* callback;
     460             :   nsCallbackEventRequest* next;
     461             : };
     462             : 
     463             : // ----------------------------------------------------------------------------
     464             : #define ASSERT_REFLOW_SCHEDULED_STATE()                                       \
     465             :   NS_ASSERTION(ObservingLayoutFlushes() ==                                    \
     466             :                  GetPresContext()->RefreshDriver()->                          \
     467             :                    IsLayoutFlushObserver(this), "Unexpected state")
     468             : 
     469             : class nsAutoCauseReflowNotifier
     470             : {
     471             : public:
     472         830 :   explicit nsAutoCauseReflowNotifier(PresShell* aShell)
     473         830 :     : mShell(aShell)
     474             :   {
     475         830 :     mShell->WillCauseReflow();
     476         830 :   }
     477         830 :   ~nsAutoCauseReflowNotifier()
     478         830 :   {
     479             :     // This check should not be needed. Currently the only place that seem
     480             :     // to need it is the code that deals with bug 337586.
     481         830 :     if (!mShell->mHaveShutDown) {
     482         830 :       mShell->DidCauseReflow();
     483             :     }
     484             :     else {
     485           0 :       nsContentUtils::RemoveScriptBlocker();
     486             :     }
     487         830 :   }
     488             : 
     489             :   PresShell* mShell;
     490             : };
     491             : 
     492          10 : class MOZ_STACK_CLASS nsPresShellEventCB : public EventDispatchingCallback
     493             : {
     494             : public:
     495          10 :   explicit nsPresShellEventCB(PresShell* aPresShell) : mPresShell(aPresShell) {}
     496             : 
     497           5 :   virtual void HandleEvent(EventChainPostVisitor& aVisitor) override
     498             :   {
     499           5 :     if (aVisitor.mPresContext && aVisitor.mEvent->mClass != eBasicEventClass) {
     500          10 :       if (aVisitor.mEvent->mMessage == eMouseDown ||
     501           5 :           aVisitor.mEvent->mMessage == eMouseUp) {
     502             :         // Mouse-up and mouse-down events call nsFrame::HandlePress/Release
     503             :         // which call GetContentOffsetsFromPoint which requires up-to-date layout.
     504             :         // Bring layout up-to-date now so that GetCurrentEventFrame() below
     505             :         // will return a real frame and we don't have to worry about
     506             :         // destroying it by flushing later.
     507           0 :         mPresShell->FlushPendingNotifications(FlushType::Layout);
     508           5 :       } else if (aVisitor.mEvent->mMessage == eWheel &&
     509           0 :                  aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
     510           0 :         nsIFrame* frame = mPresShell->GetCurrentEventFrame();
     511           0 :         if (frame) {
     512             :           // chrome (including addons) should be able to know if content
     513             :           // handles both D3E "wheel" event and legacy mouse scroll events.
     514             :           // We should dispatch legacy mouse events before dispatching the
     515             :           // "wheel" event into system group.
     516             :           RefPtr<EventStateManager> esm =
     517           0 :             aVisitor.mPresContext->EventStateManager();
     518           0 :           esm->DispatchLegacyMouseScrollEvents(frame,
     519           0 :                                                aVisitor.mEvent->AsWheelEvent(),
     520           0 :                                                &aVisitor.mEventStatus);
     521             :         }
     522             :       }
     523           5 :       nsIFrame* frame = mPresShell->GetCurrentEventFrame();
     524           5 :       if (!frame &&
     525           0 :           (aVisitor.mEvent->mMessage == eMouseUp ||
     526           0 :            aVisitor.mEvent->mMessage == eTouchEnd)) {
     527             :         // Redirect BUTTON_UP and TOUCH_END events to the root frame to ensure
     528             :         // that capturing is released.
     529           0 :         frame = mPresShell->GetRootFrame();
     530             :       }
     531           5 :       if (frame) {
     532          10 :         frame->HandleEvent(aVisitor.mPresContext,
     533           5 :                            aVisitor.mEvent->AsGUIEvent(),
     534          10 :                            &aVisitor.mEventStatus);
     535             :       }
     536             :     }
     537           5 :   }
     538             : 
     539             :   RefPtr<PresShell> mPresShell;
     540             : };
     541             : 
     542           9 : class nsBeforeFirstPaintDispatcher : public Runnable
     543             : {
     544             : public:
     545           3 :   explicit nsBeforeFirstPaintDispatcher(nsIDocument* aDocument)
     546           3 :     : mozilla::Runnable("nsBeforeFirstPaintDispatcher")
     547           3 :     , mDocument(aDocument)
     548             :   {
     549           3 :   }
     550             : 
     551             :   // Fires the "before-first-paint" event so that interested parties (right now, the
     552             :   // mobile browser) are aware of it.
     553           3 :   NS_IMETHOD Run() override
     554             :   {
     555             :     nsCOMPtr<nsIObserverService> observerService =
     556           6 :       mozilla::services::GetObserverService();
     557           3 :     if (observerService) {
     558           3 :       observerService->NotifyObservers(mDocument, "before-first-paint",
     559           3 :                                        nullptr);
     560             :     }
     561           6 :     return NS_OK;
     562             :   }
     563             : 
     564             : private:
     565             :   nsCOMPtr<nsIDocument> mDocument;
     566             : };
     567             : 
     568             : bool PresShell::sDisableNonTestMouseEvents = false;
     569             : 
     570             : mozilla::LazyLogModule PresShell::gLog("PresShell");
     571             : 
     572             : mozilla::TimeStamp PresShell::sLastInputCreated;
     573             : mozilla::TimeStamp PresShell::sLastInputProcessed;
     574             : 
     575             : #ifdef DEBUG
     576             : static void
     577         836 : VerifyStyleTree(nsPresContext* aPresContext, nsFrameManager* aFrameManager)
     578             : {
     579         836 :   if (nsFrame::GetVerifyStyleTreeEnable()) {
     580           0 :     if (aPresContext->RestyleManager()->IsServo()) {
     581           0 :       NS_ERROR("stylo: cannot verify style tree with a ServoRestyleManager");
     582           0 :       return;
     583             :     }
     584           0 :     nsIFrame* rootFrame = aFrameManager->GetRootFrame();
     585           0 :     aPresContext->RestyleManager()->AsGecko()->DebugVerifyStyleTree(rootFrame);
     586             :   }
     587             : }
     588             : #define VERIFY_STYLE_TREE ::VerifyStyleTree(mPresContext, mFrameConstructor)
     589             : #else
     590             : #define VERIFY_STYLE_TREE
     591             : #endif
     592             : 
     593             : static bool gVerifyReflowEnabled;
     594             : 
     595             : bool
     596          48 : nsIPresShell::GetVerifyReflowEnable()
     597             : {
     598             : #ifdef DEBUG
     599             :   static bool firstTime = true;
     600          48 :   if (firstTime) {
     601           2 :     firstTime = false;
     602           2 :     char* flags = PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
     603           2 :     if (flags) {
     604           0 :       bool error = false;
     605             : 
     606             :       for (;;) {
     607           0 :         char* comma = PL_strchr(flags, ',');
     608           0 :         if (comma)
     609           0 :           *comma = '\0';
     610             : 
     611           0 :         bool found = false;
     612           0 :         const VerifyReflowFlags* flag = gFlags;
     613           0 :         const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
     614           0 :         while (flag < limit) {
     615           0 :           if (PL_strcasecmp(flag->name, flags) == 0) {
     616           0 :             gVerifyReflowFlags |= flag->bit;
     617           0 :             found = true;
     618           0 :             break;
     619             :           }
     620           0 :           ++flag;
     621             :         }
     622             : 
     623           0 :         if (! found)
     624           0 :           error = true;
     625             : 
     626           0 :         if (! comma)
     627           0 :           break;
     628             : 
     629           0 :         *comma = ',';
     630           0 :         flags = comma + 1;
     631           0 :       }
     632             : 
     633           0 :       if (error)
     634           0 :         ShowVerifyReflowFlags();
     635             :     }
     636             : 
     637           2 :     if (VERIFY_REFLOW_ON & gVerifyReflowFlags) {
     638           0 :       gVerifyReflowEnabled = true;
     639             : 
     640           0 :       printf("Note: verifyreflow is enabled");
     641           0 :       if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
     642           0 :         printf(" (noisy)");
     643             :       }
     644           0 :       if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
     645           0 :         printf(" (all)");
     646             :       }
     647           0 :       if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
     648           0 :         printf(" (show reflow commands)");
     649             :       }
     650           0 :       if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
     651           0 :         printf(" (noisy reflow commands)");
     652           0 :         if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
     653           0 :           printf(" (REALLY noisy reflow commands)");
     654             :         }
     655             :       }
     656           0 :       printf("\n");
     657             :     }
     658             :   }
     659             : #endif
     660          48 :   return gVerifyReflowEnabled;
     661             : }
     662             : 
     663             : void
     664           0 : nsIPresShell::SetVerifyReflowEnable(bool aEnabled)
     665             : {
     666           0 :   gVerifyReflowEnabled = aEnabled;
     667           0 : }
     668             : 
     669             : /* virtual */ void
     670           0 : nsIPresShell::AddAutoWeakFrameExternal(AutoWeakFrame* aWeakFrame)
     671             : {
     672           0 :   AddAutoWeakFrameInternal(aWeakFrame);
     673           0 : }
     674             : 
     675             : void
     676         118 : nsIPresShell::AddAutoWeakFrameInternal(AutoWeakFrame* aWeakFrame)
     677             : {
     678         118 :   if (aWeakFrame->GetFrame()) {
     679         118 :     aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
     680             :   }
     681         118 :   aWeakFrame->SetPreviousWeakFrame(mAutoWeakFrames);
     682         118 :   mAutoWeakFrames = aWeakFrame;
     683         118 : }
     684             : 
     685             : /* virtual */ void
     686           0 : nsIPresShell::AddWeakFrameExternal(WeakFrame* aWeakFrame)
     687             : {
     688           0 :   AddWeakFrameInternal(aWeakFrame);
     689           0 : }
     690             : 
     691             : void
     692          41 : nsIPresShell::AddWeakFrameInternal(WeakFrame* aWeakFrame)
     693             : {
     694          41 :   if (aWeakFrame->GetFrame()) {
     695          41 :     aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
     696             :   }
     697          41 :   MOZ_ASSERT(!mWeakFrames.GetEntry(aWeakFrame));
     698          41 :   mWeakFrames.PutEntry(aWeakFrame);
     699          41 : }
     700             : 
     701             : /* virtual */ void
     702           0 : nsIPresShell::RemoveAutoWeakFrameExternal(AutoWeakFrame* aWeakFrame)
     703             : {
     704           0 :   RemoveAutoWeakFrameInternal(aWeakFrame);
     705           0 : }
     706             : 
     707             : void
     708         118 : nsIPresShell::RemoveAutoWeakFrameInternal(AutoWeakFrame* aWeakFrame)
     709             : {
     710         118 :   if (mAutoWeakFrames == aWeakFrame) {
     711         118 :     mAutoWeakFrames = aWeakFrame->GetPreviousWeakFrame();
     712         118 :     return;
     713             :   }
     714           0 :   AutoWeakFrame* nextWeak = mAutoWeakFrames;
     715           0 :   while (nextWeak && nextWeak->GetPreviousWeakFrame() != aWeakFrame) {
     716           0 :     nextWeak = nextWeak->GetPreviousWeakFrame();
     717             :   }
     718           0 :   if (nextWeak) {
     719           0 :     nextWeak->SetPreviousWeakFrame(aWeakFrame->GetPreviousWeakFrame());
     720             :   }
     721             : }
     722             : 
     723             : /* virtual */ void
     724           0 : nsIPresShell::RemoveWeakFrameExternal(WeakFrame* aWeakFrame)
     725             : {
     726           0 :   RemoveWeakFrameInternal(aWeakFrame);
     727           0 : }
     728             : 
     729             : void
     730          41 : nsIPresShell::RemoveWeakFrameInternal(WeakFrame* aWeakFrame)
     731             : {
     732          41 :   MOZ_ASSERT(mWeakFrames.GetEntry(aWeakFrame));
     733          41 :   mWeakFrames.RemoveEntry(aWeakFrame);
     734          41 : }
     735             : 
     736             : already_AddRefed<nsFrameSelection>
     737           4 : nsIPresShell::FrameSelection()
     738             : {
     739           8 :   RefPtr<nsFrameSelection> ret = mSelection;
     740           8 :   return ret.forget();
     741             : }
     742             : 
     743             : //----------------------------------------------------------------------
     744             : 
     745             : static bool sSynthMouseMove = true;
     746             : static uint32_t sNextPresShellId;
     747             : static bool sPointerEventEnabled = true;
     748             : static bool sPointerEventImplicitCapture = false;
     749             : static bool sAccessibleCaretEnabled = false;
     750             : static bool sAccessibleCaretOnTouch = false;
     751             : 
     752             : /* static */ bool
     753          38 : PresShell::AccessibleCaretEnabled(nsIDocShell* aDocShell)
     754             : {
     755             :   static bool initialized = false;
     756          38 :   if (!initialized) {
     757           2 :     Preferences::AddBoolVarCache(&sAccessibleCaretEnabled, "layout.accessiblecaret.enabled");
     758           2 :     Preferences::AddBoolVarCache(&sAccessibleCaretOnTouch, "layout.accessiblecaret.enabled_on_touch");
     759           2 :     initialized = true;
     760             :   }
     761             :   // If the pref forces it on, then enable it.
     762          38 :   if (sAccessibleCaretEnabled) {
     763           0 :     return true;
     764             :   }
     765             :   // If the touch pref is on, and touch events are enabled (this depends
     766             :   // on the specific device running), then enable it.
     767          38 :   if (sAccessibleCaretOnTouch && dom::TouchEvent::PrefEnabled(aDocShell)) {
     768           0 :     return true;
     769             :   }
     770             :   // Otherwise, disabled.
     771          38 :   return false;
     772             : }
     773             : 
     774          28 : nsIPresShell::nsIPresShell()
     775             :     : mFrameConstructor(nullptr)
     776             :     , mViewManager(nullptr)
     777             :     , mFrameManager(nullptr)
     778             : #ifdef ACCESSIBILITY
     779             :     , mDocAccessible(nullptr)
     780             : #endif
     781             : #ifdef DEBUG
     782             :     , mDrawEventTargetFrame(nullptr)
     783             : #endif
     784             :     , mPaintCount(0)
     785             :     , mAutoWeakFrames(nullptr)
     786             :     , mCanvasBackgroundColor(NS_RGBA(0,0,0,0))
     787             :     , mSelectionFlags(0)
     788             :     , mRenderFlags(0)
     789             :     , mDidInitialize(false)
     790             :     , mIsDestroying(false)
     791             :     , mIsReflowing(false)
     792             :     , mPaintingSuppressed(false)
     793             :     , mIsActive(false)
     794             :     , mFrozen(false)
     795             :     , mIsFirstPaint(false)
     796             :     , mObservesMutationsForPrint(false)
     797             :     , mSuppressInterruptibleReflows(false)
     798             :     , mScrollPositionClampingScrollPortSizeSet(false)
     799             :     , mNeedLayoutFlush(true)
     800             :     , mNeedStyleFlush(true)
     801             :     , mObservingStyleFlushes(false)
     802             :     , mObservingLayoutFlushes(false)
     803             :     , mNeedThrottledAnimationFlush(true)
     804             :     , mPresShellId(0)
     805             :     , mFontSizeInflationEmPerLine(0)
     806             :     , mFontSizeInflationMinTwips(0)
     807             :     , mFontSizeInflationLineThreshold(0)
     808             :     , mFontSizeInflationForceEnabled(false)
     809             :     , mFontSizeInflationDisabledInMasterProcess(false)
     810             :     , mFontSizeInflationEnabled(false)
     811             :     , mFontSizeInflationEnabledIsDirty(false)
     812             :     , mPaintingIsFrozen(false)
     813             :     , mIsNeverPainting(false)
     814          28 :     , mInFlush(false)
     815          28 :   {}
     816             : 
     817          28 : PresShell::PresShell()
     818             :   : mCaretEnabled(false)
     819             : #ifdef DEBUG
     820             :   , mInVerifyReflow(false)
     821             :   , mCurrentReflowRoot(nullptr)
     822             :   , mUpdateCount(0)
     823             : #endif
     824             : #ifdef MOZ_REFLOW_PERF
     825             :   , mReflowCountMgr(nullptr)
     826             : #endif
     827             :   , mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
     828             :   , mCurrentEventFrame(nullptr)
     829             :   , mFirstCallbackEventRequest(nullptr)
     830             :   , mLastCallbackEventRequest(nullptr)
     831             :   , mLastReflowStart(0.0)
     832             :   , mLastAnchorScrollPositionY(0)
     833             :   , mAPZFocusSequenceNumber(0)
     834             :   , mChangeNestCount(0)
     835             :   , mDocumentLoading(false)
     836             :   , mIgnoreFrameDestruction(false)
     837             :   , mHaveShutDown(false)
     838             :   , mLastRootReflowHadUnconstrainedBSize(false)
     839             :   , mNoDelayedMouseEvents(false)
     840             :   , mNoDelayedKeyEvents(false)
     841             :   , mIsDocumentGone(false)
     842             :   , mShouldUnsuppressPainting(false)
     843             :   , mAsyncResizeTimerIsActive(false)
     844             :   , mInResize(false)
     845             :   , mApproximateFrameVisibilityVisited(false)
     846             :   , mNextPaintCompressed(false)
     847             :   , mHasCSSBackgroundColor(false)
     848             :   , mScaleToResolution(false)
     849             :   , mIsLastChromeOnlyEscapeKeyConsumed(false)
     850          28 :   , mHasReceivedPaintMessage(false)
     851             : {
     852             : #ifdef MOZ_REFLOW_PERF
     853          28 :   mReflowCountMgr = new ReflowCountMgr();
     854          28 :   mReflowCountMgr->SetPresContext(mPresContext);
     855          28 :   mReflowCountMgr->SetPresShell(this);
     856             : #endif
     857          28 :   mLastOSWake = mLoadBegin = TimeStamp::Now();
     858             : 
     859          28 :   mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES;
     860          28 :   mIsActive = true;
     861             :   // FIXME/bug 735029: find a better solution to this problem
     862          28 :   mIsFirstPaint = true;
     863          28 :   mPresShellId = sNextPresShellId++;
     864          28 :   mFrozen = false;
     865          28 :   mRenderFlags = 0;
     866             : 
     867          28 :   mScrollPositionClampingScrollPortSizeSet = false;
     868             : 
     869             :   static bool addedSynthMouseMove = false;
     870          28 :   if (!addedSynthMouseMove) {
     871             :     Preferences::AddBoolVarCache(&sSynthMouseMove,
     872           2 :                                  "layout.reflow.synthMouseMove", true);
     873           2 :     addedSynthMouseMove = true;
     874             :   }
     875             :   static bool addedPointerEventEnabled = false;
     876          28 :   if (!addedPointerEventEnabled) {
     877             :     Preferences::AddBoolVarCache(&sPointerEventEnabled,
     878           2 :                                  "dom.w3c_pointer_events.enabled", true);
     879           2 :     addedPointerEventEnabled = true;
     880             :   }
     881             :   static bool addedPointerEventImplicitCapture = false;
     882          28 :   if (!addedPointerEventImplicitCapture) {
     883             :     Preferences::AddBoolVarCache(&sPointerEventImplicitCapture,
     884             :                                  "dom.w3c_pointer_events.implicit_capture",
     885           2 :                                  true);
     886           2 :     addedPointerEventImplicitCapture = true;
     887             :   }
     888          28 :   mPaintingIsFrozen = false;
     889          28 :   mHasCSSBackgroundColor = true;
     890          28 :   mIsLastChromeOnlyEscapeKeyConsumed = false;
     891          28 :   mHasReceivedPaintMessage = false;
     892          28 : }
     893             : 
     894        9560 : NS_IMPL_ISUPPORTS(PresShell, nsIPresShell, nsIDocumentObserver,
     895             :                   nsISelectionController,
     896             :                   nsISelectionDisplay, nsIObserver, nsISupportsWeakReference,
     897             :                   nsIMutationObserver)
     898             : 
     899          12 : PresShell::~PresShell()
     900             : {
     901           4 :   if (!mHaveShutDown) {
     902           0 :     NS_NOTREACHED("Someone did not call nsIPresShell::destroy");
     903           0 :     Destroy();
     904             :   }
     905             : 
     906           4 :   NS_ASSERTION(mCurrentEventContentStack.Count() == 0,
     907             :                "Huh, event content left on the stack in pres shell dtor!");
     908           4 :   NS_ASSERTION(mFirstCallbackEventRequest == nullptr &&
     909             :                mLastCallbackEventRequest == nullptr,
     910             :                "post-reflow queues not empty.  This means we're leaking");
     911             : 
     912             :   // Verify that if painting was frozen, but we're being removed from the tree,
     913             :   // that we now re-enable painting on our refresh driver, since it may need to
     914             :   // be re-used by another presentation.
     915           4 :   if (mPaintingIsFrozen) {
     916           0 :     mPresContext->RefreshDriver()->Thaw();
     917             :   }
     918             : 
     919           4 :   MOZ_ASSERT(mAllocatedPointers.IsEmpty(), "Some pres arena objects were not freed");
     920             : 
     921           4 :   mStyleSet->Delete();
     922           4 :   delete mFrameConstructor;
     923             : 
     924           4 :   mCurrentEventContent = nullptr;
     925          12 : }
     926             : 
     927             : /**
     928             :  * Initialize the presentation shell. Create view manager and style
     929             :  * manager.
     930             :  * Note this can't be merged into our constructor because caret initialization
     931             :  * calls AddRef() on us.
     932             :  */
     933             : void
     934          28 : PresShell::Init(nsIDocument* aDocument,
     935             :                 nsPresContext* aPresContext,
     936             :                 nsViewManager* aViewManager,
     937             :                 StyleSetHandle aStyleSet)
     938             : {
     939          28 :   NS_PRECONDITION(aDocument, "null ptr");
     940          28 :   NS_PRECONDITION(aPresContext, "null ptr");
     941          28 :   NS_PRECONDITION(aViewManager, "null ptr");
     942          28 :   NS_PRECONDITION(!mDocument, "already initialized");
     943             : 
     944          28 :   if (!aDocument || !aPresContext || !aViewManager || mDocument) {
     945           0 :     return;
     946             :   }
     947             : 
     948          28 :   mDocument = aDocument;
     949          28 :   mViewManager = aViewManager;
     950             : 
     951             :   // mDocument is now set.  It might have a display document whose "need layout/
     952             :   // style" flush flags are not set, but ours will be set.  To keep these
     953             :   // consistent, call the flag setting functions to propagate those flags up
     954             :   // to the display document.
     955          28 :   SetNeedLayoutFlush();
     956          28 :   SetNeedStyleFlush();
     957             : 
     958             :   // Create our frame constructor.
     959          56 :   mFrameConstructor = new nsCSSFrameConstructor(mDocument, this);
     960             : 
     961          28 :   mFrameManager = mFrameConstructor;
     962             : 
     963             :   // The document viewer owns both view manager and pres shell.
     964          28 :   mViewManager->SetPresShell(this);
     965             : 
     966             :   // Bind the context to the presentation shell.
     967          28 :   mPresContext = aPresContext;
     968          28 :   mPresContext->AttachShell(this, aStyleSet->BackendType());
     969             : 
     970             :   // Now we can initialize the style set. Make sure to set the member before
     971             :   // calling Init, since various subroutines need to find the style set off
     972             :   // the PresContext during initialization.
     973          28 :   mStyleSet = aStyleSet;
     974          28 :   mStyleSet->Init(aPresContext, mDocument->BindingManager());
     975             : 
     976             :   // Notify our prescontext that it now has a compatibility mode.  Note that
     977             :   // this MUST happen after we set up our style set but before we create any
     978             :   // frames.
     979          28 :   mPresContext->CompatibilityModeChanged();
     980             : 
     981             :   // Add the preference style sheet.
     982          28 :   UpdatePreferenceStyles();
     983             : 
     984          28 :   if (AccessibleCaretEnabled(mDocument->GetDocShell())) {
     985             :     // Need to happen before nsFrameSelection has been set up.
     986           0 :     mAccessibleCaretEventHub = new AccessibleCaretEventHub(this);
     987             :   }
     988             : 
     989          28 :   mSelection = new nsFrameSelection();
     990             : 
     991          56 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
     992          28 :   frameSelection->Init(this, nullptr);
     993             : 
     994             :   // Important: this has to happen after the selection has been set up
     995             : #ifdef SHOW_CARET
     996             :   // make the caret
     997          28 :   mCaret = new nsCaret();
     998          28 :   mCaret->Init(this);
     999          28 :   mOriginalCaret = mCaret;
    1000             : 
    1001             :   //SetCaretEnabled(true);       // make it show in browser windows
    1002             : #endif
    1003             :   //set up selection to be displayed in document
    1004             :   // Don't enable selection for print media
    1005          28 :   nsPresContext::nsPresContextType type = aPresContext->Type();
    1006          28 :   if (type != nsPresContext::eContext_PrintPreview &&
    1007             :       type != nsPresContext::eContext_Print)
    1008          28 :     SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
    1009             : 
    1010          28 :   if (gMaxRCProcessingTime == -1) {
    1011           2 :     gMaxRCProcessingTime =
    1012           2 :       Preferences::GetInt("layout.reflow.timeslice", NS_MAX_REFLOW_TIME);
    1013             :   }
    1014             : 
    1015          28 :   if (nsStyleSheetService* ss = nsStyleSheetService::GetInstance()) {
    1016          28 :     ss->RegisterPresShell(this);
    1017             :   }
    1018             : 
    1019             :   {
    1020          56 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    1021          28 :     if (os) {
    1022             : #ifdef MOZ_XUL
    1023          28 :       os->AddObserver(this, "chrome-flush-skin-caches", false);
    1024             : #endif
    1025          28 :       os->AddObserver(this, "memory-pressure", false);
    1026          28 :       os->AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, false);
    1027             :     }
    1028             :   }
    1029             : 
    1030             : #ifdef MOZ_REFLOW_PERF
    1031          28 :     if (mReflowCountMgr) {
    1032             :       bool paintFrameCounts =
    1033          28 :         Preferences::GetBool("layout.reflow.showframecounts");
    1034             : 
    1035             :       bool dumpFrameCounts =
    1036          28 :         Preferences::GetBool("layout.reflow.dumpframecounts");
    1037             : 
    1038             :       bool dumpFrameByFrameCounts =
    1039          28 :         Preferences::GetBool("layout.reflow.dumpframebyframecounts");
    1040             : 
    1041          28 :       mReflowCountMgr->SetDumpFrameCounts(dumpFrameCounts);
    1042          28 :       mReflowCountMgr->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts);
    1043          28 :       mReflowCountMgr->SetPaintFrameCounts(paintFrameCounts);
    1044             :     }
    1045             : #endif
    1046             : 
    1047          28 :   if (mDocument->HasAnimationController()) {
    1048          21 :     nsSMILAnimationController* animCtrl = mDocument->GetAnimationController();
    1049          21 :     animCtrl->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
    1050             :   }
    1051             : 
    1052          28 :   for (DocumentTimeline* timeline : mDocument->Timelines()) {
    1053           0 :     timeline->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
    1054             :   }
    1055             : 
    1056             :   // Get our activeness from the docShell.
    1057          28 :   QueryIsActive();
    1058             : 
    1059             :   // Setup our font inflation preferences.
    1060          28 :   SetupFontInflation();
    1061             : 
    1062          28 :   mTouchManager.Init(this, mDocument);
    1063             : 
    1064          28 :   if (mPresContext->IsRootContentDocument()) {
    1065           3 :     mZoomConstraintsClient = new ZoomConstraintsClient();
    1066           3 :     mZoomConstraintsClient->Init(this, mDocument);
    1067           3 :     if (gfxPrefs::MetaViewportEnabled() || gfxPrefs::APZAllowZooming()) {
    1068           0 :       mMobileViewportManager = new MobileViewportManager(this, mDocument);
    1069             :     }
    1070             :   }
    1071             : }
    1072             : 
    1073             : enum TextPerfLogType {
    1074             :   eLog_reflow,
    1075             :   eLog_loaddone,
    1076             :   eLog_totals
    1077             : };
    1078             : 
    1079             : static void
    1080           0 : LogTextPerfStats(gfxTextPerfMetrics* aTextPerf,
    1081             :                  PresShell* aPresShell,
    1082             :                  const gfxTextPerfMetrics::TextCounts& aCounts,
    1083             :                  float aTime, TextPerfLogType aLogType, const char* aURL)
    1084             : {
    1085           0 :   LogModule* tpLog = gfxPlatform::GetLog(eGfxLog_textperf);
    1086             : 
    1087             :   // ignore XUL contexts unless at debug level
    1088           0 :   mozilla::LogLevel logLevel = LogLevel::Warning;
    1089           0 :   if (aCounts.numContentTextRuns == 0) {
    1090           0 :     logLevel = LogLevel::Debug;
    1091             :   }
    1092             : 
    1093           0 :   if (!MOZ_LOG_TEST(tpLog, logLevel)) {
    1094           0 :     return;
    1095             :   }
    1096             : 
    1097             :   char prefix[256];
    1098             : 
    1099           0 :   switch (aLogType) {
    1100             :     case eLog_reflow:
    1101           0 :       SprintfLiteral(prefix, "(textperf-reflow) %p time-ms: %7.0f", aPresShell, aTime);
    1102           0 :       break;
    1103             :     case eLog_loaddone:
    1104           0 :       SprintfLiteral(prefix, "(textperf-loaddone) %p time-ms: %7.0f", aPresShell, aTime);
    1105           0 :       break;
    1106             :     default:
    1107           0 :       MOZ_ASSERT(aLogType == eLog_totals, "unknown textperf log type");
    1108           0 :       SprintfLiteral(prefix, "(textperf-totals) %p", aPresShell);
    1109             :   }
    1110             : 
    1111           0 :   double hitRatio = 0.0;
    1112           0 :   uint32_t lookups = aCounts.wordCacheHit + aCounts.wordCacheMiss;
    1113           0 :   if (lookups) {
    1114           0 :     hitRatio = double(aCounts.wordCacheHit) / double(lookups);
    1115             :   }
    1116             : 
    1117           0 :   if (aLogType == eLog_loaddone) {
    1118           0 :     MOZ_LOG(tpLog, logLevel,
    1119             :            ("%s reflow: %d chars: %d "
    1120             :             "[%s] "
    1121             :             "content-textruns: %d chrome-textruns: %d "
    1122             :             "max-textrun-len: %d "
    1123             :             "word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
    1124             :             "word-cache-space: %d word-cache-long: %d "
    1125             :             "pref-fallbacks: %d system-fallbacks: %d "
    1126             :             "textruns-const: %d textruns-destr: %d "
    1127             :             "generic-lookups: %d "
    1128             :             "cumulative-textruns-destr: %d\n",
    1129             :             prefix, aTextPerf->reflowCount, aCounts.numChars,
    1130             :             (aURL ? aURL : ""),
    1131             :             aCounts.numContentTextRuns, aCounts.numChromeTextRuns,
    1132             :             aCounts.maxTextRunLen,
    1133             :             lookups, hitRatio,
    1134             :             aCounts.wordCacheSpaceRules, aCounts.wordCacheLong,
    1135             :             aCounts.fallbackPrefs, aCounts.fallbackSystem,
    1136             :             aCounts.textrunConst, aCounts.textrunDestr,
    1137             :             aCounts.genericLookups,
    1138             :             aTextPerf->cumulative.textrunDestr));
    1139             :   } else {
    1140           0 :     MOZ_LOG(tpLog, logLevel,
    1141             :            ("%s reflow: %d chars: %d "
    1142             :             "content-textruns: %d chrome-textruns: %d "
    1143             :             "max-textrun-len: %d "
    1144             :             "word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
    1145             :             "word-cache-space: %d word-cache-long: %d "
    1146             :             "pref-fallbacks: %d system-fallbacks: %d "
    1147             :             "textruns-const: %d textruns-destr: %d "
    1148             :             "generic-lookups: %d "
    1149             :             "cumulative-textruns-destr: %d\n",
    1150             :             prefix, aTextPerf->reflowCount, aCounts.numChars,
    1151             :             aCounts.numContentTextRuns, aCounts.numChromeTextRuns,
    1152             :             aCounts.maxTextRunLen,
    1153             :             lookups, hitRatio,
    1154             :             aCounts.wordCacheSpaceRules, aCounts.wordCacheLong,
    1155             :             aCounts.fallbackPrefs, aCounts.fallbackSystem,
    1156             :             aCounts.textrunConst, aCounts.textrunDestr,
    1157             :             aCounts.genericLookups,
    1158             :             aTextPerf->cumulative.textrunDestr));
    1159             :   }
    1160             : }
    1161             : 
    1162             : void
    1163           4 : PresShell::Destroy()
    1164             : {
    1165             :   // Do not add code before this line please!
    1166           4 :   if (mHaveShutDown) {
    1167             :     // If we never got a root frame the root view could exist now still.
    1168             :     // In that case assert that it has no children and no frame.
    1169           0 :     MOZ_RELEASE_ASSERT(!mViewManager || !mViewManager->GetRootView() ||
    1170             :       (!mViewManager->GetRootView()->GetFrame() &&
    1171             :        !mViewManager->GetRootView()->GetFirstChild()));
    1172           0 :     MOZ_RELEASE_ASSERT(!mFrameConstructor || !mFrameConstructor->GetRootFrame());
    1173           0 :     return;
    1174             :   }
    1175             : 
    1176           4 :   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
    1177             :     "destroy called on presshell while scripts not blocked");
    1178             : 
    1179             :   // dump out cumulative text perf metrics
    1180             :   gfxTextPerfMetrics* tp;
    1181           4 :   if (mPresContext && (tp = mPresContext->GetTextPerfMetrics())) {
    1182           0 :     tp->Accumulate();
    1183           0 :     if (tp->cumulative.numChars > 0) {
    1184           0 :       LogTextPerfStats(tp, this, tp->cumulative, 0.0, eLog_totals, nullptr);
    1185             :     }
    1186             :   }
    1187           4 :   if (mPresContext) {
    1188           4 :     const bool mayFlushUserFontSet = false;
    1189           4 :     gfxUserFontSet* fs = mPresContext->GetUserFontSet(mayFlushUserFontSet);
    1190           4 :     if (fs) {
    1191             :       uint32_t fontCount;
    1192             :       uint64_t fontSize;
    1193           0 :       fs->GetLoadStatistics(fontCount, fontSize);
    1194           0 :       Telemetry::Accumulate(Telemetry::WEBFONT_PER_PAGE, fontCount);
    1195           0 :       Telemetry::Accumulate(Telemetry::WEBFONT_SIZE_PER_PAGE,
    1196           0 :                             uint32_t(fontSize/1024));
    1197             :     } else {
    1198           4 :       Telemetry::Accumulate(Telemetry::WEBFONT_PER_PAGE, 0);
    1199           4 :       Telemetry::Accumulate(Telemetry::WEBFONT_SIZE_PER_PAGE, 0);
    1200             :     }
    1201             :   }
    1202             : 
    1203             : #ifdef MOZ_REFLOW_PERF
    1204           4 :   DumpReflows();
    1205           4 :   if (mReflowCountMgr) {
    1206           4 :     delete mReflowCountMgr;
    1207           4 :     mReflowCountMgr = nullptr;
    1208             :   }
    1209             : #endif
    1210             : 
    1211           4 :   if (mZoomConstraintsClient) {
    1212           2 :     mZoomConstraintsClient->Destroy();
    1213           2 :     mZoomConstraintsClient = nullptr;
    1214             :   }
    1215           4 :   if (mMobileViewportManager) {
    1216           0 :     mMobileViewportManager->Destroy();
    1217           0 :     mMobileViewportManager = nullptr;
    1218             :   }
    1219             : 
    1220             : #ifdef ACCESSIBILITY
    1221           4 :   if (mDocAccessible) {
    1222             : #ifdef DEBUG
    1223           0 :     if (a11y::logging::IsEnabled(a11y::logging::eDocDestroy))
    1224           0 :       a11y::logging::DocDestroy("presshell destroyed", mDocument);
    1225             : #endif
    1226             : 
    1227           0 :     mDocAccessible->Shutdown();
    1228           0 :     mDocAccessible = nullptr;
    1229             :   }
    1230             : #endif // ACCESSIBILITY
    1231             : 
    1232           4 :   MaybeReleaseCapturingContent();
    1233             : 
    1234           4 :   if (gKeyDownTarget && gKeyDownTarget->OwnerDoc() == mDocument) {
    1235           0 :     NS_RELEASE(gKeyDownTarget);
    1236             :   }
    1237             : 
    1238           4 :   if (mContentToScrollTo) {
    1239           0 :     mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
    1240           0 :     mContentToScrollTo = nullptr;
    1241             :   }
    1242             : 
    1243           4 :   if (mPresContext) {
    1244             :     // We need to notify the destroying the nsPresContext to ESM for
    1245             :     // suppressing to use from ESM.
    1246           4 :     mPresContext->EventStateManager()->NotifyDestroyPresContext(mPresContext);
    1247             :   }
    1248             : 
    1249           4 :   if (nsStyleSheetService* ss = nsStyleSheetService::GetInstance()) {
    1250           4 :     ss->UnregisterPresShell(this);
    1251             :   }
    1252             : 
    1253             :   {
    1254           8 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    1255           4 :     if (os) {
    1256             : #ifdef MOZ_XUL
    1257           4 :       os->RemoveObserver(this, "chrome-flush-skin-caches");
    1258             : #endif
    1259           4 :       os->RemoveObserver(this, "memory-pressure");
    1260           4 :       os->RemoveObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC);
    1261             :     }
    1262             :   }
    1263             : 
    1264             :   // If our paint suppression timer is still active, kill it.
    1265           4 :   if (mPaintSuppressionTimer) {
    1266           0 :     mPaintSuppressionTimer->Cancel();
    1267           0 :     mPaintSuppressionTimer = nullptr;
    1268             :   }
    1269             : 
    1270             :   // Same for our reflow continuation timer
    1271           4 :   if (mReflowContinueTimer) {
    1272           0 :     mReflowContinueTimer->Cancel();
    1273           0 :     mReflowContinueTimer = nullptr;
    1274             :   }
    1275             : 
    1276           4 :   if (mDelayedPaintTimer) {
    1277           0 :     mDelayedPaintTimer->Cancel();
    1278           0 :     mDelayedPaintTimer = nullptr;
    1279             :   }
    1280             : 
    1281           4 :   mSynthMouseMoveEvent.Revoke();
    1282             : 
    1283           4 :   mUpdateApproximateFrameVisibilityEvent.Revoke();
    1284             : 
    1285           4 :   ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DISCARD_IMAGES));
    1286             : 
    1287           4 :   if (mCaret) {
    1288           4 :     mCaret->Terminate();
    1289           4 :     mCaret = nullptr;
    1290             :   }
    1291             : 
    1292           4 :   if (mSelection) {
    1293           8 :     RefPtr<nsFrameSelection> frameSelection = mSelection;
    1294           4 :     frameSelection->DisconnectFromPresShell();
    1295             :   }
    1296             : 
    1297           4 :   if (mAccessibleCaretEventHub) {
    1298           0 :     mAccessibleCaretEventHub->Terminate();
    1299           0 :     mAccessibleCaretEventHub = nullptr;
    1300             :   }
    1301             : 
    1302             :   // release our pref style sheet, if we have one still
    1303           4 :   RemovePreferenceStyles();
    1304             : 
    1305           4 :   mIsDestroying = true;
    1306             : 
    1307             :   // We can't release all the event content in
    1308             :   // mCurrentEventContentStack here since there might be code on the
    1309             :   // stack that will release the event content too. Double release
    1310             :   // bad!
    1311             : 
    1312             :   // The frames will be torn down, so remove them from the current
    1313             :   // event frame stack (since they'd be dangling references if we'd
    1314             :   // leave them in) and null out the mCurrentEventFrame pointer as
    1315             :   // well.
    1316             : 
    1317           4 :   mCurrentEventFrame = nullptr;
    1318             : 
    1319           4 :   int32_t i, count = mCurrentEventFrameStack.Length();
    1320           4 :   for (i = 0; i < count; i++) {
    1321           0 :     mCurrentEventFrameStack[i] = nullptr;
    1322             :   }
    1323             : 
    1324           4 :   mFramesToDirty.Clear();
    1325             : 
    1326           4 :   if (mViewManager) {
    1327             :     // Clear the view manager's weak pointer back to |this| in case it
    1328             :     // was leaked.
    1329           4 :     mViewManager->SetPresShell(nullptr);
    1330           4 :     mViewManager = nullptr;
    1331             :   }
    1332             : 
    1333             :   // mFrameArena will be destroyed soon.  Clear out any ArenaRefPtrs
    1334             :   // pointing to objects in the arena now.  This is done:
    1335             :   //
    1336             :   //   (a) before mFrameArena's destructor runs so that our
    1337             :   //       mAllocatedPointers becomes empty and doesn't trip the assertion
    1338             :   //       in ~PresShell,
    1339             :   //   (b) before the mPresContext->DetachShell() below, so
    1340             :   //       that when we clear the ArenaRefPtrs they'll still be able to
    1341             :   //       get back to this PresShell to deregister themselves (e.g. note
    1342             :   //       how nsStyleContext::Arena returns the PresShell got from its
    1343             :   //       rule node's nsPresContext, which would return null if we'd already
    1344             :   //       called mPresContext->DetachShell()), and
    1345             :   //   (c) before the mStyleSet->BeginShutdown() call just below, so that
    1346             :   //       the nsStyleContexts don't complain they're being destroyed later
    1347             :   //       than the rule tree is.
    1348           4 :   mFrameArena.ClearArenaRefPtrs();
    1349             : 
    1350           4 :   mStyleSet->BeginShutdown();
    1351           4 :   nsRefreshDriver* rd = GetPresContext()->RefreshDriver();
    1352             : 
    1353             :   // This shell must be removed from the document before the frame
    1354             :   // hierarchy is torn down to avoid finding deleted frames through
    1355             :   // this presshell while the frames are being torn down
    1356           4 :   if (mDocument) {
    1357           4 :     NS_ASSERTION(mDocument->GetShell() == this, "Wrong shell?");
    1358           4 :     mDocument->DeleteShell();
    1359             : 
    1360           4 :     if (mDocument->HasAnimationController()) {
    1361           0 :       mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
    1362             :     }
    1363           4 :     for (DocumentTimeline* timeline : mDocument->Timelines()) {
    1364           0 :       timeline->NotifyRefreshDriverDestroying(rd);
    1365             :     }
    1366             :   }
    1367             : 
    1368           4 :   if (mPresContext) {
    1369           4 :     mPresContext->AnimationManager()->ClearEventQueue();
    1370           4 :     mPresContext->TransitionManager()->ClearEventQueue();
    1371             :   }
    1372             : 
    1373             :   // Revoke any pending events.  We need to do this and cancel pending reflows
    1374             :   // before we destroy the frame manager, since apparently frame destruction
    1375             :   // sometimes spins the event queue when plug-ins are involved(!).
    1376           4 :   rd->RemoveLayoutFlushObserver(this);
    1377             : 
    1378           4 :   if (rd->GetPresContext() == GetPresContext()) {
    1379           4 :     rd->RevokeViewManagerFlush();
    1380             :   }
    1381             : 
    1382           4 :   mResizeEvent.Revoke();
    1383           4 :   if (mAsyncResizeTimerIsActive) {
    1384           0 :     mAsyncResizeEventTimer->Cancel();
    1385           0 :     mAsyncResizeTimerIsActive = false;
    1386             :   }
    1387             : 
    1388           4 :   CancelAllPendingReflows();
    1389           4 :   CancelPostedReflowCallbacks();
    1390             : 
    1391             :   // Destroy the frame manager. This will destroy the frame hierarchy
    1392           4 :   mFrameConstructor->WillDestroyFrameTree();
    1393             : 
    1394           4 :   NS_WARNING_ASSERTION(!mAutoWeakFrames && mWeakFrames.IsEmpty(),
    1395             :                        "Weak frames alive after destroying FrameManager");
    1396           4 :   while (mAutoWeakFrames) {
    1397           0 :     mAutoWeakFrames->Clear(this);
    1398             :   }
    1399           8 :   nsTArray<WeakFrame*> toRemove(mWeakFrames.Count());
    1400           4 :   for (auto iter = mWeakFrames.Iter(); !iter.Done(); iter.Next()) {
    1401           0 :     toRemove.AppendElement(iter.Get()->GetKey());
    1402             :   }
    1403           4 :   for (WeakFrame* weakFrame : toRemove) {
    1404           0 :     weakFrame->Clear(this);
    1405             :   }
    1406             : 
    1407             :   // Let the style set do its cleanup.
    1408           4 :   mStyleSet->Shutdown();
    1409             : 
    1410           4 :   if (mPresContext) {
    1411             :     // We hold a reference to the pres context, and it holds a weak link back
    1412             :     // to us. To avoid the pres context having a dangling reference, set its
    1413             :     // pres shell to nullptr
    1414           4 :     mPresContext->DetachShell();
    1415             : 
    1416             :     // Clear the link handler (weak reference) as well
    1417           4 :     mPresContext->SetLinkHandler(nullptr);
    1418             :   }
    1419             : 
    1420           4 :   mHaveShutDown = true;
    1421             : 
    1422           4 :   mTouchManager.Destroy();
    1423             : }
    1424             : 
    1425             : nsRefreshDriver*
    1426          56 : nsIPresShell::GetRefreshDriver() const
    1427             : {
    1428          56 :   return mPresContext ? mPresContext->RefreshDriver() : nullptr;
    1429             : }
    1430             : 
    1431             : void
    1432           3 : nsIPresShell::SetAuthorStyleDisabled(bool aStyleDisabled)
    1433             : {
    1434           3 :   if (aStyleDisabled != mStyleSet->GetAuthorStyleDisabled()) {
    1435           0 :     mStyleSet->SetAuthorStyleDisabled(aStyleDisabled);
    1436           0 :     RestyleForCSSRuleChanges();
    1437             : 
    1438             :     nsCOMPtr<nsIObserverService> observerService =
    1439           0 :       mozilla::services::GetObserverService();
    1440           0 :     if (observerService) {
    1441           0 :       observerService->NotifyObservers(mDocument,
    1442             :                                        "author-style-disabled-changed",
    1443           0 :                                        nullptr);
    1444             :     }
    1445             :   }
    1446           3 : }
    1447             : 
    1448             : bool
    1449           7 : nsIPresShell::GetAuthorStyleDisabled() const
    1450             : {
    1451           7 :   return mStyleSet->GetAuthorStyleDisabled();
    1452             : }
    1453             : 
    1454             : void
    1455          28 : PresShell::UpdatePreferenceStyles()
    1456             : {
    1457          28 :   if (!mDocument) {
    1458          25 :     return;
    1459             :   }
    1460             : 
    1461             :   // If the document doesn't have a window there's no need to notify
    1462             :   // its presshell about changes to preferences since the document is
    1463             :   // in a state where it doesn't matter any more (see
    1464             :   // nsDocumentViewer::Close()).
    1465          28 :   if (!mDocument->GetWindow()) {
    1466          21 :     return;
    1467             :   }
    1468             : 
    1469             :   // Documents in chrome shells do not have any preference style rules applied.
    1470           7 :   if (nsContentUtils::IsInChromeDocshell(mDocument)) {
    1471           4 :     return;
    1472             :   }
    1473             : 
    1474             :   // We need to pass in mPresContext so that if the nsLayoutStylesheetCache
    1475             :   // needs to recreate the pref style sheet, it has somewhere to get the
    1476             :   // pref styling information from.  All pres contexts for
    1477             :   // IsChromeOriginImage() == false will have the same pref styling information,
    1478             :   // and similarly for IsChromeOriginImage() == true, so it doesn't really
    1479             :   // matter which pres context we pass in when it does need to be recreated.
    1480             :   // (See nsPresContext::GetDocumentColorPreferences for how whether we
    1481             :   // are a chrome origin image affects some pref styling information.)
    1482           3 :   auto cache = nsLayoutStylesheetCache::For(mStyleSet->BackendType());
    1483             :   RefPtr<StyleSheet> newPrefSheet =
    1484           3 :     mPresContext->IsChromeOriginImage() ?
    1485           0 :       cache->ChromePreferenceSheet(mPresContext) :
    1486           6 :       cache->ContentPreferenceSheet(mPresContext);
    1487             : 
    1488           3 :   if (mPrefStyleSheet == newPrefSheet) {
    1489           0 :     return;
    1490             :   }
    1491             : 
    1492           3 :   mStyleSet->BeginUpdate();
    1493             : 
    1494           3 :   RemovePreferenceStyles();
    1495             : 
    1496           3 :   mStyleSet->AppendStyleSheet(SheetType::User, newPrefSheet);
    1497           3 :   mPrefStyleSheet = newPrefSheet;
    1498             : 
    1499           3 :   mStyleSet->EndUpdate();
    1500             : }
    1501             : 
    1502             : void
    1503           7 : PresShell::RemovePreferenceStyles()
    1504             : {
    1505           7 :   if (mPrefStyleSheet) {
    1506           2 :     mStyleSet->RemoveStyleSheet(SheetType::User, mPrefStyleSheet);
    1507           2 :     mPrefStyleSheet = nullptr;
    1508             :   }
    1509           7 : }
    1510             : 
    1511             : void
    1512           0 : PresShell::AddUserSheet(StyleSheet* aSheet)
    1513             : {
    1514             :   // Make sure this does what nsDocumentViewer::CreateStyleSet does wrt
    1515             :   // ordering. We want this new sheet to come after all the existing stylesheet
    1516             :   // service sheets, but before other user sheets; see nsIStyleSheetService.idl
    1517             :   // for the ordering.  Just remove and readd all the nsStyleSheetService
    1518             :   // sheets.
    1519             :   nsCOMPtr<nsIStyleSheetService> dummy =
    1520           0 :     do_GetService(NS_STYLESHEETSERVICE_CONTRACTID);
    1521             : 
    1522           0 :   mStyleSet->BeginUpdate();
    1523             : 
    1524           0 :   nsStyleSheetService* sheetService = nsStyleSheetService::gInstance;
    1525             :   nsTArray<RefPtr<StyleSheet>>& userSheets =
    1526           0 :     *sheetService->UserStyleSheets(mStyleSet->BackendType());
    1527             :   // Iterate forwards when removing so the searches for RemoveStyleSheet are as
    1528             :   // short as possible.
    1529           0 :   for (StyleSheet* sheet : userSheets) {
    1530           0 :     mStyleSet->RemoveStyleSheet(SheetType::User, sheet);
    1531             :   }
    1532             : 
    1533             :   // Now iterate backwards, so that the order of userSheets will be the same as
    1534             :   // the order of sheets from it in the style set.
    1535           0 :   for (StyleSheet* sheet : Reversed(userSheets)) {
    1536           0 :     mStyleSet->PrependStyleSheet(SheetType::User, sheet);
    1537             :   }
    1538             : 
    1539           0 :   mStyleSet->EndUpdate();
    1540           0 :   RestyleForCSSRuleChanges();
    1541           0 : }
    1542             : 
    1543             : void
    1544           0 : PresShell::AddAgentSheet(StyleSheet* aSheet)
    1545             : {
    1546             :   // Make sure this does what nsDocumentViewer::CreateStyleSet does
    1547             :   // wrt ordering.
    1548           0 :   mStyleSet->AppendStyleSheet(SheetType::Agent, aSheet);
    1549           0 :   RestyleForCSSRuleChanges();
    1550           0 : }
    1551             : 
    1552             : void
    1553           0 : PresShell::AddAuthorSheet(StyleSheet* aSheet)
    1554             : {
    1555             :   // Document specific "additional" Author sheets should be stronger than the
    1556             :   // ones added with the StyleSheetService.
    1557             :   StyleSheet* firstAuthorSheet =
    1558           0 :     mDocument->GetFirstAdditionalAuthorSheet();
    1559           0 :   if (firstAuthorSheet) {
    1560           0 :     mStyleSet->InsertStyleSheetBefore(SheetType::Doc, aSheet, firstAuthorSheet);
    1561             :   } else {
    1562           0 :     mStyleSet->AppendStyleSheet(SheetType::Doc, aSheet);
    1563             :   }
    1564             : 
    1565           0 :   RestyleForCSSRuleChanges();
    1566           0 : }
    1567             : 
    1568             : void
    1569           0 : PresShell::RemoveSheet(SheetType aType, StyleSheet* aSheet)
    1570             : {
    1571           0 :   mStyleSet->RemoveStyleSheet(aType, aSheet);
    1572           0 :   RestyleForCSSRuleChanges();
    1573           0 : }
    1574             : 
    1575             : NS_IMETHODIMP
    1576          31 : PresShell::SetDisplaySelection(int16_t aToggle)
    1577             : {
    1578          62 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1579          31 :   frameSelection->SetDisplaySelection(aToggle);
    1580          62 :   return NS_OK;
    1581             : }
    1582             : 
    1583             : NS_IMETHODIMP
    1584           3 : PresShell::GetDisplaySelection(int16_t *aToggle)
    1585             : {
    1586           6 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1587           3 :   *aToggle = frameSelection->GetDisplaySelection();
    1588           6 :   return NS_OK;
    1589             : }
    1590             : 
    1591             : NS_IMETHODIMP
    1592          31 : PresShell::GetSelection(RawSelectionType aRawSelectionType,
    1593             :                         nsISelection **aSelection)
    1594             : {
    1595          31 :   if (!aSelection || !mSelection)
    1596           0 :     return NS_ERROR_NULL_POINTER;
    1597             : 
    1598          62 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1599             :   nsCOMPtr<nsISelection> selection =
    1600          62 :     frameSelection->GetSelection(ToSelectionType(aRawSelectionType));
    1601             : 
    1602          31 :   if (!selection) {
    1603           0 :     return NS_ERROR_INVALID_ARG;
    1604             :   }
    1605             : 
    1606          31 :   selection.forget(aSelection);
    1607          31 :   return NS_OK;
    1608             : }
    1609             : 
    1610             : Selection*
    1611          38 : PresShell::GetCurrentSelection(SelectionType aSelectionType)
    1612             : {
    1613          38 :   if (!mSelection)
    1614           0 :     return nullptr;
    1615             : 
    1616          76 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1617          38 :   return frameSelection->GetSelection(aSelectionType);
    1618             : }
    1619             : 
    1620             : already_AddRefed<nsISelectionController>
    1621           3 : PresShell::GetSelectionControllerForFocusedContent(nsIContent** aFocusedContent)
    1622             : {
    1623           3 :   if (aFocusedContent) {
    1624           3 :     *aFocusedContent = nullptr;
    1625             :   }
    1626             : 
    1627           3 :   if (mDocument) {
    1628           5 :     nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    1629             :     nsCOMPtr<nsIContent> focusedContent =
    1630             :       nsFocusManager::GetFocusedDescendant(mDocument->GetWindow(), false,
    1631           5 :                                            getter_AddRefs(focusedWindow));
    1632           3 :     if (focusedContent) {
    1633           1 :       nsIFrame* frame = focusedContent->GetPrimaryFrame();
    1634           1 :       if (frame) {
    1635           1 :         nsCOMPtr<nsISelectionController> selectionController;
    1636           1 :         frame->GetSelectionController(mPresContext,
    1637           2 :                                       getter_AddRefs(selectionController));
    1638           1 :         if (selectionController) {
    1639           1 :           if (aFocusedContent) {
    1640           1 :             focusedContent.forget(aFocusedContent);
    1641             :           }
    1642           1 :           return selectionController.forget();
    1643             :         }
    1644             :       }
    1645             :     }
    1646             :   }
    1647           4 :   nsCOMPtr<nsISelectionController> self(this);
    1648           2 :   return self.forget();
    1649             : }
    1650             : 
    1651             : NS_IMETHODIMP
    1652           0 : PresShell::ScrollSelectionIntoView(RawSelectionType aRawSelectionType,
    1653             :                                    SelectionRegion aRegion,
    1654             :                                    int16_t aFlags)
    1655             : {
    1656           0 :   if (!mSelection)
    1657           0 :     return NS_ERROR_NULL_POINTER;
    1658             : 
    1659           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1660           0 :   return frameSelection->ScrollSelectionIntoView(
    1661           0 :                            ToSelectionType(aRawSelectionType), aRegion, aFlags);
    1662             : }
    1663             : 
    1664             : NS_IMETHODIMP
    1665           3 : PresShell::RepaintSelection(RawSelectionType aRawSelectionType)
    1666             : {
    1667           3 :   if (!mSelection)
    1668           0 :     return NS_ERROR_NULL_POINTER;
    1669             : 
    1670           6 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1671           3 :   return frameSelection->RepaintSelection(ToSelectionType(aRawSelectionType));
    1672             : }
    1673             : 
    1674             : // Make shell be a document observer
    1675             : void
    1676          28 : PresShell::BeginObservingDocument()
    1677             : {
    1678          28 :   if (mDocument && !mIsDestroying) {
    1679          28 :     mDocument->AddObserver(this);
    1680          28 :     if (mIsDocumentGone) {
    1681             :       NS_WARNING("Adding a presshell that was disconnected from the document "
    1682           0 :                  "as a document observer?  Sounds wrong...");
    1683           0 :       mIsDocumentGone = false;
    1684             :     }
    1685             :   }
    1686          28 : }
    1687             : 
    1688             : // Make shell stop being a document observer
    1689             : void
    1690           4 : PresShell::EndObservingDocument()
    1691             : {
    1692             :   // XXXbz do we need to tell the frame constructor that the document
    1693             :   // is gone, perhaps?  Except for printing it's NOT gone, sometimes.
    1694           4 :   mIsDocumentGone = true;
    1695           4 :   if (mDocument) {
    1696           4 :     mDocument->RemoveObserver(this);
    1697             :   }
    1698           4 : }
    1699             : 
    1700             : #ifdef DEBUG_kipp
    1701             : char* nsPresShell_ReflowStackPointerTop;
    1702             : #endif
    1703             : 
    1704          72 : class XBLConstructorRunner : public Runnable
    1705             : {
    1706             : public:
    1707          24 :   explicit XBLConstructorRunner(nsIDocument* aDocument)
    1708          24 :     : Runnable("XBLConstructorRunner")
    1709          24 :     , mDocument(aDocument)
    1710             :   {
    1711          24 :   }
    1712             : 
    1713          24 :   NS_IMETHOD Run() override
    1714             :   {
    1715          24 :     mDocument->BindingManager()->ProcessAttachedQueue();
    1716          24 :     return NS_OK;
    1717             :   }
    1718             : 
    1719             : private:
    1720             :   nsCOMPtr<nsIDocument> mDocument;
    1721             : };
    1722             : 
    1723             : nsresult
    1724          24 : PresShell::Initialize(nscoord aWidth, nscoord aHeight)
    1725             : {
    1726          24 :   if (mIsDestroying) {
    1727           0 :     return NS_OK;
    1728             :   }
    1729             : 
    1730          24 :   if (!mDocument) {
    1731             :     // Nothing to do
    1732           0 :     return NS_OK;
    1733             :   }
    1734             : 
    1735          24 :   NS_ASSERTION(!mDidInitialize, "Why are we being called?");
    1736             : 
    1737          48 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
    1738          24 :   mDidInitialize = true;
    1739             : 
    1740             : #ifdef DEBUG
    1741          24 :   if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
    1742           0 :     if (mDocument) {
    1743           0 :       nsIURI *uri = mDocument->GetDocumentURI();
    1744           0 :       if (uri) {
    1745           0 :         printf("*** PresShell::Initialize (this=%p, url='%s')\n",
    1746           0 :                (void*)this, uri->GetSpecOrDefault().get());
    1747             :       }
    1748             :     }
    1749             :   }
    1750             : #endif
    1751             : 
    1752             :   // XXX Do a full invalidate at the beginning so that invalidates along
    1753             :   // the way don't have region accumulation issues?
    1754             : 
    1755          24 :   mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
    1756             : 
    1757             :   // Get the root frame from the frame manager
    1758             :   // XXXbz it would be nice to move this somewhere else... like frame manager
    1759             :   // Init(), say.  But we need to make sure our views are all set up by the
    1760             :   // time we do this!
    1761          24 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    1762          24 :   NS_ASSERTION(!rootFrame, "How did that happen, exactly?");
    1763          24 :   if (!rootFrame) {
    1764          48 :     nsAutoScriptBlocker scriptBlocker;
    1765          24 :     mFrameConstructor->BeginUpdate();
    1766          24 :     rootFrame = mFrameConstructor->ConstructRootFrame();
    1767          24 :     mFrameConstructor->SetRootFrame(rootFrame);
    1768          24 :     mFrameConstructor->EndUpdate();
    1769             :   }
    1770             : 
    1771          24 :   NS_ENSURE_STATE(!mHaveShutDown);
    1772             : 
    1773          24 :   if (!rootFrame) {
    1774           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1775             :   }
    1776             : 
    1777          24 :   nsIFrame* invalidateFrame = nullptr;
    1778          48 :   for (nsIFrame* f = rootFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
    1779          24 :     if (f->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) {
    1780           0 :       invalidateFrame = f;
    1781           0 :       f->RemoveStateBits(NS_FRAME_NO_COMPONENT_ALPHA);
    1782             :     }
    1783          48 :     nsCOMPtr<nsIPresShell> shell;
    1784          48 :     if (f->IsSubDocumentFrame() &&
    1785             :         (shell = static_cast<nsSubDocumentFrame*>(f)
    1786          24 :                    ->GetSubdocumentPresShellForPainting(0)) &&
    1787           0 :         shell->GetPresContext()->IsRootContentDocument()) {
    1788             :       // Root content documents build a 'force active' layer, and component alpha flattening
    1789             :       // can't be propagated across that so no need to invalidate above this frame.
    1790           0 :       break;
    1791             :     }
    1792             : 
    1793             : 
    1794             :   }
    1795          24 :   if (invalidateFrame) {
    1796           0 :     invalidateFrame->InvalidateFrameSubtree();
    1797             :   }
    1798             : 
    1799          24 :   Element *root = mDocument->GetRootElement();
    1800             : 
    1801          24 :   if (root) {
    1802             :     {
    1803          48 :       nsAutoCauseReflowNotifier reflowNotifier(this);
    1804          24 :       mFrameConstructor->BeginUpdate();
    1805             : 
    1806             :       // Have the style sheet processor construct frame for the root
    1807             :       // content object down
    1808          24 :       mFrameConstructor->ContentInserted(nullptr, root, nullptr, false);
    1809          24 :       VERIFY_STYLE_TREE;
    1810             : 
    1811             :       // Something in mFrameConstructor->ContentInserted may have caused
    1812             :       // Destroy() to get called, bug 337586.
    1813          24 :       NS_ENSURE_STATE(!mHaveShutDown);
    1814             : 
    1815          24 :       mFrameConstructor->EndUpdate();
    1816             :     }
    1817             : 
    1818             :     // nsAutoCauseReflowNotifier (which sets up a script blocker) going out of
    1819             :     // scope may have killed us too
    1820          24 :     NS_ENSURE_STATE(!mHaveShutDown);
    1821             : 
    1822             :     // Run the XBL binding constructors for any new frames we've constructed.
    1823             :     // (Do this in a script runner, since our caller might have a script
    1824             :     // blocker on the stack.)
    1825          48 :     nsContentUtils::AddScriptRunner(new XBLConstructorRunner(mDocument));
    1826             :   }
    1827             : 
    1828          24 :   NS_ASSERTION(rootFrame, "How did that happen?");
    1829             : 
    1830             :   // Note: when the frame was created above it had the NS_FRAME_IS_DIRTY bit
    1831             :   // set, but XBL processing could have caused a reflow which clears it.
    1832          24 :   if (MOZ_LIKELY(rootFrame->GetStateBits() & NS_FRAME_IS_DIRTY)) {
    1833             :     // Unset the DIRTY bits so that FrameNeedsReflow() will work right.
    1834          24 :     rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY |
    1835          24 :                                NS_FRAME_HAS_DIRTY_CHILDREN);
    1836          24 :     NS_ASSERTION(!mDirtyRoots.Contains(rootFrame),
    1837             :                  "Why is the root in mDirtyRoots already?");
    1838          24 :     FrameNeedsReflow(rootFrame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
    1839          24 :     NS_ASSERTION(mDirtyRoots.Contains(rootFrame),
    1840             :                  "Should be in mDirtyRoots now");
    1841          24 :     NS_ASSERTION(mObservingLayoutFlushes, "Why no reflow scheduled?");
    1842             :   }
    1843             : 
    1844             :   // Restore our root scroll position now if we're getting here after EndLoad
    1845             :   // got called, since this is our one chance to do it.  Note that we need not
    1846             :   // have reflowed for this to work; when the scrollframe is finally reflowed
    1847             :   // it'll pick up the position we store in it here.
    1848          24 :   if (!mDocumentLoading) {
    1849           1 :     RestoreRootScrollPosition();
    1850             :   }
    1851             : 
    1852             :   // For printing, we just immediately unsuppress.
    1853          24 :   if (!mPresContext->IsPaginated()) {
    1854             :     // Kick off a one-shot timer based off our pref value.  When this timer
    1855             :     // fires, if painting is still locked down, then we will go ahead and
    1856             :     // trigger a full invalidate and allow painting to proceed normally.
    1857          24 :     mPaintingSuppressed = true;
    1858             :     // Don't suppress painting if the document isn't loading.
    1859          24 :     nsIDocument::ReadyState readyState = mDocument->GetReadyStateEnum();
    1860          24 :     if (readyState != nsIDocument::READYSTATE_COMPLETE) {
    1861          24 :       mPaintSuppressionTimer = do_CreateInstance("@mozilla.org/timer;1");
    1862             :     }
    1863          24 :     if (!mPaintSuppressionTimer) {
    1864           0 :       mPaintingSuppressed = false;
    1865             :     } else {
    1866             :       // Initialize the timer.
    1867             : 
    1868             :       // Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value.
    1869             :       int32_t delay =
    1870             :         Preferences::GetInt("nglayout.initialpaint.delay",
    1871          24 :                             PAINTLOCK_EVENT_DELAY);
    1872             : 
    1873          24 :       mPaintSuppressionTimer->SetTarget(
    1874          24 :           mDocument->EventTargetFor(TaskCategory::Other));
    1875          48 :       mPaintSuppressionTimer->InitWithNamedFuncCallback(
    1876             :         sPaintSuppressionCallback, this, delay, nsITimer::TYPE_ONE_SHOT,
    1877          48 :         "PresShell::sPaintSuppressionCallback");
    1878             :     }
    1879             :   }
    1880             : 
    1881             :   // If we get here and painting is not suppressed, then we can paint anytime
    1882             :   // and we should fire the before-first-paint notification
    1883          24 :   if (!mPaintingSuppressed) {
    1884           0 :     ScheduleBeforeFirstPaint();
    1885             :   }
    1886             : 
    1887          24 :   return NS_OK; //XXX this needs to be real. MMP
    1888             : }
    1889             : 
    1890             : void
    1891          22 : PresShell::sPaintSuppressionCallback(nsITimer *aTimer, void* aPresShell)
    1892             : {
    1893          44 :   RefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
    1894          22 :   if (self)
    1895          22 :     self->UnsuppressPainting();
    1896          22 : }
    1897             : 
    1898             : void
    1899           0 : PresShell::AsyncResizeEventCallback(nsITimer* aTimer, void* aPresShell)
    1900             : {
    1901           0 :   static_cast<PresShell*>(aPresShell)->FireResizeEvent();
    1902           0 : }
    1903             : 
    1904             : nsresult
    1905          22 : PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight)
    1906             : {
    1907          22 :   if (mZoomConstraintsClient) {
    1908             :     // If we have a ZoomConstraintsClient and the available screen area
    1909             :     // changed, then we might need to disable double-tap-to-zoom, so notify
    1910             :     // the ZCC to update itself.
    1911           2 :     mZoomConstraintsClient->ScreenSizeChanged();
    1912             :   }
    1913          22 :   if (mMobileViewportManager) {
    1914             :     // If we have a mobile viewport manager, request a reflow from it. It can
    1915             :     // recompute the final CSS viewport and trigger a call to
    1916             :     // ResizeReflowIgnoreOverride if it changed.
    1917           0 :     mMobileViewportManager->RequestReflow();
    1918           0 :     return NS_OK;
    1919             :   }
    1920             : 
    1921          22 :   return ResizeReflowIgnoreOverride(aWidth, aHeight, aOldWidth, aOldHeight);
    1922             : }
    1923             : 
    1924             : nsresult
    1925          22 : PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight)
    1926             : {
    1927          22 :   NS_PRECONDITION(!mIsReflowing, "Shouldn't be in reflow here!");
    1928             : 
    1929             :   // If we don't have a root frame yet, that means we haven't had our initial
    1930             :   // reflow... If that's the case, and aWidth or aHeight is unconstrained,
    1931             :   // ignore them altogether.
    1932          22 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    1933          22 :   if (!rootFrame && aHeight == NS_UNCONSTRAINEDSIZE) {
    1934             :     // We can't do the work needed for SizeToContent without a root
    1935             :     // frame, and we want to return before setting the visible area.
    1936           0 :     return NS_ERROR_NOT_AVAILABLE;
    1937             :   }
    1938             : 
    1939          22 :   mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
    1940             : 
    1941             :   // There isn't anything useful we can do if the initial reflow hasn't happened.
    1942          22 :   if (!rootFrame) {
    1943           2 :     return NS_OK;
    1944             :   }
    1945             : 
    1946          20 :   WritingMode wm = rootFrame->GetWritingMode();
    1947          20 :   NS_PRECONDITION((wm.IsVertical() ? aHeight : aWidth) != NS_UNCONSTRAINEDSIZE,
    1948             :                   "shouldn't use unconstrained isize anymore");
    1949             : 
    1950          20 :   const bool isBSizeChanging = wm.IsVertical()
    1951          20 :                                ? aOldWidth != aWidth
    1952          20 :                                : aOldHeight != aHeight;
    1953             : 
    1954          40 :   RefPtr<nsViewManager> viewManager = mViewManager;
    1955          40 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
    1956             : 
    1957          20 :   if (!GetPresContext()->SuppressingResizeReflow()) {
    1958             :     // Have to make sure that the content notifications are flushed before we
    1959             :     // start messing with the frame model; otherwise we can get content doubling.
    1960          20 :     mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
    1961             : 
    1962             :     // Make sure style is up to date
    1963             :     {
    1964          40 :       nsAutoScriptBlocker scriptBlocker;
    1965          20 :       mPresContext->RestyleManager()->ProcessPendingRestyles();
    1966             :     }
    1967             : 
    1968          20 :     rootFrame = mFrameConstructor->GetRootFrame();
    1969          20 :     if (!mIsDestroying && rootFrame) {
    1970             :       // XXX Do a full invalidate at the beginning so that invalidates along
    1971             :       // the way don't have region accumulation issues?
    1972             : 
    1973          20 :       if (isBSizeChanging) {
    1974             :         // For BSize changes driven by style, RestyleManager handles this.
    1975             :         // For height:auto BSizes (i.e. layout-controlled), descendant
    1976             :         // intrinsic sizes can't depend on them. So the only other case is
    1977             :         // viewport-controlled BSizes which we handle here.
    1978          20 :         nsLayoutUtils::MarkIntrinsicISizesDirtyIfDependentOnBSize(rootFrame);
    1979             :       }
    1980             : 
    1981             :       {
    1982          40 :         nsAutoCauseReflowNotifier crNotifier(this);
    1983          20 :         WillDoReflow();
    1984             : 
    1985             :         // Kick off a top-down reflow
    1986          40 :         AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
    1987          40 :         nsViewManager::AutoDisableRefresh refreshBlocker(viewManager);
    1988             : 
    1989          20 :         mDirtyRoots.RemoveElement(rootFrame);
    1990          20 :         DoReflow(rootFrame, true);
    1991             :       }
    1992             : 
    1993          20 :       DidDoReflow(true);
    1994             :     }
    1995             :   }
    1996             : 
    1997          20 :   rootFrame = mFrameConstructor->GetRootFrame();
    1998          20 :   if (rootFrame) {
    1999          20 :     wm = rootFrame->GetWritingMode();
    2000          20 :     if (wm.IsVertical()) {
    2001           0 :       if (aWidth == NS_UNCONSTRAINEDSIZE) {
    2002           0 :         mPresContext->SetVisibleArea(
    2003           0 :           nsRect(0, 0, rootFrame->GetRect().width, aHeight));
    2004             :       }
    2005             :     } else {
    2006          20 :       if (aHeight == NS_UNCONSTRAINEDSIZE) {
    2007           0 :         mPresContext->SetVisibleArea(
    2008           0 :           nsRect(0, 0, aWidth, rootFrame->GetRect().height));
    2009             :       }
    2010             :     }
    2011             :   }
    2012             : 
    2013          40 :   if (!mIsDestroying && !mResizeEvent.IsPending() &&
    2014          20 :       !mAsyncResizeTimerIsActive) {
    2015          20 :     if (mInResize) {
    2016           0 :       if (!mAsyncResizeEventTimer) {
    2017           0 :         mAsyncResizeEventTimer = do_CreateInstance("@mozilla.org/timer;1");
    2018             :       }
    2019           0 :       if (mAsyncResizeEventTimer) {
    2020           0 :         mAsyncResizeTimerIsActive = true;
    2021           0 :         mAsyncResizeEventTimer->SetTarget(
    2022           0 :             mDocument->EventTargetFor(TaskCategory::Other));
    2023           0 :         mAsyncResizeEventTimer->InitWithNamedFuncCallback(AsyncResizeEventCallback,
    2024             :                                                           this, 15,
    2025             :                                                           nsITimer::TYPE_ONE_SHOT,
    2026           0 :                                                           "AsyncResizeEventCallback");
    2027             :       }
    2028             :     } else {
    2029          40 :       RefPtr<nsRunnableMethod<PresShell>> event = NewRunnableMethod(
    2030          40 :         "PresShell::FireResizeEvent", this, &PresShell::FireResizeEvent);
    2031          60 :       nsresult rv = mDocument->Dispatch("PresShell::FireResizeEvent",
    2032             :                                         TaskCategory::Other,
    2033          60 :                                         do_AddRef(event));
    2034          20 :       if (NS_SUCCEEDED(rv)) {
    2035          20 :         mResizeEvent = event;
    2036          20 :         SetNeedStyleFlush();
    2037             :       }
    2038             :     }
    2039             :   }
    2040             : 
    2041          20 :   return NS_OK; //XXX this needs to be real. MMP
    2042             : }
    2043             : 
    2044             : void
    2045          20 : PresShell::FireResizeEvent()
    2046             : {
    2047          20 :   if (mAsyncResizeTimerIsActive) {
    2048           0 :     mAsyncResizeTimerIsActive = false;
    2049           0 :     mAsyncResizeEventTimer->Cancel();
    2050             :   }
    2051          20 :   mResizeEvent.Revoke();
    2052             : 
    2053          20 :   if (mIsDocumentGone)
    2054           0 :     return;
    2055             : 
    2056             :   //Send resize event from here.
    2057          40 :   WidgetEvent event(true, mozilla::eResize);
    2058          20 :   nsEventStatus status = nsEventStatus_eIgnore;
    2059             : 
    2060          20 :   if (nsPIDOMWindowOuter* window = mDocument->GetWindow()) {
    2061           4 :     nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
    2062           2 :     mInResize = true;
    2063           2 :     EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
    2064           2 :     mInResize = false;
    2065             :   }
    2066             : }
    2067             : 
    2068             : void
    2069           4 : PresShell::SetIgnoreFrameDestruction(bool aIgnore)
    2070             : {
    2071           4 :   if (mDocument) {
    2072             :     // We need to tell the ImageLoader to drop all its references to frames
    2073             :     // because they're about to go away and it won't get notifications of that.
    2074           4 :     mDocument->StyleImageLoader()->ClearFrames(mPresContext);
    2075             :   }
    2076           4 :   mIgnoreFrameDestruction = aIgnore;
    2077           4 : }
    2078             : 
    2079             : void
    2080         126 : PresShell::NotifyDestroyingFrame(nsIFrame* aFrame)
    2081             : {
    2082             :   // We must remove these from FrameLayerBuilder::DisplayItemData::mFrameList here,
    2083             :   // otherwise the DisplayItemData destructor will use the destroyed frame when it
    2084             :   // tries to remove it from the (array) value of this property.
    2085         126 :   FrameLayerBuilder::RemoveFrameFromLayerManager(aFrame, aFrame->DisplayItemData());
    2086         126 :   aFrame->DisplayItemData().Clear();
    2087             : 
    2088         126 :   if (!mIgnoreFrameDestruction) {
    2089         126 :     if (aFrame->HasImageRequest()) {
    2090           2 :       mDocument->StyleImageLoader()->DropRequestsForFrame(aFrame);
    2091             :     }
    2092             : 
    2093         126 :     mFrameConstructor->NotifyDestroyingFrame(aFrame);
    2094             : 
    2095         249 :     for (int32_t idx = mDirtyRoots.Length(); idx; ) {
    2096         123 :       --idx;
    2097         123 :       if (mDirtyRoots[idx] == aFrame) {
    2098           0 :         mDirtyRoots.RemoveElementAt(idx);
    2099             :       }
    2100             :     }
    2101             : 
    2102             :     // Remove frame properties
    2103         126 :     aFrame->DeleteAllProperties();
    2104             : 
    2105         126 :     if (aFrame == mCurrentEventFrame) {
    2106           0 :       mCurrentEventContent = aFrame->GetContent();
    2107           0 :       mCurrentEventFrame = nullptr;
    2108             :     }
    2109             : 
    2110             :   #ifdef DEBUG
    2111         126 :     if (aFrame == mDrawEventTargetFrame) {
    2112           0 :       mDrawEventTargetFrame = nullptr;
    2113             :     }
    2114             :   #endif
    2115             : 
    2116         126 :     for (unsigned int i=0; i < mCurrentEventFrameStack.Length(); i++) {
    2117           0 :       if (aFrame == mCurrentEventFrameStack.ElementAt(i)) {
    2118             :         //One of our stack frames was deleted.  Get its content so that when we
    2119             :         //pop it we can still get its new frame from its content
    2120           0 :         nsIContent *currentEventContent = aFrame->GetContent();
    2121           0 :         mCurrentEventContentStack.ReplaceObjectAt(currentEventContent, i);
    2122           0 :         mCurrentEventFrameStack[i] = nullptr;
    2123             :       }
    2124             :     }
    2125             : 
    2126         126 :     mFramesToDirty.RemoveEntry(aFrame);
    2127             :   }
    2128         126 : }
    2129             : 
    2130          36 : already_AddRefed<nsCaret> PresShell::GetCaret() const
    2131             : {
    2132          72 :   RefPtr<nsCaret> caret = mCaret;
    2133          72 :   return caret.forget();
    2134             : }
    2135             : 
    2136          61 : already_AddRefed<AccessibleCaretEventHub> PresShell::GetAccessibleCaretEventHub() const
    2137             : {
    2138         122 :   RefPtr<AccessibleCaretEventHub> eventHub = mAccessibleCaretEventHub;
    2139         122 :   return eventHub.forget();
    2140             : }
    2141             : 
    2142           0 : void PresShell::SetCaret(nsCaret *aNewCaret)
    2143             : {
    2144           0 :   mCaret = aNewCaret;
    2145           0 : }
    2146             : 
    2147           0 : void PresShell::RestoreCaret()
    2148             : {
    2149           0 :   mCaret = mOriginalCaret;
    2150           0 : }
    2151             : 
    2152           0 : NS_IMETHODIMP PresShell::SetCaretEnabled(bool aInEnable)
    2153             : {
    2154           0 :   bool oldEnabled = mCaretEnabled;
    2155             : 
    2156           0 :   mCaretEnabled = aInEnable;
    2157             : 
    2158           0 :   if (mCaretEnabled != oldEnabled)
    2159             :   {
    2160           0 :     MOZ_ASSERT(mCaret);
    2161           0 :     if (mCaret) {
    2162           0 :       mCaret->SetVisible(mCaretEnabled);
    2163             :     }
    2164             :   }
    2165             : 
    2166           0 :   return NS_OK;
    2167             : }
    2168             : 
    2169           0 : NS_IMETHODIMP PresShell::SetCaretReadOnly(bool aReadOnly)
    2170             : {
    2171           0 :   if (mCaret)
    2172           0 :     mCaret->SetCaretReadOnly(aReadOnly);
    2173           0 :   return NS_OK;
    2174             : }
    2175             : 
    2176           0 : NS_IMETHODIMP PresShell::GetCaretEnabled(bool *aOutEnabled)
    2177             : {
    2178           0 :   NS_ENSURE_ARG_POINTER(aOutEnabled);
    2179           0 :   *aOutEnabled = mCaretEnabled;
    2180           0 :   return NS_OK;
    2181             : }
    2182             : 
    2183           0 : NS_IMETHODIMP PresShell::SetCaretVisibilityDuringSelection(bool aVisibility)
    2184             : {
    2185           0 :   if (mCaret)
    2186           0 :     mCaret->SetVisibilityDuringSelection(aVisibility);
    2187           0 :   return NS_OK;
    2188             : }
    2189             : 
    2190           0 : NS_IMETHODIMP PresShell::GetCaretVisible(bool *aOutIsVisible)
    2191             : {
    2192           0 :   *aOutIsVisible = false;
    2193           0 :   if (mCaret) {
    2194           0 :     *aOutIsVisible = mCaret->IsVisible();
    2195             :   }
    2196           0 :   return NS_OK;
    2197             : }
    2198             : 
    2199           0 : NS_IMETHODIMP PresShell::SetSelectionFlags(int16_t aInEnable)
    2200             : {
    2201           0 :   mSelectionFlags = aInEnable;
    2202           0 :   return NS_OK;
    2203             : }
    2204             : 
    2205           0 : NS_IMETHODIMP PresShell::GetSelectionFlags(int16_t *aOutEnable)
    2206             : {
    2207           0 :   if (!aOutEnable)
    2208           0 :     return NS_ERROR_INVALID_ARG;
    2209           0 :   *aOutEnable = mSelectionFlags;
    2210           0 :   return NS_OK;
    2211             : }
    2212             : 
    2213             : //implementation of nsISelectionController
    2214             : 
    2215             : NS_IMETHODIMP
    2216           0 : PresShell::PhysicalMove(int16_t aDirection, int16_t aAmount, bool aExtend)
    2217             : {
    2218           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2219           0 :   return frameSelection->PhysicalMove(aDirection, aAmount, aExtend);
    2220             : }
    2221             : 
    2222             : NS_IMETHODIMP
    2223           0 : PresShell::CharacterMove(bool aForward, bool aExtend)
    2224             : {
    2225           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2226           0 :   return frameSelection->CharacterMove(aForward, aExtend);
    2227             : }
    2228             : 
    2229             : NS_IMETHODIMP
    2230           0 : PresShell::CharacterExtendForDelete()
    2231             : {
    2232           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2233           0 :   return frameSelection->CharacterExtendForDelete();
    2234             : }
    2235             : 
    2236             : NS_IMETHODIMP
    2237           0 : PresShell::CharacterExtendForBackspace()
    2238             : {
    2239           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2240           0 :   return frameSelection->CharacterExtendForBackspace();
    2241             : }
    2242             : 
    2243             : NS_IMETHODIMP
    2244           0 : PresShell::WordMove(bool aForward, bool aExtend)
    2245             : {
    2246           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2247           0 :   nsresult result = frameSelection->WordMove(aForward, aExtend);
    2248             : // if we can't go down/up any more we must then move caret completely to
    2249             : // end/beginning respectively.
    2250           0 :   if (NS_FAILED(result))
    2251           0 :     result = CompleteMove(aForward, aExtend);
    2252           0 :   return result;
    2253             : }
    2254             : 
    2255             : NS_IMETHODIMP
    2256           0 : PresShell::WordExtendForDelete(bool aForward)
    2257             : {
    2258           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2259           0 :   return frameSelection->WordExtendForDelete(aForward);
    2260             : }
    2261             : 
    2262             : NS_IMETHODIMP
    2263           0 : PresShell::LineMove(bool aForward, bool aExtend)
    2264             : {
    2265           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2266           0 :   nsresult result = frameSelection->LineMove(aForward, aExtend);
    2267             : // if we can't go down/up any more we must then move caret completely to
    2268             : // end/beginning respectively.
    2269           0 :   if (NS_FAILED(result))
    2270           0 :     result = CompleteMove(aForward,aExtend);
    2271           0 :   return result;
    2272             : }
    2273             : 
    2274             : NS_IMETHODIMP
    2275           0 : PresShell::IntraLineMove(bool aForward, bool aExtend)
    2276             : {
    2277           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2278           0 :   return frameSelection->IntraLineMove(aForward, aExtend);
    2279             : }
    2280             : 
    2281             : 
    2282             : 
    2283             : NS_IMETHODIMP
    2284           0 : PresShell::PageMove(bool aForward, bool aExtend)
    2285             : {
    2286             :   nsIScrollableFrame *scrollableFrame =
    2287           0 :     GetScrollableFrameToScroll(nsIPresShell::eVertical);
    2288           0 :   if (!scrollableFrame)
    2289           0 :     return NS_OK;
    2290             : 
    2291           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2292           0 :   frameSelection->CommonPageMove(aForward, aExtend, scrollableFrame);
    2293             :   // After ScrollSelectionIntoView(), the pending notifications might be
    2294             :   // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
    2295             :   return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
    2296             :                                  nsISelectionController::SELECTION_FOCUS_REGION,
    2297             :                                  nsISelectionController::SCROLL_SYNCHRONOUS |
    2298           0 :                                  nsISelectionController::SCROLL_FOR_CARET_MOVE);
    2299             : }
    2300             : 
    2301             : 
    2302             : 
    2303             : NS_IMETHODIMP
    2304           0 : PresShell::ScrollPage(bool aForward)
    2305             : {
    2306             :   nsIScrollableFrame* scrollFrame =
    2307           0 :     GetScrollableFrameToScroll(nsIPresShell::eVertical);
    2308           0 :   if (scrollFrame) {
    2309             :     mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
    2310           0 :         (uint32_t) ScrollInputMethod::MainThreadScrollPage);
    2311           0 :     scrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
    2312             :                           nsIScrollableFrame::PAGES,
    2313             :                           nsIScrollableFrame::SMOOTH,
    2314             :                           nullptr, nullptr,
    2315             :                           nsIScrollableFrame::NOT_MOMENTUM,
    2316           0 :                           nsIScrollableFrame::ENABLE_SNAP);
    2317             :   }
    2318           0 :   return NS_OK;
    2319             : }
    2320             : 
    2321             : NS_IMETHODIMP
    2322           0 : PresShell::ScrollLine(bool aForward)
    2323             : {
    2324             :   nsIScrollableFrame* scrollFrame =
    2325           0 :     GetScrollableFrameToScroll(nsIPresShell::eVertical);
    2326           0 :   if (scrollFrame) {
    2327             :     mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
    2328           0 :         (uint32_t) ScrollInputMethod::MainThreadScrollLine);
    2329             : 
    2330             :     int32_t lineCount = Preferences::GetInt("toolkit.scrollbox.verticalScrollDistance",
    2331           0 :                                             NS_DEFAULT_VERTICAL_SCROLL_DISTANCE);
    2332           0 :     scrollFrame->ScrollBy(nsIntPoint(0, aForward ? lineCount : -lineCount),
    2333             :                           nsIScrollableFrame::LINES,
    2334             :                           nsIScrollableFrame::SMOOTH,
    2335             :                           nullptr, nullptr,
    2336             :                           nsIScrollableFrame::NOT_MOMENTUM,
    2337           0 :                           nsIScrollableFrame::ENABLE_SNAP);
    2338             :   }
    2339           0 :   return NS_OK;
    2340             : }
    2341             : 
    2342             : NS_IMETHODIMP
    2343           0 : PresShell::ScrollCharacter(bool aRight)
    2344             : {
    2345             :   nsIScrollableFrame* scrollFrame =
    2346           0 :     GetScrollableFrameToScroll(nsIPresShell::eHorizontal);
    2347           0 :   if (scrollFrame) {
    2348             :     mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
    2349           0 :         (uint32_t) ScrollInputMethod::MainThreadScrollCharacter);
    2350             :     int32_t h = Preferences::GetInt("toolkit.scrollbox.horizontalScrollDistance",
    2351           0 :                                     NS_DEFAULT_HORIZONTAL_SCROLL_DISTANCE);
    2352           0 :     scrollFrame->ScrollBy(nsIntPoint(aRight ? h : -h, 0),
    2353             :                           nsIScrollableFrame::LINES,
    2354             :                           nsIScrollableFrame::SMOOTH,
    2355             :                           nullptr, nullptr,
    2356             :                           nsIScrollableFrame::NOT_MOMENTUM,
    2357           0 :                           nsIScrollableFrame::ENABLE_SNAP);
    2358             :   }
    2359           0 :   return NS_OK;
    2360             : }
    2361             : 
    2362             : NS_IMETHODIMP
    2363           0 : PresShell::CompleteScroll(bool aForward)
    2364             : {
    2365             :   nsIScrollableFrame* scrollFrame =
    2366           0 :     GetScrollableFrameToScroll(nsIPresShell::eVertical);
    2367           0 :   if (scrollFrame) {
    2368             :     mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
    2369           0 :         (uint32_t) ScrollInputMethod::MainThreadCompleteScroll);
    2370           0 :     scrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
    2371             :                           nsIScrollableFrame::WHOLE,
    2372             :                           nsIScrollableFrame::SMOOTH,
    2373             :                           nullptr, nullptr,
    2374             :                           nsIScrollableFrame::NOT_MOMENTUM,
    2375           0 :                           nsIScrollableFrame::ENABLE_SNAP);
    2376             :   }
    2377           0 :   return NS_OK;
    2378             : }
    2379             : 
    2380             : NS_IMETHODIMP
    2381           0 : PresShell::CompleteMove(bool aForward, bool aExtend)
    2382             : {
    2383             :   // Beware! This may flush notifications via synchronous
    2384             :   // ScrollSelectionIntoView.
    2385           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2386           0 :   nsIContent* limiter = frameSelection->GetAncestorLimiter();
    2387           0 :   nsIFrame* frame = limiter ? limiter->GetPrimaryFrame()
    2388           0 :                             : FrameConstructor()->GetRootElementFrame();
    2389           0 :   if (!frame)
    2390           0 :     return NS_ERROR_FAILURE;
    2391             :   nsIFrame::CaretPosition pos =
    2392           0 :     frame->GetExtremeCaretPosition(!aForward);
    2393           0 :   frameSelection->HandleClick(pos.mResultContent, pos.mContentOffset,
    2394           0 :                               pos.mContentOffset, aExtend, false,
    2395             :                               aForward ? CARET_ASSOCIATE_AFTER :
    2396           0 :                                          CARET_ASSOCIATE_BEFORE);
    2397           0 :   if (limiter) {
    2398             :     // HandleClick resets ancestorLimiter, so set it again.
    2399           0 :     frameSelection->SetAncestorLimiter(limiter);
    2400             :   }
    2401             : 
    2402             :   // After ScrollSelectionIntoView(), the pending notifications might be
    2403             :   // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
    2404             :   return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
    2405             :                                  nsISelectionController::SELECTION_FOCUS_REGION,
    2406             :                                  nsISelectionController::SCROLL_SYNCHRONOUS |
    2407           0 :                                  nsISelectionController::SCROLL_FOR_CARET_MOVE);
    2408             : }
    2409             : 
    2410             : NS_IMETHODIMP
    2411           0 : PresShell::SelectAll()
    2412             : {
    2413           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2414           0 :   return frameSelection->SelectAll();
    2415             : }
    2416             : 
    2417             : static void
    2418           0 : DoCheckVisibility(nsPresContext* aPresContext,
    2419             :                   nsIContent* aNode,
    2420             :                   int16_t aStartOffset,
    2421             :                   int16_t aEndOffset,
    2422             :                   bool* aRetval)
    2423             : {
    2424           0 :   nsIFrame* frame = aNode->GetPrimaryFrame();
    2425           0 :   if (!frame) {
    2426             :     // No frame to look at so it must not be visible.
    2427           0 :     return;
    2428             :   }
    2429             : 
    2430             :   // Start process now to go through all frames to find startOffset. Then check
    2431             :   // chars after that to see if anything until EndOffset is visible.
    2432           0 :   bool finished = false;
    2433           0 :   frame->CheckVisibility(aPresContext, aStartOffset, aEndOffset, true,
    2434           0 :                          &finished, aRetval);
    2435             :   // Don't worry about other return value.
    2436             : }
    2437             : 
    2438             : NS_IMETHODIMP
    2439           0 : PresShell::CheckVisibility(nsIDOMNode *node, int16_t startOffset, int16_t EndOffset, bool *_retval)
    2440             : {
    2441           0 :   if (!node || startOffset>EndOffset || !_retval || startOffset<0 || EndOffset<0)
    2442           0 :     return NS_ERROR_INVALID_ARG;
    2443           0 :   *_retval = false; //initialize return parameter
    2444           0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(node));
    2445           0 :   if (!content)
    2446           0 :     return NS_ERROR_FAILURE;
    2447             : 
    2448           0 :   DoCheckVisibility(mPresContext, content, startOffset, EndOffset, _retval);
    2449           0 :   return NS_OK;
    2450             : }
    2451             : 
    2452             : nsresult
    2453           0 : PresShell::CheckVisibilityContent(nsIContent* aNode, int16_t aStartOffset,
    2454             :                                   int16_t aEndOffset, bool* aRetval)
    2455             : {
    2456           0 :   if (!aNode || aStartOffset > aEndOffset || !aRetval ||
    2457           0 :       aStartOffset < 0 || aEndOffset < 0) {
    2458           0 :     return NS_ERROR_INVALID_ARG;
    2459             :   }
    2460             : 
    2461           0 :   *aRetval = false;
    2462           0 :   DoCheckVisibility(mPresContext, aNode, aStartOffset, aEndOffset, aRetval);
    2463           0 :   return NS_OK;
    2464             : }
    2465             : 
    2466             : //end implementations nsISelectionController
    2467             : 
    2468             : nsIFrame*
    2469           0 : nsIPresShell::GetRootFrameExternal() const
    2470             : {
    2471           0 :   return mFrameConstructor->GetRootFrame();
    2472             : }
    2473             : 
    2474             : nsIFrame*
    2475        1159 : nsIPresShell::GetRootScrollFrame() const
    2476             : {
    2477        1159 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    2478             :   // Ensure root frame is a viewport frame
    2479        1159 :   if (!rootFrame || !rootFrame->IsViewportFrame())
    2480           1 :     return nullptr;
    2481        1158 :   nsIFrame* theFrame = rootFrame->PrincipalChildList().FirstChild();
    2482        1158 :   if (!theFrame || !theFrame->IsScrollFrame())
    2483         765 :     return nullptr;
    2484         393 :   return theFrame;
    2485             : }
    2486             : 
    2487             : nsIScrollableFrame*
    2488         128 : nsIPresShell::GetRootScrollFrameAsScrollable() const
    2489             : {
    2490         128 :   nsIFrame* frame = GetRootScrollFrame();
    2491         128 :   if (!frame)
    2492          61 :     return nullptr;
    2493          67 :   nsIScrollableFrame* scrollableFrame = do_QueryFrame(frame);
    2494          67 :   NS_ASSERTION(scrollableFrame,
    2495             :                "All scroll frames must implement nsIScrollableFrame");
    2496          67 :   return scrollableFrame;
    2497             : }
    2498             : 
    2499             : nsIScrollableFrame*
    2500           0 : nsIPresShell::GetRootScrollFrameAsScrollableExternal() const
    2501             : {
    2502           0 :   return GetRootScrollFrameAsScrollable();
    2503             : }
    2504             : 
    2505             : nsIPageSequenceFrame*
    2506           0 : PresShell::GetPageSequenceFrame() const
    2507             : {
    2508           0 :   nsIFrame* frame = mFrameConstructor->GetPageSequenceFrame();
    2509           0 :   return do_QueryFrame(frame);
    2510             : }
    2511             : 
    2512             : nsCanvasFrame*
    2513          53 : PresShell::GetCanvasFrame() const
    2514             : {
    2515          53 :   nsIFrame* frame = mFrameConstructor->GetDocElementContainingBlock();
    2516          53 :   return do_QueryFrame(frame);
    2517             : }
    2518             : 
    2519             : void
    2520         618 : PresShell::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
    2521             : {
    2522             : #ifdef DEBUG
    2523         618 :   mUpdateCount++;
    2524             : #endif
    2525         618 :   mFrameConstructor->BeginUpdate();
    2526             : 
    2527         618 :   if (aUpdateType & UPDATE_STYLE)
    2528          62 :     mStyleSet->BeginUpdate();
    2529         618 : }
    2530             : 
    2531             : void
    2532         618 : PresShell::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
    2533             : {
    2534             : #ifdef DEBUG
    2535         618 :   NS_PRECONDITION(0 != mUpdateCount, "too many EndUpdate's");
    2536         618 :   --mUpdateCount;
    2537             : #endif
    2538             : 
    2539         618 :   if (aUpdateType & UPDATE_STYLE) {
    2540          62 :     mStyleSet->EndUpdate();
    2541          62 :     if (mStyleSet->StyleSheetsHaveChanged()) {
    2542          54 :       RestyleForCSSRuleChanges();
    2543             :     }
    2544             :   }
    2545             : 
    2546         618 :   mFrameConstructor->EndUpdate();
    2547         618 : }
    2548             : 
    2549             : void
    2550          25 : PresShell::RestoreRootScrollPosition()
    2551             : {
    2552          25 :   nsIScrollableFrame* scrollableFrame = GetRootScrollFrameAsScrollable();
    2553          25 :   if (scrollableFrame) {
    2554          23 :     scrollableFrame->ScrollToRestoredPosition();
    2555             :   }
    2556          25 : }
    2557             : 
    2558             : void
    2559           4 : PresShell::MaybeReleaseCapturingContent()
    2560             : {
    2561           8 :   RefPtr<nsFrameSelection> frameSelection = FrameSelection();
    2562           4 :   if (frameSelection) {
    2563           4 :     frameSelection->SetDragState(false);
    2564             :   }
    2565           4 :   if (gCaptureInfo.mContent &&
    2566           4 :       gCaptureInfo.mContent->OwnerDoc() == mDocument) {
    2567           0 :     SetCapturingContent(nullptr, 0);
    2568             :   }
    2569           4 : }
    2570             : 
    2571             : void
    2572          23 : PresShell::BeginLoad(nsIDocument *aDocument)
    2573             : {
    2574          23 :   mDocumentLoading = true;
    2575             : 
    2576          23 :   gfxTextPerfMetrics *tp = nullptr;
    2577          23 :   if (mPresContext) {
    2578          23 :     tp = mPresContext->GetTextPerfMetrics();
    2579             :   }
    2580             : 
    2581          23 :   bool shouldLog = MOZ_LOG_TEST(gLog, LogLevel::Debug);
    2582          23 :   if (shouldLog || tp) {
    2583           0 :     mLoadBegin = TimeStamp::Now();
    2584             :   }
    2585             : 
    2586          23 :   if (shouldLog) {
    2587           0 :     nsIURI* uri = mDocument->GetDocumentURI();
    2588           0 :     MOZ_LOG(gLog, LogLevel::Debug,
    2589             :            ("(presshell) %p load begin [%s]\n",
    2590             :             this, uri ? uri->GetSpecOrDefault().get() : ""));
    2591             :   }
    2592          23 : }
    2593             : 
    2594             : void
    2595          24 : PresShell::EndLoad(nsIDocument *aDocument)
    2596             : {
    2597          24 :   NS_PRECONDITION(aDocument == mDocument, "Wrong document");
    2598             : 
    2599          24 :   RestoreRootScrollPosition();
    2600             : 
    2601          24 :   mDocumentLoading = false;
    2602          24 : }
    2603             : 
    2604             : void
    2605           4 : PresShell::LoadComplete()
    2606             : {
    2607           4 :   gfxTextPerfMetrics *tp = nullptr;
    2608           4 :   if (mPresContext) {
    2609           4 :     tp = mPresContext->GetTextPerfMetrics();
    2610             :   }
    2611             : 
    2612             :   // log load
    2613           4 :   bool shouldLog = MOZ_LOG_TEST(gLog, LogLevel::Debug);
    2614           4 :   if (shouldLog || tp) {
    2615           0 :     TimeDuration loadTime = TimeStamp::Now() - mLoadBegin;
    2616           0 :     nsIURI* uri = mDocument->GetDocumentURI();
    2617           0 :     nsAutoCString spec;
    2618           0 :     if (uri) {
    2619           0 :       spec = uri->GetSpecOrDefault();
    2620             :     }
    2621           0 :     if (shouldLog) {
    2622           0 :       MOZ_LOG(gLog, LogLevel::Debug,
    2623             :              ("(presshell) %p load done time-ms: %9.2f [%s]\n",
    2624             :               this, loadTime.ToMilliseconds(), spec.get()));
    2625             :     }
    2626           0 :     if (tp) {
    2627           0 :       tp->Accumulate();
    2628           0 :       if (tp->cumulative.numChars > 0) {
    2629           0 :         LogTextPerfStats(tp, this, tp->cumulative, loadTime.ToMilliseconds(),
    2630           0 :                          eLog_loaddone, spec.get());
    2631             :       }
    2632             :     }
    2633             :   }
    2634           4 : }
    2635             : 
    2636             : #ifdef DEBUG
    2637             : void
    2638         111 : PresShell::VerifyHasDirtyRootAncestor(nsIFrame* aFrame)
    2639             : {
    2640             :   // XXXbz due to bug 372769, can't actually assert anything here...
    2641         111 :   return;
    2642             : 
    2643             :   // XXXbz shouldn't need this part; remove it once FrameNeedsReflow
    2644             :   // handles the root frame correctly.
    2645             :   if (!aFrame->GetParent()) {
    2646             :     return;
    2647             :   }
    2648             : 
    2649             :   // Make sure that there is a reflow root ancestor of |aFrame| that's
    2650             :   // in mDirtyRoots already.
    2651             :   while (aFrame && (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)) {
    2652             :     if (((aFrame->GetStateBits() & NS_FRAME_REFLOW_ROOT) ||
    2653             :          !aFrame->GetParent()) &&
    2654             :         mDirtyRoots.Contains(aFrame)) {
    2655             :       return;
    2656             :     }
    2657             : 
    2658             :     aFrame = aFrame->GetParent();
    2659             :   }
    2660             :   NS_NOTREACHED("Frame has dirty bits set but isn't scheduled to be "
    2661             :                 "reflowed?");
    2662             : }
    2663             : #endif
    2664             : 
    2665             : void
    2666         158 : PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
    2667             :                             nsFrameState aBitToAdd,
    2668             :                             ReflowRootHandling aRootHandling)
    2669             : {
    2670         158 :   NS_PRECONDITION(aBitToAdd == NS_FRAME_IS_DIRTY ||
    2671             :                   aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN ||
    2672             :                   !aBitToAdd,
    2673             :                   "Unexpected bits being added");
    2674         158 :   NS_PRECONDITION(!(aIntrinsicDirty == eStyleChange &&
    2675             :                     aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN),
    2676             :                   "bits don't correspond to style change reason");
    2677             : 
    2678         158 :   NS_ASSERTION(!mIsReflowing, "can't mark frame dirty during reflow");
    2679             : 
    2680             :   // If we've not yet done the initial reflow, then don't bother
    2681             :   // enqueuing a reflow command yet.
    2682         158 :   if (! mDidInitialize)
    2683           0 :     return;
    2684             : 
    2685             :   // If we're already destroying, don't bother with this either.
    2686         158 :   if (mIsDestroying)
    2687           0 :     return;
    2688             : 
    2689             : #ifdef DEBUG
    2690             :   //printf("gShellCounter: %d\n", gShellCounter++);
    2691         158 :   if (mInVerifyReflow)
    2692           0 :     return;
    2693             : 
    2694         158 :   if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
    2695           0 :     printf("\nPresShell@%p: frame %p needs reflow\n", (void*)this, (void*)aFrame);
    2696           0 :     if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
    2697           0 :       printf("Current content model:\n");
    2698           0 :       Element *rootElement = mDocument->GetRootElement();
    2699           0 :       if (rootElement) {
    2700           0 :         rootElement->List(stdout, 0);
    2701             :       }
    2702             :     }
    2703             :   }
    2704             : #endif
    2705             : 
    2706         316 :   AutoTArray<nsIFrame*, 4> subtrees;
    2707         158 :   subtrees.AppendElement(aFrame);
    2708             : 
    2709         164 :   do {
    2710         164 :     nsIFrame *subtreeRoot = subtrees.ElementAt(subtrees.Length() - 1);
    2711         164 :     subtrees.RemoveElementAt(subtrees.Length() - 1);
    2712             : 
    2713             :     // Grab |wasDirty| now so we can go ahead and update the bits on
    2714             :     // subtreeRoot.
    2715         164 :     bool wasDirty = NS_SUBTREE_DIRTY(subtreeRoot);
    2716         164 :     subtreeRoot->AddStateBits(aBitToAdd);
    2717             : 
    2718             :     // Determine whether we need to keep looking for the next ancestor
    2719             :     // reflow root if subtreeRoot itself is a reflow root.
    2720             :     bool targetNeedsReflowFromParent;
    2721         164 :     switch (aRootHandling) {
    2722             :       case ePositionOrSizeChange:
    2723          31 :         targetNeedsReflowFromParent = true;
    2724          31 :         break;
    2725             :       case eNoPositionOrSizeChange:
    2726           1 :         targetNeedsReflowFromParent = false;
    2727           1 :         break;
    2728             :       case eInferFromBitToAdd:
    2729         132 :         targetNeedsReflowFromParent = (aBitToAdd == NS_FRAME_IS_DIRTY);
    2730         132 :         break;
    2731             :     }
    2732             : 
    2733             : #define FRAME_IS_REFLOW_ROOT(_f)                   \
    2734             :   ((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) &&  \
    2735             :    (_f != subtreeRoot || !targetNeedsReflowFromParent))
    2736             : 
    2737             : 
    2738             :     // Mark the intrinsic widths as dirty on the frame, all of its ancestors,
    2739             :     // and all of its descendants, if needed:
    2740             : 
    2741         164 :     if (aIntrinsicDirty != nsIPresShell::eResize) {
    2742             :       // Mark argument and all ancestors dirty. (Unless we hit a reflow
    2743             :       // root that should contain the reflow.  That root could be
    2744             :       // subtreeRoot itself if it's not dirty, or it could be some
    2745             :       // ancestor of subtreeRoot.)
    2746        2596 :       for (nsIFrame *a = subtreeRoot;
    2747        1298 :            a && !FRAME_IS_REFLOW_ROOT(a);
    2748             :            a = a->GetParent())
    2749        1161 :         a->MarkIntrinsicISizesDirty();
    2750             :     }
    2751             : 
    2752         164 :     if (aIntrinsicDirty == eStyleChange) {
    2753             :       // Mark all descendants dirty (using an nsTArray stack rather than
    2754             :       // recursion).
    2755             :       // Note that ReflowInput::InitResizeFlags has some similar
    2756             :       // code; see comments there for how and why it differs.
    2757         172 :       AutoTArray<nsIFrame*, 32> stack;
    2758          86 :       stack.AppendElement(subtreeRoot);
    2759             : 
    2760         263 :       do {
    2761         263 :         nsIFrame *f = stack.ElementAt(stack.Length() - 1);
    2762         263 :         stack.RemoveElementAt(stack.Length() - 1);
    2763             : 
    2764         263 :         if (f->IsPlaceholderFrame()) {
    2765           6 :           nsIFrame *oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
    2766           6 :           if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) {
    2767             :             // We have another distinct subtree we need to mark.
    2768           6 :             subtrees.AppendElement(oof);
    2769             :           }
    2770             :         }
    2771             : 
    2772         526 :         nsIFrame::ChildListIterator lists(f);
    2773         525 :         for (; !lists.IsDone(); lists.Next()) {
    2774         308 :           for (nsIFrame* kid : lists.CurrentList()) {
    2775         177 :             kid->MarkIntrinsicISizesDirty();
    2776         177 :             stack.AppendElement(kid);
    2777             :           }
    2778             :         }
    2779         263 :       } while (stack.Length() != 0);
    2780             :     }
    2781             : 
    2782             :     // Skip setting dirty bits up the tree if we weren't given a bit to add.
    2783         164 :     if (!aBitToAdd) {
    2784           1 :       continue;
    2785             :     }
    2786             : 
    2787             :     // Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty)
    2788             :     // up the tree until we reach either a frame that's already dirty or
    2789             :     // a reflow root.
    2790         163 :     nsIFrame *f = subtreeRoot;
    2791             :     for (;;) {
    2792         483 :       if (FRAME_IS_REFLOW_ROOT(f) || !f->GetParent()) {
    2793             :         // we've hit a reflow root or the root frame
    2794          54 :         if (!wasDirty) {
    2795          52 :           mDirtyRoots.AppendElement(f);
    2796          52 :           SetNeedLayoutFlush();
    2797             :         }
    2798             : #ifdef DEBUG
    2799             :         else {
    2800           2 :           VerifyHasDirtyRootAncestor(f);
    2801             :         }
    2802             : #endif
    2803             : 
    2804          54 :         break;
    2805             :       }
    2806             : 
    2807         429 :       nsIFrame *child = f;
    2808         429 :       f = f->GetParent();
    2809         429 :       wasDirty = NS_SUBTREE_DIRTY(f);
    2810         429 :       f->ChildIsDirty(child);
    2811         429 :       NS_ASSERTION(f->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN,
    2812             :                    "ChildIsDirty didn't do its job");
    2813         429 :       if (wasDirty) {
    2814             :         // This frame was already marked dirty.
    2815             : #ifdef DEBUG
    2816         109 :         VerifyHasDirtyRootAncestor(f);
    2817             : #endif
    2818         109 :         break;
    2819             :       }
    2820         320 :     }
    2821         164 :   } while (subtrees.Length() != 0);
    2822             : 
    2823         158 :   MaybeScheduleReflow();
    2824             : }
    2825             : 
    2826             : void
    2827           0 : PresShell::FrameNeedsToContinueReflow(nsIFrame *aFrame)
    2828             : {
    2829           0 :   NS_ASSERTION(mIsReflowing, "Must be in reflow when marking path dirty.");
    2830           0 :   NS_PRECONDITION(mCurrentReflowRoot, "Must have a current reflow root here");
    2831           0 :   NS_ASSERTION(aFrame == mCurrentReflowRoot ||
    2832             :                nsLayoutUtils::IsProperAncestorFrame(mCurrentReflowRoot, aFrame),
    2833             :                "Frame passed in is not the descendant of mCurrentReflowRoot");
    2834           0 :   NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_IN_REFLOW,
    2835             :                "Frame passed in not in reflow?");
    2836             : 
    2837           0 :   mFramesToDirty.PutEntry(aFrame);
    2838           0 : }
    2839             : 
    2840             : already_AddRefed<nsIContent>
    2841           0 : nsIPresShell::GetContentForScrolling() const
    2842             : {
    2843           0 :   nsCOMPtr<nsIContent> focusedContent;
    2844           0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    2845           0 :   if (fm && mDocument) {
    2846           0 :     nsCOMPtr<nsIDOMElement> focusedElement;
    2847           0 :     fm->GetFocusedElementForWindow(mDocument->GetWindow(), false, nullptr,
    2848           0 :                                    getter_AddRefs(focusedElement));
    2849           0 :     focusedContent = do_QueryInterface(focusedElement);
    2850             :   }
    2851           0 :   if (!focusedContent && mSelection) {
    2852             :     nsISelection* domSelection =
    2853           0 :       mSelection->GetSelection(SelectionType::eNormal);
    2854           0 :     if (domSelection) {
    2855           0 :       nsCOMPtr<nsIDOMNode> focusedNode;
    2856           0 :       domSelection->GetFocusNode(getter_AddRefs(focusedNode));
    2857           0 :       focusedContent = do_QueryInterface(focusedNode);
    2858             :     }
    2859             :   }
    2860           0 :   return focusedContent.forget();
    2861             : }
    2862             : 
    2863             : nsIScrollableFrame*
    2864           0 : nsIPresShell::GetScrollableFrameToScrollForContent(
    2865             :                 nsIContent* aContent,
    2866             :                 nsIPresShell::ScrollDirection aDirection)
    2867             : {
    2868           0 :   nsIScrollableFrame* scrollFrame = nullptr;
    2869           0 :   if (aContent) {
    2870           0 :     nsIFrame* startFrame = aContent->GetPrimaryFrame();
    2871           0 :     if (startFrame) {
    2872           0 :       scrollFrame = startFrame->GetScrollTargetFrame();
    2873           0 :       if (scrollFrame) {
    2874           0 :         startFrame = scrollFrame->GetScrolledFrame();
    2875             :       }
    2876           0 :       if (aDirection == nsIPresShell::eEither) {
    2877             :         scrollFrame =
    2878           0 :           nsLayoutUtils::GetNearestScrollableFrame(startFrame);
    2879             :       } else {
    2880             :         scrollFrame =
    2881           0 :           nsLayoutUtils::GetNearestScrollableFrameForDirection(startFrame,
    2882             :             aDirection == eVertical ? nsLayoutUtils::eVertical :
    2883           0 :                                       nsLayoutUtils::eHorizontal);
    2884             :       }
    2885             :     }
    2886             :   }
    2887           0 :   if (!scrollFrame) {
    2888           0 :     scrollFrame = GetRootScrollFrameAsScrollable();
    2889             :   }
    2890           0 :   return scrollFrame;
    2891             : }
    2892             : 
    2893             : nsIScrollableFrame*
    2894           0 : nsIPresShell::GetScrollableFrameToScroll(nsIPresShell::ScrollDirection aDirection)
    2895             : {
    2896           0 :   nsCOMPtr<nsIContent> content = GetContentForScrolling();
    2897           0 :   return GetScrollableFrameToScrollForContent(content.get(), aDirection);
    2898             : }
    2899             : 
    2900             : void
    2901           4 : PresShell::CancelAllPendingReflows()
    2902             : {
    2903           4 :   mDirtyRoots.Clear();
    2904             : 
    2905           4 :   if (mObservingLayoutFlushes) {
    2906           0 :     GetPresContext()->RefreshDriver()->RemoveLayoutFlushObserver(this);
    2907           0 :     mObservingLayoutFlushes = false;
    2908             :   }
    2909             : 
    2910           4 :   ASSERT_REFLOW_SCHEDULED_STATE();
    2911           4 : }
    2912             : 
    2913             : void
    2914           0 : PresShell::DestroyFramesFor(nsIContent*  aContent,
    2915             :                             nsIContent** aDestroyedFramesFor)
    2916             : {
    2917           0 :   MOZ_ASSERT(aContent);
    2918           0 :   NS_ENSURE_TRUE_VOID(mPresContext);
    2919           0 :   if (!mDidInitialize) {
    2920           0 :     return;
    2921             :   }
    2922             : 
    2923           0 :   nsAutoScriptBlocker scriptBlocker;
    2924             : 
    2925             :   // Mark ourselves as not safe to flush while we're doing frame destruction.
    2926           0 :   ++mChangeNestCount;
    2927             : 
    2928           0 :   nsCSSFrameConstructor* fc = FrameConstructor();
    2929           0 :   fc->BeginUpdate();
    2930           0 :   fc->DestroyFramesFor(aContent, aDestroyedFramesFor);
    2931           0 :   fc->EndUpdate();
    2932             : 
    2933           0 :   --mChangeNestCount;
    2934             : }
    2935             : 
    2936             : void
    2937           0 : PresShell::CreateFramesFor(nsIContent* aContent)
    2938             : {
    2939           0 :   NS_ENSURE_TRUE_VOID(mPresContext);
    2940           0 :   if (!mDidInitialize) {
    2941             :     // Nothing to do here.  In fact, if we proceed and aContent is the
    2942             :     // root we will crash.
    2943           0 :     return;
    2944             :   }
    2945             : 
    2946             :   // Don't call RecreateFramesForContent since that is not exported and we want
    2947             :   // to keep the number of entrypoints down.
    2948             : 
    2949           0 :   NS_ASSERTION(mViewManager, "Should have view manager");
    2950           0 :   MOZ_ASSERT(aContent);
    2951             : 
    2952             :   // Have to make sure that the content notifications are flushed before we
    2953             :   // start messing with the frame model; otherwise we can get content doubling.
    2954           0 :   mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
    2955             : 
    2956           0 :   nsAutoScriptBlocker scriptBlocker;
    2957             : 
    2958             :   // Mark ourselves as not safe to flush while we're doing frame construction.
    2959           0 :   ++mChangeNestCount;
    2960             : 
    2961           0 :   nsCSSFrameConstructor* fc = FrameConstructor();
    2962           0 :   nsILayoutHistoryState* layoutState = fc->GetLastCapturedLayoutHistoryState();
    2963           0 :   fc->BeginUpdate();
    2964           0 :   fc->ContentInserted(aContent->GetParent(), aContent, layoutState, false);
    2965           0 :   fc->EndUpdate();
    2966             : 
    2967           0 :   --mChangeNestCount;
    2968             : }
    2969             : 
    2970             : void
    2971           0 : nsIPresShell::PostRecreateFramesFor(Element* aElement)
    2972             : {
    2973           0 :   if (MOZ_UNLIKELY(!mDidInitialize)) {
    2974             :     // Nothing to do here. In fact, if we proceed and aElement is the root, we
    2975             :     // will crash.
    2976           0 :     return;
    2977             :   }
    2978             : 
    2979           0 :   mPresContext->RestyleManager()->PostRestyleEvent(aElement, nsRestyleHint(0),
    2980           0 :                                                    nsChangeHint_ReconstructFrame);
    2981             : }
    2982             : 
    2983             : void
    2984          16 : nsIPresShell::RestyleForAnimation(Element* aElement, nsRestyleHint aHint)
    2985             : {
    2986             :   // Now that we no longer have separate non-animation and animation
    2987             :   // restyles, this method having a distinct identity is less important,
    2988             :   // but it still seems useful to offer as a "more public" API and as a
    2989             :   // chokepoint for these restyles to go through.
    2990          16 :   mPresContext->RestyleManager()->PostRestyleEvent(aElement, aHint,
    2991          16 :                                                    nsChangeHint(0));
    2992          16 : }
    2993             : 
    2994             : void
    2995          21 : nsIPresShell::SetForwardingContainer(const WeakPtr<nsDocShell> &aContainer)
    2996             : {
    2997          21 :   mForwardingContainer = aContainer;
    2998          21 : }
    2999             : 
    3000             : void
    3001           5 : PresShell::ClearFrameRefs(nsIFrame* aFrame)
    3002             : {
    3003           5 :   mPresContext->EventStateManager()->ClearFrameRefs(aFrame);
    3004             : 
    3005           5 :   AutoWeakFrame* weakFrame = mAutoWeakFrames;
    3006           5 :   while (weakFrame) {
    3007           0 :     AutoWeakFrame* prev = weakFrame->GetPreviousWeakFrame();
    3008           0 :     if (weakFrame->GetFrame() == aFrame) {
    3009             :       // This removes weakFrame from mAutoWeakFrames.
    3010           0 :       weakFrame->Clear(this);
    3011             :     }
    3012           0 :     weakFrame = prev;
    3013             :   }
    3014             : 
    3015          10 :   AutoTArray<WeakFrame*, 4> toRemove;
    3016           5 :   for (auto iter = mWeakFrames.Iter(); !iter.Done(); iter.Next()) {
    3017           0 :     WeakFrame* weakFrame = iter.Get()->GetKey();
    3018           0 :     if (weakFrame->GetFrame() == aFrame) {
    3019           0 :       toRemove.AppendElement(weakFrame);
    3020             :     }
    3021             :   }
    3022           5 :   for (WeakFrame* weakFrame : toRemove) {
    3023           0 :     weakFrame->Clear(this);
    3024             :   }
    3025           5 : }
    3026             : 
    3027             : already_AddRefed<gfxContext>
    3028          97 : PresShell::CreateReferenceRenderingContext()
    3029             : {
    3030          97 :   nsDeviceContext* devCtx = mPresContext->DeviceContext();
    3031         194 :   RefPtr<gfxContext> rc;
    3032          97 :   if (mPresContext->IsScreen()) {
    3033          97 :     rc = gfxContext::CreateOrNull(gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
    3034             :   } else {
    3035             :     // We assume the devCtx has positive width and height for this call.
    3036             :     // However, width and height, may be outside of the reasonable range
    3037             :     // so rc may still be null.
    3038           0 :     rc = devCtx->CreateReferenceRenderingContext();
    3039             :   }
    3040             : 
    3041         194 :   return rc ? rc.forget() : nullptr;
    3042             : }
    3043             : 
    3044             : nsresult
    3045           2 : PresShell::GoToAnchor(const nsAString& aAnchorName, bool aScroll,
    3046             :                       uint32_t aAdditionalScrollFlags)
    3047             : {
    3048           2 :   if (!mDocument) {
    3049           0 :     return NS_ERROR_FAILURE;
    3050             :   }
    3051             : 
    3052           2 :   const Element *root = mDocument->GetRootElement();
    3053           2 :   if (root && root->IsSVGElement(nsGkAtoms::svg)) {
    3054             :     // We need to execute this even if there is an empty anchor name
    3055             :     // so that any existing SVG fragment identifier effect is removed
    3056           2 :     if (SVGFragmentIdentifier::ProcessFragmentIdentifier(mDocument, aAnchorName)) {
    3057           0 :       return NS_OK;
    3058             :     }
    3059             :   }
    3060             : 
    3061             :   // Hold a reference to the ESM in case event dispatch tears us down.
    3062           4 :   RefPtr<EventStateManager> esm = mPresContext->EventStateManager();
    3063             : 
    3064           2 :   if (aAnchorName.IsEmpty()) {
    3065           0 :     NS_ASSERTION(!aScroll, "can't scroll to empty anchor name");
    3066           0 :     esm->SetContentState(nullptr, NS_EVENT_STATE_URLTARGET);
    3067           0 :     return NS_OK;
    3068             :   }
    3069             : 
    3070           4 :   nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
    3071           2 :   nsresult rv = NS_OK;
    3072           4 :   nsCOMPtr<nsIContent> content;
    3073             : 
    3074             :   // Search for an element with a matching "id" attribute
    3075           2 :   if (mDocument) {
    3076           2 :     content = mDocument->GetElementById(aAnchorName);
    3077             :   }
    3078             : 
    3079             :   // Search for an anchor element with a matching "name" attribute
    3080           2 :   if (!content && htmlDoc) {
    3081           0 :     nsCOMPtr<nsIDOMNodeList> list;
    3082             :     // Find a matching list of named nodes
    3083           0 :     rv = htmlDoc->GetElementsByName(aAnchorName, getter_AddRefs(list));
    3084           0 :     if (NS_SUCCEEDED(rv) && list) {
    3085             :       uint32_t i;
    3086             :       // Loop through the named nodes looking for the first anchor
    3087           0 :       for (i = 0; true; i++) {
    3088           0 :         nsCOMPtr<nsIDOMNode> node;
    3089           0 :         rv = list->Item(i, getter_AddRefs(node));
    3090           0 :         if (!node) {  // End of list
    3091           0 :           break;
    3092             :         }
    3093             :         // Ensure it's an anchor element
    3094           0 :         content = do_QueryInterface(node);
    3095           0 :         if (content) {
    3096           0 :           if (content->IsHTMLElement(nsGkAtoms::a)) {
    3097           0 :             break;
    3098             :           }
    3099           0 :           content = nullptr;
    3100             :         }
    3101           0 :       }
    3102             :     }
    3103             :   }
    3104             : 
    3105             :   // Search for anchor in the HTML namespace with a matching name
    3106           2 :   if (!content && !htmlDoc)
    3107             :   {
    3108           0 :     nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(mDocument);
    3109           0 :     nsCOMPtr<nsIDOMNodeList> list;
    3110           0 :     NS_NAMED_LITERAL_STRING(nameSpace, "http://www.w3.org/1999/xhtml");
    3111             :     // Get the list of anchor elements
    3112           0 :     rv = doc->GetElementsByTagNameNS(nameSpace, NS_LITERAL_STRING("a"), getter_AddRefs(list));
    3113           0 :     if (NS_SUCCEEDED(rv) && list) {
    3114             :       uint32_t i;
    3115             :       // Loop through the named nodes looking for the first anchor
    3116           0 :       for (i = 0; true; i++) {
    3117           0 :         nsCOMPtr<nsIDOMNode> node;
    3118           0 :         rv = list->Item(i, getter_AddRefs(node));
    3119           0 :         if (!node) { // End of list
    3120           0 :           break;
    3121             :         }
    3122             :         // Compare the name attribute
    3123           0 :         nsCOMPtr<nsIDOMElement> element = do_QueryInterface(node);
    3124           0 :         nsAutoString value;
    3125           0 :         if (element && NS_SUCCEEDED(element->GetAttribute(NS_LITERAL_STRING("name"), value))) {
    3126           0 :           if (value.Equals(aAnchorName)) {
    3127           0 :             content = do_QueryInterface(element);
    3128           0 :             break;
    3129             :           }
    3130             :         }
    3131           0 :       }
    3132             :     }
    3133             :   }
    3134             : 
    3135           2 :   esm->SetContentState(content, NS_EVENT_STATE_URLTARGET);
    3136             : 
    3137             : #ifdef ACCESSIBILITY
    3138           2 :   nsIContent *anchorTarget = content;
    3139             : #endif
    3140             : 
    3141           2 :   nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
    3142           2 :   if (rootScroll && rootScroll->DidHistoryRestore()) {
    3143             :     // Scroll position restored from history trumps scrolling to anchor.
    3144           0 :     aScroll = false;
    3145           0 :     rootScroll->ClearDidHistoryRestore();
    3146             :   }
    3147             : 
    3148           2 :   if (content) {
    3149           2 :     if (aScroll) {
    3150           0 :       rv = ScrollContentIntoView(content,
    3151             :                                  ScrollAxis(SCROLL_TOP, SCROLL_ALWAYS),
    3152             :                                  ScrollAxis(),
    3153           0 :                                  ANCHOR_SCROLL_FLAGS | aAdditionalScrollFlags);
    3154           0 :       NS_ENSURE_SUCCESS(rv, rv);
    3155             : 
    3156           0 :       nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
    3157           0 :       if (rootScroll) {
    3158           0 :         mLastAnchorScrolledTo = content;
    3159           0 :         mLastAnchorScrollPositionY = rootScroll->GetScrollPosition().y;
    3160             :       }
    3161             :     }
    3162             : 
    3163             :     // Should we select the target? This action is controlled by a
    3164             :     // preference: the default is to not select.
    3165           2 :     bool selectAnchor = Preferences::GetBool("layout.selectanchor");
    3166             : 
    3167             :     // Even if select anchor pref is false, we must still move the
    3168             :     // caret there. That way tabbing will start from the new
    3169             :     // location
    3170           6 :     RefPtr<nsIDOMRange> jumpToRange = new nsRange(mDocument);
    3171           6 :     while (content && content->GetFirstChild()) {
    3172           2 :       content = content->GetFirstChild();
    3173             :     }
    3174           4 :     nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
    3175           2 :     NS_ASSERTION(node, "No nsIDOMNode for descendant of anchor");
    3176           2 :     jumpToRange->SelectNodeContents(node);
    3177             :     // Select the anchor
    3178           4 :     RefPtr<Selection> sel = mSelection->GetSelection(SelectionType::eNormal);
    3179           2 :     if (sel) {
    3180           2 :       sel->RemoveAllRanges();
    3181           2 :       sel->AddRange(jumpToRange);
    3182           2 :       if (!selectAnchor) {
    3183             :         // Use a caret (collapsed selection) at the start of the anchor
    3184           2 :         sel->CollapseToStart();
    3185             :       }
    3186             :     }
    3187             :     // Selection is at anchor.
    3188             :     // Now focus the document itself if focus is on an element within it.
    3189           2 :     nsPIDOMWindowOuter *win = mDocument->GetWindow();
    3190             : 
    3191           2 :     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    3192           2 :     if (fm && win) {
    3193           0 :       nsCOMPtr<mozIDOMWindowProxy> focusedWindow;
    3194           0 :       fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
    3195           0 :       if (SameCOMIdentity(win, focusedWindow)) {
    3196           0 :         fm->ClearFocus(focusedWindow);
    3197             :       }
    3198             :     }
    3199             : 
    3200             :     // If the target is an animation element, activate the animation
    3201           2 :     if (content->IsNodeOfType(nsINode::eANIMATION)) {
    3202           0 :       SVGContentUtils::ActivateByHyperlink(content.get());
    3203             :     }
    3204             :   } else {
    3205           0 :     rv = NS_ERROR_FAILURE;
    3206           0 :     NS_NAMED_LITERAL_STRING(top, "top");
    3207           0 :     if (nsContentUtils::EqualsIgnoreASCIICase(aAnchorName, top)) {
    3208             :       // Scroll to the top/left if aAnchorName is "top" and there is no element
    3209             :       // with such a name or id.
    3210           0 :       rv = NS_OK;
    3211           0 :       nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable();
    3212             :       // Check |aScroll| after setting |rv| so we set |rv| to the same
    3213             :       // thing whether or not |aScroll| is true.
    3214           0 :       if (aScroll && sf) {
    3215             :         // Scroll to the top of the page
    3216           0 :         sf->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT);
    3217             :       }
    3218             :     }
    3219             :   }
    3220             : 
    3221             : #ifdef ACCESSIBILITY
    3222           2 :   if (anchorTarget) {
    3223           2 :     nsAccessibilityService* accService = AccService();
    3224           2 :     if (accService)
    3225           0 :       accService->NotifyOfAnchorJumpTo(anchorTarget);
    3226             :   }
    3227             : #endif
    3228             : 
    3229           2 :   return rv;
    3230             : }
    3231             : 
    3232             : nsresult
    3233           0 : PresShell::ScrollToAnchor()
    3234             : {
    3235           0 :   if (!mLastAnchorScrolledTo) {
    3236           0 :     return NS_OK;
    3237             :   }
    3238           0 :   NS_ASSERTION(mDidInitialize, "should have done initial reflow by now");
    3239             : 
    3240           0 :   nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
    3241           0 :   if (!rootScroll ||
    3242           0 :       mLastAnchorScrollPositionY != rootScroll->GetScrollPosition().y) {
    3243           0 :     return NS_OK;
    3244             :   }
    3245           0 :   nsresult rv = ScrollContentIntoView(mLastAnchorScrolledTo,
    3246             :                                       ScrollAxis(SCROLL_TOP, SCROLL_ALWAYS),
    3247             :                                       ScrollAxis(),
    3248           0 :                                       ANCHOR_SCROLL_FLAGS);
    3249           0 :   mLastAnchorScrolledTo = nullptr;
    3250           0 :   return rv;
    3251             : }
    3252             : 
    3253             : /*
    3254             :  * Helper (per-continuation) for ScrollContentIntoView.
    3255             :  *
    3256             :  * @param aContainerFrame [in] the frame which aRect is relative to
    3257             :  * @param aFrame [in] Frame whose bounds should be unioned
    3258             :  * @param aUseWholeLineHeightForInlines [in] if true, then for inline frames
    3259             :  * we should include the top of the line in the added rectangle
    3260             :  * @param aRect [inout] rect into which its bounds should be unioned
    3261             :  * @param aHaveRect [inout] whether aRect contains data yet
    3262             :  * @param aPrevBlock [inout] the block aLines is a line iterator for
    3263             :  * @param aLines [inout] the line iterator we're using
    3264             :  * @param aCurLine [inout] the line to start looking from in this iterator
    3265             :  */
    3266             : static void
    3267           0 : AccumulateFrameBounds(nsIFrame* aContainerFrame,
    3268             :                       nsIFrame* aFrame,
    3269             :                       bool aUseWholeLineHeightForInlines,
    3270             :                       nsRect& aRect,
    3271             :                       bool& aHaveRect,
    3272             :                       nsIFrame*& aPrevBlock,
    3273             :                       nsAutoLineIterator& aLines,
    3274             :                       int32_t& aCurLine)
    3275             : {
    3276           0 :   nsIFrame* frame = aFrame;
    3277           0 :   nsRect frameBounds = nsRect(nsPoint(0, 0), aFrame->GetSize());
    3278             : 
    3279             :   // If this is an inline frame and either the bounds height is 0 (quirks
    3280             :   // layout model) or aUseWholeLineHeightForInlines is set, we need to
    3281             :   // change the top of the bounds to include the whole line.
    3282           0 :   if (frameBounds.height == 0 || aUseWholeLineHeightForInlines) {
    3283           0 :     nsIFrame *prevFrame = aFrame;
    3284           0 :     nsIFrame *f = aFrame;
    3285             : 
    3286           0 :     while (f && f->IsFrameOfType(nsIFrame::eLineParticipant) &&
    3287           0 :            !f->IsTransformed() && !f->IsAbsPosContainingBlock()) {
    3288           0 :       prevFrame = f;
    3289           0 :       f = prevFrame->GetParent();
    3290             :     }
    3291             : 
    3292           0 :     if (f != aFrame && f && f->IsBlockFrame()) {
    3293             :       // find the line containing aFrame and increase the top of |offset|.
    3294           0 :       if (f != aPrevBlock) {
    3295           0 :         aLines = f->GetLineIterator();
    3296           0 :         aPrevBlock = f;
    3297           0 :         aCurLine = 0;
    3298             :       }
    3299           0 :       if (aLines) {
    3300           0 :         int32_t index = aLines->FindLineContaining(prevFrame, aCurLine);
    3301           0 :         if (index >= 0) {
    3302           0 :           aCurLine = index;
    3303             :           nsIFrame *trash1;
    3304             :           int32_t trash2;
    3305           0 :           nsRect lineBounds;
    3306             : 
    3307           0 :           if (NS_SUCCEEDED(aLines->GetLine(index, &trash1, &trash2,
    3308             :                                            lineBounds))) {
    3309           0 :             frameBounds += frame->GetOffsetTo(f);
    3310           0 :             frame = f;
    3311           0 :             if (lineBounds.y < frameBounds.y) {
    3312           0 :               frameBounds.height = frameBounds.YMost() - lineBounds.y;
    3313           0 :               frameBounds.y = lineBounds.y;
    3314             :             }
    3315             :           }
    3316             :         }
    3317             :       }
    3318             :     }
    3319             :   }
    3320             : 
    3321             :   nsRect transformedBounds = nsLayoutUtils::TransformFrameRectToAncestor(frame,
    3322           0 :     frameBounds, aContainerFrame);
    3323             : 
    3324           0 :   if (aHaveRect) {
    3325             :     // We can't use nsRect::UnionRect since it drops empty rects on
    3326             :     // the floor, and we need to include them.  (Thus we need
    3327             :     // aHaveRect to know when to drop the initial value on the floor.)
    3328           0 :     aRect.UnionRectEdges(aRect, transformedBounds);
    3329             :   } else {
    3330           0 :     aHaveRect = true;
    3331           0 :     aRect = transformedBounds;
    3332             :   }
    3333           0 : }
    3334             : 
    3335             : static bool
    3336           1 : ComputeNeedToScroll(nsIPresShell::WhenToScroll aWhenToScroll,
    3337             :                     nscoord                    aLineSize,
    3338             :                     nscoord                    aRectMin,
    3339             :                     nscoord                    aRectMax,
    3340             :                     nscoord                    aViewMin,
    3341             :                     nscoord                    aViewMax) {
    3342             :   // See how the rect should be positioned vertically
    3343           1 :   if (nsIPresShell::SCROLL_ALWAYS == aWhenToScroll) {
    3344             :     // The caller wants the frame as visible as possible
    3345           0 :     return true;
    3346           1 :   } else if (nsIPresShell::SCROLL_IF_NOT_VISIBLE == aWhenToScroll) {
    3347             :     // Scroll only if no part of the frame is visible in this view
    3348           0 :     return aRectMax - aLineSize <= aViewMin ||
    3349           0 :            aRectMin + aLineSize >= aViewMax;
    3350           1 :   } else if (nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE == aWhenToScroll) {
    3351             :     // Scroll only if part of the frame is hidden and more can fit in view
    3352           1 :     return !(aRectMin >= aViewMin && aRectMax <= aViewMax) &&
    3353           1 :       std::min(aViewMax, aRectMax) - std::max(aRectMin, aViewMin) < aViewMax - aViewMin;
    3354             :   }
    3355           0 :   return false;
    3356             : }
    3357             : 
    3358             : static nscoord
    3359           0 : ComputeWhereToScroll(int16_t aWhereToScroll,
    3360             :                      nscoord aOriginalCoord,
    3361             :                      nscoord aRectMin,
    3362             :                      nscoord aRectMax,
    3363             :                      nscoord aViewMin,
    3364             :                      nscoord aViewMax,
    3365             :                      nscoord* aRangeMin,
    3366             :                      nscoord* aRangeMax) {
    3367           0 :   nscoord resultCoord = aOriginalCoord;
    3368             :   // Allow the scroll operation to land anywhere that
    3369             :   // makes the whole rectangle visible.
    3370           0 :   if (nsIPresShell::SCROLL_MINIMUM == aWhereToScroll) {
    3371           0 :     if (aRectMin < aViewMin) {
    3372             :       // Scroll up so the frame's top edge is visible
    3373           0 :       resultCoord = aRectMin;
    3374           0 :     } else if (aRectMax > aViewMax) {
    3375             :       // Scroll down so the frame's bottom edge is visible. Make sure the
    3376             :       // frame's top edge is still visible
    3377           0 :       resultCoord = aOriginalCoord + aRectMax - aViewMax;
    3378           0 :       if (resultCoord > aRectMin) {
    3379           0 :         resultCoord = aRectMin;
    3380             :       }
    3381             :     }
    3382             :   } else {
    3383             :     nscoord frameAlignCoord =
    3384           0 :       NSToCoordRound(aRectMin + (aRectMax - aRectMin) * (aWhereToScroll / 100.0f));
    3385           0 :     resultCoord =  NSToCoordRound(frameAlignCoord - (aViewMax - aViewMin) * (
    3386           0 :                                   aWhereToScroll / 100.0f));
    3387             :   }
    3388           0 :   nscoord scrollPortLength = aViewMax - aViewMin;
    3389             :   // Force the scroll range to extend to include resultCoord.
    3390           0 :   *aRangeMin = std::min(resultCoord, aRectMax - scrollPortLength);
    3391           0 :   *aRangeMax = std::max(resultCoord, aRectMin);
    3392           0 :   return resultCoord;
    3393             : }
    3394             : 
    3395             : /**
    3396             :  * This function takes a scrollable frame, a rect in the coordinate system
    3397             :  * of the scrolled frame, and a desired percentage-based scroll
    3398             :  * position and attempts to scroll the rect to that position in the
    3399             :  * scrollport.
    3400             :  *
    3401             :  * This needs to work even if aRect has a width or height of zero.
    3402             :  */
    3403           1 : static void ScrollToShowRect(nsIScrollableFrame*      aFrameAsScrollable,
    3404             :                              const nsRect&            aRect,
    3405             :                              nsIPresShell::ScrollAxis aVertical,
    3406             :                              nsIPresShell::ScrollAxis aHorizontal,
    3407             :                              uint32_t                 aFlags)
    3408             : {
    3409           1 :   nsPoint scrollPt = aFrameAsScrollable->GetScrollPosition();
    3410             :   nsRect visibleRect(scrollPt,
    3411           2 :                      aFrameAsScrollable->GetScrollPositionClampingScrollPortSize());
    3412             : 
    3413           1 :   nsSize lineSize;
    3414             :   // Don't call GetLineScrollAmount unless we actually need it. Not only
    3415             :   // does this save time, but it's not safe to call GetLineScrollAmount
    3416             :   // during reflow (because it depends on font size inflation and doesn't
    3417             :   // use the in-reflow-safe font-size inflation path). If we did call it,
    3418             :   // it would assert and possible give the wrong result.
    3419           2 :   if (aVertical.mWhenToScroll == nsIPresShell::SCROLL_IF_NOT_VISIBLE ||
    3420           1 :       aHorizontal.mWhenToScroll == nsIPresShell::SCROLL_IF_NOT_VISIBLE) {
    3421           0 :     lineSize = aFrameAsScrollable->GetLineScrollAmount();
    3422             :   }
    3423           2 :   ScrollbarStyles ss = aFrameAsScrollable->GetScrollbarStyles();
    3424           2 :   nsRect allowedRange(scrollPt, nsSize(0, 0));
    3425           1 :   bool needToScroll = false;
    3426           1 :   uint32_t directions = aFrameAsScrollable->GetPerceivedScrollingDirections();
    3427             : 
    3428           2 :   if (((aFlags & nsIPresShell::SCROLL_OVERFLOW_HIDDEN) ||
    3429           2 :        ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN) &&
    3430           2 :       (!aVertical.mOnlyIfPerceivedScrollableDirection ||
    3431           1 :        (directions & nsIScrollableFrame::VERTICAL))) {
    3432             : 
    3433           0 :     if (ComputeNeedToScroll(aVertical.mWhenToScroll,
    3434             :                             lineSize.height,
    3435           0 :                             aRect.y,
    3436             :                             aRect.YMost(),
    3437             :                             visibleRect.y,
    3438             :                             visibleRect.YMost())) {
    3439             :       nscoord maxHeight;
    3440           0 :       scrollPt.y = ComputeWhereToScroll(aVertical.mWhereToScroll,
    3441             :                                         scrollPt.y,
    3442           0 :                                         aRect.y,
    3443             :                                         aRect.YMost(),
    3444             :                                         visibleRect.y,
    3445             :                                         visibleRect.YMost(),
    3446             :                                         &allowedRange.y, &maxHeight);
    3447           0 :       allowedRange.height = maxHeight - allowedRange.y;
    3448           0 :       needToScroll = true;
    3449             :     }
    3450             :   }
    3451             : 
    3452           2 :   if (((aFlags & nsIPresShell::SCROLL_OVERFLOW_HIDDEN) ||
    3453           2 :        ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN) &&
    3454           1 :       (!aHorizontal.mOnlyIfPerceivedScrollableDirection ||
    3455           0 :        (directions & nsIScrollableFrame::HORIZONTAL))) {
    3456             : 
    3457           2 :     if (ComputeNeedToScroll(aHorizontal.mWhenToScroll,
    3458             :                             lineSize.width,
    3459           1 :                             aRect.x,
    3460             :                             aRect.XMost(),
    3461             :                             visibleRect.x,
    3462             :                             visibleRect.XMost())) {
    3463             :       nscoord maxWidth;
    3464           0 :       scrollPt.x = ComputeWhereToScroll(aHorizontal.mWhereToScroll,
    3465             :                                         scrollPt.x,
    3466           0 :                                         aRect.x,
    3467             :                                         aRect.XMost(),
    3468             :                                         visibleRect.x,
    3469             :                                         visibleRect.XMost(),
    3470             :                                         &allowedRange.x, &maxWidth);
    3471           0 :       allowedRange.width = maxWidth - allowedRange.x;
    3472           0 :       needToScroll = true;
    3473             :     }
    3474             :   }
    3475             : 
    3476             :   // If we don't need to scroll, then don't try since it might cancel
    3477             :   // a current smooth scroll operation.
    3478           1 :   if (needToScroll) {
    3479           0 :     nsIScrollableFrame::ScrollMode scrollMode = nsIScrollableFrame::INSTANT;
    3480           0 :     bool autoBehaviorIsSmooth = (aFrameAsScrollable->GetScrollbarStyles().mScrollBehavior
    3481           0 :                                   == NS_STYLE_SCROLL_BEHAVIOR_SMOOTH);
    3482           0 :     bool smoothScroll = (aFlags & nsIPresShell::SCROLL_SMOOTH) ||
    3483           0 :                           ((aFlags & nsIPresShell::SCROLL_SMOOTH_AUTO) && autoBehaviorIsSmooth);
    3484           0 :     if (gfxPrefs::ScrollBehaviorEnabled() && smoothScroll) {
    3485           0 :       scrollMode = nsIScrollableFrame::SMOOTH_MSD;
    3486             :     }
    3487           0 :     aFrameAsScrollable->ScrollTo(scrollPt, scrollMode, &allowedRange);
    3488             :   }
    3489           1 : }
    3490             : 
    3491             : nsresult
    3492           1 : PresShell::ScrollContentIntoView(nsIContent*              aContent,
    3493             :                                  nsIPresShell::ScrollAxis aVertical,
    3494             :                                  nsIPresShell::ScrollAxis aHorizontal,
    3495             :                                  uint32_t                 aFlags)
    3496             : {
    3497           1 :   NS_ENSURE_TRUE(aContent, NS_ERROR_NULL_POINTER);
    3498           2 :   nsCOMPtr<nsIDocument> composedDoc = aContent->GetComposedDoc();
    3499           1 :   NS_ENSURE_STATE(composedDoc);
    3500             : 
    3501           1 :   NS_ASSERTION(mDidInitialize, "should have done initial reflow by now");
    3502             : 
    3503           1 :   if (mContentToScrollTo) {
    3504           0 :     mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
    3505             :   }
    3506           1 :   mContentToScrollTo = aContent;
    3507           1 :   ScrollIntoViewData* data = new ScrollIntoViewData();
    3508           1 :   data->mContentScrollVAxis = aVertical;
    3509           1 :   data->mContentScrollHAxis = aHorizontal;
    3510           1 :   data->mContentToScrollToFlags = aFlags;
    3511           1 :   if (NS_FAILED(mContentToScrollTo->SetProperty(nsGkAtoms::scrolling, data,
    3512             :                                                 nsINode::DeleteProperty<PresShell::ScrollIntoViewData>))) {
    3513           0 :     mContentToScrollTo = nullptr;
    3514             :   }
    3515             : 
    3516             :   // Flush layout and attempt to scroll in the process.
    3517           1 :   if (nsIPresShell* shell = composedDoc->GetShell()) {
    3518           1 :     shell->SetNeedLayoutFlush();
    3519             :   }
    3520           1 :   composedDoc->FlushPendingNotifications(FlushType::InterruptibleLayout);
    3521             : 
    3522             :   // If mContentToScrollTo is non-null, that means we interrupted the reflow
    3523             :   // (or suppressed it altogether because we're suppressing interruptible
    3524             :   // flushes right now) and won't necessarily get the position correct, but do
    3525             :   // a best-effort scroll here.  The other option would be to do this inside
    3526             :   // FlushPendingNotifications, but I'm not sure the repeated scrolling that
    3527             :   // could trigger if reflows keep getting interrupted would be more desirable
    3528             :   // than a single best-effort scroll followed by one final scroll on the first
    3529             :   // completed reflow.
    3530           1 :   if (mContentToScrollTo) {
    3531           0 :     DoScrollContentIntoView();
    3532             :   }
    3533           1 :   return NS_OK;
    3534             : }
    3535             : 
    3536             : void
    3537           1 : PresShell::DoScrollContentIntoView()
    3538             : {
    3539           1 :   NS_ASSERTION(mDidInitialize, "should have done initial reflow by now");
    3540             : 
    3541           1 :   nsIFrame* frame = mContentToScrollTo->GetPrimaryFrame();
    3542           1 :   if (!frame) {
    3543           0 :     mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
    3544           0 :     mContentToScrollTo = nullptr;
    3545           0 :     return;
    3546             :   }
    3547             : 
    3548           1 :   if (frame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
    3549             :     // The reflow flush before this scroll got interrupted, and this frame's
    3550             :     // coords and size are all zero, and it has no content showing anyway.
    3551             :     // Don't bother scrolling to it.  We'll try again when we finish up layout.
    3552           0 :     return;
    3553             :   }
    3554             : 
    3555             :   // Make sure we skip 'frame' ... if it's scrollable, we should use its
    3556             :   // scrollable ancestor as the container.
    3557             :   nsIFrame* container = nsLayoutUtils::GetClosestFrameOfType(
    3558           1 :     frame->GetParent(), LayoutFrameType::Scroll);
    3559           1 :   if (!container) {
    3560             :     // nothing can be scrolled
    3561           1 :     return;
    3562             :   }
    3563             : 
    3564             :   ScrollIntoViewData* data = static_cast<ScrollIntoViewData*>(
    3565           0 :     mContentToScrollTo->GetProperty(nsGkAtoms::scrolling));
    3566           0 :   if (MOZ_UNLIKELY(!data)) {
    3567           0 :     mContentToScrollTo = nullptr;
    3568           0 :     return;
    3569             :   }
    3570             : 
    3571             :   // This is a two-step process.
    3572             :   // Step 1: Find the bounds of the rect we want to scroll into view.  For
    3573             :   //         example, for an inline frame we may want to scroll in the whole
    3574             :   //         line, or we may want to scroll multiple lines into view.
    3575             :   // Step 2: Walk container frame and its ancestors and scroll them
    3576             :   //         appropriately.
    3577             :   // frameBounds is relative to container. We're assuming
    3578             :   // that scrollframes don't split so every continuation of frame will
    3579             :   // be a descendant of container. (Things would still mostly work
    3580             :   // even if that assumption was false.)
    3581           0 :   nsRect frameBounds;
    3582           0 :   bool haveRect = false;
    3583             :   bool useWholeLineHeightForInlines =
    3584           0 :     data->mContentScrollVAxis.mWhenToScroll != nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE;
    3585             :   // Reuse the same line iterator across calls to AccumulateFrameBounds.  We set
    3586             :   // it every time we detect a new block (stored in prevBlock).
    3587           0 :   nsIFrame* prevBlock = nullptr;
    3588           0 :   nsAutoLineIterator lines;
    3589             :   // The last line we found a continuation on in |lines|.  We assume that later
    3590             :   // continuations cannot come on earlier lines.
    3591           0 :   int32_t curLine = 0;
    3592           0 :   do {
    3593           0 :     AccumulateFrameBounds(container, frame, useWholeLineHeightForInlines,
    3594           0 :                           frameBounds, haveRect, prevBlock, lines, curLine);
    3595           0 :   } while ((frame = frame->GetNextContinuation()));
    3596             : 
    3597           0 :   ScrollFrameRectIntoView(container, frameBounds, data->mContentScrollVAxis,
    3598             :                           data->mContentScrollHAxis,
    3599           0 :                           data->mContentToScrollToFlags);
    3600             : }
    3601             : 
    3602             : bool
    3603           1 : PresShell::ScrollFrameRectIntoView(nsIFrame*                aFrame,
    3604             :                                    const nsRect&            aRect,
    3605             :                                    nsIPresShell::ScrollAxis aVertical,
    3606             :                                    nsIPresShell::ScrollAxis aHorizontal,
    3607             :                                    uint32_t                 aFlags)
    3608             : {
    3609           1 :   bool didScroll = false;
    3610             :   // This function needs to work even if rect has a width or height of 0.
    3611           2 :   nsRect rect = aRect;
    3612           1 :   nsIFrame* container = aFrame;
    3613             :   // Walk up the frame hierarchy scrolling the rect into view and
    3614             :   // keeping rect relative to container
    3615           2 :   do {
    3616           3 :     nsIScrollableFrame* sf = do_QueryFrame(container);
    3617           3 :     if (sf) {
    3618           1 :       nsPoint oldPosition = sf->GetScrollPosition();
    3619           1 :       nsRect targetRect = rect;
    3620           1 :       if (container->StyleDisplay()->mOverflowClipBox ==
    3621             :             NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX) {
    3622           1 :         nsMargin padding = container->GetUsedPadding();
    3623           1 :         targetRect.Inflate(padding);
    3624             :       }
    3625           2 :       ScrollToShowRect(sf, targetRect - sf->GetScrolledFrame()->GetPosition(),
    3626           1 :                        aVertical, aHorizontal, aFlags);
    3627           1 :       nsPoint newPosition = sf->LastScrollDestination();
    3628             :       // If the scroll position increased, that means our content moved up,
    3629             :       // so our rect's offset should decrease
    3630           1 :       rect += oldPosition - newPosition;
    3631             : 
    3632           1 :       if (oldPosition != newPosition) {
    3633           0 :         didScroll = true;
    3634             :       }
    3635             : 
    3636             :       // only scroll one container when this flag is set
    3637           1 :       if (aFlags & nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY) {
    3638           1 :         break;
    3639             :       }
    3640             :     }
    3641             :     nsIFrame* parent;
    3642           2 :     if (container->IsTransformed()) {
    3643           0 :       container->GetTransformMatrix(nullptr, &parent);
    3644           0 :       rect = nsLayoutUtils::TransformFrameRectToAncestor(container, rect, parent);
    3645             :     } else {
    3646           2 :       rect += container->GetPosition();
    3647           2 :       parent = container->GetParent();
    3648             :     }
    3649           2 :     if (!parent && !(aFlags & nsIPresShell::SCROLL_NO_PARENT_FRAMES)) {
    3650           0 :       nsPoint extraOffset(0,0);
    3651           0 :       parent = nsLayoutUtils::GetCrossDocParentFrame(container, &extraOffset);
    3652           0 :       if (parent) {
    3653           0 :         int32_t APD = container->PresContext()->AppUnitsPerDevPixel();
    3654           0 :         int32_t parentAPD = parent->PresContext()->AppUnitsPerDevPixel();
    3655           0 :         rect = rect.ScaleToOtherAppUnitsRoundOut(APD, parentAPD);
    3656           0 :         rect += extraOffset;
    3657             :       }
    3658             :     }
    3659           2 :     container = parent;
    3660           2 :   } while (container);
    3661             : 
    3662           2 :   return didScroll;
    3663             : }
    3664             : 
    3665             : nsRectVisibility
    3666           0 : PresShell::GetRectVisibility(nsIFrame* aFrame,
    3667             :                              const nsRect &aRect,
    3668             :                              nscoord aMinTwips) const
    3669             : {
    3670           0 :   NS_ASSERTION(aFrame->PresContext() == GetPresContext(),
    3671             :                "prescontext mismatch?");
    3672           0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    3673           0 :   NS_ASSERTION(rootFrame,
    3674             :                "How can someone have a frame for this presshell when there's no root?");
    3675           0 :   nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable();
    3676           0 :   nsRect scrollPortRect;
    3677           0 :   if (sf) {
    3678           0 :     scrollPortRect = sf->GetScrollPortRect();
    3679           0 :     nsIFrame* f = do_QueryFrame(sf);
    3680           0 :     scrollPortRect += f->GetOffsetTo(rootFrame);
    3681             :   } else {
    3682           0 :     scrollPortRect = nsRect(nsPoint(0,0), rootFrame->GetSize());
    3683             :   }
    3684             : 
    3685           0 :   nsRect r = aRect + aFrame->GetOffsetTo(rootFrame);
    3686             :   // If aRect is entirely visible then we don't need to ensure that
    3687             :   // at least aMinTwips of it is visible
    3688           0 :   if (scrollPortRect.Contains(r))
    3689           0 :     return nsRectVisibility_kVisible;
    3690             : 
    3691           0 :   nsRect insetRect = scrollPortRect;
    3692           0 :   insetRect.Deflate(aMinTwips, aMinTwips);
    3693           0 :   if (r.YMost() <= insetRect.y)
    3694           0 :     return nsRectVisibility_kAboveViewport;
    3695           0 :   if (r.y >= insetRect.YMost())
    3696           0 :     return nsRectVisibility_kBelowViewport;
    3697           0 :   if (r.XMost() <= insetRect.x)
    3698           0 :     return nsRectVisibility_kLeftOfViewport;
    3699           0 :   if (r.x >= insetRect.XMost())
    3700           0 :     return nsRectVisibility_kRightOfViewport;
    3701             : 
    3702           0 :   return nsRectVisibility_kVisible;
    3703             : }
    3704             : 
    3705             : void
    3706         245 : PresShell::ScheduleViewManagerFlush(PaintType aType)
    3707             : {
    3708         245 :   if (aType == PAINT_DELAYED_COMPRESS) {
    3709             :     // Delay paint for 1 second.
    3710             :     static const uint32_t kPaintDelayPeriod = 1000;
    3711          11 :     if (!mDelayedPaintTimer) {
    3712             :       nsTimerCallbackFunc
    3713           3 :         PaintTimerCallBack = [](nsITimer* aTimer, void* aClosure) {
    3714             :           // The passed-in PresShell is always alive here. Because if PresShell
    3715             :           // died, mDelayedPaintTimer->Cancel() would be called during the
    3716             :           // destruction and this callback would never be invoked.
    3717           1 :           auto self = static_cast<PresShell*>(aClosure);
    3718           1 :           self->SetNextPaintCompressed();
    3719           1 :           self->ScheduleViewManagerFlush();
    3720           4 :       };
    3721             : 
    3722           1 :       mDelayedPaintTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
    3723           1 :       mDelayedPaintTimer->SetTarget(
    3724           1 :           mDocument->EventTargetFor(TaskCategory::Other));
    3725           1 :       mDelayedPaintTimer->InitWithNamedFuncCallback(PaintTimerCallBack,
    3726             :                                                     this,
    3727             :                                                     kPaintDelayPeriod,
    3728             :                                                     nsITimer::TYPE_ONE_SHOT,
    3729           1 :                                                     "PaintTimerCallBack");
    3730             :     }
    3731          11 :     return;
    3732             :   }
    3733             : 
    3734         234 :   nsPresContext* presContext = GetPresContext();
    3735         234 :   if (presContext) {
    3736         234 :     presContext->RefreshDriver()->ScheduleViewManagerFlush();
    3737             :   }
    3738         234 :   SetNeedLayoutFlush();
    3739             : }
    3740             : 
    3741             : bool
    3742           0 : FlushLayoutRecursive(nsIDocument* aDocument,
    3743             :                      void* aData = nullptr)
    3744             : {
    3745           0 :   MOZ_ASSERT(!aData);
    3746           0 :   nsCOMPtr<nsIDocument> kungFuDeathGrip(aDocument);
    3747           0 :   aDocument->EnumerateSubDocuments(FlushLayoutRecursive, nullptr);
    3748           0 :   aDocument->FlushPendingNotifications(FlushType::Layout);
    3749           0 :   return true;
    3750             : }
    3751             : 
    3752             : void
    3753           0 : PresShell::DispatchSynthMouseMove(WidgetGUIEvent* aEvent,
    3754             :                                   bool aFlushOnHoverChange)
    3755             : {
    3756           0 :   AutoProfilerTracing tracing("Paint", "DispatchSynthMouseMove");
    3757           0 :   RestyleManager* restyleManager = mPresContext->RestyleManager();
    3758             :   uint32_t hoverGenerationBefore =
    3759           0 :     restyleManager->GetHoverGeneration();
    3760             :   nsEventStatus status;
    3761           0 :   nsView* targetView = nsView::GetViewFor(aEvent->mWidget);
    3762           0 :   if (!targetView)
    3763           0 :     return;
    3764           0 :   targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
    3765           0 :   if (MOZ_UNLIKELY(mIsDestroying)) {
    3766           0 :     return;
    3767             :   }
    3768           0 :   if (aFlushOnHoverChange &&
    3769           0 :       hoverGenerationBefore != restyleManager->GetHoverGeneration()) {
    3770             :     // Flush so that the resulting reflow happens now so that our caller
    3771             :     // can suppress any synthesized mouse moves caused by that reflow.
    3772             :     // This code only ever runs for the root document, but :hover changes
    3773             :     // can happen in descendant documents too, so make sure we flush
    3774             :     // all of them.
    3775           0 :     FlushLayoutRecursive(mDocument);
    3776             :   }
    3777             : }
    3778             : 
    3779             : void
    3780          11 : PresShell::ClearMouseCaptureOnView(nsView* aView)
    3781             : {
    3782          11 :   if (gCaptureInfo.mContent) {
    3783           0 :     if (aView) {
    3784             :       // if a view was specified, ensure that the captured content is within
    3785             :       // this view.
    3786           0 :       nsIFrame* frame = gCaptureInfo.mContent->GetPrimaryFrame();
    3787           0 :       if (frame) {
    3788           0 :         nsView* view = frame->GetClosestView();
    3789             :         // if there is no view, capturing won't be handled any more, so
    3790             :         // just release the capture.
    3791           0 :         if (view) {
    3792           0 :           do {
    3793           0 :             if (view == aView) {
    3794           0 :               gCaptureInfo.mContent = nullptr;
    3795             :               // the view containing the captured content likely disappeared so
    3796             :               // disable capture for now.
    3797           0 :               gCaptureInfo.mAllowed = false;
    3798           0 :               break;
    3799             :             }
    3800             : 
    3801           0 :             view = view->GetParent();
    3802           0 :           } while (view);
    3803             :           // return if the view wasn't found
    3804           0 :           return;
    3805             :         }
    3806             :       }
    3807             :     }
    3808             : 
    3809           0 :     gCaptureInfo.mContent = nullptr;
    3810             :   }
    3811             : 
    3812             :   // disable mouse capture until the next mousedown as a dialog has opened
    3813             :   // or a drag has started. Otherwise, someone could start capture during
    3814             :   // the modal dialog or drag.
    3815          11 :   gCaptureInfo.mAllowed = false;
    3816             : }
    3817             : 
    3818             : void
    3819           0 : nsIPresShell::ClearMouseCapture(nsIFrame* aFrame)
    3820             : {
    3821           0 :   if (!gCaptureInfo.mContent) {
    3822           0 :     gCaptureInfo.mAllowed = false;
    3823           0 :     return;
    3824             :   }
    3825             : 
    3826             :   // null frame argument means clear the capture
    3827           0 :   if (!aFrame) {
    3828           0 :     gCaptureInfo.mContent = nullptr;
    3829           0 :     gCaptureInfo.mAllowed = false;
    3830           0 :     return;
    3831             :   }
    3832             : 
    3833           0 :   nsIFrame* capturingFrame = gCaptureInfo.mContent->GetPrimaryFrame();
    3834           0 :   if (!capturingFrame) {
    3835           0 :     gCaptureInfo.mContent = nullptr;
    3836           0 :     gCaptureInfo.mAllowed = false;
    3837           0 :     return;
    3838             :   }
    3839             : 
    3840           0 :   if (nsLayoutUtils::IsAncestorFrameCrossDoc(aFrame, capturingFrame)) {
    3841           0 :     gCaptureInfo.mContent = nullptr;
    3842           0 :     gCaptureInfo.mAllowed = false;
    3843             :   }
    3844             : }
    3845             : 
    3846             : nsresult
    3847          25 : PresShell::CaptureHistoryState(nsILayoutHistoryState** aState)
    3848             : {
    3849          25 :   NS_PRECONDITION(nullptr != aState, "null state pointer");
    3850             : 
    3851             :   // We actually have to mess with the docshell here, since we want to
    3852             :   // store the state back in it.
    3853             :   // XXXbz this isn't really right, since this is being called in the
    3854             :   // content viewer's Hide() method...  by that point the docshell's
    3855             :   // state could be wrong.  We should sort out a better ownership
    3856             :   // model for the layout history state.
    3857          50 :   nsCOMPtr<nsIDocShell> docShell(mPresContext->GetDocShell());
    3858          25 :   if (!docShell)
    3859          21 :     return NS_ERROR_FAILURE;
    3860             : 
    3861           8 :   nsCOMPtr<nsILayoutHistoryState> historyState;
    3862           4 :   docShell->GetLayoutHistoryState(getter_AddRefs(historyState));
    3863           4 :   if (!historyState) {
    3864             :     // Create the document state object
    3865           4 :     historyState = NS_NewLayoutHistoryState();
    3866           4 :     docShell->SetLayoutHistoryState(historyState);
    3867             :   }
    3868             : 
    3869           4 :   *aState = historyState;
    3870           4 :   NS_IF_ADDREF(*aState);
    3871             : 
    3872             :   // Capture frame state for the entire frame hierarchy
    3873           4 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    3874           4 :   if (!rootFrame) return NS_OK;
    3875             : 
    3876           3 :   mFrameConstructor->CaptureFrameState(rootFrame, historyState);
    3877             : 
    3878           3 :   return NS_OK;
    3879             : }
    3880             : 
    3881             : void
    3882          24 : PresShell::ScheduleBeforeFirstPaint()
    3883             : {
    3884          24 :   if (!mDocument->IsResourceDoc()) {
    3885             :     // Notify observers that a new page is about to be drawn. Execute this
    3886             :     // as soon as it is safe to run JS, which is guaranteed to be before we
    3887             :     // go back to the event loop and actually draw the page.
    3888           6 :     nsContentUtils::AddScriptRunner(new nsBeforeFirstPaintDispatcher(mDocument));
    3889             :   }
    3890          24 : }
    3891             : 
    3892             : void
    3893          24 : PresShell::UnsuppressAndInvalidate()
    3894             : {
    3895             :   // Note: We ignore the EnsureVisible check for resource documents, because
    3896             :   // they won't have a docshell, so they'll always fail EnsureVisible.
    3897          48 :   if ((!mDocument->IsResourceDoc() && !mPresContext->EnsureVisible()) ||
    3898          24 :       mHaveShutDown) {
    3899             :     // No point; we're about to be torn down anyway.
    3900           0 :     return;
    3901             :   }
    3902             : 
    3903          24 :   ScheduleBeforeFirstPaint();
    3904             : 
    3905          24 :   mPaintingSuppressed = false;
    3906          24 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    3907          24 :   if (rootFrame) {
    3908             :     // let's assume that outline on a root frame is not supported
    3909          24 :     rootFrame->InvalidateFrame();
    3910             :   }
    3911             : 
    3912             :   // now that painting is unsuppressed, focus may be set on the document
    3913          24 :   if (nsPIDOMWindowOuter* win = mDocument->GetWindow())
    3914           3 :     win->SetReadyForFocus();
    3915             : 
    3916          24 :   if (!mHaveShutDown) {
    3917          24 :     SynthesizeMouseMove(false);
    3918          24 :     ScheduleApproximateFrameVisibilityUpdateNow();
    3919             :   }
    3920             : }
    3921             : 
    3922             : void
    3923          28 : PresShell::UnsuppressPainting()
    3924             : {
    3925          28 :   if (mPaintSuppressionTimer) {
    3926          24 :     mPaintSuppressionTimer->Cancel();
    3927          24 :     mPaintSuppressionTimer = nullptr;
    3928             :   }
    3929             : 
    3930          28 :   if (mIsDocumentGone || !mPaintingSuppressed)
    3931           4 :     return;
    3932             : 
    3933             :   // If we have reflows pending, just wait until we process
    3934             :   // the reflows and get all the frames where we want them
    3935             :   // before actually unlocking the painting.  Otherwise
    3936             :   // go ahead and unlock now.
    3937          24 :   if (!mDirtyRoots.IsEmpty())
    3938          20 :     mShouldUnsuppressPainting = true;
    3939             :   else
    3940           4 :     UnsuppressAndInvalidate();
    3941             : }
    3942             : 
    3943             : // Post a request to handle an arbitrary callback after reflow has finished.
    3944             : nsresult
    3945         184 : PresShell::PostReflowCallback(nsIReflowCallback* aCallback)
    3946             : {
    3947         184 :   void* result = AllocateByObjectID(eArenaObjectID_nsCallbackEventRequest,
    3948         184 :                                     sizeof(nsCallbackEventRequest));
    3949         184 :   nsCallbackEventRequest* request = (nsCallbackEventRequest*)result;
    3950             : 
    3951         184 :   request->callback = aCallback;
    3952         184 :   request->next = nullptr;
    3953             : 
    3954         184 :   if (mLastCallbackEventRequest) {
    3955         118 :     mLastCallbackEventRequest = mLastCallbackEventRequest->next = request;
    3956             :   } else {
    3957          66 :     mFirstCallbackEventRequest = request;
    3958          66 :     mLastCallbackEventRequest = request;
    3959             :   }
    3960             : 
    3961         184 :   return NS_OK;
    3962             : }
    3963             : 
    3964             : void
    3965           0 : PresShell::CancelReflowCallback(nsIReflowCallback* aCallback)
    3966             : {
    3967           0 :    nsCallbackEventRequest* before = nullptr;
    3968           0 :    nsCallbackEventRequest* node = mFirstCallbackEventRequest;
    3969           0 :    while(node)
    3970             :    {
    3971           0 :       nsIReflowCallback* callback = node->callback;
    3972             : 
    3973           0 :       if (callback == aCallback)
    3974             :       {
    3975           0 :         nsCallbackEventRequest* toFree = node;
    3976           0 :         if (node == mFirstCallbackEventRequest) {
    3977           0 :           node = node->next;
    3978           0 :           mFirstCallbackEventRequest = node;
    3979           0 :           NS_ASSERTION(before == nullptr, "impossible");
    3980             :         } else {
    3981           0 :           node = node->next;
    3982           0 :           before->next = node;
    3983             :         }
    3984             : 
    3985           0 :         if (toFree == mLastCallbackEventRequest) {
    3986           0 :           mLastCallbackEventRequest = before;
    3987             :         }
    3988             : 
    3989           0 :         FreeByObjectID(eArenaObjectID_nsCallbackEventRequest, toFree);
    3990             :       } else {
    3991           0 :         before = node;
    3992           0 :         node = node->next;
    3993             :       }
    3994             :    }
    3995           0 : }
    3996             : 
    3997             : void
    3998           4 : PresShell::CancelPostedReflowCallbacks()
    3999             : {
    4000           4 :   while (mFirstCallbackEventRequest) {
    4001           0 :     nsCallbackEventRequest* node = mFirstCallbackEventRequest;
    4002           0 :     mFirstCallbackEventRequest = node->next;
    4003           0 :     if (!mFirstCallbackEventRequest) {
    4004           0 :       mLastCallbackEventRequest = nullptr;
    4005             :     }
    4006           0 :     nsIReflowCallback* callback = node->callback;
    4007           0 :     FreeByObjectID(eArenaObjectID_nsCallbackEventRequest, node);
    4008           0 :     if (callback) {
    4009           0 :       callback->ReflowCallbackCanceled();
    4010             :     }
    4011             :   }
    4012           4 : }
    4013             : 
    4014             : void
    4015          68 : PresShell::HandlePostedReflowCallbacks(bool aInterruptible)
    4016             : {
    4017          68 :    bool shouldFlush = false;
    4018             : 
    4019         436 :    while (mFirstCallbackEventRequest) {
    4020         184 :      nsCallbackEventRequest* node = mFirstCallbackEventRequest;
    4021         184 :      mFirstCallbackEventRequest = node->next;
    4022         184 :      if (!mFirstCallbackEventRequest) {
    4023          66 :        mLastCallbackEventRequest = nullptr;
    4024             :      }
    4025         184 :      nsIReflowCallback* callback = node->callback;
    4026         184 :      FreeByObjectID(eArenaObjectID_nsCallbackEventRequest, node);
    4027         184 :      if (callback) {
    4028         184 :        if (callback->ReflowFinished()) {
    4029          25 :          shouldFlush = true;
    4030             :        }
    4031             :      }
    4032             :    }
    4033             : 
    4034             :    FlushType flushType =
    4035          68 :      aInterruptible ? FlushType::InterruptibleLayout : FlushType::Layout;
    4036          68 :    if (shouldFlush && !mIsDestroying) {
    4037           6 :      FlushPendingNotifications(flushType);
    4038             :    }
    4039          68 : }
    4040             : 
    4041             : bool
    4042         179 : PresShell::IsSafeToFlush() const
    4043             : {
    4044             :   // Not safe if we are reflowing or in the middle of frame construction
    4045         358 :   bool isSafeToFlush = !mIsReflowing &&
    4046         358 :                          !mChangeNestCount;
    4047             : 
    4048         179 :   if (isSafeToFlush) {
    4049             :     // Not safe if we are painting
    4050         179 :     nsViewManager* viewManager = GetViewManager();
    4051         179 :     if (viewManager) {
    4052         179 :       bool isPainting = false;
    4053         179 :       viewManager->IsPainting(isPainting);
    4054         179 :       if (isPainting) {
    4055           0 :         isSafeToFlush = false;
    4056             :       }
    4057             :     }
    4058             :   }
    4059             : 
    4060         179 :   return isSafeToFlush;
    4061             : }
    4062             : 
    4063             : 
    4064             : void
    4065          67 : PresShell::DoFlushPendingNotifications(FlushType aType)
    4066             : {
    4067             :   // by default, flush animations if aType >= FlushType::Style
    4068          67 :   mozilla::ChangesToFlush flush(aType, aType >= FlushType::Style);
    4069          67 :   FlushPendingNotifications(flush);
    4070          67 : }
    4071             : 
    4072             : void
    4073         122 : PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush aFlush)
    4074             : {
    4075             :   // Per our API contract, hold a strong ref to ourselves until we return.
    4076         244 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip = this;
    4077             : 
    4078             :   /**
    4079             :    * VERY IMPORTANT: If you add some sort of new flushing to this
    4080             :    * method, make sure to add the relevant SetNeedLayoutFlush or
    4081             :    * SetNeedStyleFlush calls on the shell.
    4082             :    */
    4083         122 :   FlushType flushType = aFlush.mFlushType;
    4084             : 
    4085         122 :   MOZ_ASSERT(NeedFlush(flushType), "Why did we get called?");
    4086             : 
    4087             :   static const EnumeratedArray<FlushType,
    4088             :                                FlushType::Count,
    4089             :                                const char*> flushTypeNames = {
    4090             :     "",
    4091             :     "Content",
    4092             :     "ContentAndNotify",
    4093             :     // As far as the profiler is concerned, EnsurePresShellInitAndFrames and
    4094             :     // Frames are the same
    4095             :     "Style",
    4096             :     "Style",
    4097             :     "InterruptibleLayout",
    4098             :     "Layout",
    4099             :     "Display"
    4100         122 :   };
    4101             : 
    4102         244 :   AUTO_PROFILER_LABEL_DYNAMIC("PresShell::DoFlushPendingNotifications",
    4103             :                               GRAPHICS, flushTypeNames[flushType]);
    4104             : 
    4105             : #ifdef ACCESSIBILITY
    4106             : #ifdef DEBUG
    4107         122 :   nsAccessibilityService* accService = GetAccService();
    4108         122 :   if (accService) {
    4109           0 :     NS_ASSERTION(!accService->IsProcessingRefreshDriverNotification(),
    4110             :                  "Flush during accessible tree update!");
    4111             :   }
    4112             : #endif
    4113             : #endif
    4114             : 
    4115         122 :   NS_ASSERTION(flushType >= FlushType::Frames, "Why did we get called?");
    4116             : 
    4117         122 :   mNeedStyleFlush = false;
    4118         122 :   mNeedThrottledAnimationFlush =
    4119         122 :     mNeedThrottledAnimationFlush && !aFlush.mFlushAnimations;
    4120         122 :   mNeedLayoutFlush =
    4121         122 :     mNeedLayoutFlush && (flushType < FlushType::InterruptibleLayout);
    4122             : 
    4123         122 :   bool isSafeToFlush = IsSafeToFlush();
    4124             : 
    4125             :   // If layout could possibly trigger scripts, then it's only safe to flush if
    4126             :   // it's safe to run script.
    4127             :   bool hasHadScriptObject;
    4128         122 :   if (mDocument->GetScriptHandlingObject(hasHadScriptObject) ||
    4129             :       hasHadScriptObject) {
    4130          83 :     isSafeToFlush = isSafeToFlush && nsContentUtils::IsSafeToRunScript();
    4131             :   }
    4132             : 
    4133         122 :   NS_ASSERTION(!isSafeToFlush || mViewManager, "Must have view manager");
    4134             :   // Make sure the view manager stays alive.
    4135         244 :   RefPtr<nsViewManager> viewManager = mViewManager;
    4136         122 :   bool didStyleFlush = false;
    4137         122 :   bool didLayoutFlush = false;
    4138         122 :   if (isSafeToFlush && viewManager) {
    4139             :     // Record that we are in a flush, so that our optimization in
    4140             :     // nsDocument::FlushPendingNotifications doesn't skip any re-entrant
    4141             :     // calls to us.  Otherwise, we might miss some needed flushes, since
    4142             :     // we clear mNeedStyleFlush / mNeedLayoutFlush here at the top of
    4143             :     // the function but we might not have done the work yet.
    4144         244 :     AutoRestore<bool> guard(mInFlush);
    4145         122 :     mInFlush = true;
    4146             : 
    4147         122 :     if (mResizeEvent.IsPending()) {
    4148          20 :       FireResizeEvent();
    4149          20 :       if (mIsDestroying) {
    4150           0 :         return;
    4151             :       }
    4152             :     }
    4153             : 
    4154             :     // We need to make sure external resource documents are flushed too (for
    4155             :     // example, svg filters that reference a filter in an external document
    4156             :     // need the frames in the external document to be constructed for the
    4157             :     // filter to work). We only need external resources to be flushed when the
    4158             :     // main document is flushing >= FlushType::Frames, so we flush external
    4159             :     // resources here instead of nsDocument::FlushPendingNotifications.
    4160         122 :     mDocument->FlushExternalResources(flushType);
    4161             : 
    4162             :     // Force flushing of any pending content notifications that might have
    4163             :     // queued up while our event was pending.  That will ensure that we don't
    4164             :     // construct frames for content right now that's still waiting to be
    4165             :     // notified on,
    4166         122 :     mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
    4167             : 
    4168             :     // Process pending restyles, since any flush of the presshell wants
    4169             :     // up-to-date style data.
    4170         122 :     if (!mIsDestroying) {
    4171         122 :       viewManager->FlushDelayedResize(false);
    4172         122 :       mPresContext->FlushPendingMediaFeatureValuesChanged();
    4173             : 
    4174             :       // Flush any pending update of the user font set, since that could
    4175             :       // cause style changes (for updating ex/ch units, and to cause a
    4176             :       // reflow).
    4177         122 :       mDocument->FlushUserFontSet();
    4178             : 
    4179         122 :       mPresContext->FlushCounterStyles();
    4180             : 
    4181             :       // Flush any requested SMIL samples.
    4182         122 :       if (mDocument->HasAnimationController()) {
    4183         106 :         mDocument->GetAnimationController()->FlushResampleRequests();
    4184             :       }
    4185             : 
    4186         122 :       if (aFlush.mFlushAnimations && mPresContext->EffectCompositor()) {
    4187          67 :         mPresContext->EffectCompositor()->PostRestyleForThrottledAnimations();
    4188             :       }
    4189             : 
    4190             :       // The FlushResampleRequests() above flushed style changes.
    4191         122 :       if (!mIsDestroying) {
    4192         244 :         nsAutoScriptBlocker scriptBlocker;
    4193         122 :         mPresContext->RestyleManager()->ProcessPendingRestyles();
    4194             :       }
    4195             :     }
    4196             : 
    4197             :     // Process whatever XBL constructors those restyles queued up.  This
    4198             :     // ensures that onload doesn't fire too early and that we won't do extra
    4199             :     // reflows after those constructors run.
    4200         122 :     if (!mIsDestroying) {
    4201         122 :       mDocument->BindingManager()->ProcessAttachedQueue();
    4202             :     }
    4203             : 
    4204             :     // Now those constructors or events might have posted restyle
    4205             :     // events.  At the same time, we still need up-to-date style data.
    4206             :     // In particular, reflow depends on style being completely up to
    4207             :     // date.  If it's not, then style context reparenting, which can
    4208             :     // happen during reflow, might suddenly pick up the new rules and
    4209             :     // we'll end up with frames whose style doesn't match the frame
    4210             :     // type.
    4211         122 :     if (!mIsDestroying) {
    4212         244 :       nsAutoScriptBlocker scriptBlocker;
    4213         122 :       mPresContext->RestyleManager()->ProcessPendingRestyles();
    4214             :     }
    4215             : 
    4216         122 :     didStyleFlush = true;
    4217             : 
    4218             : 
    4219             :     // There might be more pending constructors now, but we're not going to
    4220             :     // worry about them.  They can't be triggered during reflow, so we should
    4221             :     // be good.
    4222             : 
    4223         244 :     if (flushType >= (mSuppressInterruptibleReflows
    4224         122 :                         ? FlushType::Layout
    4225         105 :                         : FlushType::InterruptibleLayout) &&
    4226         105 :         !mIsDestroying) {
    4227         105 :       didLayoutFlush = true;
    4228         105 :       mFrameConstructor->RecalcQuotesAndCounters();
    4229         105 :       viewManager->FlushDelayedResize(true);
    4230         210 :       if (ProcessReflowCommands(flushType < FlushType::Layout) &&
    4231         105 :           mContentToScrollTo) {
    4232             :         // We didn't get interrupted.  Go ahead and scroll to our content
    4233           1 :         DoScrollContentIntoView();
    4234           1 :         if (mContentToScrollTo) {
    4235           1 :           mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
    4236           1 :           mContentToScrollTo = nullptr;
    4237             :         }
    4238             :       }
    4239             :     }
    4240             : 
    4241         122 :     if (flushType >= FlushType::Layout) {
    4242          56 :       if (!mIsDestroying) {
    4243          56 :         viewManager->UpdateWidgetGeometry();
    4244             :       }
    4245             :     }
    4246             :   }
    4247             : 
    4248         122 :   if (!didStyleFlush && flushType >= FlushType::Style && !mIsDestroying) {
    4249           0 :     SetNeedStyleFlush();
    4250           0 :     if (aFlush.mFlushAnimations) {
    4251           0 :       SetNeedThrottledAnimationFlush();
    4252             :     }
    4253             :   }
    4254             : 
    4255         122 :   if (!didLayoutFlush && flushType >= FlushType::InterruptibleLayout &&
    4256           0 :       !mIsDestroying) {
    4257             :     // We suppressed this flush either due to it not being safe to flush,
    4258             :     // or due to mSuppressInterruptibleReflows.  Either way, the
    4259             :     // mNeedLayoutFlush flag needs to be re-set.
    4260           0 :     SetNeedLayoutFlush();
    4261             :   }
    4262             : }
    4263             : 
    4264             : void
    4265           1 : PresShell::CharacterDataChanged(nsIDocument *aDocument,
    4266             :                                 nsIContent*  aContent,
    4267             :                                 CharacterDataChangeInfo* aInfo)
    4268             : {
    4269           1 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected CharacterDataChanged");
    4270           1 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
    4271             : 
    4272           2 :   nsAutoCauseReflowNotifier crNotifier(this);
    4273             : 
    4274             :   // Call this here so it only happens for real content mutations and
    4275             :   // not cases when the frame constructor calls its own methods to force
    4276             :   // frame reconstruction.
    4277           1 :   nsIContent *container = aContent->GetParent();
    4278             :   uint32_t selectorFlags =
    4279           1 :     container ? (container->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
    4280           1 :   if (selectorFlags != 0 && !aContent->IsRootOfAnonymousSubtree()) {
    4281           0 :     Element* element = container->AsElement();
    4282           0 :     if (aInfo->mAppend && !aContent->GetNextSibling())
    4283           0 :       mPresContext->RestyleManager()->RestyleForAppend(element, aContent);
    4284             :     else
    4285           0 :       mPresContext->RestyleManager()->RestyleForInsertOrChange(element, aContent);
    4286             :   }
    4287             : 
    4288           1 :   mFrameConstructor->CharacterDataChanged(aContent, aInfo);
    4289           1 :   VERIFY_STYLE_TREE;
    4290           1 : }
    4291             : 
    4292             : void
    4293          55 : PresShell::ContentStateChanged(nsIDocument* aDocument,
    4294             :                                nsIContent* aContent,
    4295             :                                EventStates aStateMask)
    4296             : {
    4297          55 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentStateChanged");
    4298          55 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
    4299             : 
    4300          55 :   if (mDidInitialize) {
    4301         102 :     nsAutoCauseReflowNotifier crNotifier(this);
    4302          51 :     mPresContext->RestyleManager()->ContentStateChanged(aContent, aStateMask);
    4303          51 :     VERIFY_STYLE_TREE;
    4304             :   }
    4305          55 : }
    4306             : 
    4307             : void
    4308           4 : PresShell::DocumentStatesChanged(nsIDocument* aDocument,
    4309             :                                  EventStates aStateMask)
    4310             : {
    4311           4 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected DocumentStatesChanged");
    4312           4 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
    4313             : 
    4314           4 :   nsStyleSet* geckoSet = mStyleSet->GetAsGecko();
    4315           4 :   if (!geckoSet) {
    4316             :     // XXXheycam ServoStyleSets don't support document state selectors,
    4317             :     // but these are only used in chrome documents, which we are not
    4318             :     // aiming to support yet.
    4319             :     NS_WARNING("stylo: ServoStyleSets cannot respond to document state "
    4320           0 :                "changes yet (only matters for chrome documents). See bug 1290285.");
    4321             : 
    4322           6 :   } else if (mDidInitialize &&
    4323           2 :              geckoSet->HasDocumentStateDependentStyle(mDocument->GetRootElement(),
    4324             :                                                       aStateMask)) {
    4325           1 :     mPresContext->RestyleManager()->PostRestyleEvent(mDocument->GetRootElement(),
    4326             :                                                      eRestyle_Subtree,
    4327           1 :                                                      nsChangeHint(0));
    4328           1 :     VERIFY_STYLE_TREE;
    4329             :   }
    4330             : 
    4331           4 :   if (aStateMask.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
    4332           4 :     nsIFrame* root = mFrameConstructor->GetRootFrame();
    4333           4 :     if (root) {
    4334           2 :       root->SchedulePaint();
    4335             :     }
    4336             :   }
    4337           4 : }
    4338             : 
    4339             : void
    4340         332 : PresShell::AttributeWillChange(nsIDocument* aDocument,
    4341             :                                Element*     aElement,
    4342             :                                int32_t      aNameSpaceID,
    4343             :                                nsIAtom*     aAttribute,
    4344             :                                int32_t      aModType,
    4345             :                                const nsAttrValue* aNewValue)
    4346             : {
    4347         332 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected AttributeWillChange");
    4348         332 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
    4349             : 
    4350             :   // XXXwaterson it might be more elegant to wait until after the
    4351             :   // initial reflow to begin observing the document. That would
    4352             :   // squelch any other inappropriate notifications as well.
    4353         332 :   if (mDidInitialize) {
    4354         652 :     nsAutoCauseReflowNotifier crNotifier(this);
    4355         326 :     mPresContext->RestyleManager()->AttributeWillChange(aElement, aNameSpaceID,
    4356             :                                                         aAttribute, aModType,
    4357         326 :                                                         aNewValue);
    4358         326 :     VERIFY_STYLE_TREE;
    4359             :   }
    4360         332 : }
    4361             : 
    4362             : void
    4363         328 : PresShell::AttributeChanged(nsIDocument* aDocument,
    4364             :                             Element*     aElement,
    4365             :                             int32_t      aNameSpaceID,
    4366             :                             nsIAtom*     aAttribute,
    4367             :                             int32_t      aModType,
    4368             :                             const nsAttrValue* aOldValue)
    4369             : {
    4370         328 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected AttributeChanged");
    4371         328 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
    4372             : 
    4373             :   // XXXwaterson it might be more elegant to wait until after the
    4374             :   // initial reflow to begin observing the document. That would
    4375             :   // squelch any other inappropriate notifications as well.
    4376         328 :   if (mDidInitialize) {
    4377         644 :     nsAutoCauseReflowNotifier crNotifier(this);
    4378         322 :     mPresContext->RestyleManager()->AttributeChanged(aElement, aNameSpaceID,
    4379             :                                                      aAttribute, aModType,
    4380         322 :                                                      aOldValue);
    4381         322 :     VERIFY_STYLE_TREE;
    4382             :   }
    4383         328 : }
    4384             : 
    4385             : // nsIMutationObserver callbacks have this terrible API where aContainer is
    4386             : // null in the case that the container is the document (since nsIDocument is
    4387             : // not an nsIContent), and callees are supposed to figure this out and use the
    4388             : // document instead. It would be nice to fix that API to just pass a single
    4389             : // nsINode* parameter in place of the nsIDocument*, nsIContent* pair, but
    4390             : // there are quite a lot of consumers. So we fix things up locally with this
    4391             : // routine for now.
    4392             : static inline nsINode*
    4393          56 : RealContainer(nsIDocument* aDocument, nsIContent* aContainer, nsIContent* aContent)
    4394             : {
    4395          56 :   MOZ_ASSERT(aDocument);
    4396          56 :   MOZ_ASSERT(!aContainer || aContainer->OwnerDoc() == aDocument);
    4397          56 :   MOZ_ASSERT(aContent->OwnerDoc() == aDocument);
    4398          56 :   MOZ_ASSERT(aContainer || aContent->GetParentNode() == aDocument);
    4399          56 :   if (!aContainer) {
    4400          26 :     return aDocument;
    4401             :   }
    4402          30 :   return aContainer;
    4403             : }
    4404             : 
    4405             : void
    4406         102 : PresShell::ContentAppended(nsIDocument *aDocument,
    4407             :                            nsIContent* aContainer,
    4408             :                            nsIContent* aFirstNewContent,
    4409             :                            int32_t     aNewIndexInContainer)
    4410             : {
    4411         102 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentAppended");
    4412         102 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
    4413             : 
    4414             :   // We never call ContentAppended with a document as the container, so we can
    4415             :   // assert that we have an nsIContent container.
    4416         102 :   MOZ_ASSERT(aContainer);
    4417         102 :   MOZ_ASSERT(aContainer->IsElement() ||
    4418             :              aContainer->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT));
    4419         102 :   if (!mDidInitialize) {
    4420          46 :     return;
    4421             :   }
    4422             : 
    4423         112 :   nsAutoCauseReflowNotifier crNotifier(this);
    4424             : 
    4425             :   // Call this here so it only happens for real content mutations and
    4426             :   // not cases when the frame constructor calls its own methods to force
    4427             :   // frame reconstruction.
    4428          56 :   mPresContext->RestyleManager()->ContentAppended(aContainer, aFirstNewContent);
    4429             : 
    4430          56 :   mFrameConstructor->ContentAppended(aContainer, aFirstNewContent, true);
    4431             : 
    4432          56 :   VERIFY_STYLE_TREE;
    4433             : }
    4434             : 
    4435             : void
    4436          45 : PresShell::ContentInserted(nsIDocument* aDocument,
    4437             :                            nsIContent*  aMaybeContainer,
    4438             :                            nsIContent*  aChild,
    4439             :                            int32_t      aIndexInContainer)
    4440             : {
    4441          45 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentInserted");
    4442          45 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
    4443          45 :   nsINode* container = RealContainer(aDocument, aMaybeContainer, aChild);
    4444             : 
    4445          45 :   if (!mDidInitialize) {
    4446          26 :     return;
    4447             :   }
    4448             : 
    4449          38 :   nsAutoCauseReflowNotifier crNotifier(this);
    4450             : 
    4451             :   // Call this here so it only happens for real content mutations and
    4452             :   // not cases when the frame constructor calls its own methods to force
    4453             :   // frame reconstruction.
    4454          19 :   mPresContext->RestyleManager()->ContentInserted(container, aChild);
    4455             : 
    4456          19 :   mFrameConstructor->ContentInserted(aMaybeContainer, aChild, nullptr, true);
    4457             : 
    4458          19 :   if (aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
    4459           0 :     MOZ_ASSERT(container == aDocument);
    4460           0 :     NotifyFontSizeInflationEnabledIsDirty();
    4461             :   }
    4462             : 
    4463          19 :   VERIFY_STYLE_TREE;
    4464             : }
    4465             : 
    4466             : void
    4467          11 : PresShell::ContentRemoved(nsIDocument *aDocument,
    4468             :                           nsIContent* aMaybeContainer,
    4469             :                           nsIContent* aChild,
    4470             :                           int32_t     aIndexInContainer,
    4471             :                           nsIContent* aPreviousSibling)
    4472             : {
    4473          11 :   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentRemoved");
    4474          11 :   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
    4475          11 :   nsINode* container = RealContainer(aDocument, aMaybeContainer, aChild);
    4476             : 
    4477             :   // Notify the ESM that the content has been removed, so that
    4478             :   // it can clean up any state related to the content.
    4479             : 
    4480             :   // XXX_jwir3: There is no null check for aDocument necessary, since, even
    4481             :   //            though by nsIMutationObserver, aDocument could be null, the
    4482             :   //            precondition check that mDocument == aDocument ensures that
    4483             :   //            aDocument will not be null (since mDocument can't be null unless
    4484             :   //            we're still intializing).
    4485          11 :   mPresContext->EventStateManager()->ContentRemoved(aDocument, aChild);
    4486             : 
    4487          22 :   nsAutoCauseReflowNotifier crNotifier(this);
    4488             : 
    4489             :   // Call this here so it only happens for real content mutations and
    4490             :   // not cases when the frame constructor calls its own methods to force
    4491             :   // frame reconstruction.
    4492          11 :   nsIContent* oldNextSibling = container->GetChildAt(aIndexInContainer);
    4493             : 
    4494          11 :   mPresContext->RestyleManager()->ContentRemoved(container, aChild, oldNextSibling);
    4495             : 
    4496             :   // After removing aChild from tree we should save information about live ancestor
    4497          11 :   if (mPointerEventTarget) {
    4498           2 :     if (nsContentUtils::ContentIsDescendantOf(mPointerEventTarget, aChild)) {
    4499           0 :       mPointerEventTarget = aMaybeContainer;
    4500             :     }
    4501             :   }
    4502             : 
    4503             :   // We should check that aChild does not contain pointer capturing elements.
    4504             :   // If it does we should release the pointer capture for the elements.
    4505          11 :   for (auto iter = sPointerCaptureList->Iter(); !iter.Done(); iter.Next()) {
    4506           0 :     nsIPresShell::PointerCaptureInfo* data = iter.UserData();
    4507           0 :     if (data && data->mPendingContent &&
    4508           0 :         nsContentUtils::ContentIsDescendantOf(data->mPendingContent, aChild)) {
    4509           0 :       nsIPresShell::ReleasePointerCapturingContent(iter.Key());
    4510             :     }
    4511             :   }
    4512             : 
    4513             :   bool didReconstruct;
    4514          11 :   mFrameConstructor->ContentRemoved(aMaybeContainer, aChild, oldNextSibling,
    4515             :                                     nsCSSFrameConstructor::REMOVE_CONTENT,
    4516          11 :                                     &didReconstruct);
    4517             : 
    4518             : 
    4519          11 :   if (aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
    4520           0 :     MOZ_ASSERT(container == aDocument);
    4521           0 :     NotifyFontSizeInflationEnabledIsDirty();
    4522             :   }
    4523             : 
    4524          11 :   VERIFY_STYLE_TREE;
    4525          11 : }
    4526             : 
    4527             : void
    4528           0 : PresShell::NotifyCounterStylesAreDirty()
    4529             : {
    4530           0 :   nsAutoCauseReflowNotifier reflowNotifier(this);
    4531           0 :   mFrameConstructor->BeginUpdate();
    4532           0 :   mFrameConstructor->NotifyCounterStylesAreDirty();
    4533           0 :   mFrameConstructor->EndUpdate();
    4534           0 : }
    4535             : 
    4536             : void
    4537           0 : PresShell::ReconstructFrames()
    4538             : {
    4539           0 :   NS_PRECONDITION(!mFrameConstructor->GetRootFrame() || mDidInitialize,
    4540             :                   "Must not have root frame before initial reflow");
    4541           0 :   if (!mDidInitialize || mIsDestroying) {
    4542             :     // Nothing to do here
    4543           0 :     return;
    4544             :   }
    4545             : 
    4546           0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
    4547             : 
    4548             :   // Have to make sure that the content notifications are flushed before we
    4549             :   // start messing with the frame model; otherwise we can get content doubling.
    4550           0 :   mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
    4551             : 
    4552           0 :   if (mIsDestroying) {
    4553           0 :     return;
    4554             :   }
    4555             : 
    4556           0 :   nsAutoCauseReflowNotifier crNotifier(this);
    4557           0 :   mFrameConstructor->BeginUpdate();
    4558           0 :   mFrameConstructor->ReconstructDocElementHierarchy();
    4559           0 :   VERIFY_STYLE_TREE;
    4560           0 :   mFrameConstructor->EndUpdate();
    4561             : }
    4562             : 
    4563             : void
    4564          54 : nsIPresShell::RestyleForCSSRuleChanges()
    4565             : {
    4566          54 :   if (mIsDestroying) {
    4567             :     // We don't want to mess with restyles at this point
    4568           0 :     return;
    4569             :   }
    4570             : 
    4571          54 :   mDocument->RebuildUserFontSet();
    4572             : 
    4573          54 :   if (mPresContext) {
    4574          54 :     mPresContext->RebuildCounterStyles();
    4575             :   }
    4576             : 
    4577          54 :   if (!mDidInitialize) {
    4578             :     // Nothing to do here, since we have no frames yet
    4579          31 :     return;
    4580             :   }
    4581             : 
    4582          23 :   mStyleSet->InvalidateStyleForCSSRuleChanges();
    4583             : }
    4584             : 
    4585             : void
    4586          48 : PresShell::RecordStyleSheetChange(StyleSheet* aStyleSheet,
    4587             :                                   StyleSheet::ChangeType aChangeType)
    4588             : {
    4589             :   // too bad we can't check that the update is UPDATE_STYLE
    4590          48 :   NS_ASSERTION(mUpdateCount != 0, "must be in an update");
    4591          48 :   MOZ_ASSERT(aStyleSheet->IsServo() == mStyleSet->IsServo());
    4592             : 
    4593          48 :   mStyleSet->RecordStyleSheetChange(aStyleSheet, aChangeType);
    4594          48 : }
    4595             : 
    4596             : void
    4597          46 : PresShell::StyleSheetAdded(StyleSheet* aStyleSheet,
    4598             :                            bool aDocumentSheet)
    4599             : {
    4600             :   // We only care when enabled sheets are added
    4601          46 :   NS_PRECONDITION(aStyleSheet, "Must have a style sheet!");
    4602             : 
    4603          46 :   if (aStyleSheet->IsApplicable() && aStyleSheet->HasRules()) {
    4604          35 :     RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::Added);
    4605             :   }
    4606          46 : }
    4607             : 
    4608             : void
    4609           0 : PresShell::StyleSheetRemoved(StyleSheet* aStyleSheet,
    4610             :                              bool aDocumentSheet)
    4611             : {
    4612             :   // We only care when enabled sheets are removed
    4613           0 :   NS_PRECONDITION(aStyleSheet, "Must have a style sheet!");
    4614             : 
    4615           0 :   if (aStyleSheet->IsApplicable() && aStyleSheet->HasRules()) {
    4616           0 :     RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::Removed);
    4617             :   }
    4618           0 : }
    4619             : 
    4620             : void
    4621          13 : PresShell::StyleSheetApplicableStateChanged(StyleSheet* aStyleSheet)
    4622             : {
    4623          13 :   if (aStyleSheet->HasRules()) {
    4624             :     RecordStyleSheetChange(
    4625          13 :         aStyleSheet, StyleSheet::ChangeType::ApplicableStateChanged);
    4626             :   }
    4627          13 : }
    4628             : 
    4629             : void
    4630           0 : PresShell::StyleRuleChanged(StyleSheet* aStyleSheet, css::Rule* aStyleRule)
    4631             : {
    4632           0 :   RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::RuleChanged);
    4633           0 : }
    4634             : 
    4635             : void
    4636           0 : PresShell::StyleRuleAdded(StyleSheet* aStyleSheet, css::Rule* aStyleRule)
    4637             : {
    4638           0 :   RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::RuleAdded);
    4639           0 : }
    4640             : 
    4641             : void
    4642           0 : PresShell::StyleRuleRemoved(StyleSheet* aStyleSheet, css::Rule* aStyleRule)
    4643             : {
    4644           0 :   RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::RuleRemoved);
    4645           0 : }
    4646             : 
    4647             : nsresult
    4648          18 : PresShell::RenderDocument(const nsRect& aRect, uint32_t aFlags,
    4649             :                           nscolor aBackgroundColor,
    4650             :                           gfxContext* aThebesContext)
    4651             : {
    4652          18 :   NS_ENSURE_TRUE(!(aFlags & RENDER_IS_UNTRUSTED), NS_ERROR_NOT_IMPLEMENTED);
    4653             : 
    4654          18 :   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
    4655          18 :   if (rootPresContext) {
    4656          18 :     rootPresContext->FlushWillPaintObservers();
    4657          18 :     if (mIsDestroying)
    4658           0 :       return NS_OK;
    4659             :   }
    4660             : 
    4661          36 :   nsAutoScriptBlocker blockScripts;
    4662             : 
    4663             :   // Set up the rectangle as the path in aThebesContext
    4664             :   gfxRect r(0, 0,
    4665          18 :             nsPresContext::AppUnitsToFloatCSSPixels(aRect.width),
    4666          36 :             nsPresContext::AppUnitsToFloatCSSPixels(aRect.height));
    4667          18 :   aThebesContext->NewPath();
    4668             : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
    4669             :   aThebesContext->Rectangle(r, true);
    4670             : #else
    4671          18 :   aThebesContext->Rectangle(r);
    4672             : #endif
    4673             : 
    4674          18 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    4675          18 :   if (!rootFrame) {
    4676             :     // Nothing to paint, just fill the rect
    4677           0 :     aThebesContext->SetColor(Color::FromABGR(aBackgroundColor));
    4678           0 :     aThebesContext->Fill();
    4679           0 :     return NS_OK;
    4680             :   }
    4681             : 
    4682          36 :   gfxContextAutoSaveRestore save(aThebesContext);
    4683             : 
    4684          18 :   MOZ_ASSERT(aThebesContext->CurrentOp() == CompositionOp::OP_OVER);
    4685             : 
    4686          18 :   aThebesContext->Clip();
    4687             : 
    4688          18 :   nsDeviceContext* devCtx = mPresContext->DeviceContext();
    4689             : 
    4690          18 :   gfxPoint offset(-nsPresContext::AppUnitsToFloatCSSPixels(aRect.x),
    4691          36 :                   -nsPresContext::AppUnitsToFloatCSSPixels(aRect.y));
    4692          18 :   gfxFloat scale = gfxFloat(devCtx->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel();
    4693             : 
    4694             :   // Since canvas APIs use floats to set up their matrices, we may have some
    4695             :   // slight rounding errors here.  We use NudgeToIntegers() here to adjust
    4696             :   // matrix components that are integers up to the accuracy of floats to be
    4697             :   // those integers.
    4698          36 :   gfxMatrix newTM = aThebesContext->CurrentMatrix().PreTranslate(offset).
    4699          18 :                                                     PreScale(scale, scale).
    4700          18 :                                                     NudgeToIntegers();
    4701          18 :   aThebesContext->SetMatrix(newTM);
    4702             : 
    4703          36 :   AutoSaveRestoreRenderingState _(this);
    4704             : 
    4705          18 :   bool wouldFlushRetainedLayers = false;
    4706          18 :   PaintFrameFlags flags = PaintFrameFlags::PAINT_IGNORE_SUPPRESSION;
    4707          18 :   if (aThebesContext->CurrentMatrix().HasNonIntegerTranslation()) {
    4708           3 :     flags |= PaintFrameFlags::PAINT_IN_TRANSFORM;
    4709             :   }
    4710          18 :   if (!(aFlags & RENDER_ASYNC_DECODE_IMAGES)) {
    4711           0 :     flags |= PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES;
    4712             :   }
    4713          18 :   if (aFlags & RENDER_USE_WIDGET_LAYERS) {
    4714             :     // We only support using widget layers on display root's with widgets.
    4715           0 :     nsView* view = rootFrame->GetView();
    4716           0 :     if (view && view->GetWidget() &&
    4717           0 :         nsLayoutUtils::GetDisplayRootFrame(rootFrame) == rootFrame) {
    4718           0 :       LayerManager* layerManager = view->GetWidget()->GetLayerManager();
    4719             :       // ClientLayerManagers or WebRenderLayerManagers in content processes
    4720             :       // don't support taking snapshots.
    4721           0 :       if (layerManager &&
    4722           0 :           (!layerManager->AsKnowsCompositor() ||
    4723           0 :            XRE_IsParentProcess())) {
    4724           0 :         flags |= PaintFrameFlags::PAINT_WIDGET_LAYERS;
    4725             :       }
    4726             :     }
    4727             :   }
    4728          18 :   if (!(aFlags & RENDER_CARET)) {
    4729          18 :     wouldFlushRetainedLayers = true;
    4730          18 :     flags |= PaintFrameFlags::PAINT_HIDE_CARET;
    4731             :   }
    4732          18 :   if (aFlags & RENDER_IGNORE_VIEWPORT_SCROLLING) {
    4733          18 :     wouldFlushRetainedLayers = !IgnoringViewportScrolling();
    4734          18 :     mRenderFlags = ChangeFlag(mRenderFlags, true, STATE_IGNORING_VIEWPORT_SCROLLING);
    4735             :   }
    4736          18 :   if (aFlags & RENDER_DRAWWINDOW_NOT_FLUSHING) {
    4737           0 :     mRenderFlags = ChangeFlag(mRenderFlags, true, STATE_DRAWWINDOW_NOT_FLUSHING);
    4738             :   }
    4739          18 :   if (aFlags & RENDER_DOCUMENT_RELATIVE) {
    4740             :     // XXX be smarter about this ... drawWindow might want a rect
    4741             :     // that's "pretty close" to what our retained layer tree covers.
    4742             :     // In that case, it wouldn't disturb normal rendering too much,
    4743             :     // and we should allow it.
    4744           0 :     wouldFlushRetainedLayers = true;
    4745           0 :     flags |= PaintFrameFlags::PAINT_DOCUMENT_RELATIVE;
    4746             :   }
    4747             : 
    4748             :   // Don't let drawWindow blow away our retained layer tree
    4749          18 :   if ((flags & PaintFrameFlags::PAINT_WIDGET_LAYERS) && wouldFlushRetainedLayers) {
    4750           0 :     flags &= ~PaintFrameFlags::PAINT_WIDGET_LAYERS;
    4751             :   }
    4752             : 
    4753          36 :   nsLayoutUtils::PaintFrame(aThebesContext, rootFrame, nsRegion(aRect),
    4754             :                             aBackgroundColor,
    4755             :                             nsDisplayListBuilderMode::PAINTING,
    4756          36 :                             flags);
    4757             : 
    4758          18 :   return NS_OK;
    4759             : }
    4760             : 
    4761             : /*
    4762             :  * Clip the display list aList to a range. Returns the clipped
    4763             :  * rectangle surrounding the range.
    4764             :  */
    4765             : nsRect
    4766           0 : PresShell::ClipListToRange(nsDisplayListBuilder *aBuilder,
    4767             :                            nsDisplayList* aList,
    4768             :                            nsRange* aRange)
    4769             : {
    4770             :   // iterate though the display items and add up the bounding boxes of each.
    4771             :   // This will allow the total area of the frames within the range to be
    4772             :   // determined. To do this, remove an item from the bottom of the list, check
    4773             :   // whether it should be part of the range, and if so, append it to the top
    4774             :   // of the temporary list tmpList. If the item is a text frame at the end of
    4775             :   // the selection range, clip it to the portion of the text frame that is
    4776             :   // part of the selection. Then, append the wrapper to the top of the list.
    4777             :   // Otherwise, just delete the item and don't append it.
    4778           0 :   nsRect surfaceRect;
    4779           0 :   nsDisplayList tmpList;
    4780             : 
    4781             :   nsDisplayItem* i;
    4782           0 :   while ((i = aList->RemoveBottom())) {
    4783             :     // itemToInsert indiciates the item that should be inserted into the
    4784             :     // temporary list. If null, no item should be inserted.
    4785           0 :     nsDisplayItem* itemToInsert = nullptr;
    4786           0 :     nsIFrame* frame = i->Frame();
    4787           0 :     nsIContent* content = frame->GetContent();
    4788           0 :     if (content) {
    4789           0 :       bool atStart = (content == aRange->GetStartContainer());
    4790           0 :       bool atEnd = (content == aRange->GetEndContainer());
    4791           0 :       if ((atStart || atEnd) && frame->IsTextFrame()) {
    4792             :         int32_t frameStartOffset, frameEndOffset;
    4793           0 :         frame->GetOffsets(frameStartOffset, frameEndOffset);
    4794             : 
    4795             :         int32_t hilightStart =
    4796           0 :           atStart ? std::max(aRange->StartOffset(), frameStartOffset) : frameStartOffset;
    4797             :         int32_t hilightEnd =
    4798           0 :           atEnd ? std::min(aRange->EndOffset(), frameEndOffset) : frameEndOffset;
    4799           0 :         if (hilightStart < hilightEnd) {
    4800             :           // determine the location of the start and end edges of the range.
    4801           0 :           nsPoint startPoint, endPoint;
    4802           0 :           frame->GetPointFromOffset(hilightStart, &startPoint);
    4803           0 :           frame->GetPointFromOffset(hilightEnd, &endPoint);
    4804             : 
    4805             :           // The clip rectangle is determined by taking the the start and
    4806             :           // end points of the range, offset from the reference frame.
    4807             :           // Because of rtl, the end point may be to the left of (or above,
    4808             :           // in vertical mode) the start point, so x (or y) is set to the
    4809             :           // lower of the values.
    4810           0 :           nsRect textRect(aBuilder->ToReferenceFrame(frame), frame->GetSize());
    4811           0 :           if (frame->GetWritingMode().IsVertical()) {
    4812           0 :             nscoord y = std::min(startPoint.y, endPoint.y);
    4813           0 :             textRect.y += y;
    4814           0 :             textRect.height = std::max(startPoint.y, endPoint.y) - y;
    4815             :           } else {
    4816           0 :             nscoord x = std::min(startPoint.x, endPoint.x);
    4817           0 :             textRect.x += x;
    4818           0 :             textRect.width = std::max(startPoint.x, endPoint.x) - x;
    4819             :           }
    4820           0 :           surfaceRect.UnionRect(surfaceRect, textRect);
    4821             : 
    4822           0 :           DisplayItemClip newClip;
    4823           0 :           newClip.SetTo(textRect);
    4824           0 :           DisplayItemClipChain newClipChain = { newClip, i->GetActiveScrolledRoot(), nullptr };
    4825           0 :           i->IntersectClip(aBuilder, &newClipChain);
    4826           0 :           itemToInsert = i;
    4827             :         }
    4828             :       }
    4829             :       // Don't try to descend into subdocuments.
    4830             :       // If this ever changes we'd need to add handling for subdocuments with
    4831             :       // different zoom levels.
    4832           0 :       else if (content->GetUncomposedDoc() ==
    4833           0 :                  aRange->GetStartContainer()->GetUncomposedDoc()) {
    4834             :         // if the node is within the range, append it to the temporary list
    4835             :         bool before, after;
    4836             :         nsresult rv =
    4837           0 :           nsRange::CompareNodeToRange(content, aRange, &before, &after);
    4838           0 :         if (NS_SUCCEEDED(rv) && !before && !after) {
    4839           0 :           itemToInsert = i;
    4840             :           bool snap;
    4841           0 :           surfaceRect.UnionRect(surfaceRect, i->GetBounds(aBuilder, &snap));
    4842             :         }
    4843             :       }
    4844             :     }
    4845             : 
    4846             :     // insert the item into the list if necessary. If the item has a child
    4847             :     // list, insert that as well
    4848           0 :     nsDisplayList* sublist = i->GetSameCoordinateSystemChildren();
    4849           0 :     if (itemToInsert || sublist) {
    4850           0 :       tmpList.AppendToTop(itemToInsert ? itemToInsert : i);
    4851             :       // if the item is a list, iterate over it as well
    4852           0 :       if (sublist)
    4853             :         surfaceRect.UnionRect(surfaceRect,
    4854           0 :           ClipListToRange(aBuilder, sublist, aRange));
    4855             :     }
    4856             :     else {
    4857             :       // otherwise, just delete the item and don't readd it to the list
    4858           0 :       i->~nsDisplayItem();
    4859             :     }
    4860             :   }
    4861             : 
    4862             :   // now add all the items back onto the original list again
    4863           0 :   aList->AppendToTop(&tmpList);
    4864             : 
    4865           0 :   return surfaceRect;
    4866             : }
    4867             : 
    4868             : #ifdef DEBUG
    4869             : #include <stdio.h>
    4870             : 
    4871             : static bool gDumpRangePaintList = false;
    4872             : #endif
    4873             : 
    4874             : UniquePtr<RangePaintInfo>
    4875           0 : PresShell::CreateRangePaintInfo(nsIDOMRange* aRange,
    4876             :                                 nsRect& aSurfaceRect,
    4877             :                                 bool aForPrimarySelection)
    4878             : {
    4879           0 :   nsRange* range = static_cast<nsRange*>(aRange);
    4880             :   nsIFrame* ancestorFrame;
    4881           0 :   nsIFrame* rootFrame = GetRootFrame();
    4882             : 
    4883             :   // If the start or end of the range is the document, just use the root
    4884             :   // frame, otherwise get the common ancestor of the two endpoints of the
    4885             :   // range.
    4886           0 :   nsINode* startContainer = range->GetStartContainer();
    4887           0 :   nsINode* endContainer = range->GetEndContainer();
    4888           0 :   nsIDocument* doc = startContainer->GetComposedDoc();
    4889           0 :   if (startContainer == doc || endContainer == doc) {
    4890           0 :     ancestorFrame = rootFrame;
    4891             :   } else {
    4892             :     nsINode* ancestor =
    4893           0 :       nsContentUtils::GetCommonAncestor(startContainer, endContainer);
    4894           0 :     NS_ASSERTION(!ancestor || ancestor->IsNodeOfType(nsINode::eCONTENT),
    4895             :                  "common ancestor is not content");
    4896           0 :     if (!ancestor || !ancestor->IsNodeOfType(nsINode::eCONTENT))
    4897           0 :       return nullptr;
    4898             : 
    4899           0 :     nsIContent* ancestorContent = static_cast<nsIContent*>(ancestor);
    4900           0 :     ancestorFrame = ancestorContent->GetPrimaryFrame();
    4901             : 
    4902             :     // XXX deal with ancestorFrame being null due to display:contents
    4903             : 
    4904             :     // use the nearest ancestor frame that includes all continuations as the
    4905             :     // root for building the display list
    4906           0 :     while (ancestorFrame &&
    4907           0 :            nsLayoutUtils::GetNextContinuationOrIBSplitSibling(ancestorFrame))
    4908           0 :       ancestorFrame = ancestorFrame->GetParent();
    4909             :   }
    4910             : 
    4911           0 :   if (!ancestorFrame) {
    4912           0 :     return nullptr;
    4913             :   }
    4914             : 
    4915             :   // get a display list containing the range
    4916           0 :   auto info = MakeUnique<RangePaintInfo>(range, ancestorFrame);
    4917           0 :   info->mBuilder.SetIncludeAllOutOfFlows();
    4918           0 :   if (aForPrimarySelection) {
    4919           0 :     info->mBuilder.SetSelectedFramesOnly();
    4920             :   }
    4921           0 :   info->mBuilder.EnterPresShell(ancestorFrame);
    4922             : 
    4923           0 :   nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
    4924           0 :   nsresult rv = iter->Init(range);
    4925           0 :   if (NS_FAILED(rv)) {
    4926           0 :     return nullptr;
    4927             :   }
    4928             : 
    4929           0 :   auto BuildDisplayListForNode = [&] (nsINode* aNode) {
    4930           0 :     if (MOZ_UNLIKELY(!aNode->IsContent())) {
    4931           0 :       return;
    4932             :     }
    4933           0 :     nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame();
    4934             :     // XXX deal with frame being null due to display:contents
    4935           0 :     for (; frame; frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) {
    4936           0 :       frame->BuildDisplayListForStackingContext(&info->mBuilder,
    4937           0 :                frame->GetVisualOverflowRect(), &info->mList);
    4938             :     }
    4939           0 :   };
    4940           0 :   if (startContainer->NodeType() == nsIDOMNode::TEXT_NODE) {
    4941           0 :     BuildDisplayListForNode(startContainer);
    4942             :   }
    4943           0 :   for (; !iter->IsDone(); iter->Next()) {
    4944           0 :     nsCOMPtr<nsINode> node = iter->GetCurrentNode();
    4945           0 :     BuildDisplayListForNode(node);
    4946             :   }
    4947           0 :   if (endContainer != startContainer &&
    4948           0 :       endContainer->NodeType() == nsIDOMNode::TEXT_NODE) {
    4949           0 :     BuildDisplayListForNode(endContainer);
    4950             :   }
    4951             : 
    4952             : #ifdef DEBUG
    4953           0 :   if (gDumpRangePaintList) {
    4954           0 :     fprintf(stderr, "CreateRangePaintInfo --- before ClipListToRange:\n");
    4955           0 :     nsFrame::PrintDisplayList(&(info->mBuilder), info->mList);
    4956             :   }
    4957             : #endif
    4958             : 
    4959           0 :   nsRect rangeRect = ClipListToRange(&info->mBuilder, &info->mList, range);
    4960             : 
    4961           0 :   info->mBuilder.LeavePresShell(ancestorFrame, &info->mList);
    4962             : 
    4963             : #ifdef DEBUG
    4964           0 :   if (gDumpRangePaintList) {
    4965           0 :     fprintf(stderr, "CreateRangePaintInfo --- after ClipListToRange:\n");
    4966           0 :     nsFrame::PrintDisplayList(&(info->mBuilder), info->mList);
    4967             :   }
    4968             : #endif
    4969             : 
    4970             :   // determine the offset of the reference frame for the display list
    4971             :   // to the root frame. This will allow the coordinates used when painting
    4972             :   // to all be offset from the same point
    4973           0 :   info->mRootOffset = ancestorFrame->GetOffsetTo(rootFrame);
    4974           0 :   rangeRect.MoveBy(info->mRootOffset);
    4975           0 :   aSurfaceRect.UnionRect(aSurfaceRect, rangeRect);
    4976             : 
    4977           0 :   return info;
    4978             : }
    4979             : 
    4980             : already_AddRefed<SourceSurface>
    4981           0 : PresShell::PaintRangePaintInfo(const nsTArray<UniquePtr<RangePaintInfo>>& aItems,
    4982             :                                nsISelection* aSelection,
    4983             :                                nsIntRegion* aRegion,
    4984             :                                nsRect aArea,
    4985             :                                const LayoutDeviceIntPoint aPoint,
    4986             :                                LayoutDeviceIntRect* aScreenRect,
    4987             :                                uint32_t aFlags)
    4988             : {
    4989           0 :   nsPresContext* pc = GetPresContext();
    4990           0 :   if (!pc || aArea.width == 0 || aArea.height == 0)
    4991           0 :     return nullptr;
    4992             : 
    4993             :   // use the rectangle to create the surface
    4994           0 :   nsIntRect pixelArea = aArea.ToOutsidePixels(pc->AppUnitsPerDevPixel());
    4995             : 
    4996             :   // if the image should not be resized, the scale, relative to the original image, must be 1
    4997           0 :   float scale = 1.0;
    4998             :   nsIntRect rootScreenRect =
    4999           0 :     GetRootFrame()->GetScreenRectInAppUnits().ToNearestPixels(
    5000           0 :       pc->AppUnitsPerDevPixel());
    5001             : 
    5002           0 :   nsRect maxSize;
    5003           0 :   pc->DeviceContext()->GetClientRect(maxSize);
    5004             : 
    5005             :   // check if the image should be resized
    5006           0 :   bool resize = aFlags & RENDER_AUTO_SCALE;
    5007             : 
    5008           0 :   if (resize) {
    5009             :     // check if image-resizing-algorithm should be used
    5010           0 :     if (aFlags & RENDER_IS_IMAGE) {
    5011             :       // get max screensize
    5012           0 :       nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width);
    5013           0 :       nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height);
    5014             :       // resize image relative to the screensize
    5015             :       // get best height/width relative to screensize
    5016           0 :       float bestHeight = float(maxHeight)*RELATIVE_SCALEFACTOR;
    5017           0 :       float bestWidth = float(maxWidth)*RELATIVE_SCALEFACTOR;
    5018             :       // get scalefactor to reach bestWidth
    5019           0 :       scale = bestWidth / float(pixelArea.width);
    5020             :       // get the worst height (height when width is perfect)
    5021           0 :       float worstHeight = float(pixelArea.height)*scale;
    5022             :       // get the difference of best and worst height
    5023           0 :       float difference = bestHeight - worstHeight;
    5024             :       // half the difference and add it to worstHeight,
    5025             :       // then get scalefactor to reach this
    5026           0 :       scale = (worstHeight + difference / 2) / float(pixelArea.height);
    5027             :     } else {
    5028             :       // get half of max screensize
    5029           0 :       nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width >> 1);
    5030           0 :       nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height >> 1);
    5031           0 :       if (pixelArea.width > maxWidth || pixelArea.height > maxHeight) {
    5032           0 :         scale = 1.0;
    5033             :         // divide the maximum size by the image size in both directions. Whichever
    5034             :         // direction produces the smallest result determines how much should be
    5035             :         // scaled.
    5036           0 :         if (pixelArea.width > maxWidth)
    5037           0 :           scale = std::min(scale, float(maxWidth) / pixelArea.width);
    5038           0 :         if (pixelArea.height > maxHeight)
    5039           0 :           scale = std::min(scale, float(maxHeight) / pixelArea.height);
    5040             :       }
    5041             :     }
    5042             : 
    5043             : 
    5044           0 :     pixelArea.width = NSToIntFloor(float(pixelArea.width) * scale);
    5045           0 :     pixelArea.height = NSToIntFloor(float(pixelArea.height) * scale);
    5046           0 :     if (!pixelArea.width || !pixelArea.height)
    5047           0 :       return nullptr;
    5048             : 
    5049             :     // adjust the screen position based on the rescaled size
    5050           0 :     nscoord left = rootScreenRect.x + pixelArea.x;
    5051           0 :     nscoord top = rootScreenRect.y + pixelArea.y;
    5052           0 :     aScreenRect->x = NSToIntFloor(aPoint.x - float(aPoint.x - left) * scale);
    5053           0 :     aScreenRect->y = NSToIntFloor(aPoint.y - float(aPoint.y - top) * scale);
    5054             :   }
    5055             :   else {
    5056             :     // move aScreenRect to the position of the surface in screen coordinates
    5057           0 :     aScreenRect->MoveTo(rootScreenRect.x + pixelArea.x, rootScreenRect.y + pixelArea.y);
    5058             :   }
    5059           0 :   aScreenRect->width = pixelArea.width;
    5060           0 :   aScreenRect->height = pixelArea.height;
    5061             : 
    5062             :   RefPtr<DrawTarget> dt =
    5063           0 :    gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
    5064           0 :                                  IntSize(pixelArea.width, pixelArea.height),
    5065           0 :                                  SurfaceFormat::B8G8R8A8);
    5066           0 :   if (!dt || !dt->IsValid()) {
    5067           0 :     return nullptr;
    5068             :   }
    5069             : 
    5070           0 :   RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
    5071           0 :   MOZ_ASSERT(ctx); // already checked the draw target above
    5072             : 
    5073           0 :   if (aRegion) {
    5074           0 :     RefPtr<PathBuilder> builder = dt->CreatePathBuilder(FillRule::FILL_WINDING);
    5075             : 
    5076             :     // Convert aRegion from CSS pixels to dev pixels
    5077             :     nsIntRegion region =
    5078           0 :       aRegion->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel())
    5079           0 :         .ToOutsidePixels(pc->AppUnitsPerDevPixel());
    5080           0 :     for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) {
    5081           0 :       const nsIntRect& rect = iter.Get();
    5082             : 
    5083           0 :       builder->MoveTo(rect.TopLeft());
    5084           0 :       builder->LineTo(rect.TopRight());
    5085           0 :       builder->LineTo(rect.BottomRight());
    5086           0 :       builder->LineTo(rect.BottomLeft());
    5087           0 :       builder->LineTo(rect.TopLeft());
    5088             :     }
    5089             : 
    5090           0 :     RefPtr<Path> path = builder->Finish();
    5091           0 :     ctx->Clip(path);
    5092             :   }
    5093             : 
    5094           0 :   gfxMatrix initialTM = ctx->CurrentMatrix();
    5095             : 
    5096           0 :   if (resize)
    5097           0 :     initialTM.PreScale(scale, scale);
    5098             : 
    5099             :   // translate so that points are relative to the surface area
    5100             :   gfxPoint surfaceOffset =
    5101           0 :     nsLayoutUtils::PointToGfxPoint(-aArea.TopLeft(), pc->AppUnitsPerDevPixel());
    5102           0 :   initialTM.PreTranslate(surfaceOffset);
    5103             : 
    5104             :   // temporarily hide the selection so that text is drawn normally. If a
    5105             :   // selection is being rendered, use that, otherwise use the presshell's
    5106             :   // selection.
    5107           0 :   RefPtr<nsFrameSelection> frameSelection;
    5108           0 :   if (aSelection) {
    5109           0 :     frameSelection = aSelection->AsSelection()->GetFrameSelection();
    5110             :   }
    5111             :   else {
    5112           0 :     frameSelection = FrameSelection();
    5113             :   }
    5114           0 :   int16_t oldDisplaySelection = frameSelection->GetDisplaySelection();
    5115           0 :   frameSelection->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
    5116             : 
    5117             :   // next, paint each range in the selection
    5118           0 :   for (const UniquePtr<RangePaintInfo>& rangeInfo : aItems) {
    5119             :     // the display lists paint relative to the offset from the reference
    5120             :     // frame, so account for that translation too:
    5121             :     gfxPoint rootOffset =
    5122           0 :       nsLayoutUtils::PointToGfxPoint(rangeInfo->mRootOffset,
    5123           0 :                                      pc->AppUnitsPerDevPixel());
    5124           0 :     ctx->SetMatrix(gfxMatrix(initialTM).PreTranslate(rootOffset));
    5125           0 :     aArea.MoveBy(-rangeInfo->mRootOffset.x, -rangeInfo->mRootOffset.y);
    5126           0 :     nsRegion visible(aArea);
    5127             :     RefPtr<LayerManager> layerManager =
    5128           0 :         rangeInfo->mList.PaintRoot(&rangeInfo->mBuilder, ctx,
    5129           0 :                                    nsDisplayList::PAINT_DEFAULT);
    5130           0 :     aArea.MoveBy(rangeInfo->mRootOffset.x, rangeInfo->mRootOffset.y);
    5131             :   }
    5132             : 
    5133             :   // restore the old selection display state
    5134           0 :   frameSelection->SetDisplaySelection(oldDisplaySelection);
    5135             : 
    5136           0 :   return dt->Snapshot();
    5137             : }
    5138             : 
    5139             : already_AddRefed<SourceSurface>
    5140           0 : PresShell::RenderNode(nsIDOMNode* aNode,
    5141             :                       nsIntRegion* aRegion,
    5142             :                       const LayoutDeviceIntPoint aPoint,
    5143             :                       LayoutDeviceIntRect* aScreenRect,
    5144             :                       uint32_t aFlags)
    5145             : {
    5146             :   // area will hold the size of the surface needed to draw the node, measured
    5147             :   // from the root frame.
    5148           0 :   nsRect area;
    5149           0 :   nsTArray<UniquePtr<RangePaintInfo>> rangeItems;
    5150             : 
    5151             :   // nothing to draw if the node isn't in a document
    5152           0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
    5153           0 :   if (!node->IsInUncomposedDoc())
    5154           0 :     return nullptr;
    5155             : 
    5156           0 :   RefPtr<nsRange> range = new nsRange(node);
    5157           0 :   if (NS_FAILED(range->SelectNode(aNode)))
    5158           0 :     return nullptr;
    5159             : 
    5160           0 :   UniquePtr<RangePaintInfo> info = CreateRangePaintInfo(range, area, false);
    5161           0 :   if (info && !rangeItems.AppendElement(Move(info))) {
    5162           0 :     return nullptr;
    5163             :   }
    5164             : 
    5165           0 :   if (aRegion) {
    5166             :     // combine the area with the supplied region
    5167           0 :     nsIntRect rrectPixels = aRegion->GetBounds();
    5168             : 
    5169           0 :     nsRect rrect = ToAppUnits(rrectPixels, nsPresContext::AppUnitsPerCSSPixel());
    5170           0 :     area.IntersectRect(area, rrect);
    5171             : 
    5172           0 :     nsPresContext* pc = GetPresContext();
    5173           0 :     if (!pc)
    5174           0 :       return nullptr;
    5175             : 
    5176             :     // move the region so that it is offset from the topleft corner of the surface
    5177           0 :     aRegion->MoveBy(-nsPresContext::AppUnitsToIntCSSPixels(area.x),
    5178           0 :                     -nsPresContext::AppUnitsToIntCSSPixels(area.y));
    5179             :   }
    5180             : 
    5181             :   return PaintRangePaintInfo(rangeItems, nullptr, aRegion, area, aPoint,
    5182           0 :                              aScreenRect, aFlags);
    5183             : }
    5184             : 
    5185             : already_AddRefed<SourceSurface>
    5186           0 : PresShell::RenderSelection(nsISelection* aSelection,
    5187             :                            const LayoutDeviceIntPoint aPoint,
    5188             :                            LayoutDeviceIntRect* aScreenRect,
    5189             :                            uint32_t aFlags)
    5190             : {
    5191             :   // area will hold the size of the surface needed to draw the selection,
    5192             :   // measured from the root frame.
    5193           0 :   nsRect area;
    5194           0 :   nsTArray<UniquePtr<RangePaintInfo>> rangeItems;
    5195             : 
    5196             :   // iterate over each range and collect them into the rangeItems array.
    5197             :   // This is done so that the size of selection can be determined so as
    5198             :   // to allocate a surface area
    5199             :   int32_t numRanges;
    5200           0 :   aSelection->GetRangeCount(&numRanges);
    5201           0 :   NS_ASSERTION(numRanges > 0, "RenderSelection called with no selection");
    5202             : 
    5203           0 :   for (int32_t r = 0; r < numRanges; r++)
    5204             :   {
    5205           0 :     nsCOMPtr<nsIDOMRange> range;
    5206           0 :     aSelection->GetRangeAt(r, getter_AddRefs(range));
    5207             : 
    5208           0 :     UniquePtr<RangePaintInfo> info = CreateRangePaintInfo(range, area, true);
    5209           0 :     if (info && !rangeItems.AppendElement(Move(info))) {
    5210           0 :       return nullptr;
    5211             :     }
    5212             :   }
    5213             : 
    5214             :   return PaintRangePaintInfo(rangeItems, aSelection, nullptr, area, aPoint,
    5215           0 :                              aScreenRect, aFlags);
    5216             : }
    5217             : 
    5218             : void
    5219           0 : PresShell::AddPrintPreviewBackgroundItem(nsDisplayListBuilder& aBuilder,
    5220             :                                          nsDisplayList&        aList,
    5221             :                                          nsIFrame*             aFrame,
    5222             :                                          const nsRect&         aBounds)
    5223             : {
    5224             :   aList.AppendNewToBottom(new (&aBuilder)
    5225           0 :     nsDisplaySolidColor(&aBuilder, aFrame, aBounds, NS_RGB(115, 115, 115)));
    5226           0 : }
    5227             : 
    5228             : static bool
    5229           2 : AddCanvasBackgroundColor(const nsDisplayList& aList, nsIFrame* aCanvasFrame,
    5230             :                          nscolor aColor, bool aCSSBackgroundColor)
    5231             : {
    5232           6 :   for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
    5233          10 :     if (i->Frame() == aCanvasFrame &&
    5234           4 :         i->GetType() == nsDisplayItem::TYPE_CANVAS_BACKGROUND_COLOR) {
    5235           2 :       nsDisplayCanvasBackgroundColor* bg = static_cast<nsDisplayCanvasBackgroundColor*>(i);
    5236           2 :       bg->SetExtraBackgroundColor(aColor);
    5237           2 :       return true;
    5238             :     }
    5239           4 :     nsDisplayList* sublist = i->GetSameCoordinateSystemChildren();
    5240           4 :     if (sublist &&
    5241           4 :         !(i->GetType() == nsDisplayItem::TYPE_BLEND_CONTAINER && !aCSSBackgroundColor) &&
    5242           0 :         AddCanvasBackgroundColor(*sublist, aCanvasFrame, aColor, aCSSBackgroundColor))
    5243           0 :       return true;
    5244             :   }
    5245           0 :   return false;
    5246             : }
    5247             : 
    5248             : void
    5249          44 : PresShell::AddCanvasBackgroundColorItem(nsDisplayListBuilder& aBuilder,
    5250             :                                         nsDisplayList&        aList,
    5251             :                                         nsIFrame*             aFrame,
    5252             :                                         const nsRect&         aBounds,
    5253             :                                         nscolor               aBackstopColor,
    5254             :                                         uint32_t              aFlags)
    5255             : {
    5256          44 :   if (aBounds.IsEmpty()) {
    5257           0 :     return;
    5258             :   }
    5259             :   // We don't want to add an item for the canvas background color if the frame
    5260             :   // (sub)tree we are painting doesn't include any canvas frames. There isn't
    5261             :   // an easy way to check this directly, but if we check if the root of the
    5262             :   // (sub)tree we are painting is a canvas frame that should cover us in all
    5263             :   // cases (it will usually be a viewport frame when we have a canvas frame in
    5264             :   // the (sub)tree).
    5265          88 :   if (!(aFlags & nsIPresShell::FORCE_DRAW) &&
    5266          44 :       !nsCSSRendering::IsCanvasFrame(aFrame)) {
    5267           0 :     return;
    5268             :   }
    5269             : 
    5270          44 :   nscolor bgcolor = NS_ComposeColors(aBackstopColor, mCanvasBackgroundColor);
    5271          44 :   if (NS_GET_A(bgcolor) == 0)
    5272          18 :     return;
    5273             : 
    5274             :   // To make layers work better, we want to avoid having a big non-scrolled
    5275             :   // color background behind a scrolled transparent background. Instead,
    5276             :   // we'll try to move the color background into the scrolled content
    5277             :   // by making nsDisplayCanvasBackground paint it.
    5278             :   // If we're only adding an unscrolled item, then pretend that we've
    5279             :   // already done it.
    5280          26 :   bool addedScrollingBackgroundColor = (aFlags & APPEND_UNSCROLLED_ONLY);
    5281          26 :   if (!aFrame->GetParent() && !addedScrollingBackgroundColor) {
    5282             :     nsIScrollableFrame* sf =
    5283          26 :       aFrame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
    5284          26 :     if (sf) {
    5285           2 :       nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame());
    5286           2 :       if (canvasFrame && canvasFrame->IsVisibleForPainting(&aBuilder)) {
    5287             :         addedScrollingBackgroundColor =
    5288           2 :           AddCanvasBackgroundColor(aList, canvasFrame, bgcolor, mHasCSSBackgroundColor);
    5289             :       }
    5290             :     }
    5291             :   }
    5292             : 
    5293             :   // With async scrolling, we'd like to have two instances of the background
    5294             :   // color: one that scrolls with the content (for the reasons stated above),
    5295             :   // and one underneath which does not scroll with the content, but which can
    5296             :   // be shown during checkerboarding and overscroll.
    5297             :   // We can only do that if the color is opaque.
    5298          52 :   bool forceUnscrolledItem = nsLayoutUtils::UsesAsyncScrolling(aFrame) &&
    5299          52 :                              NS_GET_A(bgcolor) == 255;
    5300          26 :   if ((aFlags & ADD_FOR_SUBDOC) && gfxPrefs::LayoutUseContainersForRootFrames()) {
    5301             :     // If we're using ContainerLayers for a subdoc, then any items we add here will
    5302             :     // still be scrolled (since we're inside the container at this point), so don't
    5303             :     // bother and we will do it manually later.
    5304           0 :     forceUnscrolledItem = false;
    5305             :   }
    5306             : 
    5307          26 :   if (!addedScrollingBackgroundColor || forceUnscrolledItem) {
    5308             :     aList.AppendNewToBottom(
    5309          26 :       new (&aBuilder) nsDisplaySolidColor(&aBuilder, aFrame, aBounds, bgcolor));
    5310             :   }
    5311             : }
    5312             : 
    5313           2 : static bool IsTransparentContainerElement(nsPresContext* aPresContext)
    5314             : {
    5315           4 :   nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
    5316           2 :   if (!docShell) {
    5317           0 :     return false;
    5318             :   }
    5319             : 
    5320           4 :   nsCOMPtr<nsPIDOMWindowOuter> pwin = docShell->GetWindow();
    5321           2 :   if (!pwin)
    5322           0 :     return false;
    5323           4 :   nsCOMPtr<Element> containerElement = pwin->GetFrameElementInternal();
    5324             : 
    5325           2 :   TabChild* tab = TabChild::GetFrom(docShell);
    5326           2 :   if (tab) {
    5327             :     // Check if presShell is the top PresShell. Only the top can
    5328             :     // influence the canvas background color.
    5329           4 :     nsCOMPtr<nsIPresShell> presShell = aPresContext->GetPresShell();
    5330           4 :     nsCOMPtr<nsIPresShell> topPresShell = tab->GetPresShell();
    5331           2 :     if (presShell != topPresShell) {
    5332           0 :       tab = nullptr;
    5333             :     }
    5334             :   }
    5335             : 
    5336           0 :   return (containerElement &&
    5337           2 :           containerElement->HasAttr(kNameSpaceID_None, nsGkAtoms::transparent))
    5338           4 :     || (tab && tab->IsTransparent());
    5339             : }
    5340             : 
    5341          26 : nscolor PresShell::GetDefaultBackgroundColorToDraw()
    5342             : {
    5343          26 :   if (!mPresContext || !mPresContext->GetBackgroundColorDraw()) {
    5344           0 :     return NS_RGB(255,255,255);
    5345             :   }
    5346          26 :   return mPresContext->DefaultBackgroundColor();
    5347             : }
    5348             : 
    5349          53 : void PresShell::UpdateCanvasBackground()
    5350             : {
    5351             :   // If we have a frame tree and it has style information that
    5352             :   // specifies the background color of the canvas, update our local
    5353             :   // cache of that color.
    5354          53 :   nsIFrame* rootStyleFrame = FrameConstructor()->GetRootElementStyleFrame();
    5355          53 :   if (rootStyleFrame) {
    5356             :     nsStyleContext* bgStyle =
    5357          53 :       nsCSSRendering::FindRootFrameBackground(rootStyleFrame);
    5358             :     // XXX We should really be passing the canvasframe, not the root element
    5359             :     // style frame but we don't have access to the canvasframe here. It isn't
    5360             :     // a problem because only a few frames can return something other than true
    5361             :     // and none of them would be a canvas frame or root element style frame.
    5362             :     bool drawBackgroundImage;
    5363             :     bool drawBackgroundColor;
    5364          53 :     mCanvasBackgroundColor =
    5365          53 :       nsCSSRendering::DetermineBackgroundColor(mPresContext, bgStyle,
    5366             :                                                rootStyleFrame,
    5367             :                                                drawBackgroundImage,
    5368             :                                                drawBackgroundColor);
    5369          53 :     mHasCSSBackgroundColor = drawBackgroundColor;
    5370          55 :     if (mPresContext->IsRootContentDocument() &&
    5371           2 :         !IsTransparentContainerElement(mPresContext)) {
    5372           2 :       mCanvasBackgroundColor =
    5373           2 :         NS_ComposeColors(GetDefaultBackgroundColorToDraw(), mCanvasBackgroundColor);
    5374             :     }
    5375             :   }
    5376             : 
    5377             :   // If the root element of the document (ie html) has style 'display: none'
    5378             :   // then the document's background color does not get drawn; cache the
    5379             :   // color we actually draw.
    5380          53 :   if (!FrameConstructor()->GetRootElementFrame()) {
    5381           0 :     mCanvasBackgroundColor = GetDefaultBackgroundColorToDraw();
    5382             :   }
    5383          53 : }
    5384             : 
    5385          28 : nscolor PresShell::ComputeBackstopColor(nsView* aDisplayRoot)
    5386             : {
    5387          28 :   nsIWidget* widget = aDisplayRoot->GetWidget();
    5388          52 :   if (widget && (widget->GetTransparencyMode() != eTransparencyOpaque ||
    5389          24 :                  widget->WidgetPaintsBackground())) {
    5390             :     // Within a transparent widget, so the backstop color must be
    5391             :     // totally transparent.
    5392           4 :     return NS_RGBA(0,0,0,0);
    5393             :   }
    5394             :   // Within an opaque widget (or no widget at all), so the backstop
    5395             :   // color must be totally opaque. The user's default background
    5396             :   // as reported by the prescontext is guaranteed to be opaque.
    5397          24 :   return GetDefaultBackgroundColorToDraw();
    5398             : }
    5399             : 
    5400             : struct PaintParams {
    5401             :   nscolor mBackgroundColor;
    5402             : };
    5403             : 
    5404           0 : LayerManager* PresShell::GetLayerManager()
    5405             : {
    5406           0 :   NS_ASSERTION(mViewManager, "Should have view manager");
    5407             : 
    5408           0 :   nsView* rootView = mViewManager->GetRootView();
    5409           0 :   if (rootView) {
    5410           0 :     if (nsIWidget* widget = rootView->GetWidget()) {
    5411           0 :       return widget->GetLayerManager();
    5412             :     }
    5413             :   }
    5414           0 :   return nullptr;
    5415             : }
    5416             : 
    5417           0 : bool PresShell::AsyncPanZoomEnabled()
    5418             : {
    5419           0 :   NS_ASSERTION(mViewManager, "Should have view manager");
    5420           0 :   nsView* rootView = mViewManager->GetRootView();
    5421           0 :   if (rootView) {
    5422           0 :     if (nsIWidget* widget = rootView->GetWidget()) {
    5423           0 :       return widget->AsyncPanZoomEnabled();
    5424             :     }
    5425             :   }
    5426           0 :   return gfxPlatform::AsyncPanZoomEnabled();
    5427             : }
    5428             : 
    5429           0 : void PresShell::SetIgnoreViewportScrolling(bool aIgnore)
    5430             : {
    5431           0 :   if (IgnoringViewportScrolling() == aIgnore) {
    5432           0 :     return;
    5433             :   }
    5434           0 :   RenderingState state(this);
    5435           0 :   state.mRenderFlags = ChangeFlag(state.mRenderFlags, aIgnore,
    5436             :                                   STATE_IGNORING_VIEWPORT_SCROLLING);
    5437           0 :   SetRenderingState(state);
    5438             : }
    5439             : 
    5440           0 : nsresult PresShell::SetResolutionImpl(float aResolution, bool aScaleToResolution)
    5441             : {
    5442           0 :   if (!(aResolution > 0.0)) {
    5443           0 :     return NS_ERROR_ILLEGAL_VALUE;
    5444             :   }
    5445           0 :   if (aResolution == mResolution.valueOr(0.0)) {
    5446           0 :     MOZ_ASSERT(mResolution.isSome());
    5447           0 :     return NS_OK;
    5448             :   }
    5449           0 :   RenderingState state(this);
    5450           0 :   state.mResolution = Some(aResolution);
    5451           0 :   SetRenderingState(state);
    5452           0 :   mScaleToResolution = aScaleToResolution;
    5453           0 :   if (mMobileViewportManager) {
    5454           0 :     mMobileViewportManager->ResolutionUpdated();
    5455             :   }
    5456             : 
    5457           0 :   return NS_OK;
    5458             : }
    5459             : 
    5460          44 : bool PresShell::ScaleToResolution() const
    5461             : {
    5462          44 :   return mScaleToResolution;
    5463             : }
    5464             : 
    5465          90 : float PresShell::GetCumulativeResolution()
    5466             : {
    5467          90 :   float resolution = GetResolution();
    5468          90 :   nsPresContext* parentCtx = GetPresContext()->GetParentPresContext();
    5469          90 :   if (parentCtx) {
    5470           0 :     resolution *= parentCtx->PresShell()->GetCumulativeResolution();
    5471             :   }
    5472          90 :   return resolution;
    5473             : }
    5474             : 
    5475          80 : float PresShell::GetCumulativeNonRootScaleResolution()
    5476             : {
    5477          80 :   float resolution = 1.0;
    5478          80 :   nsIPresShell* currentShell = this;
    5479         240 :   while (currentShell) {
    5480          80 :     nsPresContext* currentCtx = currentShell->GetPresContext();
    5481          80 :     if (currentCtx != currentCtx->GetRootPresContext()) {
    5482           0 :       resolution *=  currentShell->ScaleToResolution() ? currentShell->GetResolution() : 1.0f;
    5483             :     }
    5484          80 :     nsPresContext* parentCtx = currentCtx->GetParentPresContext();
    5485          80 :     if (parentCtx) {
    5486           0 :       currentShell = parentCtx->PresShell();
    5487             :     } else {
    5488          80 :       currentShell = nullptr;
    5489             :     }
    5490             :   }
    5491          80 :   return resolution;
    5492             : }
    5493             : 
    5494           0 : void PresShell::SetRestoreResolution(float aResolution,
    5495             :                                      LayoutDeviceIntSize aDisplaySize)
    5496             : {
    5497           0 :   if (mMobileViewportManager) {
    5498           0 :     mMobileViewportManager->SetRestoreResolution(aResolution, aDisplaySize);
    5499             :   }
    5500           0 : }
    5501             : 
    5502           0 : void PresShell::SetRenderingState(const RenderingState& aState)
    5503             : {
    5504           0 :   if (mRenderFlags != aState.mRenderFlags) {
    5505             :     // Rendering state changed in a way that forces us to flush any
    5506             :     // retained layers we might already have.
    5507           0 :     LayerManager* manager = GetLayerManager();
    5508           0 :     if (manager) {
    5509           0 :       FrameLayerBuilder::InvalidateAllLayers(manager);
    5510             :     }
    5511             :   }
    5512             : 
    5513           0 :   mRenderFlags = aState.mRenderFlags;
    5514           0 :   mResolution = aState.mResolution;
    5515           0 : }
    5516             : 
    5517         136 : void PresShell::SynthesizeMouseMove(bool aFromScroll)
    5518             : {
    5519         136 :   if (!sSynthMouseMove)
    5520           0 :     return;
    5521             : 
    5522         136 :   if (mPaintingSuppressed || !mIsActive || !mPresContext) {
    5523          51 :     return;
    5524             :   }
    5525             : 
    5526          85 :   if (!mPresContext->IsRoot()) {
    5527           0 :     nsIPresShell* rootPresShell = GetRootPresShell();
    5528           0 :     if (rootPresShell) {
    5529           0 :       rootPresShell->SynthesizeMouseMove(aFromScroll);
    5530             :     }
    5531           0 :     return;
    5532             :   }
    5533             : 
    5534          85 :   if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE))
    5535          81 :     return;
    5536             : 
    5537           4 :   if (!mSynthMouseMoveEvent.IsPending()) {
    5538             :     RefPtr<nsSynthMouseMoveEvent> ev =
    5539           2 :         new nsSynthMouseMoveEvent(this, aFromScroll);
    5540             : 
    5541           1 :     if (!GetPresContext()->RefreshDriver()
    5542           1 :                          ->AddRefreshObserver(ev, FlushType::Display)) {
    5543           0 :       NS_WARNING("failed to dispatch nsSynthMouseMoveEvent");
    5544           0 :       return;
    5545             :     }
    5546             : 
    5547           1 :     mSynthMouseMoveEvent = ev;
    5548             :   }
    5549             : }
    5550             : 
    5551             : /**
    5552             :  * Find the first floating view with a widget in a postorder traversal of the
    5553             :  * view tree that contains the point. Thus more deeply nested floating views
    5554             :  * are preferred over their ancestors, and floating views earlier in the
    5555             :  * view hierarchy (i.e., added later) are preferred over their siblings.
    5556             :  * This is adequate for finding the "topmost" floating view under a point,
    5557             :  * given that floating views don't supporting having a specific z-index.
    5558             :  *
    5559             :  * We cannot exit early when aPt is outside the view bounds, because floating
    5560             :  * views aren't necessarily included in their parent's bounds, so this could
    5561             :  * traverse the entire view hierarchy --- use carefully.
    5562             :  */
    5563           0 : static nsView* FindFloatingViewContaining(nsView* aView, nsPoint aPt)
    5564             : {
    5565           0 :   if (aView->GetVisibility() == nsViewVisibility_kHide)
    5566             :     // No need to look into descendants.
    5567           0 :     return nullptr;
    5568             : 
    5569           0 :   nsIFrame* frame = aView->GetFrame();
    5570           0 :   if (frame) {
    5571           0 :     if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
    5572           0 :         !frame->PresContext()->PresShell()->IsActive()) {
    5573           0 :       return nullptr;
    5574             :     }
    5575             :   }
    5576             : 
    5577           0 :   for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
    5578           0 :     nsView* r = FindFloatingViewContaining(v, v->ConvertFromParentCoords(aPt));
    5579           0 :     if (r)
    5580           0 :       return r;
    5581             :   }
    5582             : 
    5583           0 :   if (aView->GetFloating() && aView->HasWidget() &&
    5584           0 :       aView->GetDimensions().Contains(aPt))
    5585           0 :     return aView;
    5586             : 
    5587           0 :   return nullptr;
    5588             : }
    5589             : 
    5590             : /*
    5591             :  * This finds the first view containing the given point in a postorder
    5592             :  * traversal of the view tree that contains the point, assuming that the
    5593             :  * point is not in a floating view.  It assumes that only floating views
    5594             :  * extend outside the bounds of their parents.
    5595             :  *
    5596             :  * This methods should only be called if FindFloatingViewContaining
    5597             :  * returns null.
    5598             :  */
    5599           0 : static nsView* FindViewContaining(nsView* aView, nsPoint aPt)
    5600             : {
    5601           0 :   if (!aView->GetDimensions().Contains(aPt) ||
    5602           0 :       aView->GetVisibility() == nsViewVisibility_kHide) {
    5603           0 :     return nullptr;
    5604             :   }
    5605             : 
    5606           0 :   nsIFrame* frame = aView->GetFrame();
    5607           0 :   if (frame) {
    5608           0 :     if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
    5609           0 :         !frame->PresContext()->PresShell()->IsActive()) {
    5610           0 :       return nullptr;
    5611             :     }
    5612             :   }
    5613             : 
    5614           0 :   for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
    5615           0 :     nsView* r = FindViewContaining(v, v->ConvertFromParentCoords(aPt));
    5616           0 :     if (r)
    5617           0 :       return r;
    5618             :   }
    5619             : 
    5620           0 :   return aView;
    5621             : }
    5622             : 
    5623             : void
    5624           1 : PresShell::ProcessSynthMouseMoveEvent(bool aFromScroll)
    5625             : {
    5626             :   // If drag session has started, we shouldn't synthesize mousemove event.
    5627           1 :   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
    5628           1 :   if (dragSession) {
    5629           0 :     mSynthMouseMoveEvent.Forget();
    5630           0 :     return;
    5631             :   }
    5632             : 
    5633             :   // allow new event to be posted while handling this one only if the
    5634             :   // source of the event is a scroll (to prevent infinite reflow loops)
    5635           1 :   if (aFromScroll) {
    5636           0 :     mSynthMouseMoveEvent.Forget();
    5637             :   }
    5638             : 
    5639           1 :   nsView* rootView = mViewManager ? mViewManager->GetRootView() : nullptr;
    5640           3 :   if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) ||
    5641           3 :       !rootView || !rootView->HasWidget() || !mPresContext) {
    5642           1 :     mSynthMouseMoveEvent.Forget();
    5643           1 :     return;
    5644             :   }
    5645             : 
    5646           0 :   NS_ASSERTION(mPresContext->IsRoot(), "Only a root pres shell should be here");
    5647             : 
    5648             :   // Hold a ref to ourselves so DispatchEvent won't destroy us (since
    5649             :   // we need to access members after we call DispatchEvent).
    5650           0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
    5651             : 
    5652             : #ifdef DEBUG_MOUSE_LOCATION
    5653             :   printf("[ps=%p]synthesizing mouse move to (%d,%d)\n",
    5654             :          this, mMouseLocation.x, mMouseLocation.y);
    5655             : #endif
    5656             : 
    5657           0 :   int32_t APD = mPresContext->AppUnitsPerDevPixel();
    5658             : 
    5659             :   // We need a widget to put in the event we are going to dispatch so we look
    5660             :   // for a view that has a widget and the mouse location is over. We first look
    5661             :   // for floating views, if there isn't one we use the root view. |view| holds
    5662             :   // that view.
    5663           0 :   nsView* view = nullptr;
    5664             : 
    5665             :   // The appunits per devpixel ratio of |view|.
    5666             :   int32_t viewAPD;
    5667             : 
    5668             :   // mRefPoint will be mMouseLocation relative to the widget of |view|, the
    5669             :   // widget we will put in the event we dispatch, in viewAPD appunits
    5670           0 :   nsPoint refpoint(0, 0);
    5671             : 
    5672             :   // We always dispatch the event to the pres shell that contains the view that
    5673             :   // the mouse is over. pointVM is the VM of that pres shell.
    5674           0 :   nsViewManager *pointVM = nullptr;
    5675             : 
    5676             :   // This could be a bit slow (traverses entire view hierarchy)
    5677             :   // but it's OK to do it once per synthetic mouse event
    5678           0 :   view = FindFloatingViewContaining(rootView, mMouseLocation);
    5679           0 :   if (!view) {
    5680           0 :     view = rootView;
    5681           0 :     nsView *pointView = FindViewContaining(rootView, mMouseLocation);
    5682             :     // pointView can be null in situations related to mouse capture
    5683           0 :     pointVM = (pointView ? pointView : view)->GetViewManager();
    5684           0 :     refpoint = mMouseLocation + rootView->ViewToWidgetOffset();
    5685           0 :     viewAPD = APD;
    5686             :   } else {
    5687           0 :     pointVM = view->GetViewManager();
    5688           0 :     nsIFrame* frame = view->GetFrame();
    5689           0 :     NS_ASSERTION(frame, "floating views can't be anonymous");
    5690           0 :     viewAPD = frame->PresContext()->AppUnitsPerDevPixel();
    5691           0 :     refpoint = mMouseLocation.ScaleToOtherAppUnits(APD, viewAPD);
    5692           0 :     refpoint -= view->GetOffsetTo(rootView);
    5693           0 :     refpoint += view->ViewToWidgetOffset();
    5694             :   }
    5695           0 :   NS_ASSERTION(view->GetWidget(), "view should have a widget here");
    5696             :   WidgetMouseEvent event(true, eMouseMove, view->GetWidget(),
    5697           0 :                          WidgetMouseEvent::eSynthesized);
    5698             :   event.mRefPoint =
    5699           0 :     LayoutDeviceIntPoint::FromAppUnitsToNearest(refpoint, viewAPD);
    5700           0 :   event.mTime = PR_IntervalNow();
    5701             :   // XXX set event.mModifiers ?
    5702             :   // XXX mnakano I think that we should get the latest information from widget.
    5703             : 
    5704           0 :   nsCOMPtr<nsIPresShell> shell = pointVM->GetPresShell();
    5705           0 :   if (shell) {
    5706             :     // Since this gets run in a refresh tick there isn't an InputAPZContext on
    5707             :     // the stack from the nsBaseWidget. We need to simulate one with at least
    5708             :     // the correct target guid, so that the correct callback transform gets
    5709             :     // applied if this event goes to a child process. The input block id is set
    5710             :     // to 0 because this is a synthetic event which doesn't really belong to any
    5711             :     // input block. Same for the APZ response field.
    5712           0 :     InputAPZContext apzContext(mMouseEventTargetGuid, 0, nsEventStatus_eIgnore);
    5713           0 :     shell->DispatchSynthMouseMove(&event, !aFromScroll);
    5714             :   }
    5715             : 
    5716           0 :   if (!aFromScroll) {
    5717           0 :     mSynthMouseMoveEvent.Forget();
    5718             :   }
    5719             : }
    5720             : 
    5721             : static void
    5722           0 : AddFrameToVisibleRegions(nsIFrame* aFrame,
    5723             :                          nsViewManager* aViewManager,
    5724             :                          Maybe<VisibleRegions>& aVisibleRegions)
    5725             : {
    5726           0 :   if (!aVisibleRegions) {
    5727           0 :     return;
    5728             :   }
    5729             : 
    5730           0 :   MOZ_ASSERT(aFrame);
    5731           0 :   MOZ_ASSERT(aViewManager);
    5732             : 
    5733             :   // Retrieve the view ID for this frame (which we obtain from the enclosing
    5734             :   // scrollable frame).
    5735             :   nsIScrollableFrame* scrollableFrame =
    5736             :     nsLayoutUtils::GetNearestScrollableFrame(aFrame,
    5737             :                                              nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE |
    5738           0 :                                              nsLayoutUtils::SCROLLABLE_ALWAYS_MATCH_ROOT);
    5739           0 :   if (!scrollableFrame) {
    5740           0 :     return;
    5741             :   }
    5742             : 
    5743           0 :   nsIFrame* scrollableFrameAsFrame = do_QueryFrame(scrollableFrame);
    5744           0 :   MOZ_ASSERT(scrollableFrameAsFrame);
    5745             : 
    5746           0 :   nsIContent* scrollableFrameContent = scrollableFrameAsFrame->GetContent();
    5747           0 :   if (!scrollableFrameContent) {
    5748           0 :     return;
    5749             :   }
    5750             : 
    5751             :   ViewID viewID;
    5752           0 :   if (!nsLayoutUtils::FindIDFor(scrollableFrameContent, &viewID)) {
    5753           0 :     return ;
    5754             :   }
    5755             : 
    5756             :   // Update the visible region for the appropriate view ID.
    5757           0 :   nsRect frameRectInScrolledFrameSpace = aFrame->GetVisualOverflowRect();
    5758             :   nsLayoutUtils::TransformResult result =
    5759           0 :     nsLayoutUtils::TransformRect(aFrame,
    5760           0 :                                  scrollableFrame->GetScrolledFrame(),
    5761           0 :                                  frameRectInScrolledFrameSpace);
    5762           0 :   if (result != nsLayoutUtils::TransformResult::TRANSFORM_SUCCEEDED) {
    5763           0 :     return;
    5764             :   }
    5765             : 
    5766           0 :   CSSIntRegion* regionForView = aVisibleRegions->LookupOrAdd(viewID);
    5767           0 :   MOZ_ASSERT(regionForView);
    5768             : 
    5769           0 :   regionForView->OrWith(CSSPixel::FromAppUnitsRounded(frameRectInScrolledFrameSpace));
    5770             : }
    5771             : 
    5772             : /* static */ void
    5773           0 : PresShell::MarkFramesInListApproximatelyVisible(const nsDisplayList& aList,
    5774             :                                                 Maybe<VisibleRegions>& aVisibleRegions)
    5775             : {
    5776           0 :   for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
    5777           0 :     nsDisplayList* sublist = item->GetChildren();
    5778           0 :     if (sublist) {
    5779           0 :       MarkFramesInListApproximatelyVisible(*sublist, aVisibleRegions);
    5780           0 :       continue;
    5781             :     }
    5782             : 
    5783           0 :     nsIFrame* frame = item->Frame();
    5784           0 :     MOZ_ASSERT(frame);
    5785             : 
    5786           0 :     if (!frame->TrackingVisibility()) {
    5787           0 :       continue;
    5788             :     }
    5789             : 
    5790             :     // Use the presshell containing the frame.
    5791           0 :     auto* presShell = static_cast<PresShell*>(frame->PresContext()->PresShell());
    5792           0 :     MOZ_ASSERT(!presShell->AssumeAllFramesVisible());
    5793           0 :     if (presShell->mApproximatelyVisibleFrames.EnsureInserted(frame)) {
    5794             :       // The frame was added to mApproximatelyVisibleFrames, so increment its visible count.
    5795           0 :       frame->IncApproximateVisibleCount();
    5796             :     }
    5797             : 
    5798           0 :     AddFrameToVisibleRegions(frame, presShell->mViewManager, aVisibleRegions);
    5799             :   }
    5800           0 : }
    5801             : 
    5802             : static void
    5803           1 : NotifyCompositorOfVisibleRegionsChange(PresShell* aPresShell,
    5804             :                                        const Maybe<VisibleRegions>& aRegions)
    5805             : {
    5806           1 :   if (!aRegions) {
    5807           1 :     return;
    5808             :   }
    5809             : 
    5810           0 :   MOZ_ASSERT(aPresShell);
    5811             : 
    5812             :   // Retrieve the layers ID and pres shell ID.
    5813           0 :   TabChild* tabChild = TabChild::GetFrom(aPresShell);
    5814           0 :   if (!tabChild) {
    5815           0 :     return;
    5816             :   }
    5817             : 
    5818           0 :   const uint64_t layersId = tabChild->LayersId();
    5819           0 :   const uint32_t presShellId = aPresShell->GetPresShellId();
    5820             : 
    5821             :   // Retrieve the CompositorBridgeChild.
    5822           0 :   LayerManager* layerManager = aPresShell->GetLayerManager();
    5823           0 :   if (!layerManager) {
    5824           0 :     return;
    5825             :   }
    5826             : 
    5827           0 :   ClientLayerManager* clientLayerManager = layerManager->AsClientLayerManager();
    5828           0 :   if (!clientLayerManager) {
    5829           0 :     return;
    5830             :   }
    5831             : 
    5832           0 :   CompositorBridgeChild* compositorChild = clientLayerManager->GetCompositorBridgeChild();
    5833           0 :   if (!compositorChild) {
    5834           0 :     return;
    5835             :   }
    5836             : 
    5837             :   // Clear the old approximately visible regions associated with this document.
    5838           0 :   compositorChild->SendClearApproximatelyVisibleRegions(layersId, presShellId);
    5839             : 
    5840             :   // Send the new approximately visible regions to the compositor.
    5841           0 :   for (auto iter = aRegions->ConstIter(); !iter.Done(); iter.Next()) {
    5842           0 :     const ViewID viewId = iter.Key();
    5843           0 :     const CSSIntRegion* region = iter.UserData();
    5844           0 :     MOZ_ASSERT(region);
    5845             : 
    5846           0 :     const ScrollableLayerGuid guid(layersId, presShellId, viewId);
    5847             : 
    5848           0 :     compositorChild->SendNotifyApproximatelyVisibleRegion(guid, *region);
    5849             :   }
    5850             : }
    5851             : 
    5852             : /* static */ void
    5853           5 : PresShell::DecApproximateVisibleCount(VisibleFrames& aFrames,
    5854             :                                       const Maybe<OnNonvisible>& aNonvisibleAction
    5855             :                                         /* = Nothing() */)
    5856             : {
    5857           5 :   for (auto iter = aFrames.Iter(); !iter.Done(); iter.Next()) {
    5858           0 :     nsIFrame* frame = iter.Get()->GetKey();
    5859             :     // Decrement the frame's visible count if we're still tracking its
    5860             :     // visibility. (We may not be, if the frame disabled visibility tracking
    5861             :     // after we added it to the visible frames list.)
    5862           0 :     if (frame->TrackingVisibility()) {
    5863           0 :       frame->DecApproximateVisibleCount(aNonvisibleAction);
    5864             :     }
    5865             :   }
    5866           5 : }
    5867             : 
    5868             : void
    5869           0 : PresShell::RebuildApproximateFrameVisibilityDisplayList(const nsDisplayList& aList)
    5870             : {
    5871           0 :   MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "already visited?");
    5872           0 :   mApproximateFrameVisibilityVisited = true;
    5873             : 
    5874             :   // Remove the entries of the mApproximatelyVisibleFrames hashtable and put
    5875             :   // them in oldApproxVisibleFrames.
    5876           0 :   VisibleFrames oldApproximatelyVisibleFrames;
    5877           0 :   mApproximatelyVisibleFrames.SwapElements(oldApproximatelyVisibleFrames);
    5878             : 
    5879             :   // If we're visualizing visible regions, create a VisibleRegions object to
    5880             :   // store information about them. The functions we call will populate this
    5881             :   // object and send it to the compositor only if it's Some(), so we don't
    5882             :   // need to check the prefs everywhere.
    5883           0 :   Maybe<VisibleRegions> visibleRegions;
    5884           0 :   if (gfxPrefs::APZMinimap() && gfxPrefs::APZMinimapVisibilityEnabled()) {
    5885           0 :     visibleRegions.emplace();
    5886             :   }
    5887             : 
    5888           0 :   MarkFramesInListApproximatelyVisible(aList, visibleRegions);
    5889             : 
    5890           0 :   DecApproximateVisibleCount(oldApproximatelyVisibleFrames);
    5891             : 
    5892           0 :   NotifyCompositorOfVisibleRegionsChange(this, visibleRegions);
    5893           0 : }
    5894             : 
    5895             : /* static */ void
    5896           1 : PresShell::ClearApproximateFrameVisibilityVisited(nsView* aView, bool aClear)
    5897             : {
    5898           1 :   nsViewManager* vm = aView->GetViewManager();
    5899           1 :   if (aClear) {
    5900           1 :     PresShell* presShell = static_cast<PresShell*>(vm->GetPresShell());
    5901           1 :     if (!presShell->mApproximateFrameVisibilityVisited) {
    5902           0 :       presShell->ClearApproximatelyVisibleFramesList();
    5903             :     }
    5904           1 :     presShell->mApproximateFrameVisibilityVisited = false;
    5905             :   }
    5906           1 :   for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
    5907           0 :     ClearApproximateFrameVisibilityVisited(v, v->GetViewManager() != vm);
    5908             :   }
    5909           1 : }
    5910             : 
    5911             : void
    5912           4 : PresShell::ClearApproximatelyVisibleFramesList(const Maybe<OnNonvisible>& aNonvisibleAction
    5913             :                                                  /* = Nothing() */)
    5914             : {
    5915           4 :   DecApproximateVisibleCount(mApproximatelyVisibleFrames, aNonvisibleAction);
    5916           4 :   mApproximatelyVisibleFrames.Clear();
    5917           4 : }
    5918             : 
    5919             : void
    5920           4 : PresShell::MarkFramesInSubtreeApproximatelyVisible(nsIFrame* aFrame,
    5921             :                                                    const nsRect& aRect,
    5922             :                                                    Maybe<VisibleRegions>& aVisibleRegions,
    5923             :                                                    bool aRemoveOnly /* = false */)
    5924             : {
    5925           4 :   MOZ_ASSERT(aFrame->PresContext()->PresShell() == this, "wrong presshell");
    5926             : 
    5927           8 :   if (aFrame->TrackingVisibility() &&
    5928           4 :       aFrame->StyleVisibility()->IsVisible() &&
    5929           0 :       (!aRemoveOnly || aFrame->GetVisibility() == Visibility::APPROXIMATELY_VISIBLE)) {
    5930           0 :     MOZ_ASSERT(!AssumeAllFramesVisible());
    5931           0 :     if (mApproximatelyVisibleFrames.EnsureInserted(aFrame)) {
    5932             :       // The frame was added to mApproximatelyVisibleFrames, so increment its visible count.
    5933           0 :       aFrame->IncApproximateVisibleCount();
    5934             :     }
    5935             : 
    5936           0 :     AddFrameToVisibleRegions(aFrame, mViewManager, aVisibleRegions);
    5937             :   }
    5938             : 
    5939           4 :   nsSubDocumentFrame* subdocFrame = do_QueryFrame(aFrame);
    5940           4 :   if (subdocFrame) {
    5941             :     nsIPresShell* presShell = subdocFrame->GetSubdocumentPresShellForPainting(
    5942           0 :       nsSubDocumentFrame::IGNORE_PAINT_SUPPRESSION);
    5943           0 :     if (presShell && !presShell->AssumeAllFramesVisible()) {
    5944           0 :       nsRect rect = aRect;
    5945           0 :       nsIFrame* root = presShell->GetRootFrame();
    5946           0 :       if (root) {
    5947           0 :         rect.MoveBy(aFrame->GetOffsetToCrossDoc(root));
    5948             :       } else {
    5949           0 :         rect.MoveBy(-aFrame->GetContentRectRelativeToSelf().TopLeft());
    5950             :       }
    5951           0 :       rect = rect.ScaleToOtherAppUnitsRoundOut(
    5952             :         aFrame->PresContext()->AppUnitsPerDevPixel(),
    5953             :         presShell->GetPresContext()->AppUnitsPerDevPixel());
    5954             : 
    5955           0 :       presShell->RebuildApproximateFrameVisibility(&rect);
    5956             :     }
    5957           0 :     return;
    5958             :   }
    5959             : 
    5960           8 :   nsRect rect = aRect;
    5961             : 
    5962           4 :   nsIScrollableFrame* scrollFrame = do_QueryFrame(aFrame);
    5963           4 :   if (scrollFrame) {
    5964           1 :     bool ignoreDisplayPort = false;
    5965           1 :     if (nsLayoutUtils::IsMissingDisplayPortBaseRect(aFrame->GetContent())) {
    5966             :       // We can properly set the base rect for root scroll frames on top level
    5967             :       // and root content documents. Otherwise the base rect we compute might
    5968             :       // be way too big without the limiting that
    5969             :       // ScrollFrameHelper::DecideScrollableLayer does, so we just ignore the
    5970             :       // displayport in that case.
    5971           0 :       nsPresContext* pc = aFrame->PresContext();
    5972           0 :       if (scrollFrame->IsRootScrollFrameOfDocument() &&
    5973           0 :           (pc->IsRootContentDocument() || !pc->GetParentPresContext())) {
    5974             :         nsRect baseRect =
    5975           0 :           nsRect(nsPoint(0, 0), nsLayoutUtils::CalculateCompositionSizeForFrame(aFrame));
    5976           0 :         nsLayoutUtils::SetDisplayPortBase(aFrame->GetContent(), baseRect);
    5977             :       } else {
    5978           0 :         ignoreDisplayPort = true;
    5979             :       }
    5980             :     }
    5981             : 
    5982           1 :     scrollFrame->NotifyApproximateFrameVisibilityUpdate(ignoreDisplayPort);
    5983             : 
    5984           2 :     nsRect displayPort;
    5985           2 :     bool usingDisplayport = !ignoreDisplayPort &&
    5986           1 :       nsLayoutUtils::GetDisplayPortForVisibilityTesting(
    5987           1 :         aFrame->GetContent(), &displayPort, RelativeTo::ScrollFrame);
    5988           1 :     if (usingDisplayport) {
    5989           1 :       rect = displayPort;
    5990             :     } else {
    5991           0 :       rect = rect.Intersect(scrollFrame->GetScrollPortRect());
    5992             :     }
    5993           1 :     rect = scrollFrame->ExpandRectToNearlyVisible(rect);
    5994             :   }
    5995             : 
    5996           4 :   bool preserves3DChildren = aFrame->Extend3DContext();
    5997             : 
    5998             :   // We assume all frames in popups are visible, so we skip them here.
    5999             :   const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList |
    6000           4 :                                     nsIFrame::kSelectPopupList);
    6001          16 :   for (nsIFrame::ChildListIterator childLists(aFrame);
    6002          12 :        !childLists.IsDone(); childLists.Next()) {
    6003           4 :     if (skip.Contains(childLists.CurrentID())) {
    6004           0 :       continue;
    6005             :     }
    6006             : 
    6007          11 :     for (nsIFrame* child : childLists.CurrentList()) {
    6008          10 :       nsRect r = rect - child->GetPosition();
    6009           7 :       if (!r.IntersectRect(r, child->GetVisualOverflowRect())) {
    6010           4 :         continue;
    6011             :       }
    6012           3 :       if (child->IsTransformed()) {
    6013             :         // for children of a preserve3d element we just pass down the same dirty rect
    6014           0 :         if (!preserves3DChildren || !child->Combines3DTransformWithAncestors()) {
    6015           0 :           const nsRect overflow = child->GetVisualOverflowRectRelativeToSelf();
    6016           0 :           nsRect out;
    6017           0 :           if (nsDisplayTransform::UntransformRect(r, overflow, child, &out)) {
    6018           0 :             r = out;
    6019             :           } else {
    6020           0 :             r.SetEmpty();
    6021             :           }
    6022             :         }
    6023             :       }
    6024           3 :       MarkFramesInSubtreeApproximatelyVisible(child, r, aVisibleRegions);
    6025             :     }
    6026             :   }
    6027             : }
    6028             : 
    6029             : void
    6030           1 : PresShell::RebuildApproximateFrameVisibility(nsRect* aRect,
    6031             :                                              bool aRemoveOnly /* = false */)
    6032             : {
    6033           1 :   MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "already visited?");
    6034           1 :   mApproximateFrameVisibilityVisited = true;
    6035             : 
    6036           1 :   nsIFrame* rootFrame = GetRootFrame();
    6037           1 :   if (!rootFrame) {
    6038           0 :     return;
    6039             :   }
    6040             : 
    6041             :   // Remove the entries of the mApproximatelyVisibleFrames hashtable and put
    6042             :   // them in oldApproximatelyVisibleFrames.
    6043           2 :   VisibleFrames oldApproximatelyVisibleFrames;
    6044           1 :   mApproximatelyVisibleFrames.SwapElements(oldApproximatelyVisibleFrames);
    6045             : 
    6046             :   // If we're visualizing visible regions, create a VisibleRegions object to
    6047             :   // store information about them. The functions we call will populate this
    6048             :   // object and send it to the compositor only if it's Some(), so we don't
    6049             :   // need to check the prefs everywhere.
    6050           2 :   Maybe<VisibleRegions> visibleRegions;
    6051           1 :   if (gfxPrefs::APZMinimap() && gfxPrefs::APZMinimapVisibilityEnabled()) {
    6052           0 :     visibleRegions.emplace();
    6053             :   }
    6054             : 
    6055           2 :   nsRect vis(nsPoint(0, 0), rootFrame->GetSize());
    6056           1 :   if (aRect) {
    6057           0 :     vis = *aRect;
    6058             :   }
    6059             : 
    6060           1 :   MarkFramesInSubtreeApproximatelyVisible(rootFrame, vis, visibleRegions, aRemoveOnly);
    6061             : 
    6062           1 :   DecApproximateVisibleCount(oldApproximatelyVisibleFrames);
    6063             : 
    6064           1 :   NotifyCompositorOfVisibleRegionsChange(this, visibleRegions);
    6065             : }
    6066             : 
    6067             : void
    6068           1 : PresShell::UpdateApproximateFrameVisibility()
    6069             : {
    6070           1 :   DoUpdateApproximateFrameVisibility(/* aRemoveOnly = */ false);
    6071           1 : }
    6072             : 
    6073             : void
    6074           1 : PresShell::DoUpdateApproximateFrameVisibility(bool aRemoveOnly)
    6075             : {
    6076           1 :   MOZ_ASSERT(!mPresContext || mPresContext->IsRootContentDocument(),
    6077             :              "Updating approximate frame visibility on a non-root content document?");
    6078             : 
    6079           1 :   mUpdateApproximateFrameVisibilityEvent.Revoke();
    6080             : 
    6081           1 :   if (mHaveShutDown || mIsDestroying) {
    6082           0 :     return;
    6083             :   }
    6084             : 
    6085             :   // call update on that frame
    6086           1 :   nsIFrame* rootFrame = GetRootFrame();
    6087           1 :   if (!rootFrame) {
    6088           0 :     ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DISCARD_IMAGES));
    6089           0 :     return;
    6090             :   }
    6091             : 
    6092           1 :   RebuildApproximateFrameVisibility(/* aRect = */ nullptr, aRemoveOnly);
    6093           1 :   ClearApproximateFrameVisibilityVisited(rootFrame->GetView(), true);
    6094             : 
    6095             : #ifdef DEBUG_FRAME_VISIBILITY_DISPLAY_LIST
    6096             :   // This can be used to debug the frame walker by comparing beforeFrameList
    6097             :   // and mApproximatelyVisibleFrames in RebuildFrameVisibilityDisplayList to see if
    6098             :   // they produce the same results (mApproximatelyVisibleFrames holds the frames the
    6099             :   // display list thinks are visible, beforeFrameList holds the frames the
    6100             :   // frame walker thinks are visible).
    6101             :   nsDisplayListBuilder builder(rootFrame, nsDisplayListBuilderMode::FRAME_VISIBILITY, false);
    6102             :   nsRect updateRect(nsPoint(0, 0), rootFrame->GetSize());
    6103             :   nsIFrame* rootScroll = GetRootScrollFrame();
    6104             :   if (rootScroll) {
    6105             :     nsIContent* content = rootScroll->GetContent();
    6106             :     if (content) {
    6107             :       Unused << nsLayoutUtils::GetDisplayPortForVisibilityTesting(content, &updateRect,
    6108             :         RelativeTo::ScrollFrame);
    6109             :     }
    6110             : 
    6111             :     if (IgnoringViewportScrolling()) {
    6112             :       builder.SetIgnoreScrollFrame(rootScroll);
    6113             :     }
    6114             :   }
    6115             :   builder.IgnorePaintSuppression();
    6116             :   builder.EnterPresShell(rootFrame);
    6117             :   nsDisplayList list;
    6118             :   rootFrame->BuildDisplayListForStackingContext(&builder, updateRect, &list);
    6119             :   builder.LeavePresShell(rootFrame, &list);
    6120             : 
    6121             :   RebuildApproximateFrameVisibilityDisplayList(list);
    6122             : 
    6123             :   ClearApproximateFrameVisibilityVisited(rootFrame->GetView(), true);
    6124             : 
    6125             :   list.DeleteAll();
    6126             : #endif
    6127             : }
    6128             : 
    6129             : bool
    6130         824 : PresShell::AssumeAllFramesVisible()
    6131             : {
    6132             :   static bool sFrameVisibilityEnabled = true;
    6133             :   static bool sFrameVisibilityPrefCached = false;
    6134             : 
    6135         824 :   if (!sFrameVisibilityPrefCached) {
    6136             :     Preferences::AddBoolVarCache(&sFrameVisibilityEnabled,
    6137           2 :       "layout.framevisibility.enabled", true);
    6138           2 :     sFrameVisibilityPrefCached = true;
    6139             :   }
    6140             : 
    6141         824 :   if (!sFrameVisibilityEnabled || !mPresContext || !mDocument) {
    6142           0 :     return true;
    6143             :   }
    6144             : 
    6145             :   // We assume all frames are visible in print, print preview, chrome, and
    6146             :   // resource docs and don't keep track of them.
    6147        2472 :   if (mPresContext->Type() == nsPresContext::eContext_PrintPreview ||
    6148        1648 :       mPresContext->Type() == nsPresContext::eContext_Print ||
    6149        1912 :       mPresContext->IsChrome() ||
    6150         264 :       mDocument->IsResourceDoc()) {
    6151         808 :     return true;
    6152             :   }
    6153             : 
    6154             :   // If we're assuming all frames are visible in the top level content
    6155             :   // document, we need to in subdocuments as well. Otherwise we can get in a
    6156             :   // situation where things like animations won't work in subdocuments because
    6157             :   // their frames appear not to be visible, since we won't schedule an image
    6158             :   // visibility update if the top level content document is assuming all
    6159             :   // frames are visible.
    6160             :   //
    6161             :   // Note that it's not safe to call IsRootContentDocument() if we're
    6162             :   // currently being destroyed, so we have to check that first.
    6163          32 :   if (!mHaveShutDown && !mIsDestroying &&
    6164          16 :       !mPresContext->IsRootContentDocument()) {
    6165             :     nsPresContext* presContext =
    6166           0 :       mPresContext->GetToplevelContentDocumentPresContext();
    6167           0 :     if (presContext && presContext->PresShell()->AssumeAllFramesVisible()) {
    6168           0 :       return true;
    6169             :     }
    6170             :   }
    6171             : 
    6172          16 :   return false;
    6173             : }
    6174             : 
    6175             : void
    6176           0 : PresShell::ScheduleApproximateFrameVisibilityUpdateSoon()
    6177             : {
    6178           0 :   if (AssumeAllFramesVisible()) {
    6179           0 :     return;
    6180             :   }
    6181             : 
    6182           0 :   if (!mPresContext) {
    6183           0 :     return;
    6184             :   }
    6185             : 
    6186           0 :   nsRefreshDriver* refreshDriver = mPresContext->RefreshDriver();
    6187           0 :   if (!refreshDriver) {
    6188           0 :     return;
    6189             :   }
    6190             : 
    6191             :   // Ask the refresh driver to update frame visibility soon.
    6192           0 :   refreshDriver->ScheduleFrameVisibilityUpdate();
    6193             : }
    6194             : 
    6195             : void
    6196          32 : PresShell::ScheduleApproximateFrameVisibilityUpdateNow()
    6197             : {
    6198          32 :   if (AssumeAllFramesVisible()) {
    6199          60 :     return;
    6200             :   }
    6201             : 
    6202           3 :   if (!mPresContext->IsRootContentDocument()) {
    6203           0 :     nsPresContext* presContext = mPresContext->GetToplevelContentDocumentPresContext();
    6204           0 :     if (!presContext)
    6205           0 :       return;
    6206           0 :     MOZ_ASSERT(presContext->IsRootContentDocument(),
    6207             :       "Didn't get a root prescontext from GetToplevelContentDocumentPresContext?");
    6208           0 :     presContext->PresShell()->ScheduleApproximateFrameVisibilityUpdateNow();
    6209           0 :     return;
    6210             :   }
    6211             : 
    6212           3 :   if (mHaveShutDown || mIsDestroying) {
    6213           0 :     return;
    6214             :   }
    6215             : 
    6216           3 :   if (mUpdateApproximateFrameVisibilityEvent.IsPending()) {
    6217           2 :     return;
    6218             :   }
    6219             : 
    6220             :   RefPtr<nsRunnableMethod<PresShell>> event =
    6221           2 :     NewRunnableMethod("PresShell::UpdateApproximateFrameVisibility",
    6222             :                       this,
    6223           2 :                       &PresShell::UpdateApproximateFrameVisibility);
    6224             :   nsresult rv =
    6225           3 :     mDocument->Dispatch("PresShell::UpdateApproximateFrameVisibility",
    6226             :                         TaskCategory::Other,
    6227           3 :                         do_AddRef(event));
    6228             : 
    6229           1 :   if (NS_SUCCEEDED(rv)) {
    6230           1 :     mUpdateApproximateFrameVisibilityEvent = event;
    6231             :   }
    6232             : }
    6233             : 
    6234             : void
    6235           0 : PresShell::EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame)
    6236             : {
    6237           0 :   if (!aFrame->TrackingVisibility()) {
    6238           0 :     return;
    6239             :   }
    6240             : 
    6241           0 :   if (AssumeAllFramesVisible()) {
    6242           0 :     aFrame->IncApproximateVisibleCount();
    6243           0 :     return;
    6244             :   }
    6245             : 
    6246             : #ifdef DEBUG
    6247             :   // Make sure it's in this pres shell.
    6248           0 :   nsCOMPtr<nsIContent> content = aFrame->GetContent();
    6249           0 :   if (content) {
    6250           0 :     PresShell* shell = static_cast<PresShell*>(content->OwnerDoc()->GetShell());
    6251           0 :     MOZ_ASSERT(!shell || shell == this, "wrong shell");
    6252             :   }
    6253             : #endif
    6254             : 
    6255           0 :   if (mApproximatelyVisibleFrames.EnsureInserted(aFrame)) {
    6256             :     // We inserted a new entry.
    6257           0 :     aFrame->IncApproximateVisibleCount();
    6258             :   }
    6259             : }
    6260             : 
    6261             : void
    6262         126 : PresShell::RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame)
    6263             : {
    6264             : #ifdef DEBUG
    6265             :   // Make sure it's in this pres shell.
    6266         126 :   nsCOMPtr<nsIContent> content = aFrame->GetContent();
    6267         126 :   if (content) {
    6268         126 :     PresShell* shell = static_cast<PresShell*>(content->OwnerDoc()->GetShell());
    6269         126 :     MOZ_ASSERT(!shell || shell == this, "wrong shell");
    6270             :   }
    6271             : #endif
    6272             : 
    6273         126 :   if (AssumeAllFramesVisible()) {
    6274         126 :     MOZ_ASSERT(mApproximatelyVisibleFrames.Count() == 0,
    6275             :                "Shouldn't have any frames in the table");
    6276         126 :     return;
    6277             :   }
    6278             : 
    6279           0 :   if (mApproximatelyVisibleFrames.EnsureRemoved(aFrame) &&
    6280           0 :       aFrame->TrackingVisibility()) {
    6281             :     // aFrame was in the hashtable, and we're still tracking its visibility,
    6282             :     // so we need to decrement its visible count.
    6283           0 :     aFrame->DecApproximateVisibleCount();
    6284             :   }
    6285             : }
    6286             : 
    6287             : class nsAutoNotifyDidPaint
    6288             : {
    6289             : public:
    6290          29 :   nsAutoNotifyDidPaint(PresShell* aShell, uint32_t aFlags)
    6291          29 :     : mShell(aShell), mFlags(aFlags)
    6292             :   {
    6293          29 :   }
    6294          29 :   ~nsAutoNotifyDidPaint()
    6295          29 :   {
    6296          29 :     if (mFlags & nsIPresShell::PAINT_COMPOSITE) {
    6297           0 :       mShell->GetPresContext()->NotifyDidPaintForSubtree();
    6298             :     }
    6299          29 :   }
    6300             : 
    6301             : private:
    6302             :   PresShell* mShell;
    6303             :   uint32_t mFlags;
    6304             : };
    6305             : 
    6306             : void
    6307           0 : PresShell::RecordShadowStyleChange(ShadowRoot* aShadowRoot)
    6308             : {
    6309           0 :   mStyleSet->RecordShadowStyleChange(aShadowRoot);
    6310           0 : }
    6311             : 
    6312             : void
    6313          29 : PresShell::Paint(nsView*         aViewToPaint,
    6314             :                  const nsRegion& aDirtyRegion,
    6315             :                  uint32_t        aFlags)
    6316             : {
    6317          29 :   nsIURI* uri = mDocument->GetDocumentURI();
    6318          29 :   nsIDocument* contentRoot = GetPrimaryContentDocument();
    6319          29 :   if (contentRoot) {
    6320           4 :     uri = contentRoot->GetDocumentURI();
    6321             :   }
    6322          31 :   nsCString uriString = uri ? uri->GetSpecOrDefault() : NS_LITERAL_CSTRING("N/A");
    6323          31 :   AUTO_PROFILER_LABEL_DYNAMIC("PresShell::Paint", GRAPHICS, uriString.get());
    6324             : 
    6325          31 :   Maybe<js::AutoAssertNoContentJS> nojs;
    6326             : 
    6327             :   // On Android, Flash can call into content JS during painting, so we can't
    6328             :   // assert there. However, we don't rely on this assertion on Android because
    6329             :   // we don't paint while JS is running.
    6330             : #if !defined(MOZ_WIDGET_ANDROID)
    6331          29 :   if (!(aFlags & nsIPresShell::PAINT_COMPOSITE)) {
    6332             :     // We need to allow content JS when the flag is set since we may trigger
    6333             :     // MozAfterPaint events in content in those cases.
    6334          29 :     nojs.emplace(dom::danger::GetJSContext());
    6335             :   }
    6336             : #endif
    6337             : 
    6338          29 :   NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
    6339          29 :   NS_ASSERTION(aViewToPaint, "null view");
    6340             : 
    6341          29 :   MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "Should have been cleared");
    6342             : 
    6343          29 :   if (!mIsActive) {
    6344           0 :     return;
    6345             :   }
    6346             : 
    6347          29 :   if (gfxPrefs::APZKeyboardEnabled()) {
    6348             :     // Update the focus target for async keyboard scrolling. This will be forwarded
    6349             :     // to APZ by nsDisplayList::PaintRoot. We need to to do this before we enter
    6350             :     // the paint phase because dispatching eVoid events can cause layout to happen.
    6351           0 :     mAPZFocusTarget = FocusTarget(this, mAPZFocusSequenceNumber);
    6352             :   }
    6353             : 
    6354          29 :   nsPresContext* presContext = GetPresContext();
    6355          31 :   AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
    6356             : 
    6357          29 :   nsIFrame* frame = aViewToPaint->GetFrame();
    6358             : 
    6359             :   LayerManager* layerManager =
    6360          29 :     aViewToPaint->GetWidget()->GetLayerManager();
    6361          29 :   NS_ASSERTION(layerManager, "Must be in paint event");
    6362          29 :   bool shouldInvalidate = layerManager->NeedsWidgetInvalidation();
    6363             : 
    6364          31 :   nsAutoNotifyDidPaint notifyDidPaint(this, aFlags);
    6365             : 
    6366             :   // Whether or not we should set first paint when painting is suppressed
    6367             :   // is debatable. For now we'll do it because B2G relied on first paint
    6368             :   // to configure the viewport and we only want to do that when we have
    6369             :   // real content to paint. See Bug 798245
    6370          29 :   if (mIsFirstPaint && !mPaintingSuppressed) {
    6371           3 :     layerManager->SetIsFirstPaint();
    6372           3 :     mIsFirstPaint = false;
    6373             :   }
    6374             : 
    6375          29 :   if (!layerManager->BeginTransaction()) {
    6376           0 :     return;
    6377             :   }
    6378             : 
    6379             :   // Send an updated focus target with this transaction. Be sure to do this
    6380             :   // before we paint in the case this is an empty transaction.
    6381          29 :   layerManager->SetFocusTarget(mAPZFocusTarget);
    6382             : 
    6383          29 :   if (frame) {
    6384             :     // Try to do an empty transaction, if the frame tree does not
    6385             :     // need to be updated. Do not try to do an empty transaction on
    6386             :     // a non-retained layer manager (like the BasicLayerManager that
    6387             :     // draws the window title bar on Mac), because a) it won't work
    6388             :     // and b) below we don't want to clear NS_FRAME_UPDATE_LAYER_TREE,
    6389             :     // that will cause us to forget to update the real layer manager!
    6390             : 
    6391          27 :     if (!(aFlags & PAINT_LAYERS)) {
    6392           0 :       if (layerManager->EndEmptyTransaction()) {
    6393           0 :         return;
    6394             :       }
    6395           0 :       NS_WARNING("Must complete empty transaction when compositing!");
    6396             :     }
    6397             : 
    6398          81 :     if (!(aFlags & PAINT_SYNC_DECODE_IMAGES) &&
    6399          28 :         !(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE) &&
    6400           1 :         !mNextPaintCompressed) {
    6401             :       NotifySubDocInvalidationFunc computeInvalidFunc =
    6402           1 :         presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
    6403           1 :       bool computeInvalidRect = computeInvalidFunc ||
    6404           1 :                                 (layerManager->GetBackendType() == LayersBackend::LAYERS_BASIC);
    6405             : 
    6406           1 :       UniquePtr<LayerProperties> props;
    6407           1 :       if (computeInvalidRect) {
    6408           1 :         props = Move(LayerProperties::CloneFrom(layerManager->GetRoot()));
    6409             :       }
    6410             : 
    6411           1 :       MaybeSetupTransactionIdAllocator(layerManager, presContext);
    6412             : 
    6413           1 :       if (layerManager->EndEmptyTransaction((aFlags & PAINT_COMPOSITE) ?
    6414           1 :             LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE)) {
    6415           2 :         nsIntRegion invalid;
    6416           1 :         if (props) {
    6417           1 :           invalid = props->ComputeDifferences(layerManager->GetRoot(), computeInvalidFunc);
    6418             :         } else {
    6419           0 :           LayerProperties::ClearInvalidations(layerManager->GetRoot());
    6420             :         }
    6421           1 :         if (props) {
    6422           1 :           if (!invalid.IsEmpty()) {
    6423           0 :             nsIntRect bounds = invalid.GetBounds();
    6424             :             nsRect rect(presContext->DevPixelsToAppUnits(bounds.x),
    6425             :                         presContext->DevPixelsToAppUnits(bounds.y),
    6426             :                         presContext->DevPixelsToAppUnits(bounds.width),
    6427           0 :                         presContext->DevPixelsToAppUnits(bounds.height));
    6428           0 :             if (shouldInvalidate) {
    6429           0 :               aViewToPaint->GetViewManager()->InvalidateViewNoSuppression(aViewToPaint, rect);
    6430             :             }
    6431           0 :             presContext->NotifyInvalidation(layerManager->GetLastTransactionId(), bounds);
    6432             :           }
    6433           0 :         } else if (shouldInvalidate) {
    6434           0 :           aViewToPaint->GetViewManager()->InvalidateView(aViewToPaint);
    6435             :         }
    6436             : 
    6437           1 :         frame->UpdatePaintCountForPaintedPresShells();
    6438           1 :         return;
    6439             :       }
    6440             :     }
    6441          26 :     frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE);
    6442             :   }
    6443          28 :   if (frame) {
    6444          26 :     frame->ClearPresShellsFromLastPaint();
    6445             :   }
    6446             : 
    6447          28 :   nscolor bgcolor = ComputeBackstopColor(aViewToPaint);
    6448          56 :   PaintFrameFlags flags = PaintFrameFlags::PAINT_WIDGET_LAYERS |
    6449          28 :                           PaintFrameFlags::PAINT_EXISTING_TRANSACTION;
    6450          28 :   if (!(aFlags & PAINT_COMPOSITE)) {
    6451          28 :     flags |= PaintFrameFlags::PAINT_NO_COMPOSITE;
    6452             :   }
    6453          28 :   if (aFlags & PAINT_SYNC_DECODE_IMAGES) {
    6454           0 :     flags |= PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES;
    6455             :   }
    6456          28 :   if (mNextPaintCompressed) {
    6457           1 :     flags |= PaintFrameFlags::PAINT_COMPRESSED;
    6458           1 :     mNextPaintCompressed = false;
    6459             :   }
    6460             : 
    6461          28 :   if (frame) {
    6462             :     // We can paint directly into the widget using its layer manager.
    6463             :     nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor,
    6464          26 :                               nsDisplayListBuilderMode::PAINTING, flags);
    6465          26 :     return;
    6466             :   }
    6467             : 
    6468           4 :   RefPtr<ColorLayer> root = layerManager->CreateColorLayer();
    6469           2 :   if (root) {
    6470           2 :     nsPresContext* pc = GetPresContext();
    6471             :     nsIntRect bounds =
    6472           2 :       pc->GetVisibleArea().ToOutsidePixels(pc->AppUnitsPerDevPixel());
    6473           2 :     bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
    6474           2 :     root->SetColor(Color::FromABGR(bgcolor));
    6475           2 :     root->SetVisibleRegion(LayerIntRegion::FromUnknownRegion(bounds));
    6476           2 :     layerManager->SetRoot(root);
    6477             :   }
    6478           2 :   MaybeSetupTransactionIdAllocator(layerManager, presContext);
    6479           2 :   layerManager->EndTransaction(nullptr, nullptr, (aFlags & PAINT_COMPOSITE) ?
    6480           4 :     LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE);
    6481             : }
    6482             : 
    6483             : // static
    6484             : void
    6485           0 : nsIPresShell::SetCapturingContent(nsIContent* aContent, uint8_t aFlags)
    6486             : {
    6487             :   // If capture was set for pointer lock, don't unlock unless we are coming
    6488             :   // out of pointer lock explicitly.
    6489           0 :   if (!aContent && gCaptureInfo.mPointerLock &&
    6490           0 :       !(aFlags & CAPTURE_POINTERLOCK)) {
    6491           0 :     return;
    6492             :   }
    6493             : 
    6494           0 :   gCaptureInfo.mContent = nullptr;
    6495             : 
    6496             :   // only set capturing content if allowed or the CAPTURE_IGNOREALLOWED or
    6497             :   // CAPTURE_POINTERLOCK flags are used.
    6498           0 :   if ((aFlags & CAPTURE_IGNOREALLOWED) || gCaptureInfo.mAllowed ||
    6499           0 :       (aFlags & CAPTURE_POINTERLOCK)) {
    6500           0 :     if (aContent) {
    6501           0 :       gCaptureInfo.mContent = aContent;
    6502             :     }
    6503             :     // CAPTURE_POINTERLOCK is the same as CAPTURE_RETARGETTOELEMENT & CAPTURE_IGNOREALLOWED
    6504           0 :     gCaptureInfo.mRetargetToElement = ((aFlags & CAPTURE_RETARGETTOELEMENT) != 0) ||
    6505           0 :                                       ((aFlags & CAPTURE_POINTERLOCK) != 0);
    6506           0 :     gCaptureInfo.mPreventDrag = (aFlags & CAPTURE_PREVENTDRAG) != 0;
    6507           0 :     gCaptureInfo.mPointerLock = (aFlags & CAPTURE_POINTERLOCK) != 0;
    6508             :   }
    6509             : }
    6510             : 
    6511             : /* static */ void
    6512           0 : nsIPresShell::SetPointerCapturingContent(uint32_t aPointerId,
    6513             :                                          nsIContent* aContent)
    6514             : {
    6515           0 :   MOZ_ASSERT(aContent != nullptr);
    6516             : 
    6517           0 :   if (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId)) {
    6518           0 :     SetCapturingContent(aContent, CAPTURE_PREVENTDRAG);
    6519             :   }
    6520             : 
    6521           0 :   PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
    6522           0 :   if (pointerCaptureInfo) {
    6523           0 :     pointerCaptureInfo->mPendingContent = aContent;
    6524             :   } else {
    6525           0 :     sPointerCaptureList->Put(aPointerId, new PointerCaptureInfo(aContent));
    6526             :   }
    6527           0 : }
    6528             : 
    6529             : /* static */ nsIPresShell::PointerCaptureInfo*
    6530          14 : nsIPresShell::GetPointerCaptureInfo(uint32_t aPointerId)
    6531             : {
    6532          14 :   PointerCaptureInfo* pointerCaptureInfo = nullptr;
    6533          14 :   sPointerCaptureList->Get(aPointerId, &pointerCaptureInfo);
    6534          14 :   return pointerCaptureInfo;
    6535             : }
    6536             : 
    6537             : /* static */ void
    6538           0 : nsIPresShell::ReleasePointerCapturingContent(uint32_t aPointerId)
    6539             : {
    6540           0 :   if (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId)) {
    6541           0 :     SetCapturingContent(nullptr, CAPTURE_PREVENTDRAG);
    6542             :   }
    6543             : 
    6544           0 :   PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
    6545           0 :   if (pointerCaptureInfo) {
    6546           0 :     pointerCaptureInfo->mPendingContent = nullptr;
    6547             :   }
    6548           0 : }
    6549             : 
    6550             : /* static */ nsIContent*
    6551          10 : nsIPresShell::GetPointerCapturingContent(uint32_t aPointerId)
    6552             : {
    6553          10 :   PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
    6554          10 :   if (pointerCaptureInfo) {
    6555           0 :     return pointerCaptureInfo->mOverrideContent;
    6556             :   }
    6557          10 :   return nullptr;
    6558             : }
    6559             : 
    6560             : /* static */ void
    6561           4 : nsIPresShell::CheckPointerCaptureState(const WidgetPointerEvent* aPointerEvent)
    6562             : {
    6563             :   PointerCaptureInfo* captureInfo =
    6564           4 :     GetPointerCaptureInfo(aPointerEvent->pointerId);
    6565             : 
    6566           4 :   if (captureInfo &&
    6567           0 :       captureInfo->mPendingContent != captureInfo->mOverrideContent) {
    6568             :     // cache captureInfo->mPendingContent since it may be changed in the pointer
    6569             :     // event listener
    6570           0 :     nsIContent* pendingContent = captureInfo->mPendingContent.get();
    6571           0 :     if (captureInfo->mOverrideContent) {
    6572           0 :       DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ false,
    6573             :                                            aPointerEvent,
    6574           0 :                                            captureInfo->mOverrideContent);
    6575             :     }
    6576           0 :     if (pendingContent) {
    6577             :       DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ true,
    6578           0 :                                            aPointerEvent, pendingContent);
    6579             :     }
    6580             : 
    6581           0 :     captureInfo->mOverrideContent = pendingContent;
    6582           0 :     if (captureInfo->Empty()) {
    6583           0 :       sPointerCaptureList->Remove(aPointerEvent->pointerId);
    6584             :     }
    6585             :   }
    6586           4 : }
    6587             : 
    6588             : /* static */ uint16_t
    6589           0 : nsIPresShell::GetPointerType(uint32_t aPointerId)
    6590             : {
    6591           0 :   PointerInfo* pointerInfo = nullptr;
    6592           0 :   if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
    6593           0 :     return pointerInfo->mPointerType;
    6594             :   }
    6595           0 :   return nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
    6596             : }
    6597             : 
    6598             : /* static */ bool
    6599           0 : nsIPresShell::GetPointerPrimaryState(uint32_t aPointerId)
    6600             : {
    6601           0 :   PointerInfo* pointerInfo = nullptr;
    6602           0 :   if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
    6603           0 :     return pointerInfo->mPrimaryState;
    6604             :   }
    6605           0 :   return false;
    6606             : }
    6607             : 
    6608             : /* static */ bool
    6609           0 : nsIPresShell::GetPointerInfo(uint32_t aPointerId, bool& aActiveState)
    6610             : {
    6611           0 :   PointerInfo* pointerInfo = nullptr;
    6612           0 :   if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
    6613           0 :     aActiveState = pointerInfo->mActiveState;
    6614           0 :     return true;
    6615             :   }
    6616           0 :   return false;
    6617             : }
    6618             : 
    6619             : void
    6620          10 : PresShell::UpdateActivePointerState(WidgetGUIEvent* aEvent)
    6621             : {
    6622          10 :   switch (aEvent->mMessage) {
    6623             :   case eMouseEnterIntoWidget:
    6624             :     // In this case we have to know information about available mouse pointers
    6625           1 :     if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
    6626           1 :       sActivePointersIds->Put(mouseEvent->pointerId,
    6627           3 :                               new PointerInfo(false, mouseEvent->inputSource,
    6628           3 :                                               true));
    6629             :     }
    6630           1 :     break;
    6631             :   case ePointerDown:
    6632             :     // In this case we switch pointer to active state
    6633           0 :     if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
    6634           0 :       sActivePointersIds->Put(pointerEvent->pointerId,
    6635           0 :                               new PointerInfo(true, pointerEvent->inputSource,
    6636           0 :                                               pointerEvent->mIsPrimary));
    6637             :     }
    6638           0 :     break;
    6639             :   case ePointerUp:
    6640             :     // In this case we remove information about pointer or turn off active state
    6641           0 :     if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
    6642           0 :       if(pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
    6643           0 :         sActivePointersIds->Put(pointerEvent->pointerId,
    6644           0 :                                 new PointerInfo(false,
    6645           0 :                                                 pointerEvent->inputSource,
    6646           0 :                                                 pointerEvent->mIsPrimary));
    6647             :       } else {
    6648           0 :         sActivePointersIds->Remove(pointerEvent->pointerId);
    6649             :       }
    6650             :     }
    6651           0 :     break;
    6652             :   case eMouseExitFromWidget:
    6653             :     // In this case we have to remove information about disappeared mouse
    6654             :     // pointers
    6655           1 :     if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
    6656           1 :       sActivePointersIds->Remove(mouseEvent->pointerId);
    6657             :     }
    6658           1 :     break;
    6659             :   default:
    6660           8 :     break;
    6661             :   }
    6662          10 : }
    6663             : 
    6664             : nsIContent*
    6665         231 : PresShell::GetCurrentEventContent()
    6666             : {
    6667         280 :   if (mCurrentEventContent &&
    6668         280 :       mCurrentEventContent->GetComposedDoc() != mDocument) {
    6669           0 :     mCurrentEventContent = nullptr;
    6670           0 :     mCurrentEventFrame = nullptr;
    6671             :   }
    6672         231 :   return mCurrentEventContent;
    6673             : }
    6674             : 
    6675             : nsIFrame*
    6676         223 : PresShell::GetCurrentEventFrame()
    6677             : {
    6678         223 :   if (MOZ_UNLIKELY(mIsDestroying)) {
    6679           0 :     return nullptr;
    6680             :   }
    6681             : 
    6682             :   // GetCurrentEventContent() makes sure the content is still in the
    6683             :   // same document that this pres shell belongs to. If not, then the
    6684             :   // frame shouldn't get an event, nor should we even assume its safe
    6685             :   // to try and find the frame.
    6686         223 :   nsIContent* content = GetCurrentEventContent();
    6687         223 :   if (!mCurrentEventFrame && content) {
    6688           0 :     mCurrentEventFrame = content->GetPrimaryFrame();
    6689           0 :     MOZ_ASSERT(!mCurrentEventFrame ||
    6690             :                mCurrentEventFrame->PresContext()->GetPresShell() == this);
    6691             :   }
    6692         223 :   return mCurrentEventFrame;
    6693             : }
    6694             : 
    6695             : nsIFrame*
    6696         178 : PresShell::GetEventTargetFrame()
    6697             : {
    6698         178 :   return GetCurrentEventFrame();
    6699             : }
    6700             : 
    6701             : already_AddRefed<nsIContent>
    6702           8 : PresShell::GetEventTargetContent(WidgetEvent* aEvent)
    6703             : {
    6704          16 :   nsCOMPtr<nsIContent> content = GetCurrentEventContent();
    6705           8 :   if (!content) {
    6706           0 :     nsIFrame* currentEventFrame = GetCurrentEventFrame();
    6707           0 :     if (currentEventFrame) {
    6708           0 :       currentEventFrame->GetContentForEvent(aEvent, getter_AddRefs(content));
    6709           0 :       NS_ASSERTION(!content || content->GetComposedDoc() == mDocument,
    6710             :                    "handing out content from a different doc");
    6711             :     }
    6712             :   }
    6713          16 :   return content.forget();
    6714             : }
    6715             : 
    6716             : void
    6717          10 : PresShell::PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent)
    6718             : {
    6719          10 :   if (mCurrentEventFrame || mCurrentEventContent) {
    6720           0 :     mCurrentEventFrameStack.InsertElementAt(0, mCurrentEventFrame);
    6721           0 :     mCurrentEventContentStack.InsertObjectAt(mCurrentEventContent, 0);
    6722             :   }
    6723          10 :   mCurrentEventFrame = aFrame;
    6724          10 :   mCurrentEventContent = aContent;
    6725          10 : }
    6726             : 
    6727             : void
    6728          10 : PresShell::PopCurrentEventInfo()
    6729             : {
    6730          10 :   mCurrentEventFrame = nullptr;
    6731          10 :   mCurrentEventContent = nullptr;
    6732             : 
    6733          10 :   if (0 != mCurrentEventFrameStack.Length()) {
    6734           0 :     mCurrentEventFrame = mCurrentEventFrameStack.ElementAt(0);
    6735           0 :     mCurrentEventFrameStack.RemoveElementAt(0);
    6736           0 :     mCurrentEventContent = mCurrentEventContentStack.ObjectAt(0);
    6737           0 :     mCurrentEventContentStack.RemoveObjectAt(0);
    6738             : 
    6739             :     // Don't use it if it has moved to a different document.
    6740           0 :     if (mCurrentEventContent &&
    6741           0 :         mCurrentEventContent->GetComposedDoc() != mDocument) {
    6742           0 :       mCurrentEventContent = nullptr;
    6743           0 :       mCurrentEventFrame = nullptr;
    6744             :     }
    6745             :   }
    6746          10 : }
    6747             : 
    6748           0 : bool PresShell::InZombieDocument(nsIContent *aContent)
    6749             : {
    6750             :   // If a content node points to a null document, or the document is not
    6751             :   // attached to a window, then it is possibly in a zombie document,
    6752             :   // about to be replaced by a newly loading document.
    6753             :   // Such documents cannot handle DOM events.
    6754             :   // It might actually be in a node not attached to any document,
    6755             :   // in which case there is not parent presshell to retarget it to.
    6756           0 :   nsIDocument* doc = aContent->GetComposedDoc();
    6757           0 :   return !doc || !doc->GetWindow();
    6758             : }
    6759             : 
    6760             : already_AddRefed<nsPIDOMWindowOuter>
    6761           0 : PresShell::GetRootWindow()
    6762             : {
    6763           0 :   nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
    6764           0 :   if (window) {
    6765           0 :     nsCOMPtr<nsPIDOMWindowOuter> rootWindow = window->GetPrivateRoot();
    6766           0 :     NS_ASSERTION(rootWindow, "nsPIDOMWindow::GetPrivateRoot() returns NULL");
    6767           0 :     return rootWindow.forget();
    6768             :   }
    6769             : 
    6770             :   // If we don't have DOM window, we're zombie, we should find the root window
    6771             :   // with our parent shell.
    6772           0 :   nsCOMPtr<nsIPresShell> parent = GetParentPresShellForEventHandling();
    6773           0 :   NS_ENSURE_TRUE(parent, nullptr);
    6774           0 :   return parent->GetRootWindow();
    6775             : }
    6776             : 
    6777             : already_AddRefed<nsPIDOMWindowOuter>
    6778           0 : PresShell::GetFocusedDOMWindowInOurWindow()
    6779             : {
    6780           0 :   nsCOMPtr<nsPIDOMWindowOuter> rootWindow = GetRootWindow();
    6781           0 :   NS_ENSURE_TRUE(rootWindow, nullptr);
    6782           0 :   nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    6783           0 :   nsFocusManager::GetFocusedDescendant(rootWindow, true,
    6784           0 :                                        getter_AddRefs(focusedWindow));
    6785           0 :   return focusedWindow.forget();
    6786             : }
    6787             : 
    6788             : already_AddRefed<nsIPresShell>
    6789           0 : PresShell::GetParentPresShellForEventHandling()
    6790             : {
    6791           0 :   NS_ENSURE_TRUE(mPresContext, nullptr);
    6792             : 
    6793             :   // Now, find the parent pres shell and send the event there
    6794           0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem = mPresContext->GetDocShell();
    6795           0 :   if (!treeItem) {
    6796           0 :     treeItem = mForwardingContainer.get();
    6797             :   }
    6798             : 
    6799             :   // Might have gone away, or never been around to start with
    6800           0 :   NS_ENSURE_TRUE(treeItem, nullptr);
    6801             : 
    6802           0 :   nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
    6803           0 :   treeItem->GetParent(getter_AddRefs(parentTreeItem));
    6804           0 :   nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentTreeItem);
    6805           0 :   NS_ENSURE_TRUE(parentDocShell && treeItem != parentTreeItem, nullptr);
    6806             : 
    6807           0 :   nsCOMPtr<nsIPresShell> parentPresShell = parentDocShell->GetPresShell();
    6808           0 :   return parentPresShell.forget();
    6809             : }
    6810             : 
    6811             : nsresult
    6812           0 : PresShell::RetargetEventToParent(WidgetGUIEvent* aEvent,
    6813             :                                  nsEventStatus* aEventStatus)
    6814             : {
    6815             :   // Send this events straight up to the parent pres shell.
    6816             :   // We do this for keystroke events in zombie documents or if either a frame
    6817             :   // or a root content is not present.
    6818             :   // That way at least the UI key bindings can work.
    6819             : 
    6820           0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
    6821           0 :   nsCOMPtr<nsIPresShell> parentPresShell = GetParentPresShellForEventHandling();
    6822           0 :   NS_ENSURE_TRUE(parentPresShell, NS_ERROR_FAILURE);
    6823             : 
    6824             :   // Fake the event as though it's from the parent pres shell's root frame.
    6825           0 :   return parentPresShell->HandleEvent(parentPresShell->GetRootFrame(), aEvent, true, aEventStatus);
    6826             : }
    6827             : 
    6828             : void
    6829           0 : PresShell::DisableNonTestMouseEvents(bool aDisable)
    6830             : {
    6831           0 :   sDisableNonTestMouseEvents = aDisable;
    6832           0 : }
    6833             : 
    6834             : void
    6835          10 : PresShell::RecordMouseLocation(WidgetGUIEvent* aEvent)
    6836             : {
    6837          10 :   if (!mPresContext)
    6838           0 :     return;
    6839             : 
    6840          10 :   if (!mPresContext->IsRoot()) {
    6841           0 :     PresShell* rootPresShell = GetRootPresShell();
    6842           0 :     if (rootPresShell) {
    6843           0 :       rootPresShell->RecordMouseLocation(aEvent);
    6844             :     }
    6845           0 :     return;
    6846             :   }
    6847             : 
    6848          24 :   if ((aEvent->mMessage == eMouseMove &&
    6849          10 :        aEvent->AsMouseEvent()->mReason == WidgetMouseEvent::eReal) ||
    6850          11 :       aEvent->mMessage == eMouseEnterIntoWidget ||
    6851          20 :       aEvent->mMessage == eMouseDown ||
    6852           5 :       aEvent->mMessage == eMouseUp) {
    6853           5 :     nsIFrame* rootFrame = GetRootFrame();
    6854           5 :     if (!rootFrame) {
    6855           0 :       nsView* rootView = mViewManager->GetRootView();
    6856           0 :       mMouseLocation = nsLayoutUtils::TranslateWidgetToView(mPresContext,
    6857             :         aEvent->mWidget, aEvent->mRefPoint, rootView);
    6858           0 :       mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
    6859             :     } else {
    6860           5 :       mMouseLocation =
    6861          10 :         nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
    6862           5 :       mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
    6863             :     }
    6864             : #ifdef DEBUG_MOUSE_LOCATION
    6865             :     if (aEvent->mMessage == eMouseEnterIntoWidget) {
    6866             :       printf("[ps=%p]got mouse enter for %p\n",
    6867             :              this, aEvent->mWidget);
    6868             :     }
    6869             :     printf("[ps=%p]setting mouse location to (%d,%d)\n",
    6870             :            this, mMouseLocation.x, mMouseLocation.y);
    6871             : #endif
    6872           5 :     if (aEvent->mMessage == eMouseEnterIntoWidget) {
    6873           1 :       SynthesizeMouseMove(false);
    6874             :     }
    6875           5 :   } else if (aEvent->mMessage == eMouseExitFromWidget) {
    6876             :     // Although we only care about the mouse moving into an area for which this
    6877             :     // pres shell doesn't receive mouse move events, we don't check which widget
    6878             :     // the mouse exit was for since this seems to vary by platform.  Hopefully
    6879             :     // this won't matter at all since we'll get the mouse move or enter after
    6880             :     // the mouse exit when the mouse moves from one of our widgets into another.
    6881           1 :     mMouseLocation = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    6882           1 :     mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
    6883             : #ifdef DEBUG_MOUSE_LOCATION
    6884             :     printf("[ps=%p]got mouse exit for %p\n",
    6885             :            this, aEvent->mWidget);
    6886             :     printf("[ps=%p]clearing mouse location\n",
    6887             :            this);
    6888             : #endif
    6889             :   }
    6890             : }
    6891             : 
    6892           0 : nsIFrame* GetNearestFrameContainingPresShell(nsIPresShell* aPresShell)
    6893             : {
    6894           0 :   nsView* view = aPresShell->GetViewManager()->GetRootView();
    6895           0 :   while (view && !view->GetFrame()) {
    6896           0 :     view = view->GetParent();
    6897             :   }
    6898             : 
    6899           0 :   nsIFrame* frame = nullptr;
    6900           0 :   if (view) {
    6901           0 :     frame = view->GetFrame();
    6902             :   }
    6903             : 
    6904           0 :   return frame;
    6905             : }
    6906             : 
    6907             : static bool
    6908          20 : FlushThrottledStyles(nsIDocument *aDocument, void *aData)
    6909             : {
    6910          20 :   nsIPresShell* shell = aDocument->GetShell();
    6911          20 :   if (shell && shell->IsVisible()) {
    6912          10 :     nsPresContext* presContext = shell->GetPresContext();
    6913          10 :     if (presContext) {
    6914          10 :       presContext->RestyleManager()->UpdateOnlyAnimationStyles();
    6915             :     }
    6916             :   }
    6917             : 
    6918          20 :   aDocument->EnumerateSubDocuments(FlushThrottledStyles, nullptr);
    6919          20 :   return true;
    6920             : }
    6921             : 
    6922             : /*
    6923             :  * This function handles the preventDefault behavior of pointerdown. When user
    6924             :  * preventDefault on pointerdown, We have to mark the active pointer to prevent
    6925             :  * sebsequent mouse events (except mouse transition events) and default
    6926             :  * behaviors.
    6927             :  *
    6928             :  * We add mPreventMouseEventByContent flag in PointerInfo to represent the
    6929             :  * active pointer won't firing compatible mouse events. It's set to true when
    6930             :  * content preventDefault on pointerdown
    6931             :  */
    6932             : static void
    6933           4 : PostHandlePointerEventsPreventDefault(WidgetPointerEvent* aPointerEvent,
    6934             :                                       WidgetGUIEvent* aMouseOrTouchEvent)
    6935             : {
    6936           4 :   if (!aPointerEvent->mIsPrimary || aPointerEvent->mMessage != ePointerDown ||
    6937           0 :       !aPointerEvent->DefaultPreventedByContent()) {
    6938           8 :     return;
    6939             :   }
    6940           0 :   nsIPresShell::PointerInfo* pointerInfo = nullptr;
    6941           0 :   if (!sActivePointersIds->Get(aPointerEvent->pointerId, &pointerInfo) ||
    6942           0 :       !pointerInfo) {
    6943             :     // We already added the PointerInfo for active pointer when
    6944             :     // PresShell::HandleEvent handling pointerdown event.
    6945             : #ifdef DEBUG
    6946           0 :     MOZ_CRASH("Got ePointerDown w/o active pointer info!!");
    6947             : #endif // #ifdef DEBUG
    6948             :     return;
    6949             :   }
    6950             :   // PreventDefault only applied for active pointers.
    6951           0 :   if (!pointerInfo->mActiveState) {
    6952           0 :     return;
    6953             :   }
    6954           0 :   aMouseOrTouchEvent->PreventDefault(false);
    6955           0 :   pointerInfo->mPreventMouseEventByContent = true;
    6956             : }
    6957             : 
    6958             : /*
    6959             :  * This function handles the case when content had called preventDefault on the
    6960             :  * active pointer. In that case we have to prevent firing subsequent mouse
    6961             :  * to content. We check the flag PointerInfo::mPreventMouseEventByContent and
    6962             :  * call PreventDefault(false) to stop default behaviors and stop firing mouse
    6963             :  * events to content and chrome.
    6964             :  *
    6965             :  * note: mouse transition events are excluded
    6966             :  * note: we have to clean mPreventMouseEventByContent on pointerup for those
    6967             :  *       devices support hover
    6968             :  * note: we don't suppress firing mouse events to chrome and system group
    6969             :  *       handlers because they may implement default behaviors
    6970             :  */
    6971             : static void
    6972           4 : PreHandlePointerEventsPreventDefault(WidgetPointerEvent* aPointerEvent,
    6973             :                                      WidgetGUIEvent* aMouseOrTouchEvent)
    6974             : {
    6975           4 :   if (!aPointerEvent->mIsPrimary || aPointerEvent->mMessage == ePointerDown) {
    6976           4 :     return;
    6977             :   }
    6978           4 :   nsIPresShell::PointerInfo* pointerInfo = nullptr;
    6979           8 :   if (!sActivePointersIds->Get(aPointerEvent->pointerId, &pointerInfo) ||
    6980           4 :       !pointerInfo) {
    6981             :     // The PointerInfo for active pointer should be added for normal cases. But
    6982             :     // in some cases, we may receive mouse events before adding PointerInfo in
    6983             :     // sActivePointersIds. (e.g. receive mousemove before eMouseEnterIntoWidget
    6984             :     // or change preference 'dom.w3c_pointer_events.enabled' from off to on).
    6985             :     // In these cases, we could ignore them because they are not the events
    6986             :     // between a DefaultPrevented pointerdown and the corresponding pointerup.
    6987           0 :     return;
    6988             :   }
    6989           4 :   if (!pointerInfo->mPreventMouseEventByContent) {
    6990           4 :     return;
    6991             :   }
    6992           0 :   aMouseOrTouchEvent->PreventDefault(false);
    6993           0 :   if (aPointerEvent->mMessage == ePointerUp) {
    6994           0 :     pointerInfo->mPreventMouseEventByContent = false;
    6995             :   }
    6996             : }
    6997             : 
    6998             : static nsresult
    6999          10 : DispatchPointerFromMouseOrTouch(PresShell* aShell,
    7000             :                                 nsIFrame* aFrame,
    7001             :                                 WidgetGUIEvent* aEvent,
    7002             :                                 bool aDontRetargetEvents,
    7003             :                                 nsEventStatus* aStatus,
    7004             :                                 nsIContent** aTargetContent)
    7005             : {
    7006          10 :   EventMessage pointerMessage = eVoidEvent;
    7007          10 :   if (aEvent->mClass == eMouseEventClass) {
    7008           6 :     WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
    7009             :     // 1. If it is not mouse then it is likely will come as touch event
    7010             :     // 2. We don't synthesize pointer events for those events that are not
    7011             :     //    dispatched to DOM.
    7012          12 :     if (!mouseEvent->convertToPointer ||
    7013           6 :         !aEvent->IsAllowedToDispatchDOMEvent()) {
    7014           2 :       return NS_OK;
    7015             :     }
    7016           6 :     int16_t button = mouseEvent->button;
    7017           6 :     switch (mouseEvent->mMessage) {
    7018             :     case eMouseMove:
    7019           4 :       button = WidgetMouseEvent::eNoButton;
    7020           4 :       pointerMessage = ePointerMove;
    7021           4 :       break;
    7022             :     case eMouseUp:
    7023           0 :       pointerMessage = mouseEvent->buttons ? ePointerMove : ePointerUp;
    7024           0 :       break;
    7025             :     case eMouseDown:
    7026           0 :       pointerMessage =
    7027           0 :         mouseEvent->buttons & ~nsContentUtils::GetButtonsFlagForButton(button) ?
    7028             :         ePointerMove : ePointerDown;
    7029           0 :       break;
    7030             :     default:
    7031           2 :       return NS_OK;
    7032             :     }
    7033             : 
    7034           8 :     WidgetPointerEvent event(*mouseEvent);
    7035           4 :     event.pointerId = mouseEvent->pointerId;
    7036           4 :     event.inputSource = mouseEvent->inputSource;
    7037           4 :     event.mMessage = pointerMessage;
    7038           4 :     event.button = button;
    7039           4 :     event.buttons = mouseEvent->buttons;
    7040           4 :     event.pressure = event.buttons ?
    7041           0 :                      mouseEvent->pressure ? mouseEvent->pressure : 0.5f :
    7042             :                      0.0f;
    7043           4 :     event.convertToPointer = mouseEvent->convertToPointer = false;
    7044           4 :     PreHandlePointerEventsPreventDefault(&event, aEvent);
    7045           4 :     aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
    7046           4 :                         aTargetContent);
    7047           4 :     PostHandlePointerEventsPreventDefault(&event, aEvent);
    7048           4 :   } else if (aEvent->mClass == eTouchEventClass) {
    7049           0 :     WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
    7050           0 :     int16_t button = WidgetMouseEvent::eLeftButton;
    7051           0 :     int16_t buttons = WidgetMouseEvent::eLeftButtonFlag;
    7052             :     // loop over all touches and dispatch pointer events on each touch
    7053             :     // copy the event
    7054           0 :     switch (touchEvent->mMessage) {
    7055             :     case eTouchMove:
    7056           0 :       pointerMessage = ePointerMove;
    7057           0 :       button = WidgetMouseEvent::eNoButton;
    7058           0 :       break;
    7059             :     case eTouchEnd:
    7060           0 :       pointerMessage = ePointerUp;
    7061           0 :       buttons = WidgetMouseEvent::eNoButtonFlag;
    7062           0 :       break;
    7063             :     case eTouchStart:
    7064           0 :       pointerMessage = ePointerDown;
    7065           0 :       break;
    7066             :     case eTouchCancel:
    7067             :     case eTouchPointerCancel:
    7068           0 :       pointerMessage = ePointerCancel;
    7069           0 :       break;
    7070             :     default:
    7071           0 :       return NS_OK;
    7072             :     }
    7073             : 
    7074           0 :     for (uint32_t i = 0; i < touchEvent->mTouches.Length(); ++i) {
    7075           0 :       mozilla::dom::Touch* touch = touchEvent->mTouches[i];
    7076           0 :       if (!TouchManager::ShouldConvertTouchToPointer(touch, touchEvent)) {
    7077           0 :         continue;
    7078             :       }
    7079             : 
    7080           0 :       WidgetPointerEvent event(touchEvent->IsTrusted(), pointerMessage,
    7081           0 :                                touchEvent->mWidget);
    7082           0 :       event.mIsPrimary = i == 0;
    7083           0 :       event.pointerId = touch->Identifier();
    7084           0 :       event.mRefPoint = touch->mRefPoint;
    7085           0 :       event.mModifiers = touchEvent->mModifiers;
    7086           0 :       event.mWidth = touch->RadiusX();
    7087           0 :       event.mHeight = touch->RadiusY();
    7088           0 :       event.tiltX = touch->tiltX;
    7089           0 :       event.tiltY = touch->tiltY;
    7090           0 :       event.mTime = touchEvent->mTime;
    7091           0 :       event.mTimeStamp = touchEvent->mTimeStamp;
    7092           0 :       event.mFlags = touchEvent->mFlags;
    7093           0 :       event.button = button;
    7094           0 :       event.buttons = buttons;
    7095           0 :       event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
    7096           0 :       event.convertToPointer = touch->convertToPointer = false;
    7097           0 :       PreHandlePointerEventsPreventDefault(&event, aEvent);
    7098           0 :       aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
    7099           0 :                           aTargetContent);
    7100           0 :       PostHandlePointerEventsPreventDefault(&event, aEvent);
    7101             :     }
    7102             :   }
    7103           8 :   return NS_OK;
    7104             : }
    7105             : 
    7106             : class ReleasePointerCaptureCaller final
    7107             : {
    7108             : public:
    7109          10 :   ReleasePointerCaptureCaller()
    7110          10 :     : mPointerEvent(nullptr)
    7111             :   {
    7112          10 :   }
    7113          10 :   ~ReleasePointerCaptureCaller()
    7114          10 :   {
    7115          10 :     if (mPointerEvent) {
    7116           0 :       nsIPresShell::ReleasePointerCapturingContent(mPointerEvent->pointerId);
    7117           0 :       nsIPresShell::CheckPointerCaptureState(mPointerEvent);
    7118             :     }
    7119          10 :   }
    7120             : 
    7121           0 :   void SetTarget(const WidgetPointerEvent* aPointerEvent)
    7122             :   {
    7123           0 :     MOZ_ASSERT(aPointerEvent);
    7124           0 :     mPointerEvent = aPointerEvent;
    7125           0 :   }
    7126             : 
    7127             : private:
    7128             :   // This is synchronously used inside PresShell::HandleEvent.
    7129             :   const WidgetPointerEvent* mPointerEvent;
    7130             : };
    7131             : 
    7132             : bool
    7133           0 : PresShell::CanDispatchEvent(const WidgetGUIEvent* aEvent) const
    7134             : {
    7135             :   bool rv =
    7136           0 :     mPresContext && !mHaveShutDown && nsContentUtils::IsSafeToRunScript();
    7137           0 :   if (aEvent) {
    7138           0 :     rv &= (aEvent && aEvent->mWidget && !aEvent->mWidget->Destroyed());
    7139             :   }
    7140           0 :   return rv;
    7141             : }
    7142             : 
    7143             : nsresult
    7144          10 : PresShell::HandleEvent(nsIFrame* aFrame,
    7145             :                        WidgetGUIEvent* aEvent,
    7146             :                        bool aDontRetargetEvents,
    7147             :                        nsEventStatus* aEventStatus,
    7148             :                        nsIContent** aTargetContent)
    7149             : {
    7150             : #ifdef MOZ_TASK_TRACER
    7151             :   Maybe<AutoSourceEvent> taskTracerEvent;
    7152             :   if (MOZ_UNLIKELY(IsStartLogging())) {
    7153             :     // Make touch events, mouse events and hardware key events to be
    7154             :     // the source events of TaskTracer, and originate the rest
    7155             :     // correlation tasks from here.
    7156             :     SourceEventType type = SourceEventType::Unknown;
    7157             :     if (aEvent->AsTouchEvent()) {
    7158             :       type = SourceEventType::Touch;
    7159             :     } else if (aEvent->AsMouseEvent()) {
    7160             :       type = SourceEventType::Mouse;
    7161             :     } else if (aEvent->AsKeyboardEvent()) {
    7162             :       type = SourceEventType::Key;
    7163             :     }
    7164             :     taskTracerEvent.emplace(type);
    7165             :   }
    7166             : #endif
    7167             : 
    7168          10 :   NS_ASSERTION(aFrame, "aFrame should be not null");
    7169             : 
    7170             :   // Update the latest focus sequence number with this new sequence number
    7171          10 :   if (mAPZFocusSequenceNumber < aEvent->mFocusSequenceNumber) {
    7172           6 :     mAPZFocusSequenceNumber = aEvent->mFocusSequenceNumber;
    7173             :   }
    7174             : 
    7175          10 :   if (sPointerEventEnabled) {
    7176          20 :     AutoWeakFrame weakFrame(aFrame);
    7177          20 :     nsCOMPtr<nsIContent> targetContent;
    7178          10 :     DispatchPointerFromMouseOrTouch(this, aFrame, aEvent, aDontRetargetEvents,
    7179             :                                     aEventStatus,
    7180          20 :                                     getter_AddRefs(targetContent));
    7181          10 :     if (!weakFrame.IsAlive()) {
    7182           0 :       if (targetContent) {
    7183           0 :         aFrame = targetContent->GetPrimaryFrame();
    7184           0 :         if (!aFrame) {
    7185           0 :           PushCurrentEventInfo(aFrame, targetContent);
    7186           0 :           nsresult rv = HandleEventInternal(aEvent, aEventStatus, true);
    7187           0 :           PopCurrentEventInfo();
    7188           0 :           return rv;
    7189             :         }
    7190             :       } else {
    7191           0 :         return NS_OK;
    7192             :       }
    7193             :     }
    7194             :   }
    7195             : 
    7196          10 :   if (mIsDestroying ||
    7197           0 :       (sDisableNonTestMouseEvents && !aEvent->mFlags.mIsSynthesizedForTests &&
    7198           0 :        aEvent->HasMouseEventMessage())) {
    7199           0 :     return NS_OK;
    7200             :   }
    7201             : 
    7202          10 :   RecordMouseLocation(aEvent);
    7203             : 
    7204          10 :   if (AccessibleCaretEnabled(mDocument->GetDocShell())) {
    7205             :     // We have to target the focus window because regardless of where the
    7206             :     // touch goes, we want to access the copy paste manager.
    7207           0 :     nsCOMPtr<nsPIDOMWindowOuter> window = GetFocusedDOMWindowInOurWindow();
    7208             :     nsCOMPtr<nsIDocument> retargetEventDoc =
    7209           0 :       window ? window->GetExtantDoc() : nullptr;
    7210             :     nsCOMPtr<nsIPresShell> presShell =
    7211           0 :       retargetEventDoc ? retargetEventDoc->GetShell() : nullptr;
    7212             : 
    7213             :     RefPtr<AccessibleCaretEventHub> eventHub =
    7214           0 :       presShell ? presShell->GetAccessibleCaretEventHub() : nullptr;
    7215           0 :     if (eventHub && *aEventStatus != nsEventStatus_eConsumeNoDefault) {
    7216             :       // Don't dispatch event to AccessibleCaretEventHub when the event status
    7217             :       // is nsEventStatus_eConsumeNoDefault. This might be happened when content
    7218             :       // preventDefault on the pointer events. In such case, we also call
    7219             :       // preventDefault on mouse events to stop default behaviors.
    7220           0 :       *aEventStatus = eventHub->HandleEvent(aEvent);
    7221           0 :       if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
    7222             :         // If the event is consumed, cancel APZC panning by setting
    7223             :         // mMultipleActionsPrevented.
    7224           0 :         aEvent->mFlags.mMultipleActionsPrevented = true;
    7225           0 :         return NS_OK;
    7226             :       }
    7227             :     }
    7228             :   }
    7229             : 
    7230          10 :   if (sPointerEventEnabled) {
    7231          10 :     UpdateActivePointerState(aEvent);
    7232             :   }
    7233             : 
    7234          10 :   if (!nsContentUtils::IsSafeToRunScript() &&
    7235           0 :       aEvent->IsAllowedToDispatchDOMEvent()) {
    7236           0 :     if (aEvent->mClass == eCompositionEventClass) {
    7237           0 :       IMEStateManager::OnCompositionEventDiscarded(
    7238           0 :         aEvent->AsCompositionEvent());
    7239             :     }
    7240             : #ifdef DEBUG
    7241           0 :     if (aEvent->IsIMERelatedEvent()) {
    7242           0 :       nsPrintfCString warning("%d event is discarded", aEvent->mMessage);
    7243           0 :       NS_WARNING(warning.get());
    7244             :     }
    7245             : #endif
    7246           0 :     nsContentUtils::WarnScriptWasIgnored(GetDocument());
    7247           0 :     return NS_OK;
    7248             :   }
    7249             : 
    7250          16 :   nsIContent* capturingContent = ((aEvent->mClass == ePointerEventClass ||
    7251          12 :                                    aEvent->mClass == eWheelEventClass ||
    7252           6 :                                    aEvent->HasMouseEventMessage())
    7253          20 :                                  ? GetCapturingContent()
    7254          10 :                                  : nullptr);
    7255             : 
    7256          20 :   nsCOMPtr<nsIDocument> retargetEventDoc;
    7257          10 :   if (!aDontRetargetEvents) {
    7258             :     // key and IME related events should not cross top level window boundary.
    7259             :     // Basically, such input events should be fired only on focused widget.
    7260             :     // However, some IMEs might need to clean up composition after focused
    7261             :     // window is deactivated.  And also some tests on MozMill want to test key
    7262             :     // handling on deactivated window because MozMill window can be activated
    7263             :     // during tests.  So, there is no merit the events should be redirected to
    7264             :     // active window.  So, the events should be handled on the last focused
    7265             :     // content in the last focused DOM window in same top level window.
    7266             :     // Note, if no DOM window has been focused yet, we can discard the events.
    7267          10 :     if (aEvent->IsTargetedAtFocusedWindow()) {
    7268           0 :       nsCOMPtr<nsPIDOMWindowOuter> window = GetFocusedDOMWindowInOurWindow();
    7269             :       // No DOM window in same top level window has not been focused yet,
    7270             :       // discard the events.
    7271           0 :       if (!window) {
    7272           0 :         return NS_OK;
    7273             :       }
    7274             : 
    7275           0 :       retargetEventDoc = window->GetExtantDoc();
    7276           0 :       if (!retargetEventDoc)
    7277           0 :         return NS_OK;
    7278          10 :     } else if (capturingContent) {
    7279             :       // if the mouse is being captured then retarget the mouse event at the
    7280             :       // document that is being captured.
    7281           0 :       retargetEventDoc = capturingContent->GetComposedDoc();
    7282             : #ifdef ANDROID
    7283             :     } else if ((aEvent->mClass == eTouchEventClass) ||
    7284             :                (aEvent->mClass == eMouseEventClass) ||
    7285             :                (aEvent->mClass == eWheelEventClass)) {
    7286             :       retargetEventDoc = GetPrimaryContentDocument();
    7287             : #endif
    7288             :     }
    7289             : 
    7290          10 :     if (retargetEventDoc) {
    7291           0 :       nsCOMPtr<nsIPresShell> presShell = retargetEventDoc->GetShell();
    7292           0 :       if (!presShell)
    7293           0 :         return NS_OK;
    7294             : 
    7295           0 :       if (presShell != this) {
    7296           0 :         nsIFrame* frame = presShell->GetRootFrame();
    7297           0 :         if (!frame) {
    7298           0 :           if (aEvent->mMessage == eQueryTextContent ||
    7299           0 :               aEvent->IsContentCommandEvent()) {
    7300           0 :             return NS_OK;
    7301             :           }
    7302             : 
    7303           0 :           frame = GetNearestFrameContainingPresShell(presShell);
    7304             :         }
    7305             : 
    7306           0 :         if (!frame)
    7307           0 :           return NS_OK;
    7308             : 
    7309           0 :         nsCOMPtr<nsIPresShell> shell = frame->PresContext()->GetPresShell();
    7310           0 :         return shell->HandleEvent(frame, aEvent, true, aEventStatus);
    7311             :       }
    7312             :     }
    7313             :   }
    7314             : 
    7315          20 :   if (aEvent->mClass == eKeyboardEventClass &&
    7316          10 :       mDocument && mDocument->EventHandlingSuppressed()) {
    7317           0 :     if (aEvent->mMessage == eKeyDown) {
    7318           0 :       mNoDelayedKeyEvents = true;
    7319           0 :     } else if (!mNoDelayedKeyEvents) {
    7320           0 :       DelayedEvent* event = new DelayedKeyEvent(aEvent->AsKeyboardEvent());
    7321           0 :       if (!mDelayedEvents.AppendElement(event)) {
    7322           0 :         delete event;
    7323             :       }
    7324             :     }
    7325           0 :     aEvent->mFlags.mIsSuppressedOrDelayed = true;
    7326           0 :     return NS_OK;
    7327             :   }
    7328             : 
    7329          10 :   nsIFrame* frame = aFrame;
    7330             : 
    7331          10 :   if (aEvent->IsUsingCoordinates()) {
    7332          20 :     ReleasePointerCaptureCaller releasePointerCaptureCaller;
    7333          10 :     if (mDocument) {
    7334          10 :       if (aEvent->mClass == eTouchEventClass) {
    7335           0 :         nsIDocument::UnlockPointer();
    7336             :       }
    7337             : 
    7338          20 :       AutoWeakFrame weakFrame(frame);
    7339             :       {  // scope for scriptBlocker.
    7340          20 :         nsAutoScriptBlocker scriptBlocker;
    7341          10 :         FlushThrottledStyles(GetRootPresShell()->GetDocument(), nullptr);
    7342             :       }
    7343             : 
    7344             : 
    7345          10 :       if (!weakFrame.IsAlive()) {
    7346           0 :         frame = GetNearestFrameContainingPresShell(this);
    7347             :       }
    7348             :     }
    7349             : 
    7350          10 :     if (!frame) {
    7351           0 :       NS_WARNING("Nothing to handle this event!");
    7352           0 :       return NS_OK;
    7353             :     }
    7354             : 
    7355          10 :     nsPresContext* framePresContext = frame->PresContext();
    7356          10 :     nsPresContext* rootPresContext = framePresContext->GetRootPresContext();
    7357          10 :     NS_ASSERTION(rootPresContext == mPresContext->GetRootPresContext(),
    7358             :                  "How did we end up outside the connected prescontext/viewmanager hierarchy?");
    7359             :     nsIFrame* popupFrame =
    7360          10 :       nsLayoutUtils::GetPopupFrameForEventCoordinates(rootPresContext, aEvent);
    7361             :     // If a remote browser is currently capturing input break out if we
    7362             :     // detect a chrome generated popup.
    7363          10 :     if (popupFrame && capturingContent &&
    7364           0 :         EventStateManager::IsRemoteTarget(capturingContent)) {
    7365           0 :       capturingContent = nullptr;
    7366             :     }
    7367             :     // If the popupFrame is an ancestor of the 'frame', the frame should
    7368             :     // handle the event, otherwise, the popup should handle it.
    7369          10 :     if (popupFrame &&
    7370           0 :         !nsContentUtils::ContentIsCrossDocDescendantOf(
    7371           0 :            framePresContext->GetPresShell()->GetDocument(),
    7372           0 :            popupFrame->GetContent())) {
    7373             : 
    7374             :       // If we aren't starting our event dispatch from the root frame of the
    7375             :       // root prescontext, then someone must be capturing the mouse. In that
    7376             :       // case we only want to use the popup list if the capture is
    7377             :       // inside the popup.
    7378           0 :       if (framePresContext == rootPresContext &&
    7379           0 :           frame == mFrameConstructor->GetRootFrame()) {
    7380           0 :         frame = popupFrame;
    7381           0 :       } else if (capturingContent &&
    7382           0 :                  nsContentUtils::ContentIsDescendantOf(
    7383           0 :                    capturingContent, popupFrame->GetContent())) {
    7384           0 :         frame = popupFrame;
    7385             :       }
    7386             :     }
    7387             : 
    7388          10 :     bool captureRetarget = false;
    7389          10 :     if (capturingContent) {
    7390             :       // If a capture is active, determine if the docshell is visible. If not,
    7391             :       // clear the capture and target the mouse event normally instead. This
    7392             :       // would occur if the mouse button is held down while a tab change occurs.
    7393             :       // If the docshell is visible, look for a scrolling container.
    7394             :       bool vis;
    7395             :       nsCOMPtr<nsIBaseWindow> baseWin =
    7396           0 :         do_QueryInterface(mPresContext->GetContainerWeak());
    7397           0 :       if (baseWin && NS_SUCCEEDED(baseWin->GetVisibility(&vis)) && vis) {
    7398           0 :         captureRetarget = gCaptureInfo.mRetargetToElement;
    7399           0 :         if (!captureRetarget) {
    7400             :           // A check was already done above to ensure that capturingContent is
    7401             :           // in this presshell.
    7402           0 :           NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(),
    7403             :                        "Unexpected document");
    7404           0 :           nsIFrame* captureFrame = capturingContent->GetPrimaryFrame();
    7405           0 :           if (captureFrame) {
    7406           0 :             if (capturingContent->IsHTMLElement(nsGkAtoms::select)) {
    7407             :               // a dropdown <select> has a child in its selectPopupList and we should
    7408             :               // capture on that instead.
    7409           0 :               nsIFrame* childFrame = captureFrame->GetChildList(nsIFrame::kSelectPopupList).FirstChild();
    7410           0 :               if (childFrame) {
    7411           0 :                 captureFrame = childFrame;
    7412             :               }
    7413             :             }
    7414             : 
    7415             :             // scrollable frames should use the scrolling container as
    7416             :             // the root instead of the document
    7417           0 :             nsIScrollableFrame* scrollFrame = do_QueryFrame(captureFrame);
    7418           0 :             if (scrollFrame) {
    7419           0 :               frame = scrollFrame->GetScrolledFrame();
    7420             :             }
    7421             :           }
    7422             :         }
    7423             :       }
    7424             :       else {
    7425           0 :         ClearMouseCapture(nullptr);
    7426           0 :         capturingContent = nullptr;
    7427             :       }
    7428             :     }
    7429             : 
    7430             :     // all touch events except for touchstart use a captured target
    7431          10 :     if (aEvent->mClass == eTouchEventClass && aEvent->mMessage != eTouchStart) {
    7432           0 :       captureRetarget = true;
    7433             :     }
    7434             : 
    7435          10 :     WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
    7436          11 :     bool isWindowLevelMouseExit = (aEvent->mMessage == eMouseExitFromWidget) &&
    7437          11 :       (mouseEvent && mouseEvent->mExitFrom == WidgetMouseEvent::eTopLevel);
    7438             : 
    7439             :     // Get the frame at the event point. However, don't do this if we're
    7440             :     // capturing and retargeting the event because the captured frame will
    7441             :     // be used instead below. Also keep using the root frame if we're dealing
    7442             :     // with a window-level mouse exit event since we want to start sending
    7443             :     // mouse out events at the root EventStateManager.
    7444          10 :     if (!captureRetarget && !isWindowLevelMouseExit) {
    7445           9 :       nsPoint eventPoint;
    7446           9 :       uint32_t flags = 0;
    7447           9 :       if (aEvent->mMessage == eTouchStart) {
    7448           0 :         if (gfxPrefs::APZAllowZooming()) {
    7449             :           // Setting this flag will skip the scrollbars on the root frame from
    7450             :           // participating in hit-testing, and we only want that to happen on
    7451             :           // zoomable platforms (for now).
    7452           0 :           flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME;
    7453             :         }
    7454           0 :         WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
    7455             :         // if this is a continuing session, ensure that all these events are
    7456             :         // in the same document by taking the target of the events already in
    7457             :         // the capture list
    7458           0 :         nsCOMPtr<nsIContent> anyTarget;
    7459           0 :         if (touchEvent->mTouches.Length() > 1) {
    7460           0 :           anyTarget = TouchManager::GetAnyCapturedTouchTarget();
    7461             :         }
    7462             : 
    7463           0 :         for (int32_t i = touchEvent->mTouches.Length(); i; ) {
    7464           0 :           --i;
    7465           0 :           dom::Touch* touch = touchEvent->mTouches[i];
    7466             : 
    7467           0 :           int32_t id = touch->Identifier();
    7468           0 :           if (!TouchManager::HasCapturedTouch(id)) {
    7469             :             // find the target for this touch
    7470           0 :             eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
    7471             :                                                               touch->mRefPoint,
    7472             :                                                               frame);
    7473             :             nsIFrame* target = FindFrameTargetedByInputEvent(aEvent,
    7474             :                                                              frame,
    7475             :                                                              eventPoint,
    7476           0 :                                                              flags);
    7477           0 :             if (target && !anyTarget) {
    7478           0 :               target->GetContentForEvent(aEvent, getter_AddRefs(anyTarget));
    7479           0 :               while (anyTarget && !anyTarget->IsElement()) {
    7480           0 :                 anyTarget = anyTarget->GetParent();
    7481             :               }
    7482           0 :               touch->SetTarget(anyTarget);
    7483             :             } else {
    7484           0 :               nsIFrame* newTargetFrame = nullptr;
    7485           0 :               for (nsIFrame* f = target; f;
    7486             :                    f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
    7487           0 :                 if (f->PresContext()->Document() == anyTarget->OwnerDoc()) {
    7488           0 :                   newTargetFrame = f;
    7489           0 :                   break;
    7490             :                 }
    7491             :                 // We must be in a subdocument so jump directly to the root frame.
    7492             :                 // GetParentOrPlaceholderForCrossDoc gets called immediately to
    7493             :                 // jump up to the containing document.
    7494           0 :                 f = f->PresContext()->GetPresShell()->GetRootFrame();
    7495             :               }
    7496             : 
    7497             :               // if we couldn't find a target frame in the same document as
    7498             :               // anyTarget, remove the touch from the capture touch list, as
    7499             :               // well as the event->mTouches array. touchmove events that aren't
    7500             :               // in the captured touch list will be discarded
    7501           0 :               if (!newTargetFrame) {
    7502           0 :                 touchEvent->mTouches.RemoveElementAt(i);
    7503             :               } else {
    7504           0 :                 target = newTargetFrame;
    7505           0 :                 nsCOMPtr<nsIContent> targetContent;
    7506           0 :                 target->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
    7507           0 :                 while (targetContent && !targetContent->IsElement()) {
    7508           0 :                   targetContent = targetContent->GetParent();
    7509             :                 }
    7510           0 :                 touch->SetTarget(targetContent);
    7511             :               }
    7512             :             }
    7513           0 :             if (target) {
    7514           0 :               frame = target;
    7515             :             }
    7516             :           } else {
    7517             :             // This touch is an old touch, we need to ensure that is not
    7518             :             // marked as changed and set its target correctly
    7519           0 :             touch->mChanged = false;
    7520           0 :             int32_t id = touch->Identifier();
    7521             : 
    7522           0 :             RefPtr<dom::Touch> oldTouch = TouchManager::GetCapturedTouch(id);
    7523           0 :             if (oldTouch) {
    7524           0 :               touch->SetTarget(oldTouch->mTarget);
    7525             :             }
    7526             :           }
    7527             :         }
    7528             :       } else {
    7529           9 :         eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
    7530             :       }
    7531          14 :       if (mouseEvent && mouseEvent->mClass == eMouseEventClass &&
    7532           5 :           mouseEvent->mIgnoreRootScrollFrame) {
    7533           0 :         flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME;
    7534             :       }
    7535             :       nsIFrame* target =
    7536           9 :         FindFrameTargetedByInputEvent(aEvent, frame, eventPoint, flags);
    7537           9 :       if (target) {
    7538           9 :         frame = target;
    7539             :       }
    7540             :     }
    7541             : 
    7542             :     // if a node is capturing the mouse, check if the event needs to be
    7543             :     // retargeted at the capturing content instead. This will be the case when
    7544             :     // capture retargeting is being used, no frame was found or the frame's
    7545             :     // content is not a descendant of the capturing content.
    7546          10 :     if (capturingContent &&
    7547           0 :         (gCaptureInfo.mRetargetToElement || !frame->GetContent() ||
    7548           0 :          !nsContentUtils::ContentIsCrossDocDescendantOf(frame->GetContent(),
    7549             :                                                         capturingContent))) {
    7550             :       // A check was already done above to ensure that capturingContent is
    7551             :       // in this presshell.
    7552           0 :       NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(),
    7553             :                    "Unexpected document");
    7554           0 :       nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame();
    7555           0 :       if (capturingFrame) {
    7556           0 :         frame = capturingFrame;
    7557             :       }
    7558             :     }
    7559             : 
    7560          10 :     if (aEvent->mClass == ePointerEventClass) {
    7561           4 :       if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
    7562             :         // Try to keep frame for following check, because
    7563             :         // frame can be damaged during CheckPointerCaptureState.
    7564           8 :         AutoWeakFrame frameKeeper(frame);
    7565             :         // Handle pending pointer capture before any pointer events except
    7566             :         // gotpointercapture / lostpointercapture.
    7567           4 :         CheckPointerCaptureState(pointerEvent);
    7568             :         // Prevent application crashes, in case damaged frame.
    7569           4 :         if (!frameKeeper.IsAlive()) {
    7570           0 :           frame = nullptr;
    7571             :         }
    7572             :         // Implicit pointer capture for touch
    7573           4 :         if (frame && sPointerEventImplicitCapture &&
    7574           0 :             pointerEvent->mMessage == ePointerDown &&
    7575           0 :             pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
    7576           0 :           nsCOMPtr<nsIContent> targetContent;
    7577           0 :           frame->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
    7578           0 :           while (targetContent && !targetContent->IsElement()) {
    7579           0 :             targetContent = targetContent->GetParent();
    7580             :           }
    7581           0 :           if (targetContent) {
    7582           0 :             SetPointerCapturingContent(pointerEvent->pointerId, targetContent);
    7583             :           }
    7584             :         }
    7585             :       }
    7586             :     }
    7587             : 
    7588             :     // Mouse events should be fired to the same target as their mapped pointer
    7589             :     // events
    7590          16 :     if ((aEvent->mClass == ePointerEventClass ||
    7591          16 :          aEvent->mClass == eMouseEventClass) &&
    7592          20 :         aEvent->mMessage != ePointerDown && aEvent->mMessage != eMouseDown) {
    7593          10 :       if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
    7594          10 :         uint32_t pointerId = mouseEvent->pointerId;
    7595             :         nsIContent* pointerCapturingContent =
    7596          10 :           GetPointerCapturingContent(pointerId);
    7597             : 
    7598          10 :         if (pointerCapturingContent) {
    7599           0 :           if (nsIFrame* capturingFrame = pointerCapturingContent->GetPrimaryFrame()) {
    7600           0 :             frame = capturingFrame;
    7601             :           }
    7602             : 
    7603           0 :           if (aEvent->mMessage == ePointerUp ||
    7604           0 :               aEvent->mMessage == ePointerCancel) {
    7605             :             // Implicitly releasing capture for given pointer.
    7606             :             // ePointerLostCapture should be send after ePointerUp or
    7607             :             // ePointerCancel.
    7608           0 :             WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
    7609           0 :             MOZ_ASSERT(pointerEvent);
    7610           0 :             releasePointerCaptureCaller.SetTarget(pointerEvent);
    7611             :           }
    7612             :         }
    7613             :       }
    7614             :     }
    7615             : 
    7616             :     // Suppress mouse event if it's being targeted at an element inside
    7617             :     // a document which needs events suppressed
    7618          16 :     if (aEvent->mClass == eMouseEventClass &&
    7619           6 :         frame->PresContext()->Document()->EventHandlingSuppressed()) {
    7620           0 :       if (aEvent->mMessage == eMouseDown) {
    7621           0 :         mNoDelayedMouseEvents = true;
    7622           0 :       } else if (!mNoDelayedMouseEvents && (aEvent->mMessage == eMouseUp ||
    7623             :         // contextmenu is triggered after right mouseup on Windows and right
    7624             :         // mousedown on other platforms.
    7625           0 :         aEvent->mMessage == eContextMenu)) {
    7626           0 :         DelayedEvent* event = new DelayedMouseEvent(aEvent->AsMouseEvent());
    7627           0 :         if (!mDelayedEvents.AppendElement(event)) {
    7628           0 :           delete event;
    7629             :         }
    7630             :       }
    7631           0 :       return NS_OK;
    7632             :     }
    7633             : 
    7634          10 :     if (!frame) {
    7635           0 :       NS_WARNING("Nothing to handle this event!");
    7636           0 :       return NS_OK;
    7637             :     }
    7638             : 
    7639             :     PresShell* shell =
    7640          10 :         static_cast<PresShell*>(frame->PresContext()->PresShell());
    7641          10 :     switch (aEvent->mMessage) {
    7642             :       case eTouchMove:
    7643             :       case eTouchCancel:
    7644             :       case eTouchEnd: {
    7645             :         // get the correct shell to dispatch to
    7646           0 :         WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
    7647           0 :         for (dom::Touch* touch : touchEvent->mTouches) {
    7648           0 :           if (!touch) {
    7649           0 :             break;
    7650             :           }
    7651             : 
    7652             :           RefPtr<dom::Touch> oldTouch =
    7653           0 :             TouchManager::GetCapturedTouch(touch->Identifier());
    7654           0 :           if (!oldTouch) {
    7655           0 :             break;
    7656             :           }
    7657             : 
    7658             :           nsCOMPtr<nsIContent> content =
    7659           0 :             do_QueryInterface(oldTouch->GetTarget());
    7660           0 :           if (!content) {
    7661           0 :             break;
    7662             :           }
    7663             : 
    7664           0 :           nsIFrame* contentFrame = content->GetPrimaryFrame();
    7665           0 :           if (!contentFrame) {
    7666           0 :             break;
    7667             :           }
    7668             : 
    7669             :           shell = static_cast<PresShell*>(
    7670           0 :                       contentFrame->PresContext()->PresShell());
    7671           0 :           if (shell) {
    7672           0 :             break;
    7673             :           }
    7674             :         }
    7675           0 :         break;
    7676             :       }
    7677             :     default:
    7678          10 :       break;
    7679             :     }
    7680             : 
    7681             :     // Check if we have an active EventStateManager which isn't the
    7682             :     // EventStateManager of the current PresContext.
    7683             :     // If that is the case, and mouse is over some ancestor document,
    7684             :     // forward event handling to the active document.
    7685             :     // This way content can get mouse events even when
    7686             :     // mouse is over the chrome or outside the window.
    7687             :     //
    7688             :     // Note, currently for backwards compatibility we don't forward mouse events
    7689             :     // to the active document when mouse is over some subdocument.
    7690          10 :     if (EventStateManager* activeESM = EventStateManager::GetActiveEventStateManager()) {
    7691           0 :       if (aEvent->mClass == ePointerEventClass || aEvent->HasMouseEventMessage()) {
    7692           0 :         if (activeESM != shell->GetPresContext()->EventStateManager()) {
    7693           0 :           if (nsPresContext* activeContext = activeESM->GetPresContext()) {
    7694           0 :             if (nsIPresShell* activeShell = activeContext->GetPresShell()) {
    7695           0 :               if (nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(),
    7696           0 :                                                                 shell->GetDocument())) {
    7697           0 :                 shell = static_cast<PresShell*>(activeShell);
    7698           0 :                 frame = shell->GetRootFrame();
    7699             :               }
    7700             :             }
    7701             :           }
    7702             :         }
    7703             :       }
    7704             :     }
    7705             : 
    7706             :     // Before HandlePositionedEvent we should save mPointerEventTarget in some
    7707             :     // cases
    7708          20 :     AutoWeakFrame weakFrame;
    7709          14 :     if (sPointerEventEnabled && aTargetContent &&
    7710           4 :         ePointerEventClass == aEvent->mClass) {
    7711           4 :       weakFrame = frame;
    7712           4 :       shell->mPointerEventTarget = frame->GetContent();
    7713           4 :       MOZ_ASSERT(!frame->GetContent() ||
    7714             :                  shell->GetDocument() == frame->GetContent()->OwnerDoc());
    7715             :     }
    7716             : 
    7717             :     // Prevent deletion until we're done with event handling (bug 336582) and
    7718             :     // swap mPointerEventTarget to *aTargetContent
    7719          20 :     nsCOMPtr<nsIPresShell> kungFuDeathGrip(shell);
    7720             :     nsresult rv;
    7721          10 :     if (shell != this) {
    7722             :       // Handle the event in the correct shell.
    7723             :       // We pass the subshell's root frame as the frame to start from. This is
    7724             :       // the only correct alternative; if the event was captured then it
    7725             :       // must have been captured by us or some ancestor shell and we
    7726             :       // now ask the subshell to dispatch it normally.
    7727           0 :       rv = shell->HandlePositionedEvent(frame, aEvent, aEventStatus);
    7728             :     } else {
    7729          10 :       rv = HandlePositionedEvent(frame, aEvent, aEventStatus);
    7730             :     }
    7731             : 
    7732             :     // After HandlePositionedEvent we should reestablish
    7733             :     // content (which still live in tree) in some cases
    7734          14 :     if (sPointerEventEnabled && aTargetContent &&
    7735           4 :         ePointerEventClass == aEvent->mClass) {
    7736           4 :       if (!weakFrame.IsAlive()) {
    7737           0 :         shell->mPointerEventTarget.swap(*aTargetContent);
    7738             :       }
    7739             :     }
    7740             : 
    7741          10 :     return rv;
    7742             :   }
    7743             : 
    7744           0 :   nsresult rv = NS_OK;
    7745             : 
    7746           0 :   if (frame) {
    7747           0 :     PushCurrentEventInfo(nullptr, nullptr);
    7748             : 
    7749             :     // key and IME related events go to the focused frame in this DOM window.
    7750           0 :     if (aEvent->IsTargetedAtFocusedContent()) {
    7751           0 :       mCurrentEventContent = nullptr;
    7752             : 
    7753           0 :       nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
    7754           0 :       nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    7755             :       nsCOMPtr<nsIContent> eventTarget =
    7756             :         nsFocusManager::GetFocusedDescendant(window, false,
    7757           0 :                                              getter_AddRefs(focusedWindow));
    7758             : 
    7759             :       // otherwise, if there is no focused content or the focused content has
    7760             :       // no frame, just use the root content. This ensures that key events
    7761             :       // still get sent to the window properly if nothing is focused or if a
    7762             :       // frame goes away while it is focused.
    7763           0 :       if (!eventTarget || !eventTarget->GetPrimaryFrame()) {
    7764           0 :         nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
    7765           0 :         if (htmlDoc) {
    7766           0 :           nsCOMPtr<nsIDOMHTMLElement> body;
    7767           0 :           htmlDoc->GetBody(getter_AddRefs(body));
    7768           0 :           eventTarget = do_QueryInterface(body);
    7769           0 :           if (!eventTarget) {
    7770           0 :             eventTarget = mDocument->GetRootElement();
    7771             :           }
    7772             :         } else {
    7773           0 :           eventTarget = mDocument->GetRootElement();
    7774             :         }
    7775             :       }
    7776             : 
    7777           0 :       if (aEvent->mMessage == eKeyDown) {
    7778           0 :         NS_IF_RELEASE(gKeyDownTarget);
    7779           0 :         NS_IF_ADDREF(gKeyDownTarget = eventTarget);
    7780             :       }
    7781           0 :       else if ((aEvent->mMessage == eKeyPress ||
    7782           0 :                 aEvent->mMessage == eKeyUp) &&
    7783           0 :                gKeyDownTarget) {
    7784             :         // If a different element is now focused for the keypress/keyup event
    7785             :         // than what was focused during the keydown event, check if the new
    7786             :         // focused element is not in a chrome document any more, and if so,
    7787             :         // retarget the event back at the keydown target. This prevents a
    7788             :         // content area from grabbing the focus from chrome in-between key
    7789             :         // events.
    7790           0 :         if (eventTarget) {
    7791           0 :           bool keyDownIsChrome = nsContentUtils::IsChromeDoc(gKeyDownTarget->GetComposedDoc());
    7792           0 :           if (keyDownIsChrome != nsContentUtils::IsChromeDoc(eventTarget->GetComposedDoc()) ||
    7793           0 :               (keyDownIsChrome && TabParent::GetFrom(eventTarget))) {
    7794           0 :             eventTarget = gKeyDownTarget;
    7795             :           }
    7796             :         }
    7797             : 
    7798           0 :         if (aEvent->mMessage == eKeyUp) {
    7799           0 :           NS_RELEASE(gKeyDownTarget);
    7800             :         }
    7801             :       }
    7802             : 
    7803           0 :       mCurrentEventFrame = nullptr;
    7804           0 :       nsIDocument* targetDoc = eventTarget ? eventTarget->OwnerDoc() : nullptr;
    7805           0 :       if (targetDoc && targetDoc != mDocument) {
    7806           0 :         PopCurrentEventInfo();
    7807           0 :         nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell();
    7808           0 :         if (shell) {
    7809           0 :           rv = static_cast<PresShell*>(shell.get())->
    7810           0 :             HandleRetargetedEvent(aEvent, aEventStatus, eventTarget);
    7811             :         }
    7812           0 :         return rv;
    7813             :       } else {
    7814           0 :         mCurrentEventContent = eventTarget;
    7815             :       }
    7816             : 
    7817           0 :       if (!GetCurrentEventContent() || !GetCurrentEventFrame() ||
    7818           0 :           InZombieDocument(mCurrentEventContent)) {
    7819           0 :         rv = RetargetEventToParent(aEvent, aEventStatus);
    7820           0 :         PopCurrentEventInfo();
    7821           0 :         return rv;
    7822             :       }
    7823             :     } else {
    7824           0 :       mCurrentEventFrame = frame;
    7825             :     }
    7826           0 :     if (GetCurrentEventFrame()) {
    7827           0 :       rv = HandleEventInternal(aEvent, aEventStatus, true);
    7828             :     }
    7829             : 
    7830             : #ifdef DEBUG
    7831           0 :     ShowEventTargetDebug();
    7832             : #endif
    7833           0 :     PopCurrentEventInfo();
    7834             :   } else {
    7835             :     // Activation events need to be dispatched even if no frame was found, since
    7836             :     // we don't want the focus to be out of sync.
    7837             : 
    7838           0 :     if (!NS_EVENT_NEEDS_FRAME(aEvent)) {
    7839           0 :       mCurrentEventFrame = nullptr;
    7840           0 :       return HandleEventInternal(aEvent, aEventStatus, true);
    7841             :     }
    7842           0 :     else if (aEvent->HasKeyEventMessage()) {
    7843             :       // Keypress events in new blank tabs should not be completely thrown away.
    7844             :       // Retarget them -- the parent chrome shell might make use of them.
    7845           0 :       return RetargetEventToParent(aEvent, aEventStatus);
    7846             :     }
    7847             :   }
    7848             : 
    7849           0 :   return rv;
    7850             : }
    7851             : 
    7852             : nsIDocument*
    7853          29 : PresShell::GetPrimaryContentDocument()
    7854             : {
    7855          29 :   nsPresContext* context = GetPresContext();
    7856          29 :   if (!context || !context->IsRoot()) {
    7857           0 :     return nullptr;
    7858             :   }
    7859             : 
    7860          58 :   nsCOMPtr<nsIDocShellTreeItem> shellAsTreeItem = context->GetDocShell();
    7861          29 :   if (!shellAsTreeItem) {
    7862           0 :     return nullptr;
    7863             :   }
    7864             : 
    7865          58 :   nsCOMPtr<nsIDocShellTreeOwner> owner;
    7866          29 :   shellAsTreeItem->GetTreeOwner(getter_AddRefs(owner));
    7867          29 :   if (!owner) {
    7868           0 :     return nullptr;
    7869             :   }
    7870             : 
    7871             :   // now get the primary content shell (active tab)
    7872          58 :   nsCOMPtr<nsIDocShellTreeItem> item;
    7873          29 :   owner->GetPrimaryContentShell(getter_AddRefs(item));
    7874          58 :   nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(item);
    7875          29 :   if (!childDocShell) {
    7876          25 :     return nullptr;
    7877             :   }
    7878             : 
    7879           4 :   return childDocShell->GetDocument();
    7880             : }
    7881             : 
    7882             : #ifdef DEBUG
    7883             : void
    7884          10 : PresShell::ShowEventTargetDebug()
    7885             : {
    7886          10 :   if (nsFrame::GetShowEventTargetFrameBorder() &&
    7887           0 :       GetCurrentEventFrame()) {
    7888           0 :     if (mDrawEventTargetFrame) {
    7889           0 :       mDrawEventTargetFrame->InvalidateFrame();
    7890             :     }
    7891             : 
    7892           0 :     mDrawEventTargetFrame = mCurrentEventFrame;
    7893           0 :     mDrawEventTargetFrame->InvalidateFrame();
    7894             :   }
    7895          10 : }
    7896             : #endif
    7897             : 
    7898             : nsresult
    7899          10 : PresShell::HandlePositionedEvent(nsIFrame* aTargetFrame,
    7900             :                                  WidgetGUIEvent* aEvent,
    7901             :                                  nsEventStatus* aEventStatus)
    7902             : {
    7903          10 :   nsresult rv = NS_OK;
    7904             : 
    7905          10 :   PushCurrentEventInfo(nullptr, nullptr);
    7906             : 
    7907          10 :   mCurrentEventFrame = aTargetFrame;
    7908             : 
    7909          10 :   if (mCurrentEventFrame) {
    7910          20 :     nsCOMPtr<nsIContent> targetElement;
    7911          20 :     mCurrentEventFrame->GetContentForEvent(aEvent,
    7912          20 :                                            getter_AddRefs(targetElement));
    7913             : 
    7914             :     // If there is no content for this frame, target it anyway.  Some
    7915             :     // frames can be targeted but do not have content, particularly
    7916             :     // windows with scrolling off.
    7917          10 :     if (targetElement) {
    7918             :       // Bug 103055, bug 185889: mouse events apply to *elements*, not all
    7919             :       // nodes.  Thus we get the nearest element parent here.
    7920             :       // XXX we leave the frame the same even if we find an element
    7921             :       // parent, so that the text frame will receive the event (selection
    7922             :       // and friends are the ones who care about that anyway)
    7923             :       //
    7924             :       // We use weak pointers because during this tight loop, the node
    7925             :       // will *not* go away.  And this happens on every mousemove.
    7926           9 :       while (targetElement && !targetElement->IsElement()) {
    7927           0 :         targetElement = targetElement->GetFlattenedTreeParent();
    7928             :       }
    7929             : 
    7930             :       // If we found an element, target it.  Otherwise, target *nothing*.
    7931           9 :       if (!targetElement) {
    7932           0 :         mCurrentEventContent = nullptr;
    7933           0 :         mCurrentEventFrame = nullptr;
    7934           9 :       } else if (targetElement != mCurrentEventContent) {
    7935           9 :         mCurrentEventContent = targetElement;
    7936             :       }
    7937             :     }
    7938             :   }
    7939             : 
    7940          10 :   if (GetCurrentEventFrame()) {
    7941          10 :     rv = HandleEventInternal(aEvent, aEventStatus, true);
    7942             :   }
    7943             : 
    7944             : #ifdef DEBUG
    7945          10 :   ShowEventTargetDebug();
    7946             : #endif
    7947          10 :   PopCurrentEventInfo();
    7948          10 :   return rv;
    7949             : }
    7950             : 
    7951             : nsresult
    7952           0 : PresShell::HandleEventWithTarget(WidgetEvent* aEvent, nsIFrame* aFrame,
    7953             :                                  nsIContent* aContent, nsEventStatus* aStatus)
    7954             : {
    7955             : #if DEBUG
    7956           0 :   MOZ_ASSERT(!aFrame || aFrame->PresContext()->GetPresShell() == this,
    7957             :              "wrong shell");
    7958           0 :   if (aContent) {
    7959           0 :     nsIDocument* doc = aContent->GetComposedDoc();
    7960           0 :     NS_ASSERTION(doc, "event for content that isn't in a document");
    7961             :     // NOTE: We don't require that the document still have a PresShell.
    7962             :     // See bug 1375940.
    7963             :   }
    7964             : #endif
    7965           0 :   NS_ENSURE_STATE(!aContent || aContent->GetComposedDoc() == mDocument);
    7966             : 
    7967           0 :   PushCurrentEventInfo(aFrame, aContent);
    7968           0 :   nsresult rv = HandleEventInternal(aEvent, aStatus, false);
    7969           0 :   PopCurrentEventInfo();
    7970           0 :   return rv;
    7971             : }
    7972             : 
    7973             : nsresult
    7974          10 : PresShell::HandleEventInternal(WidgetEvent* aEvent,
    7975             :                                nsEventStatus* aStatus,
    7976             :                                bool aIsHandlingNativeEvent)
    7977             : {
    7978          20 :   RefPtr<EventStateManager> manager = mPresContext->EventStateManager();
    7979          10 :   nsresult rv = NS_OK;
    7980             : 
    7981          10 :   if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame() || GetCurrentEventContent()) {
    7982          10 :     bool touchIsNew = false;
    7983          10 :     bool isHandlingUserInput = false;
    7984             : 
    7985          10 :     if (mCurrentEventContent && aEvent->IsTargetedAtFocusedWindow()) {
    7986           0 :       nsFocusManager* fm = nsFocusManager::GetFocusManager();
    7987           0 :       if (fm) {
    7988           0 :          fm->FlushBeforeEventHandlingIfNeeded(mCurrentEventContent);
    7989             :       }
    7990             :     }
    7991             : 
    7992             :     // XXX How about IME events and input events for plugins?
    7993          10 :     if (aEvent->IsTrusted()) {
    7994          10 :       switch (aEvent->mMessage) {
    7995             :       case eKeyPress:
    7996             :       case eKeyDown:
    7997             :       case eKeyUp: {
    7998           0 :         nsIDocument* doc = GetCurrentEventContent() ?
    7999           0 :                            mCurrentEventContent->OwnerDoc() : nullptr;
    8000           0 :         auto keyCode = aEvent->AsKeyboardEvent()->mKeyCode;
    8001           0 :         if (keyCode == NS_VK_ESCAPE) {
    8002           0 :           nsIDocument* root = nsContentUtils::GetRootDocument(doc);
    8003           0 :           if (root && root->GetFullscreenElement()) {
    8004             :             // Prevent default action on ESC key press when exiting
    8005             :             // DOM fullscreen mode. This prevents the browser ESC key
    8006             :             // handler from stopping all loads in the document, which
    8007             :             // would cause <video> loads to stop.
    8008             :             // XXX We need to claim the Escape key event which will be
    8009             :             //     dispatched only into chrome is already consumed by
    8010             :             //     content because we need to prevent its default here
    8011             :             //     for some reasons (not sure) but we need to detect
    8012             :             //     if a chrome event handler will call PreventDefault()
    8013             :             //     again and check it later.
    8014           0 :             aEvent->PreventDefaultBeforeDispatch();
    8015           0 :             aEvent->mFlags.mOnlyChromeDispatch = true;
    8016             : 
    8017             :             // The event listeners in chrome can prevent this ESC behavior by
    8018             :             // calling prevent default on the preceding keydown/press events.
    8019           0 :             if (!mIsLastChromeOnlyEscapeKeyConsumed &&
    8020           0 :                 aEvent->mMessage == eKeyUp) {
    8021             :               // ESC key released while in DOM fullscreen mode.
    8022             :               // Fully exit all browser windows and documents from
    8023             :               // fullscreen mode.
    8024           0 :               nsIDocument::AsyncExitFullscreen(nullptr);
    8025             :             }
    8026             :           }
    8027             :           nsCOMPtr<nsIDocument> pointerLockedDoc =
    8028           0 :             do_QueryReferent(EventStateManager::sPointerLockedDoc);
    8029           0 :           if (!mIsLastChromeOnlyEscapeKeyConsumed && pointerLockedDoc) {
    8030             :             // XXX See above comment to understand the reason why this needs
    8031             :             //     to claim that the Escape key event is consumed by content
    8032             :             //     even though it will be dispatched only into chrome.
    8033           0 :             aEvent->PreventDefaultBeforeDispatch();
    8034           0 :             aEvent->mFlags.mOnlyChromeDispatch = true;
    8035           0 :             if (aEvent->mMessage == eKeyUp) {
    8036           0 :               nsIDocument::UnlockPointer();
    8037             :             }
    8038             :           }
    8039             :         }
    8040           0 :         if (keyCode != NS_VK_ESCAPE && keyCode != NS_VK_SHIFT &&
    8041           0 :             keyCode != NS_VK_CONTROL && keyCode != NS_VK_ALT &&
    8042           0 :             keyCode != NS_VK_WIN && keyCode != NS_VK_META) {
    8043             :           // Allow keys other than ESC and modifiers be marked as a
    8044             :           // valid user input for triggering popup, fullscreen, and
    8045             :           // pointer lock.
    8046           0 :           isHandlingUserInput = true;
    8047           0 :           mPresContext->RecordInteractionTime(
    8048             :             nsPresContext::InteractionType::eKeyInteraction,
    8049           0 :             aEvent->mTimeStamp);
    8050             :         }
    8051             : 
    8052           0 :         Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_KEYBOARD_MS, aEvent->mTimeStamp);
    8053           0 :         break;
    8054             :       }
    8055             :       case eMouseDown:
    8056             :       case eMouseUp:
    8057           0 :         Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_CLICK_MS, aEvent->mTimeStamp);
    8058             :         MOZ_FALLTHROUGH;
    8059             :       case ePointerDown:
    8060             :       case ePointerUp:
    8061           0 :         isHandlingUserInput = true;
    8062           0 :         mPresContext->RecordInteractionTime(
    8063             :           nsPresContext::InteractionType::eClickInteraction,
    8064           0 :           aEvent->mTimeStamp);
    8065           0 :         break;
    8066             : 
    8067             :       case eMouseMove:
    8068           4 :         if (aEvent->mFlags.mHandledByAPZ) {
    8069           4 :           Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_APZ_MOUSE_MOVE_MS, aEvent->mTimeStamp);
    8070             :         }
    8071           4 :         break;
    8072             : 
    8073             :       case eDrop: {
    8074           0 :         nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession();
    8075           0 :         if (session) {
    8076           0 :           bool onlyChromeDrop = false;
    8077           0 :           session->GetOnlyChromeDrop(&onlyChromeDrop);
    8078           0 :           if (onlyChromeDrop) {
    8079           0 :             aEvent->mFlags.mOnlyChromeDispatch = true;
    8080             :           }
    8081             :         }
    8082           0 :         break;
    8083             :       }
    8084             : 
    8085             :       case eWheel:
    8086           0 :         if (aEvent->mFlags.mHandledByAPZ) {
    8087           0 :           Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_APZ_WHEEL_MS, aEvent->mTimeStamp);
    8088             :         }
    8089           0 :         break;
    8090             : 
    8091             :       case eTouchMove:
    8092           0 :         if (aEvent->mFlags.mHandledByAPZ) {
    8093           0 :           Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_APZ_TOUCH_MOVE_MS, aEvent->mTimeStamp);
    8094             :         }
    8095           0 :         break;
    8096             : 
    8097             :       default:
    8098           6 :         break;
    8099             :       }
    8100             : 
    8101          10 :       if (!mTouchManager.PreHandleEvent(aEvent, aStatus,
    8102             :                                         touchIsNew, isHandlingUserInput,
    8103             :                                         mCurrentEventContent)) {
    8104           0 :         return NS_OK;
    8105             :       }
    8106             :     }
    8107             : 
    8108          10 :     if (aEvent->mMessage == eContextMenu) {
    8109           0 :       WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
    8110           0 :       if (mouseEvent->IsContextMenuKeyEvent() &&
    8111           0 :           !AdjustContextMenuKeyEvent(mouseEvent)) {
    8112           0 :         return NS_OK;
    8113             :       }
    8114           0 :       if (mouseEvent->IsShift()) {
    8115           0 :         aEvent->mFlags.mOnlyChromeDispatch = true;
    8116           0 :         aEvent->mFlags.mRetargetToNonNativeAnonymous = true;
    8117             :       }
    8118             :     }
    8119             : 
    8120             :     AutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput,
    8121          20 :                                                         aEvent, mDocument);
    8122             : 
    8123          10 :     if (aEvent->IsTrusted() && aEvent->mMessage == eMouseMove) {
    8124           4 :       nsIPresShell::AllowMouseCapture(
    8125           8 :         EventStateManager::GetActiveEventStateManager() == manager);
    8126             : 
    8127           4 :       mPresContext->RecordInteractionTime(
    8128             :         nsPresContext::InteractionType::eMouseMoveInteraction,
    8129           4 :         aEvent->mTimeStamp);
    8130             :     }
    8131             : 
    8132             :     nsAutoPopupStatePusher popupStatePusher(
    8133          20 :                              Event::GetEventPopupControlState(aEvent));
    8134             : 
    8135             :     // FIXME. If the event was reused, we need to clear the old target,
    8136             :     // bug 329430
    8137          10 :     aEvent->mTarget = nullptr;
    8138             : 
    8139          10 :     TimeStamp handlerStartTime = TimeStamp::Now();
    8140             : 
    8141             :     // 1. Give event to event manager for pre event state changes and
    8142             :     //    generation of synthetic events.
    8143          10 :     rv = manager->PreHandleEvent(mPresContext, aEvent, mCurrentEventFrame,
    8144          10 :                                  mCurrentEventContent, aStatus);
    8145             : 
    8146             :     // 2. Give event to the DOM for third party and JS use.
    8147          10 :     if (NS_SUCCEEDED(rv)) {
    8148             :       bool wasHandlingKeyBoardEvent =
    8149          10 :         nsContentUtils::IsHandlingKeyBoardEvent();
    8150          10 :       if (aEvent->mClass == eKeyboardEventClass) {
    8151           0 :         nsContentUtils::SetIsHandlingKeyBoardEvent(true);
    8152             :       }
    8153          10 :       if (aEvent->IsAllowedToDispatchDOMEvent()) {
    8154          10 :         MOZ_ASSERT(nsContentUtils::IsSafeToRunScript(),
    8155             :           "Somebody changed aEvent to cause a DOM event!");
    8156          20 :         nsPresShellEventCB eventCB(this);
    8157          10 :         if (nsIFrame* target = GetCurrentEventFrame()) {
    8158          10 :           if (target->OnlySystemGroupDispatch(aEvent->mMessage)) {
    8159           0 :               aEvent->StopPropagation();
    8160             :           }
    8161             :         }
    8162          10 :         if (aEvent->mClass == eTouchEventClass) {
    8163           0 :           DispatchTouchEventToDOM(aEvent, aStatus, &eventCB, touchIsNew);
    8164             :         } else {
    8165          10 :           DispatchEventToDOM(aEvent, aStatus, &eventCB);
    8166             :         }
    8167             :       }
    8168             : 
    8169          10 :       nsContentUtils::SetIsHandlingKeyBoardEvent(wasHandlingKeyBoardEvent);
    8170             : 
    8171             :       // 3. Give event to event manager for post event state changes and
    8172             :       //    generation of synthetic events.
    8173          10 :       if (!mIsDestroying && NS_SUCCEEDED(rv)) {
    8174          10 :         rv = manager->PostHandleEvent(mPresContext, aEvent,
    8175          10 :                                       GetCurrentEventFrame(), aStatus);
    8176             :       }
    8177             :     }
    8178             : 
    8179          10 :     if (!mIsDestroying && aIsHandlingNativeEvent) {
    8180             :       // Ensure that notifications to IME should be sent before getting next
    8181             :       // native event from the event queue.
    8182             :       // XXX Should we check the event message or event class instead of
    8183             :       //     using aIsHandlingNativeEvent?
    8184          10 :       manager->TryToFlushPendingNotificationsToIME();
    8185             :     }
    8186             : 
    8187          10 :     switch (aEvent->mMessage) {
    8188             :     case eKeyPress:
    8189             :     case eKeyDown:
    8190             :     case eKeyUp: {
    8191           0 :       if (aEvent->AsKeyboardEvent()->mKeyCode == NS_VK_ESCAPE) {
    8192           0 :         if (aEvent->mMessage == eKeyUp) {
    8193             :           // Reset this flag after key up is handled.
    8194           0 :           mIsLastChromeOnlyEscapeKeyConsumed = false;
    8195             :         } else {
    8196           0 :           if (aEvent->mFlags.mOnlyChromeDispatch &&
    8197           0 :               aEvent->mFlags.mDefaultPreventedByChrome) {
    8198           0 :             mIsLastChromeOnlyEscapeKeyConsumed = true;
    8199             :           }
    8200             :         }
    8201             :       }
    8202           0 :       if (aEvent->mMessage == eKeyDown) {
    8203           0 :         mIsLastKeyDownCanceled = aEvent->mFlags.mDefaultPrevented;
    8204             :       }
    8205           0 :       break;
    8206             :     }
    8207             :     case eMouseUp:
    8208             :       // reset the capturing content now that the mouse button is up
    8209           0 :       SetCapturingContent(nullptr, 0);
    8210           0 :       break;
    8211             :     case eMouseMove:
    8212           4 :       nsIPresShell::AllowMouseCapture(false);
    8213           4 :       break;
    8214             :     default:
    8215           6 :       break;
    8216             :     }
    8217             : 
    8218          10 :     if (aEvent->IsTrusted() && aEvent->mTimeStamp > mLastOSWake) {
    8219          10 :       switch (aEvent->mMessage) {
    8220             :         case eKeyPress:
    8221             :         case eKeyDown:
    8222             :         case eKeyUp:
    8223           0 :           Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_KEYBOARD_MS, handlerStartTime);
    8224           0 :           break;
    8225             :         case eMouseDown:
    8226           0 :           Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_MOUSE_DOWN_MS, handlerStartTime);
    8227           0 :           break;
    8228             :         case eMouseUp:
    8229           0 :           Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_MOUSE_UP_MS, handlerStartTime);
    8230           0 :           break;
    8231             :         case eMouseMove:
    8232           4 :           if (aEvent->mFlags.mHandledByAPZ) {
    8233           4 :             Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_APZ_MOUSE_MOVE_MS, handlerStartTime);
    8234             :           }
    8235           4 :           break;
    8236             :         case eWheel:
    8237           0 :           if (aEvent->mFlags.mHandledByAPZ) {
    8238           0 :             Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_APZ_WHEEL_MS, handlerStartTime);
    8239             :           }
    8240           0 :           break;
    8241             :         case eTouchMove:
    8242           0 :           if (aEvent->mFlags.mHandledByAPZ) {
    8243           0 :             Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_APZ_TOUCH_MOVE_MS, handlerStartTime);
    8244             :           }
    8245           0 :           break;
    8246             :         default:
    8247           6 :           break;
    8248             :       }
    8249             :     }
    8250             :   }
    8251             : 
    8252          30 :   if (Telemetry::CanRecordBase() &&
    8253          20 :       !aEvent->mTimeStamp.IsNull() &&
    8254          30 :       aEvent->mTimeStamp > mLastOSWake &&
    8255          10 :       aEvent->AsInputEvent()) {
    8256          10 :     TimeStamp now = TimeStamp::Now();
    8257          10 :     double millis = (now - aEvent->mTimeStamp).ToMilliseconds();
    8258          10 :     Telemetry::Accumulate(Telemetry::INPUT_EVENT_RESPONSE_MS, millis);
    8259          10 :     if (mDocument && mDocument->GetReadyStateEnum() != nsIDocument::READYSTATE_COMPLETE) {
    8260           0 :       Telemetry::Accumulate(Telemetry::LOAD_INPUT_EVENT_RESPONSE_MS, millis);
    8261             :     }
    8262             : 
    8263          10 :     if (!sLastInputProcessed || sLastInputProcessed < aEvent->mTimeStamp) {
    8264           3 :       if (sLastInputProcessed) {
    8265             :         // This input event was created after we handled the last one.
    8266             :         // Accumulate the previous events' coalesced duration.
    8267           2 :         double lastMillis = (sLastInputProcessed - sLastInputCreated).ToMilliseconds();
    8268           2 :         Telemetry::Accumulate(Telemetry::INPUT_EVENT_RESPONSE_COALESCED_MS,
    8269           2 :                               lastMillis);
    8270             :       }
    8271           3 :       sLastInputCreated = aEvent->mTimeStamp;
    8272           7 :     } else if (aEvent->mTimeStamp < sLastInputCreated) {
    8273             :       // This event was created before the last input. May be processing out
    8274             :       // of order, so coalesce backwards, too.
    8275           0 :       sLastInputCreated = aEvent->mTimeStamp;
    8276             :     }
    8277          10 :     sLastInputProcessed = now;
    8278             :   }
    8279             : 
    8280          10 :   return rv;
    8281             : }
    8282             : 
    8283             : /* static */ void
    8284           0 : nsIPresShell::DispatchGotOrLostPointerCaptureEvent(
    8285             :                 bool aIsGotCapture,
    8286             :                 const WidgetPointerEvent* aPointerEvent,
    8287             :                 nsIContent* aCaptureTarget)
    8288             : {
    8289           0 :   nsIDocument* targetDoc = aCaptureTarget->OwnerDoc();
    8290           0 :   nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell();
    8291           0 :   NS_ENSURE_TRUE_VOID(shell);
    8292             : 
    8293           0 :   if (!aIsGotCapture && !aCaptureTarget->IsInUncomposedDoc()) {
    8294             :     // If the capturing element was removed from the DOM tree, fire
    8295             :     // ePointerLostCapture at the document.
    8296           0 :     PointerEventInit init;
    8297           0 :     init.mPointerId = aPointerEvent->pointerId;
    8298           0 :     init.mBubbles = true;
    8299           0 :     init.mComposed = true;
    8300           0 :     ConvertPointerTypeToString(aPointerEvent->inputSource, init.mPointerType);
    8301           0 :     init.mIsPrimary = aPointerEvent->mIsPrimary;
    8302           0 :     RefPtr<mozilla::dom::PointerEvent> event;
    8303           0 :     event = PointerEvent::Constructor(aCaptureTarget,
    8304           0 :                                       NS_LITERAL_STRING("lostpointercapture"),
    8305           0 :                                       init);
    8306             :     bool dummy;
    8307           0 :     targetDoc->DispatchEvent(event->InternalDOMEvent(), &dummy);
    8308           0 :     return;
    8309             :   }
    8310           0 :   nsEventStatus status = nsEventStatus_eIgnore;
    8311           0 :   WidgetPointerEvent localEvent(aPointerEvent->IsTrusted(),
    8312             :                                 aIsGotCapture ? ePointerGotCapture :
    8313             :                                                 ePointerLostCapture,
    8314           0 :                                 aPointerEvent->mWidget);
    8315           0 :   localEvent.AssignPointerEventData(*aPointerEvent, true);
    8316           0 :   nsresult rv = shell->HandleEventWithTarget(
    8317             :                          &localEvent,
    8318             :                          aCaptureTarget->GetPrimaryFrame(),
    8319           0 :                          aCaptureTarget, &status);
    8320           0 :   NS_ENSURE_SUCCESS_VOID(rv);
    8321             : }
    8322             : 
    8323             : nsresult
    8324          10 : PresShell::DispatchEventToDOM(WidgetEvent* aEvent,
    8325             :                               nsEventStatus* aStatus,
    8326             :                               nsPresShellEventCB* aEventCB)
    8327             : {
    8328          10 :   nsresult rv = NS_OK;
    8329          20 :   nsCOMPtr<nsINode> eventTarget = mCurrentEventContent.get();
    8330          10 :   nsPresShellEventCB* eventCBPtr = aEventCB;
    8331          10 :   if (!eventTarget) {
    8332           2 :     nsCOMPtr<nsIContent> targetContent;
    8333           1 :     if (mCurrentEventFrame) {
    8334           2 :       rv = mCurrentEventFrame->
    8335           2 :              GetContentForEvent(aEvent, getter_AddRefs(targetContent));
    8336             :     }
    8337           1 :     if (NS_SUCCEEDED(rv) && targetContent) {
    8338           0 :       eventTarget = do_QueryInterface(targetContent);
    8339           1 :     } else if (mDocument) {
    8340           1 :       eventTarget = do_QueryInterface(mDocument);
    8341             :       // If we don't have any content, the callback wouldn't probably
    8342             :       // do nothing.
    8343           1 :       eventCBPtr = nullptr;
    8344             :     }
    8345             :   }
    8346          10 :   if (eventTarget) {
    8347          10 :     if (aEvent->mClass == eCompositionEventClass) {
    8348           0 :       IMEStateManager::DispatchCompositionEvent(eventTarget, mPresContext,
    8349           0 :                                                 aEvent->AsCompositionEvent(),
    8350           0 :                                                 aStatus, eventCBPtr);
    8351             :     } else {
    8352          10 :       EventDispatcher::Dispatch(eventTarget, mPresContext,
    8353          10 :                                 aEvent, nullptr, aStatus, eventCBPtr);
    8354             :     }
    8355             :   }
    8356          20 :   return rv;
    8357             : }
    8358             : 
    8359             : void
    8360           0 : PresShell::DispatchTouchEventToDOM(WidgetEvent* aEvent,
    8361             :                                    nsEventStatus* aStatus,
    8362             :                                    nsPresShellEventCB* aEventCB,
    8363             :                                    bool aTouchIsNew)
    8364             : {
    8365             :   // calling preventDefault on touchstart or the first touchmove for a
    8366             :   // point prevents mouse events. calling it on the touchend should
    8367             :   // prevent click dispatching.
    8368           0 :   bool canPrevent = (aEvent->mMessage == eTouchStart) ||
    8369           0 :                     (aEvent->mMessage == eTouchMove && aTouchIsNew) ||
    8370           0 :                     (aEvent->mMessage == eTouchEnd);
    8371           0 :   bool preventDefault = false;
    8372           0 :   nsEventStatus tmpStatus = nsEventStatus_eIgnore;
    8373           0 :   WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
    8374             : 
    8375             :   // loop over all touches and dispatch events on any that have changed
    8376           0 :   for (dom::Touch* touch : touchEvent->mTouches) {
    8377           0 :     if (!touch || !touch->mChanged) {
    8378           0 :       continue;
    8379             :     }
    8380             : 
    8381           0 :     nsCOMPtr<EventTarget> targetPtr = touch->mTarget;
    8382           0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(targetPtr);
    8383           0 :     if (!content) {
    8384           0 :       continue;
    8385             :     }
    8386             : 
    8387           0 :     nsIDocument* doc = content->OwnerDoc();
    8388           0 :     nsIContent* capturingContent = GetCapturingContent();
    8389           0 :     if (capturingContent) {
    8390           0 :       if (capturingContent->OwnerDoc() != doc) {
    8391             :         // Wrong document, don't dispatch anything.
    8392           0 :         continue;
    8393             :       }
    8394           0 :       content = capturingContent;
    8395             :     }
    8396             :     // copy the event
    8397           0 :     WidgetTouchEvent newEvent(touchEvent->IsTrusted(),
    8398           0 :                               touchEvent->mMessage, touchEvent->mWidget);
    8399           0 :     newEvent.AssignTouchEventData(*touchEvent, false);
    8400           0 :     newEvent.mTarget = targetPtr;
    8401             : 
    8402           0 :     RefPtr<PresShell> contentPresShell;
    8403           0 :     if (doc == mDocument) {
    8404           0 :       contentPresShell = static_cast<PresShell*>(doc->GetShell());
    8405           0 :       if (contentPresShell) {
    8406             :         //XXXsmaug huge hack. Pushing possibly capturing content,
    8407             :         //         even though event target is something else.
    8408           0 :         contentPresShell->PushCurrentEventInfo(
    8409           0 :             content->GetPrimaryFrame(), content);
    8410             :       }
    8411             :     }
    8412             : 
    8413           0 :     nsIPresShell *presShell = doc->GetShell();
    8414           0 :     if (!presShell) {
    8415           0 :       continue;
    8416             :     }
    8417             : 
    8418           0 :     nsPresContext *context = presShell->GetPresContext();
    8419             : 
    8420           0 :     tmpStatus = nsEventStatus_eIgnore;
    8421             :     EventDispatcher::Dispatch(targetPtr, context,
    8422           0 :                               &newEvent, nullptr, &tmpStatus, aEventCB);
    8423           0 :     if (nsEventStatus_eConsumeNoDefault == tmpStatus ||
    8424           0 :         newEvent.mFlags.mMultipleActionsPrevented) {
    8425           0 :       preventDefault = true;
    8426             :     }
    8427             : 
    8428           0 :     if (newEvent.mFlags.mMultipleActionsPrevented) {
    8429           0 :       touchEvent->mFlags.mMultipleActionsPrevented = true;
    8430             :     }
    8431             : 
    8432           0 :     if (contentPresShell) {
    8433           0 :       contentPresShell->PopCurrentEventInfo();
    8434             :     }
    8435             :   }
    8436             : 
    8437           0 :   if (preventDefault && canPrevent) {
    8438           0 :     *aStatus = nsEventStatus_eConsumeNoDefault;
    8439             :   } else {
    8440           0 :     *aStatus = nsEventStatus_eIgnore;
    8441             :   }
    8442           0 : }
    8443             : 
    8444             : // Dispatch event to content only (NOT full processing)
    8445             : // See also HandleEventWithTarget which does full event processing.
    8446             : nsresult
    8447           0 : PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent,
    8448             :                                     WidgetEvent* aEvent,
    8449             :                                     nsEventStatus* aStatus)
    8450             : {
    8451           0 :   nsresult rv = NS_OK;
    8452             : 
    8453           0 :   PushCurrentEventInfo(nullptr, aTargetContent);
    8454             : 
    8455             :   // Bug 41013: Check if the event should be dispatched to content.
    8456             :   // It's possible that we are in the middle of destroying the window
    8457             :   // and the js context is out of date. This check detects the case
    8458             :   // that caused a crash in bug 41013, but there may be a better way
    8459             :   // to handle this situation!
    8460           0 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
    8461           0 :   if (container) {
    8462             : 
    8463             :     // Dispatch event to content
    8464           0 :     rv = EventDispatcher::Dispatch(aTargetContent, mPresContext, aEvent,
    8465           0 :                                    nullptr, aStatus);
    8466             :   }
    8467             : 
    8468           0 :   PopCurrentEventInfo();
    8469           0 :   return rv;
    8470             : }
    8471             : 
    8472             : // See the method above.
    8473             : nsresult
    8474           0 : PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent,
    8475             :                                     nsIDOMEvent* aEvent,
    8476             :                                     nsEventStatus* aStatus)
    8477             : {
    8478           0 :   nsresult rv = NS_OK;
    8479             : 
    8480           0 :   PushCurrentEventInfo(nullptr, aTargetContent);
    8481           0 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
    8482           0 :   if (container) {
    8483           0 :     rv = EventDispatcher::DispatchDOMEvent(aTargetContent, nullptr, aEvent,
    8484           0 :                                            mPresContext, aStatus);
    8485             :   }
    8486             : 
    8487           0 :   PopCurrentEventInfo();
    8488           0 :   return rv;
    8489             : }
    8490             : 
    8491             : bool
    8492           0 : PresShell::AdjustContextMenuKeyEvent(WidgetMouseEvent* aEvent)
    8493             : {
    8494             : #ifdef MOZ_XUL
    8495             :   // if a menu is open, open the context menu relative to the active item on the menu.
    8496           0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    8497           0 :   if (pm) {
    8498           0 :     nsIFrame* popupFrame = pm->GetTopPopup(ePopupTypeMenu);
    8499           0 :     if (popupFrame) {
    8500             :       nsIFrame* itemFrame =
    8501           0 :         (static_cast<nsMenuPopupFrame *>(popupFrame))->GetCurrentMenuItem();
    8502           0 :       if (!itemFrame)
    8503           0 :         itemFrame = popupFrame;
    8504             : 
    8505           0 :       nsCOMPtr<nsIWidget> widget = popupFrame->GetNearestWidget();
    8506           0 :       aEvent->mWidget = widget;
    8507           0 :       LayoutDeviceIntPoint widgetPoint = widget->WidgetToScreenOffset();
    8508           0 :       aEvent->mRefPoint = LayoutDeviceIntPoint::FromAppUnitsToNearest(
    8509           0 :         itemFrame->GetScreenRectInAppUnits().BottomLeft(),
    8510           0 :         itemFrame->PresContext()->AppUnitsPerDevPixel()) - widgetPoint;
    8511             : 
    8512           0 :       mCurrentEventContent = itemFrame->GetContent();
    8513           0 :       mCurrentEventFrame = itemFrame;
    8514             : 
    8515           0 :       return true;
    8516             :     }
    8517             :   }
    8518             : #endif
    8519             : 
    8520             :   // If we're here because of the key-equiv for showing context menus, we
    8521             :   // have to twiddle with the NS event to make sure the context menu comes
    8522             :   // up in the upper left of the relevant content area before we create
    8523             :   // the DOM event. Since we never call InitMouseEvent() on the event,
    8524             :   // the client X/Y will be 0,0. We can make use of that if the widget is null.
    8525             :   // Use the root view manager's widget since it's most likely to have one,
    8526             :   // and the coordinates returned by GetCurrentItemAndPositionForElement
    8527             :   // are relative to the widget of the root of the root view manager.
    8528           0 :   nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
    8529           0 :   aEvent->mRefPoint = LayoutDeviceIntPoint(0, 0);
    8530           0 :   if (rootPC) {
    8531             :     rootPC->PresShell()->GetViewManager()->
    8532           0 :       GetRootWidget(getter_AddRefs(aEvent->mWidget));
    8533             : 
    8534           0 :     if (aEvent->mWidget) {
    8535             :       // default the refpoint to the topleft of our document
    8536           0 :       nsPoint offset(0, 0);
    8537           0 :       nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    8538           0 :       if (rootFrame) {
    8539           0 :         nsView* view = rootFrame->GetClosestView(&offset);
    8540           0 :         offset += view->GetOffsetToWidget(aEvent->mWidget);
    8541             :         aEvent->mRefPoint =
    8542           0 :           LayoutDeviceIntPoint::FromAppUnitsToNearest(offset, mPresContext->AppUnitsPerDevPixel());
    8543             :       }
    8544             :     }
    8545             :   } else {
    8546           0 :     aEvent->mWidget = nullptr;
    8547             :   }
    8548             : 
    8549             :   // see if we should use the caret position for the popup
    8550           0 :   LayoutDeviceIntPoint caretPoint;
    8551             :   // Beware! This may flush notifications via synchronous
    8552             :   // ScrollSelectionIntoView.
    8553           0 :   if (PrepareToUseCaretPosition(aEvent->mWidget, caretPoint)) {
    8554             :     // caret position is good
    8555           0 :     aEvent->mRefPoint = caretPoint;
    8556           0 :     return true;
    8557             :   }
    8558             : 
    8559             :   // If we're here because of the key-equiv for showing context menus, we
    8560             :   // have to reset the event target to the currently focused element. Get it
    8561             :   // from the focus controller.
    8562           0 :   nsCOMPtr<nsIDOMElement> currentFocus;
    8563           0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    8564           0 :   if (fm)
    8565           0 :     fm->GetFocusedElement(getter_AddRefs(currentFocus));
    8566             : 
    8567             :   // Reset event coordinates relative to focused frame in view
    8568           0 :   if (currentFocus) {
    8569           0 :     nsCOMPtr<nsIContent> currentPointElement;
    8570           0 :     GetCurrentItemAndPositionForElement(currentFocus,
    8571           0 :                                         getter_AddRefs(currentPointElement),
    8572             :                                         aEvent->mRefPoint,
    8573           0 :                                         aEvent->mWidget);
    8574           0 :     if (currentPointElement) {
    8575           0 :       mCurrentEventContent = currentPointElement;
    8576           0 :       mCurrentEventFrame = nullptr;
    8577           0 :       GetCurrentEventFrame();
    8578             :     }
    8579             :   }
    8580             : 
    8581           0 :   return true;
    8582             : }
    8583             : 
    8584             : // PresShell::PrepareToUseCaretPosition
    8585             : //
    8586             : //    This checks to see if we should use the caret position for popup context
    8587             : //    menus. Returns true if the caret position should be used, and the
    8588             : //    coordinates of that position is returned in aTargetPt. This function
    8589             : //    will also scroll the window as needed to make the caret visible.
    8590             : //
    8591             : //    The event widget should be the widget that generated the event, and
    8592             : //    whose coordinate system the resulting event's mRefPoint should be
    8593             : //    relative to.  The returned point is in device pixels realtive to the
    8594             : //    widget passed in.
    8595             : bool
    8596           0 : PresShell::PrepareToUseCaretPosition(nsIWidget* aEventWidget,
    8597             :                                      LayoutDeviceIntPoint& aTargetPt)
    8598             : {
    8599             :   nsresult rv;
    8600             : 
    8601             :   // check caret visibility
    8602           0 :   RefPtr<nsCaret> caret = GetCaret();
    8603           0 :   NS_ENSURE_TRUE(caret, false);
    8604             : 
    8605           0 :   bool caretVisible = caret->IsVisible();
    8606           0 :   if (!caretVisible)
    8607           0 :     return false;
    8608             : 
    8609             :   // caret selection, this is a temporary weak reference, so no refcounting is
    8610             :   // needed
    8611           0 :   nsISelection* domSelection = caret->GetSelection();
    8612           0 :   NS_ENSURE_TRUE(domSelection, false);
    8613             : 
    8614             :   // since the match could be an anonymous textnode inside a
    8615             :   // <textarea> or text <input>, we need to get the outer frame
    8616             :   // note: frames are not refcounted
    8617           0 :   nsIFrame* frame = nullptr; // may be nullptr
    8618           0 :   nsCOMPtr<nsIDOMNode> node;
    8619           0 :   rv = domSelection->GetFocusNode(getter_AddRefs(node));
    8620           0 :   NS_ENSURE_SUCCESS(rv, false);
    8621           0 :   NS_ENSURE_TRUE(node, false);
    8622           0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(node));
    8623           0 :   if (content) {
    8624           0 :     nsIContent* nonNative = content->FindFirstNonChromeOnlyAccessContent();
    8625           0 :     content = nonNative;
    8626             :   }
    8627             : 
    8628           0 :   if (content) {
    8629             :     // It seems like ScrollSelectionIntoView should be enough, but it's
    8630             :     // not. The problem is that scrolling the selection into view when it is
    8631             :     // below the current viewport will align the top line of the frame exactly
    8632             :     // with the bottom of the window. This is fine, BUT, the popup event causes
    8633             :     // the control to be re-focused which does this exact call to
    8634             :     // ScrollContentIntoView, which has a one-pixel disagreement of whether the
    8635             :     // frame is actually in view. The result is that the frame is aligned with
    8636             :     // the top of the window, but the menu is still at the bottom.
    8637             :     //
    8638             :     // Doing this call first forces the frame to be in view, eliminating the
    8639             :     // problem. The only difference in the result is that if your cursor is in
    8640             :     // an edit box below the current view, you'll get the edit box aligned with
    8641             :     // the top of the window. This is arguably better behavior anyway.
    8642           0 :     rv = ScrollContentIntoView(content,
    8643             :                                nsIPresShell::ScrollAxis(
    8644             :                                  nsIPresShell::SCROLL_MINIMUM,
    8645             :                                  nsIPresShell::SCROLL_IF_NOT_VISIBLE),
    8646             :                                nsIPresShell::ScrollAxis(
    8647             :                                  nsIPresShell::SCROLL_MINIMUM,
    8648             :                                  nsIPresShell::SCROLL_IF_NOT_VISIBLE),
    8649           0 :                                nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
    8650           0 :     NS_ENSURE_SUCCESS(rv, false);
    8651           0 :     frame = content->GetPrimaryFrame();
    8652           0 :     NS_WARNING_ASSERTION(frame, "No frame for focused content?");
    8653             :   }
    8654             : 
    8655             :   // Actually scroll the selection (ie caret) into view. Note that this must
    8656             :   // be synchronous since we will be checking the caret position on the screen.
    8657             :   //
    8658             :   // Be easy about errors, and just don't scroll in those cases. Better to have
    8659             :   // the correct menu at a weird place than the wrong menu.
    8660             :   // After ScrollSelectionIntoView(), the pending notifications might be
    8661             :   // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
    8662           0 :   nsCOMPtr<nsISelectionController> selCon;
    8663           0 :   if (frame)
    8664           0 :     frame->GetSelectionController(GetPresContext(), getter_AddRefs(selCon));
    8665             :   else
    8666           0 :     selCon = static_cast<nsISelectionController *>(this);
    8667           0 :   if (selCon) {
    8668           0 :     rv = selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
    8669             :                                          nsISelectionController::SELECTION_FOCUS_REGION,
    8670           0 :                                          nsISelectionController::SCROLL_SYNCHRONOUS);
    8671           0 :     NS_ENSURE_SUCCESS(rv, false);
    8672             :   }
    8673             : 
    8674           0 :   nsPresContext* presContext = GetPresContext();
    8675             : 
    8676             :   // get caret position relative to the closest view
    8677           0 :   nsRect caretCoords;
    8678           0 :   nsIFrame* caretFrame = caret->GetGeometry(&caretCoords);
    8679           0 :   if (!caretFrame)
    8680           0 :     return false;
    8681           0 :   nsPoint viewOffset;
    8682           0 :   nsView* view = caretFrame->GetClosestView(&viewOffset);
    8683           0 :   if (!view)
    8684           0 :     return false;
    8685             :   // and then get the caret coords relative to the event widget
    8686           0 :   if (aEventWidget) {
    8687           0 :     viewOffset += view->GetOffsetToWidget(aEventWidget);
    8688             :   }
    8689           0 :   caretCoords.MoveBy(viewOffset);
    8690             : 
    8691             :   // caret coordinates are in app units, convert to pixels
    8692           0 :   aTargetPt.x =
    8693           0 :     presContext->AppUnitsToDevPixels(caretCoords.x + caretCoords.width);
    8694           0 :   aTargetPt.y =
    8695           0 :     presContext->AppUnitsToDevPixels(caretCoords.y + caretCoords.height);
    8696             : 
    8697             :   // make sure rounding doesn't return a pixel which is outside the caret
    8698             :   // (e.g. one line lower)
    8699           0 :   aTargetPt.y -= 1;
    8700             : 
    8701           0 :   return true;
    8702             : }
    8703             : 
    8704             : void
    8705           0 : PresShell::GetCurrentItemAndPositionForElement(nsIDOMElement *aCurrentEl,
    8706             :                                                nsIContent** aTargetToUse,
    8707             :                                                LayoutDeviceIntPoint& aTargetPt,
    8708             :                                                nsIWidget *aRootWidget)
    8709             : {
    8710           0 :   nsCOMPtr<nsIContent> focusedContent(do_QueryInterface(aCurrentEl));
    8711           0 :   ScrollContentIntoView(focusedContent,
    8712             :                         ScrollAxis(),
    8713             :                         ScrollAxis(),
    8714           0 :                         nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
    8715             : 
    8716           0 :   nsPresContext* presContext = GetPresContext();
    8717             : 
    8718           0 :   bool istree = false, checkLineHeight = true;
    8719           0 :   nscoord extraTreeY = 0;
    8720             : 
    8721             : #ifdef MOZ_XUL
    8722             :   // Set the position to just underneath the current item for multi-select
    8723             :   // lists or just underneath the selected item for single-select lists. If
    8724             :   // the element is not a list, or there is no selection, leave the position
    8725             :   // as is.
    8726           0 :   nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
    8727             :   nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
    8728           0 :     do_QueryInterface(aCurrentEl);
    8729           0 :   if (multiSelect) {
    8730           0 :     checkLineHeight = false;
    8731             : 
    8732             :     int32_t currentIndex;
    8733           0 :     multiSelect->GetCurrentIndex(&currentIndex);
    8734           0 :     if (currentIndex >= 0) {
    8735             :       RefPtr<nsXULElement> xulElement =
    8736           0 :         nsXULElement::FromContent(focusedContent);
    8737           0 :       if (xulElement) {
    8738           0 :         IgnoredErrorResult ignored;
    8739           0 :         nsCOMPtr<nsIBoxObject> box = xulElement->GetBoxObject(ignored);
    8740           0 :         nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box));
    8741             :         // Tree view special case (tree items have no frames)
    8742             :         // Get the focused row and add its coordinates, which are already in pixels
    8743             :         // XXX Boris, should we create a new interface so that this doesn't
    8744             :         // need to know about trees? Something like nsINodelessChildCreator which
    8745             :         // could provide the current focus coordinates?
    8746           0 :         if (treeBox) {
    8747           0 :           treeBox->EnsureRowIsVisible(currentIndex);
    8748             :           int32_t firstVisibleRow, rowHeight;
    8749           0 :           treeBox->GetFirstVisibleRow(&firstVisibleRow);
    8750           0 :           treeBox->GetRowHeight(&rowHeight);
    8751             : 
    8752           0 :           extraTreeY += presContext->CSSPixelsToAppUnits(
    8753           0 :                           (currentIndex - firstVisibleRow + 1) * rowHeight);
    8754           0 :           istree = true;
    8755             : 
    8756           0 :           nsCOMPtr<nsITreeColumns> cols;
    8757           0 :           treeBox->GetColumns(getter_AddRefs(cols));
    8758           0 :           if (cols) {
    8759           0 :             nsCOMPtr<nsITreeColumn> col;
    8760           0 :             cols->GetFirstColumn(getter_AddRefs(col));
    8761           0 :             if (col) {
    8762           0 :               nsCOMPtr<nsIDOMElement> colElement;
    8763           0 :               col->GetElement(getter_AddRefs(colElement));
    8764           0 :               nsCOMPtr<nsIContent> colContent(do_QueryInterface(colElement));
    8765           0 :               if (colContent) {
    8766           0 :                 nsIFrame* frame = colContent->GetPrimaryFrame();
    8767           0 :                 if (frame) {
    8768           0 :                   extraTreeY += frame->GetSize().height;
    8769             :                 }
    8770             :               }
    8771             :             }
    8772             :           }
    8773             :         }
    8774             :         else {
    8775           0 :           multiSelect->GetCurrentItem(getter_AddRefs(item));
    8776             :         }
    8777             :       }
    8778             :     }
    8779             :   }
    8780             :   else {
    8781             :     // don't check menulists as the selected item will be inside a popup.
    8782           0 :     nsCOMPtr<nsIDOMXULMenuListElement> menulist = do_QueryInterface(aCurrentEl);
    8783           0 :     if (!menulist) {
    8784             :       nsCOMPtr<nsIDOMXULSelectControlElement> select =
    8785           0 :         do_QueryInterface(aCurrentEl);
    8786           0 :       if (select) {
    8787           0 :         checkLineHeight = false;
    8788           0 :         select->GetSelectedItem(getter_AddRefs(item));
    8789             :       }
    8790             :     }
    8791             :   }
    8792             : 
    8793           0 :   if (item)
    8794           0 :     focusedContent = do_QueryInterface(item);
    8795             : #endif
    8796             : 
    8797           0 :   nsIFrame *frame = focusedContent->GetPrimaryFrame();
    8798           0 :   if (frame) {
    8799           0 :     NS_ASSERTION(frame->PresContext() == GetPresContext(),
    8800             :       "handling event for focused content that is not in our document?");
    8801             : 
    8802           0 :     nsPoint frameOrigin(0, 0);
    8803             : 
    8804             :     // Get the frame's origin within its view
    8805           0 :     nsView *view = frame->GetClosestView(&frameOrigin);
    8806           0 :     NS_ASSERTION(view, "No view for frame");
    8807             : 
    8808             :     // View's origin relative the widget
    8809           0 :     if (aRootWidget) {
    8810           0 :       frameOrigin += view->GetOffsetToWidget(aRootWidget);
    8811             :     }
    8812             : 
    8813             :     // Start context menu down and to the right from top left of frame
    8814             :     // use the lineheight. This is a good distance to move the context
    8815             :     // menu away from the top left corner of the frame. If we always
    8816             :     // used the frame height, the context menu could end up far away,
    8817             :     // for example when we're focused on linked images.
    8818             :     // On the other hand, we want to use the frame height if it's less
    8819             :     // than the current line height, so that the context menu appears
    8820             :     // associated with the correct frame.
    8821           0 :     nscoord extra = 0;
    8822           0 :     if (!istree) {
    8823           0 :       extra = frame->GetSize().height;
    8824           0 :       if (checkLineHeight) {
    8825             :         nsIScrollableFrame *scrollFrame =
    8826           0 :           nsLayoutUtils::GetNearestScrollableFrame(frame);
    8827           0 :         if (scrollFrame) {
    8828           0 :           nsSize scrollAmount = scrollFrame->GetLineScrollAmount();
    8829           0 :           nsIFrame* f = do_QueryFrame(scrollFrame);
    8830           0 :           int32_t APD = presContext->AppUnitsPerDevPixel();
    8831           0 :           int32_t scrollAPD = f->PresContext()->AppUnitsPerDevPixel();
    8832           0 :           scrollAmount = scrollAmount.ScaleToOtherAppUnits(scrollAPD, APD);
    8833           0 :           if (extra > scrollAmount.height) {
    8834           0 :             extra = scrollAmount.height;
    8835             :           }
    8836             :         }
    8837             :       }
    8838             :     }
    8839             : 
    8840           0 :     aTargetPt.x = presContext->AppUnitsToDevPixels(frameOrigin.x);
    8841           0 :     aTargetPt.y = presContext->AppUnitsToDevPixels(
    8842           0 :                     frameOrigin.y + extra + extraTreeY);
    8843             :   }
    8844             : 
    8845           0 :   NS_IF_ADDREF(*aTargetToUse = focusedContent);
    8846           0 : }
    8847             : 
    8848             : bool
    8849           0 : PresShell::ShouldIgnoreInvalidation()
    8850             : {
    8851           0 :   return mPaintingSuppressed || !mIsActive || mIsNeverPainting;
    8852             : }
    8853             : 
    8854             : void
    8855          35 : PresShell::WillPaint()
    8856             : {
    8857             :   // Check the simplest things first.  In particular, it's important to
    8858             :   // check mIsActive before making any of the more expensive calls such
    8859             :   // as GetRootPresContext, for the case of a browser with a large
    8860             :   // number of tabs.
    8861             :   // Don't bother doing anything if some viewmanager in our tree is painting
    8862             :   // while we still have painting suppressed or we are not active.
    8863          35 :   if (!mIsActive || mPaintingSuppressed || !IsVisible()) {
    8864           2 :     return;
    8865             :   }
    8866             : 
    8867          33 :   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
    8868          33 :   if (!rootPresContext) {
    8869             :     // In some edge cases, such as when we don't have a root frame yet,
    8870             :     // we can't find the root prescontext. There's nothing to do in that
    8871             :     // case.
    8872           0 :     return;
    8873             :   }
    8874             : 
    8875          33 :   rootPresContext->FlushWillPaintObservers();
    8876          33 :   if (mIsDestroying)
    8877           0 :     return;
    8878             : 
    8879             :   // Process reflows, if we have them, to reduce flicker due to invalidates and
    8880             :   // reflow being interspersed.  Note that we _do_ allow this to be
    8881             :   // interruptible; if we can't do all the reflows it's better to flicker a bit
    8882             :   // than to freeze up.
    8883          33 :   FlushPendingNotifications(ChangesToFlush(FlushType::InterruptibleLayout, false));
    8884             : }
    8885             : 
    8886             : void
    8887           3 : PresShell::WillPaintWindow()
    8888             : {
    8889           3 :   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
    8890           3 :   if (rootPresContext != mPresContext) {
    8891             :     // This could be a popup's presshell. We don't allow plugins in popups
    8892             :     // so there's nothing to do here.
    8893           0 :     return;
    8894             :   }
    8895             : 
    8896             : #ifndef XP_MACOSX
    8897           3 :   rootPresContext->ApplyPluginGeometryUpdates();
    8898             : #endif
    8899             : }
    8900             : 
    8901             : void
    8902           3 : PresShell::DidPaintWindow()
    8903             : {
    8904           3 :   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
    8905           3 :   if (rootPresContext != mPresContext) {
    8906             :     // This could be a popup's presshell. No point in notifying XPConnect
    8907             :     // about compositing of popups.
    8908           0 :     return;
    8909             :   }
    8910             : 
    8911           3 :   if (!mHasReceivedPaintMessage) {
    8912           2 :     mHasReceivedPaintMessage = true;
    8913             : 
    8914           4 :     nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService();
    8915           2 :     if (obsvc && mDocument) {
    8916           2 :       nsPIDOMWindowOuter* window = mDocument->GetWindow();
    8917           4 :       nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(window));
    8918           2 :       if (chromeWin) {
    8919           1 :         obsvc->NotifyObservers(chromeWin, "widget-first-paint", nullptr);
    8920             :       }
    8921             :     }
    8922             :   }
    8923             : }
    8924             : 
    8925             : bool
    8926         124 : PresShell::IsVisible()
    8927             : {
    8928         124 :   if (!mIsActive || !mViewManager)
    8929           0 :     return false;
    8930             : 
    8931         124 :   nsView* view = mViewManager->GetRootView();
    8932         124 :   if (!view)
    8933           0 :     return true;
    8934             : 
    8935             :   // inner view of subdoc frame
    8936         124 :   view = view->GetParent();
    8937         124 :   if (!view)
    8938         123 :     return true;
    8939             : 
    8940             :   // subdoc view
    8941           1 :   view = view->GetParent();
    8942           1 :   if (!view)
    8943           0 :     return true;
    8944             : 
    8945           1 :   nsIFrame* frame = view->GetFrame();
    8946           1 :   if (!frame)
    8947           0 :     return true;
    8948             : 
    8949           1 :   return frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY);
    8950             : }
    8951             : 
    8952             : nsresult
    8953           0 : PresShell::GetAgentStyleSheets(nsTArray<RefPtr<StyleSheet>>& aSheets)
    8954             : {
    8955           0 :   aSheets.Clear();
    8956           0 :   int32_t sheetCount = mStyleSet->SheetCount(SheetType::Agent);
    8957             : 
    8958           0 :   if (!aSheets.SetCapacity(sheetCount, fallible)) {
    8959           0 :     return NS_ERROR_OUT_OF_MEMORY;
    8960             :   }
    8961             : 
    8962           0 :   for (int32_t i = 0; i < sheetCount; ++i) {
    8963           0 :     StyleSheet* sheet = mStyleSet->StyleSheetAt(SheetType::Agent, i);
    8964           0 :     aSheets.AppendElement(sheet);
    8965             :   }
    8966             : 
    8967           0 :   return NS_OK;
    8968             : }
    8969             : 
    8970             : nsresult
    8971           0 : PresShell::SetAgentStyleSheets(const nsTArray<RefPtr<StyleSheet>>& aSheets)
    8972             : {
    8973           0 :   return mStyleSet->ReplaceSheets(SheetType::Agent, aSheets);
    8974             : }
    8975             : 
    8976             : nsresult
    8977           0 : PresShell::AddOverrideStyleSheet(StyleSheet* aSheet)
    8978             : {
    8979           0 :   return mStyleSet->PrependStyleSheet(SheetType::Override, aSheet);
    8980             : }
    8981             : 
    8982             : nsresult
    8983           0 : PresShell::RemoveOverrideStyleSheet(StyleSheet* aSheet)
    8984             : {
    8985           0 :   return mStyleSet->RemoveStyleSheet(SheetType::Override, aSheet);
    8986             : }
    8987             : 
    8988             : static void
    8989           0 : FreezeElement(nsISupports *aSupports, void * /* unused */)
    8990             : {
    8991           0 :   nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aSupports));
    8992           0 :   if (olc) {
    8993           0 :     olc->StopPluginInstance();
    8994             :   }
    8995           0 : }
    8996             : 
    8997             : static bool
    8998           0 : FreezeSubDocument(nsIDocument *aDocument, void *aData)
    8999             : {
    9000           0 :   nsIPresShell *shell = aDocument->GetShell();
    9001           0 :   if (shell)
    9002           0 :     shell->Freeze();
    9003             : 
    9004           0 :   return true;
    9005             : }
    9006             : 
    9007             : void
    9008           0 : PresShell::Freeze()
    9009             : {
    9010           0 :   mUpdateApproximateFrameVisibilityEvent.Revoke();
    9011             : 
    9012           0 :   MaybeReleaseCapturingContent();
    9013             : 
    9014           0 :   mDocument->EnumerateActivityObservers(FreezeElement, nullptr);
    9015             : 
    9016           0 :   if (mCaret) {
    9017           0 :     SetCaretEnabled(false);
    9018             :   }
    9019             : 
    9020           0 :   mPaintingSuppressed = true;
    9021             : 
    9022           0 :   if (mDocument) {
    9023           0 :     mDocument->EnumerateSubDocuments(FreezeSubDocument, nullptr);
    9024             :   }
    9025             : 
    9026           0 :   nsPresContext* presContext = GetPresContext();
    9027           0 :   if (presContext) {
    9028           0 :     presContext->DisableInteractionTimeRecording();
    9029           0 :     if (presContext->RefreshDriver()->GetPresContext() == presContext) {
    9030           0 :       presContext->RefreshDriver()->Freeze();
    9031             :     }
    9032             :   }
    9033             : 
    9034           0 :   mFrozen = true;
    9035           0 :   if (mDocument) {
    9036           0 :     UpdateImageLockingState();
    9037             :   }
    9038           0 : }
    9039             : 
    9040             : void
    9041           0 : PresShell::FireOrClearDelayedEvents(bool aFireEvents)
    9042             : {
    9043           0 :   mNoDelayedMouseEvents = false;
    9044           0 :   mNoDelayedKeyEvents = false;
    9045           0 :   if (!aFireEvents) {
    9046           0 :     mDelayedEvents.Clear();
    9047           0 :     return;
    9048             :   }
    9049             : 
    9050           0 :   if (mDocument) {
    9051           0 :     nsCOMPtr<nsIDocument> doc = mDocument;
    9052           0 :     while (!mIsDestroying && mDelayedEvents.Length() &&
    9053           0 :            !doc->EventHandlingSuppressed()) {
    9054           0 :       nsAutoPtr<DelayedEvent> ev(mDelayedEvents[0].forget());
    9055           0 :       mDelayedEvents.RemoveElementAt(0);
    9056           0 :       if (ev->IsKeyPressEvent() && mIsLastKeyDownCanceled) {
    9057           0 :         continue;
    9058             :       }
    9059           0 :       ev->Dispatch();
    9060             :     }
    9061           0 :     if (!doc->EventHandlingSuppressed()) {
    9062           0 :       mDelayedEvents.Clear();
    9063             :     }
    9064             :   }
    9065             : }
    9066             : 
    9067             : static void
    9068           0 : ThawElement(nsISupports *aSupports, void *aShell)
    9069             : {
    9070           0 :   nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aSupports));
    9071           0 :   if (olc) {
    9072           0 :     olc->AsyncStartPluginInstance();
    9073             :   }
    9074           0 : }
    9075             : 
    9076             : static bool
    9077           0 : ThawSubDocument(nsIDocument *aDocument, void *aData)
    9078             : {
    9079           0 :   nsIPresShell *shell = aDocument->GetShell();
    9080           0 :   if (shell)
    9081           0 :     shell->Thaw();
    9082             : 
    9083           0 :   return true;
    9084             : }
    9085             : 
    9086             : void
    9087           0 : PresShell::Thaw()
    9088             : {
    9089           0 :   nsPresContext* presContext = GetPresContext();
    9090           0 :   if (presContext &&
    9091           0 :       presContext->RefreshDriver()->GetPresContext() == presContext) {
    9092           0 :     presContext->RefreshDriver()->Thaw();
    9093             :   }
    9094             : 
    9095           0 :   mDocument->EnumerateActivityObservers(ThawElement, this);
    9096             : 
    9097           0 :   if (mDocument)
    9098           0 :     mDocument->EnumerateSubDocuments(ThawSubDocument, nullptr);
    9099             : 
    9100             :   // Get the activeness of our presshell, as this might have changed
    9101             :   // while we were in the bfcache
    9102           0 :   QueryIsActive();
    9103             : 
    9104             :   // We're now unfrozen
    9105           0 :   mFrozen = false;
    9106           0 :   UpdateImageLockingState();
    9107             : 
    9108           0 :   UnsuppressPainting();
    9109           0 : }
    9110             : 
    9111             : //--------------------------------------------------------
    9112             : // Start of protected and private methods on the PresShell
    9113             : //--------------------------------------------------------
    9114             : 
    9115             : void
    9116         158 : PresShell::MaybeScheduleReflow()
    9117             : {
    9118         158 :   ASSERT_REFLOW_SCHEDULED_STATE();
    9119         210 :   if (mObservingLayoutFlushes || mIsDestroying || mIsReflowing ||
    9120          52 :       mDirtyRoots.IsEmpty())
    9121         113 :     return;
    9122             : 
    9123          45 :   if (!mPresContext->HasPendingInterrupt() || !ScheduleReflowOffTimer()) {
    9124          45 :     ScheduleReflow();
    9125             :   }
    9126             : 
    9127          45 :   ASSERT_REFLOW_SCHEDULED_STATE();
    9128             : }
    9129             : 
    9130             : void
    9131          45 : PresShell::ScheduleReflow()
    9132             : {
    9133          45 :   ASSERT_REFLOW_SCHEDULED_STATE();
    9134          45 :   DoObserveLayoutFlushes();
    9135          45 :   ASSERT_REFLOW_SCHEDULED_STATE();
    9136          45 : }
    9137             : 
    9138             : nsresult
    9139         830 : PresShell::DidCauseReflow()
    9140             : {
    9141         830 :   NS_ASSERTION(mChangeNestCount != 0, "Unexpected call to DidCauseReflow()");
    9142         830 :   --mChangeNestCount;
    9143         830 :   nsContentUtils::RemoveScriptBlocker();
    9144             : 
    9145         830 :   return NS_OK;
    9146             : }
    9147             : 
    9148             : void
    9149          68 : PresShell::WillDoReflow()
    9150             : {
    9151          68 :   mDocument->FlushUserFontSet();
    9152             : 
    9153          68 :   mPresContext->FlushCounterStyles();
    9154             : 
    9155          68 :   mFrameConstructor->BeginUpdate();
    9156             : 
    9157          68 :   mLastReflowStart = GetPerformanceNow();
    9158          68 : }
    9159             : 
    9160             : void
    9161          68 : PresShell::DidDoReflow(bool aInterruptible)
    9162             : {
    9163          68 :   mFrameConstructor->EndUpdate();
    9164             : 
    9165          68 :   HandlePostedReflowCallbacks(aInterruptible);
    9166             : 
    9167         136 :   nsCOMPtr<nsIDocShell> docShell = mPresContext->GetDocShell();
    9168          68 :   if (docShell) {
    9169          29 :     DOMHighResTimeStamp now = GetPerformanceNow();
    9170          29 :     docShell->NotifyReflowObservers(aInterruptible, mLastReflowStart, now);
    9171             :   }
    9172             : 
    9173          68 :   if (sSynthMouseMove) {
    9174          68 :     SynthesizeMouseMove(false);
    9175             :   }
    9176             : 
    9177          68 :   mPresContext->NotifyMissingFonts();
    9178          68 : }
    9179             : 
    9180             : DOMHighResTimeStamp
    9181          97 : PresShell::GetPerformanceNow()
    9182             : {
    9183          97 :   DOMHighResTimeStamp now = 0;
    9184             : 
    9185          97 :   if (nsPIDOMWindowInner* window = mDocument->GetInnerWindow()) {
    9186          58 :     Performance* perf = window->GetPerformance();
    9187             : 
    9188          58 :     if (perf) {
    9189          58 :       now = perf->Now();
    9190             :     }
    9191             :   }
    9192             : 
    9193          97 :   return now;
    9194             : }
    9195             : 
    9196             : void
    9197           0 : PresShell::sReflowContinueCallback(nsITimer* aTimer, void* aPresShell)
    9198             : {
    9199           0 :   RefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
    9200             : 
    9201           0 :   NS_PRECONDITION(aTimer == self->mReflowContinueTimer, "Unexpected timer");
    9202           0 :   self->mReflowContinueTimer = nullptr;
    9203           0 :   self->ScheduleReflow();
    9204           0 : }
    9205             : 
    9206             : bool
    9207           0 : PresShell::ScheduleReflowOffTimer()
    9208             : {
    9209           0 :   NS_PRECONDITION(!mObservingLayoutFlushes, "Shouldn't get here");
    9210           0 :   ASSERT_REFLOW_SCHEDULED_STATE();
    9211             : 
    9212           0 :   if (!mReflowContinueTimer) {
    9213           0 :     mReflowContinueTimer = do_CreateInstance("@mozilla.org/timer;1");
    9214           0 :     mReflowContinueTimer->SetTarget(
    9215           0 :         mDocument->EventTargetFor(TaskCategory::Other));
    9216           0 :     if (!mReflowContinueTimer ||
    9217           0 :         NS_FAILED(mReflowContinueTimer->
    9218             :                     InitWithNamedFuncCallback(sReflowContinueCallback, this, 30,
    9219             :                                               nsITimer::TYPE_ONE_SHOT,
    9220             :                                               "sReflowContinueCallback"))) {
    9221           0 :       return false;
    9222             :     }
    9223             :   }
    9224           0 :   return true;
    9225             : }
    9226             : 
    9227             : bool
    9228          70 : PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
    9229             : {
    9230          70 :   gfxTextPerfMetrics* tp = mPresContext->GetTextPerfMetrics();
    9231          70 :   TimeStamp timeStart;
    9232          70 :   if (tp) {
    9233           0 :     tp->Accumulate();
    9234           0 :     tp->reflowCount++;
    9235           0 :     timeStart = TimeStamp::Now();
    9236             :   }
    9237             : 
    9238          70 :   target->SchedulePaint();
    9239          70 :   nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(target);
    9240          86 :   while (parent) {
    9241           8 :     nsSVGEffects::InvalidateDirectRenderingObservers(parent);
    9242           8 :     parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
    9243             :   }
    9244             : 
    9245          70 :   nsIURI* uri = mDocument->GetDocumentURI();
    9246         140 :   nsCString uriString = uri ? uri->GetSpecOrDefault() : NS_LITERAL_CSTRING("N/A");
    9247         140 :   AUTO_PROFILER_LABEL_DYNAMIC("PresShell::DoReflow", GRAPHICS, uriString.get());
    9248             : 
    9249          70 :   nsDocShell* docShell = static_cast<nsDocShell*>(GetPresContext()->GetDocShell());
    9250         140 :   RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
    9251          70 :   bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
    9252             : 
    9253          70 :   if (isTimelineRecording) {
    9254           0 :     timelines->AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::START);
    9255             :   }
    9256             : 
    9257          70 :   if (mReflowContinueTimer) {
    9258           0 :     mReflowContinueTimer->Cancel();
    9259           0 :     mReflowContinueTimer = nullptr;
    9260             :   }
    9261             : 
    9262          70 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    9263             : 
    9264             :   // CreateReferenceRenderingContext can return nullptr
    9265         140 :   RefPtr<gfxContext> rcx(CreateReferenceRenderingContext());
    9266             : 
    9267             : #ifdef DEBUG
    9268          70 :   mCurrentReflowRoot = target;
    9269             : #endif
    9270             : 
    9271             :   // If the target frame is the root of the frame hierarchy, then
    9272             :   // use all the available space. If it's simply a `reflow root',
    9273             :   // then use the target frame's size as the available space.
    9274          70 :   WritingMode wm = target->GetWritingMode();
    9275          70 :   LogicalSize size(wm);
    9276          70 :   if (target == rootFrame) {
    9277          66 :     size = LogicalSize(wm, mPresContext->GetVisibleArea().Size());
    9278             :   } else {
    9279           4 :     size = target->GetLogicalSize();
    9280             :   }
    9281             : 
    9282          70 :   NS_ASSERTION(!target->GetNextInFlow() && !target->GetPrevInFlow(),
    9283             :                "reflow roots should never split");
    9284             : 
    9285             :   // Don't pass size directly to the reflow state, since a
    9286             :   // constrained height implies page/column breaking.
    9287          70 :   LogicalSize reflowSize(wm, size.ISize(wm), NS_UNCONSTRAINEDSIZE);
    9288             :   ReflowInput reflowInput(mPresContext, target, rcx, reflowSize,
    9289          70 :                                 ReflowInput::CALLER_WILL_INIT);
    9290          70 :   reflowInput.mOrthogonalLimit = size.BSize(wm);
    9291             : 
    9292          70 :   if (rootFrame == target) {
    9293          66 :     reflowInput.Init(mPresContext);
    9294             : 
    9295             :     // When the root frame is being reflowed with unconstrained block-size
    9296             :     // (which happens when we're called from
    9297             :     // nsDocumentViewer::SizeToContent), we're effectively doing a
    9298             :     // resize in the block direction, since it changes the meaning of
    9299             :     // percentage block-sizes even if no block-sizes actually changed.
    9300             :     // The same applies when we reflow again after that computation. This is
    9301             :     // an unusual case, and isn't caught by ReflowInput::InitResizeFlags.
    9302          66 :     bool hasUnconstrainedBSize = size.BSize(wm) == NS_UNCONSTRAINEDSIZE;
    9303             : 
    9304          66 :     if (hasUnconstrainedBSize || mLastRootReflowHadUnconstrainedBSize) {
    9305           0 :       reflowInput.SetBResize(true);
    9306             :     }
    9307             : 
    9308          66 :     mLastRootReflowHadUnconstrainedBSize = hasUnconstrainedBSize;
    9309             :   } else {
    9310             :     // Initialize reflow state with current used border and padding,
    9311             :     // in case this was set specially by the parent frame when the reflow root
    9312             :     // was reflowed by its parent.
    9313           4 :     nsMargin currentBorder = target->GetUsedBorder();
    9314           4 :     nsMargin currentPadding = target->GetUsedPadding();
    9315           4 :     reflowInput.Init(mPresContext, nullptr, &currentBorder, &currentPadding);
    9316             :   }
    9317             : 
    9318             :   // fix the computed height
    9319          70 :   NS_ASSERTION(reflowInput.ComputedPhysicalMargin() == nsMargin(0, 0, 0, 0),
    9320             :                "reflow state should not set margin for reflow roots");
    9321          70 :   if (size.BSize(wm) != NS_UNCONSTRAINEDSIZE) {
    9322             :     nscoord computedBSize =
    9323          70 :       size.BSize(wm) - reflowInput.ComputedLogicalBorderPadding().BStartEnd(wm);
    9324          70 :     computedBSize = std::max(computedBSize, 0);
    9325          70 :     reflowInput.SetComputedBSize(computedBSize);
    9326             :   }
    9327          70 :   NS_ASSERTION(reflowInput.ComputedISize() ==
    9328             :                size.ISize(wm) -
    9329             :                    reflowInput.ComputedLogicalBorderPadding().IStartEnd(wm),
    9330             :                "reflow state computed incorrect inline size");
    9331             : 
    9332          70 :   mPresContext->ReflowStarted(aInterruptible);
    9333          70 :   mIsReflowing = true;
    9334             : 
    9335          70 :   nsReflowStatus status;
    9336         140 :   ReflowOutput desiredSize(reflowInput);
    9337          70 :   target->Reflow(mPresContext, desiredSize, reflowInput, status);
    9338             : 
    9339             :   // If an incremental reflow is initiated at a frame other than the
    9340             :   // root frame, then its desired size had better not change!  If it's
    9341             :   // initiated at the root, then the size better not change unless its
    9342             :   // height was unconstrained to start with.
    9343         140 :   nsRect boundsRelativeToTarget = nsRect(0, 0, desiredSize.Width(), desiredSize.Height());
    9344          70 :   NS_ASSERTION((target == rootFrame &&
    9345             :                 size.BSize(wm) == NS_UNCONSTRAINEDSIZE) ||
    9346             :                (desiredSize.ISize(wm) == size.ISize(wm) &&
    9347             :                 desiredSize.BSize(wm) == size.BSize(wm)),
    9348             :                "non-root frame's desired size changed during an "
    9349             :                "incremental reflow");
    9350          70 :   NS_ASSERTION(target == rootFrame ||
    9351             :                desiredSize.VisualOverflow().IsEqualInterior(boundsRelativeToTarget),
    9352             :                "non-root reflow roots must not have visible overflow");
    9353          70 :   NS_ASSERTION(target == rootFrame ||
    9354             :                desiredSize.ScrollableOverflow().IsEqualEdges(boundsRelativeToTarget),
    9355             :                "non-root reflow roots must not have scrollable overflow");
    9356          70 :   NS_ASSERTION(status.IsEmpty(),
    9357             :                "reflow roots should never split");
    9358             : 
    9359          70 :   target->SetSize(boundsRelativeToTarget.Size());
    9360             : 
    9361             :   // Always use boundsRelativeToTarget here, not desiredSize.GetVisualOverflowArea(),
    9362             :   // because for root frames (where they could be different, since root frames
    9363             :   // are allowed to have overflow) the root view bounds need to match the
    9364             :   // viewport bounds; the view manager "window dimensions" code depends on it.
    9365         140 :   nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, target,
    9366             :                                              target->GetView(),
    9367         140 :                                              boundsRelativeToTarget);
    9368         140 :   nsContainerFrame::SyncWindowProperties(mPresContext, target,
    9369             :                                          target->GetView(), rcx,
    9370         140 :                                          nsContainerFrame::SET_ASYNC);
    9371             : 
    9372          70 :   target->DidReflow(mPresContext, nullptr, nsDidReflowStatus::FINISHED);
    9373          70 :   if (target == rootFrame && size.BSize(wm) == NS_UNCONSTRAINEDSIZE) {
    9374           0 :     mPresContext->SetVisibleArea(boundsRelativeToTarget);
    9375             :   }
    9376             : 
    9377             : #ifdef DEBUG
    9378          70 :   mCurrentReflowRoot = nullptr;
    9379             : #endif
    9380             : 
    9381          70 :   NS_ASSERTION(mPresContext->HasPendingInterrupt() ||
    9382             :                mFramesToDirty.Count() == 0,
    9383             :                "Why do we need to dirty anything if not interrupted?");
    9384             : 
    9385          70 :   mIsReflowing = false;
    9386          70 :   bool interrupted = mPresContext->HasPendingInterrupt();
    9387          70 :   if (interrupted) {
    9388             :     // Make sure target gets reflowed again.
    9389           0 :     for (auto iter = mFramesToDirty.Iter(); !iter.Done(); iter.Next()) {
    9390             :       // Mark frames dirty until target frame.
    9391           0 :       nsPtrHashKey<nsIFrame>* p = iter.Get();
    9392           0 :       for (nsIFrame* f = p->GetKey();
    9393           0 :            f && !NS_SUBTREE_DIRTY(f);
    9394             :            f = f->GetParent()) {
    9395           0 :         f->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
    9396             : 
    9397           0 :         if (f == target) {
    9398           0 :           break;
    9399             :         }
    9400             :       }
    9401             :     }
    9402             : 
    9403           0 :     NS_ASSERTION(NS_SUBTREE_DIRTY(target), "Why is the target not dirty?");
    9404           0 :     mDirtyRoots.AppendElement(target);
    9405           0 :     SetNeedLayoutFlush();
    9406             : 
    9407             :     // Clear mFramesToDirty after we've done the NS_SUBTREE_DIRTY(target)
    9408             :     // assertion so that if it fails it's easier to see what's going on.
    9409             : #ifdef NOISY_INTERRUPTIBLE_REFLOW
    9410             :     printf("mFramesToDirty.Count() == %u\n", mFramesToDirty.Count());
    9411             : #endif /* NOISY_INTERRUPTIBLE_REFLOW */
    9412           0 :     mFramesToDirty.Clear();
    9413             : 
    9414             :     // Any FlushPendingNotifications with interruptible reflows
    9415             :     // should be suppressed now. We don't want to do extra reflow work
    9416             :     // before our reflow event happens.
    9417           0 :     mSuppressInterruptibleReflows = true;
    9418           0 :     MaybeScheduleReflow();
    9419             :   }
    9420             : 
    9421             :   // dump text perf metrics for reflows with significant text processing
    9422          70 :   if (tp) {
    9423           0 :     if (tp->current.numChars > 100) {
    9424           0 :       TimeDuration reflowTime = TimeStamp::Now() - timeStart;
    9425           0 :       LogTextPerfStats(tp, this, tp->current,
    9426           0 :                        reflowTime.ToMilliseconds(), eLog_reflow, nullptr);
    9427             :     }
    9428           0 :     tp->Accumulate();
    9429             :   }
    9430             : 
    9431          70 :   if (isTimelineRecording) {
    9432           0 :     timelines->AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::END);
    9433             :   }
    9434             : 
    9435         140 :   return !interrupted;
    9436             : }
    9437             : 
    9438             : #ifdef DEBUG
    9439             : void
    9440          48 : PresShell::DoVerifyReflow()
    9441             : {
    9442          48 :   if (GetVerifyReflowEnable()) {
    9443             :     // First synchronously render what we have so far so that we can
    9444             :     // see it.
    9445           0 :     nsView* rootView = mViewManager->GetRootView();
    9446           0 :     mViewManager->InvalidateView(rootView);
    9447             : 
    9448           0 :     FlushPendingNotifications(FlushType::Layout);
    9449           0 :     mInVerifyReflow = true;
    9450           0 :     bool ok = VerifyIncrementalReflow();
    9451           0 :     mInVerifyReflow = false;
    9452           0 :     if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
    9453           0 :       printf("ProcessReflowCommands: finished (%s)\n",
    9454           0 :              ok ? "ok" : "failed");
    9455             :     }
    9456             : 
    9457           0 :     if (!mDirtyRoots.IsEmpty()) {
    9458           0 :       printf("XXX yikes! reflow commands queued during verify-reflow\n");
    9459             :     }
    9460             :   }
    9461          48 : }
    9462             : #endif
    9463             : 
    9464             : // used with Telemetry metrics
    9465             : #define NS_LONG_REFLOW_TIME_MS    5000
    9466             : 
    9467             : bool
    9468         105 : PresShell::ProcessReflowCommands(bool aInterruptible)
    9469             : {
    9470         105 :   if (mDirtyRoots.IsEmpty() && !mShouldUnsuppressPainting) {
    9471             :     // Nothing to do; bail out
    9472          57 :     return true;
    9473             :   }
    9474             : 
    9475          48 :   mozilla::TimeStamp timerStart = mozilla::TimeStamp::Now();
    9476          48 :   bool interrupted = false;
    9477          48 :   if (!mDirtyRoots.IsEmpty()) {
    9478             : 
    9479             : #ifdef DEBUG
    9480          48 :     if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
    9481           0 :       printf("ProcessReflowCommands: begin incremental reflow\n");
    9482             :     }
    9483             : #endif
    9484             : 
    9485             :     // If reflow is interruptible, then make a note of our deadline.
    9486             :     const PRIntervalTime deadline = aInterruptible
    9487          48 :         ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime)
    9488          48 :         : (PRIntervalTime)0;
    9489             : 
    9490             :     // Scope for the reflow entry point
    9491             :     {
    9492          96 :       nsAutoScriptBlocker scriptBlocker;
    9493          48 :       WillDoReflow();
    9494          96 :       AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
    9495          96 :       nsViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
    9496             : 
    9497          51 :       do {
    9498             :         // Send an incremental reflow notification to the target frame.
    9499          51 :         int32_t idx = mDirtyRoots.Length() - 1;
    9500          51 :         nsIFrame *target = mDirtyRoots[idx];
    9501          51 :         mDirtyRoots.RemoveElementAt(idx);
    9502             : 
    9503          51 :         if (!NS_SUBTREE_DIRTY(target)) {
    9504             :           // It's not dirty anymore, which probably means the notification
    9505             :           // was posted in the middle of a reflow (perhaps with a reflow
    9506             :           // root in the middle).  Don't do anything.
    9507           1 :           continue;
    9508             :         }
    9509             : 
    9510          50 :         interrupted = !DoReflow(target, aInterruptible);
    9511             : 
    9512             :         // Keep going until we're out of reflow commands, or we've run
    9513             :         // past our deadline, or we're interrupted.
    9514          57 :       } while (!interrupted && !mDirtyRoots.IsEmpty() &&
    9515           4 :                (!aInterruptible || PR_IntervalNow() < deadline));
    9516             : 
    9517          48 :       interrupted = !mDirtyRoots.IsEmpty();
    9518             :     }
    9519             : 
    9520             :     // Exiting the scriptblocker might have killed us
    9521          48 :     if (!mIsDestroying) {
    9522          48 :       DidDoReflow(aInterruptible);
    9523             :     }
    9524             : 
    9525             :     // DidDoReflow might have killed us
    9526          48 :     if (!mIsDestroying) {
    9527             : #ifdef DEBUG
    9528          48 :       if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
    9529             :         printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n",
    9530           0 :                (void*)this);
    9531             :       }
    9532          48 :       DoVerifyReflow();
    9533             : #endif
    9534             : 
    9535             :       // If any new reflow commands were enqueued during the reflow, schedule
    9536             :       // another reflow event to process them.  Note that we want to do this
    9537             :       // after DidDoReflow(), since that method can change whether there are
    9538             :       // dirty roots around by flushing, and there's no point in posting a
    9539             :       // reflow event just to have the flush revoke it.
    9540          48 :       if (!mDirtyRoots.IsEmpty()) {
    9541           0 :         MaybeScheduleReflow();
    9542             :         // And record that we might need flushing
    9543           0 :         SetNeedLayoutFlush();
    9544             :       }
    9545             :     }
    9546             :   }
    9547             : 
    9548          68 :   if (!mIsDestroying && mShouldUnsuppressPainting &&
    9549          20 :       mDirtyRoots.IsEmpty()) {
    9550             :     // We only unlock if we're out of reflows.  It's pointless
    9551             :     // to unlock if reflows are still pending, since reflows
    9552             :     // are just going to thrash the frames around some more.  By
    9553             :     // waiting we avoid an overeager "jitter" effect.
    9554          20 :     mShouldUnsuppressPainting = false;
    9555          20 :     UnsuppressAndInvalidate();
    9556             :   }
    9557             : 
    9558          48 :   if (mDocument->GetRootElement()) {
    9559          48 :     TimeDuration elapsed = TimeStamp::Now() - timerStart;
    9560          48 :     int32_t intElapsed = int32_t(elapsed.ToMilliseconds());
    9561             : 
    9562          48 :     if (intElapsed > NS_LONG_REFLOW_TIME_MS) {
    9563           0 :       Telemetry::Accumulate(Telemetry::LONG_REFLOW_INTERRUPTIBLE,
    9564           0 :                             aInterruptible ? 1 : 0);
    9565             :     }
    9566             :   }
    9567             : 
    9568          48 :   return !interrupted;
    9569             : }
    9570             : 
    9571             : void
    9572           0 : PresShell::WindowSizeMoveDone()
    9573             : {
    9574           0 :   if (mPresContext) {
    9575           0 :     EventStateManager::ClearGlobalActiveContent(nullptr);
    9576           0 :     ClearMouseCapture(nullptr);
    9577             :   }
    9578           0 : }
    9579             : 
    9580             : #ifdef MOZ_XUL
    9581             : /*
    9582             :  * It's better to add stuff to the |DidSetStyleContext| method of the
    9583             :  * relevant frames than adding it here.  These methods should (ideally,
    9584             :  * anyway) go away.
    9585             :  */
    9586             : 
    9587             : // Return value says whether to walk children.
    9588             : typedef bool (* frameWalkerFn)(nsIFrame *aFrame, void *aClosure);
    9589             : 
    9590             : static bool
    9591           0 : ReResolveMenusAndTrees(nsIFrame *aFrame, void *aClosure)
    9592             : {
    9593             :   // Trees have a special style cache that needs to be flushed when
    9594             :   // the theme changes.
    9595           0 :   nsTreeBodyFrame *treeBody = do_QueryFrame(aFrame);
    9596           0 :   if (treeBody)
    9597           0 :     treeBody->ClearStyleAndImageCaches();
    9598             : 
    9599             :   // We deliberately don't re-resolve style on a menu's popup
    9600             :   // sub-content, since doing so slows menus to a crawl.  That means we
    9601             :   // have to special-case them on a skin switch, and ensure that the
    9602             :   // popup frames just get destroyed completely.
    9603           0 :   nsMenuFrame* menu = do_QueryFrame(aFrame);
    9604           0 :   if (menu)
    9605           0 :     menu->CloseMenu(true);
    9606           0 :   return true;
    9607             : }
    9608             : 
    9609             : static bool
    9610           0 : ReframeImageBoxes(nsIFrame *aFrame, void *aClosure)
    9611             : {
    9612           0 :   nsStyleChangeList *list = static_cast<nsStyleChangeList*>(aClosure);
    9613           0 :   if (aFrame->IsImageBoxFrame()) {
    9614           0 :     list->AppendChange(aFrame, aFrame->GetContent(),
    9615           0 :                        nsChangeHint_ReconstructFrame);
    9616           0 :     return false; // don't walk descendants
    9617             :   }
    9618           0 :   return true; // walk descendants
    9619             : }
    9620             : 
    9621             : static void
    9622           0 : WalkFramesThroughPlaceholders(nsPresContext *aPresContext, nsIFrame *aFrame,
    9623             :                               frameWalkerFn aFunc, void *aClosure)
    9624             : {
    9625           0 :   bool walkChildren = (*aFunc)(aFrame, aClosure);
    9626           0 :   if (!walkChildren)
    9627           0 :     return;
    9628             : 
    9629           0 :   nsIFrame::ChildListIterator lists(aFrame);
    9630           0 :   for (; !lists.IsDone(); lists.Next()) {
    9631           0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    9632           0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    9633           0 :       nsIFrame* child = childFrames.get();
    9634           0 :       if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
    9635             :         // only do frames that are in flow, and recur through the
    9636             :         // out-of-flows of placeholders.
    9637           0 :         WalkFramesThroughPlaceholders(aPresContext,
    9638             :                                       nsPlaceholderFrame::GetRealFrameFor(child),
    9639           0 :                                       aFunc, aClosure);
    9640             :       }
    9641             :     }
    9642             :   }
    9643             : }
    9644             : #endif
    9645             : 
    9646             : NS_IMETHODIMP
    9647           0 : PresShell::Observe(nsISupports* aSubject,
    9648             :                    const char* aTopic,
    9649             :                    const char16_t* aData)
    9650             : {
    9651           0 :   if (mIsDestroying) {
    9652           0 :     NS_WARNING("our observers should have been unregistered by now");
    9653           0 :     return NS_OK;
    9654             :   }
    9655             : 
    9656             : #ifdef MOZ_XUL
    9657           0 :   if (!nsCRT::strcmp(aTopic, "chrome-flush-skin-caches")) {
    9658           0 :     nsIFrame *rootFrame = mFrameConstructor->GetRootFrame();
    9659             :     // Need to null-check because "chrome-flush-skin-caches" can happen
    9660             :     // at interesting times during startup.
    9661           0 :     if (rootFrame) {
    9662           0 :       NS_ASSERTION(mViewManager, "View manager must exist");
    9663             : 
    9664           0 :       AutoWeakFrame weakRoot(rootFrame);
    9665             :       // Have to make sure that the content notifications are flushed before we
    9666             :       // start messing with the frame model; otherwise we can get content doubling.
    9667           0 :       mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
    9668             : 
    9669           0 :       if (weakRoot.IsAlive()) {
    9670           0 :         WalkFramesThroughPlaceholders(mPresContext, rootFrame,
    9671           0 :                                       &ReResolveMenusAndTrees, nullptr);
    9672             : 
    9673             :         // Because "chrome:" URL equality is messy, reframe image box
    9674             :         // frames (hack!).
    9675           0 :         nsStyleChangeList changeList(mPresContext->StyleSet()->BackendType());
    9676           0 :         WalkFramesThroughPlaceholders(mPresContext, rootFrame,
    9677           0 :                                       ReframeImageBoxes, &changeList);
    9678             :         // Mark ourselves as not safe to flush while we're doing frame
    9679             :         // construction.
    9680             :         {
    9681           0 :           nsAutoScriptBlocker scriptBlocker;
    9682           0 :           ++mChangeNestCount;
    9683           0 :           RestyleManager* restyleManager = mPresContext->RestyleManager();
    9684           0 :           restyleManager->ProcessRestyledFrames(changeList);
    9685           0 :           restyleManager->FlushOverflowChangedTracker();
    9686           0 :           --mChangeNestCount;
    9687             :         }
    9688             :       }
    9689             :     }
    9690           0 :     return NS_OK;
    9691             :   }
    9692             : #endif
    9693             : 
    9694           0 :   if (!nsCRT::strcmp(aTopic, "memory-pressure")) {
    9695           0 :     if (!AssumeAllFramesVisible() && mPresContext->IsRootContentDocument()) {
    9696           0 :       DoUpdateApproximateFrameVisibility(/* aRemoveOnly = */ true);
    9697             :     }
    9698           0 :     return NS_OK;
    9699             :   }
    9700             : 
    9701           0 :   if (!nsCRT::strcmp(aTopic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) {
    9702           0 :     mLastOSWake = TimeStamp::Now();
    9703             :   }
    9704             : 
    9705           0 :   NS_WARNING("unrecognized topic in PresShell::Observe");
    9706           0 :   return NS_ERROR_FAILURE;
    9707             : }
    9708             : 
    9709             : bool
    9710           0 : nsIPresShell::AddRefreshObserverInternal(nsARefreshObserver* aObserver,
    9711             :                                          FlushType aFlushType)
    9712             : {
    9713           0 :   nsPresContext* presContext = GetPresContext();
    9714           0 :   return presContext &&
    9715           0 :       presContext->RefreshDriver()->AddRefreshObserver(aObserver, aFlushType);
    9716             : }
    9717             : 
    9718             : /* virtual */ bool
    9719           0 : nsIPresShell::AddRefreshObserverExternal(nsARefreshObserver* aObserver,
    9720             :                                          FlushType aFlushType)
    9721             : {
    9722           0 :   return AddRefreshObserverInternal(aObserver, aFlushType);
    9723             : }
    9724             : 
    9725             : bool
    9726           0 : nsIPresShell::RemoveRefreshObserverInternal(nsARefreshObserver* aObserver,
    9727             :                                             FlushType aFlushType)
    9728             : {
    9729           0 :   nsPresContext* presContext = GetPresContext();
    9730           0 :   return presContext &&
    9731           0 :       presContext->RefreshDriver()->RemoveRefreshObserver(aObserver, aFlushType);
    9732             : }
    9733             : 
    9734             : /* virtual */ bool
    9735           0 : nsIPresShell::RemoveRefreshObserverExternal(nsARefreshObserver* aObserver,
    9736             :                                             FlushType aFlushType)
    9737             : {
    9738           0 :   return RemoveRefreshObserverInternal(aObserver, aFlushType);
    9739             : }
    9740             : 
    9741             : /* virtual */ bool
    9742           0 : nsIPresShell::AddPostRefreshObserver(nsAPostRefreshObserver* aObserver)
    9743             : {
    9744           0 :   nsPresContext* presContext = GetPresContext();
    9745           0 :   if (!presContext) {
    9746           0 :     return false;
    9747             :   }
    9748           0 :   presContext->RefreshDriver()->AddPostRefreshObserver(aObserver);
    9749           0 :   return true;
    9750             : }
    9751             : 
    9752             : /* virtual */ bool
    9753           0 : nsIPresShell::RemovePostRefreshObserver(nsAPostRefreshObserver* aObserver)
    9754             : {
    9755           0 :   nsPresContext* presContext = GetPresContext();
    9756           0 :   if (!presContext) {
    9757           0 :     return false;
    9758             :   }
    9759           0 :   presContext->RefreshDriver()->RemovePostRefreshObserver(aObserver);
    9760           0 :   return true;
    9761             : }
    9762             : 
    9763             : void
    9764          38 : nsIPresShell::DoObserveStyleFlushes()
    9765             : {
    9766          38 :   MOZ_ASSERT(!ObservingStyleFlushes());
    9767          38 :   mObservingStyleFlushes =
    9768          38 :     mPresContext->RefreshDriver()->AddStyleFlushObserver(this);
    9769          38 : }
    9770             : 
    9771             : void
    9772          45 : nsIPresShell::DoObserveLayoutFlushes()
    9773             : {
    9774          45 :   MOZ_ASSERT(!ObservingLayoutFlushes());
    9775          45 :   mObservingLayoutFlushes =
    9776          45 :     mPresContext->RefreshDriver()->AddLayoutFlushObserver(this);
    9777          45 : }
    9778             : 
    9779             : //------------------------------------------------------
    9780             : // End of protected and private methods on the PresShell
    9781             : //------------------------------------------------------
    9782             : 
    9783             : //------------------------------------------------------------------
    9784             : //-- Delayed event Classes Impls
    9785             : //------------------------------------------------------------------
    9786             : 
    9787           0 : PresShell::DelayedInputEvent::DelayedInputEvent() :
    9788             :   DelayedEvent(),
    9789           0 :   mEvent(nullptr)
    9790             : {
    9791           0 : }
    9792             : 
    9793           0 : PresShell::DelayedInputEvent::~DelayedInputEvent()
    9794             : {
    9795           0 :   delete mEvent;
    9796           0 : }
    9797             : 
    9798             : void
    9799           0 : PresShell::DelayedInputEvent::Dispatch()
    9800             : {
    9801           0 :   if (!mEvent || !mEvent->mWidget) {
    9802           0 :     return;
    9803             :   }
    9804           0 :   nsCOMPtr<nsIWidget> widget = mEvent->mWidget;
    9805             :   nsEventStatus status;
    9806           0 :   widget->DispatchEvent(mEvent, status);
    9807             : }
    9808             : 
    9809           0 : PresShell::DelayedMouseEvent::DelayedMouseEvent(WidgetMouseEvent* aEvent) :
    9810           0 :   DelayedInputEvent()
    9811             : {
    9812             :   WidgetMouseEvent* mouseEvent =
    9813           0 :     new WidgetMouseEvent(aEvent->IsTrusted(),
    9814           0 :                          aEvent->mMessage,
    9815             :                          aEvent->mWidget,
    9816           0 :                          aEvent->mReason,
    9817           0 :                          aEvent->mContextMenuTrigger);
    9818           0 :   mouseEvent->AssignMouseEventData(*aEvent, false);
    9819           0 :   mEvent = mouseEvent;
    9820           0 : }
    9821             : 
    9822           0 : PresShell::DelayedKeyEvent::DelayedKeyEvent(WidgetKeyboardEvent* aEvent) :
    9823           0 :   DelayedInputEvent()
    9824             : {
    9825             :   WidgetKeyboardEvent* keyEvent =
    9826           0 :     new WidgetKeyboardEvent(aEvent->IsTrusted(),
    9827           0 :                             aEvent->mMessage,
    9828           0 :                             aEvent->mWidget);
    9829           0 :   keyEvent->AssignKeyEventData(*aEvent, false);
    9830           0 :   keyEvent->mFlags.mIsSynthesizedForTests = aEvent->mFlags.mIsSynthesizedForTests;
    9831           0 :   keyEvent->mFlags.mIsSuppressedOrDelayed = true;
    9832           0 :   mEvent = keyEvent;
    9833           0 : }
    9834             : 
    9835             : bool
    9836           0 : PresShell::DelayedKeyEvent::IsKeyPressEvent()
    9837             : {
    9838           0 :   return mEvent->mMessage == eKeyPress;
    9839             : }
    9840             : 
    9841             : // Start of DEBUG only code
    9842             : 
    9843             : #ifdef DEBUG
    9844             : 
    9845             : static void
    9846           0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg)
    9847             : {
    9848           0 :   nsAutoString n1, n2;
    9849           0 :   if (k1) {
    9850           0 :     k1->GetFrameName(n1);
    9851             :   } else {
    9852           0 :     n1.AssignLiteral(u"(null)");
    9853             :   }
    9854             : 
    9855           0 :   if (k2) {
    9856           0 :     k2->GetFrameName(n2);
    9857             :   } else {
    9858           0 :     n2.AssignLiteral(u"(null)");
    9859             :   }
    9860             : 
    9861           0 :   printf("verifyreflow: %s %p != %s %p  %s\n",
    9862           0 :          NS_LossyConvertUTF16toASCII(n1).get(), (void*)k1,
    9863           0 :          NS_LossyConvertUTF16toASCII(n2).get(), (void*)k2, aMsg);
    9864           0 : }
    9865             : 
    9866             : static void
    9867           0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
    9868             :                  const nsRect& r1, const nsRect& r2)
    9869             : {
    9870           0 :   printf("VerifyReflow Error:\n");
    9871           0 :   nsAutoString name;
    9872             : 
    9873           0 :   if (k1) {
    9874           0 :     k1->GetFrameName(name);
    9875           0 :     printf("  %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k1);
    9876             :   }
    9877           0 :   printf("{%d, %d, %d, %d} != \n", r1.x, r1.y, r1.width, r1.height);
    9878             : 
    9879           0 :   if (k2) {
    9880           0 :     k2->GetFrameName(name);
    9881           0 :     printf("  %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k2);
    9882             :   }
    9883             :   printf("{%d, %d, %d, %d}\n  %s\n",
    9884           0 :          r2.x, r2.y, r2.width, r2.height, aMsg);
    9885           0 : }
    9886             : 
    9887             : static void
    9888           0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
    9889             :                  const nsIntRect& r1, const nsIntRect& r2)
    9890             : {
    9891           0 :   printf("VerifyReflow Error:\n");
    9892           0 :   nsAutoString name;
    9893             : 
    9894           0 :   if (k1) {
    9895           0 :     k1->GetFrameName(name);
    9896           0 :     printf("  %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k1);
    9897             :   }
    9898           0 :   printf("{%d, %d, %d, %d} != \n", r1.x, r1.y, r1.width, r1.height);
    9899             : 
    9900           0 :   if (k2) {
    9901           0 :     k2->GetFrameName(name);
    9902           0 :     printf("  %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k2);
    9903             :   }
    9904             :   printf("{%d, %d, %d, %d}\n  %s\n",
    9905           0 :          r2.x, r2.y, r2.width, r2.height, aMsg);
    9906           0 : }
    9907             : 
    9908             : static bool
    9909           0 : CompareTrees(nsPresContext* aFirstPresContext, nsIFrame* aFirstFrame,
    9910             :              nsPresContext* aSecondPresContext, nsIFrame* aSecondFrame)
    9911             : {
    9912           0 :   if (!aFirstPresContext || !aFirstFrame || !aSecondPresContext || !aSecondFrame)
    9913           0 :     return true;
    9914             :   // XXX Evil hack to reduce false positives; I can't seem to figure
    9915             :   // out how to flush scrollbar changes correctly
    9916             :   //if (aFirstFrame->IsScrollbarFrame())
    9917             :   //  return true;
    9918           0 :   bool ok = true;
    9919           0 :   nsIFrame::ChildListIterator lists1(aFirstFrame);
    9920           0 :   nsIFrame::ChildListIterator lists2(aSecondFrame);
    9921           0 :   do {
    9922           0 :     const nsFrameList& kids1 = !lists1.IsDone() ? lists1.CurrentList() : nsFrameList();
    9923           0 :     const nsFrameList& kids2 = !lists2.IsDone() ? lists2.CurrentList() : nsFrameList();
    9924           0 :     int32_t l1 = kids1.GetLength();
    9925           0 :     int32_t l2 = kids2.GetLength();
    9926           0 :     if (l1 != l2) {
    9927           0 :       ok = false;
    9928           0 :       LogVerifyMessage(kids1.FirstChild(), kids2.FirstChild(),
    9929           0 :                        "child counts don't match: ");
    9930           0 :       printf("%d != %d\n", l1, l2);
    9931           0 :       if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
    9932           0 :         break;
    9933             :       }
    9934             :     }
    9935             : 
    9936           0 :     LayoutDeviceIntRect r1, r2;
    9937             :     nsView* v1;
    9938             :     nsView* v2;
    9939           0 :     for (nsFrameList::Enumerator e1(kids1), e2(kids2);
    9940             :          ;
    9941           0 :          e1.Next(), e2.Next()) {
    9942           0 :       nsIFrame* k1 = e1.get();
    9943           0 :       nsIFrame* k2 = e2.get();
    9944           0 :       if (((nullptr == k1) && (nullptr != k2)) ||
    9945           0 :           ((nullptr != k1) && (nullptr == k2))) {
    9946           0 :         ok = false;
    9947           0 :         LogVerifyMessage(k1, k2, "child lists are different\n");
    9948           0 :         break;
    9949             :       }
    9950           0 :       else if (nullptr != k1) {
    9951             :         // Verify that the frames are the same size
    9952           0 :         if (!k1->GetRect().IsEqualInterior(k2->GetRect())) {
    9953           0 :           ok = false;
    9954           0 :           LogVerifyMessage(k1, k2, "(frame rects)", k1->GetRect(), k2->GetRect());
    9955             :         }
    9956             : 
    9957             :         // Make sure either both have views or neither have views; if they
    9958             :         // do have views, make sure the views are the same size. If the
    9959             :         // views have widgets, make sure they both do or neither does. If
    9960             :         // they do, make sure the widgets are the same size.
    9961           0 :         v1 = k1->GetView();
    9962           0 :         v2 = k2->GetView();
    9963           0 :         if (((nullptr == v1) && (nullptr != v2)) ||
    9964           0 :             ((nullptr != v1) && (nullptr == v2))) {
    9965           0 :           ok = false;
    9966           0 :           LogVerifyMessage(k1, k2, "child views are not matched\n");
    9967             :         }
    9968           0 :         else if (nullptr != v1) {
    9969           0 :           if (!v1->GetBounds().IsEqualInterior(v2->GetBounds())) {
    9970           0 :             LogVerifyMessage(k1, k2, "(view rects)", v1->GetBounds(), v2->GetBounds());
    9971             :           }
    9972             : 
    9973           0 :           nsIWidget* w1 = v1->GetWidget();
    9974           0 :           nsIWidget* w2 = v2->GetWidget();
    9975           0 :           if (((nullptr == w1) && (nullptr != w2)) ||
    9976           0 :               ((nullptr != w1) && (nullptr == w2))) {
    9977           0 :             ok = false;
    9978           0 :             LogVerifyMessage(k1, k2, "child widgets are not matched\n");
    9979             :           }
    9980           0 :           else if (nullptr != w1) {
    9981           0 :             r1 = w1->GetBounds();
    9982           0 :             r2 = w2->GetBounds();
    9983           0 :             if (!r1.IsEqualEdges(r2)) {
    9984             :               LogVerifyMessage(k1, k2, "(widget rects)",
    9985           0 :                                r1.ToUnknownRect(), r2.ToUnknownRect());
    9986             :             }
    9987             :           }
    9988             :         }
    9989           0 :         if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
    9990           0 :           break;
    9991             :         }
    9992             : 
    9993             :         // XXX Should perhaps compare their float managers.
    9994             : 
    9995             :         // Compare the sub-trees too
    9996           0 :         if (!CompareTrees(aFirstPresContext, k1, aSecondPresContext, k2)) {
    9997           0 :           ok = false;
    9998           0 :           if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
    9999           0 :             break;
   10000             :           }
   10001             :         }
   10002             :       }
   10003             :       else {
   10004           0 :         break;
   10005             :       }
   10006           0 :     }
   10007           0 :     if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
   10008           0 :       break;
   10009             :     }
   10010             : 
   10011           0 :     lists1.Next();
   10012           0 :     lists2.Next();
   10013           0 :     if (lists1.IsDone() != lists2.IsDone() ||
   10014           0 :         (!lists1.IsDone() && lists1.CurrentID() != lists2.CurrentID())) {
   10015           0 :       if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
   10016           0 :         ok = false;
   10017             :       }
   10018           0 :       LogVerifyMessage(kids1.FirstChild(), kids2.FirstChild(),
   10019           0 :                        "child list names are not matched: ");
   10020           0 :       fprintf(stdout, "%s != %s\n",
   10021           0 :               !lists1.IsDone() ? mozilla::layout::ChildListName(lists1.CurrentID()) : "(null)",
   10022           0 :               !lists2.IsDone() ? mozilla::layout::ChildListName(lists2.CurrentID()) : "(null)");
   10023           0 :       break;
   10024             :     }
   10025           0 :   } while (ok && !lists1.IsDone());
   10026             : 
   10027           0 :   return ok;
   10028             : }
   10029             : #endif
   10030             : 
   10031             : #if 0
   10032             : static nsIFrame*
   10033             : FindTopFrame(nsIFrame* aRoot)
   10034             : {
   10035             :   if (aRoot) {
   10036             :     nsIContent* content = aRoot->GetContent();
   10037             :     if (content) {
   10038             :       nsIAtom* tag;
   10039             :       content->GetTag(tag);
   10040             :       if (nullptr != tag) {
   10041             :         NS_RELEASE(tag);
   10042             :         return aRoot;
   10043             :       }
   10044             :     }
   10045             : 
   10046             :     // Try one of the children
   10047             :     for (nsIFrame* kid : aRoot->PrincipalChildList()) {
   10048             :       nsIFrame* result = FindTopFrame(kid);
   10049             :       if (nullptr != result) {
   10050             :         return result;
   10051             :       }
   10052             :     }
   10053             :   }
   10054             :   return nullptr;
   10055             : }
   10056             : #endif
   10057             : 
   10058             : 
   10059             : #ifdef DEBUG
   10060             : 
   10061             : nsStyleSet*
   10062           0 : PresShell::CloneStyleSet(nsStyleSet* aSet)
   10063             : {
   10064           0 :   nsStyleSet* clone = new nsStyleSet();
   10065             : 
   10066           0 :   int32_t i, n = aSet->SheetCount(SheetType::Override);
   10067           0 :   for (i = 0; i < n; i++) {
   10068           0 :     CSSStyleSheet* ss = aSet->StyleSheetAt(SheetType::Override, i);
   10069           0 :     if (ss)
   10070           0 :       clone->AppendStyleSheet(SheetType::Override, ss);
   10071             :   }
   10072             : 
   10073             :   // The document expects to insert document stylesheets itself
   10074             : #if 0
   10075             :   n = aSet->SheetCount(SheetType::Doc);
   10076             :   for (i = 0; i < n; i++) {
   10077             :     CSSStyleSheet* ss = aSet->StyleSheetAt(SheetType::Doc, i);
   10078             :     if (ss)
   10079             :       clone->AddDocStyleSheet(ss, mDocument);
   10080             :   }
   10081             : #endif
   10082             : 
   10083           0 :   n = aSet->SheetCount(SheetType::User);
   10084           0 :   for (i = 0; i < n; i++) {
   10085           0 :     CSSStyleSheet* ss = aSet->StyleSheetAt(SheetType::User, i);
   10086           0 :     if (ss)
   10087           0 :       clone->AppendStyleSheet(SheetType::User, ss);
   10088             :   }
   10089             : 
   10090           0 :   n = aSet->SheetCount(SheetType::Agent);
   10091           0 :   for (i = 0; i < n; i++) {
   10092           0 :     CSSStyleSheet* ss = aSet->StyleSheetAt(SheetType::Agent, i);
   10093           0 :     if (ss)
   10094           0 :       clone->AppendStyleSheet(SheetType::Agent, ss);
   10095             :   }
   10096           0 :   return clone;
   10097             : }
   10098             : 
   10099             : // After an incremental reflow, we verify the correctness by doing a
   10100             : // full reflow into a fresh frame tree.
   10101             : bool
   10102           0 : PresShell::VerifyIncrementalReflow()
   10103             : {
   10104           0 :    if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
   10105           0 :      printf("Building Verification Tree...\n");
   10106             :    }
   10107             : 
   10108             :   // Create a presentation context to view the new frame tree
   10109             :   RefPtr<nsPresContext> cx =
   10110           0 :        new nsRootPresContext(mDocument, mPresContext->IsPaginated() ?
   10111             :                                         nsPresContext::eContext_PrintPreview :
   10112           0 :                                         nsPresContext::eContext_Galley);
   10113           0 :   NS_ENSURE_TRUE(cx, false);
   10114             : 
   10115           0 :   nsDeviceContext *dc = mPresContext->DeviceContext();
   10116           0 :   nsresult rv = cx->Init(dc);
   10117           0 :   NS_ENSURE_SUCCESS(rv, false);
   10118             : 
   10119             :   // Get our scrolling preference
   10120           0 :   nsView* rootView = mViewManager->GetRootView();
   10121           0 :   NS_ENSURE_TRUE(rootView->HasWidget(), false);
   10122           0 :   nsIWidget* parentWidget = rootView->GetWidget();
   10123             : 
   10124             :   // Create a new view manager.
   10125           0 :   RefPtr<nsViewManager> vm = new nsViewManager();
   10126           0 :   NS_ENSURE_TRUE(vm, false);
   10127           0 :   rv = vm->Init(dc);
   10128           0 :   NS_ENSURE_SUCCESS(rv, false);
   10129             : 
   10130             :   // Create a child window of the parent that is our "root view/window"
   10131             :   // Create a view
   10132           0 :   nsRect tbounds = mPresContext->GetVisibleArea();
   10133           0 :   nsView* view = vm->CreateView(tbounds, nullptr);
   10134           0 :   NS_ENSURE_TRUE(view, false);
   10135             : 
   10136             :   //now create the widget for the view
   10137           0 :   rv = view->CreateWidgetForParent(parentWidget, nullptr, true);
   10138           0 :   NS_ENSURE_SUCCESS(rv, false);
   10139             : 
   10140             :   // Setup hierarchical relationship in view manager
   10141           0 :   vm->SetRootView(view);
   10142             : 
   10143             :   // Make the new presentation context the same size as our
   10144             :   // presentation context.
   10145           0 :   nsRect r = mPresContext->GetVisibleArea();
   10146           0 :   cx->SetVisibleArea(r);
   10147             : 
   10148             :   // Create a new presentation shell to view the document. Use the
   10149             :   // exact same style information that this document has.
   10150           0 :   if (mStyleSet->IsServo()) {
   10151           0 :     NS_WARNING("VerifyIncrementalReflow cannot handle ServoStyleSets");
   10152           0 :     return true;
   10153             :   }
   10154           0 :   nsAutoPtr<nsStyleSet> newSet(CloneStyleSet(mStyleSet->AsGecko()));
   10155           0 :   nsCOMPtr<nsIPresShell> sh = mDocument->CreateShell(cx, vm, newSet.get());
   10156           0 :   NS_ENSURE_TRUE(sh, false);
   10157           0 :   newSet.forget();
   10158             :   // Note that after we create the shell, we must make sure to destroy it
   10159           0 :   sh->SetVerifyReflowEnable(false); // turn off verify reflow while we're reflowing the test frame tree
   10160           0 :   vm->SetPresShell(sh);
   10161             :   {
   10162           0 :     nsAutoCauseReflowNotifier crNotifier(this);
   10163           0 :     sh->Initialize(r.width, r.height);
   10164             :   }
   10165           0 :   mDocument->BindingManager()->ProcessAttachedQueue();
   10166           0 :   sh->FlushPendingNotifications(FlushType::Layout);
   10167           0 :   sh->SetVerifyReflowEnable(true);  // turn on verify reflow again now that we're done reflowing the test frame tree
   10168             :   // Force the non-primary presshell to unsuppress; it doesn't want to normally
   10169             :   // because it thinks it's hidden
   10170           0 :   ((PresShell*)sh.get())->mPaintingSuppressed = false;
   10171           0 :   if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
   10172           0 :      printf("Verification Tree built, comparing...\n");
   10173             :   }
   10174             : 
   10175             :   // Now that the document has been reflowed, use its frame tree to
   10176             :   // compare against our frame tree.
   10177           0 :   nsIFrame* root1 = mFrameConstructor->GetRootFrame();
   10178           0 :   nsIFrame* root2 = sh->GetRootFrame();
   10179           0 :   bool ok = CompareTrees(mPresContext, root1, cx, root2);
   10180           0 :   if (!ok && (VERIFY_REFLOW_NOISY & gVerifyReflowFlags)) {
   10181           0 :     printf("Verify reflow failed, primary tree:\n");
   10182           0 :     root1->List(stdout, 0);
   10183           0 :     printf("Verification tree:\n");
   10184           0 :     root2->List(stdout, 0);
   10185             :   }
   10186             : 
   10187             : #if 0
   10188             :   // Sample code for dumping page to png
   10189             :   // XXX Needs to be made more flexible
   10190             :   if (!ok) {
   10191             :     nsString stra;
   10192             :     static int num = 0;
   10193             :     stra.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea");
   10194             :     stra.AppendInt(num);
   10195             :     stra.AppendLiteral(".png");
   10196             :     gfxUtils::WriteAsPNG(sh, stra);
   10197             :     nsString strb;
   10198             :     strb.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb");
   10199             :     strb.AppendInt(num);
   10200             :     strb.AppendLiteral(".png");
   10201             :     gfxUtils::WriteAsPNG(sh, strb);
   10202             :     ++num;
   10203             :   }
   10204             : #endif
   10205             : 
   10206           0 :   sh->EndObservingDocument();
   10207           0 :   sh->Destroy();
   10208           0 :   if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
   10209           0 :     printf("Finished Verifying Reflow...\n");
   10210             :   }
   10211             : 
   10212           0 :   return ok;
   10213             : }
   10214             : 
   10215             : // Layout debugging hooks
   10216             : void
   10217           0 : PresShell::ListStyleContexts(FILE *out, int32_t aIndent)
   10218             : {
   10219           0 :   nsIFrame* rootFrame = GetRootFrame();
   10220           0 :   if (rootFrame) {
   10221           0 :     rootFrame->StyleContext()->List(out, aIndent);
   10222             :   }
   10223             : 
   10224             :   // The root element's frame's style context is the root of a separate tree.
   10225           0 :   Element* rootElement = mDocument->GetRootElement();
   10226           0 :   if (rootElement) {
   10227           0 :     nsIFrame* rootElementFrame = rootElement->GetPrimaryFrame();
   10228           0 :     if (rootElementFrame) {
   10229           0 :       rootElementFrame->StyleContext()->List(out, aIndent);
   10230             :     }
   10231             :   }
   10232           0 : }
   10233             : 
   10234             : void
   10235           0 : PresShell::ListStyleSheets(FILE *out, int32_t aIndent)
   10236             : {
   10237           0 :   int32_t sheetCount = mStyleSet->SheetCount(SheetType::Doc);
   10238           0 :   for (int32_t i = 0; i < sheetCount; ++i) {
   10239           0 :     mStyleSet->StyleSheetAt(SheetType::Doc, i)->List(out, aIndent);
   10240           0 :     fputs("\n", out);
   10241             :   }
   10242           0 : }
   10243             : 
   10244             : void
   10245          25 : PresShell::VerifyStyleTree()
   10246             : {
   10247          25 :   VERIFY_STYLE_TREE;
   10248          25 : }
   10249             : #endif
   10250             : 
   10251             : //=============================================================
   10252             : //=============================================================
   10253             : //-- Debug Reflow Counts
   10254             : //=============================================================
   10255             : //=============================================================
   10256             : #ifdef MOZ_REFLOW_PERF
   10257             : //-------------------------------------------------------------
   10258             : void
   10259           4 : PresShell::DumpReflows()
   10260             : {
   10261           4 :   if (mReflowCountMgr) {
   10262           8 :     nsAutoCString uriStr;
   10263           4 :     if (mDocument) {
   10264           4 :       nsIURI *uri = mDocument->GetDocumentURI();
   10265           4 :       if (uri) {
   10266           4 :         uri->GetPath(uriStr);
   10267             :       }
   10268             :     }
   10269           4 :     mReflowCountMgr->DisplayTotals(uriStr.get());
   10270           4 :     mReflowCountMgr->DisplayHTMLTotals(uriStr.get());
   10271           4 :     mReflowCountMgr->DisplayDiffsInTotals();
   10272             :   }
   10273           4 : }
   10274             : 
   10275             : //-------------------------------------------------------------
   10276             : void
   10277         735 : PresShell::CountReflows(const char * aName, nsIFrame * aFrame)
   10278             : {
   10279         735 :   if (mReflowCountMgr) {
   10280         735 :     mReflowCountMgr->Add(aName, aFrame);
   10281             :   }
   10282         735 : }
   10283             : 
   10284             : //-------------------------------------------------------------
   10285             : void
   10286           0 : PresShell::PaintCount(const char * aName,
   10287             :                       gfxContext* aRenderingContext,
   10288             :                       nsPresContext* aPresContext,
   10289             :                       nsIFrame * aFrame,
   10290             :                       const nsPoint& aOffset,
   10291             :                       uint32_t aColor)
   10292             : {
   10293           0 :   if (mReflowCountMgr) {
   10294           0 :     mReflowCountMgr->PaintCount(aName, aRenderingContext, aPresContext,
   10295           0 :                                 aFrame, aOffset, aColor);
   10296             :   }
   10297           0 : }
   10298             : 
   10299             : //-------------------------------------------------------------
   10300             : void
   10301           0 : PresShell::SetPaintFrameCount(bool aPaintFrameCounts)
   10302             : {
   10303           0 :   if (mReflowCountMgr) {
   10304           0 :     mReflowCountMgr->SetPaintFrameCounts(aPaintFrameCounts);
   10305             :   }
   10306           0 : }
   10307             : 
   10308             : bool
   10309         121 : PresShell::IsPaintingFrameCounts()
   10310             : {
   10311         121 :   if (mReflowCountMgr)
   10312         121 :     return mReflowCountMgr->IsPaintingFrameCounts();
   10313           0 :   return false;
   10314             : }
   10315             : 
   10316             : //------------------------------------------------------------------
   10317             : //-- Reflow Counter Classes Impls
   10318             : //------------------------------------------------------------------
   10319             : 
   10320             : //------------------------------------------------------------------
   10321           0 : ReflowCounter::ReflowCounter(ReflowCountMgr * aMgr) :
   10322           0 :   mMgr(aMgr)
   10323             : {
   10324           0 :   ClearTotals();
   10325           0 :   SetTotalsCache();
   10326           0 : }
   10327             : 
   10328             : //------------------------------------------------------------------
   10329           0 : ReflowCounter::~ReflowCounter()
   10330             : {
   10331             : 
   10332           0 : }
   10333             : 
   10334             : //------------------------------------------------------------------
   10335           0 : void ReflowCounter::ClearTotals()
   10336             : {
   10337           0 :   mTotal = 0;
   10338           0 : }
   10339             : 
   10340             : //------------------------------------------------------------------
   10341           0 : void ReflowCounter::SetTotalsCache()
   10342             : {
   10343           0 :   mCacheTotal = mTotal;
   10344           0 : }
   10345             : 
   10346             : //------------------------------------------------------------------
   10347           0 : void ReflowCounter::CalcDiffInTotals()
   10348             : {
   10349           0 :   mCacheTotal = mTotal - mCacheTotal;
   10350           0 : }
   10351             : 
   10352             : //------------------------------------------------------------------
   10353           0 : void ReflowCounter::DisplayTotals(const char * aStr)
   10354             : {
   10355           0 :   DisplayTotals(mTotal, aStr?aStr:"Totals");
   10356           0 : }
   10357             : 
   10358             : //------------------------------------------------------------------
   10359           0 : void ReflowCounter::DisplayDiffTotals(const char * aStr)
   10360             : {
   10361           0 :   DisplayTotals(mCacheTotal, aStr?aStr:"Diff Totals");
   10362           0 : }
   10363             : 
   10364             : //------------------------------------------------------------------
   10365           0 : void ReflowCounter::DisplayHTMLTotals(const char * aStr)
   10366             : {
   10367           0 :   DisplayHTMLTotals(mTotal, aStr?aStr:"Totals");
   10368           0 : }
   10369             : 
   10370             : //------------------------------------------------------------------
   10371           0 : void ReflowCounter::DisplayTotals(uint32_t aTotal, const char * aTitle)
   10372             : {
   10373             :   // figure total
   10374           0 :   if (aTotal == 0) {
   10375           0 :     return;
   10376             :   }
   10377           0 :   ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr);
   10378             : 
   10379           0 :   printf("%25s\t", aTitle);
   10380           0 :   printf("%d\t", aTotal);
   10381           0 :   if (gTots != this && aTotal > 0) {
   10382           0 :     gTots->Add(aTotal);
   10383             :   }
   10384             : }
   10385             : 
   10386             : //------------------------------------------------------------------
   10387           0 : void ReflowCounter::DisplayHTMLTotals(uint32_t aTotal, const char * aTitle)
   10388             : {
   10389           0 :   if (aTotal == 0) {
   10390           0 :     return;
   10391             :   }
   10392             : 
   10393           0 :   ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr);
   10394           0 :   FILE * fd = mMgr->GetOutFile();
   10395           0 :   if (!fd) {
   10396           0 :     return;
   10397             :   }
   10398             : 
   10399           0 :   fprintf(fd, "<tr><td><center>%s</center></td>", aTitle);
   10400           0 :   fprintf(fd, "<td><center>%d</center></td></tr>\n", aTotal);
   10401             : 
   10402           0 :   if (gTots != this && aTotal > 0) {
   10403           0 :     gTots->Add(aTotal);
   10404             :   }
   10405             : }
   10406             : 
   10407             : //------------------------------------------------------------------
   10408             : //-- ReflowCountMgr
   10409             : //------------------------------------------------------------------
   10410             : 
   10411             : #define KEY_BUF_SIZE_FOR_PTR  24 // adequate char[] buffer to sprintf a pointer
   10412             : 
   10413          28 : ReflowCountMgr::ReflowCountMgr()
   10414             : {
   10415          28 :   mCounts = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
   10416             :                                 PL_CompareValues, nullptr, nullptr);
   10417          28 :   mIndiFrameCounts = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
   10418             :                                      PL_CompareValues, nullptr, nullptr);
   10419          28 :   mCycledOnce              = false;
   10420          28 :   mDumpFrameCounts         = false;
   10421          28 :   mDumpFrameByFrameCounts  = false;
   10422          28 :   mPaintFrameByFrameCounts = false;
   10423          28 : }
   10424             : 
   10425             : //------------------------------------------------------------------
   10426          12 : ReflowCountMgr::~ReflowCountMgr()
   10427             : {
   10428           4 :   CleanUp();
   10429          12 : }
   10430             : 
   10431             : //------------------------------------------------------------------
   10432           0 : ReflowCounter * ReflowCountMgr::LookUp(const char * aName)
   10433             : {
   10434           0 :   if (nullptr != mCounts) {
   10435           0 :     ReflowCounter * counter = (ReflowCounter *)PL_HashTableLookup(mCounts, aName);
   10436           0 :     return counter;
   10437             :   }
   10438           0 :   return nullptr;
   10439             : 
   10440             : }
   10441             : 
   10442             : //------------------------------------------------------------------
   10443         735 : void ReflowCountMgr::Add(const char * aName, nsIFrame * aFrame)
   10444             : {
   10445         735 :   NS_ASSERTION(aName != nullptr, "Name shouldn't be null!");
   10446             : 
   10447         735 :   if (mDumpFrameCounts && nullptr != mCounts) {
   10448           0 :     ReflowCounter * counter = (ReflowCounter *)PL_HashTableLookup(mCounts, aName);
   10449           0 :     if (counter == nullptr) {
   10450           0 :       counter = new ReflowCounter(this);
   10451           0 :       char * name = NS_strdup(aName);
   10452           0 :       NS_ASSERTION(name != nullptr, "null ptr");
   10453           0 :       PL_HashTableAdd(mCounts, name, counter);
   10454             :     }
   10455           0 :     counter->Add();
   10456             :   }
   10457             : 
   10458         735 :   if ((mDumpFrameByFrameCounts || mPaintFrameByFrameCounts) &&
   10459           0 :       nullptr != mIndiFrameCounts &&
   10460             :       aFrame != nullptr) {
   10461             :     char key[KEY_BUF_SIZE_FOR_PTR];
   10462           0 :     SprintfLiteral(key, "%p", (void*)aFrame);
   10463           0 :     IndiReflowCounter * counter = (IndiReflowCounter *)PL_HashTableLookup(mIndiFrameCounts, key);
   10464           0 :     if (counter == nullptr) {
   10465           0 :       counter = new IndiReflowCounter(this);
   10466           0 :       counter->mFrame = aFrame;
   10467           0 :       counter->mName.AssignASCII(aName);
   10468           0 :       PL_HashTableAdd(mIndiFrameCounts, NS_strdup(key), counter);
   10469             :     }
   10470             :     // this eliminates extra counts from super classes
   10471           0 :     if (counter != nullptr && counter->mName.EqualsASCII(aName)) {
   10472           0 :       counter->mCount++;
   10473           0 :       counter->mCounter.Add(1);
   10474             :     }
   10475             :   }
   10476         735 : }
   10477             : 
   10478             : //------------------------------------------------------------------
   10479           0 : void ReflowCountMgr::PaintCount(const char*     aName,
   10480             :                                 gfxContext*     aRenderingContext,
   10481             :                                 nsPresContext*  aPresContext,
   10482             :                                 nsIFrame*       aFrame,
   10483             :                                 const nsPoint&  aOffset,
   10484             :                                 uint32_t        aColor)
   10485             : {
   10486           0 :   if (mPaintFrameByFrameCounts &&
   10487           0 :       nullptr != mIndiFrameCounts &&
   10488             :       aFrame != nullptr) {
   10489             :     char key[KEY_BUF_SIZE_FOR_PTR];
   10490           0 :     SprintfLiteral(key, "%p", (void*)aFrame);
   10491             :     IndiReflowCounter * counter =
   10492           0 :       (IndiReflowCounter *)PL_HashTableLookup(mIndiFrameCounts, key);
   10493           0 :     if (counter != nullptr && counter->mName.EqualsASCII(aName)) {
   10494           0 :       DrawTarget* drawTarget = aRenderingContext->GetDrawTarget();
   10495           0 :       int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
   10496             : 
   10497           0 :       aRenderingContext->Save();
   10498             :       gfxPoint devPixelOffset =
   10499           0 :         nsLayoutUtils::PointToGfxPoint(aOffset, appUnitsPerDevPixel);
   10500             :       aRenderingContext->SetMatrix(
   10501           0 :         aRenderingContext->CurrentMatrix().PreTranslate(devPixelOffset));
   10502             : 
   10503             :       // We don't care about the document language or user fonts here;
   10504             :       // just get a default Latin font.
   10505           0 :       nsFont font(eFamily_serif, nsPresContext::CSSPixelsToAppUnits(11));
   10506           0 :       nsFontMetrics::Params params;
   10507           0 :       params.language = nsGkAtoms::x_western;
   10508           0 :       params.textPerf = aPresContext->GetTextPerfMetrics();
   10509             :       RefPtr<nsFontMetrics> fm =
   10510           0 :         aPresContext->DeviceContext()->GetMetricsFor(font, params);
   10511             : 
   10512             :       char buf[16];
   10513           0 :       int len = SprintfLiteral(buf, "%d", counter->mCount);
   10514           0 :       nscoord x = 0, y = fm->MaxAscent();
   10515           0 :       nscoord width, height = fm->MaxHeight();
   10516           0 :       fm->SetTextRunRTL(false);
   10517           0 :       width = fm->GetWidth(buf, len, drawTarget);
   10518             : 
   10519           0 :       Color color;
   10520           0 :       Color color2;
   10521           0 :       if (aColor != 0) {
   10522           0 :         color  = Color::FromABGR(aColor);
   10523           0 :         color2 = Color(0.f, 0.f, 0.f);
   10524             :       } else {
   10525           0 :         gfx::Float rc = 0.f, gc = 0.f, bc = 0.f;
   10526           0 :         if (counter->mCount < 5) {
   10527           0 :           rc = 1.f;
   10528           0 :           gc = 1.f;
   10529           0 :         } else if (counter->mCount < 11) {
   10530           0 :           gc = 1.f;
   10531             :         } else {
   10532           0 :           rc = 1.f;
   10533             :         }
   10534           0 :         color  = Color(rc, gc, bc);
   10535           0 :         color2 = Color(rc/2, gc/2, bc/2);
   10536             :       }
   10537             : 
   10538           0 :       nsRect rect(0,0, width+15, height+15);
   10539             :       Rect devPxRect =
   10540           0 :         NSRectToSnappedRect(rect, appUnitsPerDevPixel, *drawTarget);
   10541           0 :       ColorPattern black(ToDeviceColor(Color(0.f, 0.f, 0.f, 1.f)));
   10542           0 :       drawTarget->FillRect(devPxRect, black);
   10543             : 
   10544           0 :       aRenderingContext->SetColor(color2);
   10545           0 :       fm->DrawString(buf, len, x+15, y+15, aRenderingContext);
   10546           0 :       aRenderingContext->SetColor(color);
   10547           0 :       fm->DrawString(buf, len, x, y, aRenderingContext);
   10548             : 
   10549           0 :       aRenderingContext->Restore();
   10550             :     }
   10551             :   }
   10552           0 : }
   10553             : 
   10554             : //------------------------------------------------------------------
   10555           0 : int ReflowCountMgr::RemoveItems(PLHashEntry *he, int i, void *arg)
   10556             : {
   10557           0 :   char *str = (char *)he->key;
   10558           0 :   ReflowCounter * counter = (ReflowCounter *)he->value;
   10559           0 :   delete counter;
   10560           0 :   free(str);
   10561             : 
   10562           0 :   return HT_ENUMERATE_REMOVE;
   10563             : }
   10564             : 
   10565             : //------------------------------------------------------------------
   10566           0 : int ReflowCountMgr::RemoveIndiItems(PLHashEntry *he, int i, void *arg)
   10567             : {
   10568           0 :   char *str = (char *)he->key;
   10569           0 :   IndiReflowCounter * counter = (IndiReflowCounter *)he->value;
   10570           0 :   delete counter;
   10571           0 :   free(str);
   10572             : 
   10573           0 :   return HT_ENUMERATE_REMOVE;
   10574             : }
   10575             : 
   10576             : //------------------------------------------------------------------
   10577           4 : void ReflowCountMgr::CleanUp()
   10578             : {
   10579           4 :   if (nullptr != mCounts) {
   10580           4 :     PL_HashTableEnumerateEntries(mCounts, RemoveItems, nullptr);
   10581           4 :     PL_HashTableDestroy(mCounts);
   10582           4 :     mCounts = nullptr;
   10583             :   }
   10584             : 
   10585           4 :   if (nullptr != mIndiFrameCounts) {
   10586           4 :     PL_HashTableEnumerateEntries(mIndiFrameCounts, RemoveIndiItems, nullptr);
   10587           4 :     PL_HashTableDestroy(mIndiFrameCounts);
   10588           4 :     mIndiFrameCounts = nullptr;
   10589             :   }
   10590           4 : }
   10591             : 
   10592             : //------------------------------------------------------------------
   10593           0 : int ReflowCountMgr::DoSingleTotal(PLHashEntry *he, int i, void *arg)
   10594             : {
   10595           0 :   char *str = (char *)he->key;
   10596           0 :   ReflowCounter * counter = (ReflowCounter *)he->value;
   10597             : 
   10598           0 :   counter->DisplayTotals(str);
   10599             : 
   10600           0 :   return HT_ENUMERATE_NEXT;
   10601             : }
   10602             : 
   10603             : //------------------------------------------------------------------
   10604           0 : void ReflowCountMgr::DoGrandTotals()
   10605             : {
   10606           0 :   if (nullptr != mCounts) {
   10607           0 :     ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr);
   10608           0 :     if (gTots == nullptr) {
   10609           0 :       gTots = new ReflowCounter(this);
   10610           0 :       PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots);
   10611             :     } else {
   10612           0 :       gTots->ClearTotals();
   10613             :     }
   10614             : 
   10615           0 :     printf("\t\t\t\tTotal\n");
   10616           0 :     for (uint32_t i=0;i<78;i++) {
   10617           0 :       printf("-");
   10618             :     }
   10619           0 :     printf("\n");
   10620           0 :     PL_HashTableEnumerateEntries(mCounts, DoSingleTotal, this);
   10621             :   }
   10622           0 : }
   10623             : 
   10624           0 : static void RecurseIndiTotals(nsPresContext* aPresContext,
   10625             :                               PLHashTable *   aHT,
   10626             :                               nsIFrame *      aParentFrame,
   10627             :                               int32_t         aLevel)
   10628             : {
   10629           0 :   if (aParentFrame == nullptr) {
   10630           0 :     return;
   10631             :   }
   10632             : 
   10633             :   char key[KEY_BUF_SIZE_FOR_PTR];
   10634           0 :   SprintfLiteral(key, "%p", (void*)aParentFrame);
   10635           0 :   IndiReflowCounter * counter = (IndiReflowCounter *)PL_HashTableLookup(aHT, key);
   10636           0 :   if (counter) {
   10637           0 :     counter->mHasBeenOutput = true;
   10638           0 :     char * name = ToNewCString(counter->mName);
   10639           0 :     for (int32_t i=0;i<aLevel;i++) printf(" ");
   10640           0 :     printf("%s - %p   [%d][", name, (void*)aParentFrame, counter->mCount);
   10641           0 :     printf("%d", counter->mCounter.GetTotal());
   10642           0 :     printf("]\n");
   10643           0 :     free(name);
   10644             :   }
   10645             : 
   10646           0 :   for (nsIFrame* child : aParentFrame->PrincipalChildList()) {
   10647           0 :     RecurseIndiTotals(aPresContext, aHT, child, aLevel+1);
   10648             :   }
   10649             : 
   10650             : }
   10651             : 
   10652             : //------------------------------------------------------------------
   10653           0 : int ReflowCountMgr::DoSingleIndi(PLHashEntry *he, int i, void *arg)
   10654             : {
   10655           0 :   IndiReflowCounter * counter = (IndiReflowCounter *)he->value;
   10656           0 :   if (counter && !counter->mHasBeenOutput) {
   10657           0 :     char * name = ToNewCString(counter->mName);
   10658           0 :     printf("%s - %p   [%d][", name, (void*)counter->mFrame, counter->mCount);
   10659           0 :     printf("%d", counter->mCounter.GetTotal());
   10660           0 :     printf("]\n");
   10661           0 :     free(name);
   10662             :   }
   10663           0 :   return HT_ENUMERATE_NEXT;
   10664             : }
   10665             : 
   10666             : //------------------------------------------------------------------
   10667           0 : void ReflowCountMgr::DoIndiTotalsTree()
   10668             : {
   10669           0 :   if (nullptr != mCounts) {
   10670           0 :     printf("\n------------------------------------------------\n");
   10671           0 :     printf("-- Individual Frame Counts\n");
   10672           0 :     printf("------------------------------------------------\n");
   10673             : 
   10674           0 :     if (mPresShell) {
   10675           0 :       nsIFrame * rootFrame = mPresShell->FrameManager()->GetRootFrame();
   10676           0 :       RecurseIndiTotals(mPresContext, mIndiFrameCounts, rootFrame, 0);
   10677           0 :       printf("------------------------------------------------\n");
   10678           0 :       printf("-- Individual Counts of Frames not in Root Tree\n");
   10679           0 :       printf("------------------------------------------------\n");
   10680           0 :       PL_HashTableEnumerateEntries(mIndiFrameCounts, DoSingleIndi, this);
   10681             :     }
   10682             :   }
   10683           0 : }
   10684             : 
   10685             : //------------------------------------------------------------------
   10686           0 : int ReflowCountMgr::DoSingleHTMLTotal(PLHashEntry *he, int i, void *arg)
   10687             : {
   10688           0 :   char *str = (char *)he->key;
   10689           0 :   ReflowCounter * counter = (ReflowCounter *)he->value;
   10690             : 
   10691           0 :   counter->DisplayHTMLTotals(str);
   10692             : 
   10693           0 :   return HT_ENUMERATE_NEXT;
   10694             : }
   10695             : 
   10696             : //------------------------------------------------------------------
   10697           0 : void ReflowCountMgr::DoGrandHTMLTotals()
   10698             : {
   10699           0 :   if (nullptr != mCounts) {
   10700           0 :     ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr);
   10701           0 :     if (gTots == nullptr) {
   10702           0 :       gTots = new ReflowCounter(this);
   10703           0 :       PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots);
   10704             :     } else {
   10705           0 :       gTots->ClearTotals();
   10706             :     }
   10707             : 
   10708             :     static const char * title[] = {"Class", "Reflows"};
   10709           0 :     fprintf(mFD, "<tr>");
   10710           0 :     for (uint32_t i=0; i < ArrayLength(title); i++) {
   10711           0 :       fprintf(mFD, "<td><center><b>%s<b></center></td>", title[i]);
   10712             :     }
   10713           0 :     fprintf(mFD, "</tr>\n");
   10714           0 :     PL_HashTableEnumerateEntries(mCounts, DoSingleHTMLTotal, this);
   10715             :   }
   10716           0 : }
   10717             : 
   10718             : //------------------------------------
   10719           4 : void ReflowCountMgr::DisplayTotals(const char * aStr)
   10720             : {
   10721             : #ifdef DEBUG_rods
   10722             :   printf("%s\n", aStr?aStr:"No name");
   10723             : #endif
   10724           4 :   if (mDumpFrameCounts) {
   10725           0 :     DoGrandTotals();
   10726             :   }
   10727           4 :   if (mDumpFrameByFrameCounts) {
   10728           0 :     DoIndiTotalsTree();
   10729             :   }
   10730             : 
   10731           4 : }
   10732             : //------------------------------------
   10733           4 : void ReflowCountMgr::DisplayHTMLTotals(const char * aStr)
   10734             : {
   10735             : #ifdef WIN32x // XXX NOT XP!
   10736             :   char name[1024];
   10737             : 
   10738             :   char * sptr = strrchr(aStr, '/');
   10739             :   if (sptr) {
   10740             :     sptr++;
   10741             :     strcpy(name, sptr);
   10742             :     char * eptr = strrchr(name, '.');
   10743             :     if (eptr) {
   10744             :       *eptr = 0;
   10745             :     }
   10746             :     strcat(name, "_stats.html");
   10747             :   }
   10748             :   mFD = fopen(name, "w");
   10749             :   if (mFD) {
   10750             :     fprintf(mFD, "<html><head><title>Reflow Stats</title></head><body>\n");
   10751             :     const char * title = aStr?aStr:"No name";
   10752             :     fprintf(mFD, "<center><b>%s</b><br><table border=1 style=\"background-color:#e0e0e0\">", title);
   10753             :     DoGrandHTMLTotals();
   10754             :     fprintf(mFD, "</center></table>\n");
   10755             :     fprintf(mFD, "</body></html>\n");
   10756             :     fclose(mFD);
   10757             :     mFD = nullptr;
   10758             :   }
   10759             : #endif // not XP!
   10760           4 : }
   10761             : 
   10762             : //------------------------------------------------------------------
   10763           0 : int ReflowCountMgr::DoClearTotals(PLHashEntry *he, int i, void *arg)
   10764             : {
   10765           0 :   ReflowCounter * counter = (ReflowCounter *)he->value;
   10766           0 :   counter->ClearTotals();
   10767             : 
   10768           0 :   return HT_ENUMERATE_NEXT;
   10769             : }
   10770             : 
   10771             : //------------------------------------------------------------------
   10772           0 : void ReflowCountMgr::ClearTotals()
   10773             : {
   10774           0 :   PL_HashTableEnumerateEntries(mCounts, DoClearTotals, this);
   10775           0 : }
   10776             : 
   10777             : //------------------------------------------------------------------
   10778           0 : void ReflowCountMgr::ClearGrandTotals()
   10779             : {
   10780           0 :   if (nullptr != mCounts) {
   10781           0 :     ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr);
   10782           0 :     if (gTots == nullptr) {
   10783           0 :       gTots = new ReflowCounter(this);
   10784           0 :       PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots);
   10785             :     } else {
   10786           0 :       gTots->ClearTotals();
   10787           0 :       gTots->SetTotalsCache();
   10788             :     }
   10789             :   }
   10790           0 : }
   10791             : 
   10792             : //------------------------------------------------------------------
   10793           0 : int ReflowCountMgr::DoDisplayDiffTotals(PLHashEntry *he, int i, void *arg)
   10794             : {
   10795           0 :   bool cycledOnce = (arg != 0);
   10796             : 
   10797           0 :   char *str = (char *)he->key;
   10798           0 :   ReflowCounter * counter = (ReflowCounter *)he->value;
   10799             : 
   10800           0 :   if (cycledOnce) {
   10801           0 :     counter->CalcDiffInTotals();
   10802           0 :     counter->DisplayDiffTotals(str);
   10803             :   }
   10804           0 :   counter->SetTotalsCache();
   10805             : 
   10806           0 :   return HT_ENUMERATE_NEXT;
   10807             : }
   10808             : 
   10809             : //------------------------------------------------------------------
   10810           4 : void ReflowCountMgr::DisplayDiffsInTotals()
   10811             : {
   10812           4 :   if (mCycledOnce) {
   10813           0 :     printf("Differences\n");
   10814           0 :     for (int32_t i=0;i<78;i++) {
   10815           0 :       printf("-");
   10816             :     }
   10817           0 :     printf("\n");
   10818           0 :     ClearGrandTotals();
   10819             :   }
   10820           4 :   PL_HashTableEnumerateEntries(mCounts, DoDisplayDiffTotals, (void *)mCycledOnce);
   10821             : 
   10822           4 :   mCycledOnce = true;
   10823           4 : }
   10824             : 
   10825             : #endif // MOZ_REFLOW_PERF
   10826             : 
   10827           0 : nsIFrame* nsIPresShell::GetAbsoluteContainingBlock(nsIFrame *aFrame)
   10828             : {
   10829           0 :   return FrameConstructor()->GetAbsoluteContainingBlock(aFrame,
   10830           0 :       nsCSSFrameConstructor::ABS_POS);
   10831             : }
   10832             : 
   10833             : #ifdef ACCESSIBILITY
   10834             : bool
   10835        2396 : nsIPresShell::IsAccessibilityActive()
   10836             : {
   10837        2396 :   return GetAccService() != nullptr;
   10838             : }
   10839             : 
   10840             : nsAccessibilityService*
   10841         158 : nsIPresShell::AccService()
   10842             : {
   10843         158 :   return GetAccService();
   10844             : }
   10845             : #endif
   10846             : 
   10847           3 : void nsIPresShell::InitializeStatics()
   10848             : {
   10849           3 :   MOZ_ASSERT(!sPointerCaptureList, "InitializeStatics called multiple times!");
   10850           3 :   sPointerCaptureList =
   10851           3 :     new nsClassHashtable<nsUint32HashKey, PointerCaptureInfo>;
   10852           3 :   sActivePointersIds = new nsClassHashtable<nsUint32HashKey, PointerInfo>;
   10853           3 : }
   10854             : 
   10855           0 : void nsIPresShell::ReleaseStatics()
   10856             : {
   10857           0 :   MOZ_ASSERT(sPointerCaptureList, "ReleaseStatics called without Initialize!");
   10858           0 :   delete sPointerCaptureList;
   10859           0 :   sPointerCaptureList = nullptr;
   10860           0 :   delete sActivePointersIds;
   10861           0 :   sActivePointersIds = nullptr;
   10862           0 : }
   10863             : 
   10864             : // Asks our docshell whether we're active.
   10865          28 : void PresShell::QueryIsActive()
   10866             : {
   10867          56 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
   10868          28 :   if (mDocument) {
   10869          28 :     nsIDocument* displayDoc = mDocument->GetDisplayDocument();
   10870          28 :     if (displayDoc) {
   10871             :       // Ok, we're an external resource document -- we need to use our display
   10872             :       // document's docshell to determine "IsActive" status, since we lack
   10873             :       // a container.
   10874           0 :       MOZ_ASSERT(!container,
   10875             :                  "external resource doc shouldn't have its own container");
   10876             : 
   10877           0 :       nsIPresShell* displayPresShell = displayDoc->GetShell();
   10878           0 :       if (displayPresShell) {
   10879           0 :         container = displayPresShell->GetPresContext()->GetContainerWeak();
   10880             :       }
   10881             :     }
   10882             :   }
   10883             : 
   10884          56 :   nsCOMPtr<nsIDocShell> docshell(do_QueryInterface(container));
   10885          28 :   if (docshell) {
   10886             :     bool isActive;
   10887           7 :     nsresult rv = docshell->GetIsActive(&isActive);
   10888             :     // Even though in theory the docshell here could be "Inactive and
   10889             :     // Foreground", thus implying aIsHidden=false for SetIsActive(),
   10890             :     // this is a newly created PresShell so we'd like to invalidate anyway
   10891             :     // upon being made active to ensure that the contents get painted.
   10892           7 :     if (NS_SUCCEEDED(rv))
   10893           7 :       SetIsActive(isActive);
   10894             :   }
   10895          28 : }
   10896             : 
   10897             : // Helper for propagating mIsActive changes to external resources
   10898             : static bool
   10899           0 : SetExternalResourceIsActive(nsIDocument* aDocument, void* aClosure)
   10900             : {
   10901           0 :   nsIPresShell* shell = aDocument->GetShell();
   10902           0 :   if (shell) {
   10903           0 :     shell->SetIsActive(*static_cast<bool*>(aClosure));
   10904             :   }
   10905           0 :   return true;
   10906             : }
   10907             : 
   10908             : static void
   10909           0 : SetPluginIsActive(nsISupports* aSupports, void* aClosure)
   10910             : {
   10911           0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports));
   10912           0 :   if (!content) {
   10913           0 :     return;
   10914             :   }
   10915             : 
   10916           0 :   nsIFrame *frame = content->GetPrimaryFrame();
   10917           0 :   nsIObjectFrame *objectFrame = do_QueryFrame(frame);
   10918           0 :   if (objectFrame) {
   10919           0 :     objectFrame->SetIsDocumentActive(*static_cast<bool*>(aClosure));
   10920             :   }
   10921             : }
   10922             : 
   10923             : nsresult
   10924           7 : PresShell::SetIsActive(bool aIsActive)
   10925             : {
   10926           7 :   NS_PRECONDITION(mDocument, "should only be called with a document");
   10927             : 
   10928           7 :   mIsActive = aIsActive;
   10929             : 
   10930           7 :   nsPresContext* presContext = GetPresContext();
   10931          14 :   if (presContext &&
   10932           7 :       presContext->RefreshDriver()->GetPresContext() == presContext) {
   10933           7 :     presContext->RefreshDriver()->SetThrottled(!mIsActive);
   10934             :   }
   10935             : 
   10936             :   // Propagate state-change to my resource documents' PresShells
   10937           7 :   mDocument->EnumerateExternalResources(SetExternalResourceIsActive,
   10938           7 :                                         &aIsActive);
   10939           7 :   mDocument->EnumerateActivityObservers(SetPluginIsActive,
   10940           7 :                                         &aIsActive);
   10941           7 :   nsresult rv = UpdateImageLockingState();
   10942             : #ifdef ACCESSIBILITY
   10943           7 :   if (aIsActive) {
   10944           7 :     nsAccessibilityService* accService = AccService();
   10945           7 :     if (accService) {
   10946           0 :       accService->PresShellActivated(this);
   10947             :     }
   10948             :   }
   10949             : #endif
   10950           7 :   return rv;
   10951             : }
   10952             : 
   10953             : /*
   10954             :  * Determines the current image locking state. Called when one of the
   10955             :  * dependent factors changes.
   10956             :  */
   10957             : nsresult
   10958           7 : PresShell::UpdateImageLockingState()
   10959             : {
   10960             :   // We're locked if we're both thawed and active.
   10961           7 :   bool locked = !mFrozen && mIsActive;
   10962             : 
   10963           7 :   nsresult rv = mDocument->ImageTracker()->SetLockingState(locked);
   10964             : 
   10965           7 :   if (locked) {
   10966             :     // Request decodes for visible image frames; we want to start decoding as
   10967             :     // quickly as possible when we get foregrounded to minimize flashing.
   10968           7 :     for (auto iter = mApproximatelyVisibleFrames.Iter(); !iter.Done(); iter.Next()) {
   10969           0 :       nsImageFrame* imageFrame = do_QueryFrame(iter.Get()->GetKey());
   10970           0 :       if (imageFrame) {
   10971           0 :         imageFrame->MaybeDecodeForPredictedSize();
   10972             :       }
   10973             :     }
   10974             :   }
   10975             : 
   10976           7 :   return rv;
   10977             : }
   10978             : 
   10979             : PresShell*
   10980          10 : PresShell::GetRootPresShell()
   10981             : {
   10982          10 :   if (mPresContext) {
   10983          10 :     nsPresContext* rootPresContext = mPresContext->GetRootPresContext();
   10984          10 :     if (rootPresContext) {
   10985          10 :       return static_cast<PresShell*>(rootPresContext->PresShell());
   10986             :     }
   10987             :   }
   10988           0 :   return nullptr;
   10989             : }
   10990             : 
   10991             : void
   10992          21 : PresShell::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
   10993             :                                   nsArenaMemoryStats* aArenaObjectsSize,
   10994             :                                   size_t* aPresShellSize,
   10995             :                                   size_t* aStyleSetsSize,
   10996             :                                   size_t* aTextRunsSize,
   10997             :                                   size_t* aPresContextSize,
   10998             :                                   size_t* aFramePropertiesSize)
   10999             : {
   11000          21 :   mFrameArena.AddSizeOfExcludingThis(aMallocSizeOf, aArenaObjectsSize);
   11001          21 :   *aPresShellSize += aMallocSizeOf(this);
   11002          21 :   if (mCaret) {
   11003          21 :     *aPresShellSize += mCaret->SizeOfIncludingThis(aMallocSizeOf);
   11004             :   }
   11005          21 :   *aPresShellSize += mApproximatelyVisibleFrames.ShallowSizeOfExcludingThis(aMallocSizeOf);
   11006          21 :   *aPresShellSize += mFramesToDirty.ShallowSizeOfExcludingThis(aMallocSizeOf);
   11007          21 :   *aPresShellSize += aArenaObjectsSize->mOther;
   11008             : 
   11009          21 :   if (nsStyleSet* styleSet = StyleSet()->GetAsGecko()) {
   11010          21 :     *aStyleSetsSize += styleSet->SizeOfIncludingThis(aMallocSizeOf);
   11011           0 :   } else if (ServoStyleSet* styleSet = StyleSet()->GetAsServo()) {
   11012           0 :     *aStyleSetsSize += styleSet->SizeOfIncludingThis(aMallocSizeOf);
   11013             :   } else {
   11014           0 :     MOZ_CRASH();
   11015             :   }
   11016             : 
   11017          21 :   *aTextRunsSize += SizeOfTextRuns(aMallocSizeOf);
   11018             : 
   11019          21 :   *aPresContextSize += mPresContext->SizeOfIncludingThis(aMallocSizeOf);
   11020             : 
   11021          21 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
   11022          21 :   if (rootFrame) {
   11023          21 :     *aFramePropertiesSize +=
   11024          21 :       rootFrame->SizeOfFramePropertiesForTree(aMallocSizeOf);
   11025             :   }
   11026          21 : }
   11027             : 
   11028             : size_t
   11029          21 : PresShell::SizeOfTextRuns(MallocSizeOf aMallocSizeOf) const
   11030             : {
   11031          21 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
   11032          21 :   if (!rootFrame) {
   11033           0 :     return 0;
   11034             :   }
   11035             : 
   11036             :   // clear the TEXT_RUN_MEMORY_ACCOUNTED flags
   11037             :   nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, nullptr,
   11038          21 :                                          /* clear = */true);
   11039             : 
   11040             :   // collect the total memory in use for textruns
   11041             :   return nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, aMallocSizeOf,
   11042          21 :                                                 /* clear = */false);
   11043             : }
   11044             : 
   11045             : void
   11046           0 : nsIPresShell::MarkFixedFramesForReflow(IntrinsicDirty aIntrinsicDirty)
   11047             : {
   11048           0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
   11049           0 :   if (rootFrame) {
   11050           0 :     const nsFrameList& childList = rootFrame->GetChildList(nsIFrame::kFixedList);
   11051           0 :     for (nsIFrame* childFrame : childList) {
   11052           0 :       FrameNeedsReflow(childFrame, aIntrinsicDirty, NS_FRAME_IS_DIRTY);
   11053             :     }
   11054             :   }
   11055           0 : }
   11056             : 
   11057             : void
   11058           0 : nsIPresShell::SetScrollPositionClampingScrollPortSize(nscoord aWidth, nscoord aHeight)
   11059             : {
   11060           0 :   if (!mScrollPositionClampingScrollPortSizeSet ||
   11061           0 :       mScrollPositionClampingScrollPortSize.width != aWidth ||
   11062           0 :       mScrollPositionClampingScrollPortSize.height != aHeight) {
   11063           0 :     mScrollPositionClampingScrollPortSizeSet = true;
   11064           0 :     mScrollPositionClampingScrollPortSize.width = aWidth;
   11065           0 :     mScrollPositionClampingScrollPortSize.height = aHeight;
   11066             : 
   11067           0 :     if (nsIScrollableFrame* rootScrollFrame = GetRootScrollFrameAsScrollable()) {
   11068           0 :       rootScrollFrame->MarkScrollbarsDirtyForReflow();
   11069             :     }
   11070           0 :     MarkFixedFramesForReflow(nsIPresShell::eResize);
   11071             :   }
   11072           0 : }
   11073             : 
   11074             : void
   11075          28 : PresShell::SetupFontInflation()
   11076             : {
   11077          28 :   mFontSizeInflationEmPerLine = nsLayoutUtils::FontSizeInflationEmPerLine();
   11078          28 :   mFontSizeInflationMinTwips = nsLayoutUtils::FontSizeInflationMinTwips();
   11079          28 :   mFontSizeInflationLineThreshold = nsLayoutUtils::FontSizeInflationLineThreshold();
   11080          28 :   mFontSizeInflationForceEnabled = nsLayoutUtils::FontSizeInflationForceEnabled();
   11081          28 :   mFontSizeInflationDisabledInMasterProcess = nsLayoutUtils::FontSizeInflationDisabledInMasterProcess();
   11082             : 
   11083          28 :   NotifyFontSizeInflationEnabledIsDirty();
   11084          28 : }
   11085             : 
   11086             : void
   11087          24 : nsIPresShell::RecomputeFontSizeInflationEnabled()
   11088             : {
   11089          24 :   mFontSizeInflationEnabledIsDirty = false;
   11090          24 :   mFontSizeInflationEnabled = DetermineFontSizeInflationState();
   11091             : 
   11092          24 :   HandleSystemFontScale();
   11093          24 : }
   11094             : 
   11095             : bool
   11096          24 : nsIPresShell::DetermineFontSizeInflationState()
   11097             : {
   11098          24 :   MOZ_ASSERT(mPresContext, "our pres context should not be null");
   11099          72 :   if ((FontSizeInflationEmPerLine() == 0 &&
   11100          24 :       FontSizeInflationMinTwips() == 0) || mPresContext->IsChrome()) {
   11101          24 :     return false;
   11102             :   }
   11103             : 
   11104             :   // Force-enabling font inflation always trumps the heuristics here.
   11105           0 :   if (!FontSizeInflationForceEnabled()) {
   11106           0 :     if (TabChild* tab = TabChild::GetFrom(this)) {
   11107             :       // We're in a child process.  Cancel inflation if we're not
   11108             :       // async-pan zoomed.
   11109           0 :       if (!tab->AsyncPanZoomEnabled()) {
   11110           0 :         return false;
   11111             :       }
   11112           0 :     } else if (XRE_IsParentProcess()) {
   11113             :       // We're in the master process.  Cancel inflation if it's been
   11114             :       // explicitly disabled.
   11115           0 :       if (FontSizeInflationDisabledInMasterProcess()) {
   11116           0 :         return false;
   11117             :       }
   11118             :     }
   11119             :   }
   11120             : 
   11121             :   // XXXjwir3:
   11122             :   // See bug 706918, comment 23 for more information on this particular section
   11123             :   // of the code. We're using "screen size" in place of the size of the content
   11124             :   // area, because on mobile, these are close or equal. This will work for our
   11125             :   // purposes (bug 706198), but it will need to be changed in the future to be
   11126             :   // more correct when we bring the rest of the viewport code into platform.
   11127             :   // We actually want the size of the content area, in the event that we don't
   11128             :   // have any metadata about the width and/or height. On mobile, the screen size
   11129             :   // and the size of the content area are very close, or the same value.
   11130             :   // In XUL fennec, the content area is the size of the <browser> widget, but
   11131             :   // in native fennec, the content area is the size of the Gecko LayerView
   11132             :   // object.
   11133             : 
   11134             :   // TODO:
   11135             :   // Once bug 716575 has been resolved, this code should be changed so that it
   11136             :   // does the right thing on all platforms.
   11137             :   nsresult rv;
   11138             :   nsCOMPtr<nsIScreenManager> screenMgr =
   11139           0 :     do_GetService("@mozilla.org/gfx/screenmanager;1", &rv);
   11140           0 :   if (!NS_SUCCEEDED(rv)) {
   11141           0 :     return false;
   11142             :   }
   11143             : 
   11144           0 :   nsCOMPtr<nsIScreen> screen;
   11145           0 :   screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
   11146           0 :   if (screen) {
   11147             :     int32_t screenLeft, screenTop, screenWidth, screenHeight;
   11148           0 :     screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
   11149             : 
   11150             :     nsViewportInfo vInf =
   11151           0 :       GetDocument()->GetViewportInfo(ScreenIntSize(screenWidth, screenHeight));
   11152             : 
   11153           0 :     if (vInf.GetDefaultZoom() >= CSSToScreenScale(1.0f) || vInf.IsAutoSizeEnabled()) {
   11154           0 :       return false;
   11155             :     }
   11156             :   }
   11157             : 
   11158           0 :   return true;
   11159             : }
   11160             : 
   11161             : bool
   11162        2400 : nsIPresShell::FontSizeInflationEnabled()
   11163             : {
   11164        2400 :   if (mFontSizeInflationEnabledIsDirty) {
   11165          24 :     RecomputeFontSizeInflationEnabled();
   11166             :   }
   11167             : 
   11168        2400 :   return mFontSizeInflationEnabled;
   11169             : }
   11170             : 
   11171             : void
   11172          24 : nsIPresShell::HandleSystemFontScale()
   11173             : {
   11174          24 :   float fontScale = nsLayoutUtils::SystemFontScale();
   11175          24 :   if (fontScale == 0.0f) {
   11176           0 :     return;
   11177             :   }
   11178             : 
   11179          24 :   MOZ_ASSERT(mDocument && mPresContext, "our document and pres context should not be null");
   11180             : 
   11181          24 :   if (!mFontSizeInflationEnabled && !mDocument->IsSyntheticDocument()) {
   11182          24 :     mPresContext->SetSystemFontScale(fontScale);
   11183             :   } else {
   11184           0 :     mPresContext->SetSystemFontScale(1.0f);
   11185             :   }
   11186             : }
   11187             : 
   11188             : void
   11189           0 : PresShell::PausePainting()
   11190             : {
   11191           0 :   if (GetPresContext()->RefreshDriver()->GetPresContext() != GetPresContext())
   11192           0 :     return;
   11193             : 
   11194           0 :   mPaintingIsFrozen = true;
   11195           0 :   GetPresContext()->RefreshDriver()->Freeze();
   11196             : }
   11197             : 
   11198             : void
   11199           0 : PresShell::ResumePainting()
   11200             : {
   11201           0 :   if (GetPresContext()->RefreshDriver()->GetPresContext() != GetPresContext())
   11202           0 :     return;
   11203             : 
   11204           0 :   mPaintingIsFrozen = false;
   11205           0 :   GetPresContext()->RefreshDriver()->Thaw();
   11206             : }
   11207             : 
   11208             : void
   11209          20 : nsIPresShell::SyncWindowProperties(nsView* aView)
   11210             : {
   11211          20 :   nsIFrame* frame = aView->GetFrame();
   11212          20 :   if (frame && mPresContext) {
   11213             :     // CreateReferenceRenderingContext can return nullptr
   11214          40 :     RefPtr<gfxContext> rcx(CreateReferenceRenderingContext());
   11215          20 :     nsContainerFrame::SyncWindowProperties(mPresContext, frame, aView, rcx, 0);
   11216             :   }
   11217          20 : }
   11218             : 
   11219             : static SheetType
   11220           0 : ToSheetType(uint32_t aServiceSheetType)
   11221             : {
   11222           0 :   switch (aServiceSheetType) {
   11223             :     case nsIStyleSheetService::AGENT_SHEET:
   11224           0 :       return SheetType::Agent;
   11225             :       break;
   11226             :     case nsIStyleSheetService::USER_SHEET:
   11227           0 :       return SheetType::User;
   11228             :       break;
   11229             :     default:
   11230           0 :       MOZ_FALLTHROUGH_ASSERT("unexpected aSheetType value");
   11231             :     case nsIStyleSheetService::AUTHOR_SHEET:
   11232           0 :       return SheetType::Doc;
   11233             :   }
   11234             : }
   11235             : 
   11236             : nsresult
   11237           0 : nsIPresShell::HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType,
   11238             :                                                       bool* aRetVal)
   11239             : {
   11240           0 :   *aRetVal = false;
   11241           0 :   if (nsStyleSet* styleSet = mStyleSet->GetAsGecko()) {
   11242             :     // ServoStyleSets do not have rule processors.
   11243           0 :     SheetType type = ToSheetType(aSheetType);
   11244           0 :     *aRetVal = styleSet->HasRuleProcessorUsedByMultipleStyleSets(type);
   11245             :   }
   11246           0 :   return NS_OK;
   11247             : }
   11248             : 
   11249             : void
   11250           0 : PresShell::NotifyStyleSheetServiceSheetAdded(StyleSheet* aSheet,
   11251             :                                              uint32_t aSheetType)
   11252             : {
   11253           0 :   if (!mStyleSet) {
   11254           0 :     return;
   11255             :   }
   11256             : 
   11257           0 :   switch (aSheetType) {
   11258             :     case nsIStyleSheetService::AGENT_SHEET:
   11259           0 :       AddAgentSheet(aSheet);
   11260           0 :       break;
   11261             :     case nsIStyleSheetService::USER_SHEET:
   11262           0 :       AddUserSheet(aSheet);
   11263           0 :       break;
   11264             :     case nsIStyleSheetService::AUTHOR_SHEET:
   11265           0 :       AddAuthorSheet(aSheet);
   11266           0 :       break;
   11267             :     default:
   11268           0 :       MOZ_ASSERT_UNREACHABLE("unexpected aSheetType value");
   11269             :       break;
   11270             :   }
   11271             : }
   11272             : 
   11273             : void
   11274           0 : PresShell::NotifyStyleSheetServiceSheetRemoved(StyleSheet* aSheet,
   11275             :                                                uint32_t aSheetType)
   11276             : {
   11277           0 :   if (!mStyleSet) {
   11278           0 :     return;
   11279             :   }
   11280             : 
   11281           0 :   RemoveSheet(ToSheetType(aSheetType), aSheet);
   11282             : }

Generated by: LCOV version 1.13