LCOV - code coverage report
Current view: top level - layout/base - PresShell.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 190 4471 4.2 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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             : /* a presentation of a document, part 2 */
       8             : 
       9             : #include "mozilla/PresShell.h"
      10             : 
      11             : #include "mozilla/dom/FontFaceSet.h"
      12             : #include "mozilla/ArrayUtils.h"
      13             : #include "mozilla/Attributes.h"
      14             : #include "mozilla/AutoRestore.h"
      15             : #include "mozilla/StyleSheetInlines.h"
      16             : #include "mozilla/EventDispatcher.h"
      17             : #include "mozilla/EventStateManager.h"
      18             : #include "mozilla/EventStates.h"
      19             : #include "mozilla/IMEStateManager.h"
      20             : #include "mozilla/MemoryReporting.h"
      21             : #include "mozilla/dom/TabChild.h"
      22             : #include "mozilla/Likely.h"
      23             : #include "mozilla/Logging.h"
      24             : #include "mozilla/MouseEvents.h"
      25             : #include "mozilla/Sprintf.h"
      26             : #include "mozilla/TextEvents.h"
      27             : #include "mozilla/TimeStamp.h"
      28             : #include "mozilla/TouchEvents.h"
      29             : #include "mozilla/UniquePtr.h"
      30             : #include "mozilla/Unused.h"
      31             : #include <algorithm>
      32             : 
      33             : #ifdef XP_WIN
      34             : #include "winuser.h"
      35             : #endif
      36             : 
      37             : #include "gfxContext.h"
      38             : #include "gfxPrefs.h"
      39             : #include "gfxUserFontSet.h"
      40             : #include "nsContentList.h"
      41             : #include "nsPresContext.h"
      42             : #include "nsIContent.h"
      43             : #include "nsIContentIterator.h"
      44             : #include "nsIPresShellInlines.h"
      45             : #include "mozilla/dom/Element.h"
      46             : #include "mozilla/dom/Event.h" // for Event::GetEventPopupControlState()
      47             : #include "mozilla/dom/PointerEventHandler.h"
      48             : #include "nsIDocument.h"
      49             : #include "nsAnimationManager.h"
      50             : #include "nsNameSpaceManager.h"  // for Pref-related rule management (bugs 22963,20760,31816)
      51             : #include "nsFrame.h"
      52             : #include "FrameLayerBuilder.h"
      53             : #include "nsViewManager.h"
      54             : #include "nsView.h"
      55             : #include "nsCRTGlue.h"
      56             : #include "prinrval.h"
      57             : #include "nsTArray.h"
      58             : #include "nsCOMArray.h"
      59             : #include "nsContainerFrame.h"
      60             : #include "mozilla/dom/Selection.h"
      61             : #include "nsGkAtoms.h"
      62             : #include "nsRange.h"
      63             : #include "nsWindowSizes.h"
      64             : #include "nsCOMPtr.h"
      65             : #include "nsAutoPtr.h"
      66             : #include "nsReadableUtils.h"
      67             : #include "nsIPageSequenceFrame.h"
      68             : #include "nsIPermissionManager.h"
      69             : #include "nsIMozBrowserFrame.h"
      70             : #include "nsCaret.h"
      71             : #include "AccessibleCaretEventHub.h"
      72             : #include "nsFrameManager.h"
      73             : #include "nsXPCOM.h"
      74             : #include "nsILayoutHistoryState.h"
      75             : #include "nsILineIterator.h" // for ScrollContentIntoView
      76             : #include "PLDHashTable.h"
      77             : #include "mozilla/dom/Touch.h"
      78             : #include "mozilla/dom/TouchEvent.h"
      79             : #include "mozilla/dom/PointerEventBinding.h"
      80             : #include "nsIObserverService.h"
      81             : #include "nsDocShell.h"        // for reflow observation
      82             : #include "nsIBaseWindow.h"
      83             : #include "nsError.h"
      84             : #include "nsLayoutUtils.h"
      85             : #include "nsViewportInfo.h"
      86             : #include "nsCSSRendering.h"
      87             :   // for |#ifdef DEBUG| code
      88             : #include "prenv.h"
      89             : #include "nsDisplayList.h"
      90             : #include "nsRegion.h"
      91             : #include "nsAutoLayoutPhase.h"
      92             : #ifdef MOZ_GECKO_PROFILER
      93             : #include "AutoProfilerStyleMarker.h"
      94             : #endif
      95             : #ifdef MOZ_REFLOW_PERF
      96             : #include "nsFontMetrics.h"
      97             : #endif
      98             : #include "PositionedEventTargeting.h"
      99             : 
     100             : #include "nsIReflowCallback.h"
     101             : 
     102             : #include "nsPIDOMWindow.h"
     103             : #include "nsFocusManager.h"
     104             : #include "nsIObjectFrame.h"
     105             : #include "nsIObjectLoadingContent.h"
     106             : #include "nsNetUtil.h"
     107             : #include "nsThreadUtils.h"
     108             : #include "nsStyleSheetService.h"
     109             : #include "gfxUtils.h"
     110             : #include "nsSMILAnimationController.h"
     111             : #include "SVGContentUtils.h"
     112             : #include "SVGObserverUtils.h"
     113             : #include "SVGFragmentIdentifier.h"
     114             : #include "nsFrameSelection.h"
     115             : 
     116             : #include "mozilla/dom/Performance.h"
     117             : #include "nsRefreshDriver.h"
     118             : #include "nsDOMNavigationTiming.h"
     119             : 
     120             : // Drag & Drop, Clipboard
     121             : #include "nsIDocShellTreeItem.h"
     122             : #include "nsIURI.h"
     123             : #include "nsIScrollableFrame.h"
     124             : #include "nsITimer.h"
     125             : #ifdef ACCESSIBILITY
     126             : #include "nsAccessibilityService.h"
     127             : #include "mozilla/a11y/DocAccessible.h"
     128             : #ifdef DEBUG
     129             : #include "mozilla/a11y/Logging.h"
     130             : #endif
     131             : #endif
     132             : 
     133             : // For style data reconstruction
     134             : #include "nsStyleChangeList.h"
     135             : #include "nsCSSFrameConstructor.h"
     136             : #ifdef MOZ_XUL
     137             : #include "nsMenuFrame.h"
     138             : #include "nsTreeBodyFrame.h"
     139             : #include "nsIBoxObject.h"
     140             : #include "nsITreeBoxObject.h"
     141             : #include "nsMenuPopupFrame.h"
     142             : #include "nsTreeColumns.h"
     143             : #include "nsIDOMXULMultSelectCntrlEl.h"
     144             : #include "nsIDOMXULSelectCntrlItemEl.h"
     145             : #include "nsIDOMXULMenuListElement.h"
     146             : #include "nsXULElement.h"
     147             : #include "mozilla/dom/BoxObject.h"
     148             : #endif // MOZ_XUL
     149             : 
     150             : #include "mozilla/layers/CompositorBridgeChild.h"
     151             : #include "ClientLayerManager.h"
     152             : #include "GeckoProfiler.h"
     153             : #include "gfxPlatform.h"
     154             : #include "Layers.h"
     155             : #include "LayerTreeInvalidation.h"
     156             : #include "mozilla/css/ImageLoader.h"
     157             : #include "mozilla/dom/DocumentTimeline.h"
     158             : #include "mozilla/dom/ScriptSettings.h"
     159             : #include "mozilla/ErrorResult.h"
     160             : #include "mozilla/Preferences.h"
     161             : #include "mozilla/Telemetry.h"
     162             : #include "nsCanvasFrame.h"
     163             : #include "nsIImageLoadingContent.h"
     164             : #include "nsImageFrame.h"
     165             : #include "nsIScreen.h"
     166             : #include "nsIScreenManager.h"
     167             : #include "nsPlaceholderFrame.h"
     168             : #include "nsTransitionManager.h"
     169             : #include "ChildIterator.h"
     170             : #include "mozilla/RestyleManager.h"
     171             : #include "nsIDragSession.h"
     172             : #include "nsIFrameInlines.h"
     173             : #include "mozilla/gfx/2D.h"
     174             : #include "nsSubDocumentFrame.h"
     175             : #include "nsQueryObject.h"
     176             : #include "nsLayoutStylesheetCache.h"
     177             : #include "mozilla/layers/InputAPZContext.h"
     178             : #include "mozilla/layers/FocusTarget.h"
     179             : #include "mozilla/ServoBindings.h"
     180             : #include "mozilla/ServoStyleSet.h"
     181             : #include "mozilla/StyleSheet.h"
     182             : #include "mozilla/StyleSheetInlines.h"
     183             : #include "mozilla/dom/ImageTracker.h"
     184             : #include "nsIDocShellTreeOwner.h"
     185             : #include "nsBindingManager.h"
     186             : #include "nsClassHashtable.h"
     187             : #include "nsHashKeys.h"
     188             : 
     189             : #ifdef MOZ_TASK_TRACER
     190             : #include "GeckoTaskTracer.h"
     191             : using namespace mozilla::tasktracer;
     192             : #endif
     193             : 
     194             : #define ANCHOR_SCROLL_FLAGS \
     195             :   (nsIPresShell::SCROLL_OVERFLOW_HIDDEN | nsIPresShell::SCROLL_NO_PARENT_FRAMES)
     196             : 
     197             :   // define the scalfactor of drag and drop images
     198             :   // relative to the max screen height/width
     199             : #define RELATIVE_SCALEFACTOR 0.0925f
     200             : 
     201             : using namespace mozilla;
     202             : using namespace mozilla::css;
     203             : using namespace mozilla::dom;
     204             : using namespace mozilla::gfx;
     205             : using namespace mozilla::layers;
     206             : using namespace mozilla::gfx;
     207             : using namespace mozilla::layout;
     208             : using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
     209             : typedef FrameMetrics::ViewID ViewID;
     210             : 
     211             : CapturingContentInfo nsIPresShell::gCaptureInfo =
     212             :   { false /* mAllowed */, false /* mPointerLock */, false /* mRetargetToElement */,
     213           0 :     false /* mPreventDrag */ };
     214             : nsIContent* nsIPresShell::gKeyDownTarget;
     215             : 
     216             : // RangePaintInfo is used to paint ranges to offscreen buffers
     217             : struct RangePaintInfo {
     218             :   RefPtr<nsRange> mRange;
     219             :   nsDisplayListBuilder mBuilder;
     220             :   nsDisplayList mList;
     221             : 
     222             :   // offset of builder's reference frame to the root frame
     223             :   nsPoint mRootOffset;
     224             : 
     225           0 :   RangePaintInfo(nsRange* aRange, nsIFrame* aFrame)
     226           0 :     : mRange(aRange)
     227           0 :     , mBuilder(aFrame, nsDisplayListBuilderMode::PAINTING, false)
     228             :   {
     229           0 :     MOZ_COUNT_CTOR(RangePaintInfo);
     230           0 :     mBuilder.BeginFrame();
     231           0 :   }
     232             : 
     233           0 :   ~RangePaintInfo()
     234           0 :   {
     235           0 :     mList.DeleteAll(&mBuilder);
     236           0 :     mBuilder.EndFrame();
     237           0 :     MOZ_COUNT_DTOR(RangePaintInfo);
     238           0 :   }
     239             : };
     240             : 
     241             : #undef NOISY
     242             : 
     243             : // ----------------------------------------------------------------------
     244             : 
     245             : #ifdef DEBUG
     246             : // Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or
     247             : // more of the following flags (comma separated) for handy debug
     248             : // output.
     249             : static uint32_t gVerifyReflowFlags;
     250             : 
     251             : struct VerifyReflowFlags {
     252             :   const char*    name;
     253             :   uint32_t bit;
     254             : };
     255             : 
     256             : static const VerifyReflowFlags gFlags[] = {
     257             :   { "verify",                VERIFY_REFLOW_ON },
     258             :   { "reflow",                VERIFY_REFLOW_NOISY },
     259             :   { "all",                   VERIFY_REFLOW_ALL },
     260             :   { "list-commands",         VERIFY_REFLOW_DUMP_COMMANDS },
     261             :   { "noisy-commands",        VERIFY_REFLOW_NOISY_RC },
     262             :   { "really-noisy-commands", VERIFY_REFLOW_REALLY_NOISY_RC },
     263             :   { "resize",                VERIFY_REFLOW_DURING_RESIZE_REFLOW },
     264             : };
     265             : 
     266             : #define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
     267             : 
     268             : static void
     269           0 : ShowVerifyReflowFlags()
     270             : {
     271           0 :   printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n");
     272           0 :   const VerifyReflowFlags* flag = gFlags;
     273           0 :   const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
     274           0 :   while (flag < limit) {
     275           0 :     printf("  %s\n", flag->name);
     276           0 :     ++flag;
     277             :   }
     278           0 :   printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n");
     279           0 :   printf("names (no whitespace)\n");
     280           0 : }
     281             : #endif
     282             : 
     283             : //========================================================================
     284             : //========================================================================
     285             : //========================================================================
     286             : #ifdef MOZ_REFLOW_PERF
     287             : class ReflowCountMgr;
     288             : 
     289             : static const char kGrandTotalsStr[] = "Grand Totals";
     290             : 
     291             : // Counting Class
     292             : class ReflowCounter {
     293             : public:
     294             :   explicit ReflowCounter(ReflowCountMgr * aMgr = nullptr);
     295             :   ~ReflowCounter();
     296             : 
     297             :   void ClearTotals();
     298             :   void DisplayTotals(const char * aStr);
     299             :   void DisplayDiffTotals(const char * aStr);
     300             :   void DisplayHTMLTotals(const char * aStr);
     301             : 
     302           0 :   void Add()                { mTotal++;         }
     303           0 :   void Add(uint32_t aTotal) { mTotal += aTotal; }
     304             : 
     305             :   void CalcDiffInTotals();
     306             :   void SetTotalsCache();
     307             : 
     308             :   void SetMgr(ReflowCountMgr * aMgr) { mMgr = aMgr; }
     309             : 
     310             :   uint32_t GetTotal() { return mTotal; }
     311             : 
     312             : protected:
     313             :   void DisplayTotals(uint32_t aTotal, const char * aTitle);
     314             :   void DisplayHTMLTotals(uint32_t aTotal, const char * aTitle);
     315             : 
     316             :   uint32_t mTotal;
     317             :   uint32_t mCacheTotal;
     318             : 
     319             :   ReflowCountMgr * mMgr; // weak reference (don't delete)
     320             : };
     321             : 
     322             : // Counting Class
     323             : class IndiReflowCounter {
     324             : public:
     325           0 :   explicit IndiReflowCounter(ReflowCountMgr * aMgr = nullptr)
     326           0 :     : mFrame(nullptr),
     327             :       mCount(0),
     328             :       mMgr(aMgr),
     329             :       mCounter(aMgr),
     330           0 :       mHasBeenOutput(false)
     331           0 :     {}
     332           0 :   virtual ~IndiReflowCounter() {}
     333             : 
     334             :   nsAutoString mName;
     335             :   nsIFrame *   mFrame;   // weak reference (don't delete)
     336             :   int32_t      mCount;
     337             : 
     338             :   ReflowCountMgr * mMgr; // weak reference (don't delete)
     339             : 
     340             :   ReflowCounter mCounter;
     341             :   bool          mHasBeenOutput;
     342             : 
     343             : };
     344             : 
     345             : //--------------------
     346             : // Manager Class
     347             : //--------------------
     348             : class ReflowCountMgr {
     349             : public:
     350             :   ReflowCountMgr();
     351             :   virtual ~ReflowCountMgr();
     352             : 
     353             :   void ClearTotals();
     354             :   void ClearGrandTotals();
     355             :   void DisplayTotals(const char * aStr);
     356             :   void DisplayHTMLTotals(const char * aStr);
     357             :   void DisplayDiffsInTotals();
     358             : 
     359             :   void Add(const char * aName, nsIFrame * aFrame);
     360             :   ReflowCounter * LookUp(const char * aName);
     361             : 
     362             :   void PaintCount(const char *aName, gfxContext* aRenderingContext,
     363             :                   nsPresContext *aPresContext, nsIFrame *aFrame,
     364             :                   const nsPoint &aOffset, uint32_t aColor);
     365             : 
     366             :   FILE * GetOutFile() { return mFD; }
     367             : 
     368           0 :   void SetPresContext(nsPresContext * aPresContext) { mPresContext = aPresContext; } // weak reference
     369           0 :   void SetPresShell(nsIPresShell* aPresShell) { mPresShell= aPresShell; } // weak reference
     370             : 
     371           0 :   void SetDumpFrameCounts(bool aVal)         { mDumpFrameCounts = aVal; }
     372           0 :   void SetDumpFrameByFrameCounts(bool aVal)  { mDumpFrameByFrameCounts = aVal; }
     373           0 :   void SetPaintFrameCounts(bool aVal)        { mPaintFrameByFrameCounts = aVal; }
     374             : 
     375             :   bool IsPaintingFrameCounts() { return mPaintFrameByFrameCounts; }
     376             : 
     377             : protected:
     378             :   void DisplayTotals(uint32_t aTotal, uint32_t * aDupArray, char * aTitle);
     379             :   void DisplayHTMLTotals(uint32_t aTotal, uint32_t * aDupArray, char * aTitle);
     380             : 
     381             :   void DoGrandTotals();
     382             :   void DoIndiTotalsTree();
     383             : 
     384             :   // HTML Output Methods
     385             :   void DoGrandHTMLTotals();
     386             : 
     387             :   nsClassHashtable<nsCharPtrHashKey, ReflowCounter> mCounts;
     388             :   nsClassHashtable<nsCharPtrHashKey, IndiReflowCounter> mIndiFrameCounts;
     389             :   FILE * mFD;
     390             : 
     391             :   bool mDumpFrameCounts;
     392             :   bool mDumpFrameByFrameCounts;
     393             :   bool mPaintFrameByFrameCounts;
     394             : 
     395             :   bool mCycledOnce;
     396             : 
     397             :   // Root Frame for Individual Tracking
     398             :   nsPresContext * mPresContext;
     399             :   nsIPresShell*    mPresShell;
     400             : 
     401             :   // ReflowCountMgr gReflowCountMgr;
     402             : };
     403             : #endif
     404             : //========================================================================
     405             : 
     406             : // comment out to hide caret
     407             : #define SHOW_CARET
     408             : 
     409             : // The upper bound on the amount of time to spend reflowing, in
     410             : // microseconds.  When this bound is exceeded and reflow commands are
     411             : // still queued up, a reflow event is posted.  The idea is for reflow
     412             : // to not hog the processor beyond the time specifed in
     413             : // gMaxRCProcessingTime.  This data member is initialized from the
     414             : // layout.reflow.timeslice pref.
     415             : #define NS_MAX_REFLOW_TIME    1000000
     416             : static int32_t gMaxRCProcessingTime = -1;
     417             : 
     418             : struct nsCallbackEventRequest
     419             : {
     420             :   nsIReflowCallback* callback;
     421             :   nsCallbackEventRequest* next;
     422             : };
     423             : 
     424             : // ----------------------------------------------------------------------------
     425             : //
     426             : // NOTE(emilio): It'd be nice for this to assert that our document isn't in the
     427             : // bfcache, but font pref changes don't care about that, and maybe / probably
     428             : // shouldn't.
     429             : #ifdef DEBUG
     430             : #define ASSERT_REFLOW_SCHEDULED_STATE()                                       \
     431             : {                                                                             \
     432             :   if (ObservingLayoutFlushes()) {                                             \
     433             :     MOZ_ASSERT(mDocument->GetBFCacheEntry() ||                                \
     434             :                mPresContext->RefreshDriver()->IsLayoutFlushObserver(this),    \
     435             :                "Unexpected state");                                           \
     436             :   } else {                                                                    \
     437             :     MOZ_ASSERT(!mPresContext->RefreshDriver()->IsLayoutFlushObserver(this),   \
     438             :                "Unexpected state");                                           \
     439             :   }                                                                           \
     440             : }
     441             : #else
     442             : #define ASSERT_REFLOW_SCHEDULED_STATE() /* nothing */
     443             : #endif
     444             : 
     445             : class nsAutoCauseReflowNotifier
     446             : {
     447             : public:
     448             :   explicit nsAutoCauseReflowNotifier(PresShell* aShell)
     449           0 :     : mShell(aShell)
     450             :   {
     451           0 :     mShell->WillCauseReflow();
     452             :   }
     453           0 :   ~nsAutoCauseReflowNotifier()
     454           0 :   {
     455             :     // This check should not be needed. Currently the only place that seem
     456             :     // to need it is the code that deals with bug 337586.
     457           0 :     if (!mShell->mHaveShutDown) {
     458           0 :       mShell->DidCauseReflow();
     459             :     }
     460             :     else {
     461           0 :       nsContentUtils::RemoveScriptBlocker();
     462             :     }
     463           0 :   }
     464             : 
     465             :   PresShell* mShell;
     466             : };
     467             : 
     468           0 : class MOZ_STACK_CLASS nsPresShellEventCB : public EventDispatchingCallback
     469             : {
     470             : public:
     471           0 :   explicit nsPresShellEventCB(PresShell* aPresShell) : mPresShell(aPresShell) {}
     472             : 
     473           0 :   virtual void HandleEvent(EventChainPostVisitor& aVisitor) override
     474             :   {
     475           0 :     if (aVisitor.mPresContext && aVisitor.mEvent->mClass != eBasicEventClass) {
     476           0 :       if (aVisitor.mEvent->mMessage == eMouseDown ||
     477             :           aVisitor.mEvent->mMessage == eMouseUp) {
     478             :         // Mouse-up and mouse-down events call nsFrame::HandlePress/Release
     479             :         // which call GetContentOffsetsFromPoint which requires up-to-date layout.
     480             :         // Bring layout up-to-date now so that GetCurrentEventFrame() below
     481             :         // will return a real frame and we don't have to worry about
     482             :         // destroying it by flushing later.
     483           0 :         mPresShell->FlushPendingNotifications(FlushType::Layout);
     484           0 :       } else if (aVisitor.mEvent->mMessage == eWheel &&
     485           0 :                  aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
     486           0 :         nsIFrame* frame = mPresShell->GetCurrentEventFrame();
     487           0 :         if (frame) {
     488             :           // chrome (including addons) should be able to know if content
     489             :           // handles both D3E "wheel" event and legacy mouse scroll events.
     490             :           // We should dispatch legacy mouse events before dispatching the
     491             :           // "wheel" event into system group.
     492             :           RefPtr<EventStateManager> esm =
     493           0 :             aVisitor.mPresContext->EventStateManager();
     494           0 :           esm->DispatchLegacyMouseScrollEvents(frame,
     495           0 :                                                aVisitor.mEvent->AsWheelEvent(),
     496           0 :                                                &aVisitor.mEventStatus);
     497             :         }
     498             :       }
     499           0 :       nsIFrame* frame = mPresShell->GetCurrentEventFrame();
     500           0 :       if (!frame &&
     501           0 :           (aVisitor.mEvent->mMessage == eMouseUp ||
     502             :            aVisitor.mEvent->mMessage == eTouchEnd)) {
     503             :         // Redirect BUTTON_UP and TOUCH_END events to the root frame to ensure
     504             :         // that capturing is released.
     505           0 :         frame = mPresShell->GetRootFrame();
     506             :       }
     507           0 :       if (frame) {
     508           0 :         frame->HandleEvent(aVisitor.mPresContext,
     509           0 :                            aVisitor.mEvent->AsGUIEvent(),
     510           0 :                            &aVisitor.mEventStatus);
     511             :       }
     512             :     }
     513           0 :   }
     514             : 
     515             :   RefPtr<PresShell> mPresShell;
     516             : };
     517             : 
     518           0 : class nsBeforeFirstPaintDispatcher : public Runnable
     519             : {
     520             : public:
     521           0 :   explicit nsBeforeFirstPaintDispatcher(nsIDocument* aDocument)
     522           0 :     : mozilla::Runnable("nsBeforeFirstPaintDispatcher")
     523           0 :     , mDocument(aDocument)
     524             :   {
     525           0 :   }
     526             : 
     527             :   // Fires the "before-first-paint" event so that interested parties (right now, the
     528             :   // mobile browser) are aware of it.
     529           0 :   NS_IMETHOD Run() override
     530             :   {
     531             :     nsCOMPtr<nsIObserverService> observerService =
     532           0 :       mozilla::services::GetObserverService();
     533           0 :     if (observerService) {
     534           0 :       observerService->NotifyObservers(mDocument, "before-first-paint",
     535           0 :                                        nullptr);
     536             :     }
     537           0 :     return NS_OK;
     538             :   }
     539             : 
     540             : private:
     541             :   nsCOMPtr<nsIDocument> mDocument;
     542             : };
     543             : 
     544             : // This is a helper class to track whether the targeted frame is destroyed after
     545             : // dispatching pointer events. In that case, we need the original targeted
     546             : // content so that we can dispatch the mouse events to it.
     547             : class MOZ_STACK_CLASS AutoPointerEventTargetUpdater final
     548             : {
     549             : public:
     550           0 :   AutoPointerEventTargetUpdater(PresShell* aShell,
     551             :                                 WidgetEvent* aEvent,
     552             :                                 nsIFrame* aFrame,
     553             :                                 nsIContent** aTargetContent)
     554           0 :   {
     555           0 :     MOZ_ASSERT(aEvent);
     556           0 :     if (!aTargetContent || aEvent->mClass != ePointerEventClass) {
     557             :       // Make the destructor happy.
     558           0 :       mTargetContent = nullptr;
     559           0 :       return;
     560             :     }
     561           0 :     MOZ_ASSERT(aShell);
     562           0 :     MOZ_ASSERT(aFrame);
     563           0 :     MOZ_ASSERT(!aFrame->GetContent() ||
     564             :                aShell->GetDocument() == aFrame->GetContent()->OwnerDoc());
     565             : 
     566           0 :     MOZ_ASSERT(PointerEventHandler::IsPointerEventEnabled());
     567           0 :     mShell = aShell;
     568           0 :     mWeakFrame = aFrame;
     569           0 :     mTargetContent = aTargetContent;
     570           0 :     aShell->mPointerEventTarget = aFrame->GetContent();
     571             :   }
     572             : 
     573           0 :   ~AutoPointerEventTargetUpdater()
     574           0 :   {
     575           0 :     if (!mTargetContent || !mShell || mWeakFrame.IsAlive()) {
     576             :       return;
     577             :     }
     578           0 :     mShell->mPointerEventTarget.swap(*mTargetContent);
     579           0 :   }
     580             : 
     581             : private:
     582             :   RefPtr<PresShell> mShell;
     583             :   AutoWeakFrame mWeakFrame;
     584             :   nsIContent** mTargetContent;
     585             : };
     586             : 
     587             : bool PresShell::sDisableNonTestMouseEvents = false;
     588             : 
     589             : mozilla::LazyLogModule PresShell::gLog("PresShell");
     590             : 
     591             : mozilla::TimeStamp PresShell::sLastInputCreated;
     592             : mozilla::TimeStamp PresShell::sLastInputProcessed;
     593             : 
     594             : bool PresShell::sProcessInteractable = false;
     595             : 
     596             : static bool gVerifyReflowEnabled;
     597             : 
     598             : bool
     599           0 : nsIPresShell::GetVerifyReflowEnable()
     600             : {
     601             : #ifdef DEBUG
     602             :   static bool firstTime = true;
     603           0 :   if (firstTime) {
     604           0 :     firstTime = false;
     605           0 :     char* flags = PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS");
     606           0 :     if (flags) {
     607             :       bool error = false;
     608             : 
     609             :       for (;;) {
     610           0 :         char* comma = PL_strchr(flags, ',');
     611           0 :         if (comma)
     612           0 :           *comma = '\0';
     613             : 
     614             :         bool found = false;
     615             :         const VerifyReflowFlags* flag = gFlags;
     616             :         const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS;
     617           0 :         while (flag < limit) {
     618           0 :           if (PL_strcasecmp(flag->name, flags) == 0) {
     619           0 :             gVerifyReflowFlags |= flag->bit;
     620           0 :             found = true;
     621           0 :             break;
     622             :           }
     623           0 :           ++flag;
     624             :         }
     625             : 
     626           0 :         if (! found)
     627           0 :           error = true;
     628             : 
     629           0 :         if (! comma)
     630             :           break;
     631             : 
     632           0 :         *comma = ',';
     633           0 :         flags = comma + 1;
     634           0 :       }
     635             : 
     636           0 :       if (error)
     637           0 :         ShowVerifyReflowFlags();
     638             :     }
     639             : 
     640           0 :     if (VERIFY_REFLOW_ON & gVerifyReflowFlags) {
     641           0 :       gVerifyReflowEnabled = true;
     642             : 
     643           0 :       printf("Note: verifyreflow is enabled");
     644           0 :       if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
     645             :         printf(" (noisy)");
     646             :       }
     647           0 :       if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
     648             :         printf(" (all)");
     649             :       }
     650           0 :       if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
     651             :         printf(" (show reflow commands)");
     652             :       }
     653           0 :       if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
     654           0 :         printf(" (noisy reflow commands)");
     655           0 :         if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
     656             :           printf(" (REALLY noisy reflow commands)");
     657             :         }
     658             :       }
     659             :       printf("\n");
     660             :     }
     661             :   }
     662             : #endif
     663           0 :   return gVerifyReflowEnabled;
     664             : }
     665             : 
     666             : void
     667           0 : nsIPresShell::SetVerifyReflowEnable(bool aEnabled)
     668             : {
     669           0 :   gVerifyReflowEnabled = aEnabled;
     670           0 : }
     671             : 
     672             : void
     673           0 : nsIPresShell::AddAutoWeakFrame(AutoWeakFrame* aWeakFrame)
     674             : {
     675           0 :   if (aWeakFrame->GetFrame()) {
     676           0 :     aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
     677             :   }
     678           0 :   aWeakFrame->SetPreviousWeakFrame(mAutoWeakFrames);
     679           0 :   mAutoWeakFrames = aWeakFrame;
     680           0 : }
     681             : 
     682             : void
     683           0 : nsIPresShell::AddWeakFrame(WeakFrame* aWeakFrame)
     684             : {
     685           0 :   if (aWeakFrame->GetFrame()) {
     686           0 :     aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
     687             :   }
     688           0 :   MOZ_ASSERT(!mWeakFrames.GetEntry(aWeakFrame));
     689           0 :   mWeakFrames.PutEntry(aWeakFrame);
     690           0 : }
     691             : 
     692             : void
     693           0 : nsIPresShell::RemoveAutoWeakFrame(AutoWeakFrame* aWeakFrame)
     694             : {
     695           0 :   if (mAutoWeakFrames == aWeakFrame) {
     696           0 :     mAutoWeakFrames = aWeakFrame->GetPreviousWeakFrame();
     697           0 :     return;
     698             :   }
     699             :   AutoWeakFrame* nextWeak = mAutoWeakFrames;
     700           0 :   while (nextWeak && nextWeak->GetPreviousWeakFrame() != aWeakFrame) {
     701           0 :     nextWeak = nextWeak->GetPreviousWeakFrame();
     702             :   }
     703           0 :   if (nextWeak) {
     704           0 :     nextWeak->SetPreviousWeakFrame(aWeakFrame->GetPreviousWeakFrame());
     705             :   }
     706             : }
     707             : 
     708             : void
     709           0 : nsIPresShell::RemoveWeakFrame(WeakFrame* aWeakFrame)
     710             : {
     711           0 :   MOZ_ASSERT(mWeakFrames.GetEntry(aWeakFrame));
     712           0 :   mWeakFrames.RemoveEntry(aWeakFrame);
     713           0 : }
     714             : 
     715             : already_AddRefed<nsFrameSelection>
     716           0 : nsIPresShell::FrameSelection()
     717             : {
     718           0 :   RefPtr<nsFrameSelection> ret = mSelection;
     719           0 :   return ret.forget();
     720             : }
     721             : 
     722             : //----------------------------------------------------------------------
     723             : 
     724             : static bool sSynthMouseMove = true;
     725             : static uint32_t sNextPresShellId;
     726             : static bool sAccessibleCaretEnabled = false;
     727             : static bool sAccessibleCaretOnTouch = false;
     728             : 
     729             : /* static */ bool
     730           0 : PresShell::AccessibleCaretEnabled(nsIDocShell* aDocShell)
     731             : {
     732             :   static bool initialized = false;
     733           0 :   if (!initialized) {
     734           0 :     Preferences::AddBoolVarCache(&sAccessibleCaretEnabled, "layout.accessiblecaret.enabled");
     735           0 :     Preferences::AddBoolVarCache(&sAccessibleCaretOnTouch, "layout.accessiblecaret.enabled_on_touch");
     736           0 :     initialized = true;
     737             :   }
     738             :   // If the pref forces it on, then enable it.
     739           0 :   if (sAccessibleCaretEnabled) {
     740             :     return true;
     741             :   }
     742             :   // If the touch pref is on, and touch events are enabled (this depends
     743             :   // on the specific device running), then enable it.
     744           0 :   if (sAccessibleCaretOnTouch && dom::TouchEvent::PrefEnabled(aDocShell)) {
     745             :     return true;
     746             :   }
     747             :   // Otherwise, disabled.
     748           0 :   return false;
     749             : }
     750             : 
     751           0 : nsIPresShell::nsIPresShell()
     752             :     : mFrameConstructor(nullptr)
     753             :     , mViewManager(nullptr)
     754             :     , mFrameManager(nullptr)
     755             : #ifdef ACCESSIBILITY
     756             :     , mDocAccessible(nullptr)
     757             : #endif
     758             : #ifdef DEBUG
     759             :     , mDrawEventTargetFrame(nullptr)
     760             : #endif
     761             :     , mPaintCount(0)
     762             :     , mAutoWeakFrames(nullptr)
     763             :     , mCanvasBackgroundColor(NS_RGBA(0,0,0,0))
     764             :     , mSelectionFlags(0)
     765             :     , mChangeNestCount(0)
     766             :     , mRenderFlags(0)
     767             :     , mDidInitialize(false)
     768             :     , mIsDestroying(false)
     769             :     , mIsReflowing(false)
     770             :     , mIsObservingDocument(false)
     771             :     , mIsDocumentGone(false)
     772             :     , mPaintingSuppressed(false)
     773             :     , mIsActive(false)
     774             :     , mFrozen(false)
     775             :     , mIsFirstPaint(false)
     776             :     , mObservesMutationsForPrint(false)
     777             :     , mWasLastReflowInterrupted(false)
     778             :     , mScrollPositionClampingScrollPortSizeSet(false)
     779             :     , mNeedLayoutFlush(true)
     780             :     , mNeedStyleFlush(true)
     781             :     , mObservingStyleFlushes(false)
     782             :     , mObservingLayoutFlushes(false)
     783             :     , mResizeEventPending(false)
     784             :     , mNeedThrottledAnimationFlush(true)
     785             :     , mPresShellId(0)
     786             :     , mFontSizeInflationEmPerLine(0)
     787             :     , mFontSizeInflationMinTwips(0)
     788             :     , mFontSizeInflationLineThreshold(0)
     789             :     , mFontSizeInflationForceEnabled(false)
     790             :     , mFontSizeInflationDisabledInMasterProcess(false)
     791             :     , mFontSizeInflationEnabled(false)
     792             :     , mPaintingIsFrozen(false)
     793             :     , mIsNeverPainting(false)
     794           0 :     , mInFlush(false)
     795           0 :   {}
     796             : 
     797           0 : PresShell::PresShell()
     798             :   : mCaretEnabled(false)
     799             : #ifdef DEBUG
     800             :   , mInVerifyReflow(false)
     801             :   , mCurrentReflowRoot(nullptr)
     802             : #endif
     803             : #ifdef MOZ_REFLOW_PERF
     804             :   , mReflowCountMgr(nullptr)
     805             : #endif
     806             :   , mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
     807             :   , mCurrentEventFrame(nullptr)
     808             :   , mFirstCallbackEventRequest(nullptr)
     809             :   , mLastCallbackEventRequest(nullptr)
     810             :   , mLastReflowStart(0.0)
     811             :   , mLastAnchorScrollPositionY(0)
     812             :   , mAPZFocusSequenceNumber(0)
     813             :   , mDocumentLoading(false)
     814             :   , mIgnoreFrameDestruction(false)
     815             :   , mHaveShutDown(false)
     816             :   , mLastRootReflowHadUnconstrainedBSize(false)
     817             :   , mNoDelayedMouseEvents(false)
     818             :   , mNoDelayedKeyEvents(false)
     819             :   , mShouldUnsuppressPainting(false)
     820             :   , mApproximateFrameVisibilityVisited(false)
     821             :   , mNextPaintCompressed(false)
     822             :   , mHasCSSBackgroundColor(false)
     823             :   , mScaleToResolution(false)
     824             :   , mIsLastChromeOnlyEscapeKeyConsumed(false)
     825             :   , mHasReceivedPaintMessage(false)
     826             :   , mHasHandledUserInput(false)
     827             : #ifdef NIGHTLY_BUILD
     828             :   , mForceDispatchKeyPressEventsForNonPrintableKeys(false)
     829           0 :   , mInitializedForceDispatchKeyPressEventsForNonPrintableKeys(false)
     830             : #endif // #ifdef NIGHTLY_BUILD
     831             : {
     832           0 :   MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::PresShell this=%p", this));
     833             : 
     834             : #ifdef MOZ_REFLOW_PERF
     835           0 :   mReflowCountMgr = new ReflowCountMgr();
     836           0 :   mReflowCountMgr->SetPresContext(mPresContext);
     837           0 :   mReflowCountMgr->SetPresShell(this);
     838             : #endif
     839           0 :   mLastOSWake = mLoadBegin = TimeStamp::Now();
     840             : 
     841           0 :   mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES;
     842           0 :   mIsActive = true;
     843             :   // FIXME/bug 735029: find a better solution to this problem
     844           0 :   mIsFirstPaint = true;
     845           0 :   mPresShellId = sNextPresShellId++;
     846           0 :   mFrozen = false;
     847           0 :   mRenderFlags = 0;
     848             : 
     849           0 :   mScrollPositionClampingScrollPortSizeSet = false;
     850             : 
     851             :   static bool addedSynthMouseMove = false;
     852           0 :   if (!addedSynthMouseMove) {
     853             :     Preferences::AddBoolVarCache(&sSynthMouseMove,
     854           0 :                                  "layout.reflow.synthMouseMove", true);
     855           0 :     addedSynthMouseMove = true;
     856             :   }
     857           0 :   PointerEventHandler::Initialize();
     858           0 :   mPaintingIsFrozen = false;
     859           0 :   mHasCSSBackgroundColor = true;
     860           0 :   mIsLastChromeOnlyEscapeKeyConsumed = false;
     861           0 :   mHasReceivedPaintMessage = false;
     862           0 : }
     863             : 
     864           0 : NS_IMPL_ISUPPORTS(PresShell, nsIPresShell, nsIDocumentObserver,
     865             :                   nsISelectionController,
     866             :                   nsISelectionDisplay, nsIObserver, nsISupportsWeakReference,
     867             :                   nsIMutationObserver)
     868             : 
     869           0 : PresShell::~PresShell()
     870             : {
     871           0 :   MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::~PresShell this=%p", this));
     872             : 
     873           0 :   if (!mHaveShutDown) {
     874           0 :     NS_NOTREACHED("Someone did not call nsIPresShell::destroy");
     875           0 :     Destroy();
     876             :   }
     877             : 
     878           0 :   NS_ASSERTION(mCurrentEventContentStack.Count() == 0,
     879             :                "Huh, event content left on the stack in pres shell dtor!");
     880           0 :   NS_ASSERTION(mFirstCallbackEventRequest == nullptr &&
     881             :                mLastCallbackEventRequest == nullptr,
     882             :                "post-reflow queues not empty.  This means we're leaking");
     883             : 
     884             :   // Verify that if painting was frozen, but we're being removed from the tree,
     885             :   // that we now re-enable painting on our refresh driver, since it may need to
     886             :   // be re-used by another presentation.
     887           0 :   if (mPaintingIsFrozen) {
     888           0 :     mPresContext->RefreshDriver()->Thaw();
     889             :   }
     890             : 
     891           0 :   MOZ_ASSERT(mAllocatedPointers.IsEmpty(), "Some pres arena objects were not freed");
     892             : 
     893           0 :   mStyleSet = nullptr;
     894           0 :   delete mFrameConstructor;
     895             : 
     896           0 :   mCurrentEventContent = nullptr;
     897           0 : }
     898             : 
     899             : /**
     900             :  * Initialize the presentation shell. Create view manager and style
     901             :  * manager.
     902             :  * Note this can't be merged into our constructor because caret initialization
     903             :  * calls AddRef() on us.
     904             :  */
     905             : void
     906           0 : PresShell::Init(nsIDocument* aDocument,
     907             :                 nsPresContext* aPresContext,
     908             :                 nsViewManager* aViewManager,
     909             :                 UniquePtr<ServoStyleSet> aStyleSet)
     910             : {
     911           0 :   MOZ_ASSERT(aDocument, "null ptr");
     912           0 :   MOZ_ASSERT(aPresContext, "null ptr");
     913           0 :   MOZ_ASSERT(aViewManager, "null ptr");
     914           0 :   MOZ_ASSERT(!mDocument, "already initialized");
     915             : 
     916           0 :   if (!aDocument || !aPresContext || !aViewManager || mDocument) {
     917           0 :     return;
     918             :   }
     919             : 
     920           0 :   mDocument = aDocument;
     921           0 :   mViewManager = aViewManager;
     922             : 
     923             :   // mDocument is now set.  It might have a display document whose "need layout/
     924             :   // style" flush flags are not set, but ours will be set.  To keep these
     925             :   // consistent, call the flag setting functions to propagate those flags up
     926             :   // to the display document.
     927           0 :   SetNeedLayoutFlush();
     928           0 :   SetNeedStyleFlush();
     929             : 
     930             :   // Create our frame constructor.
     931           0 :   mFrameConstructor = new nsCSSFrameConstructor(mDocument, this);
     932             : 
     933           0 :   mFrameManager = mFrameConstructor;
     934             : 
     935             :   // The document viewer owns both view manager and pres shell.
     936           0 :   mViewManager->SetPresShell(this);
     937             : 
     938             :   // Bind the context to the presentation shell.
     939           0 :   mPresContext = aPresContext;
     940           0 :   mPresContext->AttachShell(this);
     941             : 
     942             :   // Now we can initialize the style set. Make sure to set the member before
     943             :   // calling Init, since various subroutines need to find the style set off
     944             :   // the PresContext during initialization.
     945           0 :   mStyleSet = std::move(aStyleSet);
     946           0 :   mStyleSet->Init(aPresContext);
     947             : 
     948             :   // Notify our prescontext that it now has a compatibility mode.  Note that
     949             :   // this MUST happen after we set up our style set but before we create any
     950             :   // frames.
     951           0 :   mPresContext->CompatibilityModeChanged();
     952             : 
     953             :   // Add the preference style sheet.
     954           0 :   UpdatePreferenceStyles();
     955             : 
     956           0 :   bool accessibleCaretEnabled = AccessibleCaretEnabled(mDocument->GetDocShell());
     957           0 :   if (accessibleCaretEnabled) {
     958             :     // Need to happen before nsFrameSelection has been set up.
     959           0 :     mAccessibleCaretEventHub = new AccessibleCaretEventHub(this);
     960             :   }
     961             : 
     962           0 :   mSelection = new nsFrameSelection();
     963             : 
     964           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
     965           0 :   frameSelection->Init(this, nullptr, accessibleCaretEnabled);
     966             : 
     967             :   // Important: this has to happen after the selection has been set up
     968             : #ifdef SHOW_CARET
     969             :   // make the caret
     970           0 :   mCaret = new nsCaret();
     971           0 :   mCaret->Init(this);
     972           0 :   mOriginalCaret = mCaret;
     973             : 
     974             :   //SetCaretEnabled(true);       // make it show in browser windows
     975             : #endif
     976             :   //set up selection to be displayed in document
     977             :   // Don't enable selection for print media
     978           0 :   nsPresContext::nsPresContextType type = aPresContext->Type();
     979           0 :   if (type != nsPresContext::eContext_PrintPreview &&
     980             :       type != nsPresContext::eContext_Print)
     981           0 :     SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
     982             : 
     983           0 :   if (gMaxRCProcessingTime == -1) {
     984           0 :     gMaxRCProcessingTime =
     985           0 :       Preferences::GetInt("layout.reflow.timeslice", NS_MAX_REFLOW_TIME);
     986             :   }
     987             : 
     988           0 :   if (nsStyleSheetService* ss = nsStyleSheetService::GetInstance()) {
     989           0 :     ss->RegisterPresShell(this);
     990             :   }
     991             : 
     992             :   {
     993           0 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     994           0 :     if (os) {
     995             : #ifdef MOZ_XUL
     996           0 :       os->AddObserver(this, "chrome-flush-skin-caches", false);
     997             : #endif
     998           0 :       os->AddObserver(this, "memory-pressure", false);
     999           0 :       os->AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, false);
    1000           0 :       if (XRE_IsParentProcess() && !sProcessInteractable) {
    1001           0 :         os->AddObserver(this, "sessionstore-one-or-no-tab-restored", false);
    1002             :       }
    1003           0 :       os->AddObserver(this, "font-info-updated", false);
    1004             :     }
    1005             :   }
    1006             : 
    1007             : #ifdef MOZ_REFLOW_PERF
    1008           0 :     if (mReflowCountMgr) {
    1009             :       bool paintFrameCounts =
    1010           0 :         Preferences::GetBool("layout.reflow.showframecounts");
    1011             : 
    1012             :       bool dumpFrameCounts =
    1013           0 :         Preferences::GetBool("layout.reflow.dumpframecounts");
    1014             : 
    1015             :       bool dumpFrameByFrameCounts =
    1016           0 :         Preferences::GetBool("layout.reflow.dumpframebyframecounts");
    1017             : 
    1018           0 :       mReflowCountMgr->SetDumpFrameCounts(dumpFrameCounts);
    1019           0 :       mReflowCountMgr->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts);
    1020           0 :       mReflowCountMgr->SetPaintFrameCounts(paintFrameCounts);
    1021             :     }
    1022             : #endif
    1023             : 
    1024           0 :   if (mDocument->HasAnimationController()) {
    1025           0 :     nsSMILAnimationController* animCtrl = mDocument->GetAnimationController();
    1026           0 :     animCtrl->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
    1027             :   }
    1028             : 
    1029           0 :   for (DocumentTimeline* timeline : mDocument->Timelines()) {
    1030           0 :     timeline->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver());
    1031             :   }
    1032             : 
    1033             :   // Get our activeness from the docShell.
    1034           0 :   QueryIsActive();
    1035             : 
    1036             :   // Setup our font inflation preferences.
    1037           0 :   mFontSizeInflationEmPerLine = nsLayoutUtils::FontSizeInflationEmPerLine();
    1038           0 :   mFontSizeInflationMinTwips = nsLayoutUtils::FontSizeInflationMinTwips();
    1039           0 :   mFontSizeInflationLineThreshold = nsLayoutUtils::FontSizeInflationLineThreshold();
    1040           0 :   mFontSizeInflationForceEnabled = nsLayoutUtils::FontSizeInflationForceEnabled();
    1041           0 :   mFontSizeInflationDisabledInMasterProcess = nsLayoutUtils::FontSizeInflationDisabledInMasterProcess();
    1042             :   // We'll compute the font size inflation state in Initialize(), when we know
    1043             :   // the document type.
    1044             : 
    1045           0 :   mTouchManager.Init(this, mDocument);
    1046             : 
    1047           0 :   if (mPresContext->IsRootContentDocument()) {
    1048           0 :     mZoomConstraintsClient = new ZoomConstraintsClient();
    1049           0 :     mZoomConstraintsClient->Init(this, mDocument);
    1050           0 :     if (gfxPrefs::MetaViewportEnabled() || gfxPrefs::APZAllowZooming()) {
    1051           0 :       mMobileViewportManager = new MobileViewportManager(this, mDocument);
    1052             :     }
    1053             :   }
    1054             : }
    1055             : 
    1056             : enum TextPerfLogType {
    1057             :   eLog_reflow,
    1058             :   eLog_loaddone,
    1059             :   eLog_totals
    1060             : };
    1061             : 
    1062             : static void
    1063           0 : LogTextPerfStats(gfxTextPerfMetrics* aTextPerf,
    1064             :                  PresShell* aPresShell,
    1065             :                  const gfxTextPerfMetrics::TextCounts& aCounts,
    1066             :                  float aTime, TextPerfLogType aLogType, const char* aURL)
    1067             : {
    1068           0 :   LogModule* tpLog = gfxPlatform::GetLog(eGfxLog_textperf);
    1069             : 
    1070             :   // ignore XUL contexts unless at debug level
    1071           0 :   mozilla::LogLevel logLevel = LogLevel::Warning;
    1072           0 :   if (aCounts.numContentTextRuns == 0) {
    1073           0 :     logLevel = LogLevel::Debug;
    1074             :   }
    1075             : 
    1076           0 :   if (!MOZ_LOG_TEST(tpLog, logLevel)) {
    1077           0 :     return;
    1078             :   }
    1079             : 
    1080             :   char prefix[256];
    1081             : 
    1082           0 :   switch (aLogType) {
    1083             :     case eLog_reflow:
    1084           0 :       SprintfLiteral(prefix, "(textperf-reflow) %p time-ms: %7.0f", aPresShell, aTime);
    1085           0 :       break;
    1086             :     case eLog_loaddone:
    1087           0 :       SprintfLiteral(prefix, "(textperf-loaddone) %p time-ms: %7.0f", aPresShell, aTime);
    1088           0 :       break;
    1089             :     default:
    1090           0 :       MOZ_ASSERT(aLogType == eLog_totals, "unknown textperf log type");
    1091           0 :       SprintfLiteral(prefix, "(textperf-totals) %p", aPresShell);
    1092             :   }
    1093             : 
    1094           0 :   double hitRatio = 0.0;
    1095           0 :   uint32_t lookups = aCounts.wordCacheHit + aCounts.wordCacheMiss;
    1096           0 :   if (lookups) {
    1097           0 :     hitRatio = double(aCounts.wordCacheHit) / double(lookups);
    1098             :   }
    1099             : 
    1100           0 :   if (aLogType == eLog_loaddone) {
    1101           0 :     MOZ_LOG(tpLog, logLevel,
    1102             :            ("%s reflow: %d chars: %d "
    1103             :             "[%s] "
    1104             :             "content-textruns: %d chrome-textruns: %d "
    1105             :             "max-textrun-len: %d "
    1106             :             "word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
    1107             :             "word-cache-space: %d word-cache-long: %d "
    1108             :             "pref-fallbacks: %d system-fallbacks: %d "
    1109             :             "textruns-const: %d textruns-destr: %d "
    1110             :             "generic-lookups: %d "
    1111             :             "cumulative-textruns-destr: %d\n",
    1112             :             prefix, aTextPerf->reflowCount, aCounts.numChars,
    1113             :             (aURL ? aURL : ""),
    1114             :             aCounts.numContentTextRuns, aCounts.numChromeTextRuns,
    1115             :             aCounts.maxTextRunLen,
    1116             :             lookups, hitRatio,
    1117             :             aCounts.wordCacheSpaceRules, aCounts.wordCacheLong,
    1118             :             aCounts.fallbackPrefs, aCounts.fallbackSystem,
    1119             :             aCounts.textrunConst, aCounts.textrunDestr,
    1120             :             aCounts.genericLookups,
    1121             :             aTextPerf->cumulative.textrunDestr));
    1122             :   } else {
    1123           0 :     MOZ_LOG(tpLog, logLevel,
    1124             :            ("%s reflow: %d chars: %d "
    1125             :             "content-textruns: %d chrome-textruns: %d "
    1126             :             "max-textrun-len: %d "
    1127             :             "word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
    1128             :             "word-cache-space: %d word-cache-long: %d "
    1129             :             "pref-fallbacks: %d system-fallbacks: %d "
    1130             :             "textruns-const: %d textruns-destr: %d "
    1131             :             "generic-lookups: %d "
    1132             :             "cumulative-textruns-destr: %d\n",
    1133             :             prefix, aTextPerf->reflowCount, aCounts.numChars,
    1134             :             aCounts.numContentTextRuns, aCounts.numChromeTextRuns,
    1135             :             aCounts.maxTextRunLen,
    1136             :             lookups, hitRatio,
    1137             :             aCounts.wordCacheSpaceRules, aCounts.wordCacheLong,
    1138             :             aCounts.fallbackPrefs, aCounts.fallbackSystem,
    1139             :             aCounts.textrunConst, aCounts.textrunDestr,
    1140             :             aCounts.genericLookups,
    1141             :             aTextPerf->cumulative.textrunDestr));
    1142             :   }
    1143             : }
    1144             : 
    1145             : void
    1146           0 : PresShell::Destroy()
    1147             : {
    1148             :   // Do not add code before this line please!
    1149           0 :   if (mHaveShutDown) {
    1150           0 :     return;
    1151             :   }
    1152             : 
    1153           0 :   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
    1154             :     "destroy called on presshell while scripts not blocked");
    1155             : 
    1156             :   // dump out cumulative text perf metrics
    1157             :   gfxTextPerfMetrics* tp;
    1158           0 :   if (mPresContext && (tp = mPresContext->GetTextPerfMetrics())) {
    1159           0 :     tp->Accumulate();
    1160           0 :     if (tp->cumulative.numChars > 0) {
    1161           0 :       LogTextPerfStats(tp, this, tp->cumulative, 0.0, eLog_totals, nullptr);
    1162             :     }
    1163             :   }
    1164           0 :   if (mPresContext) {
    1165           0 :     const bool mayFlushUserFontSet = false;
    1166           0 :     gfxUserFontSet* fs = mPresContext->GetUserFontSet(mayFlushUserFontSet);
    1167           0 :     if (fs) {
    1168             :       uint32_t fontCount;
    1169             :       uint64_t fontSize;
    1170           0 :       fs->GetLoadStatistics(fontCount, fontSize);
    1171           0 :       Telemetry::Accumulate(Telemetry::WEBFONT_PER_PAGE, fontCount);
    1172           0 :       Telemetry::Accumulate(Telemetry::WEBFONT_SIZE_PER_PAGE,
    1173           0 :                             uint32_t(fontSize/1024));
    1174             :     } else {
    1175           0 :       Telemetry::Accumulate(Telemetry::WEBFONT_PER_PAGE, 0);
    1176           0 :       Telemetry::Accumulate(Telemetry::WEBFONT_SIZE_PER_PAGE, 0);
    1177             :     }
    1178             :   }
    1179             : 
    1180             : #ifdef MOZ_REFLOW_PERF
    1181           0 :   DumpReflows();
    1182           0 :   if (mReflowCountMgr) {
    1183           0 :     delete mReflowCountMgr;
    1184           0 :     mReflowCountMgr = nullptr;
    1185             :   }
    1186             : #endif
    1187             : 
    1188           0 :   if (mZoomConstraintsClient) {
    1189           0 :     mZoomConstraintsClient->Destroy();
    1190           0 :     mZoomConstraintsClient = nullptr;
    1191             :   }
    1192           0 :   if (mMobileViewportManager) {
    1193           0 :     mMobileViewportManager->Destroy();
    1194           0 :     mMobileViewportManager = nullptr;
    1195             :   }
    1196             : 
    1197             : #ifdef ACCESSIBILITY
    1198           0 :   if (mDocAccessible) {
    1199             : #ifdef DEBUG
    1200           0 :     if (a11y::logging::IsEnabled(a11y::logging::eDocDestroy))
    1201           0 :       a11y::logging::DocDestroy("presshell destroyed", mDocument);
    1202             : #endif
    1203             : 
    1204           0 :     mDocAccessible->Shutdown();
    1205           0 :     mDocAccessible = nullptr;
    1206             :   }
    1207             : #endif // ACCESSIBILITY
    1208             : 
    1209           0 :   MaybeReleaseCapturingContent();
    1210             : 
    1211           0 :   if (gKeyDownTarget && gKeyDownTarget->OwnerDoc() == mDocument) {
    1212           0 :     NS_RELEASE(gKeyDownTarget);
    1213             :   }
    1214             : 
    1215           0 :   if (mContentToScrollTo) {
    1216           0 :     mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
    1217           0 :     mContentToScrollTo = nullptr;
    1218             :   }
    1219             : 
    1220           0 :   if (mPresContext) {
    1221             :     // We need to notify the destroying the nsPresContext to ESM for
    1222             :     // suppressing to use from ESM.
    1223           0 :     mPresContext->EventStateManager()->NotifyDestroyPresContext(mPresContext);
    1224             :   }
    1225             : 
    1226           0 :   if (nsStyleSheetService* ss = nsStyleSheetService::GetInstance()) {
    1227           0 :     ss->UnregisterPresShell(this);
    1228             :   }
    1229             : 
    1230             :   {
    1231           0 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    1232           0 :     if (os) {
    1233             : #ifdef MOZ_XUL
    1234           0 :       os->RemoveObserver(this, "chrome-flush-skin-caches");
    1235             : #endif
    1236           0 :       os->RemoveObserver(this, "memory-pressure");
    1237           0 :       os->RemoveObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC);
    1238           0 :       if (XRE_IsParentProcess()) {
    1239           0 :         os->RemoveObserver(this, "sessionstore-one-or-no-tab-restored");
    1240             :       }
    1241           0 :       os->RemoveObserver(this, "font-info-updated");
    1242             :     }
    1243             :   }
    1244             : 
    1245             :   // If our paint suppression timer is still active, kill it.
    1246           0 :   if (mPaintSuppressionTimer) {
    1247           0 :     mPaintSuppressionTimer->Cancel();
    1248           0 :     mPaintSuppressionTimer = nullptr;
    1249             :   }
    1250             : 
    1251             :   // Same for our reflow continuation timer
    1252           0 :   if (mReflowContinueTimer) {
    1253           0 :     mReflowContinueTimer->Cancel();
    1254           0 :     mReflowContinueTimer = nullptr;
    1255             :   }
    1256             : 
    1257           0 :   if (mDelayedPaintTimer) {
    1258           0 :     mDelayedPaintTimer->Cancel();
    1259           0 :     mDelayedPaintTimer = nullptr;
    1260             :   }
    1261             : 
    1262           0 :   mSynthMouseMoveEvent.Revoke();
    1263             : 
    1264           0 :   mUpdateApproximateFrameVisibilityEvent.Revoke();
    1265             : 
    1266           0 :   ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DISCARD_IMAGES));
    1267             : 
    1268           0 :   if (mCaret) {
    1269           0 :     mCaret->Terminate();
    1270           0 :     mCaret = nullptr;
    1271             :   }
    1272             : 
    1273           0 :   if (mSelection) {
    1274           0 :     RefPtr<nsFrameSelection> frameSelection = mSelection;
    1275           0 :     frameSelection->DisconnectFromPresShell();
    1276             :   }
    1277             : 
    1278           0 :   if (mAccessibleCaretEventHub) {
    1279           0 :     mAccessibleCaretEventHub->Terminate();
    1280           0 :     mAccessibleCaretEventHub = nullptr;
    1281             :   }
    1282             : 
    1283             :   // release our pref style sheet, if we have one still
    1284             :   //
    1285             :   // FIXME(emilio): Why do we need to do this? The stylist is getting nixed with
    1286             :   // us anyway.
    1287           0 :   RemovePreferenceStyles();
    1288             : 
    1289           0 :   mIsDestroying = true;
    1290             : 
    1291             :   // We can't release all the event content in
    1292             :   // mCurrentEventContentStack here since there might be code on the
    1293             :   // stack that will release the event content too. Double release
    1294             :   // bad!
    1295             : 
    1296             :   // The frames will be torn down, so remove them from the current
    1297             :   // event frame stack (since they'd be dangling references if we'd
    1298             :   // leave them in) and null out the mCurrentEventFrame pointer as
    1299             :   // well.
    1300             : 
    1301           0 :   mCurrentEventFrame = nullptr;
    1302             : 
    1303           0 :   int32_t i, count = mCurrentEventFrameStack.Length();
    1304           0 :   for (i = 0; i < count; i++) {
    1305           0 :     mCurrentEventFrameStack[i] = nullptr;
    1306             :   }
    1307             : 
    1308           0 :   mFramesToDirty.Clear();
    1309             : 
    1310           0 :   if (mViewManager) {
    1311             :     // Clear the view manager's weak pointer back to |this| in case it
    1312             :     // was leaked.
    1313           0 :     mViewManager->SetPresShell(nullptr);
    1314           0 :     mViewManager = nullptr;
    1315             :   }
    1316             : 
    1317             :   // mFrameArena will be destroyed soon.  Clear out any ArenaRefPtrs
    1318             :   // pointing to objects in the arena now.  This is done:
    1319             :   //
    1320             :   //   (a) before mFrameArena's destructor runs so that our
    1321             :   //       mAllocatedPointers becomes empty and doesn't trip the assertion
    1322             :   //       in ~PresShell,
    1323             :   //   (b) before the mPresContext->DetachShell() below, so
    1324             :   //       that when we clear the ArenaRefPtrs they'll still be able to
    1325             :   //       get back to this PresShell to deregister themselves (e.g. note
    1326             :   //       how ComputedStyle::Arena returns the PresShell got from its
    1327             :   //       rule node's nsPresContext, which would return null if we'd already
    1328             :   //       called mPresContext->DetachShell()), and
    1329             :   //   (c) before the mStyleSet->BeginShutdown() call just below, so that
    1330             :   //       the ComputedStyles don't complain they're being destroyed later
    1331             :   //       than the rule tree is.
    1332           0 :   mFrameArena.ClearArenaRefPtrs();
    1333             : 
    1334           0 :   mStyleSet->BeginShutdown();
    1335           0 :   nsRefreshDriver* rd = GetPresContext()->RefreshDriver();
    1336             : 
    1337             :   // This shell must be removed from the document before the frame
    1338             :   // hierarchy is torn down to avoid finding deleted frames through
    1339             :   // this presshell while the frames are being torn down
    1340           0 :   if (mDocument) {
    1341           0 :     NS_ASSERTION(mDocument->GetShell() == this, "Wrong shell?");
    1342           0 :     mDocument->ClearServoRestyleRoot();
    1343           0 :     mDocument->DeleteShell();
    1344             : 
    1345           0 :     if (mDocument->HasAnimationController()) {
    1346           0 :       mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
    1347             :     }
    1348           0 :     for (DocumentTimeline* timeline : mDocument->Timelines()) {
    1349           0 :       timeline->NotifyRefreshDriverDestroying(rd);
    1350             :     }
    1351             :   }
    1352             : 
    1353           0 :   if (mPresContext) {
    1354           0 :     rd->CancelPendingAnimationEvents(mPresContext->AnimationEventDispatcher());
    1355             :   }
    1356             : 
    1357             :   // Revoke any pending events.  We need to do this and cancel pending reflows
    1358             :   // before we destroy the frame manager, since apparently frame destruction
    1359             :   // sometimes spins the event queue when plug-ins are involved(!).
    1360           0 :   StopObservingRefreshDriver();
    1361             : 
    1362           0 :   if (rd->GetPresContext() == GetPresContext()) {
    1363             :     rd->RevokeViewManagerFlush();
    1364             :   }
    1365             : 
    1366           0 :   CancelAllPendingReflows();
    1367           0 :   CancelPostedReflowCallbacks();
    1368             : 
    1369             :   // Destroy the frame manager. This will destroy the frame hierarchy
    1370           0 :   mFrameConstructor->WillDestroyFrameTree();
    1371             : 
    1372           0 :   NS_WARNING_ASSERTION(!mAutoWeakFrames && mWeakFrames.IsEmpty(),
    1373             :                        "Weak frames alive after destroying FrameManager");
    1374           0 :   while (mAutoWeakFrames) {
    1375           0 :     mAutoWeakFrames->Clear(this);
    1376             :   }
    1377           0 :   nsTArray<WeakFrame*> toRemove(mWeakFrames.Count());
    1378           0 :   for (auto iter = mWeakFrames.Iter(); !iter.Done(); iter.Next()) {
    1379           0 :     toRemove.AppendElement(iter.Get()->GetKey());
    1380             :   }
    1381           0 :   for (WeakFrame* weakFrame : toRemove) {
    1382           0 :     weakFrame->Clear(this);
    1383             :   }
    1384             : 
    1385             :   // Let the style set do its cleanup.
    1386           0 :   mStyleSet->Shutdown();
    1387             : 
    1388           0 :   if (mPresContext) {
    1389             :     // We hold a reference to the pres context, and it holds a weak link back
    1390             :     // to us. To avoid the pres context having a dangling reference, set its
    1391             :     // pres shell to nullptr
    1392           0 :     mPresContext->DetachShell();
    1393             : 
    1394             :     // Clear the link handler (weak reference) as well
    1395           0 :     mPresContext->SetLinkHandler(nullptr);
    1396             :   }
    1397             : 
    1398           0 :   mHaveShutDown = true;
    1399             : 
    1400           0 :   mTouchManager.Destroy();
    1401             : }
    1402             : 
    1403             : void
    1404           0 : nsIPresShell::StopObservingRefreshDriver()
    1405             : {
    1406           0 :   nsRefreshDriver* rd = mPresContext->RefreshDriver();
    1407           0 :   if (mResizeEventPending) {
    1408             :     rd->RemoveResizeEventFlushObserver(this);
    1409             :   }
    1410           0 :   if (mObservingLayoutFlushes) {
    1411             :     rd->RemoveLayoutFlushObserver(this);
    1412             :   }
    1413           0 :   if (mObservingStyleFlushes) {
    1414             :     rd->RemoveStyleFlushObserver(this);
    1415             :   }
    1416           0 : }
    1417             : 
    1418             : void
    1419           0 : nsIPresShell::StartObservingRefreshDriver()
    1420             : {
    1421           0 :   nsRefreshDriver* rd = mPresContext->RefreshDriver();
    1422           0 :   if (mResizeEventPending) {
    1423           0 :     rd->AddResizeEventFlushObserver(this);
    1424             :   }
    1425           0 :   if (mObservingLayoutFlushes) {
    1426           0 :     rd->AddLayoutFlushObserver(this);
    1427             :   }
    1428           0 :   if (mObservingStyleFlushes) {
    1429           0 :     rd->AddStyleFlushObserver(this);
    1430             :   }
    1431           0 : }
    1432             : 
    1433             : nsRefreshDriver*
    1434           0 : nsIPresShell::GetRefreshDriver() const
    1435             : {
    1436           0 :   return mPresContext ? mPresContext->RefreshDriver() : nullptr;
    1437             : }
    1438             : 
    1439             : void
    1440           0 : nsIPresShell::SetAuthorStyleDisabled(bool aStyleDisabled)
    1441             : {
    1442           0 :   if (aStyleDisabled != mStyleSet->GetAuthorStyleDisabled()) {
    1443           0 :     mStyleSet->SetAuthorStyleDisabled(aStyleDisabled);
    1444           0 :     ApplicableStylesChanged();
    1445             : 
    1446             :     nsCOMPtr<nsIObserverService> observerService =
    1447           0 :       mozilla::services::GetObserverService();
    1448           0 :     if (observerService) {
    1449           0 :       observerService->NotifyObservers(mDocument,
    1450             :                                        "author-style-disabled-changed",
    1451           0 :                                        nullptr);
    1452             :     }
    1453             :   }
    1454           0 : }
    1455             : 
    1456             : bool
    1457           0 : nsIPresShell::GetAuthorStyleDisabled() const
    1458             : {
    1459           0 :   return mStyleSet->GetAuthorStyleDisabled();
    1460             : }
    1461             : 
    1462             : void
    1463           0 : PresShell::UpdatePreferenceStyles()
    1464             : {
    1465           0 :   if (!mDocument) {
    1466           0 :     return;
    1467             :   }
    1468             : 
    1469             :   // If the document doesn't have a window there's no need to notify
    1470             :   // its presshell about changes to preferences since the document is
    1471             :   // in a state where it doesn't matter any more (see
    1472             :   // nsDocumentViewer::Close()).
    1473           0 :   if (!mDocument->GetWindow()) {
    1474             :     return;
    1475             :   }
    1476             : 
    1477             :   // Documents in chrome shells do not have any preference style rules applied.
    1478           0 :   if (nsContentUtils::IsInChromeDocshell(mDocument)) {
    1479             :     return;
    1480             :   }
    1481             : 
    1482             :   // We need to pass in mPresContext so that if the nsLayoutStylesheetCache
    1483             :   // needs to recreate the pref style sheet, it has somewhere to get the
    1484             :   // pref styling information from.  All pres contexts for
    1485             :   // IsChromeOriginImage() == false will have the same pref styling information,
    1486             :   // and similarly for IsChromeOriginImage() == true, so it doesn't really
    1487             :   // matter which pres context we pass in when it does need to be recreated.
    1488             :   // (See nsPresContext::GetDocumentColorPreferences for how whether we
    1489             :   // are a chrome origin image affects some pref styling information.)
    1490           0 :   auto cache = nsLayoutStylesheetCache::Singleton();
    1491             :   RefPtr<StyleSheet> newPrefSheet =
    1492           0 :     mPresContext->IsChromeOriginImage() ?
    1493           0 :       cache->ChromePreferenceSheet(mPresContext) :
    1494           0 :       cache->ContentPreferenceSheet(mPresContext);
    1495             : 
    1496           0 :   if (mPrefStyleSheet == newPrefSheet) {
    1497           0 :     return;
    1498             :   }
    1499             : 
    1500           0 :   RemovePreferenceStyles();
    1501             : 
    1502             :   // NOTE(emilio): This sheet is added as an agent sheet, because we don't want
    1503             :   // it to be modifiable from devtools and similar, see bugs 1239336 and
    1504             :   // 1436782. I think it conceptually should be a user sheet, and could be
    1505             :   // without too much trouble I'd think.
    1506           0 :   mStyleSet->AppendStyleSheet(SheetType::Agent, newPrefSheet);
    1507           0 :   mPrefStyleSheet = newPrefSheet;
    1508             : }
    1509             : 
    1510             : void
    1511           0 : PresShell::RemovePreferenceStyles()
    1512             : {
    1513           0 :   if (mPrefStyleSheet) {
    1514           0 :     mStyleSet->RemoveStyleSheet(SheetType::Agent, mPrefStyleSheet);
    1515           0 :     mPrefStyleSheet = nullptr;
    1516             :   }
    1517           0 : }
    1518             : 
    1519             : void
    1520           0 : PresShell::AddUserSheet(StyleSheet* aSheet)
    1521             : {
    1522             :   // Make sure this does what nsDocumentViewer::CreateStyleSet does wrt
    1523             :   // ordering. We want this new sheet to come after all the existing stylesheet
    1524             :   // service sheets, but before other user sheets; see nsIStyleSheetService.idl
    1525             :   // for the ordering.  Just remove and readd all the nsStyleSheetService
    1526             :   // sheets.
    1527             :   nsCOMPtr<nsIStyleSheetService> dummy =
    1528           0 :     do_GetService(NS_STYLESHEETSERVICE_CONTRACTID);
    1529             : 
    1530           0 :   nsStyleSheetService* sheetService = nsStyleSheetService::gInstance;
    1531           0 :   nsTArray<RefPtr<StyleSheet>>& userSheets = *sheetService->UserStyleSheets();
    1532             :   // Iterate forwards when removing so the searches for RemoveStyleSheet are as
    1533             :   // short as possible.
    1534           0 :   for (StyleSheet* sheet : userSheets) {
    1535           0 :     mStyleSet->RemoveStyleSheet(SheetType::User, sheet);
    1536             :   }
    1537             : 
    1538             :   // Now iterate backwards, so that the order of userSheets will be the same as
    1539             :   // the order of sheets from it in the style set.
    1540           0 :   for (StyleSheet* sheet : Reversed(userSheets)) {
    1541           0 :     mStyleSet->PrependStyleSheet(SheetType::User, sheet);
    1542             :   }
    1543             : 
    1544           0 :   ApplicableStylesChanged();
    1545           0 : }
    1546             : 
    1547             : void
    1548           0 : PresShell::AddAgentSheet(StyleSheet* aSheet)
    1549             : {
    1550             :   // Make sure this does what nsDocumentViewer::CreateStyleSet does
    1551             :   // wrt ordering.
    1552           0 :   mStyleSet->AppendStyleSheet(SheetType::Agent, aSheet);
    1553           0 :   ApplicableStylesChanged();
    1554           0 : }
    1555             : 
    1556             : void
    1557           0 : PresShell::AddAuthorSheet(StyleSheet* aSheet)
    1558             : {
    1559             :   // Document specific "additional" Author sheets should be stronger than the
    1560             :   // ones added with the StyleSheetService.
    1561             :   StyleSheet* firstAuthorSheet =
    1562           0 :     mDocument->GetFirstAdditionalAuthorSheet();
    1563           0 :   if (firstAuthorSheet) {
    1564           0 :     mStyleSet->InsertStyleSheetBefore(SheetType::Doc, aSheet,
    1565           0 :                                       firstAuthorSheet);
    1566             :   } else {
    1567           0 :     mStyleSet->AppendStyleSheet(SheetType::Doc, aSheet);
    1568             :   }
    1569             : 
    1570           0 :   ApplicableStylesChanged();
    1571           0 : }
    1572             : 
    1573             : void
    1574           0 : PresShell::RemoveSheet(SheetType aType, StyleSheet* aSheet)
    1575             : {
    1576           0 :   mStyleSet->RemoveStyleSheet(aType, aSheet);
    1577           0 :   ApplicableStylesChanged();
    1578           0 : }
    1579             : 
    1580             : NS_IMETHODIMP
    1581           0 : PresShell::SetDisplaySelection(int16_t aToggle)
    1582             : {
    1583           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1584           0 :   frameSelection->SetDisplaySelection(aToggle);
    1585           0 :   return NS_OK;
    1586             : }
    1587             : 
    1588             : NS_IMETHODIMP
    1589           0 : PresShell::GetDisplaySelection(int16_t *aToggle)
    1590             : {
    1591           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1592           0 :   *aToggle = frameSelection->GetDisplaySelection();
    1593           0 :   return NS_OK;
    1594             : }
    1595             : 
    1596             : NS_IMETHODIMP
    1597           0 : PresShell::GetSelectionFromScript(RawSelectionType aRawSelectionType,
    1598             :                                   Selection **aSelection)
    1599             : {
    1600           0 :   if (!aSelection || !mSelection)
    1601             :     return NS_ERROR_NULL_POINTER;
    1602             : 
    1603           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1604             :   RefPtr<Selection> selection =
    1605           0 :     frameSelection->GetSelection(ToSelectionType(aRawSelectionType));
    1606             : 
    1607           0 :   if (!selection) {
    1608             :     return NS_ERROR_INVALID_ARG;
    1609             :   }
    1610             : 
    1611           0 :   selection.forget(aSelection);
    1612           0 :   return NS_OK;
    1613             : }
    1614             : 
    1615             : Selection*
    1616           0 : PresShell::GetSelection(RawSelectionType aRawSelectionType)
    1617             : {
    1618           0 :   if (!mSelection) {
    1619             :     return nullptr;
    1620             :   }
    1621             : 
    1622           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1623           0 :   return frameSelection->GetSelection(ToSelectionType(aRawSelectionType));
    1624             : }
    1625             : 
    1626             : Selection*
    1627           0 : PresShell::GetCurrentSelection(SelectionType aSelectionType)
    1628             : {
    1629           0 :   if (!mSelection)
    1630             :     return nullptr;
    1631             : 
    1632           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1633           0 :   return frameSelection->GetSelection(aSelectionType);
    1634             : }
    1635             : 
    1636             : already_AddRefed<nsISelectionController>
    1637           0 : PresShell::GetSelectionControllerForFocusedContent(nsIContent** aFocusedContent)
    1638             : {
    1639           0 :   if (aFocusedContent) {
    1640           0 :     *aFocusedContent = nullptr;
    1641             :   }
    1642             : 
    1643           0 :   if (mDocument) {
    1644           0 :     nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    1645             :     nsCOMPtr<nsIContent> focusedContent =
    1646           0 :       nsFocusManager::GetFocusedDescendant(mDocument->GetWindow(),
    1647             :                                            nsFocusManager::eOnlyCurrentWindow,
    1648           0 :                                            getter_AddRefs(focusedWindow));
    1649           0 :     if (focusedContent) {
    1650           0 :       nsIFrame* frame = focusedContent->GetPrimaryFrame();
    1651           0 :       if (frame) {
    1652           0 :         nsCOMPtr<nsISelectionController> selectionController;
    1653           0 :         frame->GetSelectionController(mPresContext,
    1654           0 :                                       getter_AddRefs(selectionController));
    1655           0 :         if (selectionController) {
    1656           0 :           if (aFocusedContent) {
    1657           0 :             focusedContent.forget(aFocusedContent);
    1658             :           }
    1659           0 :           return selectionController.forget();
    1660             :         }
    1661             :       }
    1662             :     }
    1663             :   }
    1664           0 :   nsCOMPtr<nsISelectionController> self(this);
    1665           0 :   return self.forget();
    1666             : }
    1667             : 
    1668             : NS_IMETHODIMP
    1669           0 : PresShell::ScrollSelectionIntoView(RawSelectionType aRawSelectionType,
    1670             :                                    SelectionRegion aRegion,
    1671             :                                    int16_t aFlags)
    1672             : {
    1673           0 :   if (!mSelection)
    1674             :     return NS_ERROR_NULL_POINTER;
    1675             : 
    1676           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1677           0 :   return frameSelection->ScrollSelectionIntoView(
    1678           0 :                            ToSelectionType(aRawSelectionType), aRegion, aFlags);
    1679             : }
    1680             : 
    1681             : NS_IMETHODIMP
    1682           0 : PresShell::RepaintSelection(RawSelectionType aRawSelectionType)
    1683             : {
    1684           0 :   if (!mSelection)
    1685             :     return NS_ERROR_NULL_POINTER;
    1686             : 
    1687           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    1688           0 :   return frameSelection->RepaintSelection(ToSelectionType(aRawSelectionType));
    1689             : }
    1690             : 
    1691             : // Make shell be a document observer
    1692             : void
    1693           0 : nsIPresShell::BeginObservingDocument()
    1694             : {
    1695           0 :   if (mDocument && !mIsDestroying) {
    1696           0 :     mIsObservingDocument = true;
    1697           0 :     if (mIsDocumentGone) {
    1698             :       NS_WARNING("Adding a presshell that was disconnected from the document "
    1699           0 :                  "as a document observer?  Sounds wrong...");
    1700           0 :       mIsDocumentGone = false;
    1701             :     }
    1702             :   }
    1703           0 : }
    1704             : 
    1705             : // Make shell stop being a document observer
    1706             : void
    1707           0 : nsIPresShell::EndObservingDocument()
    1708             : {
    1709             :   // XXXbz do we need to tell the frame constructor that the document
    1710             :   // is gone, perhaps?  Except for printing it's NOT gone, sometimes.
    1711           0 :   mIsDocumentGone = true;
    1712           0 :   mIsObservingDocument = false;
    1713           0 : }
    1714             : 
    1715             : #ifdef DEBUG_kipp
    1716             : char* nsPresShell_ReflowStackPointerTop;
    1717             : #endif
    1718             : 
    1719           0 : class XBLConstructorRunner : public Runnable
    1720             : {
    1721             : public:
    1722           0 :   explicit XBLConstructorRunner(nsIDocument* aDocument)
    1723           0 :     : Runnable("XBLConstructorRunner")
    1724           0 :     , mDocument(aDocument)
    1725             :   {
    1726           0 :   }
    1727             : 
    1728           0 :   NS_IMETHOD Run() override
    1729             :   {
    1730           0 :     mDocument->BindingManager()->ProcessAttachedQueue();
    1731           0 :     return NS_OK;
    1732             :   }
    1733             : 
    1734             : private:
    1735             :   nsCOMPtr<nsIDocument> mDocument;
    1736             : };
    1737             : 
    1738             : nsresult
    1739           0 : PresShell::Initialize()
    1740             : {
    1741           0 :   if (mIsDestroying) {
    1742             :     return NS_OK;
    1743             :   }
    1744             : 
    1745           0 :   if (!mDocument) {
    1746             :     // Nothing to do
    1747             :     return NS_OK;
    1748             :   }
    1749             : 
    1750           0 :   MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::Initialize this=%p", this));
    1751             : 
    1752           0 :   NS_ASSERTION(!mDidInitialize, "Why are we being called?");
    1753             : 
    1754           0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
    1755             : 
    1756           0 :   RecomputeFontSizeInflationEnabled();
    1757           0 :   MOZ_DIAGNOSTIC_ASSERT(!mIsDestroying);
    1758             : 
    1759             :   // Ensure the pres context doesn't think it has changed, since we haven't even
    1760             :   // started layout. This avoids spurious restyles / reflows afterwards.
    1761             :   //
    1762             :   // Note that this is very intentionally before setting mDidInitialize so it
    1763             :   // doesn't notify the document, or run media query change events.
    1764           0 :   mPresContext->FlushPendingMediaFeatureValuesChanged();
    1765           0 :   MOZ_DIAGNOSTIC_ASSERT(!mIsDestroying);
    1766             : 
    1767           0 :   mDidInitialize = true;
    1768             : 
    1769             : #ifdef DEBUG
    1770           0 :   if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
    1771           0 :     if (mDocument) {
    1772           0 :       nsIURI *uri = mDocument->GetDocumentURI();
    1773           0 :       if (uri) {
    1774           0 :         printf("*** PresShell::Initialize (this=%p, url='%s')\n",
    1775           0 :                (void*)this, uri->GetSpecOrDefault().get());
    1776             :       }
    1777             :     }
    1778             :   }
    1779             : #endif
    1780             : 
    1781             :   // Get the root frame from the frame manager
    1782             :   // XXXbz it would be nice to move this somewhere else... like frame manager
    1783             :   // Init(), say.  But we need to make sure our views are all set up by the
    1784             :   // time we do this!
    1785           0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    1786           0 :   NS_ASSERTION(!rootFrame, "How did that happen, exactly?");
    1787             : 
    1788           0 :   if (!rootFrame) {
    1789           0 :     nsAutoScriptBlocker scriptBlocker;
    1790           0 :     rootFrame = mFrameConstructor->ConstructRootFrame();
    1791           0 :     mFrameConstructor->SetRootFrame(rootFrame);
    1792             :   }
    1793             : 
    1794           0 :   NS_ENSURE_STATE(!mHaveShutDown);
    1795             : 
    1796           0 :   if (!rootFrame) {
    1797             :     return NS_ERROR_OUT_OF_MEMORY;
    1798             :   }
    1799             : 
    1800           0 :   if (Element* root = mDocument->GetRootElement()) {
    1801             :     {
    1802           0 :       nsAutoCauseReflowNotifier reflowNotifier(this);
    1803             :       // Have the style sheet processor construct frame for the root
    1804             :       // content object down
    1805           0 :       mFrameConstructor->ContentInserted(
    1806           0 :           root, nullptr, nsCSSFrameConstructor::InsertionKind::Sync);
    1807             : 
    1808             :       // Something in mFrameConstructor->ContentInserted may have caused
    1809             :       // Destroy() to get called, bug 337586.
    1810           0 :       NS_ENSURE_STATE(!mHaveShutDown);
    1811             :     }
    1812             : 
    1813             :     // nsAutoCauseReflowNotifier (which sets up a script blocker) going out of
    1814             :     // scope may have killed us too
    1815           0 :     NS_ENSURE_STATE(!mHaveShutDown);
    1816             : 
    1817             :     // Run the XBL binding constructors for any new frames we've constructed.
    1818             :     // (Do this in a script runner, since our caller might have a script
    1819             :     // blocker on the stack.)
    1820           0 :     nsContentUtils::AddScriptRunner(new XBLConstructorRunner(mDocument));
    1821             : 
    1822             :     // XBLConstructorRunner might destroy us.
    1823           0 :     NS_ENSURE_STATE(!mHaveShutDown);
    1824             :   }
    1825             : 
    1826           0 :   mDocument->TriggerAutoFocus();
    1827             : 
    1828             :   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           0 :   if (MOZ_LIKELY(rootFrame->GetStateBits() & NS_FRAME_IS_DIRTY)) {
    1833             :     // Unset the DIRTY bits so that FrameNeedsReflow() will work right.
    1834           0 :     rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY |
    1835           0 :                                NS_FRAME_HAS_DIRTY_CHILDREN);
    1836           0 :     NS_ASSERTION(!mDirtyRoots.Contains(rootFrame),
    1837             :                  "Why is the root in mDirtyRoots already?");
    1838           0 :     FrameNeedsReflow(rootFrame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
    1839           0 :     NS_ASSERTION(mDirtyRoots.Contains(rootFrame),
    1840             :                  "Should be in mDirtyRoots now");
    1841           0 :     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           0 :   if (!mDocumentLoading) {
    1849           0 :     RestoreRootScrollPosition();
    1850             :   }
    1851             : 
    1852             :   // For printing, we just immediately unsuppress.
    1853           0 :   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           0 :     mPaintingSuppressed = true;
    1858             :     // Don't suppress painting if the document isn't loading.
    1859           0 :     nsIDocument::ReadyState readyState = mDocument->GetReadyStateEnum();
    1860           0 :     if (readyState != nsIDocument::READYSTATE_COMPLETE) {
    1861           0 :       mPaintSuppressionTimer = NS_NewTimer();
    1862             :     }
    1863           0 :     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           0 :                             PAINTLOCK_EVENT_DELAY);
    1872             : 
    1873           0 :       mPaintSuppressionTimer->SetTarget(
    1874           0 :           mDocument->EventTargetFor(TaskCategory::Other));
    1875           0 :       mPaintSuppressionTimer->InitWithNamedFuncCallback(
    1876             :         sPaintSuppressionCallback, this, delay, nsITimer::TYPE_ONE_SHOT,
    1877           0 :         "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           0 :   if (!mPaintingSuppressed) {
    1884           0 :     ScheduleBeforeFirstPaint();
    1885             :   }
    1886             : 
    1887             :   return NS_OK; //XXX this needs to be real. MMP
    1888             : }
    1889             : 
    1890             : void
    1891           0 : PresShell::sPaintSuppressionCallback(nsITimer *aTimer, void* aPresShell)
    1892             : {
    1893           0 :   RefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
    1894           0 :   if (self)
    1895           0 :     self->UnsuppressPainting();
    1896           0 : }
    1897             : 
    1898             : nsresult
    1899           0 : PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth,
    1900             :                         nscoord aOldHeight, ResizeReflowOptions aOptions)
    1901             : {
    1902           0 :   if (mZoomConstraintsClient) {
    1903             :     // If we have a ZoomConstraintsClient and the available screen area
    1904             :     // changed, then we might need to disable double-tap-to-zoom, so notify
    1905             :     // the ZCC to update itself.
    1906           0 :     mZoomConstraintsClient->ScreenSizeChanged();
    1907             :   }
    1908           0 :   if (mMobileViewportManager) {
    1909             :     // If we have a mobile viewport manager, request a reflow from it. It can
    1910             :     // recompute the final CSS viewport and trigger a call to
    1911             :     // ResizeReflowIgnoreOverride if it changed.
    1912           0 :     mMobileViewportManager->RequestReflow();
    1913           0 :     return NS_OK;
    1914             :   }
    1915             : 
    1916             :   return ResizeReflowIgnoreOverride(aWidth, aHeight, aOldWidth,
    1917           0 :                                     aOldHeight, aOptions);
    1918             : }
    1919             : 
    1920             : nsresult
    1921           0 : PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight,
    1922             :                                       nscoord aOldWidth, nscoord aOldHeight,
    1923             :                                       ResizeReflowOptions aOptions)
    1924             : {
    1925           0 :   MOZ_ASSERT(!mIsReflowing, "Shouldn't be in reflow here!");
    1926             : 
    1927           0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    1928           0 :   if (!rootFrame) {
    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           0 :     if (aHeight == NS_UNCONSTRAINEDSIZE || aWidth == NS_UNCONSTRAINEDSIZE) {
    1933             :       // We can't do the work needed for SizeToContent without a root
    1934             :       // frame, and we want to return before setting the visible area.
    1935             :       return NS_ERROR_NOT_AVAILABLE;
    1936             :     }
    1937             : 
    1938           0 :     mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
    1939             :     // There isn't anything useful we can do if the initial reflow hasn't
    1940             :     // happened.
    1941           0 :     return NS_OK;
    1942             :   }
    1943             : 
    1944           0 :   WritingMode wm = rootFrame->GetWritingMode();
    1945           0 :   const bool shrinkToFit = aOptions == ResizeReflowOptions::eBSizeLimit;
    1946           0 :   MOZ_ASSERT(shrinkToFit ||
    1947             :              (wm.IsVertical() ? aWidth : aHeight) != NS_UNCONSTRAINEDSIZE,
    1948             :              "unconstrained bsize only usable with eBSizeLimit");
    1949           0 :   MOZ_ASSERT((wm.IsVertical() ? aHeight : aWidth) != NS_UNCONSTRAINEDSIZE,
    1950             :              "unconstrained isize not allowed");
    1951           0 :   bool isBSizeChanging = wm.IsVertical() ? aOldWidth != aWidth
    1952           0 :                                          : aOldHeight != aHeight;
    1953           0 :   nscoord targetWidth = aWidth;
    1954           0 :   nscoord targetHeight = aHeight;
    1955             : 
    1956           0 :   if (shrinkToFit) {
    1957           0 :     if (wm.IsVertical()) {
    1958             :       targetWidth = NS_UNCONSTRAINEDSIZE;
    1959             :     } else {
    1960           0 :       targetHeight = NS_UNCONSTRAINEDSIZE;
    1961             :     }
    1962             :     isBSizeChanging = true;
    1963             :   }
    1964             : 
    1965             :   const bool suppressingResizeReflow =
    1966           0 :     GetPresContext()->SuppressingResizeReflow();
    1967             : 
    1968           0 :   RefPtr<nsViewManager> viewManager = mViewManager;
    1969           0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
    1970             : 
    1971           0 :   if (!suppressingResizeReflow && shrinkToFit) {
    1972             :     // Make sure that style is flushed before setting the pres context
    1973             :     // VisibleArea if we're shrinking to fit.
    1974             :     //
    1975             :     // Otherwise we may end up with bogus viewport units resolved against the
    1976             :     // unconstrained bsize, or restyling the whole document resolving viewport
    1977             :     // units against targetWidth, which may end up doing wasteful work.
    1978           0 :     mDocument->FlushPendingNotifications(FlushType::Frames);
    1979             :   }
    1980             : 
    1981           0 :   if (!mIsDestroying) {
    1982           0 :     mPresContext->SetVisibleArea(nsRect(0, 0, targetWidth, targetHeight));
    1983             :   }
    1984             : 
    1985           0 :   if (!mIsDestroying && !suppressingResizeReflow) {
    1986           0 :     if (!shrinkToFit) {
    1987             :       // Flush styles _now_ (with the correct visible area) if not computing the
    1988             :       // shrink-to-fit size.
    1989             :       //
    1990             :       // We've asserted above that sizes are not unconstrained, so this is going
    1991             :       // to be the final size, which means that we'll get the (correct) final
    1992             :       // styles now, and avoid a further potentially-wasteful full recascade on
    1993             :       // the next flush.
    1994           0 :       mDocument->FlushPendingNotifications(FlushType::Frames);
    1995             :     }
    1996             : 
    1997           0 :     rootFrame = mFrameConstructor->GetRootFrame();
    1998           0 :     if (!mIsDestroying && rootFrame) {
    1999             :       // XXX Do a full invalidate at the beginning so that invalidates along
    2000             :       // the way don't have region accumulation issues?
    2001             : 
    2002           0 :       if (isBSizeChanging) {
    2003             :         // For BSize changes driven by style, RestyleManager handles this.
    2004             :         // For height:auto BSizes (i.e. layout-controlled), descendant
    2005             :         // intrinsic sizes can't depend on them. So the only other case is
    2006             :         // viewport-controlled BSizes which we handle here.
    2007           0 :         nsLayoutUtils::MarkIntrinsicISizesDirtyIfDependentOnBSize(rootFrame);
    2008             :       }
    2009             : 
    2010             :       {
    2011           0 :         nsAutoCauseReflowNotifier crNotifier(this);
    2012           0 :         WillDoReflow();
    2013             : 
    2014             :         // Kick off a top-down reflow
    2015           0 :         AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
    2016           0 :         nsViewManager::AutoDisableRefresh refreshBlocker(viewManager);
    2017             : 
    2018           0 :         mDirtyRoots.RemoveElement(rootFrame);
    2019           0 :         DoReflow(rootFrame, true);
    2020             : 
    2021           0 :         if (shrinkToFit) {
    2022           0 :           const bool reflowAgain = wm.IsVertical() ?
    2023           0 :                                 mPresContext->GetVisibleArea().width > aWidth :
    2024           0 :                                 mPresContext->GetVisibleArea().height > aHeight;
    2025             : 
    2026           0 :           if (reflowAgain) {
    2027           0 :             mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
    2028           0 :             DoReflow(rootFrame, true);
    2029             :           }
    2030             :         }
    2031             :       }
    2032             : 
    2033             :       // the first DoReflow above should've set our bsize if it was
    2034             :       // NS_UNCONSTRAINEDSIZE, and the isize shouldn't be NS_UNCONSTRAINEDSIZE
    2035             :       // anyway
    2036           0 :       NS_ASSERTION(
    2037             :         mPresContext->GetVisibleArea().width != NS_UNCONSTRAINEDSIZE,
    2038             :         "width should not be NS_UNCONSTRAINEDSIZE after reflow");
    2039           0 :       NS_ASSERTION(
    2040             :         mPresContext->GetVisibleArea().height != NS_UNCONSTRAINEDSIZE,
    2041             :         "height should not be NS_UNCONSTRAINEDSIZE after reflow");
    2042             : 
    2043           0 :       DidDoReflow(true);
    2044             :     }
    2045             :   }
    2046             : 
    2047           0 :   rootFrame = mFrameConstructor->GetRootFrame();
    2048           0 :   if (rootFrame) {
    2049           0 :     wm = rootFrame->GetWritingMode();
    2050             :     // reflow did not happen; if the reflow happened, our bsize should not be
    2051             :     // NS_UNCONSTRAINEDSIZE because DoReflow will fix it up to the same values
    2052             :     // as below
    2053           0 :     if (wm.IsVertical()) {
    2054           0 :       if (mPresContext->GetVisibleArea().width == NS_UNCONSTRAINEDSIZE) {
    2055           0 :         mPresContext->SetVisibleArea(
    2056           0 :           nsRect(0, 0, rootFrame->GetRect().width, aHeight));
    2057             :       }
    2058             :     } else {
    2059           0 :       if (mPresContext->GetVisibleArea().height == NS_UNCONSTRAINEDSIZE) {
    2060           0 :         mPresContext->SetVisibleArea(
    2061           0 :           nsRect(0, 0, aWidth, rootFrame->GetRect().height));
    2062             :       }
    2063             :     }
    2064             :   }
    2065             : 
    2066           0 :   if (!mIsDestroying && !mResizeEventPending) {
    2067           0 :     mResizeEventPending = true;
    2068           0 :     if (MOZ_LIKELY(!mDocument->GetBFCacheEntry())) {
    2069           0 :       mPresContext->RefreshDriver()->AddResizeEventFlushObserver(this);
    2070             :     }
    2071             :   }
    2072             : 
    2073             :   return NS_OK; //XXX this needs to be real. MMP
    2074             : }
    2075             : 
    2076             : void
    2077           0 : PresShell::FireResizeEvent()
    2078             : {
    2079           0 :   if (mIsDocumentGone) {
    2080           0 :     return;
    2081             :   }
    2082             : 
    2083           0 :   mResizeEventPending = false;
    2084             : 
    2085             :   //Send resize event from here.
    2086           0 :   WidgetEvent event(true, mozilla::eResize);
    2087           0 :   nsEventStatus status = nsEventStatus_eIgnore;
    2088             : 
    2089           0 :   if (nsPIDOMWindowOuter* window = mDocument->GetWindow()) {
    2090           0 :     EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
    2091             :   }
    2092             : }
    2093             : 
    2094             : void
    2095           0 : PresShell::SetIgnoreFrameDestruction(bool aIgnore)
    2096             : {
    2097           0 :   if (mDocument) {
    2098             :     // We need to tell the ImageLoader to drop all its references to frames
    2099             :     // because they're about to go away and it won't get notifications of that.
    2100           0 :     mDocument->StyleImageLoader()->ClearFrames(mPresContext);
    2101             :   }
    2102           0 :   mIgnoreFrameDestruction = aIgnore;
    2103           0 : }
    2104             : 
    2105             : void
    2106           0 : PresShell::NotifyDestroyingFrame(nsIFrame* aFrame)
    2107             : {
    2108             :   // We must remove these from FrameLayerBuilder::DisplayItemData::mFrameList here,
    2109             :   // otherwise the DisplayItemData destructor will use the destroyed frame when it
    2110             :   // tries to remove it from the (array) value of this property.
    2111           0 :   aFrame->RemoveDisplayItemDataForDeletion();
    2112             : 
    2113           0 :   if (!mIgnoreFrameDestruction) {
    2114           0 :     if (aFrame->HasImageRequest()) {
    2115           0 :       mDocument->StyleImageLoader()->DropRequestsForFrame(aFrame);
    2116             :     }
    2117             : 
    2118           0 :     mFrameConstructor->NotifyDestroyingFrame(aFrame);
    2119             : 
    2120           0 :     for (int32_t idx = mDirtyRoots.Length(); idx; ) {
    2121           0 :       --idx;
    2122           0 :       if (mDirtyRoots[idx] == aFrame) {
    2123           0 :         mDirtyRoots.RemoveElementAt(idx);
    2124             :       }
    2125             :     }
    2126             : 
    2127             :     // Remove frame properties
    2128           0 :     aFrame->DeleteAllProperties();
    2129             : 
    2130           0 :     if (aFrame == mCurrentEventFrame) {
    2131           0 :       mCurrentEventContent = aFrame->GetContent();
    2132           0 :       mCurrentEventFrame = nullptr;
    2133             :     }
    2134             : 
    2135             :   #ifdef DEBUG
    2136           0 :     if (aFrame == mDrawEventTargetFrame) {
    2137           0 :       mDrawEventTargetFrame = nullptr;
    2138             :     }
    2139             :   #endif
    2140             : 
    2141           0 :     for (unsigned int i=0; i < mCurrentEventFrameStack.Length(); i++) {
    2142           0 :       if (aFrame == mCurrentEventFrameStack.ElementAt(i)) {
    2143             :         //One of our stack frames was deleted.  Get its content so that when we
    2144             :         //pop it we can still get its new frame from its content
    2145           0 :         nsIContent *currentEventContent = aFrame->GetContent();
    2146           0 :         mCurrentEventContentStack.ReplaceObjectAt(currentEventContent, i);
    2147           0 :         mCurrentEventFrameStack[i] = nullptr;
    2148             :       }
    2149             :     }
    2150             : 
    2151           0 :     mFramesToDirty.RemoveEntry(aFrame);
    2152             :   }
    2153           0 : }
    2154             : 
    2155           0 : already_AddRefed<nsCaret> PresShell::GetCaret() const
    2156             : {
    2157           0 :   RefPtr<nsCaret> caret = mCaret;
    2158           0 :   return caret.forget();
    2159             : }
    2160             : 
    2161           0 : already_AddRefed<AccessibleCaretEventHub> PresShell::GetAccessibleCaretEventHub() const
    2162             : {
    2163           0 :   RefPtr<AccessibleCaretEventHub> eventHub = mAccessibleCaretEventHub;
    2164           0 :   return eventHub.forget();
    2165             : }
    2166             : 
    2167           0 : void PresShell::SetCaret(nsCaret *aNewCaret)
    2168             : {
    2169           0 :   mCaret = aNewCaret;
    2170           0 : }
    2171             : 
    2172           0 : void PresShell::RestoreCaret()
    2173             : {
    2174           0 :   mCaret = mOriginalCaret;
    2175           0 : }
    2176             : 
    2177           0 : NS_IMETHODIMP PresShell::SetCaretEnabled(bool aInEnable)
    2178             : {
    2179           0 :   bool oldEnabled = mCaretEnabled;
    2180             : 
    2181           0 :   mCaretEnabled = aInEnable;
    2182             : 
    2183           0 :   if (mCaretEnabled != oldEnabled)
    2184             :   {
    2185           0 :     MOZ_ASSERT(mCaret);
    2186           0 :     if (mCaret) {
    2187           0 :       mCaret->SetVisible(mCaretEnabled);
    2188             :     }
    2189             :   }
    2190             : 
    2191           0 :   return NS_OK;
    2192             : }
    2193             : 
    2194           0 : NS_IMETHODIMP PresShell::SetCaretReadOnly(bool aReadOnly)
    2195             : {
    2196           0 :   if (mCaret)
    2197           0 :     mCaret->SetCaretReadOnly(aReadOnly);
    2198           0 :   return NS_OK;
    2199             : }
    2200             : 
    2201           0 : NS_IMETHODIMP PresShell::GetCaretEnabled(bool *aOutEnabled)
    2202             : {
    2203           0 :   NS_ENSURE_ARG_POINTER(aOutEnabled);
    2204           0 :   *aOutEnabled = mCaretEnabled;
    2205           0 :   return NS_OK;
    2206             : }
    2207             : 
    2208           0 : NS_IMETHODIMP PresShell::SetCaretVisibilityDuringSelection(bool aVisibility)
    2209             : {
    2210           0 :   if (mCaret)
    2211           0 :     mCaret->SetVisibilityDuringSelection(aVisibility);
    2212           0 :   return NS_OK;
    2213             : }
    2214             : 
    2215           0 : NS_IMETHODIMP PresShell::GetCaretVisible(bool *aOutIsVisible)
    2216             : {
    2217           0 :   *aOutIsVisible = false;
    2218           0 :   if (mCaret) {
    2219           0 :     *aOutIsVisible = mCaret->IsVisible();
    2220             :   }
    2221           0 :   return NS_OK;
    2222             : }
    2223             : 
    2224           0 : NS_IMETHODIMP PresShell::SetSelectionFlags(int16_t aInEnable)
    2225             : {
    2226           0 :   mSelectionFlags = aInEnable;
    2227           0 :   return NS_OK;
    2228             : }
    2229             : 
    2230           0 : NS_IMETHODIMP PresShell::GetSelectionFlags(int16_t *aOutEnable)
    2231             : {
    2232           0 :   if (!aOutEnable)
    2233             :     return NS_ERROR_INVALID_ARG;
    2234           0 :   *aOutEnable = mSelectionFlags;
    2235           0 :   return NS_OK;
    2236             : }
    2237             : 
    2238             : //implementation of nsISelectionController
    2239             : 
    2240             : NS_IMETHODIMP
    2241           0 : PresShell::PhysicalMove(int16_t aDirection, int16_t aAmount, bool aExtend)
    2242             : {
    2243           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2244           0 :   return frameSelection->PhysicalMove(aDirection, aAmount, aExtend);
    2245             : }
    2246             : 
    2247             : NS_IMETHODIMP
    2248           0 : PresShell::CharacterMove(bool aForward, bool aExtend)
    2249             : {
    2250           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2251           0 :   return frameSelection->CharacterMove(aForward, aExtend);
    2252             : }
    2253             : 
    2254             : NS_IMETHODIMP
    2255           0 : PresShell::CharacterExtendForDelete()
    2256             : {
    2257           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2258           0 :   return frameSelection->CharacterExtendForDelete();
    2259             : }
    2260             : 
    2261             : NS_IMETHODIMP
    2262           0 : PresShell::CharacterExtendForBackspace()
    2263             : {
    2264           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2265           0 :   return frameSelection->CharacterExtendForBackspace();
    2266             : }
    2267             : 
    2268             : NS_IMETHODIMP
    2269           0 : PresShell::WordMove(bool aForward, bool aExtend)
    2270             : {
    2271           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2272           0 :   nsresult result = frameSelection->WordMove(aForward, aExtend);
    2273             : // if we can't go down/up any more we must then move caret completely to
    2274             : // end/beginning respectively.
    2275           0 :   if (NS_FAILED(result))
    2276           0 :     result = CompleteMove(aForward, aExtend);
    2277           0 :   return result;
    2278             : }
    2279             : 
    2280             : NS_IMETHODIMP
    2281           0 : PresShell::WordExtendForDelete(bool aForward)
    2282             : {
    2283           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2284           0 :   return frameSelection->WordExtendForDelete(aForward);
    2285             : }
    2286             : 
    2287             : NS_IMETHODIMP
    2288           0 : PresShell::LineMove(bool aForward, bool aExtend)
    2289             : {
    2290           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2291           0 :   nsresult result = frameSelection->LineMove(aForward, aExtend);
    2292             : // if we can't go down/up any more we must then move caret completely to
    2293             : // end/beginning respectively.
    2294           0 :   if (NS_FAILED(result))
    2295           0 :     result = CompleteMove(aForward,aExtend);
    2296           0 :   return result;
    2297             : }
    2298             : 
    2299             : NS_IMETHODIMP
    2300           0 : PresShell::IntraLineMove(bool aForward, bool aExtend)
    2301             : {
    2302           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2303           0 :   return frameSelection->IntraLineMove(aForward, aExtend);
    2304             : }
    2305             : 
    2306             : 
    2307             : 
    2308             : NS_IMETHODIMP
    2309           0 : PresShell::PageMove(bool aForward, bool aExtend)
    2310             : {
    2311             :   nsIScrollableFrame *scrollableFrame =
    2312           0 :     GetScrollableFrameToScroll(nsIPresShell::eVertical);
    2313           0 :   if (!scrollableFrame)
    2314             :     return NS_OK;
    2315             : 
    2316           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2317           0 :   frameSelection->CommonPageMove(aForward, aExtend, scrollableFrame);
    2318             :   // After ScrollSelectionIntoView(), the pending notifications might be
    2319             :   // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
    2320             :   return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
    2321             :                                  nsISelectionController::SELECTION_FOCUS_REGION,
    2322             :                                  nsISelectionController::SCROLL_SYNCHRONOUS |
    2323           0 :                                  nsISelectionController::SCROLL_FOR_CARET_MOVE);
    2324             : }
    2325             : 
    2326             : 
    2327             : 
    2328             : NS_IMETHODIMP
    2329           0 : PresShell::ScrollPage(bool aForward)
    2330             : {
    2331             :   nsIScrollableFrame* scrollFrame =
    2332           0 :     GetScrollableFrameToScroll(nsIPresShell::eVertical);
    2333           0 :   if (scrollFrame) {
    2334           0 :     scrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
    2335             :                           nsIScrollableFrame::PAGES,
    2336             :                           nsIScrollableFrame::SMOOTH,
    2337             :                           nullptr, nullptr,
    2338             :                           nsIScrollableFrame::NOT_MOMENTUM,
    2339           0 :                           nsIScrollableFrame::ENABLE_SNAP);
    2340             :   }
    2341           0 :   return NS_OK;
    2342             : }
    2343             : 
    2344             : NS_IMETHODIMP
    2345           0 : PresShell::ScrollLine(bool aForward)
    2346             : {
    2347             :   nsIScrollableFrame* scrollFrame =
    2348           0 :     GetScrollableFrameToScroll(nsIPresShell::eVertical);
    2349           0 :   if (scrollFrame) {
    2350             :     int32_t lineCount = Preferences::GetInt("toolkit.scrollbox.verticalScrollDistance",
    2351           0 :                                             NS_DEFAULT_VERTICAL_SCROLL_DISTANCE);
    2352           0 :     scrollFrame->ScrollBy(nsIntPoint(0, aForward ? lineCount : -lineCount),
    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::ScrollCharacter(bool aRight)
    2364             : {
    2365             :   nsIScrollableFrame* scrollFrame =
    2366           0 :     GetScrollableFrameToScroll(nsIPresShell::eHorizontal);
    2367           0 :   if (scrollFrame) {
    2368             :     int32_t h = Preferences::GetInt("toolkit.scrollbox.horizontalScrollDistance",
    2369           0 :                                     NS_DEFAULT_HORIZONTAL_SCROLL_DISTANCE);
    2370           0 :     scrollFrame->ScrollBy(nsIntPoint(aRight ? h : -h, 0),
    2371             :                           nsIScrollableFrame::LINES,
    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::CompleteScroll(bool aForward)
    2382             : {
    2383             :   nsIScrollableFrame* scrollFrame =
    2384           0 :     GetScrollableFrameToScroll(nsIPresShell::eVertical);
    2385           0 :   if (scrollFrame) {
    2386           0 :     scrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1),
    2387             :                           nsIScrollableFrame::WHOLE,
    2388             :                           nsIScrollableFrame::SMOOTH,
    2389             :                           nullptr, nullptr,
    2390             :                           nsIScrollableFrame::NOT_MOMENTUM,
    2391           0 :                           nsIScrollableFrame::ENABLE_SNAP);
    2392             :   }
    2393           0 :   return NS_OK;
    2394             : }
    2395             : 
    2396             : NS_IMETHODIMP
    2397           0 : PresShell::CompleteMove(bool aForward, bool aExtend)
    2398             : {
    2399             :   // Beware! This may flush notifications via synchronous
    2400             :   // ScrollSelectionIntoView.
    2401           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2402           0 :   nsIContent* limiter = frameSelection->GetAncestorLimiter();
    2403           0 :   nsIFrame* frame = limiter ? limiter->GetPrimaryFrame()
    2404           0 :                             : FrameConstructor()->GetRootElementFrame();
    2405           0 :   if (!frame)
    2406             :     return NS_ERROR_FAILURE;
    2407             :   nsIFrame::CaretPosition pos =
    2408           0 :     frame->GetExtremeCaretPosition(!aForward);
    2409           0 :   frameSelection->HandleClick(pos.mResultContent, pos.mContentOffset,
    2410           0 :                               pos.mContentOffset, aExtend, false,
    2411             :                               aForward ? CARET_ASSOCIATE_AFTER :
    2412           0 :                                          CARET_ASSOCIATE_BEFORE);
    2413           0 :   if (limiter) {
    2414             :     // HandleClick resets ancestorLimiter, so set it again.
    2415           0 :     frameSelection->SetAncestorLimiter(limiter);
    2416             :   }
    2417             : 
    2418             :   // After ScrollSelectionIntoView(), the pending notifications might be
    2419             :   // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
    2420             :   return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
    2421             :                                  nsISelectionController::SELECTION_FOCUS_REGION,
    2422             :                                  nsISelectionController::SCROLL_SYNCHRONOUS |
    2423           0 :                                  nsISelectionController::SCROLL_FOR_CARET_MOVE);
    2424             : }
    2425             : 
    2426             : NS_IMETHODIMP
    2427           0 : PresShell::SelectAll()
    2428             : {
    2429           0 :   RefPtr<nsFrameSelection> frameSelection = mSelection;
    2430           0 :   return frameSelection->SelectAll();
    2431             : }
    2432             : 
    2433             : static void
    2434           0 : DoCheckVisibility(nsPresContext* aPresContext,
    2435             :                   nsIContent* aNode,
    2436             :                   int16_t aStartOffset,
    2437             :                   int16_t aEndOffset,
    2438             :                   bool* aRetval)
    2439             : {
    2440           0 :   nsIFrame* frame = aNode->GetPrimaryFrame();
    2441           0 :   if (!frame) {
    2442             :     // No frame to look at so it must not be visible.
    2443           0 :     return;
    2444             :   }
    2445             : 
    2446             :   // Start process now to go through all frames to find startOffset. Then check
    2447             :   // chars after that to see if anything until EndOffset is visible.
    2448           0 :   bool finished = false;
    2449           0 :   frame->CheckVisibility(aPresContext, aStartOffset, aEndOffset, true,
    2450           0 :                          &finished, aRetval);
    2451             :   // Don't worry about other return value.
    2452             : }
    2453             : 
    2454             : NS_IMETHODIMP
    2455           0 : PresShell::CheckVisibility(nsINode *node, int16_t startOffset, int16_t EndOffset, bool *_retval)
    2456             : {
    2457           0 :   if (!node || startOffset>EndOffset || !_retval || startOffset<0 || EndOffset<0)
    2458             :     return NS_ERROR_INVALID_ARG;
    2459           0 :   *_retval = false; //initialize return parameter
    2460           0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(node));
    2461           0 :   if (!content)
    2462             :     return NS_ERROR_FAILURE;
    2463             : 
    2464           0 :   DoCheckVisibility(mPresContext, content, startOffset, EndOffset, _retval);
    2465           0 :   return NS_OK;
    2466             : }
    2467             : 
    2468             : nsresult
    2469           0 : PresShell::CheckVisibilityContent(nsIContent* aNode, int16_t aStartOffset,
    2470             :                                   int16_t aEndOffset, bool* aRetval)
    2471             : {
    2472           0 :   if (!aNode || aStartOffset > aEndOffset || !aRetval ||
    2473           0 :       aStartOffset < 0 || aEndOffset < 0) {
    2474             :     return NS_ERROR_INVALID_ARG;
    2475             :   }
    2476             : 
    2477           0 :   *aRetval = false;
    2478           0 :   DoCheckVisibility(mPresContext, aNode, aStartOffset, aEndOffset, aRetval);
    2479           0 :   return NS_OK;
    2480             : }
    2481             : 
    2482             : //end implementations nsISelectionController
    2483             : 
    2484             : nsIFrame*
    2485           0 : nsIPresShell::GetRootScrollFrame() const
    2486             : {
    2487           0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    2488             :   // Ensure root frame is a viewport frame
    2489           0 :   if (!rootFrame || !rootFrame->IsViewportFrame())
    2490             :     return nullptr;
    2491           0 :   nsIFrame* theFrame = rootFrame->PrincipalChildList().FirstChild();
    2492           0 :   if (!theFrame || !theFrame->IsScrollFrame())
    2493             :     return nullptr;
    2494           0 :   return theFrame;
    2495             : }
    2496             : 
    2497             : nsIScrollableFrame*
    2498           0 : nsIPresShell::GetRootScrollFrameAsScrollable() const
    2499             : {
    2500           0 :   nsIFrame* frame = GetRootScrollFrame();
    2501           0 :   if (!frame)
    2502             :     return nullptr;
    2503           0 :   nsIScrollableFrame* scrollableFrame = do_QueryFrame(frame);
    2504           0 :   NS_ASSERTION(scrollableFrame,
    2505             :                "All scroll frames must implement nsIScrollableFrame");
    2506             :   return scrollableFrame;
    2507             : }
    2508             : 
    2509             : nsIPageSequenceFrame*
    2510           0 : PresShell::GetPageSequenceFrame() const
    2511             : {
    2512           0 :   nsIFrame* frame = mFrameConstructor->GetPageSequenceFrame();
    2513           0 :   return do_QueryFrame(frame);
    2514             : }
    2515             : 
    2516             : nsCanvasFrame*
    2517           0 : PresShell::GetCanvasFrame() const
    2518             : {
    2519           0 :   nsIFrame* frame = mFrameConstructor->GetDocElementContainingBlock();
    2520           0 :   return do_QueryFrame(frame);
    2521             : }
    2522             : 
    2523             : void
    2524           0 : PresShell::RestoreRootScrollPosition()
    2525             : {
    2526           0 :   nsIScrollableFrame* scrollableFrame = GetRootScrollFrameAsScrollable();
    2527           0 :   if (scrollableFrame) {
    2528           0 :     scrollableFrame->ScrollToRestoredPosition();
    2529             :   }
    2530           0 : }
    2531             : 
    2532             : void
    2533           0 : PresShell::MaybeReleaseCapturingContent()
    2534             : {
    2535           0 :   RefPtr<nsFrameSelection> frameSelection = FrameSelection();
    2536           0 :   if (frameSelection) {
    2537           0 :     frameSelection->SetDragState(false);
    2538             :   }
    2539           0 :   if (gCaptureInfo.mContent &&
    2540           0 :       gCaptureInfo.mContent->OwnerDoc() == mDocument) {
    2541           0 :     SetCapturingContent(nullptr, 0);
    2542             :   }
    2543           0 : }
    2544             : 
    2545             : void
    2546           0 : PresShell::BeginLoad(nsIDocument *aDocument)
    2547             : {
    2548           0 :   mDocumentLoading = true;
    2549             : 
    2550           0 :   gfxTextPerfMetrics *tp = nullptr;
    2551           0 :   if (mPresContext) {
    2552           0 :     tp = mPresContext->GetTextPerfMetrics();
    2553             :   }
    2554             : 
    2555           0 :   bool shouldLog = MOZ_LOG_TEST(gLog, LogLevel::Debug);
    2556           0 :   if (shouldLog || tp) {
    2557           0 :     mLoadBegin = TimeStamp::Now();
    2558             :   }
    2559             : 
    2560           0 :   if (shouldLog) {
    2561           0 :     nsIURI* uri = mDocument->GetDocumentURI();
    2562           0 :     MOZ_LOG(gLog, LogLevel::Debug,
    2563             :            ("(presshell) %p load begin [%s]\n",
    2564             :             this, uri ? uri->GetSpecOrDefault().get() : ""));
    2565             :   }
    2566           0 : }
    2567             : 
    2568             : void
    2569           0 : PresShell::EndLoad(nsIDocument *aDocument)
    2570             : {
    2571           0 :   MOZ_ASSERT(aDocument == mDocument, "Wrong document");
    2572             : 
    2573           0 :   RestoreRootScrollPosition();
    2574             : 
    2575           0 :   mDocumentLoading = false;
    2576           0 : }
    2577             : 
    2578             : void
    2579           0 : PresShell::LoadComplete()
    2580             : {
    2581           0 :   gfxTextPerfMetrics *tp = nullptr;
    2582           0 :   if (mPresContext) {
    2583           0 :     tp = mPresContext->GetTextPerfMetrics();
    2584             :   }
    2585             : 
    2586             :   // log load
    2587           0 :   bool shouldLog = MOZ_LOG_TEST(gLog, LogLevel::Debug);
    2588           0 :   if (shouldLog || tp) {
    2589           0 :     TimeDuration loadTime = TimeStamp::Now() - mLoadBegin;
    2590           0 :     nsIURI* uri = mDocument->GetDocumentURI();
    2591           0 :     nsAutoCString spec;
    2592           0 :     if (uri) {
    2593           0 :       spec = uri->GetSpecOrDefault();
    2594             :     }
    2595           0 :     if (shouldLog) {
    2596           0 :       MOZ_LOG(gLog, LogLevel::Debug,
    2597             :              ("(presshell) %p load done time-ms: %9.2f [%s]\n",
    2598             :               this, loadTime.ToMilliseconds(), spec.get()));
    2599             :     }
    2600           0 :     if (tp) {
    2601           0 :       tp->Accumulate();
    2602           0 :       if (tp->cumulative.numChars > 0) {
    2603           0 :         LogTextPerfStats(tp, this, tp->cumulative, loadTime.ToMilliseconds(),
    2604           0 :                          eLog_loaddone, spec.get());
    2605             :       }
    2606             :     }
    2607             :   }
    2608           0 : }
    2609             : 
    2610             : #ifdef DEBUG
    2611             : void
    2612           0 : PresShell::VerifyHasDirtyRootAncestor(nsIFrame* aFrame)
    2613             : {
    2614             :   // XXXbz due to bug 372769, can't actually assert anything here...
    2615             :   return;
    2616             : 
    2617             :   // XXXbz shouldn't need this part; remove it once FrameNeedsReflow
    2618             :   // handles the root frame correctly.
    2619             :   if (!aFrame->GetParent()) {
    2620             :     return;
    2621             :   }
    2622             : 
    2623             :   // Make sure that there is a reflow root ancestor of |aFrame| that's
    2624             :   // in mDirtyRoots already.
    2625             :   while (aFrame && (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)) {
    2626             :     if (((aFrame->GetStateBits() & NS_FRAME_REFLOW_ROOT) ||
    2627             :          !aFrame->GetParent()) &&
    2628             :         mDirtyRoots.Contains(aFrame)) {
    2629             :       return;
    2630             :     }
    2631             : 
    2632             :     aFrame = aFrame->GetParent();
    2633             :   }
    2634             :   NS_NOTREACHED("Frame has dirty bits set but isn't scheduled to be "
    2635             :                 "reflowed?");
    2636             : }
    2637             : #endif
    2638             : 
    2639             : void
    2640           0 : PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
    2641             :                             nsFrameState aBitToAdd,
    2642             :                             ReflowRootHandling aRootHandling)
    2643             : {
    2644           0 :   MOZ_ASSERT(aBitToAdd == NS_FRAME_IS_DIRTY ||
    2645             :              aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN ||
    2646             :              !aBitToAdd,
    2647             :              "Unexpected bits being added");
    2648             : 
    2649             :   // FIXME bug 478135
    2650           0 :   NS_ASSERTION(!(aIntrinsicDirty == eStyleChange &&
    2651             :                  aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN),
    2652             :                "bits don't correspond to style change reason");
    2653             : 
    2654             :   // FIXME bug 457400
    2655           0 :   NS_ASSERTION(!mIsReflowing, "can't mark frame dirty during reflow");
    2656             : 
    2657             :   // If we've not yet done the initial reflow, then don't bother
    2658             :   // enqueuing a reflow command yet.
    2659           0 :   if (! mDidInitialize)
    2660           0 :     return;
    2661             : 
    2662             :   // If we're already destroying, don't bother with this either.
    2663           0 :   if (mIsDestroying)
    2664             :     return;
    2665             : 
    2666             : #ifdef DEBUG
    2667             :   //printf("gShellCounter: %d\n", gShellCounter++);
    2668           0 :   if (mInVerifyReflow)
    2669             :     return;
    2670             : 
    2671           0 :   if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
    2672           0 :     printf("\nPresShell@%p: frame %p needs reflow\n", (void*)this, (void*)aFrame);
    2673           0 :     if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) {
    2674           0 :       printf("Current content model:\n");
    2675           0 :       Element *rootElement = mDocument->GetRootElement();
    2676           0 :       if (rootElement) {
    2677           0 :         rootElement->List(stdout, 0);
    2678             :       }
    2679             :     }
    2680             :   }
    2681             : #endif
    2682             : 
    2683           0 :   AutoTArray<nsIFrame*, 4> subtrees;
    2684           0 :   subtrees.AppendElement(aFrame);
    2685             : 
    2686           0 :   do {
    2687           0 :     nsIFrame *subtreeRoot = subtrees.PopLastElement();
    2688             : 
    2689             :     // Grab |wasDirty| now so we can go ahead and update the bits on
    2690             :     // subtreeRoot.
    2691           0 :     bool wasDirty = NS_SUBTREE_DIRTY(subtreeRoot);
    2692           0 :     subtreeRoot->AddStateBits(aBitToAdd);
    2693             : 
    2694             :     // Determine whether we need to keep looking for the next ancestor
    2695             :     // reflow root if subtreeRoot itself is a reflow root.
    2696             :     bool targetNeedsReflowFromParent;
    2697           0 :     switch (aRootHandling) {
    2698             :       case ePositionOrSizeChange:
    2699           0 :         targetNeedsReflowFromParent = true;
    2700           0 :         break;
    2701             :       case eNoPositionOrSizeChange:
    2702           0 :         targetNeedsReflowFromParent = false;
    2703           0 :         break;
    2704             :       case eInferFromBitToAdd:
    2705           0 :         targetNeedsReflowFromParent = (aBitToAdd == NS_FRAME_IS_DIRTY);
    2706           0 :         break;
    2707             :     }
    2708             : 
    2709             : #define FRAME_IS_REFLOW_ROOT(_f)                   \
    2710             :   ((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) &&  \
    2711             :    (_f != subtreeRoot || !targetNeedsReflowFromParent))
    2712             : 
    2713             : 
    2714             :     // Mark the intrinsic widths as dirty on the frame, all of its ancestors,
    2715             :     // and all of its descendants, if needed:
    2716             : 
    2717           0 :     if (aIntrinsicDirty != nsIPresShell::eResize) {
    2718             :       // Mark argument and all ancestors dirty. (Unless we hit a reflow
    2719             :       // root that should contain the reflow.  That root could be
    2720             :       // subtreeRoot itself if it's not dirty, or it could be some
    2721             :       // ancestor of subtreeRoot.)
    2722           0 :       for (nsIFrame *a = subtreeRoot;
    2723           0 :            a && !FRAME_IS_REFLOW_ROOT(a);
    2724             :            a = a->GetParent())
    2725           0 :         a->MarkIntrinsicISizesDirty();
    2726             :     }
    2727             : 
    2728           0 :     if (aIntrinsicDirty == eStyleChange) {
    2729             :       // Mark all descendants dirty (using an nsTArray stack rather than
    2730             :       // recursion).
    2731             :       // Note that ReflowInput::InitResizeFlags has some similar
    2732             :       // code; see comments there for how and why it differs.
    2733           0 :       AutoTArray<nsIFrame*, 32> stack;
    2734           0 :       stack.AppendElement(subtreeRoot);
    2735             : 
    2736           0 :       do {
    2737           0 :         nsIFrame *f = stack.PopLastElement();
    2738             : 
    2739           0 :         if (f->IsPlaceholderFrame()) {
    2740           0 :           nsIFrame *oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
    2741           0 :           if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) {
    2742             :             // We have another distinct subtree we need to mark.
    2743           0 :             subtrees.AppendElement(oof);
    2744             :           }
    2745             :         }
    2746             : 
    2747           0 :         nsIFrame::ChildListIterator lists(f);
    2748           0 :         for (; !lists.IsDone(); lists.Next()) {
    2749           0 :           for (nsIFrame* kid : lists.CurrentList()) {
    2750           0 :             kid->MarkIntrinsicISizesDirty();
    2751           0 :             stack.AppendElement(kid);
    2752             :           }
    2753             :         }
    2754           0 :       } while (stack.Length() != 0);
    2755             :     }
    2756             : 
    2757             :     // Skip setting dirty bits up the tree if we weren't given a bit to add.
    2758           0 :     if (!aBitToAdd) {
    2759           0 :       continue;
    2760             :     }
    2761             : 
    2762             :     // Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty)
    2763             :     // up the tree until we reach either a frame that's already dirty or
    2764             :     // a reflow root.
    2765           0 :     nsIFrame *f = subtreeRoot;
    2766             :     for (;;) {
    2767           0 :       if (FRAME_IS_REFLOW_ROOT(f) || !f->GetParent()) {
    2768             :         // we've hit a reflow root or the root frame
    2769           0 :         if (!wasDirty) {
    2770           0 :           mDirtyRoots.AppendElement(f);
    2771           0 :           SetNeedLayoutFlush();
    2772             :         }
    2773             : #ifdef DEBUG
    2774             :         else {
    2775             :           VerifyHasDirtyRootAncestor(f);
    2776             :         }
    2777             : #endif
    2778             : 
    2779             :         break;
    2780             :       }
    2781             : 
    2782           0 :       nsIFrame *child = f;
    2783           0 :       f = f->GetParent();
    2784           0 :       wasDirty = NS_SUBTREE_DIRTY(f);
    2785           0 :       f->ChildIsDirty(child);
    2786           0 :       NS_ASSERTION(f->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN,
    2787             :                    "ChildIsDirty didn't do its job");
    2788           0 :       if (wasDirty) {
    2789             :         // This frame was already marked dirty.
    2790             : #ifdef DEBUG
    2791             :         VerifyHasDirtyRootAncestor(f);
    2792             : #endif
    2793             :         break;
    2794             :       }
    2795             :     }
    2796           0 :   } while (subtrees.Length() != 0);
    2797             : 
    2798           0 :   MaybeScheduleReflow();
    2799             : }
    2800             : 
    2801             : void
    2802           0 : PresShell::FrameNeedsToContinueReflow(nsIFrame *aFrame)
    2803             : {
    2804           0 :   NS_ASSERTION(mIsReflowing, "Must be in reflow when marking path dirty.");
    2805           0 :   MOZ_ASSERT(mCurrentReflowRoot, "Must have a current reflow root here");
    2806           0 :   NS_ASSERTION(aFrame == mCurrentReflowRoot ||
    2807             :                nsLayoutUtils::IsProperAncestorFrame(mCurrentReflowRoot, aFrame),
    2808             :                "Frame passed in is not the descendant of mCurrentReflowRoot");
    2809           0 :   NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_IN_REFLOW,
    2810             :                "Frame passed in not in reflow?");
    2811             : 
    2812           0 :   mFramesToDirty.PutEntry(aFrame);
    2813           0 : }
    2814             : 
    2815             : already_AddRefed<nsIContent>
    2816           0 : nsIPresShell::GetContentForScrolling() const
    2817             : {
    2818           0 :   if (nsCOMPtr<nsIContent> focused = GetFocusedContentInOurWindow()) {
    2819           0 :     return focused.forget();
    2820             :   }
    2821           0 :   return GetSelectedContentForScrolling();
    2822             : }
    2823             : 
    2824             : already_AddRefed<nsIContent>
    2825           0 : nsIPresShell::GetSelectedContentForScrolling() const
    2826             : {
    2827           0 :   nsCOMPtr<nsIContent> selectedContent;
    2828           0 :   if (mSelection) {
    2829             :     Selection* domSelection =
    2830           0 :       mSelection->GetSelection(SelectionType::eNormal);
    2831           0 :     if (domSelection) {
    2832           0 :       selectedContent = nsIContent::FromNodeOrNull(domSelection->GetFocusNode());
    2833             :     }
    2834             :   }
    2835           0 :   return selectedContent.forget();
    2836             : }
    2837             : 
    2838             : nsIScrollableFrame*
    2839           0 : nsIPresShell::GetNearestScrollableFrame(
    2840             :                 nsIFrame* aFrame,
    2841             :                 nsIPresShell::ScrollDirection aDirection)
    2842             : {
    2843           0 :   if (aDirection == nsIPresShell::eEither) {
    2844           0 :     return nsLayoutUtils::GetNearestScrollableFrame(aFrame);
    2845             :   }
    2846             : 
    2847           0 :   return nsLayoutUtils::GetNearestScrollableFrameForDirection(aFrame,
    2848             :            aDirection == eVertical ? nsLayoutUtils::eVertical :
    2849           0 :                                      nsLayoutUtils::eHorizontal);
    2850             : }
    2851             : 
    2852             : nsIScrollableFrame*
    2853           0 : nsIPresShell::GetScrollableFrameToScrollForContent(
    2854             :                 nsIContent* aContent,
    2855             :                 nsIPresShell::ScrollDirection aDirection)
    2856             : {
    2857           0 :   nsIScrollableFrame* scrollFrame = nullptr;
    2858           0 :   if (aContent) {
    2859           0 :     nsIFrame* startFrame = aContent->GetPrimaryFrame();
    2860           0 :     if (startFrame) {
    2861           0 :       scrollFrame = startFrame->GetScrollTargetFrame();
    2862           0 :       if (scrollFrame) {
    2863           0 :         startFrame = scrollFrame->GetScrolledFrame();
    2864             :       }
    2865           0 :       scrollFrame = GetNearestScrollableFrame(startFrame, aDirection);
    2866             :     }
    2867             :   }
    2868           0 :   if (!scrollFrame) {
    2869           0 :     scrollFrame = GetRootScrollFrameAsScrollable();
    2870           0 :     if (!scrollFrame || !scrollFrame->GetScrolledFrame()) {
    2871             :       return nullptr;
    2872             :     }
    2873           0 :     scrollFrame = GetNearestScrollableFrame(scrollFrame->GetScrolledFrame(),
    2874           0 :                                             aDirection);
    2875             :   }
    2876             :   return scrollFrame;
    2877             : }
    2878             : 
    2879             : nsIScrollableFrame*
    2880           0 : nsIPresShell::GetScrollableFrameToScroll(nsIPresShell::ScrollDirection aDirection)
    2881             : {
    2882           0 :   nsCOMPtr<nsIContent> content = GetContentForScrolling();
    2883           0 :   return GetScrollableFrameToScrollForContent(content.get(), aDirection);
    2884             : }
    2885             : 
    2886             : void
    2887           0 : PresShell::CancelAllPendingReflows()
    2888             : {
    2889           0 :   mDirtyRoots.Clear();
    2890             : 
    2891           0 :   if (mObservingLayoutFlushes) {
    2892           0 :     GetPresContext()->RefreshDriver()->RemoveLayoutFlushObserver(this);
    2893           0 :     mObservingLayoutFlushes = false;
    2894             :   }
    2895             : 
    2896           0 :   ASSERT_REFLOW_SCHEDULED_STATE();
    2897           0 : }
    2898             : 
    2899             : static bool
    2900           0 : DestroyFramesAndStyleDataFor(Element* aElement,
    2901             :                              nsPresContext& aPresContext,
    2902             :                              RestyleManager::IncludeRoot aIncludeRoot)
    2903             : {
    2904             :   bool didReconstruct =
    2905           0 :     aPresContext.FrameConstructor()->DestroyFramesFor(aElement);
    2906           0 :   RestyleManager::ClearServoDataFromSubtree(aElement, aIncludeRoot);
    2907           0 :   return didReconstruct;
    2908             : }
    2909             : 
    2910             : void
    2911           0 : nsIPresShell::SlotAssignmentWillChange(Element& aElement,
    2912             :                                        HTMLSlotElement* aOldSlot,
    2913             :                                        HTMLSlotElement* aNewSlot)
    2914             : {
    2915           0 :   MOZ_ASSERT(aOldSlot != aNewSlot);
    2916             : 
    2917           0 :   if (MOZ_UNLIKELY(!mDidInitialize)) {
    2918             :     return;
    2919             :   }
    2920             : 
    2921             :   // If the old slot is about to become empty, let layout know that it needs to
    2922             :   // do work.
    2923           0 :   if (aOldSlot && aOldSlot->AssignedNodes().Length() == 1) {
    2924           0 :     DestroyFramesForAndRestyle(aOldSlot);
    2925             :   }
    2926             : 
    2927             :   // Ensure the new element starts off clean.
    2928           0 :   DestroyFramesAndStyleDataFor(&aElement,
    2929             :                                *mPresContext,
    2930           0 :                                RestyleManager::IncludeRoot::Yes);
    2931             : 
    2932           0 :   if (aNewSlot) {
    2933             :     // If the new slot will stop showing fallback content, we need to reframe it
    2934             :     // altogether.
    2935           0 :     if (aNewSlot->AssignedNodes().IsEmpty()) {
    2936           0 :       DestroyFramesForAndRestyle(aNewSlot);
    2937             :     // Otherwise we just care about the element, but we need to ensure that
    2938             :     // something takes care of traversing to the relevant slot, if needed.
    2939           0 :     } else if (aNewSlot->HasServoData() &&
    2940           0 :                !Servo_Element_IsDisplayNone(aNewSlot)) {
    2941             :       // Set the reframe bits...
    2942           0 :       aNewSlot->NoteDescendantsNeedFramesForServo();
    2943           0 :       aElement.SetFlags(NODE_NEEDS_FRAME);
    2944             :       // Now the style dirty bits. Note that we can't just do
    2945             :       // aElement.NoteDirtyForServo(), because the new slot is not setup yet.
    2946           0 :       aNewSlot->SetHasDirtyDescendantsForServo();
    2947           0 :       aNewSlot->NoteDirtySubtreeForServo();
    2948             :     }
    2949             :   }
    2950             : }
    2951             : 
    2952             : #ifdef DEBUG
    2953             : static void
    2954           0 : AssertNoFramesInSubtree(nsIContent* aContent)
    2955             : {
    2956           0 :   for (nsIContent* c = aContent; c; c = c->GetNextNode(aContent)) {
    2957           0 :     MOZ_ASSERT(!c->GetPrimaryFrame());
    2958           0 :     if (auto* shadowRoot = c->GetShadowRoot()) {
    2959           0 :       AssertNoFramesInSubtree(shadowRoot);
    2960             :     }
    2961           0 :     if (auto* binding = c->GetXBLBinding()) {
    2962           0 :       if (auto* bindingWithContent = binding->GetBindingWithContent()) {
    2963           0 :         nsIContent* anonContent = bindingWithContent->GetAnonymousContent();
    2964           0 :         MOZ_ASSERT(!anonContent->GetPrimaryFrame());
    2965             : 
    2966             :         // Need to do this instead of just AssertNoFramesInSubtree(anonContent),
    2967             :         // because the parent of the children of the <content> element isn't the
    2968             :         // <content> element, but the bound element, and that confuses
    2969             :         // GetNextNode a lot.
    2970           0 :         for (nsIContent* child = anonContent->GetFirstChild();
    2971           0 :              child;
    2972           0 :              child = child->GetNextSibling()) {
    2973           0 :           AssertNoFramesInSubtree(child);
    2974             :         }
    2975             :       }
    2976             :     }
    2977             :   }
    2978           0 : }
    2979             : #endif
    2980             : 
    2981             : void
    2982           0 : nsIPresShell::DestroyFramesForAndRestyle(Element* aElement)
    2983             : {
    2984             : #ifdef DEBUG
    2985           0 :   auto postCondition = mozilla::MakeScopeExit([&]() {
    2986           0 :     AssertNoFramesInSubtree(aElement);
    2987           0 :   });
    2988             : #endif
    2989             : 
    2990           0 :   MOZ_ASSERT(aElement);
    2991           0 :   if (MOZ_UNLIKELY(!mDidInitialize)) {
    2992           0 :     return;
    2993             :   }
    2994             : 
    2995           0 :   if (!aElement->GetFlattenedTreeParentNode()) {
    2996             :     // Nothing to do here, the element already is out of the frame tree.
    2997             :     return;
    2998             :   }
    2999             : 
    3000           0 :   nsAutoScriptBlocker scriptBlocker;
    3001             : 
    3002             :   // Mark ourselves as not safe to flush while we're doing frame destruction.
    3003           0 :   ++mChangeNestCount;
    3004             : 
    3005           0 :   const bool didReconstruct = FrameConstructor()->DestroyFramesFor(aElement);
    3006             : 
    3007             :   // Clear the style data from all the flattened tree descendants, but _not_
    3008             :   // from us, since otherwise we wouldn't see the reframe.
    3009             :   RestyleManager::ClearServoDataFromSubtree(
    3010           0 :       aElement, RestyleManager::IncludeRoot::No);
    3011             : 
    3012             :   auto changeHint = didReconstruct
    3013           0 :     ? nsChangeHint(0)
    3014           0 :     : nsChangeHint_ReconstructFrame;
    3015             : 
    3016             :   // NOTE(emilio): eRestyle_Subtree is needed to force also a full subtree
    3017             :   // restyle for the content (in Stylo, where the existence of frames != the
    3018             :   // existence of styles).
    3019           0 :   mPresContext->RestyleManager()->PostRestyleEvent(
    3020           0 :     aElement, eRestyle_Subtree, changeHint);
    3021             : 
    3022           0 :   --mChangeNestCount;
    3023             : }
    3024             : 
    3025             : void
    3026           0 : nsIPresShell::PostRecreateFramesFor(Element* aElement)
    3027             : {
    3028           0 :   if (MOZ_UNLIKELY(!mDidInitialize)) {
    3029             :     // Nothing to do here. In fact, if we proceed and aElement is the root, we
    3030             :     // will crash.
    3031             :     return;
    3032             :   }
    3033             : 
    3034           0 :   mPresContext->RestyleManager()->PostRestyleEvent(aElement, nsRestyleHint(0),
    3035           0 :                                                    nsChangeHint_ReconstructFrame);
    3036             : }
    3037             : 
    3038             : void
    3039           0 : nsIPresShell::RestyleForAnimation(Element* aElement, nsRestyleHint aHint)
    3040             : {
    3041             :   // Now that we no longer have separate non-animation and animation
    3042             :   // restyles, this method having a distinct identity is less important,
    3043             :   // but it still seems useful to offer as a "more public" API and as a
    3044             :   // chokepoint for these restyles to go through.
    3045           0 :   mPresContext->RestyleManager()->PostRestyleEvent(aElement, aHint,
    3046           0 :                                                    nsChangeHint(0));
    3047           0 : }
    3048             : 
    3049             : void
    3050           0 : nsIPresShell::SetForwardingContainer(const WeakPtr<nsDocShell> &aContainer)
    3051             : {
    3052           0 :   mForwardingContainer = aContainer;
    3053           0 : }
    3054             : 
    3055             : void
    3056           0 : PresShell::ClearFrameRefs(nsIFrame* aFrame)
    3057             : {
    3058           0 :   mPresContext->EventStateManager()->ClearFrameRefs(aFrame);
    3059             : 
    3060           0 :   AutoWeakFrame* weakFrame = mAutoWeakFrames;
    3061           0 :   while (weakFrame) {
    3062           0 :     AutoWeakFrame* prev = weakFrame->GetPreviousWeakFrame();
    3063           0 :     if (weakFrame->GetFrame() == aFrame) {
    3064             :       // This removes weakFrame from mAutoWeakFrames.
    3065           0 :       weakFrame->Clear(this);
    3066             :     }
    3067             :     weakFrame = prev;
    3068             :   }
    3069             : 
    3070           0 :   AutoTArray<WeakFrame*, 4> toRemove;
    3071           0 :   for (auto iter = mWeakFrames.Iter(); !iter.Done(); iter.Next()) {
    3072           0 :     WeakFrame* weakFrame = iter.Get()->GetKey();
    3073           0 :     if (weakFrame->GetFrame() == aFrame) {
    3074           0 :       toRemove.AppendElement(weakFrame);
    3075             :     }
    3076             :   }
    3077           0 :   for (WeakFrame* weakFrame : toRemove) {
    3078           0 :     weakFrame->Clear(this);
    3079             :   }
    3080           0 : }
    3081             : 
    3082             : already_AddRefed<gfxContext>
    3083           0 : PresShell::CreateReferenceRenderingContext()
    3084             : {
    3085           0 :   nsDeviceContext* devCtx = mPresContext->DeviceContext();
    3086           0 :   RefPtr<gfxContext> rc;
    3087           0 :   if (mPresContext->IsScreen()) {
    3088           0 :     rc = gfxContext::CreateOrNull(
    3089           0 :       gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get());
    3090             :   } else {
    3091             :     // We assume the devCtx has positive width and height for this call.
    3092             :     // However, width and height, may be outside of the reasonable range
    3093             :     // so rc may still be null.
    3094           0 :     rc = devCtx->CreateReferenceRenderingContext();
    3095             :   }
    3096             : 
    3097           0 :   return rc ? rc.forget() : nullptr;
    3098             : }
    3099             : 
    3100             : nsresult
    3101           0 : PresShell::GoToAnchor(const nsAString& aAnchorName, bool aScroll,
    3102             :                       uint32_t aAdditionalScrollFlags)
    3103             : {
    3104           0 :   if (!mDocument) {
    3105             :     return NS_ERROR_FAILURE;
    3106             :   }
    3107             : 
    3108           0 :   const Element *root = mDocument->GetRootElement();
    3109           0 :   if (root && root->IsSVGElement(nsGkAtoms::svg)) {
    3110             :     // We need to execute this even if there is an empty anchor name
    3111             :     // so that any existing SVG fragment identifier effect is removed
    3112           0 :     if (SVGFragmentIdentifier::ProcessFragmentIdentifier(mDocument, aAnchorName)) {
    3113             :       return NS_OK;
    3114             :     }
    3115             :   }
    3116             : 
    3117             :   // Hold a reference to the ESM in case event dispatch tears us down.
    3118           0 :   RefPtr<EventStateManager> esm = mPresContext->EventStateManager();
    3119             : 
    3120           0 :   if (aAnchorName.IsEmpty()) {
    3121           0 :     NS_ASSERTION(!aScroll, "can't scroll to empty anchor name");
    3122           0 :     esm->SetContentState(nullptr, NS_EVENT_STATE_URLTARGET);
    3123           0 :     return NS_OK;
    3124             :   }
    3125             : 
    3126           0 :   nsresult rv = NS_OK;
    3127           0 :   nsCOMPtr<nsIContent> content;
    3128             : 
    3129             :   // Search for an element with a matching "id" attribute
    3130           0 :   if (mDocument) {
    3131           0 :     content = mDocument->GetElementById(aAnchorName);
    3132             :   }
    3133             : 
    3134             :   // Search for an anchor element with a matching "name" attribute
    3135           0 :   if (!content && mDocument->IsHTMLDocument()) {
    3136             :     // Find a matching list of named nodes
    3137           0 :     nsCOMPtr<nsINodeList> list = mDocument->GetElementsByName(aAnchorName);
    3138           0 :     if (list) {
    3139             :       // Loop through the named nodes looking for the first anchor
    3140           0 :       uint32_t length = list->Length();
    3141           0 :       for (uint32_t i = 0; i < length; i++) {
    3142           0 :         nsIContent* node = list->Item(i);
    3143           0 :         if (node->IsHTMLElement(nsGkAtoms::a)) {
    3144           0 :           content = node;
    3145           0 :           break;
    3146             :         }
    3147             :       }
    3148             :     }
    3149             :   }
    3150             : 
    3151             :   // Search for anchor in the HTML namespace with a matching name
    3152           0 :   if (!content && !mDocument->IsHTMLDocument())
    3153             :   {
    3154           0 :     NS_NAMED_LITERAL_STRING(nameSpace, "http://www.w3.org/1999/xhtml");
    3155             :     // Get the list of anchor elements
    3156             :     nsCOMPtr<nsINodeList> list =
    3157           0 :       mDocument->GetElementsByTagNameNS(nameSpace, NS_LITERAL_STRING("a"));
    3158             :     // Loop through the anchors looking for the first one with the given name.
    3159           0 :     for (uint32_t i = 0; true; i++) {
    3160           0 :       nsIContent* node = list->Item(i);
    3161           0 :       if (!node) { // End of list
    3162             :         break;
    3163             :       }
    3164             : 
    3165             :       // Compare the name attribute
    3166           0 :       if (node->IsElement() &&
    3167           0 :           node->AsElement()->AttrValueIs(kNameSpaceID_None,
    3168             :                                          nsGkAtoms::name,
    3169             :                                          aAnchorName,
    3170             :                                          eCaseMatters)) {
    3171           0 :         content = node;
    3172           0 :         break;
    3173             :       }
    3174           0 :     }
    3175             :   }
    3176             : 
    3177           0 :   esm->SetContentState(content, NS_EVENT_STATE_URLTARGET);
    3178             : 
    3179             : #ifdef ACCESSIBILITY
    3180           0 :   nsIContent *anchorTarget = content;
    3181             : #endif
    3182             : 
    3183           0 :   nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
    3184           0 :   if (rootScroll && rootScroll->DidHistoryRestore()) {
    3185             :     // Scroll position restored from history trumps scrolling to anchor.
    3186           0 :     aScroll = false;
    3187           0 :     rootScroll->ClearDidHistoryRestore();
    3188             :   }
    3189             : 
    3190           0 :   if (content) {
    3191           0 :     if (aScroll) {
    3192           0 :       rv = ScrollContentIntoView(content,
    3193             :                                  ScrollAxis(SCROLL_TOP, SCROLL_ALWAYS),
    3194             :                                  ScrollAxis(),
    3195           0 :                                  ANCHOR_SCROLL_FLAGS | aAdditionalScrollFlags);
    3196           0 :       NS_ENSURE_SUCCESS(rv, rv);
    3197             : 
    3198           0 :       nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
    3199           0 :       if (rootScroll) {
    3200           0 :         mLastAnchorScrolledTo = content;
    3201           0 :         mLastAnchorScrollPositionY = rootScroll->GetScrollPosition().y;
    3202             :       }
    3203             :     }
    3204             : 
    3205             :     // Should we select the target? This action is controlled by a
    3206             :     // preference: the default is to not select.
    3207           0 :     bool selectAnchor = Preferences::GetBool("layout.selectanchor");
    3208             : 
    3209             :     // Even if select anchor pref is false, we must still move the
    3210             :     // caret there. That way tabbing will start from the new
    3211             :     // location
    3212           0 :     RefPtr<nsRange> jumpToRange = new nsRange(mDocument);
    3213           0 :     while (content && content->GetFirstChild()) {
    3214           0 :       content = content->GetFirstChild();
    3215             :     }
    3216           0 :     jumpToRange->SelectNodeContents(*content, IgnoreErrors());
    3217             :     // Select the anchor
    3218           0 :     RefPtr<Selection> sel = mSelection->GetSelection(SelectionType::eNormal);
    3219           0 :     if (sel) {
    3220           0 :       sel->RemoveAllRanges(IgnoreErrors());
    3221           0 :       sel->AddRange(*jumpToRange, IgnoreErrors());
    3222           0 :       if (!selectAnchor) {
    3223             :         // Use a caret (collapsed selection) at the start of the anchor
    3224           0 :         sel->CollapseToStart(IgnoreErrors());
    3225             :       }
    3226             :     }
    3227             :     // Selection is at anchor.
    3228             :     // Now focus the document itself if focus is on an element within it.
    3229           0 :     nsPIDOMWindowOuter *win = mDocument->GetWindow();
    3230             : 
    3231           0 :     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    3232           0 :     if (fm && win) {
    3233           0 :       nsCOMPtr<mozIDOMWindowProxy> focusedWindow;
    3234           0 :       fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
    3235           0 :       if (SameCOMIdentity(win, focusedWindow)) {
    3236           0 :         fm->ClearFocus(focusedWindow);
    3237             :       }
    3238             :     }
    3239             : 
    3240             :     // If the target is an animation element, activate the animation
    3241           0 :     if (content->IsNodeOfType(nsINode::eANIMATION)) {
    3242           0 :       SVGContentUtils::ActivateByHyperlink(content.get());
    3243             :     }
    3244             :   } else {
    3245           0 :     rv = NS_ERROR_FAILURE;
    3246           0 :     NS_NAMED_LITERAL_STRING(top, "top");
    3247           0 :     if (nsContentUtils::EqualsIgnoreASCIICase(aAnchorName, top)) {
    3248             :       // Scroll to the top/left if aAnchorName is "top" and there is no element
    3249             :       // with such a name or id.
    3250           0 :       rv = NS_OK;
    3251           0 :       nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable();
    3252             :       // Check |aScroll| after setting |rv| so we set |rv| to the same
    3253             :       // thing whether or not |aScroll| is true.
    3254           0 :       if (aScroll && sf) {
    3255             :         // Scroll to the top of the page
    3256           0 :         sf->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT);
    3257             :       }
    3258             :     }
    3259             :   }
    3260             : 
    3261             : #ifdef ACCESSIBILITY
    3262           0 :   if (anchorTarget) {
    3263           0 :     nsAccessibilityService* accService = AccService();
    3264           0 :     if (accService)
    3265           0 :       accService->NotifyOfAnchorJumpTo(anchorTarget);
    3266             :   }
    3267             : #endif
    3268             : 
    3269             :   return rv;
    3270             : }
    3271             : 
    3272             : nsresult
    3273           0 : PresShell::ScrollToAnchor()
    3274             : {
    3275           0 :   if (!mLastAnchorScrolledTo) {
    3276             :     return NS_OK;
    3277             :   }
    3278           0 :   NS_ASSERTION(mDidInitialize, "should have done initial reflow by now");
    3279             : 
    3280           0 :   nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable();
    3281           0 :   if (!rootScroll ||
    3282           0 :       mLastAnchorScrollPositionY != rootScroll->GetScrollPosition().y) {
    3283             :     return NS_OK;
    3284             :   }
    3285           0 :   nsresult rv = ScrollContentIntoView(mLastAnchorScrolledTo,
    3286             :                                       ScrollAxis(SCROLL_TOP, SCROLL_ALWAYS),
    3287             :                                       ScrollAxis(),
    3288           0 :                                       ANCHOR_SCROLL_FLAGS);
    3289           0 :   mLastAnchorScrolledTo = nullptr;
    3290           0 :   return rv;
    3291             : }
    3292             : 
    3293             : /*
    3294             :  * Helper (per-continuation) for ScrollContentIntoView.
    3295             :  *
    3296             :  * @param aContainerFrame [in] the frame which aRect is relative to
    3297             :  * @param aFrame [in] Frame whose bounds should be unioned
    3298             :  * @param aUseWholeLineHeightForInlines [in] if true, then for inline frames
    3299             :  * we should include the top of the line in the added rectangle
    3300             :  * @param aRect [inout] rect into which its bounds should be unioned
    3301             :  * @param aHaveRect [inout] whether aRect contains data yet
    3302             :  * @param aPrevBlock [inout] the block aLines is a line iterator for
    3303             :  * @param aLines [inout] the line iterator we're using
    3304             :  * @param aCurLine [inout] the line to start looking from in this iterator
    3305             :  */
    3306             : static void
    3307           0 : AccumulateFrameBounds(nsIFrame* aContainerFrame,
    3308             :                       nsIFrame* aFrame,
    3309             :                       bool aUseWholeLineHeightForInlines,
    3310             :                       nsRect& aRect,
    3311             :                       bool& aHaveRect,
    3312             :                       nsIFrame*& aPrevBlock,
    3313             :                       nsAutoLineIterator& aLines,
    3314             :                       int32_t& aCurLine)
    3315             : {
    3316           0 :   nsIFrame* frame = aFrame;
    3317           0 :   nsRect frameBounds = nsRect(nsPoint(0, 0), aFrame->GetSize());
    3318             : 
    3319             :   // If this is an inline frame and either the bounds height is 0 (quirks
    3320             :   // layout model) or aUseWholeLineHeightForInlines is set, we need to
    3321             :   // change the top of the bounds to include the whole line.
    3322           0 :   if (frameBounds.height == 0 || aUseWholeLineHeightForInlines) {
    3323             :     nsIFrame *prevFrame = aFrame;
    3324             :     nsIFrame *f = aFrame;
    3325             : 
    3326           0 :     while (f && f->IsFrameOfType(nsIFrame::eLineParticipant) &&
    3327           0 :            !f->IsTransformed() && !f->IsAbsPosContainingBlock()) {
    3328           0 :       prevFrame = f;
    3329           0 :       f = prevFrame->GetParent();
    3330             :     }
    3331             : 
    3332           0 :     if (f != aFrame && f && f->IsBlockFrame()) {
    3333             :       // find the line containing aFrame and increase the top of |offset|.
    3334           0 :       if (f != aPrevBlock) {
    3335           0 :         aLines = f->GetLineIterator();
    3336           0 :         aPrevBlock = f;
    3337           0 :         aCurLine = 0;
    3338             :       }
    3339           0 :       if (aLines) {
    3340           0 :         int32_t index = aLines->FindLineContaining(prevFrame, aCurLine);
    3341           0 :         if (index >= 0) {
    3342           0 :           aCurLine = index;
    3343             :           nsIFrame *trash1;
    3344             :           int32_t trash2;
    3345           0 :           nsRect lineBounds;
    3346             : 
    3347           0 :           if (NS_SUCCEEDED(aLines->GetLine(index, &trash1, &trash2,
    3348             :                                            lineBounds))) {
    3349           0 :             frameBounds += frame->GetOffsetTo(f);
    3350           0 :             frame = f;
    3351           0 :             if (lineBounds.y < frameBounds.y) {
    3352           0 :               frameBounds.height = frameBounds.YMost() - lineBounds.y;
    3353           0 :               frameBounds.y = lineBounds.y;
    3354             :             }
    3355             :           }
    3356             :         }
    3357             :       }
    3358             :     }
    3359             :   }
    3360             : 
    3361             :   nsRect transformedBounds = nsLayoutUtils::TransformFrameRectToAncestor(frame,
    3362           0 :     frameBounds, aContainerFrame);
    3363             : 
    3364           0 :   if (aHaveRect) {
    3365             :     // We can't use nsRect::UnionRect since it drops empty rects on
    3366             :     // the floor, and we need to include them.  (Thus we need
    3367             :     // aHaveRect to know when to drop the initial value on the floor.)
    3368           0 :     aRect.UnionRectEdges(aRect, transformedBounds);
    3369             :   } else {
    3370           0 :     aHaveRect = true;
    3371           0 :     aRect = transformedBounds;
    3372             :   }
    3373           0 : }
    3374             : 
    3375             : static bool
    3376           0 : ComputeNeedToScroll(nsIPresShell::WhenToScroll aWhenToScroll,
    3377             :                     nscoord                    aLineSize,
    3378             :                     nscoord                    aRectMin,
    3379             :                     nscoord                    aRectMax,
    3380             :                     nscoord                    aViewMin,
    3381             :                     nscoord                    aViewMax) {
    3382             :   // See how the rect should be positioned vertically
    3383           0 :   if (nsIPresShell::SCROLL_ALWAYS == aWhenToScroll) {
    3384             :     // The caller wants the frame as visible as possible
    3385             :     return true;
    3386           0 :   } else if (nsIPresShell::SCROLL_IF_NOT_VISIBLE == aWhenToScroll) {
    3387             :     // Scroll only if no part of the frame is visible in this view
    3388           0 :     return aRectMax - aLineSize <= aViewMin ||
    3389           0 :            aRectMin + aLineSize >= aViewMax;
    3390           0 :   } else if (nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE == aWhenToScroll) {
    3391             :     // Scroll only if part of the frame is hidden and more can fit in view
    3392           0 :     return !(aRectMin >= aViewMin && aRectMax <= aViewMax) &&
    3393           0 :       std::min(aViewMax, aRectMax) - std::max(aRectMin, aViewMin) < aViewMax - aViewMin;
    3394             :   }
    3395             :   return false;
    3396             : }
    3397             : 
    3398             : static nscoord
    3399           0 : ComputeWhereToScroll(int16_t aWhereToScroll,
    3400             :                      nscoord aOriginalCoord,
    3401             :                      nscoord aRectMin,
    3402             :                      nscoord aRectMax,
    3403             :                      nscoord aViewMin,
    3404             :                      nscoord aViewMax,
    3405             :                      nscoord* aRangeMin,
    3406             :                      nscoord* aRangeMax) {
    3407           0 :   nscoord resultCoord = aOriginalCoord;
    3408           0 :   nscoord scrollPortLength = aViewMax - aViewMin;
    3409           0 :   if (nsIPresShell::SCROLL_MINIMUM == aWhereToScroll) {
    3410             :     // Scroll the minimum amount necessary to show as much as possible of the frame.
    3411             :     // If the frame is too large, don't hide any initially visible part of it.
    3412           0 :     nscoord min = std::min(aRectMin, aRectMax - scrollPortLength);
    3413           0 :     nscoord max = std::max(aRectMin, aRectMax - scrollPortLength);
    3414           0 :     resultCoord = std::min(std::max(aOriginalCoord, min), max);
    3415             :   } else {
    3416             :     nscoord frameAlignCoord =
    3417           0 :       NSToCoordRound(aRectMin + (aRectMax - aRectMin) * (aWhereToScroll / 100.0f));
    3418           0 :     resultCoord =  NSToCoordRound(frameAlignCoord - scrollPortLength * (
    3419             :                                   aWhereToScroll / 100.0f));
    3420             :   }
    3421             :   // Force the scroll range to extend to include resultCoord.
    3422           0 :   *aRangeMin = std::min(resultCoord, aRectMax - scrollPortLength);
    3423           0 :   *aRangeMax = std::max(resultCoord, aRectMin);
    3424           0 :   return resultCoord;
    3425             : }
    3426             : 
    3427             : /**
    3428             :  * This function takes a scrollable frame, a rect in the coordinate system
    3429             :  * of the scrolled frame, and a desired percentage-based scroll
    3430             :  * position and attempts to scroll the rect to that position in the
    3431             :  * scrollport.
    3432             :  *
    3433             :  * This needs to work even if aRect has a width or height of zero.
    3434             :  */
    3435           0 : static void ScrollToShowRect(nsIScrollableFrame*      aFrameAsScrollable,
    3436             :                              const nsRect&            aRect,
    3437             :                              nsIPresShell::ScrollAxis aVertical,
    3438             :                              nsIPresShell::ScrollAxis aHorizontal,
    3439             :                              uint32_t                 aFlags)
    3440             : {
    3441           0 :   nsPoint scrollPt = aFrameAsScrollable->GetScrollPosition();
    3442             :   nsRect visibleRect(scrollPt,
    3443           0 :                      aFrameAsScrollable->GetScrollPositionClampingScrollPortSize());
    3444             : 
    3445           0 :   nsSize lineSize;
    3446             :   // Don't call GetLineScrollAmount unless we actually need it. Not only
    3447             :   // does this save time, but it's not safe to call GetLineScrollAmount
    3448             :   // during reflow (because it depends on font size inflation and doesn't
    3449             :   // use the in-reflow-safe font-size inflation path). If we did call it,
    3450             :   // it would assert and possible give the wrong result.
    3451           0 :   if (aVertical.mWhenToScroll == nsIPresShell::SCROLL_IF_NOT_VISIBLE ||
    3452             :       aHorizontal.mWhenToScroll == nsIPresShell::SCROLL_IF_NOT_VISIBLE) {
    3453           0 :     lineSize = aFrameAsScrollable->GetLineScrollAmount();
    3454             :   }
    3455           0 :   ScrollbarStyles ss = aFrameAsScrollable->GetScrollbarStyles();
    3456           0 :   nsRect allowedRange(scrollPt, nsSize(0, 0));
    3457           0 :   bool needToScroll = false;
    3458           0 :   uint32_t directions = aFrameAsScrollable->GetPerceivedScrollingDirections();
    3459             : 
    3460           0 :   if (((aFlags & nsIPresShell::SCROLL_OVERFLOW_HIDDEN) ||
    3461           0 :        ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN) &&
    3462           0 :       (!aVertical.mOnlyIfPerceivedScrollableDirection ||
    3463           0 :        (directions & nsIScrollableFrame::VERTICAL))) {
    3464             : 
    3465           0 :     if (ComputeNeedToScroll(aVertical.mWhenToScroll,
    3466             :                             lineSize.height,
    3467             :                             aRect.y,
    3468             :                             aRect.YMost(),
    3469             :                             visibleRect.y,
    3470             :                             visibleRect.YMost())) {
    3471             :       nscoord maxHeight;
    3472           0 :       scrollPt.y = ComputeWhereToScroll(aVertical.mWhereToScroll,
    3473             :                                         scrollPt.y,
    3474             :                                         aRect.y,
    3475             :                                         aRect.YMost(),
    3476             :                                         visibleRect.y,
    3477             :                                         visibleRect.YMost(),
    3478             :                                         &allowedRange.y, &maxHeight);
    3479           0 :       allowedRange.height = maxHeight - allowedRange.y;
    3480           0 :       needToScroll = true;
    3481             :     }
    3482             :   }
    3483             : 
    3484           0 :   if (((aFlags & nsIPresShell::SCROLL_OVERFLOW_HIDDEN) ||
    3485           0 :        ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN) &&
    3486           0 :       (!aHorizontal.mOnlyIfPerceivedScrollableDirection ||
    3487           0 :        (directions & nsIScrollableFrame::HORIZONTAL))) {
    3488             : 
    3489           0 :     if (ComputeNeedToScroll(aHorizontal.mWhenToScroll,
    3490             :                             lineSize.width,
    3491             :                             aRect.x,
    3492             :                             aRect.XMost(),
    3493             :                             visibleRect.x,
    3494             :                             visibleRect.XMost())) {
    3495             :       nscoord maxWidth;
    3496           0 :       scrollPt.x = ComputeWhereToScroll(aHorizontal.mWhereToScroll,
    3497             :                                         scrollPt.x,
    3498             :                                         aRect.x,
    3499             :                                         aRect.XMost(),
    3500             :                                         visibleRect.x,
    3501             :                                         visibleRect.XMost(),
    3502             :                                         &allowedRange.x, &maxWidth);
    3503           0 :       allowedRange.width = maxWidth - allowedRange.x;
    3504           0 :       needToScroll = true;
    3505             :     }
    3506             :   }
    3507             : 
    3508             :   // If we don't need to scroll, then don't try since it might cancel
    3509             :   // a current smooth scroll operation.
    3510           0 :   if (needToScroll) {
    3511           0 :     nsIScrollableFrame::ScrollMode scrollMode = nsIScrollableFrame::INSTANT;
    3512           0 :     bool autoBehaviorIsSmooth = (aFrameAsScrollable->GetScrollbarStyles().mScrollBehavior
    3513           0 :                                   == NS_STYLE_SCROLL_BEHAVIOR_SMOOTH);
    3514           0 :     bool smoothScroll = (aFlags & nsIPresShell::SCROLL_SMOOTH) ||
    3515           0 :                           ((aFlags & nsIPresShell::SCROLL_SMOOTH_AUTO) && autoBehaviorIsSmooth);
    3516           0 :     if (gfxPrefs::ScrollBehaviorEnabled() && smoothScroll) {
    3517           0 :       scrollMode = nsIScrollableFrame::SMOOTH_MSD;
    3518             :     }
    3519           0 :     aFrameAsScrollable->ScrollTo(scrollPt, scrollMode, &allowedRange);
    3520             :   }
    3521           0 : }
    3522             : 
    3523             : nsresult
    3524           0 : PresShell::ScrollContentIntoView(nsIContent*              aContent,
    3525             :                                  nsIPresShell::ScrollAxis aVertical,
    3526             :                                  nsIPresShell::ScrollAxis aHorizontal,
    3527             :                                  uint32_t                 aFlags)
    3528             : {
    3529           0 :   NS_ENSURE_TRUE(aContent, NS_ERROR_NULL_POINTER);
    3530           0 :   nsCOMPtr<nsIDocument> composedDoc = aContent->GetComposedDoc();
    3531           0 :   NS_ENSURE_STATE(composedDoc);
    3532             : 
    3533           0 :   NS_ASSERTION(mDidInitialize, "should have done initial reflow by now");
    3534             : 
    3535           0 :   if (mContentToScrollTo) {
    3536           0 :     mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
    3537             :   }
    3538           0 :   mContentToScrollTo = aContent;
    3539           0 :   ScrollIntoViewData* data = new ScrollIntoViewData();
    3540           0 :   data->mContentScrollVAxis = aVertical;
    3541           0 :   data->mContentScrollHAxis = aHorizontal;
    3542           0 :   data->mContentToScrollToFlags = aFlags;
    3543           0 :   if (NS_FAILED(mContentToScrollTo->SetProperty(nsGkAtoms::scrolling, data,
    3544             :                                                 nsINode::DeleteProperty<PresShell::ScrollIntoViewData>))) {
    3545           0 :     mContentToScrollTo = nullptr;
    3546             :   }
    3547             : 
    3548             :   // Flush layout and attempt to scroll in the process.
    3549           0 :   if (nsIPresShell* shell = composedDoc->GetShell()) {
    3550           0 :     shell->SetNeedLayoutFlush();
    3551             :   }
    3552           0 :   composedDoc->FlushPendingNotifications(FlushType::InterruptibleLayout);
    3553             : 
    3554             :   // If mContentToScrollTo is non-null, that means we interrupted the reflow
    3555             :   // (or suppressed it altogether because we're suppressing interruptible
    3556             :   // flushes right now) and won't necessarily get the position correct, but do
    3557             :   // a best-effort scroll here.  The other option would be to do this inside
    3558             :   // FlushPendingNotifications, but I'm not sure the repeated scrolling that
    3559             :   // could trigger if reflows keep getting interrupted would be more desirable
    3560             :   // than a single best-effort scroll followed by one final scroll on the first
    3561             :   // completed reflow.
    3562           0 :   if (mContentToScrollTo) {
    3563           0 :     DoScrollContentIntoView();
    3564             :   }
    3565             :   return NS_OK;
    3566             : }
    3567             : 
    3568             : void
    3569           0 : PresShell::DoScrollContentIntoView()
    3570             : {
    3571           0 :   NS_ASSERTION(mDidInitialize, "should have done initial reflow by now");
    3572             : 
    3573           0 :   nsIFrame* frame = mContentToScrollTo->GetPrimaryFrame();
    3574           0 :   if (!frame) {
    3575           0 :     mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
    3576           0 :     mContentToScrollTo = nullptr;
    3577           0 :     return;
    3578             :   }
    3579             : 
    3580           0 :   if (frame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
    3581             :     // The reflow flush before this scroll got interrupted, and this frame's
    3582             :     // coords and size are all zero, and it has no content showing anyway.
    3583             :     // Don't bother scrolling to it.  We'll try again when we finish up layout.
    3584             :     return;
    3585             :   }
    3586             : 
    3587             :   // Make sure we skip 'frame' ... if it's scrollable, we should use its
    3588             :   // scrollable ancestor as the container.
    3589             :   nsIFrame* container = nsLayoutUtils::GetClosestFrameOfType(
    3590           0 :     frame->GetParent(), LayoutFrameType::Scroll);
    3591           0 :   if (!container) {
    3592             :     // nothing can be scrolled
    3593             :     return;
    3594             :   }
    3595             : 
    3596             :   ScrollIntoViewData* data = static_cast<ScrollIntoViewData*>(
    3597           0 :     mContentToScrollTo->GetProperty(nsGkAtoms::scrolling));
    3598           0 :   if (MOZ_UNLIKELY(!data)) {
    3599           0 :     mContentToScrollTo = nullptr;
    3600           0 :     return;
    3601             :   }
    3602             : 
    3603             :   // This is a two-step process.
    3604             :   // Step 1: Find the bounds of the rect we want to scroll into view.  For
    3605             :   //         example, for an inline frame we may want to scroll in the whole
    3606             :   //         line, or we may want to scroll multiple lines into view.
    3607             :   // Step 2: Walk container frame and its ancestors and scroll them
    3608             :   //         appropriately.
    3609             :   // frameBounds is relative to container. We're assuming
    3610             :   // that scrollframes don't split so every continuation of frame will
    3611             :   // be a descendant of container. (Things would still mostly work
    3612             :   // even if that assumption was false.)
    3613           0 :   nsRect frameBounds;
    3614           0 :   bool haveRect = false;
    3615             :   bool useWholeLineHeightForInlines =
    3616           0 :     data->mContentScrollVAxis.mWhenToScroll != nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE;
    3617             :   // Reuse the same line iterator across calls to AccumulateFrameBounds.  We set
    3618             :   // it every time we detect a new block (stored in prevBlock).
    3619           0 :   nsIFrame* prevBlock = nullptr;
    3620           0 :   nsAutoLineIterator lines;
    3621             :   // The last line we found a continuation on in |lines|.  We assume that later
    3622             :   // continuations cannot come on earlier lines.
    3623           0 :   int32_t curLine = 0;
    3624           0 :   do {
    3625           0 :     AccumulateFrameBounds(container, frame, useWholeLineHeightForInlines,
    3626           0 :                           frameBounds, haveRect, prevBlock, lines, curLine);
    3627           0 :   } while ((frame = frame->GetNextContinuation()));
    3628             : 
    3629           0 :   ScrollFrameRectIntoView(container, frameBounds, data->mContentScrollVAxis,
    3630             :                           data->mContentScrollHAxis,
    3631           0 :                           data->mContentToScrollToFlags);
    3632             : }
    3633             : 
    3634             : bool
    3635           0 : PresShell::ScrollFrameRectIntoView(nsIFrame*                aFrame,
    3636             :                                    const nsRect&            aRect,
    3637             :                                    nsIPresShell::ScrollAxis aVertical,
    3638             :                                    nsIPresShell::ScrollAxis aHorizontal,
    3639             :                                    uint32_t                 aFlags)
    3640             : {
    3641           0 :   bool didScroll = false;
    3642             :   // This function needs to work even if rect has a width or height of 0.
    3643           0 :   nsRect rect = aRect;
    3644           0 :   nsIFrame* container = aFrame;
    3645             :   // Walk up the frame hierarchy scrolling the rect into view and
    3646             :   // keeping rect relative to container
    3647             :   do {
    3648           0 :     nsIScrollableFrame* sf = do_QueryFrame(container);
    3649           0 :     if (sf) {
    3650           0 :       nsPoint oldPosition = sf->GetScrollPosition();
    3651           0 :       nsRect targetRect = rect;
    3652             :       // Inflate the scrolled rect by the container's padding in each dimension,
    3653             :       // unless we have 'overflow-clip-box-*: content-box' in that dimension.
    3654           0 :       auto* disp = container->StyleDisplay();
    3655           0 :       if (disp->mOverflowClipBoxBlock ==
    3656           0 :             NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX ||
    3657           0 :           disp->mOverflowClipBoxInline ==
    3658             :             NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX) {
    3659           0 :         WritingMode wm = container->GetWritingMode();
    3660           0 :         bool cbH = (wm.IsVertical() ? disp->mOverflowClipBoxBlock
    3661           0 :                                     : disp->mOverflowClipBoxInline) ==
    3662           0 :                    NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
    3663           0 :         bool cbV = (wm.IsVertical() ? disp->mOverflowClipBoxInline
    3664           0 :                                     : disp->mOverflowClipBoxBlock) ==
    3665           0 :                    NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
    3666           0 :         nsMargin padding = container->GetUsedPadding();
    3667           0 :         if (!cbH) {
    3668           0 :           padding.left = padding.right = nscoord(0);
    3669             :         }
    3670           0 :         if (!cbV) {
    3671           0 :           padding.top = padding.bottom = nscoord(0);
    3672             :         }
    3673           0 :         targetRect.Inflate(padding);
    3674             :       }
    3675           0 :       ScrollToShowRect(sf, targetRect - sf->GetScrolledFrame()->GetPosition(),
    3676           0 :                        aVertical, aHorizontal, aFlags);
    3677           0 :       nsPoint newPosition = sf->LastScrollDestination();
    3678             :       // If the scroll position increased, that means our content moved up,
    3679             :       // so our rect's offset should decrease
    3680           0 :       rect += oldPosition - newPosition;
    3681             : 
    3682           0 :       if (oldPosition != newPosition) {
    3683           0 :         didScroll = true;
    3684             :       }
    3685             : 
    3686             :       // only scroll one container when this flag is set
    3687           0 :       if (aFlags & nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY) {
    3688             :         break;
    3689             :       }
    3690             :     }
    3691             :     nsIFrame* parent;
    3692           0 :     if (container->IsTransformed()) {
    3693           0 :       container->GetTransformMatrix(nullptr, &parent);
    3694           0 :       rect = nsLayoutUtils::TransformFrameRectToAncestor(container, rect, parent);
    3695             :     } else {
    3696           0 :       rect += container->GetPosition();
    3697           0 :       parent = container->GetParent();
    3698             :     }
    3699           0 :     if (!parent && !(aFlags & nsIPresShell::SCROLL_NO_PARENT_FRAMES)) {
    3700           0 :       nsPoint extraOffset(0,0);
    3701           0 :       parent = nsLayoutUtils::GetCrossDocParentFrame(container, &extraOffset);
    3702           0 :       if (parent) {
    3703           0 :         int32_t APD = container->PresContext()->AppUnitsPerDevPixel();
    3704           0 :         int32_t parentAPD = parent->PresContext()->AppUnitsPerDevPixel();
    3705           0 :         rect = rect.ScaleToOtherAppUnitsRoundOut(APD, parentAPD);
    3706             :         rect += extraOffset;
    3707             :       }
    3708             :     }
    3709           0 :     container = parent;
    3710           0 :   } while (container);
    3711             : 
    3712           0 :   return didScroll;
    3713             : }
    3714             : 
    3715             : nsRectVisibility
    3716           0 : PresShell::GetRectVisibility(nsIFrame* aFrame,
    3717             :                              const nsRect &aRect,
    3718             :                              nscoord aMinTwips) const
    3719             : {
    3720           0 :   NS_ASSERTION(aFrame->PresContext() == GetPresContext(),
    3721             :                "prescontext mismatch?");
    3722           0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    3723           0 :   NS_ASSERTION(rootFrame,
    3724             :                "How can someone have a frame for this presshell when there's no root?");
    3725           0 :   nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable();
    3726           0 :   nsRect scrollPortRect;
    3727           0 :   if (sf) {
    3728           0 :     scrollPortRect = sf->GetScrollPortRect();
    3729           0 :     nsIFrame* f = do_QueryFrame(sf);
    3730           0 :     scrollPortRect += f->GetOffsetTo(rootFrame);
    3731             :   } else {
    3732           0 :     scrollPortRect = nsRect(nsPoint(0,0), rootFrame->GetSize());
    3733             :   }
    3734             : 
    3735             :   // scrollPortRect has the viewport visible area relative to rootFrame.
    3736           0 :   nsRect visibleAreaRect(scrollPortRect);
    3737             :   // Find the intersection of this and the frame's ancestor scrollable
    3738             :   // frames. We walk the whole ancestor chain to find all the scrollable
    3739             :   // frames.
    3740             :   nsIScrollableFrame* scrollAncestorFrame =
    3741             :     nsLayoutUtils::GetNearestScrollableFrame(aFrame,
    3742           0 :       nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
    3743           0 :   while (scrollAncestorFrame) {
    3744           0 :     nsRect scrollAncestorRect = scrollAncestorFrame->GetScrollPortRect();
    3745           0 :     nsIFrame* f = do_QueryFrame(scrollAncestorFrame);
    3746           0 :     scrollAncestorRect += f->GetOffsetTo(rootFrame);
    3747             : 
    3748           0 :     visibleAreaRect = visibleAreaRect.Intersect(scrollAncestorRect);
    3749             : 
    3750             :     // Continue up the chain.
    3751             :     scrollAncestorFrame =
    3752           0 :       nsLayoutUtils::GetNearestScrollableFrame(f->GetParent(),
    3753           0 :         nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
    3754             :   }
    3755             : 
    3756             :   // aRect is in the aFrame coordinate space, so bring it into rootFrame
    3757             :   // coordinate space.
    3758           0 :   nsRect r = aRect + aFrame->GetOffsetTo(rootFrame);
    3759             :   // If aRect is entirely visible then we don't need to ensure that
    3760             :   // at least aMinTwips of it is visible
    3761           0 :   if (visibleAreaRect.Contains(r)) {
    3762             :     return nsRectVisibility_kVisible;
    3763             :   }
    3764             : 
    3765           0 :   nsRect insetRect = visibleAreaRect;
    3766           0 :   insetRect.Deflate(aMinTwips, aMinTwips);
    3767           0 :   if (r.YMost() <= insetRect.y)
    3768             :     return nsRectVisibility_kAboveViewport;
    3769           0 :   if (r.y >= insetRect.YMost())
    3770             :     return nsRectVisibility_kBelowViewport;
    3771           0 :   if (r.XMost() <= insetRect.x)
    3772             :     return nsRectVisibility_kLeftOfViewport;
    3773           0 :   if (r.x >= insetRect.XMost())
    3774             :     return nsRectVisibility_kRightOfViewport;
    3775             : 
    3776           0 :   return nsRectVisibility_kVisible;
    3777             : }
    3778             : 
    3779             : void
    3780           0 : PresShell::ScheduleViewManagerFlush(PaintType aType)
    3781             : {
    3782           0 :   if (MOZ_UNLIKELY(mIsDestroying)) {
    3783             :     return;
    3784             :   }
    3785             : 
    3786           0 :   if (aType == PAINT_DELAYED_COMPRESS) {
    3787             :     // Delay paint for 1 second.
    3788             :     static const uint32_t kPaintDelayPeriod = 1000;
    3789           0 :     if (!mDelayedPaintTimer) {
    3790             :       nsTimerCallbackFunc
    3791           0 :         PaintTimerCallBack = [](nsITimer* aTimer, void* aClosure) {
    3792             :           // The passed-in PresShell is always alive here. Because if PresShell
    3793             :           // died, mDelayedPaintTimer->Cancel() would be called during the
    3794             :           // destruction and this callback would never be invoked.
    3795           0 :           auto self = static_cast<PresShell*>(aClosure);
    3796           0 :           self->SetNextPaintCompressed();
    3797           0 :           self->ScheduleViewManagerFlush();
    3798           0 :       };
    3799             : 
    3800           0 :       NS_NewTimerWithFuncCallback(getter_AddRefs(mDelayedPaintTimer),
    3801             :                                   PaintTimerCallBack,
    3802             :                                   this,
    3803             :                                   kPaintDelayPeriod,
    3804             :                                   nsITimer::TYPE_ONE_SHOT,
    3805             :                                   "PaintTimerCallBack",
    3806           0 :                                   mDocument->EventTargetFor(TaskCategory::Other));
    3807             :     }
    3808             :     return;
    3809             :   }
    3810             : 
    3811           0 :   nsPresContext* presContext = GetPresContext();
    3812           0 :   if (presContext) {
    3813           0 :     presContext->RefreshDriver()->ScheduleViewManagerFlush();
    3814             :   }
    3815           0 :   SetNeedLayoutFlush();
    3816             : }
    3817             : 
    3818             : void
    3819           0 : nsIPresShell::DispatchSynthMouseMove(WidgetGUIEvent* aEvent)
    3820             : {
    3821           0 :   AUTO_PROFILER_TRACING("Paint", "DispatchSynthMouseMove");
    3822           0 :   nsEventStatus status = nsEventStatus_eIgnore;
    3823           0 :   nsView* targetView = nsView::GetViewFor(aEvent->mWidget);
    3824           0 :   if (!targetView)
    3825           0 :     return;
    3826           0 :   targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
    3827             : }
    3828             : 
    3829             : void
    3830           0 : PresShell::ClearMouseCaptureOnView(nsView* aView)
    3831             : {
    3832           0 :   if (gCaptureInfo.mContent) {
    3833           0 :     if (aView) {
    3834             :       // if a view was specified, ensure that the captured content is within
    3835             :       // this view.
    3836           0 :       nsIFrame* frame = gCaptureInfo.mContent->GetPrimaryFrame();
    3837           0 :       if (frame) {
    3838           0 :         nsView* view = frame->GetClosestView();
    3839             :         // if there is no view, capturing won't be handled any more, so
    3840             :         // just release the capture.
    3841           0 :         if (view) {
    3842             :           do {
    3843           0 :             if (view == aView) {
    3844           0 :               gCaptureInfo.mContent = nullptr;
    3845             :               // the view containing the captured content likely disappeared so
    3846             :               // disable capture for now.
    3847           0 :               gCaptureInfo.mAllowed = false;
    3848           0 :               break;
    3849             :             }
    3850             : 
    3851           0 :             view = view->GetParent();
    3852           0 :           } while (view);
    3853             :           // return if the view wasn't found
    3854             :           return;
    3855             :         }
    3856             :       }
    3857             :     }
    3858             : 
    3859             :     gCaptureInfo.mContent = nullptr;
    3860             :   }
    3861             : 
    3862             :   // disable mouse capture until the next mousedown as a dialog has opened
    3863             :   // or a drag has started. Otherwise, someone could start capture during
    3864             :   // the modal dialog or drag.
    3865           0 :   gCaptureInfo.mAllowed = false;
    3866             : }
    3867             : 
    3868             : void
    3869           0 : nsIPresShell::ClearMouseCapture(nsIFrame* aFrame)
    3870             : {
    3871           0 :   if (!gCaptureInfo.mContent) {
    3872           0 :     gCaptureInfo.mAllowed = false;
    3873           0 :     return;
    3874             :   }
    3875             : 
    3876             :   // null frame argument means clear the capture
    3877           0 :   if (!aFrame) {
    3878           0 :     gCaptureInfo.mContent = nullptr;
    3879           0 :     gCaptureInfo.mAllowed = false;
    3880           0 :     return;
    3881             :   }
    3882             : 
    3883           0 :   nsIFrame* capturingFrame = gCaptureInfo.mContent->GetPrimaryFrame();
    3884           0 :   if (!capturingFrame) {
    3885           0 :     gCaptureInfo.mContent = nullptr;
    3886           0 :     gCaptureInfo.mAllowed = false;
    3887           0 :     return;
    3888             :   }
    3889             : 
    3890           0 :   if (nsLayoutUtils::IsAncestorFrameCrossDoc(aFrame, capturingFrame)) {
    3891           0 :     gCaptureInfo.mContent = nullptr;
    3892           0 :     gCaptureInfo.mAllowed = false;
    3893             :   }
    3894             : }
    3895             : 
    3896             : nsresult
    3897           0 : PresShell::CaptureHistoryState(nsILayoutHistoryState** aState)
    3898             : {
    3899           0 :   MOZ_ASSERT(nullptr != aState, "null state pointer");
    3900             : 
    3901             :   // We actually have to mess with the docshell here, since we want to
    3902             :   // store the state back in it.
    3903             :   // XXXbz this isn't really right, since this is being called in the
    3904             :   // content viewer's Hide() method...  by that point the docshell's
    3905             :   // state could be wrong.  We should sort out a better ownership
    3906             :   // model for the layout history state.
    3907           0 :   nsCOMPtr<nsIDocShell> docShell(mPresContext->GetDocShell());
    3908           0 :   if (!docShell)
    3909             :     return NS_ERROR_FAILURE;
    3910             : 
    3911           0 :   nsCOMPtr<nsILayoutHistoryState> historyState;
    3912           0 :   docShell->GetLayoutHistoryState(getter_AddRefs(historyState));
    3913           0 :   if (!historyState) {
    3914             :     // Create the document state object
    3915           0 :     historyState = NS_NewLayoutHistoryState();
    3916           0 :     docShell->SetLayoutHistoryState(historyState);
    3917             :   }
    3918             : 
    3919           0 :   *aState = historyState;
    3920           0 :   NS_IF_ADDREF(*aState);
    3921             : 
    3922             :   // Capture frame state for the entire frame hierarchy
    3923           0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    3924           0 :   if (!rootFrame) return NS_OK;
    3925             : 
    3926           0 :   mFrameConstructor->CaptureFrameState(rootFrame, historyState);
    3927             : 
    3928           0 :   return NS_OK;
    3929             : }
    3930             : 
    3931             : void
    3932           0 : PresShell::ScheduleBeforeFirstPaint()
    3933             : {
    3934           0 :   if (!mDocument->IsResourceDoc()) {
    3935             :     // Notify observers that a new page is about to be drawn. Execute this
    3936             :     // as soon as it is safe to run JS, which is guaranteed to be before we
    3937             :     // go back to the event loop and actually draw the page.
    3938           0 :     MOZ_LOG(gLog, LogLevel::Debug,
    3939             :            ("PresShell::ScheduleBeforeFirstPaint this=%p", this));
    3940             : 
    3941           0 :     nsContentUtils::AddScriptRunner(new nsBeforeFirstPaintDispatcher(mDocument));
    3942             :   }
    3943           0 : }
    3944             : 
    3945             : void
    3946           0 : PresShell::UnsuppressAndInvalidate()
    3947             : {
    3948             :   // Note: We ignore the EnsureVisible check for resource documents, because
    3949             :   // they won't have a docshell, so they'll always fail EnsureVisible.
    3950           0 :   if ((!mDocument->IsResourceDoc() && !mPresContext->EnsureVisible()) ||
    3951           0 :       mHaveShutDown) {
    3952             :     // No point; we're about to be torn down anyway.
    3953             :     return;
    3954             :   }
    3955             : 
    3956           0 :   ScheduleBeforeFirstPaint();
    3957             : 
    3958           0 :   mPaintingSuppressed = false;
    3959           0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    3960           0 :   if (rootFrame) {
    3961             :     // let's assume that outline on a root frame is not supported
    3962           0 :     rootFrame->InvalidateFrame();
    3963             :   }
    3964             : 
    3965             :   // now that painting is unsuppressed, focus may be set on the document
    3966           0 :   if (nsPIDOMWindowOuter* win = mDocument->GetWindow())
    3967           0 :     win->SetReadyForFocus();
    3968             : 
    3969           0 :   if (!mHaveShutDown) {
    3970           0 :     SynthesizeMouseMove(false);
    3971           0 :     ScheduleApproximateFrameVisibilityUpdateNow();
    3972             :   }
    3973             : }
    3974             : 
    3975             : void
    3976           0 : PresShell::UnsuppressPainting()
    3977             : {
    3978           0 :   if (mPaintSuppressionTimer) {
    3979           0 :     mPaintSuppressionTimer->Cancel();
    3980           0 :     mPaintSuppressionTimer = nullptr;
    3981             :   }
    3982             : 
    3983           0 :   if (mIsDocumentGone || !mPaintingSuppressed)
    3984             :     return;
    3985             : 
    3986             :   // If we have reflows pending, just wait until we process
    3987             :   // the reflows and get all the frames where we want them
    3988             :   // before actually unlocking the painting.  Otherwise
    3989             :   // go ahead and unlock now.
    3990           0 :   if (!mDirtyRoots.IsEmpty())
    3991           0 :     mShouldUnsuppressPainting = true;
    3992             :   else
    3993           0 :     UnsuppressAndInvalidate();
    3994             : }
    3995             : 
    3996             : // Post a request to handle an arbitrary callback after reflow has finished.
    3997             : nsresult
    3998           0 : PresShell::PostReflowCallback(nsIReflowCallback* aCallback)
    3999             : {
    4000           0 :   void* result = AllocateByObjectID(eArenaObjectID_nsCallbackEventRequest,
    4001           0 :                                     sizeof(nsCallbackEventRequest));
    4002           0 :   nsCallbackEventRequest* request = (nsCallbackEventRequest*)result;
    4003             : 
    4004           0 :   request->callback = aCallback;
    4005           0 :   request->next = nullptr;
    4006             : 
    4007           0 :   if (mLastCallbackEventRequest) {
    4008           0 :     mLastCallbackEventRequest = mLastCallbackEventRequest->next = request;
    4009             :   } else {
    4010           0 :     mFirstCallbackEventRequest = request;
    4011           0 :     mLastCallbackEventRequest = request;
    4012             :   }
    4013             : 
    4014           0 :   return NS_OK;
    4015             : }
    4016             : 
    4017             : void
    4018           0 : PresShell::CancelReflowCallback(nsIReflowCallback* aCallback)
    4019             : {
    4020           0 :    nsCallbackEventRequest* before = nullptr;
    4021           0 :    nsCallbackEventRequest* node = mFirstCallbackEventRequest;
    4022           0 :    while(node)
    4023             :    {
    4024           0 :       nsIReflowCallback* callback = node->callback;
    4025             : 
    4026           0 :       if (callback == aCallback)
    4027             :       {
    4028           0 :         nsCallbackEventRequest* toFree = node;
    4029           0 :         if (node == mFirstCallbackEventRequest) {
    4030           0 :           node = node->next;
    4031           0 :           mFirstCallbackEventRequest = node;
    4032           0 :           NS_ASSERTION(before == nullptr, "impossible");
    4033             :         } else {
    4034           0 :           node = node->next;
    4035           0 :           before->next = node;
    4036             :         }
    4037             : 
    4038           0 :         if (toFree == mLastCallbackEventRequest) {
    4039           0 :           mLastCallbackEventRequest = before;
    4040             :         }
    4041             : 
    4042           0 :         FreeByObjectID(eArenaObjectID_nsCallbackEventRequest, toFree);
    4043             :       } else {
    4044           0 :         before = node;
    4045           0 :         node = node->next;
    4046             :       }
    4047             :    }
    4048           0 : }
    4049             : 
    4050             : void
    4051           0 : PresShell::CancelPostedReflowCallbacks()
    4052             : {
    4053           0 :   while (mFirstCallbackEventRequest) {
    4054           0 :     nsCallbackEventRequest* node = mFirstCallbackEventRequest;
    4055           0 :     mFirstCallbackEventRequest = node->next;
    4056           0 :     if (!mFirstCallbackEventRequest) {
    4057           0 :       mLastCallbackEventRequest = nullptr;
    4058             :     }
    4059           0 :     nsIReflowCallback* callback = node->callback;
    4060           0 :     FreeByObjectID(eArenaObjectID_nsCallbackEventRequest, node);
    4061           0 :     if (callback) {
    4062           0 :       callback->ReflowCallbackCanceled();
    4063             :     }
    4064             :   }
    4065           0 : }
    4066             : 
    4067             : void
    4068           0 : PresShell::HandlePostedReflowCallbacks(bool aInterruptible)
    4069             : {
    4070           0 :    bool shouldFlush = false;
    4071             : 
    4072           0 :    while (mFirstCallbackEventRequest) {
    4073           0 :      nsCallbackEventRequest* node = mFirstCallbackEventRequest;
    4074           0 :      mFirstCallbackEventRequest = node->next;
    4075           0 :      if (!mFirstCallbackEventRequest) {
    4076           0 :        mLastCallbackEventRequest = nullptr;
    4077             :      }
    4078           0 :      nsIReflowCallback* callback = node->callback;
    4079           0 :      FreeByObjectID(eArenaObjectID_nsCallbackEventRequest, node);
    4080           0 :      if (callback) {
    4081           0 :        if (callback->ReflowFinished()) {
    4082           0 :          shouldFlush = true;
    4083             :        }
    4084             :      }
    4085             :    }
    4086             : 
    4087             :    FlushType flushType =
    4088           0 :      aInterruptible ? FlushType::InterruptibleLayout : FlushType::Layout;
    4089           0 :    if (shouldFlush && !mIsDestroying) {
    4090           0 :      FlushPendingNotifications(flushType);
    4091             :    }
    4092           0 : }
    4093             : 
    4094             : bool
    4095           0 : nsIPresShell::IsSafeToFlush() const
    4096             : {
    4097             :   // Not safe if we are getting torn down, reflowing, or in the middle of frame
    4098             :   // construction.
    4099           0 :   if (mIsReflowing || mChangeNestCount || mIsDestroying) {
    4100             :     return false;
    4101             :   }
    4102             : 
    4103             :     // Not safe if we are painting
    4104           0 :   if (nsViewManager* viewManager = GetViewManager()) {
    4105           0 :     bool isPainting = false;
    4106           0 :     viewManager->IsPainting(isPainting);
    4107           0 :     if (isPainting) {
    4108           0 :       return false;
    4109             :     }
    4110             :   }
    4111             : 
    4112             :   return true;
    4113             : }
    4114             : 
    4115             : void
    4116           0 : nsIPresShell::NotifyFontFaceSetOnRefresh()
    4117             : {
    4118           0 :   if (FontFaceSet* set = mDocument->GetFonts()) {
    4119           0 :     set->DidRefresh();
    4120             :   }
    4121           0 : }
    4122             : 
    4123             : void
    4124           0 : PresShell::DoFlushPendingNotifications(FlushType aType)
    4125             : {
    4126             :   // by default, flush animations if aType >= FlushType::Style
    4127           0 :   mozilla::ChangesToFlush flush(aType, aType >= FlushType::Style);
    4128           0 :   FlushPendingNotifications(flush);
    4129           0 : }
    4130             : 
    4131             : #ifdef DEBUG
    4132             : static void
    4133           0 : AssertFrameSubtreeIsSane(const nsIFrame& aRoot)
    4134             : {
    4135           0 :   if (const nsIContent* content = aRoot.GetContent()) {
    4136           0 :     MOZ_ASSERT(content->GetFlattenedTreeParentNodeForStyle(),
    4137             :                "Node not in the flattened tree still has a frame?");
    4138             :   }
    4139             : 
    4140           0 :   nsIFrame::ChildListIterator childLists(&aRoot);
    4141           0 :   for (; !childLists.IsDone(); childLists.Next()) {
    4142           0 :     for (const nsIFrame* child : childLists.CurrentList()) {
    4143           0 :       AssertFrameSubtreeIsSane(*child);
    4144             :     }
    4145             :   }
    4146           0 : }
    4147             : #endif
    4148             : 
    4149             : static inline void
    4150           0 : AssertFrameTreeIsSane(const nsIPresShell& aShell)
    4151             : {
    4152             : #ifdef DEBUG
    4153           0 :   if (const nsIFrame* root = aShell.GetRootFrame()) {
    4154           0 :     AssertFrameSubtreeIsSane(*root);
    4155             :   }
    4156             : #endif
    4157           0 : }
    4158             : 
    4159             : void
    4160           0 : PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush aFlush)
    4161             : {
    4162             :   // Per our API contract, hold a strong ref to ourselves until we return.
    4163           0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip = this;
    4164             : 
    4165             :   /**
    4166             :    * VERY IMPORTANT: If you add some sort of new flushing to this
    4167             :    * method, make sure to add the relevant SetNeedLayoutFlush or
    4168             :    * SetNeedStyleFlush calls on the shell.
    4169             :    */
    4170           0 :   FlushType flushType = aFlush.mFlushType;
    4171             : 
    4172           0 :   MOZ_ASSERT(NeedFlush(flushType), "Why did we get called?");
    4173             : 
    4174             : #ifdef MOZ_GECKO_PROFILER
    4175             :   static const EnumeratedArray<FlushType,
    4176             :                                FlushType::Count,
    4177             :                                const char*> flushTypeNames = {
    4178             :     "",
    4179             :     "Event",
    4180             :     "Content",
    4181             :     "ContentAndNotify",
    4182             :     // As far as the profiler is concerned, EnsurePresShellInitAndFrames and
    4183             :     // Frames are the same
    4184             :     "Style",
    4185             :     "Style",
    4186             :     "InterruptibleLayout",
    4187             :     "Layout",
    4188             :     "Display"
    4189           0 :   };
    4190           0 :   AUTO_PROFILER_LABEL_DYNAMIC_CSTR("PresShell::DoFlushPendingNotifications",
    4191             :                                    LAYOUT, flushTypeNames[flushType]);
    4192             : #endif
    4193             : 
    4194             : 
    4195             : #ifdef ACCESSIBILITY
    4196             : #ifdef DEBUG
    4197           0 :   if (nsAccessibilityService* accService = GetAccService()) {
    4198           0 :     NS_ASSERTION(!accService->IsProcessingRefreshDriverNotification(),
    4199             :                  "Flush during accessible tree update!");
    4200             :   }
    4201             : #endif
    4202             : #endif
    4203             : 
    4204           0 :   NS_ASSERTION(flushType >= FlushType::Frames, "Why did we get called?");
    4205             : 
    4206           0 :   mNeedStyleFlush = false;
    4207           0 :   mNeedThrottledAnimationFlush =
    4208           0 :     mNeedThrottledAnimationFlush && !aFlush.mFlushAnimations;
    4209           0 :   mNeedLayoutFlush =
    4210           0 :     mNeedLayoutFlush && (flushType < FlushType::InterruptibleLayout);
    4211             : 
    4212           0 :   bool isSafeToFlush = IsSafeToFlush();
    4213             : 
    4214             :   // If layout could possibly trigger scripts, then it's only safe to flush if
    4215             :   // it's safe to run script.
    4216             :   bool hasHadScriptObject;
    4217           0 :   if (mDocument->GetScriptHandlingObject(hasHadScriptObject) ||
    4218             :       hasHadScriptObject) {
    4219           0 :     isSafeToFlush = isSafeToFlush && nsContentUtils::IsSafeToRunScript();
    4220             :   }
    4221             : 
    4222           0 :   MOZ_DIAGNOSTIC_ASSERT(!mIsDestroying || !isSafeToFlush);
    4223           0 :   MOZ_DIAGNOSTIC_ASSERT(mIsDestroying || mViewManager);
    4224           0 :   MOZ_DIAGNOSTIC_ASSERT(mIsDestroying || mDocument->HasShellOrBFCacheEntry());
    4225           0 :   MOZ_DIAGNOSTIC_ASSERT(mIsDestroying || mDocument->GetShell() == this);
    4226             : 
    4227             :   // Make sure the view manager stays alive.
    4228           0 :   RefPtr<nsViewManager> viewManager = mViewManager;
    4229           0 :   bool didStyleFlush = false;
    4230           0 :   bool didLayoutFlush = false;
    4231           0 :   if (isSafeToFlush) {
    4232             :     // Record that we are in a flush, so that our optimization in
    4233             :     // nsDocument::FlushPendingNotifications doesn't skip any re-entrant
    4234             :     // calls to us.  Otherwise, we might miss some needed flushes, since
    4235             :     // we clear mNeedStyleFlush / mNeedLayoutFlush here at the top of
    4236             :     // the function but we might not have done the work yet.
    4237           0 :     AutoRestore<bool> guard(mInFlush);
    4238           0 :     mInFlush = true;
    4239             : 
    4240             :     // We need to make sure external resource documents are flushed too (for
    4241             :     // example, svg filters that reference a filter in an external document
    4242             :     // need the frames in the external document to be constructed for the
    4243             :     // filter to work). We only need external resources to be flushed when the
    4244             :     // main document is flushing >= FlushType::Frames, so we flush external
    4245             :     // resources here instead of nsDocument::FlushPendingNotifications.
    4246           0 :     mDocument->FlushExternalResources(flushType);
    4247             : 
    4248             :     // Force flushing of any pending content notifications that might have
    4249             :     // queued up while our event was pending.  That will ensure that we don't
    4250             :     // construct frames for content right now that's still waiting to be
    4251             :     // notified on,
    4252           0 :     mDocument->FlushPendingNotifications(FlushType::ContentAndNotify);
    4253             : 
    4254             :     // Process pending restyles, since any flush of the presshell wants
    4255             :     // up-to-date style data.
    4256           0 :     if (!mIsDestroying) {
    4257           0 :       viewManager->FlushDelayedResize(false);
    4258           0 :       mPresContext->FlushPendingMediaFeatureValuesChanged();
    4259             : 
    4260             :       // Flush any pending update of the user font set, since that could
    4261             :       // cause style changes (for updating ex/ch units, and to cause a
    4262             :       // reflow).
    4263           0 :       mDocument->FlushUserFontSet();
    4264             : 
    4265           0 :       mPresContext->FlushCounterStyles();
    4266             : 
    4267           0 :       mPresContext->FlushFontFeatureValues();
    4268             : 
    4269             :       // Flush any requested SMIL samples.
    4270           0 :       if (mDocument->HasAnimationController()) {
    4271           0 :         mDocument->GetAnimationController()->FlushResampleRequests();
    4272             :       }
    4273             : 
    4274           0 :       if (aFlush.mFlushAnimations && mPresContext->EffectCompositor()) {
    4275           0 :         mPresContext->EffectCompositor()->PostRestyleForThrottledAnimations();
    4276             :       }
    4277             : 
    4278             :       // The FlushResampleRequests() above flushed style changes.
    4279           0 :       if (!mIsDestroying) {
    4280           0 :         nsAutoScriptBlocker scriptBlocker;
    4281             : #ifdef MOZ_GECKO_PROFILER
    4282           0 :         AutoProfilerStyleMarker tracingStyleFlush(std::move(mStyleCause));
    4283             : #endif
    4284             : 
    4285           0 :         mPresContext->RestyleManager()->ProcessPendingRestyles();
    4286             :       }
    4287             :     }
    4288             : 
    4289             :     // Process whatever XBL constructors those restyles queued up.  This
    4290             :     // ensures that onload doesn't fire too early and that we won't do extra
    4291             :     // reflows after those constructors run.
    4292           0 :     if (!mIsDestroying) {
    4293           0 :       mDocument->BindingManager()->ProcessAttachedQueue();
    4294             :     }
    4295             : 
    4296             :     // Now those constructors or events might have posted restyle
    4297             :     // events.  At the same time, we still need up-to-date style data.
    4298             :     // In particular, reflow depends on style being completely up to
    4299             :     // date.  If it's not, then style reparenting, which can
    4300             :     // happen during reflow, might suddenly pick up the new rules and
    4301             :     // we'll end up with frames whose style doesn't match the frame
    4302             :     // type.
    4303           0 :     if (!mIsDestroying) {
    4304           0 :       nsAutoScriptBlocker scriptBlocker;
    4305             : #ifdef MOZ_GECKO_PROFILER
    4306           0 :       AutoProfilerStyleMarker tracingStyleFlush(std::move(mStyleCause));
    4307             : #endif
    4308             : 
    4309           0 :       mPresContext->RestyleManager()->ProcessPendingRestyles();
    4310             :       // Clear mNeedStyleFlush here agagin to make this flag work properly for
    4311             :       // optimization since the flag might have set in ProcessPendingRestyles().
    4312           0 :       mNeedStyleFlush = false;
    4313             :     }
    4314             : 
    4315           0 :     AssertFrameTreeIsSane(*this);
    4316             : 
    4317           0 :     didStyleFlush = true;
    4318             : 
    4319             :     // There might be more pending constructors now, but we're not going to
    4320             :     // worry about them.  They can't be triggered during reflow, so we should
    4321             :     // be good.
    4322             : 
    4323           0 :     if (flushType >= (SuppressInterruptibleReflows()
    4324           0 :                         ? FlushType::Layout
    4325           0 :                         : FlushType::InterruptibleLayout) &&
    4326           0 :         !mIsDestroying) {
    4327             : #ifdef MOZ_GECKO_PROFILER
    4328             :       AutoProfilerTracing tracingLayoutFlush("Paint", "Reflow",
    4329           0 :                                               std::move(mReflowCause));
    4330           0 :       mReflowCause = nullptr;
    4331             : #endif
    4332           0 :       didLayoutFlush = true;
    4333           0 :       mFrameConstructor->RecalcQuotesAndCounters();
    4334           0 :       viewManager->FlushDelayedResize(true);
    4335           0 :       if (ProcessReflowCommands(flushType < FlushType::Layout) &&
    4336           0 :           mContentToScrollTo) {
    4337             :         // We didn't get interrupted.  Go ahead and scroll to our content
    4338           0 :         DoScrollContentIntoView();
    4339           0 :         if (mContentToScrollTo) {
    4340           0 :           mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling);
    4341           0 :           mContentToScrollTo = nullptr;
    4342             :         }
    4343             :       }
    4344             :     }
    4345             : 
    4346           0 :     if (flushType >= FlushType::Layout) {
    4347           0 :       if (!mIsDestroying) {
    4348           0 :         viewManager->UpdateWidgetGeometry();
    4349             :       }
    4350             :     }
    4351             :   }
    4352             : 
    4353           0 :   if (!didStyleFlush && flushType >= FlushType::Style && !mIsDestroying) {
    4354           0 :     SetNeedStyleFlush();
    4355           0 :     if (aFlush.mFlushAnimations) {
    4356           0 :       SetNeedThrottledAnimationFlush();
    4357             :     }
    4358             :   }
    4359             : 
    4360           0 :   if (!didLayoutFlush && flushType >= FlushType::InterruptibleLayout &&
    4361           0 :       !mIsDestroying) {
    4362             :     // We suppressed this flush either due to it not being safe to flush,
    4363             :     // or due to SuppressInterruptibleReflows().  Either way, the
    4364             :     // mNeedLayoutFlush flag needs to be re-set.
    4365           0 :     SetNeedLayoutFlush();
    4366             :   }
    4367           0 : }
    4368             : 
    4369             : void
    4370           0 : PresShell::CharacterDataChanged(nsIContent* aContent,
    4371             :                                 const CharacterDataChangeInfo& aInfo)
    4372             : {
    4373           0 :   MOZ_ASSERT(!mIsDocumentGone, "Unexpected CharacterDataChanged");
    4374           0 :   MOZ_ASSERT(aContent->OwnerDoc() == mDocument, "Unexpected document");
    4375             : 
    4376           0 :   nsAutoCauseReflowNotifier crNotifier(this);
    4377             : 
    4378           0 :   mPresContext->RestyleManager()->CharacterDataChanged(aContent, aInfo);
    4379           0 :   mFrameConstructor->CharacterDataChanged(aContent, aInfo);
    4380           0 : }
    4381             : 
    4382             : void
    4383           0 : PresShell::ContentStateChanged(nsIDocument* aDocument,
    4384             :                                nsIContent* aContent,
    4385             :                                EventStates aStateMask)
    4386             : {
    4387           0 :   MOZ_ASSERT(!mIsDocumentGone, "Unexpected ContentStateChanged");
    4388           0 :   MOZ_ASSERT(aDocument == mDocument, "Unexpected aDocument");
    4389             : 
    4390           0 :   if (mDidInitialize) {
    4391           0 :     nsAutoCauseReflowNotifier crNotifier(this);
    4392           0 :     mPresContext->RestyleManager()->ContentStateChanged(aContent, aStateMask);
    4393             :   }
    4394           0 : }
    4395             : 
    4396             : void
    4397           0 : PresShell::DocumentStatesChanged(nsIDocument* aDocument, EventStates aStateMask)
    4398             : {
    4399           0 :   MOZ_ASSERT(!mIsDocumentGone, "Unexpected DocumentStatesChanged");
    4400           0 :   MOZ_ASSERT(aDocument == mDocument, "Unexpected aDocument");
    4401           0 :   MOZ_ASSERT(!aStateMask.IsEmpty());
    4402             : 
    4403           0 :   if (mDidInitialize) {
    4404           0 :     mStyleSet->InvalidateStyleForDocumentStateChanges(aStateMask);
    4405             :   }
    4406             : 
    4407           0 :   if (aStateMask.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
    4408           0 :     if (nsIFrame* root = mFrameConstructor->GetRootFrame()) {
    4409           0 :       root->SchedulePaint();
    4410             :     }
    4411             :   }
    4412           0 : }
    4413             : 
    4414             : void
    4415           0 : PresShell::AttributeWillChange(Element* aElement,
    4416             :                                int32_t aNameSpaceID,
    4417             :                                nsAtom* aAttribute,
    4418             :                                int32_t aModType,
    4419             :                                const nsAttrValue* aNewValue)
    4420             : {
    4421           0 :   MOZ_ASSERT(!mIsDocumentGone, "Unexpected AttributeWillChange");
    4422           0 :   MOZ_ASSERT(aElement->OwnerDoc() == mDocument, "Unexpected document");
    4423             : 
    4424             :   // XXXwaterson it might be more elegant to wait until after the
    4425             :   // initial reflow to begin observing the document. That would
    4426             :   // squelch any other inappropriate notifications as well.
    4427           0 :   if (mDidInitialize) {
    4428           0 :     nsAutoCauseReflowNotifier crNotifier(this);
    4429           0 :     mPresContext->RestyleManager()->AttributeWillChange(aElement, aNameSpaceID,
    4430             :                                                         aAttribute, aModType,
    4431           0 :                                                         aNewValue);
    4432             :   }
    4433           0 : }
    4434             : 
    4435             : void
    4436           0 : PresShell::AttributeChanged(Element* aElement,
    4437             :                             int32_t aNameSpaceID,
    4438             :                             nsAtom* aAttribute,
    4439             :                             int32_t aModType,
    4440             :                             const nsAttrValue* aOldValue)
    4441             : {
    4442           0 :   MOZ_ASSERT(!mIsDocumentGone, "Unexpected AttributeChanged");
    4443           0 :   MOZ_ASSERT(aElement->OwnerDoc() == mDocument, "Unexpected document");
    4444             : 
    4445             :   // XXXwaterson it might be more elegant to wait until after the
    4446             :   // initial reflow to begin observing the document. That would
    4447             :   // squelch any other inappropriate notifications as well.
    4448           0 :   if (mDidInitialize) {
    4449           0 :     nsAutoCauseReflowNotifier crNotifier(this);
    4450           0 :     mPresContext->RestyleManager()->AttributeChanged(aElement, aNameSpaceID,
    4451             :                                                      aAttribute, aModType,
    4452           0 :                                                      aOldValue);
    4453             :   }
    4454           0 : }
    4455             : 
    4456             : void
    4457           0 : PresShell::ContentAppended(nsIContent* aFirstNewContent)
    4458             : {
    4459           0 :   MOZ_ASSERT(!mIsDocumentGone, "Unexpected ContentAppended");
    4460           0 :   MOZ_ASSERT(aFirstNewContent->OwnerDoc() == mDocument,
    4461             :                   "Unexpected document");
    4462             : 
    4463             :   // We never call ContentAppended with a document as the container, so we can
    4464             :   // assert that we have an nsIContent parent.
    4465           0 :   MOZ_ASSERT(aFirstNewContent->GetParent());
    4466           0 :   MOZ_ASSERT(aFirstNewContent->GetParent()->IsElement() ||
    4467             :              aFirstNewContent->GetParent()->IsShadowRoot());
    4468             : 
    4469           0 :   if (!mDidInitialize) {
    4470           0 :     return;
    4471             :   }
    4472             : 
    4473           0 :   nsAutoCauseReflowNotifier crNotifier(this);
    4474             : 
    4475             :   // Call this here so it only happens for real content mutations and
    4476             :   // not cases when the frame constructor calls its own methods to force
    4477             :   // frame reconstruction.
    4478           0 :   mPresContext->RestyleManager()->ContentAppended(aFirstNewContent);
    4479             : 
    4480           0 :   mFrameConstructor->ContentAppended(
    4481             :       aFirstNewContent,
    4482           0 :       nsCSSFrameConstructor::InsertionKind::Async);
    4483             : }
    4484             : 
    4485             : void
    4486           0 : PresShell::ContentInserted(nsIContent* aChild)
    4487             : {
    4488           0 :   MOZ_ASSERT(!mIsDocumentGone, "Unexpected ContentInserted");
    4489           0 :   MOZ_ASSERT(aChild->OwnerDoc() == mDocument, "Unexpected document");
    4490             : 
    4491           0 :   if (!mDidInitialize) {
    4492           0 :     return;
    4493             :   }
    4494             : 
    4495           0 :   nsAutoCauseReflowNotifier crNotifier(this);
    4496             : 
    4497             :   // Call this here so it only happens for real content mutations and
    4498             :   // not cases when the frame constructor calls its own methods to force
    4499             :   // frame reconstruction.
    4500           0 :   mPresContext->RestyleManager()->ContentInserted(aChild);
    4501             : 
    4502           0 :   mFrameConstructor->ContentInserted(
    4503             :       aChild,
    4504             :       nullptr,
    4505           0 :       nsCSSFrameConstructor::InsertionKind::Async);
    4506             : }
    4507             : 
    4508             : void
    4509           0 : PresShell::ContentRemoved(nsIContent* aChild, nsIContent* aPreviousSibling)
    4510             : {
    4511           0 :   MOZ_ASSERT(!mIsDocumentGone, "Unexpected ContentRemoved");
    4512           0 :   MOZ_ASSERT(aChild->OwnerDoc() == mDocument, "Unexpected document");
    4513           0 :   nsINode* container = aChild->GetParentNode();
    4514             : 
    4515             :   // Notify the ESM that the content has been removed, so that
    4516             :   // it can clean up any state related to the content.
    4517             : 
    4518           0 :   mPresContext->EventStateManager()->ContentRemoved(mDocument, aChild);
    4519             : 
    4520           0 :   nsAutoCauseReflowNotifier crNotifier(this);
    4521             : 
    4522             :   // Call this here so it only happens for real content mutations and
    4523             :   // not cases when the frame constructor calls its own methods to force
    4524             :   // frame reconstruction.
    4525           0 :   nsIContent* oldNextSibling = nullptr;
    4526             : 
    4527             :   // Editor calls into here with NAC via HTMLEditor::DeleteRefToAnonymousNode.
    4528             :   // This could be asserted if that caller is fixed.
    4529           0 :   if (MOZ_LIKELY(!aChild->IsRootOfAnonymousSubtree())) {
    4530             :     oldNextSibling = aPreviousSibling
    4531           0 :       ? aPreviousSibling->GetNextSibling()
    4532             :       : container->GetFirstChild();
    4533             :   }
    4534             : 
    4535             :   // After removing aChild from tree we should save information about live ancestor
    4536           0 :   if (mPointerEventTarget &&
    4537           0 :       nsContentUtils::ContentIsDescendantOf(mPointerEventTarget, aChild)) {
    4538           0 :     mPointerEventTarget = aChild->GetParent();
    4539             :   }
    4540             : 
    4541           0 :   mFrameConstructor->ContentRemoved(aChild,
    4542             :                                     oldNextSibling,
    4543           0 :                                     nsCSSFrameConstructor::REMOVE_CONTENT);
    4544             : 
    4545             :   // NOTE(emilio): It's important that this goes after the frame constructor
    4546             :   // stuff, otherwise the frame constructor can't see elements which are
    4547             :   // display: contents / display: none, because we'd have cleared all the style
    4548             :   // data from there.
    4549           0 :   mPresContext->RestyleManager()->ContentRemoved(aChild, oldNextSibling);
    4550           0 : }
    4551             : 
    4552             : void
    4553           0 : PresShell::NotifyCounterStylesAreDirty()
    4554             : {
    4555           0 :   nsAutoCauseReflowNotifier reflowNotifier(this);
    4556           0 :   mFrameConstructor->NotifyCounterStylesAreDirty();
    4557           0 : }
    4558             : 
    4559             : void
    4560           0 : PresShell::ReconstructFrames()
    4561             : {
    4562           0 :   MOZ_ASSERT(!mFrameConstructor->GetRootFrame() || mDidInitialize,
    4563             :              "Must not have root frame before initial reflow");
    4564           0 :   if (!mDidInitialize || mIsDestroying) {
    4565             :     // Nothing to do here
    4566           0 :     return;
    4567             :   }
    4568             : 
    4569           0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
    4570             : 
    4571             :   // Have to make sure that the content notifications are flushed before we
    4572             :   // start messing with the frame model; otherwise we can get content doubling.
    4573             :   //
    4574             :   // Also make sure that styles are flushed before calling into the frame
    4575             :   // constructor, since that's what it expects.
    4576           0 :   mDocument->FlushPendingNotifications(FlushType::Style);
    4577             : 
    4578           0 :   if (mIsDestroying) {
    4579           0 :     return;
    4580             :   }
    4581             : 
    4582           0 :   nsAutoCauseReflowNotifier crNotifier(this);
    4583           0 :   mFrameConstructor->ReconstructDocElementHierarchy(nsCSSFrameConstructor::InsertionKind::Sync);
    4584             : }
    4585             : 
    4586             : void
    4587           0 : nsIPresShell::ApplicableStylesChanged()
    4588             : {
    4589           0 :   if (mIsDestroying) {
    4590             :     // We don't want to mess with restyles at this point
    4591             :     return;
    4592             :   }
    4593             : 
    4594           0 :   EnsureStyleFlush();
    4595           0 :   mDocument->MarkUserFontSetDirty();
    4596             : 
    4597           0 :   if (mPresContext) {
    4598           0 :     mPresContext->MarkCounterStylesDirty();
    4599           0 :     mPresContext->MarkFontFeatureValuesDirty();
    4600           0 :     mPresContext->RestyleManager()->NextRestyleIsForCSSRuleChanges();
    4601             :   }
    4602             : }
    4603             : 
    4604             : nsresult
    4605           0 : PresShell::RenderDocument(const nsRect& aRect, uint32_t aFlags,
    4606             :                           nscolor aBackgroundColor,
    4607             :                           gfxContext* aThebesContext)
    4608             : {
    4609           0 :   NS_ENSURE_TRUE(!(aFlags & RENDER_IS_UNTRUSTED), NS_ERROR_NOT_IMPLEMENTED);
    4610             : 
    4611           0 :   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
    4612           0 :   if (rootPresContext) {
    4613           0 :     rootPresContext->FlushWillPaintObservers();
    4614           0 :     if (mIsDestroying)
    4615             :       return NS_OK;
    4616             :   }
    4617             : 
    4618           0 :   nsAutoScriptBlocker blockScripts;
    4619             : 
    4620             :   // Set up the rectangle as the path in aThebesContext
    4621             :   gfxRect r(0, 0,
    4622           0 :             nsPresContext::AppUnitsToFloatCSSPixels(aRect.width),
    4623           0 :             nsPresContext::AppUnitsToFloatCSSPixels(aRect.height));
    4624           0 :   aThebesContext->NewPath();
    4625             : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
    4626             :   aThebesContext->Rectangle(r, true);
    4627             : #else
    4628           0 :   aThebesContext->Rectangle(r);
    4629             : #endif
    4630             : 
    4631           0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    4632           0 :   if (!rootFrame) {
    4633             :     // Nothing to paint, just fill the rect
    4634           0 :     aThebesContext->SetColor(Color::FromABGR(aBackgroundColor));
    4635           0 :     aThebesContext->Fill();
    4636           0 :     return NS_OK;
    4637             :   }
    4638             : 
    4639           0 :   gfxContextAutoSaveRestore save(aThebesContext);
    4640             : 
    4641           0 :   MOZ_ASSERT(aThebesContext->CurrentOp() == CompositionOp::OP_OVER);
    4642             : 
    4643           0 :   aThebesContext->Clip();
    4644             : 
    4645           0 :   nsDeviceContext* devCtx = mPresContext->DeviceContext();
    4646             : 
    4647           0 :   gfxPoint offset(-nsPresContext::AppUnitsToFloatCSSPixels(aRect.x),
    4648           0 :                   -nsPresContext::AppUnitsToFloatCSSPixels(aRect.y));
    4649           0 :   gfxFloat scale = gfxFloat(devCtx->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel();
    4650             : 
    4651             :   // Since canvas APIs use floats to set up their matrices, we may have some
    4652             :   // slight rounding errors here.  We use NudgeToIntegers() here to adjust
    4653             :   // matrix components that are integers up to the accuracy of floats to be
    4654             :   // those integers.
    4655           0 :   gfxMatrix newTM = aThebesContext->CurrentMatrixDouble().PreTranslate(offset).
    4656           0 :                                                           PreScale(scale, scale).
    4657           0 :                                                           NudgeToIntegers();
    4658           0 :   aThebesContext->SetMatrixDouble(newTM);
    4659             : 
    4660           0 :   AutoSaveRestoreRenderingState _(this);
    4661             : 
    4662           0 :   bool wouldFlushRetainedLayers = false;
    4663           0 :   PaintFrameFlags flags = PaintFrameFlags::PAINT_IGNORE_SUPPRESSION;
    4664           0 :   if (aThebesContext->CurrentMatrix().HasNonIntegerTranslation()) {
    4665             :     flags |= PaintFrameFlags::PAINT_IN_TRANSFORM;
    4666             :   }
    4667           0 :   if (!(aFlags & RENDER_ASYNC_DECODE_IMAGES)) {
    4668             :     flags |= PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES;
    4669             :   }
    4670           0 :   if (aFlags & RENDER_USE_WIDGET_LAYERS) {
    4671             :     // We only support using widget layers on display root's with widgets.
    4672           0 :     nsView* view = rootFrame->GetView();
    4673           0 :     if (view && view->GetWidget() &&
    4674           0 :         nsLayoutUtils::GetDisplayRootFrame(rootFrame) == rootFrame) {
    4675           0 :       LayerManager* layerManager = view->GetWidget()->GetLayerManager();
    4676             :       // ClientLayerManagers or WebRenderLayerManagers in content processes
    4677             :       // don't support taking snapshots.
    4678           0 :       if (layerManager &&
    4679           0 :           (!layerManager->AsKnowsCompositor() ||
    4680           0 :            XRE_IsParentProcess())) {
    4681             :         flags |= PaintFrameFlags::PAINT_WIDGET_LAYERS;
    4682             :       }
    4683             :     }
    4684             :   }
    4685           0 :   if (!(aFlags & RENDER_CARET)) {
    4686           0 :     wouldFlushRetainedLayers = true;
    4687             :     flags |= PaintFrameFlags::PAINT_HIDE_CARET;
    4688             :   }
    4689           0 :   if (aFlags & RENDER_IGNORE_VIEWPORT_SCROLLING) {
    4690           0 :     wouldFlushRetainedLayers = !IgnoringViewportScrolling();
    4691           0 :     mRenderFlags = ChangeFlag(mRenderFlags, true, STATE_IGNORING_VIEWPORT_SCROLLING);
    4692             :   }
    4693           0 :   if (aFlags & RENDER_DRAWWINDOW_NOT_FLUSHING) {
    4694           0 :     mRenderFlags = ChangeFlag(mRenderFlags, true, STATE_DRAWWINDOW_NOT_FLUSHING);
    4695             :   }
    4696           0 :   if (aFlags & RENDER_DOCUMENT_RELATIVE) {
    4697             :     // XXX be smarter about this ... drawWindow might want a rect
    4698             :     // that's "pretty close" to what our retained layer tree covers.
    4699             :     // In that case, it wouldn't disturb normal rendering too much,
    4700             :     // and we should allow it.
    4701           0 :     wouldFlushRetainedLayers = true;
    4702             :     flags |= PaintFrameFlags::PAINT_DOCUMENT_RELATIVE;
    4703             :   }
    4704             : 
    4705             :   // Don't let drawWindow blow away our retained layer tree
    4706           0 :   if ((flags & PaintFrameFlags::PAINT_WIDGET_LAYERS) && wouldFlushRetainedLayers) {
    4707           0 :     flags &= ~PaintFrameFlags::PAINT_WIDGET_LAYERS;
    4708             :   }
    4709             : 
    4710           0 :   nsLayoutUtils::PaintFrame(aThebesContext, rootFrame, nsRegion(aRect),
    4711             :                             aBackgroundColor,
    4712             :                             nsDisplayListBuilderMode::PAINTING,
    4713           0 :                             flags);
    4714             : 
    4715             :   return NS_OK;
    4716             : }
    4717             : 
    4718             : /*
    4719             :  * Clip the display list aList to a range. Returns the clipped
    4720             :  * rectangle surrounding the range.
    4721             :  */
    4722             : nsRect
    4723           0 : PresShell::ClipListToRange(nsDisplayListBuilder *aBuilder,
    4724             :                            nsDisplayList* aList,
    4725             :                            nsRange* aRange)
    4726             : {
    4727             :   // iterate though the display items and add up the bounding boxes of each.
    4728             :   // This will allow the total area of the frames within the range to be
    4729             :   // determined. To do this, remove an item from the bottom of the list, check
    4730             :   // whether it should be part of the range, and if so, append it to the top
    4731             :   // of the temporary list tmpList. If the item is a text frame at the end of
    4732             :   // the selection range, clip it to the portion of the text frame that is
    4733             :   // part of the selection. Then, append the wrapper to the top of the list.
    4734             :   // Otherwise, just delete the item and don't append it.
    4735           0 :   nsRect surfaceRect;
    4736           0 :   nsDisplayList tmpList;
    4737             : 
    4738             :   nsDisplayItem* i;
    4739           0 :   while ((i = aList->RemoveBottom())) {
    4740             :     // itemToInsert indiciates the item that should be inserted into the
    4741             :     // temporary list. If null, no item should be inserted.
    4742           0 :     nsDisplayItem* itemToInsert = nullptr;
    4743           0 :     nsIFrame* frame = i->Frame();
    4744           0 :     nsIContent* content = frame->GetContent();
    4745           0 :     if (content) {
    4746           0 :       bool atStart = (content == aRange->GetStartContainer());
    4747           0 :       bool atEnd = (content == aRange->GetEndContainer());
    4748           0 :       if ((atStart || atEnd) && frame->IsTextFrame()) {
    4749             :         int32_t frameStartOffset, frameEndOffset;
    4750           0 :         frame->GetOffsets(frameStartOffset, frameEndOffset);
    4751             : 
    4752             :         int32_t hilightStart =
    4753           0 :           atStart ? std::max(static_cast<int32_t>(aRange->StartOffset()),
    4754           0 :                              frameStartOffset) : frameStartOffset;
    4755             :         int32_t hilightEnd =
    4756           0 :           atEnd ? std::min(static_cast<int32_t>(aRange->EndOffset()),
    4757           0 :                            frameEndOffset) : frameEndOffset;
    4758           0 :         if (hilightStart < hilightEnd) {
    4759             :           // determine the location of the start and end edges of the range.
    4760           0 :           nsPoint startPoint, endPoint;
    4761           0 :           frame->GetPointFromOffset(hilightStart, &startPoint);
    4762           0 :           frame->GetPointFromOffset(hilightEnd, &endPoint);
    4763             : 
    4764             :           // The clip rectangle is determined by taking the the start and
    4765             :           // end points of the range, offset from the reference frame.
    4766             :           // Because of rtl, the end point may be to the left of (or above,
    4767             :           // in vertical mode) the start point, so x (or y) is set to the
    4768             :           // lower of the values.
    4769           0 :           nsRect textRect(aBuilder->ToReferenceFrame(frame), frame->GetSize());
    4770           0 :           if (frame->GetWritingMode().IsVertical()) {
    4771           0 :             nscoord y = std::min(startPoint.y, endPoint.y);
    4772           0 :             textRect.y += y;
    4773           0 :             textRect.height = std::max(startPoint.y, endPoint.y) - y;
    4774             :           } else {
    4775           0 :             nscoord x = std::min(startPoint.x, endPoint.x);
    4776           0 :             textRect.x += x;
    4777           0 :             textRect.width = std::max(startPoint.x, endPoint.x) - x;
    4778             :           }
    4779           0 :           surfaceRect.UnionRect(surfaceRect, textRect);
    4780             : 
    4781           0 :           const ActiveScrolledRoot* asr = i->GetActiveScrolledRoot();
    4782             : 
    4783           0 :           DisplayItemClip newClip;
    4784           0 :           newClip.SetTo(textRect);
    4785             : 
    4786             :           const DisplayItemClipChain* newClipChain =
    4787           0 :             aBuilder->AllocateDisplayItemClipChain(newClip, asr, nullptr);
    4788             : 
    4789           0 :           i->IntersectClip(aBuilder, newClipChain, true);
    4790           0 :           itemToInsert = i;
    4791             :         }
    4792             :       }
    4793             :       // Don't try to descend into subdocuments.
    4794             :       // If this ever changes we'd need to add handling for subdocuments with
    4795             :       // different zoom levels.
    4796           0 :       else if (content->GetUncomposedDoc() ==
    4797           0 :                  aRange->GetStartContainer()->GetUncomposedDoc()) {
    4798             :         // if the node is within the range, append it to the temporary list
    4799             :         bool before, after;
    4800             :         nsresult rv =
    4801           0 :           nsRange::CompareNodeToRange(content, aRange, &before, &after);
    4802           0 :         if (NS_SUCCEEDED(rv) && !before && !after) {
    4803           0 :           itemToInsert = i;
    4804             :           bool snap;
    4805           0 :           surfaceRect.UnionRect(surfaceRect, i->GetBounds(aBuilder, &snap));
    4806             :         }
    4807             :       }
    4808             :     }
    4809             : 
    4810             :     // insert the item into the list if necessary. If the item has a child
    4811             :     // list, insert that as well
    4812           0 :     nsDisplayList* sublist = i->GetSameCoordinateSystemChildren();
    4813           0 :     if (itemToInsert || sublist) {
    4814           0 :       tmpList.AppendToTop(itemToInsert ? itemToInsert : i);
    4815             :       // if the item is a list, iterate over it as well
    4816           0 :       if (sublist)
    4817             :         surfaceRect.UnionRect(surfaceRect,
    4818           0 :           ClipListToRange(aBuilder, sublist, aRange));
    4819             :     }
    4820             :     else {
    4821             :       // otherwise, just delete the item and don't readd it to the list
    4822           0 :       i->Destroy(aBuilder);
    4823             :     }
    4824             :   }
    4825             : 
    4826             :   // now add all the items back onto the original list again
    4827           0 :   aList->AppendToTop(&tmpList);
    4828             : 
    4829           0 :   return surfaceRect;
    4830             : }
    4831             : 
    4832             : #ifdef DEBUG
    4833             : #include <stdio.h>
    4834             : 
    4835             : static bool gDumpRangePaintList = false;
    4836             : #endif
    4837             : 
    4838             : UniquePtr<RangePaintInfo>
    4839           0 : PresShell::CreateRangePaintInfo(nsRange* aRange,
    4840             :                                 nsRect& aSurfaceRect,
    4841             :                                 bool aForPrimarySelection)
    4842             : {
    4843             :   nsIFrame* ancestorFrame;
    4844           0 :   nsIFrame* rootFrame = GetRootFrame();
    4845             : 
    4846             :   // If the start or end of the range is the document, just use the root
    4847             :   // frame, otherwise get the common ancestor of the two endpoints of the
    4848             :   // range.
    4849           0 :   nsINode* startContainer = aRange->GetStartContainer();
    4850           0 :   nsINode* endContainer = aRange->GetEndContainer();
    4851           0 :   nsIDocument* doc = startContainer->GetComposedDoc();
    4852           0 :   if (startContainer == doc || endContainer == doc) {
    4853             :     ancestorFrame = rootFrame;
    4854             :   } else {
    4855             :     nsINode* ancestor =
    4856           0 :       nsContentUtils::GetCommonAncestor(startContainer, endContainer);
    4857           0 :     NS_ASSERTION(!ancestor || ancestor->IsContent(),
    4858             :                  "common ancestor is not content");
    4859           0 :     if (!ancestor || !ancestor->IsContent())
    4860             :       return nullptr;
    4861             : 
    4862           0 :     ancestorFrame = ancestor->AsContent()->GetPrimaryFrame();
    4863             : 
    4864             :     // XXX deal with ancestorFrame being null due to display:contents
    4865             : 
    4866             :     // use the nearest ancestor frame that includes all continuations as the
    4867             :     // root for building the display list
    4868           0 :     while (ancestorFrame &&
    4869           0 :            nsLayoutUtils::GetNextContinuationOrIBSplitSibling(ancestorFrame))
    4870           0 :       ancestorFrame = ancestorFrame->GetParent();
    4871             :   }
    4872             : 
    4873           0 :   if (!ancestorFrame) {
    4874             :     return nullptr;
    4875             :   }
    4876             : 
    4877             :   // get a display list containing the range
    4878           0 :   auto info = MakeUnique<RangePaintInfo>(aRange, ancestorFrame);
    4879           0 :   info->mBuilder.SetIncludeAllOutOfFlows();
    4880           0 :   if (aForPrimarySelection) {
    4881           0 :     info->mBuilder.SetSelectedFramesOnly();
    4882             :   }
    4883           0 :   info->mBuilder.EnterPresShell(ancestorFrame);
    4884             : 
    4885           0 :   nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
    4886           0 :   nsresult rv = iter->Init(aRange);
    4887           0 :   if (NS_FAILED(rv)) {
    4888             :     return nullptr;
    4889             :   }
    4890             : 
    4891           0 :   auto BuildDisplayListForNode = [&] (nsINode* aNode) {
    4892           0 :     if (MOZ_UNLIKELY(!aNode->IsContent())) {
    4893             :       return;
    4894             :     }
    4895           0 :     nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame();
    4896             :     // XXX deal with frame being null due to display:contents
    4897           0 :     for (; frame; frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) {
    4898           0 :       info->mBuilder.SetVisibleRect(frame->GetVisualOverflowRect());
    4899           0 :       info->mBuilder.SetDirtyRect(frame->GetVisualOverflowRect());
    4900           0 :       frame->BuildDisplayListForStackingContext(&info->mBuilder, &info->mList);
    4901             :     }
    4902           0 :   };
    4903           0 :   if (startContainer->NodeType() == nsINode::TEXT_NODE) {
    4904           0 :     BuildDisplayListForNode(startContainer);
    4905             :   }
    4906           0 :   for (; !iter->IsDone(); iter->Next()) {
    4907           0 :     nsCOMPtr<nsINode> node = iter->GetCurrentNode();
    4908           0 :     BuildDisplayListForNode(node);
    4909             :   }
    4910           0 :   if (endContainer != startContainer &&
    4911           0 :       endContainer->NodeType() == nsINode::TEXT_NODE) {
    4912           0 :     BuildDisplayListForNode(endContainer);
    4913             :   }
    4914             : 
    4915             : #ifdef DEBUG
    4916           0 :   if (gDumpRangePaintList) {
    4917           0 :     fprintf(stderr, "CreateRangePaintInfo --- before ClipListToRange:\n");
    4918           0 :     nsFrame::PrintDisplayList(&(info->mBuilder), info->mList);
    4919             :   }
    4920             : #endif
    4921             : 
    4922           0 :   nsRect rangeRect = ClipListToRange(&info->mBuilder, &info->mList, aRange);
    4923             : 
    4924           0 :   info->mBuilder.LeavePresShell(ancestorFrame, &info->mList);
    4925             : 
    4926             : #ifdef DEBUG
    4927           0 :   if (gDumpRangePaintList) {
    4928           0 :     fprintf(stderr, "CreateRangePaintInfo --- after ClipListToRange:\n");
    4929           0 :     nsFrame::PrintDisplayList(&(info->mBuilder), info->mList);
    4930             :   }
    4931             : #endif
    4932             : 
    4933             :   // determine the offset of the reference frame for the display list
    4934             :   // to the root frame. This will allow the coordinates used when painting
    4935             :   // to all be offset from the same point
    4936           0 :   info->mRootOffset = ancestorFrame->GetOffsetTo(rootFrame);
    4937           0 :   rangeRect.MoveBy(info->mRootOffset);
    4938           0 :   aSurfaceRect.UnionRect(aSurfaceRect, rangeRect);
    4939             : 
    4940           0 :   return info;
    4941             : }
    4942             : 
    4943             : already_AddRefed<SourceSurface>
    4944           0 : PresShell::PaintRangePaintInfo(const nsTArray<UniquePtr<RangePaintInfo>>& aItems,
    4945             :                                Selection* aSelection,
    4946             :                                nsIntRegion* aRegion,
    4947             :                                nsRect aArea,
    4948             :                                const LayoutDeviceIntPoint aPoint,
    4949             :                                LayoutDeviceIntRect* aScreenRect,
    4950             :                                uint32_t aFlags)
    4951             : {
    4952           0 :   nsPresContext* pc = GetPresContext();
    4953           0 :   if (!pc || aArea.width == 0 || aArea.height == 0)
    4954             :     return nullptr;
    4955             : 
    4956             :   // use the rectangle to create the surface
    4957           0 :   nsIntRect pixelArea = aArea.ToOutsidePixels(pc->AppUnitsPerDevPixel());
    4958             : 
    4959             :   // if the image should not be resized, scale must be 1
    4960           0 :   float scale = 1.0;
    4961             :   nsIntRect rootScreenRect =
    4962           0 :     GetRootFrame()->GetScreenRectInAppUnits().ToNearestPixels(
    4963           0 :       pc->AppUnitsPerDevPixel());
    4964             : 
    4965           0 :   nsRect maxSize;
    4966           0 :   pc->DeviceContext()->GetClientRect(maxSize);
    4967             : 
    4968             :   // check if the image should be resized
    4969           0 :   bool resize = aFlags & RENDER_AUTO_SCALE;
    4970             : 
    4971           0 :   if (resize) {
    4972             :     // check if image-resizing-algorithm should be used
    4973           0 :     if (aFlags & RENDER_IS_IMAGE) {
    4974             :       // get max screensize
    4975           0 :       nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width);
    4976           0 :       nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height);
    4977             :       // resize image relative to the screensize
    4978             :       // get best height/width relative to screensize
    4979           0 :       float bestHeight = float(maxHeight)*RELATIVE_SCALEFACTOR;
    4980           0 :       float bestWidth = float(maxWidth)*RELATIVE_SCALEFACTOR;
    4981             :       // calculate scale for bestWidth
    4982           0 :       float adjustedScale = bestWidth / float(pixelArea.width);
    4983             :       // get the worst height (height when width is perfect)
    4984           0 :       float worstHeight = float(pixelArea.height)*adjustedScale;
    4985             :       // get the difference of best and worst height
    4986           0 :       float difference = bestHeight - worstHeight;
    4987             :       // halve the difference and add it to worstHeight to get
    4988             :       // the best compromise between bestHeight and bestWidth,
    4989             :       // then calculate the corresponding scale factor
    4990           0 :       adjustedScale = (worstHeight + difference / 2) / float(pixelArea.height);
    4991             :       // prevent upscaling
    4992           0 :       scale = std::min(scale, adjustedScale);
    4993             :     } else {
    4994             :       // get half of max screensize
    4995           0 :       nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width >> 1);
    4996           0 :       nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height >> 1);
    4997           0 :       if (pixelArea.width > maxWidth || pixelArea.height > maxHeight) {
    4998             :         // divide the maximum size by the image size in both directions. Whichever
    4999             :         // direction produces the smallest result determines how much should be
    5000             :         // scaled.
    5001           0 :         if (pixelArea.width > maxWidth)
    5002           0 :           scale = std::min(scale, float(maxWidth) / pixelArea.width);
    5003           0 :         if (pixelArea.height > maxHeight)
    5004           0 :           scale = std::min(scale, float(maxHeight) / pixelArea.height);
    5005             :       }
    5006             :     }
    5007             : 
    5008             : 
    5009           0 :     pixelArea.width = NSToIntFloor(float(pixelArea.width) * scale);
    5010           0 :     pixelArea.height = NSToIntFloor(float(pixelArea.height) * scale);
    5011           0 :     if (!pixelArea.width || !pixelArea.height)
    5012             :       return nullptr;
    5013             : 
    5014             :     // adjust the screen position based on the rescaled size
    5015           0 :     nscoord left = rootScreenRect.x + pixelArea.x;
    5016           0 :     nscoord top = rootScreenRect.y + pixelArea.y;
    5017           0 :     aScreenRect->x = NSToIntFloor(aPoint.x - float(aPoint.x - left) * scale);
    5018           0 :     aScreenRect->y = NSToIntFloor(aPoint.y - float(aPoint.y - top) * scale);
    5019             :   }
    5020             :   else {
    5021             :     // move aScreenRect to the position of the surface in screen coordinates
    5022           0 :     aScreenRect->MoveTo(rootScreenRect.x + pixelArea.x, rootScreenRect.y + pixelArea.y);
    5023             :   }
    5024           0 :   aScreenRect->width = pixelArea.width;
    5025           0 :   aScreenRect->height = pixelArea.height;
    5026             : 
    5027             :   RefPtr<DrawTarget> dt =
    5028           0 :    gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
    5029           0 :                                  IntSize(pixelArea.width, pixelArea.height),
    5030           0 :                                  SurfaceFormat::B8G8R8A8);
    5031           0 :   if (!dt || !dt->IsValid()) {
    5032             :     return nullptr;
    5033             :   }
    5034             : 
    5035           0 :   RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
    5036           0 :   MOZ_ASSERT(ctx); // already checked the draw target above
    5037             : 
    5038           0 :   if (aRegion) {
    5039           0 :     RefPtr<PathBuilder> builder = dt->CreatePathBuilder(FillRule::FILL_WINDING);
    5040             : 
    5041             :     // Convert aRegion from CSS pixels to dev pixels
    5042             :     nsIntRegion region =
    5043           0 :       aRegion->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel())
    5044           0 :         .ToOutsidePixels(pc->AppUnitsPerDevPixel());
    5045           0 :     for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) {
    5046           0 :       const nsIntRect& rect = iter.Get();
    5047             : 
    5048           0 :       builder->MoveTo(rect.TopLeft());
    5049           0 :       builder->LineTo(rect.TopRight());
    5050           0 :       builder->LineTo(rect.BottomRight());
    5051           0 :       builder->LineTo(rect.BottomLeft());
    5052           0 :       builder->LineTo(rect.TopLeft());
    5053             :     }
    5054             : 
    5055           0 :     RefPtr<Path> path = builder->Finish();
    5056           0 :     ctx->Clip(path);
    5057             :   }
    5058             : 
    5059           0 :   gfxMatrix initialTM = ctx->CurrentMatrixDouble();
    5060             : 
    5061           0 :   if (resize)
    5062           0 :     initialTM.PreScale(scale, scale);
    5063             : 
    5064             :   // translate so that points are relative to the surface area
    5065             :   gfxPoint surfaceOffset =
    5066           0 :     nsLayoutUtils::PointToGfxPoint(-aArea.TopLeft(), pc->AppUnitsPerDevPixel());
    5067           0 :   initialTM.PreTranslate(surfaceOffset);
    5068             : 
    5069             :   // temporarily hide the selection so that text is drawn normally. If a
    5070             :   // selection is being rendered, use that, otherwise use the presshell's
    5071             :   // selection.
    5072           0 :   RefPtr<nsFrameSelection> frameSelection;
    5073           0 :   if (aSelection) {
    5074           0 :     frameSelection = aSelection->GetFrameSelection();
    5075             :   }
    5076             :   else {
    5077           0 :     frameSelection = FrameSelection();
    5078             :   }
    5079           0 :   int16_t oldDisplaySelection = frameSelection->GetDisplaySelection();
    5080           0 :   frameSelection->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
    5081             : 
    5082             :   // next, paint each range in the selection
    5083           0 :   for (const UniquePtr<RangePaintInfo>& rangeInfo : aItems) {
    5084             :     // the display lists paint relative to the offset from the reference
    5085             :     // frame, so account for that translation too:
    5086             :     gfxPoint rootOffset =
    5087           0 :       nsLayoutUtils::PointToGfxPoint(rangeInfo->mRootOffset,
    5088           0 :                                      pc->AppUnitsPerDevPixel());
    5089           0 :     ctx->SetMatrixDouble(initialTM.PreTranslate(rootOffset));
    5090           0 :     aArea.MoveBy(-rangeInfo->mRootOffset.x, -rangeInfo->mRootOffset.y);
    5091           0 :     nsRegion visible(aArea);
    5092             :     RefPtr<LayerManager> layerManager =
    5093           0 :         rangeInfo->mList.PaintRoot(&rangeInfo->mBuilder, ctx,
    5094           0 :                                    nsDisplayList::PAINT_DEFAULT);
    5095           0 :     aArea.MoveBy(rangeInfo->mRootOffset.x, rangeInfo->mRootOffset.y);
    5096             :   }
    5097             : 
    5098             :   // restore the old selection display state
    5099           0 :   frameSelection->SetDisplaySelection(oldDisplaySelection);
    5100             : 
    5101           0 :   return dt->Snapshot();
    5102             : }
    5103             : 
    5104             : already_AddRefed<SourceSurface>
    5105           0 : PresShell::RenderNode(nsINode* aNode,
    5106             :                       nsIntRegion* aRegion,
    5107             :                       const LayoutDeviceIntPoint aPoint,
    5108             :                       LayoutDeviceIntRect* aScreenRect,
    5109             :                       uint32_t aFlags)
    5110             : {
    5111             :   // area will hold the size of the surface needed to draw the node, measured
    5112             :   // from the root frame.
    5113           0 :   nsRect area;
    5114           0 :   nsTArray<UniquePtr<RangePaintInfo>> rangeItems;
    5115             : 
    5116             :   // nothing to draw if the node isn't in a document
    5117           0 :   if (!aNode->IsInUncomposedDoc())
    5118             :     return nullptr;
    5119             : 
    5120           0 :   RefPtr<nsRange> range = new nsRange(aNode);
    5121           0 :   IgnoredErrorResult rv;
    5122           0 :   range->SelectNode(*aNode, rv);
    5123           0 :   if (rv.Failed()) {
    5124             :     return nullptr;
    5125             :   }
    5126             : 
    5127           0 :   UniquePtr<RangePaintInfo> info = CreateRangePaintInfo(range, area, false);
    5128           0 :   if (info && !rangeItems.AppendElement(std::move(info))) {
    5129             :     return nullptr;
    5130             :   }
    5131             : 
    5132           0 :   if (aRegion) {
    5133             :     // combine the area with the supplied region
    5134           0 :     nsIntRect rrectPixels = aRegion->GetBounds();
    5135             : 
    5136           0 :     nsRect rrect = ToAppUnits(rrectPixels, nsPresContext::AppUnitsPerCSSPixel());
    5137           0 :     area.IntersectRect(area, rrect);
    5138             : 
    5139           0 :     nsPresContext* pc = GetPresContext();
    5140           0 :     if (!pc)
    5141           0 :       return nullptr;
    5142             : 
    5143             :     // move the region so that it is offset from the topleft corner of the surface
    5144           0 :     aRegion->MoveBy(-nsPresContext::AppUnitsToIntCSSPixels(area.x),
    5145           0 :                     -nsPresContext::AppUnitsToIntCSSPixels(area.y));
    5146             :   }
    5147             : 
    5148             :   return PaintRangePaintInfo(rangeItems, nullptr, aRegion, area, aPoint,
    5149           0 :                              aScreenRect, aFlags);
    5150             : }
    5151             : 
    5152             : already_AddRefed<SourceSurface>
    5153           0 : PresShell::RenderSelection(Selection* aSelection,
    5154             :                            const LayoutDeviceIntPoint aPoint,
    5155             :                            LayoutDeviceIntRect* aScreenRect,
    5156             :                            uint32_t aFlags)
    5157             : {
    5158             :   // area will hold the size of the surface needed to draw the selection,
    5159             :   // measured from the root frame.
    5160           0 :   nsRect area;
    5161           0 :   nsTArray<UniquePtr<RangePaintInfo>> rangeItems;
    5162             : 
    5163             :   // iterate over each range and collect them into the rangeItems array.
    5164             :   // This is done so that the size of selection can be determined so as
    5165             :   // to allocate a surface area
    5166           0 :   uint32_t numRanges = aSelection->RangeCount();
    5167           0 :   NS_ASSERTION(numRanges > 0, "RenderSelection called with no selection");
    5168             : 
    5169           0 :   for (uint32_t r = 0; r < numRanges; r++)
    5170             :   {
    5171           0 :     RefPtr<nsRange> range = aSelection->GetRangeAt(r);
    5172             : 
    5173           0 :     UniquePtr<RangePaintInfo> info = CreateRangePaintInfo(range, area, true);
    5174           0 :     if (info && !rangeItems.AppendElement(std::move(info))) {
    5175           0 :       return nullptr;
    5176             :     }
    5177             :   }
    5178             : 
    5179             :   return PaintRangePaintInfo(rangeItems, aSelection, nullptr, area, aPoint,
    5180           0 :                              aScreenRect, aFlags);
    5181             : }
    5182             : 
    5183             : void
    5184           0 : PresShell::AddPrintPreviewBackgroundItem(nsDisplayListBuilder& aBuilder,
    5185             :                                          nsDisplayList&        aList,
    5186             :                                          nsIFrame*             aFrame,
    5187             :                                          const nsRect&         aBounds)
    5188             : {
    5189             :   aList.AppendToBottom(
    5190           0 :     MakeDisplayItem<nsDisplaySolidColor>(&aBuilder, aFrame, aBounds, NS_RGB(115, 115, 115)));
    5191           0 : }
    5192             : 
    5193             : static bool
    5194           0 : AddCanvasBackgroundColor(const nsDisplayList& aList, nsIFrame* aCanvasFrame,
    5195             :                          nscolor aColor, bool aCSSBackgroundColor)
    5196             : {
    5197           0 :   for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
    5198           0 :     const DisplayItemType type = i->GetType();
    5199             : 
    5200           0 :     if (i->Frame() == aCanvasFrame &&
    5201             :         type == DisplayItemType::TYPE_CANVAS_BACKGROUND_COLOR) {
    5202           0 :       nsDisplayCanvasBackgroundColor* bg = static_cast<nsDisplayCanvasBackgroundColor*>(i);
    5203           0 :       bg->SetExtraBackgroundColor(aColor);
    5204           0 :       return true;
    5205             :     }
    5206             : 
    5207             :     const bool isBlendContainer =
    5208           0 :       type == DisplayItemType::TYPE_BLEND_CONTAINER ||
    5209           0 :       type == DisplayItemType::TYPE_TABLE_BLEND_CONTAINER;
    5210             : 
    5211           0 :     nsDisplayList* sublist = i->GetSameCoordinateSystemChildren();
    5212           0 :     if (sublist && !(isBlendContainer && !aCSSBackgroundColor) &&
    5213           0 :         AddCanvasBackgroundColor(*sublist, aCanvasFrame, aColor, aCSSBackgroundColor))
    5214             :       return true;
    5215             :   }
    5216             :   return false;
    5217             : }
    5218             : 
    5219             : void
    5220           0 : PresShell::AddCanvasBackgroundColorItem(nsDisplayListBuilder& aBuilder,
    5221             :                                         nsDisplayList&        aList,
    5222             :                                         nsIFrame*             aFrame,
    5223             :                                         const nsRect&         aBounds,
    5224             :                                         nscolor               aBackstopColor,
    5225             :                                         uint32_t              aFlags)
    5226             : {
    5227           0 :   if (aBounds.IsEmpty()) {
    5228           0 :     return;
    5229             :   }
    5230             :   // We don't want to add an item for the canvas background color if the frame
    5231             :   // (sub)tree we are painting doesn't include any canvas frames. There isn't
    5232             :   // an easy way to check this directly, but if we check if the root of the
    5233             :   // (sub)tree we are painting is a canvas frame that should cover us in all
    5234             :   // cases (it will usually be a viewport frame when we have a canvas frame in
    5235             :   // the (sub)tree).
    5236           0 :   if (!(aFlags & nsIPresShell::FORCE_DRAW) &&
    5237           0 :       !nsCSSRendering::IsCanvasFrame(aFrame)) {
    5238             :     return;
    5239             :   }
    5240             : 
    5241           0 :   nscolor bgcolor = NS_ComposeColors(aBackstopColor, mCanvasBackgroundColor);
    5242           0 :   if (NS_GET_A(bgcolor) == 0)
    5243             :     return;
    5244             : 
    5245             :   // To make layers work better, we want to avoid having a big non-scrolled
    5246             :   // color background behind a scrolled transparent background. Instead,
    5247             :   // we'll try to move the color background into the scrolled content
    5248             :   // by making nsDisplayCanvasBackground paint it.
    5249             :   // If we're only adding an unscrolled item, then pretend that we've
    5250             :   // already done it.
    5251           0 :   bool addedScrollingBackgroundColor = (aFlags & APPEND_UNSCROLLED_ONLY);
    5252           0 :   if (!aFrame->GetParent() && !addedScrollingBackgroundColor) {
    5253             :     nsIScrollableFrame* sf =
    5254           0 :       aFrame->PresShell()->GetRootScrollFrameAsScrollable();
    5255           0 :     if (sf) {
    5256           0 :       nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame());
    5257           0 :       if (canvasFrame && canvasFrame->IsVisibleForPainting(&aBuilder)) {
    5258             :         addedScrollingBackgroundColor =
    5259           0 :           AddCanvasBackgroundColor(aList, canvasFrame, bgcolor, mHasCSSBackgroundColor);
    5260             :       }
    5261             :     }
    5262             :   }
    5263             : 
    5264             :   // With async scrolling, we'd like to have two instances of the background
    5265             :   // color: one that scrolls with the content (for the reasons stated above),
    5266             :   // and one underneath which does not scroll with the content, but which can
    5267             :   // be shown during checkerboarding and overscroll.
    5268             :   // We can only do that if the color is opaque.
    5269           0 :   bool forceUnscrolledItem = nsLayoutUtils::UsesAsyncScrolling(aFrame) &&
    5270           0 :                              NS_GET_A(bgcolor) == 255;
    5271           0 :   if ((aFlags & ADD_FOR_SUBDOC) && gfxPrefs::LayoutUseContainersForRootFrames()) {
    5272             :     // If we're using ContainerLayers for a subdoc, then any items we add here will
    5273             :     // still be scrolled (since we're inside the container at this point), so don't
    5274             :     // bother and we will do it manually later.
    5275           0 :     forceUnscrolledItem = false;
    5276             :   }
    5277             : 
    5278           0 :   if (!addedScrollingBackgroundColor || forceUnscrolledItem) {
    5279             :     aList.AppendToBottom(
    5280           0 :       MakeDisplayItem<nsDisplaySolidColor>(&aBuilder, aFrame, aBounds, bgcolor));
    5281             :   }
    5282             : }
    5283             : 
    5284           0 : static bool IsTransparentContainerElement(nsPresContext* aPresContext)
    5285             : {
    5286           0 :   nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
    5287           0 :   if (!docShell) {
    5288             :     return false;
    5289             :   }
    5290             : 
    5291           0 :   nsCOMPtr<nsPIDOMWindowOuter> pwin = docShell->GetWindow();
    5292           0 :   if (!pwin)
    5293             :     return false;
    5294           0 :   nsCOMPtr<Element> containerElement = pwin->GetFrameElementInternal();
    5295             : 
    5296           0 :   TabChild* tab = TabChild::GetFrom(docShell);
    5297           0 :   if (tab) {
    5298             :     // Check if presShell is the top PresShell. Only the top can
    5299             :     // influence the canvas background color.
    5300           0 :     nsCOMPtr<nsIPresShell> presShell = aPresContext->GetPresShell();
    5301           0 :     nsCOMPtr<nsIPresShell> topPresShell = tab->GetPresShell();
    5302           0 :     if (presShell != topPresShell) {
    5303           0 :       tab = nullptr;
    5304             :     }
    5305             :   }
    5306             : 
    5307           0 :   return (containerElement &&
    5308           0 :           containerElement->HasAttr(kNameSpaceID_None, nsGkAtoms::transparent))
    5309           0 :     || (tab && tab->IsTransparent());
    5310             : }
    5311             : 
    5312           0 : nscolor PresShell::GetDefaultBackgroundColorToDraw()
    5313             : {
    5314           0 :   if (!mPresContext || !mPresContext->GetBackgroundColorDraw()) {
    5315             :     return NS_RGB(255,255,255);
    5316             :   }
    5317           0 :   return mPresContext->DefaultBackgroundColor();
    5318             : }
    5319             : 
    5320           0 : void PresShell::UpdateCanvasBackground()
    5321             : {
    5322             :   // If we have a frame tree and it has style information that
    5323             :   // specifies the background color of the canvas, update our local
    5324             :   // cache of that color.
    5325           0 :   nsIFrame* rootStyleFrame = FrameConstructor()->GetRootElementStyleFrame();
    5326           0 :   if (rootStyleFrame) {
    5327             :     ComputedStyle* bgStyle =
    5328           0 :       nsCSSRendering::FindRootFrameBackground(rootStyleFrame);
    5329             :     // XXX We should really be passing the canvasframe, not the root element
    5330             :     // style frame but we don't have access to the canvasframe here. It isn't
    5331             :     // a problem because only a few frames can return something other than true
    5332             :     // and none of them would be a canvas frame or root element style frame.
    5333             :     bool drawBackgroundImage;
    5334             :     bool drawBackgroundColor;
    5335           0 :     mCanvasBackgroundColor =
    5336           0 :       nsCSSRendering::DetermineBackgroundColor(mPresContext, bgStyle,
    5337             :                                                rootStyleFrame,
    5338             :                                                drawBackgroundImage,
    5339             :                                                drawBackgroundColor);
    5340           0 :     mHasCSSBackgroundColor = drawBackgroundColor;
    5341           0 :     if (mPresContext->IsRootContentDocument() &&
    5342           0 :         !IsTransparentContainerElement(mPresContext)) {
    5343           0 :       mCanvasBackgroundColor =
    5344           0 :         NS_ComposeColors(GetDefaultBackgroundColorToDraw(), mCanvasBackgroundColor);
    5345             :     }
    5346             :   }
    5347             : 
    5348             :   // If the root element of the document (ie html) has style 'display: none'
    5349             :   // then the document's background color does not get drawn; cache the
    5350             :   // color we actually draw.
    5351           0 :   if (!FrameConstructor()->GetRootElementFrame()) {
    5352           0 :     mCanvasBackgroundColor = GetDefaultBackgroundColorToDraw();
    5353             :   }
    5354           0 : }
    5355             : 
    5356           0 : nscolor PresShell::ComputeBackstopColor(nsView* aDisplayRoot)
    5357             : {
    5358           0 :   nsIWidget* widget = aDisplayRoot->GetWidget();
    5359           0 :   if (widget && (widget->GetTransparencyMode() != eTransparencyOpaque ||
    5360           0 :                  widget->WidgetPaintsBackground())) {
    5361             :     // Within a transparent widget, so the backstop color must be
    5362             :     // totally transparent.
    5363             :     return NS_RGBA(0,0,0,0);
    5364             :   }
    5365             :   // Within an opaque widget (or no widget at all), so the backstop
    5366             :   // color must be totally opaque. The user's default background
    5367             :   // as reported by the prescontext is guaranteed to be opaque.
    5368           0 :   return GetDefaultBackgroundColorToDraw();
    5369             : }
    5370             : 
    5371             : struct PaintParams {
    5372             :   nscolor mBackgroundColor;
    5373             : };
    5374             : 
    5375           0 : LayerManager* PresShell::GetLayerManager()
    5376             : {
    5377           0 :   NS_ASSERTION(mViewManager, "Should have view manager");
    5378             : 
    5379           0 :   nsView* rootView = mViewManager->GetRootView();
    5380           0 :   if (rootView) {
    5381           0 :     if (nsIWidget* widget = rootView->GetWidget()) {
    5382           0 :       return widget->GetLayerManager();
    5383             :     }
    5384             :   }
    5385             :   return nullptr;
    5386             : }
    5387             : 
    5388           0 : bool PresShell::AsyncPanZoomEnabled()
    5389             : {
    5390           0 :   NS_ASSERTION(mViewManager, "Should have view manager");
    5391           0 :   nsView* rootView = mViewManager->GetRootView();
    5392           0 :   if (rootView) {
    5393           0 :     if (nsIWidget* widget = rootView->GetWidget()) {
    5394           0 :       return widget->AsyncPanZoomEnabled();
    5395             :     }
    5396             :   }
    5397           0 :   return gfxPlatform::AsyncPanZoomEnabled();
    5398             : }
    5399             : 
    5400           0 : void PresShell::SetIgnoreViewportScrolling(bool aIgnore)
    5401             : {
    5402           0 :   if (IgnoringViewportScrolling() == aIgnore) {
    5403           0 :     return;
    5404             :   }
    5405           0 :   RenderingState state(this);
    5406           0 :   state.mRenderFlags = ChangeFlag(state.mRenderFlags, aIgnore,
    5407             :                                   STATE_IGNORING_VIEWPORT_SCROLLING);
    5408           0 :   SetRenderingState(state);
    5409             : }
    5410             : 
    5411           0 : nsresult PresShell::SetResolutionImpl(float aResolution, bool aScaleToResolution)
    5412             : {
    5413           0 :   if (!(aResolution > 0.0)) {
    5414             :     return NS_ERROR_ILLEGAL_VALUE;
    5415             :   }
    5416           0 :   if (aResolution == mResolution.valueOr(0.0)) {
    5417           0 :     MOZ_ASSERT(mResolution.isSome());
    5418             :     return NS_OK;
    5419             :   }
    5420           0 :   RenderingState state(this);
    5421           0 :   state.mResolution = Some(aResolution);
    5422           0 :   SetRenderingState(state);
    5423           0 :   mScaleToResolution = aScaleToResolution;
    5424           0 :   if (mMobileViewportManager) {
    5425           0 :     mMobileViewportManager->ResolutionUpdated();
    5426             :   }
    5427             : 
    5428           0 :   return NS_OK;
    5429             : }
    5430             : 
    5431           0 : bool PresShell::ScaleToResolution() const
    5432             : {
    5433           0 :   return mScaleToResolution;
    5434             : }
    5435             : 
    5436           0 : float PresShell::GetCumulativeResolution()
    5437             : {
    5438           0 :   float resolution = GetResolution();
    5439           0 :   nsPresContext* parentCtx = GetPresContext()->GetParentPresContext();
    5440           0 :   if (parentCtx) {
    5441           0 :     resolution *= parentCtx->PresShell()->GetCumulativeResolution();
    5442             :   }
    5443           0 :   return resolution;
    5444             : }
    5445             : 
    5446           0 : float PresShell::GetCumulativeNonRootScaleResolution()
    5447             : {
    5448           0 :   float resolution = 1.0;
    5449           0 :   nsIPresShell* currentShell = this;
    5450           0 :   while (currentShell) {
    5451           0 :     nsPresContext* currentCtx = currentShell->GetPresContext();
    5452           0 :     if (currentCtx != currentCtx->GetRootPresContext()) {
    5453           0 :       resolution *=  currentShell->ScaleToResolution() ? currentShell->GetResolution() : 1.0f;
    5454             :     }
    5455           0 :     nsPresContext* parentCtx = currentCtx->GetParentPresContext();
    5456           0 :     if (parentCtx) {
    5457           0 :       currentShell = parentCtx->PresShell();
    5458             :     } else {
    5459             :       currentShell = nullptr;
    5460             :     }
    5461             :   }
    5462           0 :   return resolution;
    5463             : }
    5464             : 
    5465           0 : void PresShell::SetRestoreResolution(float aResolution,
    5466             :                                      LayoutDeviceIntSize aDisplaySize)
    5467             : {
    5468           0 :   if (mMobileViewportManager) {
    5469           0 :     mMobileViewportManager->SetRestoreResolution(aResolution, aDisplaySize);
    5470             :   }
    5471           0 : }
    5472             : 
    5473           0 : void PresShell::SetRenderingState(const RenderingState& aState)
    5474             : {
    5475           0 :   if (mRenderFlags != aState.mRenderFlags) {
    5476             :     // Rendering state changed in a way that forces us to flush any
    5477             :     // retained layers we might already have.
    5478           0 :     LayerManager* manager = GetLayerManager();
    5479           0 :     if (manager) {
    5480           0 :       FrameLayerBuilder::InvalidateAllLayers(manager);
    5481             :     }
    5482             :   }
    5483             : 
    5484           0 :   mRenderFlags = aState.mRenderFlags;
    5485           0 :   mResolution = aState.mResolution;
    5486           0 : }
    5487             : 
    5488           0 : void PresShell::SynthesizeMouseMove(bool aFromScroll)
    5489             : {
    5490           0 :   if (!sSynthMouseMove)
    5491             :     return;
    5492             : 
    5493           0 :   if (mPaintingSuppressed || !mIsActive || !mPresContext) {
    5494             :     return;
    5495             :   }
    5496             : 
    5497           0 :   if (!mPresContext->IsRoot()) {
    5498           0 :     nsIPresShell* rootPresShell = GetRootPresShell();
    5499           0 :     if (rootPresShell) {
    5500           0 :       rootPresShell->SynthesizeMouseMove(aFromScroll);
    5501             :     }
    5502             :     return;
    5503             :   }
    5504             : 
    5505           0 :   if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE))
    5506             :     return;
    5507             : 
    5508           0 :   if (!mSynthMouseMoveEvent.IsPending()) {
    5509             :     RefPtr<nsSynthMouseMoveEvent> ev =
    5510           0 :         new nsSynthMouseMoveEvent(this, aFromScroll);
    5511             : 
    5512           0 :     if (!GetPresContext()->RefreshDriver()
    5513           0 :                          ->AddRefreshObserver(ev, FlushType::Display)) {
    5514           0 :       NS_WARNING("failed to dispatch nsSynthMouseMoveEvent");
    5515           0 :       return;
    5516             :     }
    5517             : 
    5518           0 :     mSynthMouseMoveEvent = std::move(ev);
    5519             :   }
    5520             : }
    5521             : 
    5522             : /**
    5523             :  * Find the first floating view with a widget in a postorder traversal of the
    5524             :  * view tree that contains the point. Thus more deeply nested floating views
    5525             :  * are preferred over their ancestors, and floating views earlier in the
    5526             :  * view hierarchy (i.e., added later) are preferred over their siblings.
    5527             :  * This is adequate for finding the "topmost" floating view under a point,
    5528             :  * given that floating views don't supporting having a specific z-index.
    5529             :  *
    5530             :  * We cannot exit early when aPt is outside the view bounds, because floating
    5531             :  * views aren't necessarily included in their parent's bounds, so this could
    5532             :  * traverse the entire view hierarchy --- use carefully.
    5533             :  */
    5534           0 : static nsView* FindFloatingViewContaining(nsView* aView, nsPoint aPt)
    5535             : {
    5536           0 :   if (aView->GetVisibility() == nsViewVisibility_kHide)
    5537             :     // No need to look into descendants.
    5538             :     return nullptr;
    5539             : 
    5540           0 :   nsIFrame* frame = aView->GetFrame();
    5541           0 :   if (frame) {
    5542           0 :     if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
    5543           0 :         !frame->PresShell()->IsActive()) {
    5544             :       return nullptr;
    5545             :     }
    5546             :   }
    5547             : 
    5548           0 :   for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
    5549           0 :     nsView* r = FindFloatingViewContaining(v, v->ConvertFromParentCoords(aPt));
    5550           0 :     if (r)
    5551             :       return r;
    5552             :   }
    5553             : 
    5554           0 :   if (aView->GetFloating() && aView->HasWidget() &&
    5555           0 :       aView->GetDimensions().Contains(aPt))
    5556             :     return aView;
    5557             : 
    5558           0 :   return nullptr;
    5559             : }
    5560             : 
    5561             : /*
    5562             :  * This finds the first view containing the given point in a postorder
    5563             :  * traversal of the view tree that contains the point, assuming that the
    5564             :  * point is not in a floating view.  It assumes that only floating views
    5565             :  * extend outside the bounds of their parents.
    5566             :  *
    5567             :  * This methods should only be called if FindFloatingViewContaining
    5568             :  * returns null.
    5569             :  */
    5570           0 : static nsView* FindViewContaining(nsView* aView, nsPoint aPt)
    5571             : {
    5572           0 :   if (!aView->GetDimensions().Contains(aPt) ||
    5573           0 :       aView->GetVisibility() == nsViewVisibility_kHide) {
    5574             :     return nullptr;
    5575             :   }
    5576             : 
    5577           0 :   nsIFrame* frame = aView->GetFrame();
    5578           0 :   if (frame) {
    5579           0 :     if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
    5580           0 :         !frame->PresShell()->IsActive()) {
    5581             :       return nullptr;
    5582             :     }
    5583             :   }
    5584             : 
    5585           0 :   for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
    5586           0 :     nsView* r = FindViewContaining(v, v->ConvertFromParentCoords(aPt));
    5587           0 :     if (r)
    5588             :       return r;
    5589             :   }
    5590             : 
    5591             :   return aView;
    5592             : }
    5593             : 
    5594             : void
    5595           0 : PresShell::ProcessSynthMouseMoveEvent(bool aFromScroll)
    5596             : {
    5597             :   // If drag session has started, we shouldn't synthesize mousemove event.
    5598           0 :   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
    5599           0 :   if (dragSession) {
    5600           0 :     mSynthMouseMoveEvent.Forget();
    5601           0 :     return;
    5602             :   }
    5603             : 
    5604             :   // allow new event to be posted while handling this one only if the
    5605             :   // source of the event is a scroll (to prevent infinite reflow loops)
    5606           0 :   if (aFromScroll) {
    5607           0 :     mSynthMouseMoveEvent.Forget();
    5608             :   }
    5609             : 
    5610           0 :   nsView* rootView = mViewManager ? mViewManager->GetRootView() : nullptr;
    5611           0 :   if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) ||
    5612           0 :       !rootView || !rootView->HasWidget() || !mPresContext) {
    5613           0 :     mSynthMouseMoveEvent.Forget();
    5614             :     return;
    5615             :   }
    5616             : 
    5617           0 :   NS_ASSERTION(mPresContext->IsRoot(), "Only a root pres shell should be here");
    5618             : 
    5619             :   // Hold a ref to ourselves so DispatchEvent won't destroy us (since
    5620             :   // we need to access members after we call DispatchEvent).
    5621           0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
    5622             : 
    5623             : #ifdef DEBUG_MOUSE_LOCATION
    5624             :   printf("[ps=%p]synthesizing mouse move to (%d,%d)\n",
    5625             :          this, mMouseLocation.x, mMouseLocation.y);
    5626             : #endif
    5627             : 
    5628           0 :   int32_t APD = mPresContext->AppUnitsPerDevPixel();
    5629             : 
    5630             :   // We need a widget to put in the event we are going to dispatch so we look
    5631             :   // for a view that has a widget and the mouse location is over. We first look
    5632             :   // for floating views, if there isn't one we use the root view. |view| holds
    5633             :   // that view.
    5634           0 :   nsView* view = nullptr;
    5635             : 
    5636             :   // The appunits per devpixel ratio of |view|.
    5637             :   int32_t viewAPD;
    5638             : 
    5639             :   // mRefPoint will be mMouseLocation relative to the widget of |view|, the
    5640             :   // widget we will put in the event we dispatch, in viewAPD appunits
    5641           0 :   nsPoint refpoint(0, 0);
    5642             : 
    5643             :   // We always dispatch the event to the pres shell that contains the view that
    5644             :   // the mouse is over. pointVM is the VM of that pres shell.
    5645           0 :   nsViewManager *pointVM = nullptr;
    5646             : 
    5647             :   // This could be a bit slow (traverses entire view hierarchy)
    5648             :   // but it's OK to do it once per synthetic mouse event
    5649           0 :   view = FindFloatingViewContaining(rootView, mMouseLocation);
    5650           0 :   if (!view) {
    5651           0 :     view = rootView;
    5652           0 :     nsView *pointView = FindViewContaining(rootView, mMouseLocation);
    5653             :     // pointView can be null in situations related to mouse capture
    5654           0 :     pointVM = (pointView ? pointView : view)->GetViewManager();
    5655           0 :     refpoint = mMouseLocation + rootView->ViewToWidgetOffset();
    5656           0 :     viewAPD = APD;
    5657             :   } else {
    5658           0 :     pointVM = view->GetViewManager();
    5659           0 :     nsIFrame* frame = view->GetFrame();
    5660           0 :     NS_ASSERTION(frame, "floating views can't be anonymous");
    5661           0 :     viewAPD = frame->PresContext()->AppUnitsPerDevPixel();
    5662           0 :     refpoint = mMouseLocation.ScaleToOtherAppUnits(APD, viewAPD);
    5663           0 :     refpoint -= view->GetOffsetTo(rootView);
    5664           0 :     refpoint += view->ViewToWidgetOffset();
    5665             :   }
    5666           0 :   NS_ASSERTION(view->GetWidget(), "view should have a widget here");
    5667             :   WidgetMouseEvent event(true, eMouseMove, view->GetWidget(),
    5668           0 :                          WidgetMouseEvent::eSynthesized);
    5669             :   event.mRefPoint =
    5670           0 :     LayoutDeviceIntPoint::FromAppUnitsToNearest(refpoint, viewAPD);
    5671           0 :   event.mTime = PR_IntervalNow();
    5672             :   // XXX set event.mModifiers ?
    5673             :   // XXX mnakano I think that we should get the latest information from widget.
    5674             : 
    5675           0 :   nsCOMPtr<nsIPresShell> shell = pointVM->GetPresShell();
    5676           0 :   if (shell) {
    5677             :     // Since this gets run in a refresh tick there isn't an InputAPZContext on
    5678             :     // the stack from the nsBaseWidget. We need to simulate one with at least
    5679             :     // the correct target guid, so that the correct callback transform gets
    5680             :     // applied if this event goes to a child process. The input block id is set
    5681             :     // to 0 because this is a synthetic event which doesn't really belong to any
    5682             :     // input block. Same for the APZ response field.
    5683           0 :     InputAPZContext apzContext(mMouseEventTargetGuid, 0, nsEventStatus_eIgnore);
    5684           0 :     shell->DispatchSynthMouseMove(&event);
    5685             :   }
    5686             : 
    5687           0 :   if (!aFromScroll) {
    5688           0 :     mSynthMouseMoveEvent.Forget();
    5689             :   }
    5690             : }
    5691             : 
    5692             : /* static */ void
    5693           0 : PresShell::MarkFramesInListApproximatelyVisible(const nsDisplayList& aList)
    5694             : {
    5695           0 :   for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
    5696           0 :     nsDisplayList* sublist = item->GetChildren();
    5697           0 :     if (sublist) {
    5698           0 :       MarkFramesInListApproximatelyVisible(*sublist);
    5699           0 :       continue;
    5700             :     }
    5701             : 
    5702           0 :     nsIFrame* frame = item->Frame();
    5703           0 :     MOZ_ASSERT(frame);
    5704             : 
    5705           0 :     if (!frame->TrackingVisibility()) {
    5706             :       continue;
    5707             :     }
    5708             : 
    5709             :     // Use the presshell containing the frame.
    5710           0 :     auto* presShell = static_cast<PresShell*>(frame->PresShell());
    5711           0 :     MOZ_ASSERT(!presShell->AssumeAllFramesVisible());
    5712           0 :     if (presShell->mApproximatelyVisibleFrames.EnsureInserted(frame)) {
    5713             :       // The frame was added to mApproximatelyVisibleFrames, so increment its visible count.
    5714           0 :       frame->IncApproximateVisibleCount();
    5715             :     }
    5716             :   }
    5717           0 : }
    5718             : 
    5719             : /* static */ void
    5720           0 : PresShell::DecApproximateVisibleCount(VisibleFrames& aFrames,
    5721             :                                       const Maybe<OnNonvisible>& aNonvisibleAction
    5722             :                                         /* = Nothing() */)
    5723             : {
    5724           0 :   for (auto iter = aFrames.Iter(); !iter.Done(); iter.Next()) {
    5725           0 :     nsIFrame* frame = iter.Get()->GetKey();
    5726             :     // Decrement the frame's visible count if we're still tracking its
    5727             :     // visibility. (We may not be, if the frame disabled visibility tracking
    5728             :     // after we added it to the visible frames list.)
    5729           0 :     if (frame->TrackingVisibility()) {
    5730           0 :       frame->DecApproximateVisibleCount(aNonvisibleAction);
    5731             :     }
    5732             :   }
    5733           0 : }
    5734             : 
    5735             : void
    5736           0 : PresShell::RebuildApproximateFrameVisibilityDisplayList(const nsDisplayList& aList)
    5737             : {
    5738           0 :   MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "already visited?");
    5739           0 :   mApproximateFrameVisibilityVisited = true;
    5740             : 
    5741             :   // Remove the entries of the mApproximatelyVisibleFrames hashtable and put
    5742             :   // them in oldApproxVisibleFrames.
    5743           0 :   VisibleFrames oldApproximatelyVisibleFrames;
    5744           0 :   mApproximatelyVisibleFrames.SwapElements(oldApproximatelyVisibleFrames);
    5745             : 
    5746           0 :   MarkFramesInListApproximatelyVisible(aList);
    5747             : 
    5748           0 :   DecApproximateVisibleCount(oldApproximatelyVisibleFrames);
    5749           0 : }
    5750             : 
    5751             : /* static */ void
    5752           0 : PresShell::ClearApproximateFrameVisibilityVisited(nsView* aView, bool aClear)
    5753             : {
    5754           0 :   nsViewManager* vm = aView->GetViewManager();
    5755           0 :   if (aClear) {
    5756           0 :     PresShell* presShell = static_cast<PresShell*>(vm->GetPresShell());
    5757           0 :     if (!presShell->mApproximateFrameVisibilityVisited) {
    5758           0 :       presShell->ClearApproximatelyVisibleFramesList();
    5759             :     }
    5760           0 :     presShell->mApproximateFrameVisibilityVisited = false;
    5761             :   }
    5762           0 :   for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
    5763           0 :     ClearApproximateFrameVisibilityVisited(v, v->GetViewManager() != vm);
    5764             :   }
    5765           0 : }
    5766             : 
    5767             : void
    5768           0 : PresShell::ClearApproximatelyVisibleFramesList(const Maybe<OnNonvisible>& aNonvisibleAction
    5769             :                                                  /* = Nothing() */)
    5770             : {
    5771           0 :   DecApproximateVisibleCount(mApproximatelyVisibleFrames, aNonvisibleAction);
    5772           0 :   mApproximatelyVisibleFrames.Clear();
    5773           0 : }
    5774             : 
    5775             : void
    5776           0 : PresShell::MarkFramesInSubtreeApproximatelyVisible(nsIFrame* aFrame,
    5777             :                                                    const nsRect& aRect,
    5778             :                                                    bool aRemoveOnly /* = false */)
    5779             : {
    5780           0 :   MOZ_ASSERT(aFrame->PresShell() == this, "wrong presshell");
    5781             : 
    5782           0 :   if (aFrame->TrackingVisibility() &&
    5783           0 :       aFrame->StyleVisibility()->IsVisible() &&
    5784           0 :       (!aRemoveOnly || aFrame->GetVisibility() == Visibility::APPROXIMATELY_VISIBLE)) {
    5785           0 :     MOZ_ASSERT(!AssumeAllFramesVisible());
    5786           0 :     if (mApproximatelyVisibleFrames.EnsureInserted(aFrame)) {
    5787             :       // The frame was added to mApproximatelyVisibleFrames, so increment its visible count.
    5788           0 :       aFrame->IncApproximateVisibleCount();
    5789             :     }
    5790             :   }
    5791             : 
    5792           0 :   nsSubDocumentFrame* subdocFrame = do_QueryFrame(aFrame);
    5793           0 :   if (subdocFrame) {
    5794             :     nsIPresShell* presShell = subdocFrame->GetSubdocumentPresShellForPainting(
    5795           0 :       nsSubDocumentFrame::IGNORE_PAINT_SUPPRESSION);
    5796           0 :     if (presShell && !presShell->AssumeAllFramesVisible()) {
    5797           0 :       nsRect rect = aRect;
    5798           0 :       nsIFrame* root = presShell->GetRootFrame();
    5799           0 :       if (root) {
    5800           0 :         rect.MoveBy(aFrame->GetOffsetToCrossDoc(root));
    5801             :       } else {
    5802           0 :         rect.MoveBy(-aFrame->GetContentRectRelativeToSelf().TopLeft());
    5803             :       }
    5804           0 :       rect = rect.ScaleToOtherAppUnitsRoundOut(
    5805             :         aFrame->PresContext()->AppUnitsPerDevPixel(),
    5806             :         presShell->GetPresContext()->AppUnitsPerDevPixel());
    5807             : 
    5808           0 :       presShell->RebuildApproximateFrameVisibility(&rect);
    5809             :     }
    5810           0 :     return;
    5811             :   }
    5812             : 
    5813           0 :   nsRect rect = aRect;
    5814             : 
    5815           0 :   nsIScrollableFrame* scrollFrame = do_QueryFrame(aFrame);
    5816           0 :   if (scrollFrame) {
    5817           0 :     bool ignoreDisplayPort = false;
    5818           0 :     if (nsLayoutUtils::IsMissingDisplayPortBaseRect(aFrame->GetContent())) {
    5819             :       // We can properly set the base rect for root scroll frames on top level
    5820             :       // and root content documents. Otherwise the base rect we compute might
    5821             :       // be way too big without the limiting that
    5822             :       // ScrollFrameHelper::DecideScrollableLayer does, so we just ignore the
    5823             :       // displayport in that case.
    5824           0 :       nsPresContext* pc = aFrame->PresContext();
    5825           0 :       if (scrollFrame->IsRootScrollFrameOfDocument() &&
    5826           0 :           (pc->IsRootContentDocument() || !pc->GetParentPresContext())) {
    5827             :         nsRect baseRect =
    5828           0 :           nsRect(nsPoint(0, 0), nsLayoutUtils::CalculateCompositionSizeForFrame(aFrame));
    5829           0 :         nsLayoutUtils::SetDisplayPortBase(aFrame->GetContent(), baseRect);
    5830             :       } else {
    5831             :         ignoreDisplayPort = true;
    5832             :       }
    5833             :     }
    5834             : 
    5835           0 :     nsRect displayPort;
    5836           0 :     bool usingDisplayport = !ignoreDisplayPort &&
    5837           0 :       nsLayoutUtils::GetDisplayPortForVisibilityTesting(
    5838           0 :         aFrame->GetContent(), &displayPort, RelativeTo::ScrollFrame);
    5839             : 
    5840           0 :     scrollFrame->NotifyApproximateFrameVisibilityUpdate(!usingDisplayport);
    5841             : 
    5842           0 :     if (usingDisplayport) {
    5843           0 :       rect = displayPort;
    5844             :     } else {
    5845           0 :       rect = rect.Intersect(scrollFrame->GetScrollPortRect());
    5846             :     }
    5847           0 :     rect = scrollFrame->ExpandRectToNearlyVisible(rect);
    5848             :   }
    5849             : 
    5850           0 :   bool preserves3DChildren = aFrame->Extend3DContext();
    5851             : 
    5852             :   // We assume all frames in popups are visible, so we skip them here.
    5853             :   const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList |
    5854           0 :                                     nsIFrame::kSelectPopupList);
    5855           0 :   for (nsIFrame::ChildListIterator childLists(aFrame);
    5856           0 :        !childLists.IsDone(); childLists.Next()) {
    5857           0 :     if (skip.Contains(childLists.CurrentID())) {
    5858             :       continue;
    5859             :     }
    5860             : 
    5861           0 :     for (nsIFrame* child : childLists.CurrentList()) {
    5862           0 :       nsRect r = rect - child->GetPosition();
    5863           0 :       if (!r.IntersectRect(r, child->GetVisualOverflowRect())) {
    5864           0 :         continue;
    5865             :       }
    5866           0 :       if (child->IsTransformed()) {
    5867             :         // for children of a preserve3d element we just pass down the same dirty rect
    5868           0 :         if (!preserves3DChildren || !child->Combines3DTransformWithAncestors()) {
    5869           0 :           const nsRect overflow = child->GetVisualOverflowRectRelativeToSelf();
    5870           0 :           nsRect out;
    5871           0 :           if (nsDisplayTransform::UntransformRect(r, overflow, child, &out)) {
    5872           0 :             r = out;
    5873             :           } else {
    5874             :             r.SetEmpty();
    5875             :           }
    5876             :         }
    5877             :       }
    5878           0 :       MarkFramesInSubtreeApproximatelyVisible(child, r);
    5879             :     }
    5880             :   }
    5881             : }
    5882             : 
    5883             : void
    5884           0 : PresShell::RebuildApproximateFrameVisibility(nsRect* aRect,
    5885             :                                              bool aRemoveOnly /* = false */)
    5886             : {
    5887           0 :   MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "already visited?");
    5888           0 :   mApproximateFrameVisibilityVisited = true;
    5889             : 
    5890           0 :   nsIFrame* rootFrame = GetRootFrame();
    5891           0 :   if (!rootFrame) {
    5892           0 :     return;
    5893             :   }
    5894             : 
    5895             :   // Remove the entries of the mApproximatelyVisibleFrames hashtable and put
    5896             :   // them in oldApproximatelyVisibleFrames.
    5897           0 :   VisibleFrames oldApproximatelyVisibleFrames;
    5898           0 :   mApproximatelyVisibleFrames.SwapElements(oldApproximatelyVisibleFrames);
    5899             : 
    5900           0 :   nsRect vis(nsPoint(0, 0), rootFrame->GetSize());
    5901           0 :   if (aRect) {
    5902           0 :     vis = *aRect;
    5903             :   }
    5904             : 
    5905           0 :   MarkFramesInSubtreeApproximatelyVisible(rootFrame, vis, aRemoveOnly);
    5906             : 
    5907           0 :   DecApproximateVisibleCount(oldApproximatelyVisibleFrames);
    5908             : }
    5909             : 
    5910             : void
    5911           0 : PresShell::UpdateApproximateFrameVisibility()
    5912             : {
    5913           0 :   DoUpdateApproximateFrameVisibility(/* aRemoveOnly = */ false);
    5914           0 : }
    5915             : 
    5916             : void
    5917           0 : PresShell::DoUpdateApproximateFrameVisibility(bool aRemoveOnly)
    5918             : {
    5919           0 :   MOZ_ASSERT(!mPresContext || mPresContext->IsRootContentDocument(),
    5920             :              "Updating approximate frame visibility on a non-root content document?");
    5921             : 
    5922           0 :   mUpdateApproximateFrameVisibilityEvent.Revoke();
    5923             : 
    5924           0 :   if (mHaveShutDown || mIsDestroying) {
    5925             :     return;
    5926             :   }
    5927             : 
    5928             :   // call update on that frame
    5929           0 :   nsIFrame* rootFrame = GetRootFrame();
    5930           0 :   if (!rootFrame) {
    5931           0 :     ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DISCARD_IMAGES));
    5932           0 :     return;
    5933             :   }
    5934             : 
    5935           0 :   RebuildApproximateFrameVisibility(/* aRect = */ nullptr, aRemoveOnly);
    5936           0 :   ClearApproximateFrameVisibilityVisited(rootFrame->GetView(), true);
    5937             : 
    5938             : #ifdef DEBUG_FRAME_VISIBILITY_DISPLAY_LIST
    5939             :   // This can be used to debug the frame walker by comparing beforeFrameList
    5940             :   // and mApproximatelyVisibleFrames in RebuildFrameVisibilityDisplayList to see if
    5941             :   // they produce the same results (mApproximatelyVisibleFrames holds the frames the
    5942             :   // display list thinks are visible, beforeFrameList holds the frames the
    5943             :   // frame walker thinks are visible).
    5944             :   nsDisplayListBuilder builder(rootFrame, nsDisplayListBuilderMode::FRAME_VISIBILITY, false);
    5945             :   nsRect updateRect(nsPoint(0, 0), rootFrame->GetSize());
    5946             :   nsIFrame* rootScroll = GetRootScrollFrame();
    5947             :   if (rootScroll) {
    5948             :     nsIContent* content = rootScroll->GetContent();
    5949             :     if (content) {
    5950             :       Unused << nsLayoutUtils::GetDisplayPortForVisibilityTesting(content, &updateRect,
    5951             :         RelativeTo::ScrollFrame);
    5952             :     }
    5953             : 
    5954             :     if (IgnoringViewportScrolling()) {
    5955             :       builder.SetIgnoreScrollFrame(rootScroll);
    5956             :     }
    5957             :   }
    5958             :   builder.IgnorePaintSuppression();
    5959             :   builder.EnterPresShell(rootFrame);
    5960             :   nsDisplayList list;
    5961             :   rootFrame->BuildDisplayListForStackingContext(&builder, updateRect, &list);
    5962             :   builder.LeavePresShell(rootFrame, &list);
    5963             : 
    5964             :   RebuildApproximateFrameVisibilityDisplayList(list);
    5965             : 
    5966             :   ClearApproximateFrameVisibilityVisited(rootFrame->GetView(), true);
    5967             : 
    5968             :   list.DeleteAll(&builder);
    5969             : #endif
    5970             : }
    5971             : 
    5972             : bool
    5973           0 : PresShell::AssumeAllFramesVisible()
    5974             : {
    5975             :   static bool sFrameVisibilityEnabled = true;
    5976             :   static bool sFrameVisibilityPrefCached = false;
    5977             : 
    5978           0 :   if (!sFrameVisibilityPrefCached) {
    5979             :     Preferences::AddBoolVarCache(&sFrameVisibilityEnabled,
    5980           0 :       "layout.framevisibility.enabled", true);
    5981           0 :     sFrameVisibilityPrefCached = true;
    5982             :   }
    5983             : 
    5984           0 :   if (!sFrameVisibilityEnabled || !mPresContext || !mDocument) {
    5985             :     return true;
    5986             :   }
    5987             : 
    5988             :   // We assume all frames are visible in print, print preview, chrome, and
    5989             :   // resource docs and don't keep track of them.
    5990           0 :   if (mPresContext->Type() == nsPresContext::eContext_PrintPreview ||
    5991           0 :       mPresContext->Type() == nsPresContext::eContext_Print ||
    5992           0 :       mPresContext->IsChrome() ||
    5993           0 :       mDocument->IsResourceDoc()) {
    5994             :     return true;
    5995             :   }
    5996             : 
    5997             :   // If we're assuming all frames are visible in the top level content
    5998             :   // document, we need to in subdocuments as well. Otherwise we can get in a
    5999             :   // situation where things like animations won't work in subdocuments because
    6000             :   // their frames appear not to be visible, since we won't schedule an image
    6001             :   // visibility update if the top level content document is assuming all
    6002             :   // frames are visible.
    6003             :   //
    6004             :   // Note that it's not safe to call IsRootContentDocument() if we're
    6005             :   // currently being destroyed, so we have to check that first.
    6006           0 :   if (!mHaveShutDown && !mIsDestroying &&
    6007           0 :       !mPresContext->IsRootContentDocument()) {
    6008             :     nsPresContext* presContext =
    6009           0 :       mPresContext->GetToplevelContentDocumentPresContext();
    6010           0 :     if (presContext && presContext->PresShell()->AssumeAllFramesVisible()) {
    6011             :       return true;
    6012             :     }
    6013             :   }
    6014             : 
    6015             :   return false;
    6016             : }
    6017             : 
    6018             : void
    6019           0 : PresShell::ScheduleApproximateFrameVisibilityUpdateSoon()
    6020             : {
    6021           0 :   if (AssumeAllFramesVisible()) {
    6022             :     return;
    6023             :   }
    6024             : 
    6025           0 :   if (!mPresContext) {
    6026             :     return;
    6027             :   }
    6028             : 
    6029           0 :   nsRefreshDriver* refreshDriver = mPresContext->RefreshDriver();
    6030           0 :   if (!refreshDriver) {
    6031             :     return;
    6032             :   }
    6033             : 
    6034             :   // Ask the refresh driver to update frame visibility soon.
    6035             :   refreshDriver->ScheduleFrameVisibilityUpdate();
    6036             : }
    6037             : 
    6038             : void
    6039           0 : PresShell::ScheduleApproximateFrameVisibilityUpdateNow()
    6040             : {
    6041           0 :   if (AssumeAllFramesVisible()) {
    6042           0 :     return;
    6043             :   }
    6044             : 
    6045           0 :   if (!mPresContext->IsRootContentDocument()) {
    6046           0 :     nsPresContext* presContext = mPresContext->GetToplevelContentDocumentPresContext();
    6047           0 :     if (!presContext)
    6048             :       return;
    6049           0 :     MOZ_ASSERT(presContext->IsRootContentDocument(),
    6050             :       "Didn't get a root prescontext from GetToplevelContentDocumentPresContext?");
    6051           0 :     presContext->PresShell()->ScheduleApproximateFrameVisibilityUpdateNow();
    6052           0 :     return;
    6053             :   }
    6054             : 
    6055           0 :   if (mHaveShutDown || mIsDestroying) {
    6056             :     return;
    6057             :   }
    6058             : 
    6059           0 :   if (mUpdateApproximateFrameVisibilityEvent.IsPending()) {
    6060             :     return;
    6061             :   }
    6062             : 
    6063             :   RefPtr<nsRunnableMethod<PresShell>> event =
    6064           0 :     NewRunnableMethod("PresShell::UpdateApproximateFrameVisibility",
    6065             :                       this,
    6066           0 :                       &PresShell::UpdateApproximateFrameVisibility);
    6067             :   nsresult rv =
    6068           0 :     mDocument->Dispatch(TaskCategory::Other, do_AddRef(event));
    6069             : 
    6070           0 :   if (NS_SUCCEEDED(rv)) {
    6071           0 :     mUpdateApproximateFrameVisibilityEvent = std::move(event);
    6072             :   }
    6073             : }
    6074             : 
    6075             : void
    6076           0 : PresShell::EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame)
    6077             : {
    6078           0 :   if (!aFrame->TrackingVisibility()) {
    6079           0 :     return;
    6080             :   }
    6081             : 
    6082           0 :   if (AssumeAllFramesVisible()) {
    6083           0 :     aFrame->IncApproximateVisibleCount();
    6084           0 :     return;
    6085             :   }
    6086             : 
    6087             : #ifdef DEBUG
    6088             :   // Make sure it's in this pres shell.
    6089           0 :   nsCOMPtr<nsIContent> content = aFrame->GetContent();
    6090           0 :   if (content) {
    6091           0 :     PresShell* shell = static_cast<PresShell*>(content->OwnerDoc()->GetShell());
    6092           0 :     MOZ_ASSERT(!shell || shell == this, "wrong shell");
    6093             :   }
    6094             : #endif
    6095             : 
    6096           0 :   if (mApproximatelyVisibleFrames.EnsureInserted(aFrame)) {
    6097             :     // We inserted a new entry.
    6098           0 :     aFrame->IncApproximateVisibleCount();
    6099             :   }
    6100             : }
    6101             : 
    6102             : void
    6103           0 : PresShell::RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame)
    6104             : {
    6105             : #ifdef DEBUG
    6106             :   // Make sure it's in this pres shell.
    6107           0 :   nsCOMPtr<nsIContent> content = aFrame->GetContent();
    6108           0 :   if (content) {
    6109           0 :     PresShell* shell = static_cast<PresShell*>(content->OwnerDoc()->GetShell());
    6110           0 :     MOZ_ASSERT(!shell || shell == this, "wrong shell");
    6111             :   }
    6112             : #endif
    6113             : 
    6114           0 :   if (AssumeAllFramesVisible()) {
    6115           0 :     MOZ_ASSERT(mApproximatelyVisibleFrames.Count() == 0,
    6116             :                "Shouldn't have any frames in the table");
    6117           0 :     return;
    6118             :   }
    6119             : 
    6120           0 :   if (mApproximatelyVisibleFrames.EnsureRemoved(aFrame) &&
    6121           0 :       aFrame->TrackingVisibility()) {
    6122             :     // aFrame was in the hashtable, and we're still tracking its visibility,
    6123             :     // so we need to decrement its visible count.
    6124           0 :     aFrame->DecApproximateVisibleCount();
    6125             :   }
    6126             : }
    6127             : 
    6128             : class nsAutoNotifyDidPaint
    6129             : {
    6130             : public:
    6131             :   nsAutoNotifyDidPaint(PresShell* aShell, uint32_t aFlags)
    6132           0 :     : mShell(aShell), mFlags(aFlags)
    6133             :   {
    6134             :   }
    6135           0 :   ~nsAutoNotifyDidPaint()
    6136           0 :   {
    6137           0 :     if (mFlags & nsIPresShell::PAINT_COMPOSITE) {
    6138           0 :       mShell->GetPresContext()->NotifyDidPaintForSubtree();
    6139             :     }
    6140           0 :   }
    6141             : 
    6142             : private:
    6143             :   PresShell* mShell;
    6144             :   uint32_t mFlags;
    6145             : };
    6146             : 
    6147             : void
    6148           0 : nsIPresShell::RecordShadowStyleChange(ShadowRoot& aShadowRoot)
    6149             : {
    6150           0 :   mStyleSet->RecordShadowStyleChange(aShadowRoot);
    6151           0 :   ApplicableStylesChanged();
    6152           0 : }
    6153             : 
    6154             : void
    6155           0 : PresShell::Paint(nsView*         aViewToPaint,
    6156             :                  const nsRegion& aDirtyRegion,
    6157             :                  uint32_t        aFlags)
    6158             : {
    6159             : #ifdef MOZ_GECKO_PROFILER
    6160           0 :   nsIURI* uri = mDocument->GetDocumentURI();
    6161           0 :   nsIDocument* contentRoot = GetPrimaryContentDocument();
    6162           0 :   if (contentRoot) {
    6163           0 :     uri = contentRoot->GetDocumentURI();
    6164             :   }
    6165           0 :   AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
    6166             :     "PresShell::Paint", GRAPHICS,
    6167             :     uri ? uri->GetSpecOrDefault() : NS_LITERAL_CSTRING("N/A"));
    6168             : #endif
    6169             : 
    6170           0 :   Maybe<js::AutoAssertNoContentJS> nojs;
    6171             : 
    6172             :   // On Android, Flash can call into content JS during painting, so we can't
    6173             :   // assert there. However, we don't rely on this assertion on Android because
    6174             :   // we don't paint while JS is running.
    6175             : #if !defined(MOZ_WIDGET_ANDROID)
    6176           0 :   if (!(aFlags & nsIPresShell::PAINT_COMPOSITE)) {
    6177             :     // We need to allow content JS when the flag is set since we may trigger
    6178             :     // MozAfterPaint events in content in those cases.
    6179           0 :     nojs.emplace(dom::danger::GetJSContext());
    6180             :   }
    6181             : #endif
    6182             : 
    6183           0 :   NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
    6184           0 :   NS_ASSERTION(aViewToPaint, "null view");
    6185             : 
    6186           0 :   MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "Should have been cleared");
    6187             : 
    6188           0 :   if (!mIsActive) {
    6189           0 :     return;
    6190             :   }
    6191             : 
    6192           0 :   if (gfxPrefs::APZKeyboardEnabled()) {
    6193             :     // Update the focus target for async keyboard scrolling. This will be forwarded
    6194             :     // to APZ by nsDisplayList::PaintRoot. We need to to do this before we enter
    6195             :     // the paint phase because dispatching eVoid events can cause layout to happen.
    6196           0 :     mAPZFocusTarget = FocusTarget(this, mAPZFocusSequenceNumber);
    6197             :   }
    6198             : 
    6199           0 :   nsPresContext* presContext = GetPresContext();
    6200           0 :   AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
    6201             : 
    6202           0 :   nsIFrame* frame = aViewToPaint->GetFrame();
    6203             : 
    6204             :   LayerManager* layerManager =
    6205           0 :     aViewToPaint->GetWidget()->GetLayerManager();
    6206           0 :   NS_ASSERTION(layerManager, "Must be in paint event");
    6207           0 :   bool shouldInvalidate = layerManager->NeedsWidgetInvalidation();
    6208             : 
    6209           0 :   nsAutoNotifyDidPaint notifyDidPaint(this, aFlags);
    6210             : 
    6211             :   // Whether or not we should set first paint when painting is suppressed
    6212             :   // is debatable. For now we'll do it because B2G relied on first paint
    6213             :   // to configure the viewport and we only want to do that when we have
    6214             :   // real content to paint. See Bug 798245
    6215           0 :   if (mIsFirstPaint && !mPaintingSuppressed) {
    6216           0 :     layerManager->SetIsFirstPaint();
    6217           0 :     mIsFirstPaint = false;
    6218             :   }
    6219             : 
    6220           0 :   if (!layerManager->BeginTransaction()) {
    6221           0 :     return;
    6222             :   }
    6223             : 
    6224             :   // Send an updated focus target with this transaction. Be sure to do this
    6225             :   // before we paint in the case this is an empty transaction.
    6226           0 :   layerManager->SetFocusTarget(mAPZFocusTarget);
    6227             : 
    6228           0 :   if (frame) {
    6229             :     // Try to do an empty transaction, if the frame tree does not
    6230             :     // need to be updated. Do not try to do an empty transaction on
    6231             :     // a non-retained layer manager (like the BasicLayerManager that
    6232             :     // draws the window title bar on Mac), because a) it won't work
    6233             :     // and b) below we don't want to clear NS_FRAME_UPDATE_LAYER_TREE,
    6234             :     // that will cause us to forget to update the real layer manager!
    6235             : 
    6236           0 :     if (!(aFlags & PAINT_LAYERS)) {
    6237           0 :       if (layerManager->EndEmptyTransaction()) {
    6238             :         return;
    6239             :       }
    6240           0 :       NS_WARNING("Must complete empty transaction when compositing!");
    6241             :     }
    6242             : 
    6243           0 :     if (!(aFlags & PAINT_SYNC_DECODE_IMAGES) &&
    6244           0 :         !(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE) &&
    6245           0 :         !mNextPaintCompressed) {
    6246             :       NotifySubDocInvalidationFunc computeInvalidFunc =
    6247           0 :         presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
    6248           0 :       bool computeInvalidRect = computeInvalidFunc ||
    6249           0 :                                 (layerManager->GetBackendType() == LayersBackend::LAYERS_BASIC);
    6250             : 
    6251           0 :       UniquePtr<LayerProperties> props;
    6252             :       // For WR, the layermanager has no root layer. We want to avoid
    6253             :       // calling ComputeDifferences in that case because it assumes non-null
    6254             :       // and crashes.
    6255           0 :       if (computeInvalidRect && layerManager->GetRoot()) {
    6256           0 :         props = LayerProperties::CloneFrom(layerManager->GetRoot());
    6257             :       }
    6258             : 
    6259           0 :       MaybeSetupTransactionIdAllocator(layerManager, presContext);
    6260             : 
    6261           0 :       if (layerManager->EndEmptyTransaction((aFlags & PAINT_COMPOSITE) ?
    6262           0 :             LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE)) {
    6263           0 :         nsIntRegion invalid;
    6264           0 :         bool areaOverflowed = false;
    6265           0 :         if (props) {
    6266           0 :           if (!props->ComputeDifferences(layerManager->GetRoot(), invalid, computeInvalidFunc)) {
    6267           0 :             areaOverflowed = true;
    6268             :           }
    6269             :         } else {
    6270           0 :           LayerProperties::ClearInvalidations(layerManager->GetRoot());
    6271             :         }
    6272           0 :         if (props && !areaOverflowed) {
    6273           0 :           if (!invalid.IsEmpty()) {
    6274           0 :             nsIntRect bounds = invalid.GetBounds();
    6275             :             nsRect rect(presContext->DevPixelsToAppUnits(bounds.x),
    6276             :                         presContext->DevPixelsToAppUnits(bounds.y),
    6277             :                         presContext->DevPixelsToAppUnits(bounds.width),
    6278           0 :                         presContext->DevPixelsToAppUnits(bounds.height));
    6279           0 :             if (shouldInvalidate) {
    6280           0 :               aViewToPaint->GetViewManager()->InvalidateViewNoSuppression(aViewToPaint, rect);
    6281             :             }
    6282           0 :             presContext->NotifyInvalidation(layerManager->GetLastTransactionId(), bounds);
    6283             :           }
    6284           0 :         } else if (shouldInvalidate) {
    6285           0 :           aViewToPaint->GetViewManager()->InvalidateView(aViewToPaint);
    6286             :         }
    6287             : 
    6288           0 :         frame->UpdatePaintCountForPaintedPresShells();
    6289             :         return;
    6290             :       }
    6291             :     }
    6292             :     frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE);
    6293             :   }
    6294           0 :   if (frame) {
    6295           0 :     frame->ClearPresShellsFromLastPaint();
    6296             :   }
    6297             : 
    6298           0 :   nscolor bgcolor = ComputeBackstopColor(aViewToPaint);
    6299             :   PaintFrameFlags flags = PaintFrameFlags::PAINT_WIDGET_LAYERS |
    6300           0 :                           PaintFrameFlags::PAINT_EXISTING_TRANSACTION;
    6301           0 :   if (!(aFlags & PAINT_COMPOSITE)) {
    6302             :     flags |= PaintFrameFlags::PAINT_NO_COMPOSITE;
    6303             :   }
    6304           0 :   if (aFlags & PAINT_SYNC_DECODE_IMAGES) {
    6305             :     flags |= PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES;
    6306             :   }
    6307           0 :   if (mNextPaintCompressed) {
    6308           0 :     flags |= PaintFrameFlags::PAINT_COMPRESSED;
    6309           0 :     mNextPaintCompressed = false;
    6310             :   }
    6311             : 
    6312           0 :   if (frame) {
    6313             :     // We can paint directly into the widget using its layer manager.
    6314             :     nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor,
    6315           0 :                               nsDisplayListBuilderMode::PAINTING, flags);
    6316           0 :     return;
    6317             :   }
    6318             : 
    6319           0 :   if (layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
    6320             :     // TODO: bug 1405465 - create a WR display list which simulates the color layer below.
    6321             :     return;
    6322             :   }
    6323             : 
    6324           0 :   RefPtr<ColorLayer> root = layerManager->CreateColorLayer();
    6325           0 :   if (root) {
    6326           0 :     nsPresContext* pc = GetPresContext();
    6327             :     nsIntRect bounds =
    6328           0 :       pc->GetVisibleArea().ToOutsidePixels(pc->AppUnitsPerDevPixel());
    6329           0 :     bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
    6330           0 :     root->SetColor(Color::FromABGR(bgcolor));
    6331           0 :     root->SetVisibleRegion(LayerIntRegion::FromUnknownRegion(bounds));
    6332           0 :     layerManager->SetRoot(root);
    6333             :   }
    6334           0 :   MaybeSetupTransactionIdAllocator(layerManager, presContext);
    6335           0 :   layerManager->EndTransaction(nullptr, nullptr, (aFlags & PAINT_COMPOSITE) ?
    6336           0 :     LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE);
    6337             : }
    6338             : 
    6339             : // static
    6340             : void
    6341           0 : nsIPresShell::SetCapturingContent(nsIContent* aContent, uint8_t aFlags)
    6342             : {
    6343             :   // If capture was set for pointer lock, don't unlock unless we are coming
    6344             :   // out of pointer lock explicitly.
    6345           0 :   if (!aContent && gCaptureInfo.mPointerLock &&
    6346             :       !(aFlags & CAPTURE_POINTERLOCK)) {
    6347             :     return;
    6348             :   }
    6349             : 
    6350           0 :   gCaptureInfo.mContent = nullptr;
    6351             : 
    6352             :   // only set capturing content if allowed or the CAPTURE_IGNOREALLOWED or
    6353             :   // CAPTURE_POINTERLOCK flags are used.
    6354           0 :   if ((aFlags & CAPTURE_IGNOREALLOWED) || gCaptureInfo.mAllowed ||
    6355             :       (aFlags & CAPTURE_POINTERLOCK)) {
    6356           0 :     if (aContent) {
    6357             :       gCaptureInfo.mContent = aContent;
    6358             :     }
    6359             :     // CAPTURE_POINTERLOCK is the same as CAPTURE_RETARGETTOELEMENT & CAPTURE_IGNOREALLOWED
    6360           0 :     gCaptureInfo.mRetargetToElement = ((aFlags & CAPTURE_RETARGETTOELEMENT) != 0) ||
    6361             :                                       ((aFlags & CAPTURE_POINTERLOCK) != 0);
    6362           0 :     gCaptureInfo.mPreventDrag = (aFlags & CAPTURE_PREVENTDRAG) != 0;
    6363           0 :     gCaptureInfo.mPointerLock = (aFlags & CAPTURE_POINTERLOCK) != 0;
    6364             :   }
    6365             : }
    6366             : 
    6367             : nsIContent*
    6368           0 : PresShell::GetCurrentEventContent()
    6369             : {
    6370           0 :   if (mCurrentEventContent &&
    6371           0 :       mCurrentEventContent->GetComposedDoc() != mDocument) {
    6372           0 :     mCurrentEventContent = nullptr;
    6373           0 :     mCurrentEventFrame = nullptr;
    6374             :   }
    6375           0 :   return mCurrentEventContent;
    6376             : }
    6377             : 
    6378             : nsIFrame*
    6379           0 : PresShell::GetCurrentEventFrame()
    6380             : {
    6381           0 :   if (MOZ_UNLIKELY(mIsDestroying)) {
    6382             :     return nullptr;
    6383             :   }
    6384             : 
    6385             :   // GetCurrentEventContent() makes sure the content is still in the
    6386             :   // same document that this pres shell belongs to. If not, then the
    6387             :   // frame shouldn't get an event, nor should we even assume its safe
    6388             :   // to try and find the frame.
    6389           0 :   nsIContent* content = GetCurrentEventContent();
    6390           0 :   if (!mCurrentEventFrame && content) {
    6391           0 :     mCurrentEventFrame = content->GetPrimaryFrame();
    6392           0 :     MOZ_ASSERT(!mCurrentEventFrame ||
    6393             :                mCurrentEventFrame->PresContext()->GetPresShell() == this);
    6394             :   }
    6395           0 :   return mCurrentEventFrame;
    6396             : }
    6397             : 
    6398             : nsIFrame*
    6399           0 : PresShell::GetEventTargetFrame()
    6400             : {
    6401           0 :   return GetCurrentEventFrame();
    6402             : }
    6403             : 
    6404             : already_AddRefed<nsIContent>
    6405           0 : PresShell::GetEventTargetContent(WidgetEvent* aEvent)
    6406             : {
    6407           0 :   nsCOMPtr<nsIContent> content = GetCurrentEventContent();
    6408           0 :   if (!content) {
    6409           0 :     nsIFrame* currentEventFrame = GetCurrentEventFrame();
    6410           0 :     if (currentEventFrame) {
    6411           0 :       currentEventFrame->GetContentForEvent(aEvent, getter_AddRefs(content));
    6412           0 :       NS_ASSERTION(!content || content->GetComposedDoc() == mDocument,
    6413             :                    "handing out content from a different doc");
    6414             :     }
    6415             :   }
    6416           0 :   return content.forget();
    6417             : }
    6418             : 
    6419             : void
    6420           0 : PresShell::PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent)
    6421             : {
    6422           0 :   if (mCurrentEventFrame || mCurrentEventContent) {
    6423           0 :     mCurrentEventFrameStack.InsertElementAt(0, mCurrentEventFrame);
    6424           0 :     mCurrentEventContentStack.InsertObjectAt(mCurrentEventContent, 0);
    6425             :   }
    6426           0 :   mCurrentEventFrame = aFrame;
    6427           0 :   mCurrentEventContent = aContent;
    6428           0 : }
    6429             : 
    6430             : void
    6431           0 : PresShell::PopCurrentEventInfo()
    6432             : {
    6433           0 :   mCurrentEventFrame = nullptr;
    6434           0 :   mCurrentEventContent = nullptr;
    6435             : 
    6436           0 :   if (0 != mCurrentEventFrameStack.Length()) {
    6437           0 :     mCurrentEventFrame = mCurrentEventFrameStack.ElementAt(0);
    6438           0 :     mCurrentEventFrameStack.RemoveElementAt(0);
    6439           0 :     mCurrentEventContent = mCurrentEventContentStack.ObjectAt(0);
    6440           0 :     mCurrentEventContentStack.RemoveObjectAt(0);
    6441             : 
    6442             :     // Don't use it if it has moved to a different document.
    6443           0 :     if (mCurrentEventContent &&
    6444           0 :         mCurrentEventContent->GetComposedDoc() != mDocument) {
    6445           0 :       mCurrentEventContent = nullptr;
    6446           0 :       mCurrentEventFrame = nullptr;
    6447             :     }
    6448             :   }
    6449           0 : }
    6450             : 
    6451           0 : bool PresShell::InZombieDocument(nsIContent *aContent)
    6452             : {
    6453             :   // If a content node points to a null document, or the document is not
    6454             :   // attached to a window, then it is possibly in a zombie document,
    6455             :   // about to be replaced by a newly loading document.
    6456             :   // Such documents cannot handle DOM events.
    6457             :   // It might actually be in a node not attached to any document,
    6458             :   // in which case there is not parent presshell to retarget it to.
    6459           0 :   nsIDocument* doc = aContent->GetComposedDoc();
    6460           0 :   return !doc || !doc->GetWindow();
    6461             : }
    6462             : 
    6463             : already_AddRefed<nsPIDOMWindowOuter>
    6464           0 : PresShell::GetRootWindow()
    6465             : {
    6466           0 :   nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
    6467           0 :   if (window) {
    6468           0 :     nsCOMPtr<nsPIDOMWindowOuter> rootWindow = window->GetPrivateRoot();
    6469           0 :     NS_ASSERTION(rootWindow, "nsPIDOMWindow::GetPrivateRoot() returns NULL");
    6470           0 :     return rootWindow.forget();
    6471             :   }
    6472             : 
    6473             :   // If we don't have DOM window, we're zombie, we should find the root window
    6474             :   // with our parent shell.
    6475           0 :   nsCOMPtr<nsIPresShell> parent = GetParentPresShellForEventHandling();
    6476           0 :   NS_ENSURE_TRUE(parent, nullptr);
    6477           0 :   return parent->GetRootWindow();
    6478             : }
    6479             : 
    6480             : already_AddRefed<nsPIDOMWindowOuter>
    6481           0 : PresShell::GetFocusedDOMWindowInOurWindow()
    6482             : {
    6483           0 :   nsCOMPtr<nsPIDOMWindowOuter> rootWindow = GetRootWindow();
    6484           0 :   NS_ENSURE_TRUE(rootWindow, nullptr);
    6485           0 :   nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    6486           0 :   nsFocusManager::GetFocusedDescendant(rootWindow,
    6487             :                                        nsFocusManager::eIncludeAllDescendants,
    6488           0 :                                        getter_AddRefs(focusedWindow));
    6489           0 :   return focusedWindow.forget();
    6490             : }
    6491             : 
    6492             : already_AddRefed<nsIContent>
    6493           0 : nsIPresShell::GetFocusedContentInOurWindow() const
    6494             : {
    6495           0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    6496           0 :   if (fm && mDocument) {
    6497           0 :     RefPtr<Element> focusedElement;
    6498           0 :     fm->GetFocusedElementForWindow(mDocument->GetWindow(), false, nullptr,
    6499           0 :                                    getter_AddRefs(focusedElement));
    6500           0 :     return focusedElement.forget();
    6501             :   }
    6502             :   return nullptr;
    6503             : }
    6504             : 
    6505             : already_AddRefed<nsIPresShell>
    6506           0 : PresShell::GetParentPresShellForEventHandling()
    6507             : {
    6508           0 :   NS_ENSURE_TRUE(mPresContext, nullptr);
    6509             : 
    6510             :   // Now, find the parent pres shell and send the event there
    6511           0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem = mPresContext->GetDocShell();
    6512           0 :   if (!treeItem) {
    6513           0 :     treeItem = mForwardingContainer.get();
    6514             :   }
    6515             : 
    6516             :   // Might have gone away, or never been around to start with
    6517           0 :   NS_ENSURE_TRUE(treeItem, nullptr);
    6518             : 
    6519           0 :   nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
    6520           0 :   treeItem->GetParent(getter_AddRefs(parentTreeItem));
    6521           0 :   nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentTreeItem);
    6522           0 :   NS_ENSURE_TRUE(parentDocShell && treeItem != parentTreeItem, nullptr);
    6523             : 
    6524           0 :   nsCOMPtr<nsIPresShell> parentPresShell = parentDocShell->GetPresShell();
    6525           0 :   return parentPresShell.forget();
    6526             : }
    6527             : 
    6528             : nsresult
    6529           0 : PresShell::RetargetEventToParent(WidgetGUIEvent* aEvent,
    6530             :                                  nsEventStatus* aEventStatus)
    6531             : {
    6532             :   // Send this events straight up to the parent pres shell.
    6533             :   // We do this for keystroke events in zombie documents or if either a frame
    6534             :   // or a root content is not present.
    6535             :   // That way at least the UI key bindings can work.
    6536             : 
    6537           0 :   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
    6538           0 :   nsCOMPtr<nsIPresShell> parentPresShell = GetParentPresShellForEventHandling();
    6539           0 :   NS_ENSURE_TRUE(parentPresShell, NS_ERROR_FAILURE);
    6540             : 
    6541             :   // Fake the event as though it's from the parent pres shell's root frame.
    6542           0 :   return parentPresShell->HandleEvent(parentPresShell->GetRootFrame(), aEvent, true, aEventStatus);
    6543             : }
    6544             : 
    6545             : void
    6546           0 : PresShell::DisableNonTestMouseEvents(bool aDisable)
    6547             : {
    6548           0 :   sDisableNonTestMouseEvents = aDisable;
    6549           0 : }
    6550             : 
    6551             : void
    6552           0 : PresShell::RecordMouseLocation(WidgetGUIEvent* aEvent)
    6553             : {
    6554           0 :   if (!mPresContext)
    6555             :     return;
    6556             : 
    6557           0 :   if (!mPresContext->IsRoot()) {
    6558           0 :     PresShell* rootPresShell = GetRootPresShell();
    6559           0 :     if (rootPresShell) {
    6560           0 :       rootPresShell->RecordMouseLocation(aEvent);
    6561             :     }
    6562             :     return;
    6563             :   }
    6564             : 
    6565           0 :   if ((aEvent->mMessage == eMouseMove &&
    6566           0 :        aEvent->AsMouseEvent()->mReason == WidgetMouseEvent::eReal) ||
    6567           0 :       aEvent->mMessage == eMouseEnterIntoWidget ||
    6568           0 :       aEvent->mMessage == eMouseDown ||
    6569             :       aEvent->mMessage == eMouseUp) {
    6570           0 :     nsIFrame* rootFrame = GetRootFrame();
    6571           0 :     if (!rootFrame) {
    6572           0 :       nsView* rootView = mViewManager->GetRootView();
    6573           0 :       mMouseLocation = nsLayoutUtils::TranslateWidgetToView(mPresContext,
    6574             :         aEvent->mWidget, aEvent->mRefPoint, rootView);
    6575           0 :       mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
    6576             :     } else {
    6577           0 :       mMouseLocation =
    6578           0 :         nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
    6579           0 :       mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
    6580             :     }
    6581             : #ifdef DEBUG_MOUSE_LOCATION
    6582             :     if (aEvent->mMessage == eMouseEnterIntoWidget) {
    6583             :       printf("[ps=%p]got mouse enter for %p\n",
    6584             :              this, aEvent->mWidget);
    6585             :     }
    6586             :     printf("[ps=%p]setting mouse location to (%d,%d)\n",
    6587             :            this, mMouseLocation.x, mMouseLocation.y);
    6588             : #endif
    6589           0 :     if (aEvent->mMessage == eMouseEnterIntoWidget) {
    6590           0 :       SynthesizeMouseMove(false);
    6591             :     }
    6592           0 :   } else if (aEvent->mMessage == eMouseExitFromWidget) {
    6593             :     // Although we only care about the mouse moving into an area for which this
    6594             :     // pres shell doesn't receive mouse move events, we don't check which widget
    6595             :     // the mouse exit was for since this seems to vary by platform.  Hopefully
    6596             :     // this won't matter at all since we'll get the mouse move or enter after
    6597             :     // the mouse exit when the mouse moves from one of our widgets into another.
    6598           0 :     mMouseLocation = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    6599           0 :     mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
    6600             : #ifdef DEBUG_MOUSE_LOCATION
    6601             :     printf("[ps=%p]got mouse exit for %p\n",
    6602             :            this, aEvent->mWidget);
    6603             :     printf("[ps=%p]clearing mouse location\n",
    6604             :            this);
    6605             : #endif
    6606             :   }
    6607             : }
    6608             : 
    6609             : static nsIFrame*
    6610           0 : GetNearestFrameContainingPresShell(nsIPresShell* aPresShell)
    6611             : {
    6612           0 :   nsView* view = aPresShell->GetViewManager()->GetRootView();
    6613           0 :   while (view && !view->GetFrame()) {
    6614           0 :     view = view->GetParent();
    6615             :   }
    6616             : 
    6617           0 :   nsIFrame* frame = nullptr;
    6618           0 :   if (view) {
    6619           0 :     frame = view->GetFrame();
    6620             :   }
    6621             : 
    6622           0 :   return frame;
    6623             : }
    6624             : 
    6625             : static bool
    6626           0 : FlushThrottledStyles(nsIDocument* aDocument, void *aData)
    6627             : {
    6628           0 :   nsIPresShell* shell = aDocument->GetShell();
    6629           0 :   if (shell && shell->IsVisible()) {
    6630           0 :     nsPresContext* presContext = shell->GetPresContext();
    6631           0 :     if (presContext) {
    6632           0 :       presContext->RestyleManager()->UpdateOnlyAnimationStyles();
    6633             :     }
    6634             :   }
    6635             : 
    6636           0 :   aDocument->EnumerateSubDocuments(FlushThrottledStyles, nullptr);
    6637           0 :   return true;
    6638             : }
    6639             : 
    6640             : bool
    6641           0 : PresShell::CanDispatchEvent(const WidgetGUIEvent* aEvent) const
    6642             : {
    6643             :   bool rv =
    6644           0 :     mPresContext && !mHaveShutDown && nsContentUtils::IsSafeToRunScript();
    6645           0 :   if (aEvent) {
    6646           0 :     rv &= (aEvent && aEvent->mWidget && !aEvent->mWidget->Destroyed());
    6647             :   }
    6648           0 :   return rv;
    6649             : }
    6650             : 
    6651             : /* static */ PresShell*
    6652           0 : PresShell::GetShellForEventTarget(nsIFrame* aFrame, nsIContent* aContent)
    6653             : {
    6654           0 :   if (aFrame) {
    6655           0 :     return static_cast<PresShell*>(aFrame->PresShell());
    6656             :   }
    6657           0 :   if (aContent) {
    6658           0 :     nsIDocument* doc = aContent->GetComposedDoc();
    6659           0 :     if (!doc) {
    6660             :       return nullptr;
    6661             :     }
    6662             :     return static_cast<PresShell*>(doc->GetShell());
    6663             :   }
    6664             :   return nullptr;
    6665             : }
    6666             : 
    6667             : /* static */ PresShell*
    6668           0 : PresShell::GetShellForTouchEvent(WidgetGUIEvent* aEvent)
    6669             : {
    6670           0 :   PresShell* shell = nullptr;
    6671           0 :   switch (aEvent->mMessage) {
    6672             :   case eTouchMove:
    6673             :   case eTouchCancel:
    6674             :   case eTouchEnd: {
    6675             :     // get the correct shell to dispatch to
    6676           0 :     WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
    6677           0 :     for (dom::Touch* touch : touchEvent->mTouches) {
    6678           0 :       if (!touch) {
    6679             :         break;
    6680             :       }
    6681             : 
    6682             :       RefPtr<dom::Touch> oldTouch =
    6683           0 :         TouchManager::GetCapturedTouch(touch->Identifier());
    6684           0 :       if (!oldTouch) {
    6685             :         break;
    6686             :       }
    6687             : 
    6688           0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(oldTouch->GetTarget());
    6689           0 :       if (!content) {
    6690             :         break;
    6691             :       }
    6692             : 
    6693           0 :       nsIFrame* contentFrame = content->GetPrimaryFrame();
    6694           0 :       if (!contentFrame) {
    6695             :         break;
    6696             :       }
    6697             : 
    6698           0 :       shell = static_cast<PresShell*>(contentFrame->PresContext()->PresShell());
    6699           0 :       if (shell) {
    6700             :         break;
    6701             :       }
    6702             :     }
    6703           0 :     break;
    6704             :   }
    6705             :   default:
    6706             :     break;
    6707             :   }
    6708           0 :   return shell;
    6709             : }
    6710             : 
    6711             : nsresult
    6712           0 : PresShell::HandleEvent(nsIFrame* aFrame,
    6713             :                        WidgetGUIEvent* aEvent,
    6714             :                        bool aDontRetargetEvents,
    6715             :                        nsEventStatus* aEventStatus)
    6716             : {
    6717             : #ifdef MOZ_TASK_TRACER
    6718             :   Maybe<AutoSourceEvent> taskTracerEvent;
    6719             :   if (MOZ_UNLIKELY(IsStartLogging())) {
    6720             :     // Make touch events, mouse events and hardware key events to be
    6721             :     // the source events of TaskTracer, and originate the rest
    6722             :     // correlation tasks from here.
    6723             :     SourceEventType type = SourceEventType::Unknown;
    6724             :     if (aEvent->AsTouchEvent()) {
    6725             :       type = SourceEventType::Touch;
    6726             :     } else if (aEvent->AsMouseEvent()) {
    6727             :       type = SourceEventType::Mouse;
    6728             :     } else if (aEvent->AsKeyboardEvent()) {
    6729             :       type = SourceEventType::Key;
    6730             :     }
    6731             :     taskTracerEvent.emplace(type);
    6732             :   }
    6733             : #endif
    6734             : 
    6735           0 :   NS_ASSERTION(aFrame, "aFrame should be not null");
    6736             : 
    6737             :   // Update the latest focus sequence number with this new sequence number;
    6738             :   // the next transasction that gets sent to the compositor will carry this over
    6739           0 :   if (mAPZFocusSequenceNumber < aEvent->mFocusSequenceNumber) {
    6740           0 :     mAPZFocusSequenceNumber = aEvent->mFocusSequenceNumber;
    6741             :   }
    6742             : 
    6743           0 :   if (mIsDestroying ||
    6744           0 :       (sDisableNonTestMouseEvents && !aEvent->mFlags.mIsSynthesizedForTests &&
    6745           0 :        aEvent->HasMouseEventMessage())) {
    6746             :     return NS_OK;
    6747             :   }
    6748             : 
    6749           0 :   RecordMouseLocation(aEvent);
    6750             : 
    6751           0 :   if (AccessibleCaretEnabled(mDocument->GetDocShell())) {
    6752             :     // We have to target the focus window because regardless of where the
    6753             :     // touch goes, we want to access the copy paste manager.
    6754           0 :     nsCOMPtr<nsPIDOMWindowOuter> window = GetFocusedDOMWindowInOurWindow();
    6755             :     nsCOMPtr<nsIDocument> retargetEventDoc =
    6756           0 :       window ? window->GetExtantDoc() : nullptr;
    6757             :     nsCOMPtr<nsIPresShell> presShell =
    6758           0 :       retargetEventDoc ? retargetEventDoc->GetShell() : nullptr;
    6759             : 
    6760             :     RefPtr<AccessibleCaretEventHub> eventHub =
    6761           0 :       presShell ? presShell->GetAccessibleCaretEventHub() : nullptr;
    6762           0 :     if (eventHub && *aEventStatus != nsEventStatus_eConsumeNoDefault) {
    6763             :       // Don't dispatch event to AccessibleCaretEventHub when the event status
    6764             :       // is nsEventStatus_eConsumeNoDefault. This might be happened when content
    6765             :       // preventDefault on the pointer events. In such case, we also call
    6766             :       // preventDefault on mouse events to stop default behaviors.
    6767           0 :       *aEventStatus = eventHub->HandleEvent(aEvent);
    6768           0 :       if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
    6769             :         // If the event is consumed, cancel APZC panning by setting
    6770             :         // mMultipleActionsPrevented.
    6771           0 :         aEvent->mFlags.mMultipleActionsPrevented = true;
    6772           0 :         return NS_OK;
    6773             :       }
    6774             :     }
    6775             :   }
    6776             : 
    6777           0 :   if (!nsContentUtils::IsSafeToRunScript() &&
    6778           0 :       aEvent->IsAllowedToDispatchDOMEvent()) {
    6779           0 :     if (aEvent->mClass == eCompositionEventClass) {
    6780           0 :       IMEStateManager::OnCompositionEventDiscarded(
    6781           0 :         aEvent->AsCompositionEvent());
    6782             :     }
    6783             : #ifdef DEBUG
    6784           0 :     if (aEvent->IsIMERelatedEvent()) {
    6785           0 :       nsPrintfCString warning("%d event is discarded", aEvent->mMessage);
    6786           0 :       NS_WARNING(warning.get());
    6787             :     }
    6788             : #endif
    6789           0 :     nsContentUtils::WarnScriptWasIgnored(GetDocument());
    6790           0 :     return NS_OK;
    6791             :   }
    6792             : 
    6793           0 :   nsIContent* capturingContent = ((aEvent->mClass == ePointerEventClass ||
    6794           0 :                                    aEvent->mClass == eWheelEventClass ||
    6795           0 :                                    aEvent->HasMouseEventMessage())
    6796           0 :                                  ? GetCapturingContent()
    6797           0 :                                  : nullptr);
    6798             : 
    6799           0 :   nsCOMPtr<nsIDocument> retargetEventDoc;
    6800           0 :   if (!aDontRetargetEvents) {
    6801             :     // key and IME related events should not cross top level window boundary.
    6802             :     // Basically, such input events should be fired only on focused widget.
    6803             :     // However, some IMEs might need to clean up composition after focused
    6804             :     // window is deactivated.  And also some tests on MozMill want to test key
    6805             :     // handling on deactivated window because MozMill window can be activated
    6806             :     // during tests.  So, there is no merit the events should be redirected to
    6807             :     // active window.  So, the events should be handled on the last focused
    6808             :     // content in the last focused DOM window in same top level window.
    6809             :     // Note, if no DOM window has been focused yet, we can discard the events.
    6810           0 :     if (aEvent->IsTargetedAtFocusedWindow()) {
    6811           0 :       nsCOMPtr<nsPIDOMWindowOuter> window = GetFocusedDOMWindowInOurWindow();
    6812             :       // No DOM window in same top level window has not been focused yet,
    6813             :       // discard the events.
    6814           0 :       if (!window) {
    6815           0 :         return NS_OK;
    6816             :       }
    6817             : 
    6818           0 :       retargetEventDoc = window->GetExtantDoc();
    6819           0 :       if (!retargetEventDoc)
    6820             :         return NS_OK;
    6821           0 :     } else if (capturingContent) {
    6822             :       // if the mouse is being captured then retarget the mouse event at the
    6823             :       // document that is being captured.
    6824           0 :       retargetEventDoc = capturingContent->GetComposedDoc();
    6825             : #ifdef ANDROID
    6826             :     } else if ((aEvent->mClass == eTouchEventClass) ||
    6827             :                (aEvent->mClass == eMouseEventClass) ||
    6828             :                (aEvent->mClass == eWheelEventClass)) {
    6829             :       retargetEventDoc = GetPrimaryContentDocument();
    6830             : #endif
    6831             :     }
    6832             : 
    6833           0 :     if (retargetEventDoc) {
    6834           0 :       nsCOMPtr<nsIPresShell> presShell = retargetEventDoc->GetShell();
    6835             :       // Even if the document doesn't have PresShell, i.e., it's invisible, we
    6836             :       // need to dispatch only KeyboardEvent in its nearest visible document
    6837             :       // because key focus shouldn't be caught by invisible document.
    6838           0 :       if (!presShell) {
    6839           0 :         if (!aEvent->HasKeyEventMessage()) {
    6840           0 :           return NS_OK;
    6841             :         }
    6842           0 :         while (!presShell) {
    6843           0 :           retargetEventDoc = retargetEventDoc->GetParentDocument();
    6844           0 :           if (!retargetEventDoc) {
    6845             :             return NS_OK;
    6846             :           }
    6847           0 :           presShell = retargetEventDoc->GetShell();
    6848             :         }
    6849             :       }
    6850             : 
    6851           0 :       if (presShell != this) {
    6852           0 :         nsIFrame* frame = presShell->GetRootFrame();
    6853           0 :         if (!frame) {
    6854           0 :           if (aEvent->mMessage == eQueryTextContent ||
    6855           0 :               aEvent->IsContentCommandEvent()) {
    6856             :             return NS_OK;
    6857             :           }
    6858             : 
    6859           0 :           frame = GetNearestFrameContainingPresShell(presShell);
    6860             :         }
    6861             : 
    6862           0 :         if (!frame)
    6863             :           return NS_OK;
    6864             : 
    6865           0 :         nsCOMPtr<nsIPresShell> shell = frame->PresContext()->GetPresShell();
    6866           0 :         return shell->HandleEvent(frame, aEvent, true, aEventStatus);
    6867             :       }
    6868             :     }
    6869             :   }
    6870             : 
    6871           0 :   if (aEvent->mClass == eKeyboardEventClass &&
    6872           0 :       mDocument && mDocument->EventHandlingSuppressed()) {
    6873           0 :     if (aEvent->mMessage == eKeyDown) {
    6874           0 :       mNoDelayedKeyEvents = true;
    6875           0 :     } else if (!mNoDelayedKeyEvents) {
    6876           0 :       DelayedEvent* event = new DelayedKeyEvent(aEvent->AsKeyboardEvent());
    6877           0 :       if (!mDelayedEvents.AppendElement(event)) {
    6878           0 :         delete event;
    6879             :       }
    6880             :     }
    6881           0 :     aEvent->mFlags.mIsSuppressedOrDelayed = true;
    6882           0 :     return NS_OK;
    6883             :   }
    6884             : 
    6885           0 :   nsIFrame* frame = aFrame;
    6886             : 
    6887           0 :   if (aEvent->IsUsingCoordinates()) {
    6888           0 :     if (mDocument) {
    6889           0 :       if (aEvent->mClass == eTouchEventClass) {
    6890           0 :         nsIDocument::UnlockPointer();
    6891             :       }
    6892             : 
    6893           0 :       AutoWeakFrame weakFrame(frame);
    6894             :       {  // scope for scriptBlocker.
    6895           0 :         nsAutoScriptBlocker scriptBlocker;
    6896           0 :         FlushThrottledStyles(GetRootPresShell()->GetDocument(), nullptr);
    6897             :       }
    6898             : 
    6899             : 
    6900           0 :       if (!weakFrame.IsAlive()) {
    6901           0 :         frame = GetNearestFrameContainingPresShell(this);
    6902             :       }
    6903             :     }
    6904             : 
    6905           0 :     if (!frame) {
    6906           0 :       NS_WARNING("Nothing to handle this event!");
    6907           0 :       return NS_OK;
    6908             :     }
    6909             : 
    6910           0 :     nsPresContext* framePresContext = frame->PresContext();
    6911           0 :     nsPresContext* rootPresContext = framePresContext->GetRootPresContext();
    6912           0 :     NS_ASSERTION(rootPresContext == mPresContext->GetRootPresContext(),
    6913             :                  "How did we end up outside the connected prescontext/viewmanager hierarchy?");
    6914             :     nsIFrame* popupFrame =
    6915           0 :       nsLayoutUtils::GetPopupFrameForEventCoordinates(rootPresContext, aEvent);
    6916             :     // If a remote browser is currently capturing input break out if we
    6917             :     // detect a chrome generated popup.
    6918           0 :     if (popupFrame && capturingContent &&
    6919           0 :         EventStateManager::IsRemoteTarget(capturingContent)) {
    6920           0 :       capturingContent = nullptr;
    6921             :     }
    6922             :     // If the popupFrame is an ancestor of the 'frame', the frame should
    6923             :     // handle the event, otherwise, the popup should handle it.
    6924           0 :     if (popupFrame &&
    6925           0 :         !nsContentUtils::ContentIsCrossDocDescendantOf(
    6926           0 :            framePresContext->GetPresShell()->GetDocument(),
    6927           0 :            popupFrame->GetContent())) {
    6928             : 
    6929             :       // If we aren't starting our event dispatch from the root frame of the
    6930             :       // root prescontext, then someone must be capturing the mouse. In that
    6931             :       // case we only want to use the popup list if the capture is
    6932             :       // inside the popup.
    6933           0 :       if (framePresContext == rootPresContext &&
    6934           0 :           frame == mFrameConstructor->GetRootFrame()) {
    6935             :         frame = popupFrame;
    6936           0 :       } else if (capturingContent &&
    6937           0 :                  nsContentUtils::ContentIsDescendantOf(
    6938           0 :                    capturingContent, popupFrame->GetContent())) {
    6939           0 :         frame = popupFrame;
    6940             :       }
    6941             :     }
    6942             : 
    6943           0 :     bool captureRetarget = false;
    6944           0 :     if (capturingContent) {
    6945             :       // If a capture is active, determine if the docshell is visible. If not,
    6946             :       // clear the capture and target the mouse event normally instead. This
    6947             :       // would occur if the mouse button is held down while a tab change occurs.
    6948             :       // If the docshell is visible, look for a scrolling container.
    6949             :       bool vis;
    6950             :       nsCOMPtr<nsIBaseWindow> baseWin =
    6951           0 :         do_QueryInterface(mPresContext->GetContainerWeak());
    6952           0 :       if (baseWin && NS_SUCCEEDED(baseWin->GetVisibility(&vis)) && vis) {
    6953           0 :         captureRetarget = gCaptureInfo.mRetargetToElement;
    6954           0 :         if (!captureRetarget) {
    6955             :           // A check was already done above to ensure that capturingContent is
    6956             :           // in this presshell.
    6957           0 :           NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(),
    6958             :                        "Unexpected document");
    6959           0 :           nsIFrame* captureFrame = capturingContent->GetPrimaryFrame();
    6960           0 :           if (captureFrame) {
    6961           0 :             if (capturingContent->IsHTMLElement(nsGkAtoms::select)) {
    6962             :               // a dropdown <select> has a child in its selectPopupList and we should
    6963             :               // capture on that instead.
    6964           0 :               nsIFrame* childFrame = captureFrame->GetChildList(nsIFrame::kSelectPopupList).FirstChild();
    6965           0 :               if (childFrame) {
    6966           0 :                 captureFrame = childFrame;
    6967             :               }
    6968             :             }
    6969             : 
    6970             :             // scrollable frames should use the scrolling container as
    6971             :             // the root instead of the document
    6972           0 :             nsIScrollableFrame* scrollFrame = do_QueryFrame(captureFrame);
    6973           0 :             if (scrollFrame) {
    6974           0 :               frame = scrollFrame->GetScrolledFrame();
    6975             :             }
    6976             :           }
    6977             :         }
    6978             :       }
    6979             :       else {
    6980           0 :         ClearMouseCapture(nullptr);
    6981           0 :         capturingContent = nullptr;
    6982             :       }
    6983             :     }
    6984             : 
    6985             :     // The order to generate pointer event is
    6986             :     // 1. check pending pointer capture.
    6987             :     // 2. check if there is a capturing content.
    6988             :     // 3. hit test
    6989             :     // 4. dispatch pointer events
    6990             :     // 5. check whether the targets of all Touch instances are in the same
    6991             :     //    document and suppress invalid instances.
    6992             :     // 6. dispatch mouse or touch events.
    6993             : 
    6994             :     // Try to keep frame for following check, because frame can be damaged
    6995             :     // during MaybeProcessPointerCapture.
    6996             :     {
    6997           0 :       AutoWeakFrame frameKeeper(frame);
    6998           0 :       PointerEventHandler::MaybeProcessPointerCapture(aEvent);
    6999             :       // Prevent application crashes, in case damaged frame.
    7000           0 :       if (!frameKeeper.IsAlive()) {
    7001           0 :         NS_WARNING("Nothing to handle this event!");
    7002           0 :         return NS_OK;
    7003             :       }
    7004             :     }
    7005             : 
    7006             :     // Only capture mouse events and pointer events.
    7007             :     nsCOMPtr<nsIContent> pointerCapturingContent =
    7008           0 :       PointerEventHandler::GetPointerCapturingContent(aEvent);
    7009             : 
    7010           0 :     if (pointerCapturingContent) {
    7011           0 :       frame = pointerCapturingContent->GetPrimaryFrame();
    7012             : 
    7013           0 :       if (!frame) {
    7014             :         RefPtr<PresShell> shell =
    7015           0 :           GetShellForEventTarget(nullptr, pointerCapturingContent);
    7016           0 :         if (!shell) {
    7017             :           // If we can't process event for the capturing content, release
    7018             :           // the capture.
    7019           0 :           PointerEventHandler::ReleaseIfCaptureByDescendant(
    7020           0 :             pointerCapturingContent);
    7021           0 :           return NS_OK;
    7022             :         }
    7023             : 
    7024             :         nsCOMPtr<nsIContent> overrideClickTarget =
    7025           0 :           GetOverrideClickTarget(aEvent, aFrame);
    7026             : 
    7027             :         // Dispatch events to the capturing content even it's frame is
    7028             :         // destroyed.
    7029           0 :         PointerEventHandler::DispatchPointerFromMouseOrTouch(
    7030             :           shell, nullptr, pointerCapturingContent, aEvent, false,
    7031           0 :           aEventStatus, nullptr);
    7032             : 
    7033           0 :         return shell->HandleEventWithTarget(aEvent, nullptr,
    7034             :                                             pointerCapturingContent,
    7035             :                                             aEventStatus, true, nullptr,
    7036           0 :                                             overrideClickTarget);
    7037             :       }
    7038             :     }
    7039             : 
    7040           0 :     WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
    7041           0 :     bool isWindowLevelMouseExit = (aEvent->mMessage == eMouseExitFromWidget) &&
    7042           0 :       (mouseEvent && mouseEvent->mExitFrom == WidgetMouseEvent::eTopLevel);
    7043             : 
    7044             :     // Get the frame at the event point. However, don't do this if we're
    7045             :     // capturing and retargeting the event because the captured frame will
    7046             :     // be used instead below. Also keep using the root frame if we're dealing
    7047             :     // with a window-level mouse exit event since we want to start sending
    7048             :     // mouse out events at the root EventStateManager.
    7049           0 :     if (!captureRetarget && !isWindowLevelMouseExit &&
    7050           0 :         !pointerCapturingContent) {
    7051           0 :       if (aEvent->mClass == eTouchEventClass) {
    7052           0 :         frame = TouchManager::SetupTarget(aEvent->AsTouchEvent(), frame);
    7053             :       } else {
    7054           0 :         uint32_t flags = 0;
    7055             :         nsPoint eventPoint =
    7056           0 :           nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
    7057             : 
    7058           0 :         if (mouseEvent && mouseEvent->mClass == eMouseEventClass &&
    7059           0 :             mouseEvent->mIgnoreRootScrollFrame) {
    7060           0 :           flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME;
    7061             :         }
    7062             :         nsIFrame* target =
    7063           0 :           FindFrameTargetedByInputEvent(aEvent, frame, eventPoint, flags);
    7064           0 :         if (target) {
    7065           0 :           frame = target;
    7066             :         }
    7067             :       }
    7068             :     }
    7069             : 
    7070             :     // if a node is capturing the mouse, check if the event needs to be
    7071             :     // retargeted at the capturing content instead. This will be the case when
    7072             :     // capture retargeting is being used, no frame was found or the frame's
    7073             :     // content is not a descendant of the capturing content.
    7074           0 :     if (capturingContent && !pointerCapturingContent &&
    7075           0 :         (gCaptureInfo.mRetargetToElement || !frame->GetContent() ||
    7076           0 :          !nsContentUtils::ContentIsCrossDocDescendantOf(frame->GetContent(),
    7077             :                                                         capturingContent))) {
    7078             :       // A check was already done above to ensure that capturingContent is
    7079             :       // in this presshell.
    7080           0 :       NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(),
    7081             :                    "Unexpected document");
    7082           0 :       nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame();
    7083           0 :       if (capturingFrame) {
    7084           0 :         frame = capturingFrame;
    7085             :       }
    7086             :     }
    7087             : 
    7088             :     // Suppress mouse event if it's being targeted at an element inside
    7089             :     // a document which needs events suppressed
    7090           0 :     if (aEvent->mClass == eMouseEventClass &&
    7091           0 :         frame->PresContext()->Document()->EventHandlingSuppressed()) {
    7092           0 :       if (aEvent->mMessage == eMouseDown) {
    7093           0 :         mNoDelayedMouseEvents = true;
    7094           0 :       } else if (!mNoDelayedMouseEvents && (aEvent->mMessage == eMouseUp ||
    7095             :         // contextmenu is triggered after right mouseup on Windows and right
    7096             :         // mousedown on other platforms.
    7097             :         aEvent->mMessage == eContextMenu)) {
    7098           0 :         DelayedEvent* event = new DelayedMouseEvent(aEvent->AsMouseEvent());
    7099           0 :         if (!mDelayedEvents.AppendElement(event)) {
    7100           0 :           delete event;
    7101             :         }
    7102             :       }
    7103             :       return NS_OK;
    7104             :     }
    7105             : 
    7106           0 :     if (!frame) {
    7107           0 :       NS_WARNING("Nothing to handle this event!");
    7108           0 :       return NS_OK;
    7109             :     }
    7110             : 
    7111           0 :     RefPtr<PresShell> shell = static_cast<PresShell*>(frame->PresShell());
    7112             :     // Check if we have an active EventStateManager which isn't the
    7113             :     // EventStateManager of the current PresContext.
    7114             :     // If that is the case, and mouse is over some ancestor document,
    7115             :     // forward event handling to the active document.
    7116             :     // This way content can get mouse events even when
    7117             :     // mouse is over the chrome or outside the window.
    7118             :     //
    7119             :     // Note, currently for backwards compatibility we don't forward mouse events
    7120             :     // to the active document when mouse is over some subdocument.
    7121           0 :     if (EventStateManager* activeESM = EventStateManager::GetActiveEventStateManager()) {
    7122           0 :       if (aEvent->mClass == ePointerEventClass || aEvent->HasMouseEventMessage()) {
    7123           0 :         if (activeESM != shell->GetPresContext()->EventStateManager()) {
    7124           0 :           if (nsPresContext* activeContext = activeESM->GetPresContext()) {
    7125           0 :             if (nsIPresShell* activeShell = activeContext->GetPresShell()) {
    7126           0 :               if (nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(),
    7127           0 :                                                                 shell->GetDocument())) {
    7128           0 :                 shell = static_cast<PresShell*>(activeShell);
    7129           0 :                 frame = shell->GetRootFrame();
    7130             :               }
    7131             :             }
    7132             :           }
    7133             :         }
    7134             :       }
    7135             :     }
    7136             : 
    7137           0 :     if (!frame) {
    7138           0 :       NS_WARNING("Nothing to handle this event!");
    7139           0 :       return NS_OK;
    7140             :     }
    7141             : 
    7142           0 :     nsCOMPtr<nsIContent> targetElement;
    7143           0 :     frame->GetContentForEvent(aEvent, getter_AddRefs(targetElement));
    7144             : 
    7145             :     // If there is no content for this frame, target it anyway.  Some
    7146             :     // frames can be targeted but do not have content, particularly
    7147             :     // windows with scrolling off.
    7148           0 :     if (targetElement) {
    7149             :       // Bug 103055, bug 185889: mouse events apply to *elements*, not all
    7150             :       // nodes.  Thus we get the nearest element parent here.
    7151             :       // XXX we leave the frame the same even if we find an element
    7152             :       // parent, so that the text frame will receive the event (selection
    7153             :       // and friends are the ones who care about that anyway)
    7154             :       //
    7155             :       // We use weak pointers because during this tight loop, the node
    7156             :       // will *not* go away.  And this happens on every mousemove.
    7157           0 :       while (targetElement && !targetElement->IsElement()) {
    7158           0 :         targetElement = targetElement->GetFlattenedTreeParent();
    7159             :       }
    7160             : 
    7161             :       // If we found an element, target it.  Otherwise, target *nothing*.
    7162           0 :       if (!targetElement) {
    7163             :         return NS_OK;
    7164             :       }
    7165             :     }
    7166             : 
    7167           0 :     nsCOMPtr<nsIContent> overrideClickTarget;
    7168           0 :     if (PointerEventHandler::IsPointerEventEnabled()) {
    7169             :       // Dispatch pointer events from the mouse or touch events. Regarding
    7170             :       // pointer events from mouse, we should dispatch those pointer events to
    7171             :       // the same target as the source mouse events. We pass the frame found
    7172             :       // in hit test to PointerEventHandler and dispatch pointer events to it.
    7173             :       //
    7174             :       // Regarding pointer events from touch, the behavior is different. Touch
    7175             :       // events are dispatched to the same target as the target of touchstart.
    7176             :       // Multiple touch points must be dispatched to the same document. Pointer
    7177             :       // events from touch can be dispatched to different documents. We Pass the
    7178             :       // original frame to PointerEventHandler, reentry PresShell::HandleEvent,
    7179             :       // and do hit test for each point.
    7180             :       nsIFrame* targetFrame =
    7181           0 :         aEvent->mClass == eTouchEventClass ? aFrame : frame;
    7182             : 
    7183           0 :       if (pointerCapturingContent) {
    7184           0 :         overrideClickTarget = GetOverrideClickTarget(aEvent, aFrame);
    7185           0 :         shell = GetShellForEventTarget(nullptr, pointerCapturingContent);
    7186           0 :         if (!shell) {
    7187             :           // If we can't process event for the capturing content, release
    7188             :           // the capture.
    7189           0 :           PointerEventHandler::ReleaseIfCaptureByDescendant(
    7190           0 :             pointerCapturingContent);
    7191           0 :           return NS_OK;
    7192             :         }
    7193             : 
    7194           0 :         targetFrame = pointerCapturingContent->GetPrimaryFrame();
    7195           0 :         frame = targetFrame;
    7196             :       }
    7197             : 
    7198           0 :       AutoWeakFrame weakTargetFrame(targetFrame);
    7199           0 :       AutoWeakFrame weakFrame(frame);
    7200           0 :       nsCOMPtr<nsIContent> targetContent;
    7201           0 :       PointerEventHandler::DispatchPointerFromMouseOrTouch(
    7202             :                              shell, targetFrame, targetElement, aEvent,
    7203             :                              aDontRetargetEvents, aEventStatus,
    7204           0 :                              getter_AddRefs(targetContent));
    7205             : 
    7206           0 :       if (!weakTargetFrame.IsAlive() && aEvent->mClass == eMouseEventClass) {
    7207             :         // Spec only defines that mouse events must be dispatched to the same
    7208             :         // target as the pointer event. If the target is no longer participating
    7209             :         // in its ownerDocument's tree, fire the event at the original target's
    7210             :         // nearest ancestor node
    7211           0 :         if (!targetContent) {
    7212           0 :           return NS_OK;
    7213             :         }
    7214           0 :         frame = targetContent->GetPrimaryFrame();
    7215           0 :         shell = GetShellForEventTarget(frame, targetContent);
    7216           0 :         if (!shell) {
    7217             :           return NS_OK;
    7218             :         }
    7219           0 :       } else if (!weakFrame.IsAlive()) {
    7220             :         return NS_OK;
    7221             :       }
    7222             :     }
    7223             : 
    7224             :     // frame could be null after dispatching pointer events.
    7225           0 :     if (aEvent->mClass == eTouchEventClass) {
    7226           0 :       if (aEvent->mMessage == eTouchStart) {
    7227           0 :         WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
    7228           0 :         if (nsIFrame* newFrame =
    7229             :               TouchManager::SuppressInvalidPointsAndGetTargetedFrame(
    7230           0 :                 touchEvent)) {
    7231           0 :           frame = newFrame;
    7232           0 :           frame->GetContentForEvent(aEvent, getter_AddRefs(targetElement));
    7233           0 :           shell = static_cast<PresShell*>(frame->PresShell());
    7234             :         }
    7235           0 :       } else if (PresShell* newShell = GetShellForTouchEvent(aEvent)) {
    7236             :         // Touch events (except touchstart) are dispatching to the captured
    7237             :         // element. Get correct shell from it.
    7238             :         shell = newShell;
    7239             :       }
    7240             :     }
    7241             : 
    7242             :     nsresult rv;
    7243             : 
    7244             :     // Handle the event in the correct shell.
    7245             :     // We pass the subshell's root frame as the frame to start from. This is
    7246             :     // the only correct alternative; if the event was captured then it
    7247             :     // must have been captured by us or some ancestor shell and we
    7248             :     // now ask the subshell to dispatch it normally.
    7249           0 :     shell->PushCurrentEventInfo(frame, targetElement);
    7250           0 :     rv = shell->HandleEventInternal(aEvent, aEventStatus, true,
    7251           0 :                                     overrideClickTarget);
    7252             : #ifdef DEBUG
    7253           0 :     shell->ShowEventTargetDebug();
    7254             : #endif
    7255           0 :     shell->PopCurrentEventInfo();
    7256           0 :     return rv;
    7257             :   }
    7258             : 
    7259           0 :   nsresult rv = NS_OK;
    7260             : 
    7261           0 :   if (frame) {
    7262           0 :     PushCurrentEventInfo(nullptr, nullptr);
    7263             : 
    7264             :     // key and IME related events go to the focused frame in this DOM window.
    7265           0 :     if (aEvent->IsTargetedAtFocusedContent()) {
    7266           0 :       mCurrentEventContent = nullptr;
    7267             : 
    7268           0 :       nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
    7269           0 :       nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    7270             :       nsCOMPtr<nsIContent> eventTarget =
    7271           0 :         nsFocusManager::GetFocusedDescendant(window,
    7272             :                                              nsFocusManager::eOnlyCurrentWindow,
    7273           0 :                                              getter_AddRefs(focusedWindow));
    7274             : 
    7275             :       // otherwise, if there is no focused content or the focused content has
    7276             :       // no frame, just use the root content. This ensures that key events
    7277             :       // still get sent to the window properly if nothing is focused or if a
    7278             :       // frame goes away while it is focused.
    7279           0 :       if (!eventTarget || !eventTarget->GetPrimaryFrame()) {
    7280           0 :         eventTarget = mDocument->GetUnfocusedKeyEventTarget();
    7281             :       }
    7282             : 
    7283           0 :       if (aEvent->mMessage == eKeyDown) {
    7284           0 :         NS_IF_RELEASE(gKeyDownTarget);
    7285           0 :         NS_IF_ADDREF(gKeyDownTarget = eventTarget);
    7286             :       }
    7287           0 :       else if ((aEvent->mMessage == eKeyPress ||
    7288           0 :                 aEvent->mMessage == eKeyUp) &&
    7289           0 :                gKeyDownTarget) {
    7290             :         // If a different element is now focused for the keypress/keyup event
    7291             :         // than what was focused during the keydown event, check if the new
    7292             :         // focused element is not in a chrome document any more, and if so,
    7293             :         // retarget the event back at the keydown target. This prevents a
    7294             :         // content area from grabbing the focus from chrome in-between key
    7295             :         // events.
    7296           0 :         if (eventTarget) {
    7297           0 :           bool keyDownIsChrome = nsContentUtils::IsChromeDoc(gKeyDownTarget->GetComposedDoc());
    7298           0 :           if (keyDownIsChrome != nsContentUtils::IsChromeDoc(eventTarget->GetComposedDoc()) ||
    7299           0 :               (keyDownIsChrome && TabParent::GetFrom(eventTarget))) {
    7300           0 :             eventTarget = gKeyDownTarget;
    7301             :           }
    7302             :         }
    7303             : 
    7304           0 :         if (aEvent->mMessage == eKeyUp) {
    7305           0 :           NS_RELEASE(gKeyDownTarget);
    7306             :         }
    7307             :       }
    7308             : 
    7309           0 :       mCurrentEventFrame = nullptr;
    7310           0 :       nsIDocument* targetDoc = eventTarget ? eventTarget->OwnerDoc() : nullptr;
    7311           0 :       if (targetDoc && targetDoc != mDocument) {
    7312           0 :         PopCurrentEventInfo();
    7313           0 :         nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell();
    7314           0 :         if (shell) {
    7315           0 :           rv = static_cast<PresShell*>(shell.get())->
    7316           0 :             HandleRetargetedEvent(aEvent, aEventStatus, eventTarget);
    7317             :         }
    7318             :         return rv;
    7319             :       } else {
    7320           0 :         mCurrentEventContent = eventTarget;
    7321             :       }
    7322             : 
    7323           0 :       if (!GetCurrentEventContent() || !GetCurrentEventFrame() ||
    7324           0 :           InZombieDocument(mCurrentEventContent)) {
    7325           0 :         rv = RetargetEventToParent(aEvent, aEventStatus);
    7326           0 :         PopCurrentEventInfo();
    7327           0 :         return rv;
    7328             :       }
    7329             :     } else {
    7330           0 :       mCurrentEventFrame = frame;
    7331             :     }
    7332           0 :     if (GetCurrentEventFrame()) {
    7333           0 :       rv = HandleEventInternal(aEvent, aEventStatus, true);
    7334             :     }
    7335             : 
    7336             : #ifdef DEBUG
    7337           0 :     ShowEventTargetDebug();
    7338             : #endif
    7339           0 :     PopCurrentEventInfo();
    7340             :   } else {
    7341             :     // Activation events need to be dispatched even if no frame was found, since
    7342             :     // we don't want the focus to be out of sync.
    7343             : 
    7344           0 :     if (!NS_EVENT_NEEDS_FRAME(aEvent)) {
    7345           0 :       mCurrentEventFrame = nullptr;
    7346           0 :       return HandleEventInternal(aEvent, aEventStatus, true);
    7347             :     }
    7348           0 :     else if (aEvent->HasKeyEventMessage()) {
    7349             :       // Keypress events in new blank tabs should not be completely thrown away.
    7350             :       // Retarget them -- the parent chrome shell might make use of them.
    7351           0 :       return RetargetEventToParent(aEvent, aEventStatus);
    7352             :     }
    7353             :   }
    7354             : 
    7355             :   return rv;
    7356             : }
    7357             : 
    7358             : nsIDocument*
    7359           0 : PresShell::GetPrimaryContentDocument()
    7360             : {
    7361           0 :   nsPresContext* context = GetPresContext();
    7362           0 :   if (!context || !context->IsRoot()) {
    7363             :     return nullptr;
    7364             :   }
    7365             : 
    7366           0 :   nsCOMPtr<nsIDocShellTreeItem> shellAsTreeItem = context->GetDocShell();
    7367           0 :   if (!shellAsTreeItem) {
    7368             :     return nullptr;
    7369             :   }
    7370             : 
    7371           0 :   nsCOMPtr<nsIDocShellTreeOwner> owner;
    7372           0 :   shellAsTreeItem->GetTreeOwner(getter_AddRefs(owner));
    7373           0 :   if (!owner) {
    7374             :     return nullptr;
    7375             :   }
    7376             : 
    7377             :   // now get the primary content shell (active tab)
    7378           0 :   nsCOMPtr<nsIDocShellTreeItem> item;
    7379           0 :   owner->GetPrimaryContentShell(getter_AddRefs(item));
    7380           0 :   nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(item);
    7381           0 :   if (!childDocShell) {
    7382             :     return nullptr;
    7383             :   }
    7384             : 
    7385           0 :   return childDocShell->GetDocument();
    7386             : }
    7387             : 
    7388             : #ifdef DEBUG
    7389             : void
    7390           0 : PresShell::ShowEventTargetDebug()
    7391             : {
    7392           0 :   if (nsFrame::GetShowEventTargetFrameBorder() &&
    7393           0 :       GetCurrentEventFrame()) {
    7394           0 :     if (mDrawEventTargetFrame) {
    7395           0 :       mDrawEventTargetFrame->InvalidateFrame();
    7396             :     }
    7397             : 
    7398           0 :     mDrawEventTargetFrame = mCurrentEventFrame;
    7399           0 :     mDrawEventTargetFrame->InvalidateFrame();
    7400             :   }
    7401           0 : }
    7402             : #endif
    7403             : 
    7404             : nsresult
    7405           0 : PresShell::HandleEventWithTarget(WidgetEvent* aEvent, nsIFrame* aFrame,
    7406             :                                  nsIContent* aContent, nsEventStatus* aStatus,
    7407             :                                  bool aIsHandlingNativeEvent,
    7408             :                                  nsIContent** aTargetContent,
    7409             :                                  nsIContent* aOverrideClickTarget)
    7410             : {
    7411             : #if DEBUG
    7412           0 :   MOZ_ASSERT(!aFrame || aFrame->PresContext()->GetPresShell() == this,
    7413             :              "wrong shell");
    7414           0 :   if (aContent) {
    7415           0 :     nsIDocument* doc = aContent->GetComposedDoc();
    7416           0 :     NS_ASSERTION(doc, "event for content that isn't in a document");
    7417             :     // NOTE: We don't require that the document still have a PresShell.
    7418             :     // See bug 1375940.
    7419             :   }
    7420             : #endif
    7421           0 :   NS_ENSURE_STATE(!aContent || aContent->GetComposedDoc() == mDocument);
    7422           0 :   AutoPointerEventTargetUpdater updater(this, aEvent, aFrame, aTargetContent);
    7423           0 :   PushCurrentEventInfo(aFrame, aContent);
    7424             :   nsresult rv =
    7425           0 :     HandleEventInternal(aEvent, aStatus, false, aOverrideClickTarget);
    7426           0 :   PopCurrentEventInfo();
    7427             :   return rv;
    7428             : }
    7429             : 
    7430             : nsresult
    7431           0 : PresShell::HandleEventInternal(WidgetEvent* aEvent,
    7432             :                                nsEventStatus* aStatus,
    7433             :                                bool aIsHandlingNativeEvent,
    7434             :                                nsIContent* aOverrideClickTarget)
    7435             : {
    7436           0 :   RefPtr<EventStateManager> manager = mPresContext->EventStateManager();
    7437           0 :   nsresult rv = NS_OK;
    7438             : 
    7439           0 :   if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame() || GetCurrentEventContent()) {
    7440           0 :     bool touchIsNew = false;
    7441           0 :     bool isHandlingUserInput = false;
    7442             : 
    7443           0 :     if (mCurrentEventContent && aEvent->IsTargetedAtFocusedWindow()) {
    7444           0 :       nsFocusManager* fm = nsFocusManager::GetFocusManager();
    7445           0 :       if (fm) {
    7446           0 :          fm->FlushBeforeEventHandlingIfNeeded(mCurrentEventContent);
    7447             :       }
    7448             :     }
    7449             : 
    7450             :     // XXX How about IME events and input events for plugins?
    7451           0 :     if (aEvent->IsTrusted()) {
    7452           0 :       if (aEvent->IsUserAction()) {
    7453           0 :         mHasHandledUserInput = true;
    7454             :       }
    7455             : 
    7456           0 :       switch (aEvent->mMessage) {
    7457             :       case eKeyPress:
    7458             :       case eKeyDown:
    7459             :       case eKeyUp: {
    7460           0 :         nsIDocument* doc = GetCurrentEventContent() ?
    7461           0 :                            mCurrentEventContent->OwnerDoc() : nullptr;
    7462           0 :         auto keyCode = aEvent->AsKeyboardEvent()->mKeyCode;
    7463           0 :         if (keyCode == NS_VK_ESCAPE) {
    7464           0 :           nsIDocument* root = nsContentUtils::GetRootDocument(doc);
    7465           0 :           if (root && root->GetFullscreenElement()) {
    7466             :             // Prevent default action on ESC key press when exiting
    7467             :             // DOM fullscreen mode. This prevents the browser ESC key
    7468             :             // handler from stopping all loads in the document, which
    7469             :             // would cause <video> loads to stop.
    7470             :             // XXX We need to claim the Escape key event which will be
    7471             :             //     dispatched only into chrome is already consumed by
    7472             :             //     content because we need to prevent its default here
    7473             :             //     for some reasons (not sure) but we need to detect
    7474             :             //     if a chrome event handler will call PreventDefault()
    7475             :             //     again and check it later.
    7476           0 :             aEvent->PreventDefaultBeforeDispatch();
    7477           0 :             aEvent->mFlags.mOnlyChromeDispatch = true;
    7478             : 
    7479             :             // The event listeners in chrome can prevent this ESC behavior by
    7480             :             // calling prevent default on the preceding keydown/press events.
    7481           0 :             if (!mIsLastChromeOnlyEscapeKeyConsumed &&
    7482           0 :                 aEvent->mMessage == eKeyUp) {
    7483             :               // ESC key released while in DOM fullscreen mode.
    7484             :               // Fully exit all browser windows and documents from
    7485             :               // fullscreen mode.
    7486           0 :               nsIDocument::AsyncExitFullscreen(nullptr);
    7487             :             }
    7488             :           }
    7489             :           nsCOMPtr<nsIDocument> pointerLockedDoc =
    7490           0 :             do_QueryReferent(EventStateManager::sPointerLockedDoc);
    7491           0 :           if (!mIsLastChromeOnlyEscapeKeyConsumed && pointerLockedDoc) {
    7492             :             // XXX See above comment to understand the reason why this needs
    7493             :             //     to claim that the Escape key event is consumed by content
    7494             :             //     even though it will be dispatched only into chrome.
    7495           0 :             aEvent->PreventDefaultBeforeDispatch();
    7496           0 :             aEvent->mFlags.mOnlyChromeDispatch = true;
    7497           0 :             if (aEvent->mMessage == eKeyUp) {
    7498           0 :               nsIDocument::UnlockPointer();
    7499             :             }
    7500             :           }
    7501             :         }
    7502           0 :         if (keyCode != NS_VK_ESCAPE && keyCode != NS_VK_SHIFT &&
    7503           0 :             keyCode != NS_VK_CONTROL && keyCode != NS_VK_ALT &&
    7504           0 :             keyCode != NS_VK_WIN && keyCode != NS_VK_META) {
    7505             :           // Allow keys other than ESC and modifiers be marked as a
    7506             :           // valid user input for triggering popup, fullscreen, and
    7507             :           // pointer lock.
    7508           0 :           isHandlingUserInput = true;
    7509           0 :           mPresContext->RecordInteractionTime(
    7510             :             nsPresContext::InteractionType::eKeyInteraction,
    7511           0 :             aEvent->mTimeStamp);
    7512             :         }
    7513             : 
    7514           0 :         Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_KEYBOARD_MS, aEvent->mTimeStamp);
    7515           0 :         break;
    7516             :       }
    7517             :       case eMouseDown:
    7518             :       case eMouseUp:
    7519           0 :         Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_CLICK_MS, aEvent->mTimeStamp);
    7520             :         MOZ_FALLTHROUGH;
    7521             :       case ePointerDown:
    7522             :       case ePointerUp:
    7523           0 :         isHandlingUserInput = true;
    7524           0 :         mPresContext->RecordInteractionTime(
    7525             :           nsPresContext::InteractionType::eClickInteraction,
    7526           0 :           aEvent->mTimeStamp);
    7527           0 :         break;
    7528             : 
    7529             :       case eMouseMove:
    7530           0 :         if (aEvent->mFlags.mHandledByAPZ) {
    7531           0 :           Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_APZ_MOUSE_MOVE_MS, aEvent->mTimeStamp);
    7532             :         }
    7533             :         break;
    7534             : 
    7535             :       case eDrop: {
    7536           0 :         nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession();
    7537           0 :         if (session) {
    7538           0 :           bool onlyChromeDrop = false;
    7539           0 :           session->GetOnlyChromeDrop(&onlyChromeDrop);
    7540           0 :           if (onlyChromeDrop) {
    7541           0 :             aEvent->mFlags.mOnlyChromeDispatch = true;
    7542             :           }
    7543             :         }
    7544             :         break;
    7545             :       }
    7546             : 
    7547             :       case eWheel:
    7548           0 :         if (aEvent->mFlags.mHandledByAPZ) {
    7549           0 :           Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_APZ_WHEEL_MS, aEvent->mTimeStamp);
    7550             :         }
    7551             :         break;
    7552             : 
    7553             :       case eTouchMove:
    7554           0 :         if (aEvent->mFlags.mHandledByAPZ) {
    7555           0 :           Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_QUEUED_APZ_TOUCH_MOVE_MS, aEvent->mTimeStamp);
    7556             :         }
    7557             :         break;
    7558             : 
    7559             :       default:
    7560             :         break;
    7561             :       }
    7562             : 
    7563           0 :       if (!mTouchManager.PreHandleEvent(aEvent, aStatus,
    7564             :                                         touchIsNew, isHandlingUserInput,
    7565             :                                         mCurrentEventContent)) {
    7566           0 :         return NS_OK;
    7567             :       }
    7568             :     }
    7569             : 
    7570           0 :     if (aEvent->mMessage == eContextMenu) {
    7571           0 :       WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
    7572           0 :       if (mouseEvent->IsContextMenuKeyEvent() &&
    7573           0 :           !AdjustContextMenuKeyEvent(mouseEvent)) {
    7574             :         return NS_OK;
    7575             :       }
    7576           0 :       if (mouseEvent->IsShift()) {
    7577           0 :         aEvent->mFlags.mOnlyChromeDispatch = true;
    7578           0 :         aEvent->mFlags.mRetargetToNonNativeAnonymous = true;
    7579             :       }
    7580             :     }
    7581             : 
    7582             :     AutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput,
    7583           0 :                                                         aEvent, mDocument);
    7584             : 
    7585           0 :     if (aEvent->IsTrusted() && aEvent->mMessage == eMouseMove) {
    7586             :       nsIPresShell::AllowMouseCapture(
    7587           0 :         EventStateManager::GetActiveEventStateManager() == manager);
    7588             : 
    7589           0 :       mPresContext->RecordInteractionTime(
    7590             :         nsPresContext::InteractionType::eMouseMoveInteraction,
    7591           0 :         aEvent->mTimeStamp);
    7592             :     }
    7593             : 
    7594             :     nsAutoPopupStatePusher popupStatePusher(
    7595           0 :                              Event::GetEventPopupControlState(aEvent));
    7596             : 
    7597             :     // FIXME. If the event was reused, we need to clear the old target,
    7598             :     // bug 329430
    7599           0 :     aEvent->mTarget = nullptr;
    7600             : 
    7601           0 :     TimeStamp handlerStartTime = TimeStamp::Now();
    7602             : 
    7603             :     // 1. Give event to event manager for pre event state changes and
    7604             :     //    generation of synthetic events.
    7605           0 :     rv = manager->PreHandleEvent(mPresContext, aEvent, mCurrentEventFrame,
    7606             :                                  mCurrentEventContent, aStatus,
    7607           0 :                                  aOverrideClickTarget);
    7608             : 
    7609             :     // 2. Give event to the DOM for third party and JS use.
    7610           0 :     if (NS_SUCCEEDED(rv)) {
    7611             :       bool wasHandlingKeyBoardEvent =
    7612           0 :         nsContentUtils::IsHandlingKeyBoardEvent();
    7613           0 :       if (aEvent->mClass == eKeyboardEventClass) {
    7614             :         nsContentUtils::SetIsHandlingKeyBoardEvent(true);
    7615             :       }
    7616             :       // If EventStateManager or something wants reply from remote process and
    7617             :       // needs to win any other event listeners in chrome, the event is both
    7618             :       // stopped its propagation and marked as "waiting reply from remote
    7619             :       // process".  In this case, PresShell shouldn't dispatch the event into
    7620             :       // the DOM tree because they don't have a chance to stop propagation in
    7621             :       // the system event group.  On the other hand, if its propagation is not
    7622             :       // stopped, that means that the event may be reserved by chrome.  If it's
    7623             :       // reserved by chrome, the event shouldn't be sent to any remote
    7624             :       // processes.  In this case, PresShell needs to dispatch the event to
    7625             :       // the DOM tree for checking if it's reserved.
    7626           0 :       if (aEvent->IsAllowedToDispatchDOMEvent() &&
    7627           0 :           !(aEvent->PropagationStopped() &&
    7628           0 :             aEvent->IsWaitingReplyFromRemoteProcess())) {
    7629           0 :         MOZ_ASSERT(nsContentUtils::IsSafeToRunScript(),
    7630             :           "Somebody changed aEvent to cause a DOM event!");
    7631           0 :         nsPresShellEventCB eventCB(this);
    7632           0 :         if (nsIFrame* target = GetCurrentEventFrame()) {
    7633           0 :           if (target->OnlySystemGroupDispatch(aEvent->mMessage)) {
    7634           0 :               aEvent->StopPropagation();
    7635             :           }
    7636             :         }
    7637           0 :         if (aEvent->mClass == eTouchEventClass) {
    7638           0 :           DispatchTouchEventToDOM(aEvent, aStatus, &eventCB, touchIsNew);
    7639             :         } else {
    7640           0 :           DispatchEventToDOM(aEvent, aStatus, &eventCB);
    7641             :         }
    7642             :       }
    7643             : 
    7644           0 :       nsContentUtils::SetIsHandlingKeyBoardEvent(wasHandlingKeyBoardEvent);
    7645             : 
    7646           0 :       if (aEvent->mMessage == ePointerUp ||
    7647             :           aEvent->mMessage == ePointerCancel) {
    7648             :         // Implicitly releasing capture for given pointer.
    7649             :         // ePointerLostCapture should be send after ePointerUp or
    7650             :         // ePointerCancel.
    7651           0 :         WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
    7652           0 :         MOZ_ASSERT(pointerEvent);
    7653           0 :         PointerEventHandler::ReleasePointerCaptureById(pointerEvent->pointerId);
    7654           0 :         PointerEventHandler::CheckPointerCaptureState(pointerEvent);
    7655             :       }
    7656             : 
    7657             :       // 3. Give event to event manager for post event state changes and
    7658             :       //    generation of synthetic events.
    7659           0 :       if (!mIsDestroying && NS_SUCCEEDED(rv)) {
    7660           0 :         rv = manager->PostHandleEvent(mPresContext, aEvent,
    7661             :                                       GetCurrentEventFrame(), aStatus,
    7662           0 :                                       aOverrideClickTarget);
    7663             :       }
    7664             :     }
    7665             : 
    7666           0 :     if (!mIsDestroying && aIsHandlingNativeEvent) {
    7667             :       // Ensure that notifications to IME should be sent before getting next
    7668             :       // native event from the event queue.
    7669             :       // XXX Should we check the event message or event class instead of
    7670             :       //     using aIsHandlingNativeEvent?
    7671           0 :       manager->TryToFlushPendingNotificationsToIME();
    7672             :     }
    7673             : 
    7674           0 :     switch (aEvent->mMessage) {
    7675             :     case eKeyPress:
    7676             :     case eKeyDown:
    7677             :     case eKeyUp: {
    7678           0 :       if (aEvent->AsKeyboardEvent()->mKeyCode == NS_VK_ESCAPE) {
    7679           0 :         if (aEvent->mMessage == eKeyUp) {
    7680             :           // Reset this flag after key up is handled.
    7681           0 :           mIsLastChromeOnlyEscapeKeyConsumed = false;
    7682             :         } else {
    7683           0 :           if (aEvent->mFlags.mOnlyChromeDispatch &&
    7684           0 :               aEvent->mFlags.mDefaultPreventedByChrome) {
    7685           0 :             mIsLastChromeOnlyEscapeKeyConsumed = true;
    7686             :           }
    7687             :         }
    7688             :       }
    7689           0 :       if (aEvent->mMessage == eKeyDown) {
    7690           0 :         mIsLastKeyDownCanceled = aEvent->mFlags.mDefaultPrevented;
    7691             :       }
    7692             :       break;
    7693             :     }
    7694             :     case eMouseUp:
    7695             :       // reset the capturing content now that the mouse button is up
    7696           0 :       SetCapturingContent(nullptr, 0);
    7697           0 :       break;
    7698             :     case eMouseMove:
    7699             :       nsIPresShell::AllowMouseCapture(false);
    7700             :       break;
    7701             :     case eDrag:
    7702             :     case eDragEnd:
    7703             :     case eDragEnter:
    7704             :     case eDragExit:
    7705             :     case eDragLeave:
    7706             :     case eDragOver:
    7707             :     case eDrop: {
    7708             :       // After any drag event other than dragstart (which is handled separately,
    7709             :       // as we need to collect the data first), the DataTransfer needs to be
    7710             :       // made protected, and then disconnected.
    7711           0 :       DataTransfer* dataTransfer = aEvent->AsDragEvent()->mDataTransfer;
    7712           0 :       if (dataTransfer) {
    7713           0 :         dataTransfer->Disconnect();
    7714             :       }
    7715             :       break;
    7716             :     }
    7717             :     default:
    7718             :       break;
    7719             :     }
    7720             : 
    7721           0 :     if (aEvent->IsTrusted() && aEvent->mTimeStamp > mLastOSWake) {
    7722           0 :       switch (aEvent->mMessage) {
    7723             :         case eKeyPress:
    7724             :         case eKeyDown:
    7725             :         case eKeyUp:
    7726           0 :           Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_KEYBOARD_MS, handlerStartTime);
    7727           0 :           break;
    7728             :         case eMouseDown:
    7729           0 :           Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_MOUSE_DOWN_MS, handlerStartTime);
    7730           0 :           break;
    7731             :         case eMouseUp:
    7732           0 :           Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_MOUSE_UP_MS, handlerStartTime);
    7733           0 :           break;
    7734             :         case eMouseMove:
    7735           0 :           if (aEvent->mFlags.mHandledByAPZ) {
    7736           0 :             Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_APZ_MOUSE_MOVE_MS, handlerStartTime);
    7737             :           }
    7738             :           break;
    7739             :         case eWheel:
    7740           0 :           if (aEvent->mFlags.mHandledByAPZ) {
    7741           0 :             Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_APZ_WHEEL_MS, handlerStartTime);
    7742             :           }
    7743             :           break;
    7744             :         case eTouchMove:
    7745           0 :           if (aEvent->mFlags.mHandledByAPZ) {
    7746           0 :             Telemetry::AccumulateTimeDelta(Telemetry::INPUT_EVENT_HANDLED_APZ_TOUCH_MOVE_MS, handlerStartTime);
    7747             :           }
    7748             :           break;
    7749             :         default:
    7750             :           break;
    7751             :       }
    7752             :     }
    7753             :   }
    7754             : 
    7755           0 :   if (Telemetry::CanRecordBase() &&
    7756           0 :       !aEvent->mTimeStamp.IsNull() &&
    7757           0 :       aEvent->mTimeStamp > mLastOSWake &&
    7758           0 :       aEvent->AsInputEvent()) {
    7759           0 :     TimeStamp now = TimeStamp::Now();
    7760           0 :     double millis = (now - aEvent->mTimeStamp).ToMilliseconds();
    7761           0 :     Telemetry::Accumulate(Telemetry::INPUT_EVENT_RESPONSE_MS, millis);
    7762           0 :     if (mDocument && mDocument->GetReadyStateEnum() != nsIDocument::READYSTATE_COMPLETE) {
    7763           0 :       Telemetry::Accumulate(Telemetry::LOAD_INPUT_EVENT_RESPONSE_MS, millis);
    7764             :     }
    7765             : 
    7766           0 :     if (!sLastInputProcessed || sLastInputProcessed < aEvent->mTimeStamp) {
    7767           0 :       if (sLastInputProcessed) {
    7768             :         // This input event was created after we handled the last one.
    7769             :         // Accumulate the previous events' coalesced duration.
    7770           0 :         double lastMillis = (sLastInputProcessed - sLastInputCreated).ToMilliseconds();
    7771           0 :         Telemetry::Accumulate(Telemetry::INPUT_EVENT_RESPONSE_COALESCED_MS,
    7772           0 :                               lastMillis);
    7773             : 
    7774           0 :         if (MOZ_UNLIKELY(!sProcessInteractable)) {
    7775             :           // For content process, we use the ready state of
    7776             :           // top-level-content-document to know if the process has finished the
    7777             :           // start-up.
    7778             :           // For parent process, see the topic
    7779             :           // 'sessionstore-one-or-no-tab-restored' in PresShell::Observe.
    7780           0 :           if (XRE_IsContentProcess() &&
    7781           0 :               mDocument && mDocument->IsTopLevelContentDocument()) {
    7782           0 :             switch (mDocument->GetReadyStateEnum()) {
    7783             :               case nsIDocument::READYSTATE_INTERACTIVE:
    7784             :               case nsIDocument::READYSTATE_COMPLETE:
    7785           0 :                 sProcessInteractable = true;
    7786           0 :                 break;
    7787             :               default:
    7788             :                 break;
    7789             :             }
    7790             :           }
    7791             :         }
    7792           0 :         if (MOZ_LIKELY(sProcessInteractable)) {
    7793             :           Telemetry::Accumulate(Telemetry::INPUT_EVENT_RESPONSE_POST_STARTUP_MS,
    7794           0 :                                 lastMillis);
    7795             :         } else {
    7796             :           Telemetry::Accumulate(Telemetry::INPUT_EVENT_RESPONSE_STARTUP_MS,
    7797           0 :                                 lastMillis);
    7798             :         }
    7799             :       }
    7800           0 :       sLastInputCreated = aEvent->mTimeStamp;
    7801           0 :     } else if (aEvent->mTimeStamp < sLastInputCreated) {
    7802             :       // This event was created before the last input. May be processing out
    7803             :       // of order, so coalesce backwards, too.
    7804           0 :       sLastInputCreated = aEvent->mTimeStamp;
    7805             :     }
    7806           0 :     sLastInputProcessed = now;
    7807             :   }
    7808             : 
    7809             :   return rv;
    7810             : }
    7811             : 
    7812             : #ifdef NIGHTLY_BUILD
    7813             : static already_AddRefed<nsIURI>
    7814           0 : GetDocumentURIToCompareWithBlacklist(PresShell& aPresShell)
    7815             : {
    7816           0 :   nsPresContext* presContext = aPresShell.GetPresContext();
    7817           0 :   if (NS_WARN_IF(!presContext)) {
    7818             :     return nullptr;
    7819             :   }
    7820             :   // If the document is sandboxed document or data: document, we should
    7821             :   // get URI of the parent document.
    7822           0 :   for (nsIDocument* document = presContext->Document();
    7823           0 :        document && document->IsContentDocument();
    7824             :        document = document->GetParentDocument()) {
    7825             :     // The document URI may be about:blank even if it comes from actual web
    7826             :     // site.  Therefore, we need to check the URI of its principal.
    7827           0 :     nsIPrincipal* principal = document->NodePrincipal();
    7828           0 :     if (principal->GetIsNullPrincipal()) {
    7829           0 :       continue;
    7830             :     }
    7831           0 :     nsCOMPtr<nsIURI> uri;
    7832           0 :     principal->GetURI(getter_AddRefs(uri));
    7833           0 :     return uri.forget();
    7834             :   }
    7835             :   return nullptr;
    7836             : }
    7837             : 
    7838             : static bool
    7839           0 : DispatchKeyPressEventsEvenForNonPrintableKeys(nsIURI* aURI)
    7840             : {
    7841           0 :   if (!aURI) {
    7842             :     return false;
    7843             :   }
    7844             : 
    7845           0 :   nsAutoCString scheme;
    7846           0 :   aURI->GetScheme(scheme);
    7847           0 :   if (!scheme.EqualsLiteral("http") &&
    7848           0 :       !scheme.EqualsLiteral("https")) {
    7849             :     return false;
    7850             :   }
    7851             : 
    7852           0 :   nsAutoCString host;
    7853           0 :   aURI->GetHost(host);
    7854           0 :   if (host.IsEmpty()) {
    7855             :     return false;
    7856             :   }
    7857             : 
    7858             :   // The black list is comma separated domain list.  Each item may start with
    7859             :   // "*.".  If starts with "*.", it matches any sub-domains.
    7860             :   static const char* kPrefNameOfBlackList =
    7861             :     "dom.keyboardevent.keypress.hack.dispatch_non_printable_keys";
    7862             : 
    7863           0 :   nsAutoCString blackList;
    7864           0 :   Preferences::GetCString(kPrefNameOfBlackList, blackList);
    7865           0 :   if (blackList.IsEmpty()) {
    7866             :     return false;
    7867             :   }
    7868             : 
    7869             :   for (;;) {
    7870           0 :     int32_t index = blackList.Find(host, false);
    7871           0 :     if (index >= 0 &&
    7872           0 :         static_cast<uint32_t>(index) + host.Length() <= blackList.Length() &&
    7873             :         // If start of the black list or next to ","?
    7874           0 :         (!index || blackList[index - 1] == ',')) {
    7875             :       // If end of the black list or immediately before ","?
    7876           0 :       size_t indexAfterHost = index + host.Length();
    7877           0 :       if (indexAfterHost == blackList.Length() ||
    7878           0 :           blackList[indexAfterHost] == ',') {
    7879             :         return true;
    7880             :       }
    7881             :       // If next character is '/', we need to check the path too.
    7882             :       // We assume the path in blacklist means "/foo" + "*".
    7883           0 :       if (blackList[indexAfterHost] == '/') {
    7884           0 :         int32_t endOfPath = blackList.Find(",", false, indexAfterHost);
    7885             :         nsDependentCSubstring::size_type length =
    7886             :           endOfPath < 0 ? static_cast<nsDependentCSubstring::size_type>(-1) :
    7887           0 :                           endOfPath - indexAfterHost;
    7888             :         nsDependentCSubstring pathInBlackList(blackList,
    7889           0 :                                               indexAfterHost, length);
    7890           0 :         nsAutoCString filePath;
    7891           0 :         aURI->GetFilePath(filePath);
    7892           0 :         if (StringBeginsWith(filePath, pathInBlackList)) {
    7893           0 :           return true;
    7894             :         }
    7895             :       }
    7896             :     }
    7897           0 :     int32_t startIndexOfCurrentLevel = host[0] == '*' ? 1 : 0;
    7898             :     int32_t startIndexOfNextLevel =
    7899           0 :       host.Find(".", false, startIndexOfCurrentLevel + 1);
    7900           0 :     if (startIndexOfNextLevel <= 0) {
    7901             :       return false;
    7902             :     }
    7903           0 :     host = NS_LITERAL_CSTRING("*") +
    7904           0 :              nsDependentCSubstring(host, startIndexOfNextLevel);
    7905           0 :   }
    7906             :   return false;
    7907             : }
    7908             : #endif // #ifdef NIGHTLY_BUILD
    7909             : 
    7910             : nsresult
    7911           0 : PresShell::DispatchEventToDOM(WidgetEvent* aEvent,
    7912             :                               nsEventStatus* aStatus,
    7913             :                               nsPresShellEventCB* aEventCB)
    7914             : {
    7915           0 :   nsresult rv = NS_OK;
    7916           0 :   nsCOMPtr<nsINode> eventTarget = mCurrentEventContent.get();
    7917           0 :   nsPresShellEventCB* eventCBPtr = aEventCB;
    7918           0 :   if (!eventTarget) {
    7919           0 :     nsCOMPtr<nsIContent> targetContent;
    7920           0 :     if (mCurrentEventFrame) {
    7921           0 :       rv = mCurrentEventFrame->
    7922           0 :              GetContentForEvent(aEvent, getter_AddRefs(targetContent));
    7923             :     }
    7924           0 :     if (NS_SUCCEEDED(rv) && targetContent) {
    7925           0 :       eventTarget = do_QueryInterface(targetContent);
    7926           0 :     } else if (mDocument) {
    7927           0 :       eventTarget = do_QueryInterface(mDocument);
    7928             :       // If we don't have any content, the callback wouldn't probably
    7929             :       // do nothing.
    7930           0 :       eventCBPtr = nullptr;
    7931             :     }
    7932             :   }
    7933           0 :   if (eventTarget) {
    7934           0 :     if (aEvent->IsBlockedForFingerprintingResistance()) {
    7935           0 :       aEvent->mFlags.mOnlySystemGroupDispatchInContent = true;
    7936             : #ifdef NIGHTLY_BUILD
    7937           0 :     } else if (aEvent->mMessage == eKeyPress &&
    7938           0 :                aEvent->mFlags.mOnlySystemGroupDispatchInContent) {
    7939             :       // If eKeyPress event is marked as not dispatched in the default event
    7940             :       // group in web content, it's caused by non-printable key or key
    7941             :       // combination.  In this case, UI Events declares that browsers
    7942             :       // shouldn't dispatch keypress event.  However, some web apps may be
    7943             :       // broken with this strict behavior due to historical issue.
    7944             :       // Therefore, we need to keep dispatching keypress event for such keys
    7945             :       // even with breaking the standard.
    7946           0 :       if (!mInitializedForceDispatchKeyPressEventsForNonPrintableKeys) {
    7947           0 :         mInitializedForceDispatchKeyPressEventsForNonPrintableKeys = true;
    7948           0 :         nsCOMPtr<nsIURI> uri = GetDocumentURIToCompareWithBlacklist(*this);
    7949           0 :         mForceDispatchKeyPressEventsForNonPrintableKeys =
    7950           0 :           DispatchKeyPressEventsEvenForNonPrintableKeys(uri);
    7951             :       }
    7952           0 :       if (mForceDispatchKeyPressEventsForNonPrintableKeys) {
    7953           0 :         aEvent->mFlags.mOnlySystemGroupDispatchInContent = false;
    7954             :       }
    7955             : #endif // #ifdef NIGHTLY_BUILD
    7956             :     }
    7957             : 
    7958           0 :     if (aEvent->mClass == eCompositionEventClass) {
    7959           0 :       IMEStateManager::DispatchCompositionEvent(eventTarget, mPresContext,
    7960           0 :                                                 aEvent->AsCompositionEvent(),
    7961           0 :                                                 aStatus, eventCBPtr);
    7962             :     } else {
    7963           0 :       EventDispatcher::Dispatch(eventTarget, mPresContext,
    7964           0 :                                 aEvent, nullptr, aStatus, eventCBPtr);
    7965             :     }
    7966             :   }
    7967           0 :   return rv;
    7968             : }
    7969             : 
    7970             : void
    7971           0 : PresShell::DispatchTouchEventToDOM(WidgetEvent* aEvent,
    7972             :                                    nsEventStatus* aStatus,
    7973             :                                    nsPresShellEventCB* aEventCB,
    7974             :                                    bool aTouchIsNew)
    7975             : {
    7976             :   // calling preventDefault on touchstart or the first touchmove for a
    7977             :   // point prevents mouse events. calling it on the touchend should
    7978             :   // prevent click dispatching.
    7979           0 :   bool canPrevent = (aEvent->mMessage == eTouchStart) ||
    7980           0 :                     (aEvent->mMessage == eTouchMove && aTouchIsNew) ||
    7981           0 :                     (aEvent->mMessage == eTouchEnd);
    7982           0 :   bool preventDefault = false;
    7983           0 :   nsEventStatus tmpStatus = nsEventStatus_eIgnore;
    7984           0 :   WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
    7985             : 
    7986             :   // loop over all touches and dispatch events on any that have changed
    7987           0 :   for (dom::Touch* touch : touchEvent->mTouches) {
    7988             :     // We should remove all suppressed touch instances in
    7989             :     // TouchManager::PreHandleEvent.
    7990           0 :     MOZ_ASSERT(!touch->mIsTouchEventSuppressed);
    7991             : 
    7992           0 :     if (!touch || !touch->mChanged) {
    7993           0 :       continue;
    7994             :     }
    7995             : 
    7996           0 :     nsCOMPtr<EventTarget> targetPtr = touch->mTarget;
    7997           0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(targetPtr);
    7998           0 :     if (!content) {
    7999           0 :       continue;
    8000             :     }
    8001             : 
    8002           0 :     nsIDocument* doc = content->OwnerDoc();
    8003           0 :     nsIContent* capturingContent = GetCapturingContent();
    8004           0 :     if (capturingContent) {
    8005           0 :       if (capturingContent->OwnerDoc() != doc) {
    8006             :         // Wrong document, don't dispatch anything.
    8007             :         continue;
    8008             :       }
    8009           0 :       content = capturingContent;
    8010             :     }
    8011             :     // copy the event
    8012           0 :     WidgetTouchEvent newEvent(touchEvent->IsTrusted(),
    8013           0 :                               touchEvent->mMessage, touchEvent->mWidget);
    8014           0 :     newEvent.AssignTouchEventData(*touchEvent, false);
    8015           0 :     newEvent.mTarget = targetPtr;
    8016           0 :     newEvent.mFlags.mHandledByAPZ = touchEvent->mFlags.mHandledByAPZ;
    8017             : 
    8018           0 :     RefPtr<PresShell> contentPresShell;
    8019           0 :     if (doc == mDocument) {
    8020           0 :       contentPresShell = static_cast<PresShell*>(doc->GetShell());
    8021           0 :       if (contentPresShell) {
    8022             :         //XXXsmaug huge hack. Pushing possibly capturing content,
    8023             :         //         even though event target is something else.
    8024           0 :         contentPresShell->PushCurrentEventInfo(
    8025           0 :             content->GetPrimaryFrame(), content);
    8026             :       }
    8027             :     }
    8028             : 
    8029           0 :     nsPresContext *context = doc->GetPresContext();
    8030           0 :     if (!context) {
    8031           0 :       continue;
    8032             :     }
    8033             : 
    8034           0 :     tmpStatus = nsEventStatus_eIgnore;
    8035             :     EventDispatcher::Dispatch(targetPtr, context,
    8036           0 :                               &newEvent, nullptr, &tmpStatus, aEventCB);
    8037           0 :     if (nsEventStatus_eConsumeNoDefault == tmpStatus ||
    8038           0 :         newEvent.mFlags.mMultipleActionsPrevented) {
    8039           0 :       preventDefault = true;
    8040             :     }
    8041             : 
    8042           0 :     if (newEvent.mFlags.mMultipleActionsPrevented) {
    8043           0 :       touchEvent->mFlags.mMultipleActionsPrevented = true;
    8044             :     }
    8045             : 
    8046           0 :     if (contentPresShell) {
    8047           0 :       contentPresShell->PopCurrentEventInfo();
    8048             :     }
    8049             :   }
    8050             : 
    8051           0 :   if (preventDefault && canPrevent) {
    8052           0 :     *aStatus = nsEventStatus_eConsumeNoDefault;
    8053             :   } else {
    8054           0 :     *aStatus = nsEventStatus_eIgnore;
    8055             :   }
    8056           0 : }
    8057             : 
    8058             : // Dispatch event to content only (NOT full processing)
    8059             : // See also HandleEventWithTarget which does full event processing.
    8060             : nsresult
    8061           0 : PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent,
    8062             :                                     WidgetEvent* aEvent,
    8063             :                                     nsEventStatus* aStatus)
    8064             : {
    8065           0 :   nsresult rv = NS_OK;
    8066             : 
    8067           0 :   PushCurrentEventInfo(nullptr, aTargetContent);
    8068             : 
    8069             :   // Bug 41013: Check if the event should be dispatched to content.
    8070             :   // It's possible that we are in the middle of destroying the window
    8071             :   // and the js context is out of date. This check detects the case
    8072             :   // that caused a crash in bug 41013, but there may be a better way
    8073             :   // to handle this situation!
    8074           0 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
    8075           0 :   if (container) {
    8076             : 
    8077             :     // Dispatch event to content
    8078           0 :     rv = EventDispatcher::Dispatch(aTargetContent, mPresContext, aEvent,
    8079           0 :                                    nullptr, aStatus);
    8080             :   }
    8081             : 
    8082           0 :   PopCurrentEventInfo();
    8083           0 :   return rv;
    8084             : }
    8085             : 
    8086             : // See the method above.
    8087             : nsresult
    8088           0 : PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent,
    8089             :                                     Event* aEvent,
    8090             :                                     nsEventStatus* aStatus)
    8091             : {
    8092           0 :   nsresult rv = NS_OK;
    8093             : 
    8094           0 :   PushCurrentEventInfo(nullptr, aTargetContent);
    8095           0 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
    8096           0 :   if (container) {
    8097           0 :     rv = EventDispatcher::DispatchDOMEvent(aTargetContent, nullptr, aEvent,
    8098           0 :                                            mPresContext, aStatus);
    8099             :   }
    8100             : 
    8101           0 :   PopCurrentEventInfo();
    8102           0 :   return rv;
    8103             : }
    8104             : 
    8105             : bool
    8106           0 : PresShell::AdjustContextMenuKeyEvent(WidgetMouseEvent* aEvent)
    8107             : {
    8108             : #ifdef MOZ_XUL
    8109             :   // if a menu is open, open the context menu relative to the active item on the menu.
    8110           0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    8111           0 :   if (pm) {
    8112           0 :     nsIFrame* popupFrame = pm->GetTopPopup(ePopupTypeMenu);
    8113           0 :     if (popupFrame) {
    8114             :       nsIFrame* itemFrame =
    8115           0 :         (static_cast<nsMenuPopupFrame *>(popupFrame))->GetCurrentMenuItem();
    8116           0 :       if (!itemFrame)
    8117           0 :         itemFrame = popupFrame;
    8118             : 
    8119           0 :       nsCOMPtr<nsIWidget> widget = popupFrame->GetNearestWidget();
    8120           0 :       aEvent->mWidget = widget;
    8121           0 :       LayoutDeviceIntPoint widgetPoint = widget->WidgetToScreenOffset();
    8122           0 :       aEvent->mRefPoint = LayoutDeviceIntPoint::FromAppUnitsToNearest(
    8123           0 :         itemFrame->GetScreenRectInAppUnits().BottomLeft(),
    8124           0 :         itemFrame->PresContext()->AppUnitsPerDevPixel()) - widgetPoint;
    8125             : 
    8126           0 :       mCurrentEventContent = itemFrame->GetContent();
    8127           0 :       mCurrentEventFrame = itemFrame;
    8128             : 
    8129             :       return true;
    8130             :     }
    8131             :   }
    8132             : #endif
    8133             : 
    8134             :   // If we're here because of the key-equiv for showing context menus, we
    8135             :   // have to twiddle with the NS event to make sure the context menu comes
    8136             :   // up in the upper left of the relevant content area before we create
    8137             :   // the DOM event. Since we never call InitMouseEvent() on the event,
    8138             :   // the client X/Y will be 0,0. We can make use of that if the widget is null.
    8139             :   // Use the root view manager's widget since it's most likely to have one,
    8140             :   // and the coordinates returned by GetCurrentItemAndPositionForElement
    8141             :   // are relative to the widget of the root of the root view manager.
    8142           0 :   nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
    8143           0 :   aEvent->mRefPoint = LayoutDeviceIntPoint(0, 0);
    8144           0 :   if (rootPC) {
    8145             :     rootPC->PresShell()->GetViewManager()->
    8146           0 :       GetRootWidget(getter_AddRefs(aEvent->mWidget));
    8147             : 
    8148           0 :     if (aEvent->mWidget) {
    8149             :       // default the refpoint to the topleft of our document
    8150           0 :       nsPoint offset(0, 0);
    8151           0 :       nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    8152           0 :       if (rootFrame) {
    8153           0 :         nsView* view = rootFrame->GetClosestView(&offset);
    8154           0 :         offset += view->GetOffsetToWidget(aEvent->mWidget);
    8155             :         aEvent->mRefPoint =
    8156           0 :           LayoutDeviceIntPoint::FromAppUnitsToNearest(offset, mPresContext->AppUnitsPerDevPixel());
    8157             :       }
    8158             :     }
    8159             :   } else {
    8160           0 :     aEvent->mWidget = nullptr;
    8161             :   }
    8162             : 
    8163             :   // see if we should use the caret position for the popup
    8164           0 :   LayoutDeviceIntPoint caretPoint;
    8165             :   // Beware! This may flush notifications via synchronous
    8166             :   // ScrollSelectionIntoView.
    8167           0 :   if (PrepareToUseCaretPosition(aEvent->mWidget, caretPoint)) {
    8168             :     // caret position is good
    8169           0 :     aEvent->mRefPoint = caretPoint;
    8170           0 :     return true;
    8171             :   }
    8172             : 
    8173             :   // If we're here because of the key-equiv for showing context menus, we
    8174             :   // have to reset the event target to the currently focused element. Get it
    8175             :   // from the focus controller.
    8176           0 :   RefPtr<Element> currentFocus;
    8177           0 :   nsFocusManager* fm = nsFocusManager::GetFocusManager();
    8178           0 :   if (fm) {
    8179           0 :     currentFocus = fm->GetFocusedElement();
    8180             :   }
    8181             : 
    8182             :   // Reset event coordinates relative to focused frame in view
    8183           0 :   if (currentFocus) {
    8184           0 :     nsCOMPtr<nsIContent> currentPointElement;
    8185           0 :     GetCurrentItemAndPositionForElement(currentFocus,
    8186           0 :                                         getter_AddRefs(currentPointElement),
    8187             :                                         aEvent->mRefPoint,
    8188           0 :                                         aEvent->mWidget);
    8189           0 :     if (currentPointElement) {
    8190           0 :       mCurrentEventContent = currentPointElement;
    8191           0 :       mCurrentEventFrame = nullptr;
    8192           0 :       GetCurrentEventFrame();
    8193             :     }
    8194             :   }
    8195             : 
    8196             :   return true;
    8197             : }
    8198             : 
    8199             : // PresShell::PrepareToUseCaretPosition
    8200             : //
    8201             : //    This checks to see if we should use the caret position for popup context
    8202             : //    menus. Returns true if the caret position should be used, and the
    8203             : //    coordinates of that position is returned in aTargetPt. This function
    8204             : //    will also scroll the window as needed to make the caret visible.
    8205             : //
    8206             : //    The event widget should be the widget that generated the event, and
    8207             : //    whose coordinate system the resulting event's mRefPoint should be
    8208             : //    relative to.  The returned point is in device pixels realtive to the
    8209             : //    widget passed in.
    8210             : bool
    8211           0 : PresShell::PrepareToUseCaretPosition(nsIWidget* aEventWidget,
    8212             :                                      LayoutDeviceIntPoint& aTargetPt)
    8213             : {
    8214             :   nsresult rv;
    8215             : 
    8216             :   // check caret visibility
    8217           0 :   RefPtr<nsCaret> caret = GetCaret();
    8218           0 :   NS_ENSURE_TRUE(caret, false);
    8219             : 
    8220           0 :   bool caretVisible = caret->IsVisible();
    8221           0 :   if (!caretVisible)
    8222             :     return false;
    8223             : 
    8224             :   // caret selection, this is a temporary weak reference, so no refcounting is
    8225             :   // needed
    8226           0 :   Selection* domSelection = caret->GetSelection();
    8227           0 :   NS_ENSURE_TRUE(domSelection, false);
    8228             : 
    8229             :   // since the match could be an anonymous textnode inside a
    8230             :   // <textarea> or text <input>, we need to get the outer frame
    8231             :   // note: frames are not refcounted
    8232           0 :   nsIFrame* frame = nullptr; // may be nullptr
    8233           0 :   nsINode* node = domSelection->GetFocusNode();
    8234           0 :   NS_ENSURE_TRUE(node, false);
    8235           0 :   nsCOMPtr<nsIContent> content = nsIContent::FromNode(node);
    8236           0 :   if (content) {
    8237           0 :     nsIContent* nonNative = content->FindFirstNonChromeOnlyAccessContent();
    8238           0 :     content = nonNative;
    8239             :   }
    8240             : 
    8241           0 :   if (content) {
    8242             :     // It seems like ScrollSelectionIntoView should be enough, but it's
    8243             :     // not. The problem is that scrolling the selection into view when it is
    8244             :     // below the current viewport will align the top line of the frame exactly
    8245             :     // with the bottom of the window. This is fine, BUT, the popup event causes
    8246             :     // the control to be re-focused which does this exact call to
    8247             :     // ScrollContentIntoView, which has a one-pixel disagreement of whether the
    8248             :     // frame is actually in view. The result is that the frame is aligned with
    8249             :     // the top of the window, but the menu is still at the bottom.
    8250             :     //
    8251             :     // Doing this call first forces the frame to be in view, eliminating the
    8252             :     // problem. The only difference in the result is that if your cursor is in
    8253             :     // an edit box below the current view, you'll get the edit box aligned with
    8254             :     // the top of the window. This is arguably better behavior anyway.
    8255           0 :     rv = ScrollContentIntoView(content,
    8256             :                                nsIPresShell::ScrollAxis(
    8257             :                                  nsIPresShell::SCROLL_MINIMUM,
    8258             :                                  nsIPresShell::SCROLL_IF_NOT_VISIBLE),
    8259             :                                nsIPresShell::ScrollAxis(
    8260             :                                  nsIPresShell::SCROLL_MINIMUM,
    8261             :                                  nsIPresShell::SCROLL_IF_NOT_VISIBLE),
    8262           0 :                                nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
    8263           0 :     NS_ENSURE_SUCCESS(rv, false);
    8264           0 :     frame = content->GetPrimaryFrame();
    8265           0 :     NS_WARNING_ASSERTION(frame, "No frame for focused content?");
    8266             :   }
    8267             : 
    8268             :   // Actually scroll the selection (ie caret) into view. Note that this must
    8269             :   // be synchronous since we will be checking the caret position on the screen.
    8270             :   //
    8271             :   // Be easy about errors, and just don't scroll in those cases. Better to have
    8272             :   // the correct menu at a weird place than the wrong menu.
    8273             :   // After ScrollSelectionIntoView(), the pending notifications might be
    8274             :   // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
    8275           0 :   nsCOMPtr<nsISelectionController> selCon;
    8276           0 :   if (frame)
    8277           0 :     frame->GetSelectionController(GetPresContext(), getter_AddRefs(selCon));
    8278             :   else
    8279           0 :     selCon = static_cast<nsISelectionController *>(this);
    8280           0 :   if (selCon) {
    8281           0 :     rv = selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
    8282             :                                          nsISelectionController::SELECTION_FOCUS_REGION,
    8283           0 :                                          nsISelectionController::SCROLL_SYNCHRONOUS);
    8284           0 :     NS_ENSURE_SUCCESS(rv, false);
    8285             :   }
    8286             : 
    8287           0 :   nsPresContext* presContext = GetPresContext();
    8288             : 
    8289             :   // get caret position relative to the closest view
    8290           0 :   nsRect caretCoords;
    8291           0 :   nsIFrame* caretFrame = caret->GetGeometry(&caretCoords);
    8292           0 :   if (!caretFrame)
    8293             :     return false;
    8294           0 :   nsPoint viewOffset;
    8295           0 :   nsView* view = caretFrame->GetClosestView(&viewOffset);
    8296           0 :   if (!view)
    8297             :     return false;
    8298             :   // and then get the caret coords relative to the event widget
    8299           0 :   if (aEventWidget) {
    8300           0 :     viewOffset += view->GetOffsetToWidget(aEventWidget);
    8301             :   }
    8302           0 :   caretCoords.MoveBy(viewOffset);
    8303             : 
    8304             :   // caret coordinates are in app units, convert to pixels
    8305           0 :   aTargetPt.x =
    8306           0 :     presContext->AppUnitsToDevPixels(caretCoords.x + caretCoords.width);
    8307             :   aTargetPt.y =
    8308           0 :     presContext->AppUnitsToDevPixels(caretCoords.y + caretCoords.height);
    8309             : 
    8310             :   // make sure rounding doesn't return a pixel which is outside the caret
    8311             :   // (e.g. one line lower)
    8312           0 :   aTargetPt.y -= 1;
    8313             : 
    8314           0 :   return true;
    8315             : }
    8316             : 
    8317             : void
    8318           0 : PresShell::GetCurrentItemAndPositionForElement(Element* aFocusedElement,
    8319             :                                                nsIContent** aTargetToUse,
    8320             :                                                LayoutDeviceIntPoint& aTargetPt,
    8321             :                                                nsIWidget *aRootWidget)
    8322             : {
    8323           0 :   nsCOMPtr<nsIContent> focusedContent = aFocusedElement;
    8324           0 :   ScrollContentIntoView(focusedContent,
    8325             :                         ScrollAxis(),
    8326             :                         ScrollAxis(),
    8327           0 :                         nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
    8328             : 
    8329           0 :   nsPresContext* presContext = GetPresContext();
    8330             : 
    8331           0 :   bool istree = false, checkLineHeight = true;
    8332           0 :   nscoord extraTreeY = 0;
    8333             : 
    8334             : #ifdef MOZ_XUL
    8335             :   // Set the position to just underneath the current item for multi-select
    8336             :   // lists or just underneath the selected item for single-select lists. If
    8337             :   // the element is not a list, or there is no selection, leave the position
    8338             :   // as is.
    8339           0 :   nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
    8340             :   nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
    8341           0 :     do_QueryInterface(aFocusedElement);
    8342           0 :   if (multiSelect) {
    8343           0 :     checkLineHeight = false;
    8344             : 
    8345             :     int32_t currentIndex;
    8346           0 :     multiSelect->GetCurrentIndex(&currentIndex);
    8347           0 :     if (currentIndex >= 0) {
    8348           0 :       RefPtr<nsXULElement> xulElement = nsXULElement::FromNode(focusedContent);
    8349           0 :       if (xulElement) {
    8350           0 :         nsCOMPtr<nsIBoxObject> box = xulElement->GetBoxObject(IgnoreErrors());
    8351           0 :         nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box));
    8352             :         // Tree view special case (tree items have no frames)
    8353             :         // Get the focused row and add its coordinates, which are already in pixels
    8354             :         // XXX Boris, should we create a new interface so that this doesn't
    8355             :         // need to know about trees? Something like nsINodelessChildCreator which
    8356             :         // could provide the current focus coordinates?
    8357           0 :         if (treeBox) {
    8358           0 :           treeBox->EnsureRowIsVisible(currentIndex);
    8359             :           int32_t firstVisibleRow, rowHeight;
    8360           0 :           treeBox->GetFirstVisibleRow(&firstVisibleRow);
    8361           0 :           treeBox->GetRowHeight(&rowHeight);
    8362             : 
    8363           0 :           extraTreeY += nsPresContext::CSSPixelsToAppUnits(
    8364           0 :                           (currentIndex - firstVisibleRow + 1) * rowHeight);
    8365           0 :           istree = true;
    8366             : 
    8367           0 :           RefPtr<nsTreeColumns> cols;
    8368           0 :           treeBox->GetColumns(getter_AddRefs(cols));
    8369           0 :           if (cols) {
    8370           0 :             nsTreeColumn* col = cols->GetFirstColumn();
    8371           0 :             if (col) {
    8372           0 :               RefPtr<Element> colElement = col->Element();
    8373           0 :               nsIFrame* frame = colElement->GetPrimaryFrame();
    8374           0 :               if (frame) {
    8375           0 :                 extraTreeY += frame->GetSize().height;
    8376             :               }
    8377             :             }
    8378             :           }
    8379             :         }
    8380             :         else {
    8381           0 :           multiSelect->GetCurrentItem(getter_AddRefs(item));
    8382             :         }
    8383             :       }
    8384             :     }
    8385             :   }
    8386             :   else {
    8387             :     // don't check menulists as the selected item will be inside a popup.
    8388           0 :     nsCOMPtr<nsIDOMXULMenuListElement> menulist = do_QueryInterface(aFocusedElement);
    8389           0 :     if (!menulist) {
    8390             :       nsCOMPtr<nsIDOMXULSelectControlElement> select =
    8391           0 :         do_QueryInterface(aFocusedElement);
    8392           0 :       if (select) {
    8393           0 :         checkLineHeight = false;
    8394           0 :         select->GetSelectedItem(getter_AddRefs(item));
    8395             :       }
    8396             :     }
    8397             :   }
    8398             : 
    8399           0 :   if (item)
    8400           0 :     focusedContent = do_QueryInterface(item);
    8401             : #endif
    8402             : 
    8403           0 :   nsIFrame *frame = focusedContent->GetPrimaryFrame();
    8404           0 :   if (frame) {
    8405           0 :     NS_ASSERTION(frame->PresContext() == GetPresContext(),
    8406             :       "handling event for focused content that is not in our document?");
    8407             : 
    8408           0 :     nsPoint frameOrigin(0, 0);
    8409             : 
    8410             :     // Get the frame's origin within its view
    8411           0 :     nsView *view = frame->GetClosestView(&frameOrigin);
    8412           0 :     NS_ASSERTION(view, "No view for frame");
    8413             : 
    8414             :     // View's origin relative the widget
    8415           0 :     if (aRootWidget) {
    8416           0 :       frameOrigin += view->GetOffsetToWidget(aRootWidget);
    8417             :     }
    8418             : 
    8419             :     // Start context menu down and to the right from top left of frame
    8420             :     // use the lineheight. This is a good distance to move the context
    8421             :     // menu away from the top left corner of the frame. If we always
    8422             :     // used the frame height, the context menu could end up far away,
    8423             :     // for example when we're focused on linked images.
    8424             :     // On the other hand, we want to use the frame height if it's less
    8425             :     // than the current line height, so that the context menu appears
    8426             :     // associated with the correct frame.
    8427           0 :     nscoord extra = 0;
    8428           0 :     if (!istree) {
    8429           0 :       extra = frame->GetSize().height;
    8430           0 :       if (checkLineHeight) {
    8431             :         nsIScrollableFrame *scrollFrame =
    8432           0 :           nsLayoutUtils::GetNearestScrollableFrame(frame);
    8433           0 :         if (scrollFrame) {
    8434           0 :           nsSize scrollAmount = scrollFrame->GetLineScrollAmount();
    8435           0 :           nsIFrame* f = do_QueryFrame(scrollFrame);
    8436           0 :           int32_t APD = presContext->AppUnitsPerDevPixel();
    8437           0 :           int32_t scrollAPD = f->PresContext()->AppUnitsPerDevPixel();
    8438           0 :           scrollAmount = scrollAmount.ScaleToOtherAppUnits(scrollAPD, APD);
    8439           0 :           if (extra > scrollAmount.height) {
    8440           0 :             extra = scrollAmount.height;
    8441             :           }
    8442             :         }
    8443             :       }
    8444             :     }
    8445             : 
    8446           0 :     aTargetPt.x = presContext->AppUnitsToDevPixels(frameOrigin.x);
    8447           0 :     aTargetPt.y = presContext->AppUnitsToDevPixels(
    8448           0 :                     frameOrigin.y + extra + extraTreeY);
    8449             :   }
    8450             : 
    8451           0 :   NS_IF_ADDREF(*aTargetToUse = focusedContent);
    8452           0 : }
    8453             : 
    8454             : bool
    8455           0 : PresShell::ShouldIgnoreInvalidation()
    8456             : {
    8457           0 :   return mPaintingSuppressed || !mIsActive || mIsNeverPainting;
    8458             : }
    8459             : 
    8460             : void
    8461           1 : PresShell::WillPaint()
    8462             : {
    8463             :   // Check the simplest things first.  In particular, it's important to
    8464             :   // check mIsActive before making any of the more expensive calls such
    8465             :   // as GetRootPresContext, for the case of a browser with a large
    8466             :   // number of tabs.
    8467             :   // Don't bother doing anything if some viewmanager in our tree is painting
    8468             :   // while we still have painting suppressed or we are not active.
    8469          28 :   if (!mIsActive || mPaintingSuppressed || !IsVisible()) {
    8470             :     return;
    8471             :   }
    8472             : 
    8473           0 :   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
    8474          22 :   if (!rootPresContext) {
    8475             :     // In some edge cases, such as when we don't have a root frame yet,
    8476             :     // we can't find the root prescontext. There's nothing to do in that
    8477             :     // case.
    8478             :     return;
    8479             :   }
    8480             : 
    8481          22 :   rootPresContext->FlushWillPaintObservers();
    8482          22 :   if (mIsDestroying)
    8483             :     return;
    8484             : 
    8485             :   // Process reflows, if we have them, to reduce flicker due to invalidates and
    8486             :   // reflow being interspersed.  Note that we _do_ allow this to be
    8487             :   // interruptible; if we can't do all the reflows it's better to flicker a bit
    8488             :   // than to freeze up.
    8489          22 :   FlushPendingNotifications(ChangesToFlush(FlushType::InterruptibleLayout, false));
    8490             : }
    8491             : 
    8492             : void
    8493           0 : PresShell::WillPaintWindow()
    8494             : {
    8495           0 :   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
    8496           0 :   if (rootPresContext != mPresContext) {
    8497             :     // This could be a popup's presshell. We don't allow plugins in popups
    8498             :     // so there's nothing to do here.
    8499             :     return;
    8500             :   }
    8501             : 
    8502             : #ifndef XP_MACOSX
    8503           0 :   rootPresContext->ApplyPluginGeometryUpdates();
    8504             : #endif
    8505             : }
    8506             : 
    8507             : void
    8508           0 : PresShell::DidPaintWindow()
    8509             : {
    8510           0 :   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
    8511           0 :   if (rootPresContext != mPresContext) {
    8512             :     // This could be a popup's presshell. No point in notifying XPConnect
    8513             :     // about compositing of popups.
    8514             :     return;
    8515             :   }
    8516             : 
    8517           0 :   if (!mHasReceivedPaintMessage) {
    8518           0 :     mHasReceivedPaintMessage = true;
    8519             : 
    8520           0 :     nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService();
    8521           0 :     if (obsvc && mDocument) {
    8522           0 :       nsPIDOMWindowOuter* window = mDocument->GetWindow();
    8523           0 :       nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(window));
    8524           0 :       if (chromeWin) {
    8525           0 :         obsvc->NotifyObservers(chromeWin, "widget-first-paint", nullptr);
    8526             :       }
    8527             :     }
    8528             :   }
    8529             : }
    8530             : 
    8531             : bool
    8532          73 : PresShell::IsVisible()
    8533             : {
    8534          73 :   if (!mIsActive || !mViewManager)
    8535             :     return false;
    8536             : 
    8537          73 :   nsView* view = mViewManager->GetRootView();
    8538           0 :   if (!view)
    8539             :     return true;
    8540             : 
    8541             :   // inner view of subdoc frame
    8542           0 :   view = view->GetParent();
    8543          73 :   if (!view)
    8544             :     return true;
    8545             : 
    8546             :   // subdoc view
    8547           0 :   view = view->GetParent();
    8548          12 :   if (!view)
    8549             :     return true;
    8550             : 
    8551           0 :   nsIFrame* frame = view->GetFrame();
    8552           0 :   if (!frame)
    8553             :     return true;
    8554             : 
    8555           0 :   return frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY);
    8556             : }
    8557             : 
    8558             : nsresult
    8559           0 : PresShell::GetAgentStyleSheets(nsTArray<RefPtr<StyleSheet>>& aSheets)
    8560             : {
    8561           0 :   aSheets.Clear();
    8562           0 :   int32_t sheetCount = mStyleSet->SheetCount(SheetType::Agent);
    8563             : 
    8564           0 :   if (!aSheets.SetCapacity(sheetCount, fallible)) {
    8565             :     return NS_ERROR_OUT_OF_MEMORY;
    8566             :   }
    8567             : 
    8568           0 :   for (int32_t i = 0; i < sheetCount; ++i) {
    8569           0 :     StyleSheet* sheet = mStyleSet->StyleSheetAt(SheetType::Agent, i);
    8570           0 :     aSheets.AppendElement(sheet);
    8571             :   }
    8572             : 
    8573             :   return NS_OK;
    8574             : }
    8575             : 
    8576             : nsresult
    8577           0 : PresShell::SetAgentStyleSheets(const nsTArray<RefPtr<StyleSheet>>& aSheets)
    8578             : {
    8579           0 :   return mStyleSet->ReplaceSheets(SheetType::Agent, aSheets);
    8580             : }
    8581             : 
    8582             : nsresult
    8583           0 : PresShell::AddOverrideStyleSheet(StyleSheet* aSheet)
    8584             : {
    8585           0 :   return mStyleSet->PrependStyleSheet(SheetType::Override, aSheet);
    8586             : }
    8587             : 
    8588             : nsresult
    8589           0 : PresShell::RemoveOverrideStyleSheet(StyleSheet* aSheet)
    8590             : {
    8591           0 :   return mStyleSet->RemoveStyleSheet(SheetType::Override, aSheet);
    8592             : }
    8593             : 
    8594             : static void
    8595           0 : FreezeElement(nsISupports *aSupports, void * /* unused */)
    8596             : {
    8597           0 :   nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aSupports));
    8598           0 :   if (olc) {
    8599           0 :     olc->StopPluginInstance();
    8600             :   }
    8601           0 : }
    8602             : 
    8603             : static bool
    8604           0 : FreezeSubDocument(nsIDocument *aDocument, void *aData)
    8605             : {
    8606           0 :   nsIPresShell *shell = aDocument->GetShell();
    8607           0 :   if (shell)
    8608           0 :     shell->Freeze();
    8609             : 
    8610           0 :   return true;
    8611             : }
    8612             : 
    8613             : void
    8614           0 : PresShell::Freeze()
    8615             : {
    8616           0 :   mUpdateApproximateFrameVisibilityEvent.Revoke();
    8617             : 
    8618           0 :   MaybeReleaseCapturingContent();
    8619             : 
    8620           0 :   mDocument->EnumerateActivityObservers(FreezeElement, nullptr);
    8621             : 
    8622           0 :   if (mCaret) {
    8623           0 :     SetCaretEnabled(false);
    8624             :   }
    8625             : 
    8626           0 :   mPaintingSuppressed = true;
    8627             : 
    8628           0 :   if (mDocument) {
    8629           0 :     mDocument->EnumerateSubDocuments(FreezeSubDocument, nullptr);
    8630             :   }
    8631             : 
    8632           0 :   nsPresContext* presContext = GetPresContext();
    8633           0 :   if (presContext) {
    8634           0 :     presContext->DisableInteractionTimeRecording();
    8635           0 :     if (presContext->RefreshDriver()->GetPresContext() == presContext) {
    8636           0 :       presContext->RefreshDriver()->Freeze();
    8637             :     }
    8638             :   }
    8639             : 
    8640           0 :   mFrozen = true;
    8641           0 :   if (mDocument) {
    8642           0 :     UpdateImageLockingState();
    8643             :   }
    8644           0 : }
    8645             : 
    8646             : void
    8647           0 : PresShell::FireOrClearDelayedEvents(bool aFireEvents)
    8648             : {
    8649           0 :   mNoDelayedMouseEvents = false;
    8650           0 :   mNoDelayedKeyEvents = false;
    8651           0 :   if (!aFireEvents) {
    8652           0 :     mDelayedEvents.Clear();
    8653           0 :     return;
    8654             :   }
    8655             : 
    8656           0 :   if (mDocument) {
    8657           0 :     nsCOMPtr<nsIDocument> doc = mDocument;
    8658           0 :     while (!mIsDestroying && mDelayedEvents.Length() &&
    8659           0 :            !doc->EventHandlingSuppressed()) {
    8660           0 :       nsAutoPtr<DelayedEvent> ev(mDelayedEvents[0].forget());
    8661           0 :       mDelayedEvents.RemoveElementAt(0);
    8662           0 :       if (ev->IsKeyPressEvent() && mIsLastKeyDownCanceled) {
    8663           0 :         continue;
    8664             :       }
    8665           0 :       ev->Dispatch();
    8666             :     }
    8667           0 :     if (!doc->EventHandlingSuppressed()) {
    8668           0 :       mDelayedEvents.Clear();
    8669             :     }
    8670             :   }
    8671             : }
    8672             : 
    8673             : static void
    8674           0 : ThawElement(nsISupports *aSupports, void *aShell)
    8675             : {
    8676           0 :   nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aSupports));
    8677           0 :   if (olc) {
    8678           0 :     olc->AsyncStartPluginInstance();
    8679             :   }
    8680           0 : }
    8681             : 
    8682             : static bool
    8683           0 : ThawSubDocument(nsIDocument *aDocument, void *aData)
    8684             : {
    8685           0 :   nsIPresShell *shell = aDocument->GetShell();
    8686           0 :   if (shell)
    8687           0 :     shell->Thaw();
    8688             : 
    8689           0 :   return true;
    8690             : }
    8691             : 
    8692             : void
    8693           0 : PresShell::Thaw()
    8694             : {
    8695           0 :   nsPresContext* presContext = GetPresContext();
    8696           0 :   if (presContext &&
    8697           0 :       presContext->RefreshDriver()->GetPresContext() == presContext) {
    8698           0 :     presContext->RefreshDriver()->Thaw();
    8699             :   }
    8700             : 
    8701           0 :   mDocument->EnumerateActivityObservers(ThawElement, this);
    8702             : 
    8703           0 :   if (mDocument)
    8704           0 :     mDocument->EnumerateSubDocuments(ThawSubDocument, nullptr);
    8705             : 
    8706             :   // Get the activeness of our presshell, as this might have changed
    8707             :   // while we were in the bfcache
    8708           0 :   QueryIsActive();
    8709             : 
    8710             :   // We're now unfrozen
    8711           0 :   mFrozen = false;
    8712           0 :   UpdateImageLockingState();
    8713             : 
    8714           0 :   UnsuppressPainting();
    8715           0 : }
    8716             : 
    8717             : //--------------------------------------------------------
    8718             : // Start of protected and private methods on the PresShell
    8719             : //--------------------------------------------------------
    8720             : 
    8721             : void
    8722         110 : PresShell::MaybeScheduleReflow()
    8723             : {
    8724         440 :   ASSERT_REFLOW_SCHEDULED_STATE();
    8725         142 :   if (mObservingLayoutFlushes || mIsDestroying || mIsReflowing ||
    8726           0 :       mDirtyRoots.IsEmpty())
    8727             :     return;
    8728             : 
    8729           0 :   if (!mPresContext->HasPendingInterrupt() || !ScheduleReflowOffTimer()) {
    8730           0 :     ScheduleReflow();
    8731             :   }
    8732             : 
    8733           0 :   ASSERT_REFLOW_SCHEDULED_STATE();
    8734             : }
    8735             : 
    8736             : void
    8737           0 : PresShell::ScheduleReflow()
    8738             : {
    8739         120 :   ASSERT_REFLOW_SCHEDULED_STATE();
    8740          30 :   DoObserveLayoutFlushes();
    8741           0 :   ASSERT_REFLOW_SCHEDULED_STATE();
    8742          30 : }
    8743             : 
    8744             : nsresult
    8745           0 : PresShell::DidCauseReflow()
    8746             : {
    8747         717 :   NS_ASSERTION(mChangeNestCount != 0, "Unexpected call to DidCauseReflow()");
    8748         717 :   --mChangeNestCount;
    8749           0 :   nsContentUtils::RemoveScriptBlocker();
    8750             : 
    8751           0 :   return NS_OK;
    8752             : }
    8753             : 
    8754             : void
    8755           0 : PresShell::WillDoReflow()
    8756             : {
    8757          45 :   mDocument->FlushUserFontSet();
    8758             : 
    8759           0 :   mPresContext->FlushCounterStyles();
    8760             : 
    8761           0 :   mPresContext->FlushFontFeatureValues();
    8762             : 
    8763           0 :   mLastReflowStart = GetPerformanceNowUnclamped();
    8764          45 : }
    8765             : 
    8766             : void
    8767           0 : PresShell::DidDoReflow(bool aInterruptible)
    8768             : {
    8769          45 :   HandlePostedReflowCallbacks(aInterruptible);
    8770             : 
    8771           0 :   nsCOMPtr<nsIDocShell> docShell = mPresContext->GetDocShell();
    8772          45 :   if (docShell) {
    8773           0 :     DOMHighResTimeStamp now = GetPerformanceNowUnclamped();
    8774          21 :     docShell->NotifyReflowObservers(aInterruptible, mLastReflowStart, now);
    8775             :   }
    8776             : 
    8777           0 :   if (sSynthMouseMove) {
    8778           0 :     SynthesizeMouseMove(false);
    8779             :   }
    8780             : 
    8781           0 :   mPresContext->NotifyMissingFonts();
    8782           0 : }
    8783             : 
    8784             : DOMHighResTimeStamp
    8785           0 : PresShell::GetPerformanceNowUnclamped()
    8786             : {
    8787          66 :   DOMHighResTimeStamp now = 0;
    8788             : 
    8789           0 :   if (nsPIDOMWindowInner* window = mDocument->GetInnerWindow()) {
    8790          42 :     Performance* perf = window->GetPerformance();
    8791             : 
    8792          42 :     if (perf) {
    8793           0 :       now = perf->NowUnclamped();
    8794             :     }
    8795             :   }
    8796             : 
    8797           0 :   return now;
    8798             : }
    8799             : 
    8800             : void
    8801           0 : PresShell::sReflowContinueCallback(nsITimer* aTimer, void* aPresShell)
    8802             : {
    8803           0 :   RefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
    8804             : 
    8805           0 :   MOZ_ASSERT(aTimer == self->mReflowContinueTimer, "Unexpected timer");
    8806           0 :   self->mReflowContinueTimer = nullptr;
    8807           0 :   self->ScheduleReflow();
    8808           0 : }
    8809             : 
    8810             : bool
    8811           0 : PresShell::ScheduleReflowOffTimer()
    8812             : {
    8813           0 :   MOZ_ASSERT(!mObservingLayoutFlushes, "Shouldn't get here");
    8814           0 :   ASSERT_REFLOW_SCHEDULED_STATE();
    8815             : 
    8816           0 :   if (!mReflowContinueTimer) {
    8817           0 :     nsresult rv = NS_NewTimerWithFuncCallback(
    8818           0 :         getter_AddRefs(mReflowContinueTimer),
    8819             :         sReflowContinueCallback, this, 30,
    8820             :         nsITimer::TYPE_ONE_SHOT,
    8821             :         "sReflowContinueCallback",
    8822           0 :         mDocument->EventTargetFor(TaskCategory::Other));
    8823           0 :     return NS_SUCCEEDED(rv);
    8824             :   }
    8825             :   return true;
    8826             : }
    8827             : 
    8828             : bool
    8829          50 : PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
    8830             : {
    8831         100 :   gfxTextPerfMetrics* tp = mPresContext->GetTextPerfMetrics();
    8832          50 :   TimeStamp timeStart;
    8833           0 :   if (tp) {
    8834           0 :     tp->Accumulate();
    8835           0 :     tp->reflowCount++;
    8836           0 :     timeStart = TimeStamp::Now();
    8837             :   }
    8838             : 
    8839             :   // Schedule a paint, but don't actually mark this frame as changed for
    8840             :   // retained DL building purposes. If any child frames get moved, then
    8841             :   // they will schedule paint again. We could probaby skip this, and just
    8842             :   // schedule a similar paint when a frame is deleted.
    8843          50 :   target->SchedulePaint(nsIFrame::PAINT_DEFAULT, false);
    8844             : 
    8845             : #ifdef MOZ_GECKO_PROFILER
    8846         100 :   nsIURI* uri = mDocument->GetDocumentURI();
    8847           0 :   AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
    8848             :     "PresShell::DoReflow", LAYOUT,
    8849             :     uri ? uri->GetSpecOrDefault() : NS_LITERAL_CSTRING("N/A"));
    8850             : #endif
    8851             : 
    8852         100 :   nsDocShell* docShell = static_cast<nsDocShell*>(GetPresContext()->GetDocShell());
    8853         150 :   RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
    8854          50 :   bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
    8855             : 
    8856           0 :   if (isTimelineRecording) {
    8857           0 :     timelines->AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::START);
    8858             :   }
    8859             : 
    8860           0 :   if (mReflowContinueTimer) {
    8861           0 :     mReflowContinueTimer->Cancel();
    8862           0 :     mReflowContinueTimer = nullptr;
    8863             :   }
    8864             : 
    8865           0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
    8866             : 
    8867             :   // CreateReferenceRenderingContext can return nullptr
    8868         150 :   RefPtr<gfxContext> rcx(CreateReferenceRenderingContext());
    8869             : 
    8870             : #ifdef DEBUG
    8871          50 :   mCurrentReflowRoot = target;
    8872             : #endif
    8873             : 
    8874             :   // If the target frame is the root of the frame hierarchy, then
    8875             :   // use all the available space. If it's simply a `reflow root',
    8876             :   // then use the target frame's size as the available space.
    8877          50 :   WritingMode wm = target->GetWritingMode();
    8878          50 :   LogicalSize size(wm);
    8879          50 :   if (target == rootFrame) {
    8880         120 :     size = LogicalSize(wm, mPresContext->GetVisibleArea().Size());
    8881             :   } else {
    8882           0 :     size = target->GetLogicalSize();
    8883             :   }
    8884             : 
    8885          50 :   NS_ASSERTION(!target->GetNextInFlow() && !target->GetPrevInFlow(),
    8886             :                "reflow roots should never split");
    8887             : 
    8888             :   // Don't pass size directly to the reflow state, since a
    8889             :   // constrained height implies page/column breaking.
    8890         100 :   LogicalSize reflowSize(wm, size.ISize(wm), NS_UNCONSTRAINEDSIZE);
    8891             :   ReflowInput reflowInput(mPresContext, target, rcx, reflowSize,
    8892         100 :                                 ReflowInput::CALLER_WILL_INIT);
    8893          50 :   reflowInput.mOrthogonalLimit = size.BSize(wm);
    8894             : 
    8895          50 :   if (rootFrame == target) {
    8896           0 :     reflowInput.Init(mPresContext);
    8897             : 
    8898             :     // When the root frame is being reflowed with unconstrained block-size
    8899             :     // (which happens when we're called from
    8900             :     // nsDocumentViewer::SizeToContent), we're effectively doing a
    8901             :     // resize in the block direction, since it changes the meaning of
    8902             :     // percentage block-sizes even if no block-sizes actually changed.
    8903             :     // The same applies when we reflow again after that computation. This is
    8904             :     // an unusual case, and isn't caught by ReflowInput::InitResizeFlags.
    8905          40 :     bool hasUnconstrainedBSize = size.BSize(wm) == NS_UNCONSTRAINEDSIZE;
    8906             : 
    8907          40 :     if (hasUnconstrainedBSize || mLastRootReflowHadUnconstrainedBSize) {
    8908             :       reflowInput.SetBResize(true);
    8909             :     }
    8910             : 
    8911           0 :     mLastRootReflowHadUnconstrainedBSize = hasUnconstrainedBSize;
    8912             :   } else {
    8913             :     // Initialize reflow state with current used border and padding,
    8914             :     // in case this was set specially by the parent frame when the reflow root
    8915             :     // was reflowed by its parent.
    8916          10 :     nsMargin currentBorder = target->GetUsedBorder();
    8917          10 :     nsMargin currentPadding = target->GetUsedPadding();
    8918          20 :     reflowInput.Init(mPresContext, nullptr, &currentBorder, &currentPadding);
    8919             :   }
    8920             : 
    8921             :   // fix the computed height
    8922           0 :   NS_ASSERTION(reflowInput.ComputedPhysicalMargin() == nsMargin(0, 0, 0, 0),
    8923             :                "reflow state should not set margin for reflow roots");
    8924          50 :   if (size.BSize(wm) != NS_UNCONSTRAINEDSIZE) {
    8925             :     nscoord computedBSize =
    8926           0 :       size.BSize(wm) - reflowInput.ComputedLogicalBorderPadding().BStartEnd(wm);
    8927         100 :     computedBSize = std::max(computedBSize, 0);
    8928           0 :     reflowInput.SetComputedBSize(computedBSize);
    8929             :   }
    8930           0 :   NS_ASSERTION(reflowInput.ComputedISize() ==
    8931             :                size.ISize(wm) -
    8932             :                    reflowInput.ComputedLogicalBorderPadding().IStartEnd(wm),
    8933             :                "reflow state computed incorrect inline size");
    8934             : 
    8935          50 :   mPresContext->ReflowStarted(aInterruptible);
    8936          50 :   mIsReflowing = true;
    8937             : 
    8938          50 :   nsReflowStatus status;
    8939           0 :   ReflowOutput desiredSize(reflowInput);
    8940           0 :   target->Reflow(mPresContext, desiredSize, reflowInput, status);
    8941             : 
    8942             :   // If an incremental reflow is initiated at a frame other than the
    8943             :   // root frame, then its desired size had better not change!  If it's
    8944             :   // initiated at the root, then the size better not change unless its
    8945             :   // height was unconstrained to start with.
    8946         150 :   nsRect boundsRelativeToTarget = nsRect(0, 0, desiredSize.Width(), desiredSize.Height());
    8947          50 :   NS_ASSERTION((target == rootFrame &&
    8948             :                 size.BSize(wm) == NS_UNCONSTRAINEDSIZE) ||
    8949             :                (desiredSize.ISize(wm) == size.ISize(wm) &&
    8950             :                 desiredSize.BSize(wm) == size.BSize(wm)),
    8951             :                "non-root frame's desired size changed during an "
    8952             :                "incremental reflow");
    8953          60 :   NS_ASSERTION(target == rootFrame ||
    8954             :                desiredSize.VisualOverflow().IsEqualInterior(boundsRelativeToTarget),
    8955             :                "non-root reflow roots must not have visible overflow");
    8956          60 :   NS_ASSERTION(target == rootFrame ||
    8957             :                desiredSize.ScrollableOverflow().IsEqualEdges(boundsRelativeToTarget),
    8958             :                "non-root reflow roots must not have scrollable overflow");
    8959          50 :   NS_ASSERTION(status.IsEmpty(),
    8960             :                "reflow roots should never split");
    8961             : 
    8962         100 :   target->SetSize(boundsRelativeToTarget.Size());
    8963             : 
    8964             :   // Always use boundsRelativeToTarget here, not desiredSize.GetVisualOverflowArea(),
    8965             :   // because for root frames (where they could be different, since root frames
    8966             :   // are allowed to have overflow) the root view bounds need to match the
    8967             :   // viewport bounds; the view manager "window dimensions" code depends on it.
    8968         150 :   nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, target,
    8969             :                                              target->GetView(),
    8970         100 :                                              boundsRelativeToTarget);
    8971         150 :   nsContainerFrame::SyncWindowProperties(mPresContext, target,
    8972             :                                          target->GetView(), rcx,
    8973         100 :                                          nsContainerFrame::SET_ASYNC);
    8974             : 
    8975           0 :   target->DidReflow(mPresContext, nullptr);
    8976          50 :   if (target == rootFrame && size.BSize(wm) == NS_UNCONSTRAINEDSIZE) {
    8977           0 :     mPresContext->SetVisibleArea(boundsRelativeToTarget);
    8978             :   }
    8979             : 
    8980             : #ifdef DEBUG
    8981           0 :   mCurrentReflowRoot = nullptr;
    8982             : #endif
    8983             : 
    8984         150 :   NS_ASSERTION(mPresContext->HasPendingInterrupt() ||
    8985             :                mFramesToDirty.Count() == 0,
    8986             :                "Why do we need to dirty anything if not interrupted?");
    8987             : 
    8988           0 :   mIsReflowing = false;
    8989         100 :   bool interrupted = mPresContext->HasPendingInterrupt();
    8990          50 :   if (interrupted) {
    8991             :     // Make sure target gets reflowed again.
    8992           0 :     for (auto iter = mFramesToDirty.Iter(); !iter.Done(); iter.Next()) {
    8993             :       // Mark frames dirty until target frame.
    8994           0 :       nsPtrHashKey<nsIFrame>* p = iter.Get();
    8995           0 :       for (nsIFrame* f = p->GetKey();
    8996           0 :            f && !NS_SUBTREE_DIRTY(f);
    8997           0 :            f = f->GetParent()) {
    8998           0 :         f->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
    8999             : 
    9000           0 :         if (f == target) {
    9001             :           break;
    9002             :         }
    9003             :       }
    9004             :     }
    9005             : 
    9006           0 :     NS_ASSERTION(NS_SUBTREE_DIRTY(target), "Why is the target not dirty?");
    9007           0 :     mDirtyRoots.AppendElement(target);
    9008           0 :     SetNeedLayoutFlush();
    9009             : 
    9010             :     // Clear mFramesToDirty after we've done the NS_SUBTREE_DIRTY(target)
    9011             :     // assertion so that if it fails it's easier to see what's going on.
    9012             : #ifdef NOISY_INTERRUPTIBLE_REFLOW
    9013             :     printf("mFramesToDirty.Count() == %u\n", mFramesToDirty.Count());
    9014             : #endif /* NOISY_INTERRUPTIBLE_REFLOW */
    9015           0 :     mFramesToDirty.Clear();
    9016             : 
    9017             :     // Any FlushPendingNotifications with interruptible reflows
    9018             :     // should be suppressed now. We don't want to do extra reflow work
    9019             :     // before our reflow event happens.
    9020           0 :     mWasLastReflowInterrupted = true;
    9021           0 :     MaybeScheduleReflow();
    9022             :   }
    9023             : 
    9024             :   // dump text perf metrics for reflows with significant text processing
    9025           0 :   if (tp) {
    9026           0 :     if (tp->current.numChars > 100) {
    9027           0 :       TimeDuration reflowTime = TimeStamp::Now() - timeStart;
    9028           0 :       LogTextPerfStats(tp, this, tp->current,
    9029           0 :                        reflowTime.ToMilliseconds(), eLog_reflow, nullptr);
    9030             :     }
    9031           0 :     tp->Accumulate();
    9032             :   }
    9033             : 
    9034          50 :   if (isTimelineRecording) {
    9035           0 :     timelines->AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::END);
    9036             :   }
    9037             : 
    9038           0 :   return !interrupted;
    9039             : }
    9040             : 
    9041             : #ifdef DEBUG
    9042             : void
    9043          33 : PresShell::DoVerifyReflow()
    9044             : {
    9045          33 :   if (GetVerifyReflowEnable()) {
    9046             :     // First synchronously render what we have so far so that we can
    9047             :     // see it.
    9048           0 :     nsView* rootView = mViewManager->GetRootView();
    9049           0 :     mViewManager->InvalidateView(rootView);
    9050             : 
    9051           0 :     FlushPendingNotifications(FlushType::Layout);
    9052           0 :     mInVerifyReflow = true;
    9053           0 :     bool ok = VerifyIncrementalReflow();
    9054           0 :     mInVerifyReflow = false;
    9055           0 :     if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) {
    9056           0 :       printf("ProcessReflowCommands: finished (%s)\n",
    9057             :              ok ? "ok" : "failed");
    9058             :     }
    9059             : 
    9060           0 :     if (!mDirtyRoots.IsEmpty()) {
    9061             :       printf("XXX yikes! reflow commands queued during verify-reflow\n");
    9062             :     }
    9063             :   }
    9064           1 : }
    9065             : #endif
    9066             : 
    9067             : // used with Telemetry metrics
    9068             : #define NS_LONG_REFLOW_TIME_MS    5000
    9069             : 
    9070             : bool
    9071          58 : PresShell::ProcessReflowCommands(bool aInterruptible)
    9072             : {
    9073         116 :   if (mDirtyRoots.IsEmpty() && !mShouldUnsuppressPainting) {
    9074             :     // Nothing to do; bail out
    9075             :     return true;
    9076             :   }
    9077             : 
    9078          33 :   mozilla::TimeStamp timerStart = mozilla::TimeStamp::Now();
    9079          33 :   bool interrupted = false;
    9080          66 :   if (!mDirtyRoots.IsEmpty()) {
    9081             : 
    9082             : #ifdef DEBUG
    9083           0 :     if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
    9084             :       printf("ProcessReflowCommands: begin incremental reflow\n");
    9085             :     }
    9086             : #endif
    9087             : 
    9088             :     // If reflow is interruptible, then make a note of our deadline.
    9089             :     const PRIntervalTime deadline = aInterruptible
    9090          33 :         ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime)
    9091          33 :         : (PRIntervalTime)0;
    9092             : 
    9093             :     // Scope for the reflow entry point
    9094             :     {
    9095           0 :       nsAutoScriptBlocker scriptBlocker;
    9096          33 :       WillDoReflow();
    9097         132 :       AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
    9098          66 :       nsViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
    9099             : 
    9100           0 :       do {
    9101             :         // Send an incremental reflow notification to the target frame.
    9102           0 :         int32_t idx = mDirtyRoots.Length() - 1;
    9103          76 :         nsIFrame *target = mDirtyRoots[idx];
    9104           0 :         mDirtyRoots.RemoveElementAt(idx);
    9105             : 
    9106           0 :         if (!NS_SUBTREE_DIRTY(target)) {
    9107             :           // It's not dirty anymore, which probably means the notification
    9108             :           // was posted in the middle of a reflow (perhaps with a reflow
    9109             :           // root in the middle).  Don't do anything.
    9110             :           continue;
    9111             :         }
    9112             : 
    9113          38 :         interrupted = !DoReflow(target, aInterruptible);
    9114             : 
    9115             :         // Keep going until we're out of reflow commands, or we've run
    9116             :         // past our deadline, or we're interrupted.
    9117           0 :       } while (!interrupted && !mDirtyRoots.IsEmpty() &&
    9118           5 :                (!aInterruptible || PR_IntervalNow() < deadline));
    9119             : 
    9120          66 :       interrupted = !mDirtyRoots.IsEmpty();
    9121             :     }
    9122             : 
    9123             :     // Exiting the scriptblocker might have killed us
    9124           0 :     if (!mIsDestroying) {
    9125          33 :       DidDoReflow(aInterruptible);
    9126             :     }
    9127             : 
    9128             :     // DidDoReflow might have killed us
    9129           0 :     if (!mIsDestroying) {
    9130             : #ifdef DEBUG
    9131          33 :       if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
    9132             :         printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n",
    9133             :                (void*)this);
    9134             :       }
    9135           0 :       DoVerifyReflow();
    9136             : #endif
    9137             : 
    9138             :       // If any new reflow commands were enqueued during the reflow, schedule
    9139             :       // another reflow event to process them.  Note that we want to do this
    9140             :       // after DidDoReflow(), since that method can change whether there are
    9141             :       // dirty roots around by flushing, and there's no point in posting a
    9142             :       // reflow event just to have the flush revoke it.
    9143          66 :       if (!mDirtyRoots.IsEmpty()) {
    9144           0 :         MaybeScheduleReflow();
    9145             :         // And record that we might need flushing
    9146           0 :         SetNeedLayoutFlush();
    9147             :       }
    9148             :     }
    9149             :   }
    9150             : 
    9151          46 :   if (!mIsDestroying && mShouldUnsuppressPainting &&
    9152          26 :       mDirtyRoots.IsEmpty()) {
    9153             :     // We only unlock if we're out of reflows.  It's pointless
    9154             :     // to unlock if reflows are still pending, since reflows
    9155             :     // are just going to thrash the frames around some more.  By
    9156             :     // waiting we avoid an overeager "jitter" effect.
    9157          13 :     mShouldUnsuppressPainting = false;
    9158          13 :     UnsuppressAndInvalidate();
    9159             :   }
    9160             : 
    9161           0 :   if (mDocument->GetRootElement()) {
    9162           0 :     TimeDuration elapsed = TimeStamp::Now() - timerStart;
    9163          33 :     int32_t intElapsed = int32_t(elapsed.ToMilliseconds());
    9164             : 
    9165           0 :     if (intElapsed > NS_LONG_REFLOW_TIME_MS) {
    9166           0 :       Telemetry::Accumulate(Telemetry::LONG_REFLOW_INTERRUPTIBLE,
    9167           0 :                             aInterruptible ? 1 : 0);
    9168             :     }
    9169             :   }
    9170             : 
    9171           0 :   return !interrupted;
    9172             : }
    9173             : 
    9174             : void
    9175           0 : PresShell::WindowSizeMoveDone()
    9176             : {
    9177           0 :   if (mPresContext) {
    9178           0 :     EventStateManager::ClearGlobalActiveContent(nullptr);
    9179           0 :     ClearMouseCapture(nullptr);
    9180             :   }
    9181           0 : }
    9182             : 
    9183             : #ifdef MOZ_XUL
    9184             : /*
    9185             :  * It's better to add stuff to the |DidSetComputedStyle| method of the
    9186             :  * relevant frames than adding it here.  These methods should (ideally,
    9187             :  * anyway) go away.
    9188             :  */
    9189             : 
    9190             : // Return value says whether to walk children.
    9191             : typedef bool (*frameWalkerFn)(nsIFrame* aFrame);
    9192             : 
    9193             : static bool
    9194           0 : ReResolveMenusAndTrees(nsIFrame* aFrame)
    9195             : {
    9196             :   // Trees have a special style cache that needs to be flushed when
    9197             :   // the theme changes.
    9198           0 :   nsTreeBodyFrame* treeBody = do_QueryFrame(aFrame);
    9199           0 :   if (treeBody)
    9200           0 :     treeBody->ClearStyleAndImageCaches();
    9201             : 
    9202             :   // We deliberately don't re-resolve style on a menu's popup
    9203             :   // sub-content, since doing so slows menus to a crawl.  That means we
    9204             :   // have to special-case them on a skin switch, and ensure that the
    9205             :   // popup frames just get destroyed completely.
    9206           0 :   nsMenuFrame* menu = do_QueryFrame(aFrame);
    9207           0 :   if (menu)
    9208           0 :     menu->CloseMenu(true);
    9209           0 :   return true;
    9210             : }
    9211             : 
    9212             : static bool
    9213           0 : ReframeImageBoxes(nsIFrame* aFrame)
    9214             : {
    9215           0 :   if (aFrame->IsImageBoxFrame()) {
    9216           0 :     aFrame->PresContext()->RestyleManager()->PostRestyleEvent(
    9217           0 :         aFrame->GetContent()->AsElement(),
    9218             :         nsRestyleHint(0),
    9219           0 :         nsChangeHint_ReconstructFrame);
    9220           0 :     return false; // don't walk descendants
    9221             :   }
    9222             :   return true; // walk descendants
    9223             : }
    9224             : 
    9225             : static void
    9226           0 : WalkFramesThroughPlaceholders(nsPresContext* aPresContext,
    9227             :                               nsIFrame* aFrame,
    9228             :                               frameWalkerFn aFunc)
    9229             : {
    9230           0 :   bool walkChildren = (*aFunc)(aFrame);
    9231           0 :   if (!walkChildren)
    9232           0 :     return;
    9233             : 
    9234           0 :   nsIFrame::ChildListIterator lists(aFrame);
    9235           0 :   for (; !lists.IsDone(); lists.Next()) {
    9236           0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    9237           0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    9238           0 :       nsIFrame* child = childFrames.get();
    9239           0 :       if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
    9240             :         // only do frames that are in flow, and recur through the
    9241             :         // out-of-flows of placeholders.
    9242           0 :         WalkFramesThroughPlaceholders(aPresContext,
    9243             :                                       nsPlaceholderFrame::GetRealFrameFor(child),
    9244           0 :                                       aFunc);
    9245             :       }
    9246             :     }
    9247             :   }
    9248             : }
    9249             : #endif
    9250             : 
    9251             : NS_IMETHODIMP
    9252          19 : PresShell::Observe(nsISupports* aSubject,
    9253             :                    const char* aTopic,
    9254             :                    const char16_t* aData)
    9255             : {
    9256           0 :   if (mIsDestroying) {
    9257           0 :     NS_WARNING("our observers should have been unregistered by now");
    9258           0 :     return NS_OK;
    9259             :   }
    9260             : 
    9261             : #ifdef MOZ_XUL
    9262           1 :   if (!nsCRT::strcmp(aTopic, "chrome-flush-skin-caches")) {
    9263             :     // Need to null-check because "chrome-flush-skin-caches" can happen
    9264             :     // at interesting times during startup.
    9265           0 :     if (nsIFrame* rootFrame = mFrameConstructor->GetRootFrame()) {
    9266           0 :       NS_ASSERTION(mViewManager, "View manager must exist");
    9267             : 
    9268           0 :       WalkFramesThroughPlaceholders(
    9269           0 :           mPresContext, rootFrame, ReResolveMenusAndTrees);
    9270             : 
    9271             :       // Because "chrome:" URL equality is messy, reframe image box
    9272             :       // frames (hack!).
    9273           0 :       WalkFramesThroughPlaceholders(
    9274           0 :           mPresContext, rootFrame, ReframeImageBoxes);
    9275             :     }
    9276             :     return NS_OK;
    9277             :   }
    9278             : #endif
    9279             : 
    9280          19 :   if (!nsCRT::strcmp(aTopic, "memory-pressure")) {
    9281           0 :     if (!AssumeAllFramesVisible() && mPresContext->IsRootContentDocument()) {
    9282           0 :       DoUpdateApproximateFrameVisibility(/* aRemoveOnly = */ true);
    9283             :     }
    9284             :     return NS_OK;
    9285             :   }
    9286             : 
    9287          19 :   if (!nsCRT::strcmp(aTopic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) {
    9288           0 :     mLastOSWake = TimeStamp::Now();
    9289           0 :     return NS_OK;
    9290             :   }
    9291             : 
    9292             :   // For parent process, user may expect the UI is interactable after a
    9293             :   // tab (previously opened page or home page) has restored.
    9294          19 :   if (!nsCRT::strcmp(aTopic, "sessionstore-one-or-no-tab-restored")) {
    9295          19 :     MOZ_ASSERT(XRE_IsParentProcess());
    9296          19 :     sProcessInteractable = true;
    9297             : 
    9298           0 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    9299           0 :     if (os) {
    9300           0 :       os->RemoveObserver(this, "sessionstore-one-or-no-tab-restored");
    9301             :     }
    9302             :     return NS_OK;
    9303             :   }
    9304             : 
    9305           0 :   if (!nsCRT::strcmp(aTopic, "font-info-updated")) {
    9306           0 :     mPresContext->ForceReflowForFontInfoUpdate();
    9307           0 :     return NS_OK;
    9308             :   }
    9309             : 
    9310           0 :   NS_WARNING("unrecognized topic in PresShell::Observe");
    9311           0 :   return NS_ERROR_FAILURE;
    9312             : }
    9313             : 
    9314             : bool
    9315           0 : nsIPresShell::AddRefreshObserver(nsARefreshObserver* aObserver,
    9316             :                                  FlushType aFlushType)
    9317             : {
    9318           0 :   nsPresContext* presContext = GetPresContext();
    9319           0 :   return presContext &&
    9320           0 :       presContext->RefreshDriver()->AddRefreshObserver(aObserver, aFlushType);
    9321             : }
    9322             : 
    9323             : bool
    9324           0 : nsIPresShell::RemoveRefreshObserver(nsARefreshObserver* aObserver,
    9325             :                                     FlushType aFlushType)
    9326             : {
    9327           0 :   nsPresContext* presContext = GetPresContext();
    9328           0 :   return presContext &&
    9329           0 :       presContext->RefreshDriver()->RemoveRefreshObserver(aObserver, aFlushType);
    9330             : }
    9331             : 
    9332             : /* virtual */ bool
    9333           0 : nsIPresShell::AddPostRefreshObserver(nsAPostRefreshObserver* aObserver)
    9334             : {
    9335           0 :   nsPresContext* presContext = GetPresContext();
    9336           0 :   if (!presContext) {
    9337             :     return false;
    9338             :   }
    9339           0 :   presContext->RefreshDriver()->AddPostRefreshObserver(aObserver);
    9340           0 :   return true;
    9341             : }
    9342             : 
    9343             : /* virtual */ bool
    9344           0 : nsIPresShell::RemovePostRefreshObserver(nsAPostRefreshObserver* aObserver)
    9345             : {
    9346           0 :   nsPresContext* presContext = GetPresContext();
    9347           0 :   if (!presContext) {
    9348             :     return false;
    9349             :   }
    9350           0 :   presContext->RefreshDriver()->RemovePostRefreshObserver(aObserver);
    9351           0 :   return true;
    9352             : }
    9353             : 
    9354             : void
    9355           0 : nsIPresShell::DoObserveStyleFlushes()
    9356             : {
    9357          44 :   MOZ_ASSERT(!ObservingStyleFlushes());
    9358          44 :   mObservingStyleFlushes = true;
    9359             : 
    9360          44 :   if (MOZ_LIKELY(!mDocument->GetBFCacheEntry())) {
    9361           0 :     mPresContext->RefreshDriver()->AddStyleFlushObserver(this);
    9362             :   }
    9363          44 : }
    9364             : 
    9365             : void
    9366          30 : nsIPresShell::DoObserveLayoutFlushes()
    9367             : {
    9368          30 :   MOZ_ASSERT(!ObservingLayoutFlushes());
    9369          30 :   mObservingLayoutFlushes = true;
    9370             : 
    9371          30 :   if (MOZ_LIKELY(!mDocument->GetBFCacheEntry())) {
    9372           0 :     mPresContext->RefreshDriver()->AddLayoutFlushObserver(this);
    9373             :   }
    9374          30 : }
    9375             : 
    9376             : //------------------------------------------------------
    9377             : // End of protected and private methods on the PresShell
    9378             : //------------------------------------------------------
    9379             : 
    9380             : //------------------------------------------------------------------
    9381             : //-- Delayed event Classes Impls
    9382             : //------------------------------------------------------------------
    9383             : 
    9384           0 : PresShell::DelayedInputEvent::DelayedInputEvent() :
    9385             :   DelayedEvent(),
    9386           0 :   mEvent(nullptr)
    9387             : {
    9388           0 : }
    9389             : 
    9390           0 : PresShell::DelayedInputEvent::~DelayedInputEvent()
    9391             : {
    9392           0 :   delete mEvent;
    9393           0 : }
    9394             : 
    9395             : void
    9396           0 : PresShell::DelayedInputEvent::Dispatch()
    9397             : {
    9398           0 :   if (!mEvent || !mEvent->mWidget) {
    9399           0 :     return;
    9400             :   }
    9401           0 :   nsCOMPtr<nsIWidget> widget = mEvent->mWidget;
    9402             :   nsEventStatus status;
    9403           0 :   widget->DispatchEvent(mEvent, status);
    9404             : }
    9405             : 
    9406           0 : PresShell::DelayedMouseEvent::DelayedMouseEvent(WidgetMouseEvent* aEvent) :
    9407           0 :   DelayedInputEvent()
    9408             : {
    9409             :   WidgetMouseEvent* mouseEvent =
    9410           0 :     new WidgetMouseEvent(aEvent->IsTrusted(),
    9411           0 :                          aEvent->mMessage,
    9412             :                          aEvent->mWidget,
    9413           0 :                          aEvent->mReason,
    9414           0 :                          aEvent->mContextMenuTrigger);
    9415           0 :   mouseEvent->AssignMouseEventData(*aEvent, false);
    9416           0 :   mEvent = mouseEvent;
    9417           0 : }
    9418             : 
    9419           0 : PresShell::DelayedKeyEvent::DelayedKeyEvent(WidgetKeyboardEvent* aEvent) :
    9420           0 :   DelayedInputEvent()
    9421             : {
    9422             :   WidgetKeyboardEvent* keyEvent =
    9423           0 :     new WidgetKeyboardEvent(aEvent->IsTrusted(),
    9424           0 :                             aEvent->mMessage,
    9425           0 :                             aEvent->mWidget);
    9426           0 :   keyEvent->AssignKeyEventData(*aEvent, false);
    9427           0 :   keyEvent->mFlags.mIsSynthesizedForTests = aEvent->mFlags.mIsSynthesizedForTests;
    9428           0 :   keyEvent->mFlags.mIsSuppressedOrDelayed = true;
    9429           0 :   mEvent = keyEvent;
    9430           0 : }
    9431             : 
    9432             : bool
    9433           0 : PresShell::DelayedKeyEvent::IsKeyPressEvent()
    9434             : {
    9435           0 :   return mEvent->mMessage == eKeyPress;
    9436             : }
    9437             : 
    9438             : // Start of DEBUG only code
    9439             : 
    9440             : #ifdef DEBUG
    9441             : 
    9442             : static void
    9443           0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg)
    9444             : {
    9445           0 :   nsAutoString n1, n2;
    9446           0 :   if (k1) {
    9447           0 :     k1->GetFrameName(n1);
    9448             :   } else {
    9449           0 :     n1.AssignLiteral(u"(null)");
    9450             :   }
    9451             : 
    9452           0 :   if (k2) {
    9453           0 :     k2->GetFrameName(n2);
    9454             :   } else {
    9455           0 :     n2.AssignLiteral(u"(null)");
    9456             :   }
    9457             : 
    9458           0 :   printf("verifyreflow: %s %p != %s %p  %s\n",
    9459           0 :          NS_LossyConvertUTF16toASCII(n1).get(), (void*)k1,
    9460           0 :          NS_LossyConvertUTF16toASCII(n2).get(), (void*)k2, aMsg);
    9461           0 : }
    9462             : 
    9463             : static void
    9464           0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
    9465             :                  const nsRect& r1, const nsRect& r2)
    9466             : {
    9467           0 :   printf("VerifyReflow Error:\n");
    9468           0 :   nsAutoString name;
    9469             : 
    9470           0 :   if (k1) {
    9471           0 :     k1->GetFrameName(name);
    9472           0 :     printf("  %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k1);
    9473             :   }
    9474           0 :   printf("{%d, %d, %d, %d} != \n", r1.x, r1.y, r1.width, r1.height);
    9475             : 
    9476           0 :   if (k2) {
    9477           0 :     k2->GetFrameName(name);
    9478           0 :     printf("  %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k2);
    9479             :   }
    9480             :   printf("{%d, %d, %d, %d}\n  %s\n",
    9481           0 :          r2.x, r2.y, r2.width, r2.height, aMsg);
    9482           0 : }
    9483             : 
    9484             : static void
    9485           0 : LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg,
    9486             :                  const nsIntRect& r1, const nsIntRect& r2)
    9487             : {
    9488           0 :   printf("VerifyReflow Error:\n");
    9489           0 :   nsAutoString name;
    9490             : 
    9491           0 :   if (k1) {
    9492           0 :     k1->GetFrameName(name);
    9493           0 :     printf("  %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k1);
    9494             :   }
    9495           0 :   printf("{%d, %d, %d, %d} != \n", r1.x, r1.y, r1.width, r1.height);
    9496             : 
    9497           0 :   if (k2) {
    9498           0 :     k2->GetFrameName(name);
    9499           0 :     printf("  %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k2);
    9500             :   }
    9501             :   printf("{%d, %d, %d, %d}\n  %s\n",
    9502           0 :          r2.x, r2.y, r2.width, r2.height, aMsg);
    9503           0 : }
    9504             : 
    9505             : static bool
    9506           0 : CompareTrees(nsPresContext* aFirstPresContext, nsIFrame* aFirstFrame,
    9507             :              nsPresContext* aSecondPresContext, nsIFrame* aSecondFrame)
    9508             : {
    9509           0 :   if (!aFirstPresContext || !aFirstFrame || !aSecondPresContext || !aSecondFrame)
    9510             :     return true;
    9511             :   // XXX Evil hack to reduce false positives; I can't seem to figure
    9512             :   // out how to flush scrollbar changes correctly
    9513             :   //if (aFirstFrame->IsScrollbarFrame())
    9514             :   //  return true;
    9515           0 :   bool ok = true;
    9516           0 :   nsIFrame::ChildListIterator lists1(aFirstFrame);
    9517           0 :   nsIFrame::ChildListIterator lists2(aSecondFrame);
    9518           0 :   do {
    9519           0 :     const nsFrameList& kids1 = !lists1.IsDone() ? lists1.CurrentList() : nsFrameList();
    9520           0 :     const nsFrameList& kids2 = !lists2.IsDone() ? lists2.CurrentList() : nsFrameList();
    9521           0 :     int32_t l1 = kids1.GetLength();
    9522           0 :     int32_t l2 = kids2.GetLength();
    9523           0 :     if (l1 != l2) {
    9524           0 :       ok = false;
    9525           0 :       LogVerifyMessage(kids1.FirstChild(), kids2.FirstChild(),
    9526           0 :                        "child counts don't match: ");
    9527           0 :       printf("%d != %d\n", l1, l2);
    9528           0 :       if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
    9529             :         break;
    9530             :       }
    9531             :     }
    9532             : 
    9533           0 :     LayoutDeviceIntRect r1, r2;
    9534             :     nsView* v1;
    9535             :     nsView* v2;
    9536           0 :     for (nsFrameList::Enumerator e1(kids1), e2(kids2);
    9537             :          ;
    9538           0 :          e1.Next(), e2.Next()) {
    9539           0 :       nsIFrame* k1 = e1.get();
    9540           0 :       nsIFrame* k2 = e2.get();
    9541           0 :       if (((nullptr == k1) && (nullptr != k2)) ||
    9542             :           ((nullptr != k1) && (nullptr == k2))) {
    9543           0 :         ok = false;
    9544           0 :         LogVerifyMessage(k1, k2, "child lists are different\n");
    9545           0 :         break;
    9546             :       }
    9547           0 :       else if (nullptr != k1) {
    9548             :         // Verify that the frames are the same size
    9549           0 :         if (!k1->GetRect().IsEqualInterior(k2->GetRect())) {
    9550           0 :           ok = false;
    9551           0 :           LogVerifyMessage(k1, k2, "(frame rects)", k1->GetRect(), k2->GetRect());
    9552             :         }
    9553             : 
    9554             :         // Make sure either both have views or neither have views; if they
    9555             :         // do have views, make sure the views are the same size. If the
    9556             :         // views have widgets, make sure they both do or neither does. If
    9557             :         // they do, make sure the widgets are the same size.
    9558           0 :         v1 = k1->GetView();
    9559           0 :         v2 = k2->GetView();
    9560           0 :         if (((nullptr == v1) && (nullptr != v2)) ||
    9561             :             ((nullptr != v1) && (nullptr == v2))) {
    9562           0 :           ok = false;
    9563           0 :           LogVerifyMessage(k1, k2, "child views are not matched\n");
    9564             :         }
    9565           0 :         else if (nullptr != v1) {
    9566           0 :           if (!v1->GetBounds().IsEqualInterior(v2->GetBounds())) {
    9567           0 :             LogVerifyMessage(k1, k2, "(view rects)", v1->GetBounds(), v2->GetBounds());
    9568             :           }
    9569             : 
    9570           0 :           nsIWidget* w1 = v1->GetWidget();
    9571           0 :           nsIWidget* w2 = v2->GetWidget();
    9572           0 :           if (((nullptr == w1) && (nullptr != w2)) ||
    9573             :               ((nullptr != w1) && (nullptr == w2))) {
    9574           0 :             ok = false;
    9575           0 :             LogVerifyMessage(k1, k2, "child widgets are not matched\n");
    9576             :           }
    9577           0 :           else if (nullptr != w1) {
    9578           0 :             r1 = w1->GetBounds();
    9579           0 :             r2 = w2->GetBounds();
    9580           0 :             if (!r1.IsEqualEdges(r2)) {
    9581             :               LogVerifyMessage(k1, k2, "(widget rects)",
    9582           0 :                                r1.ToUnknownRect(), r2.ToUnknownRect());
    9583             :             }
    9584             :           }
    9585             :         }
    9586           0 :         if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
    9587             :           break;
    9588             :         }
    9589             : 
    9590             :         // XXX Should perhaps compare their float managers.
    9591             : 
    9592             :         // Compare the sub-trees too
    9593           0 :         if (!CompareTrees(aFirstPresContext, k1, aSecondPresContext, k2)) {
    9594           0 :           ok = false;
    9595           0 :           if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
    9596             :             break;
    9597             :           }
    9598             :         }
    9599             :       }
    9600             :       else {
    9601             :         break;
    9602             :       }
    9603           0 :     }
    9604           0 :     if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) {
    9605             :       break;
    9606             :     }
    9607             : 
    9608           0 :     lists1.Next();
    9609           0 :     lists2.Next();
    9610           0 :     if (lists1.IsDone() != lists2.IsDone() ||
    9611           0 :         (!lists1.IsDone() && lists1.CurrentID() != lists2.CurrentID())) {
    9612           0 :       if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) {
    9613           0 :         ok = false;
    9614             :       }
    9615           0 :       LogVerifyMessage(kids1.FirstChild(), kids2.FirstChild(),
    9616           0 :                        "child list names are not matched: ");
    9617           0 :       fprintf(stdout, "%s != %s\n",
    9618           0 :               !lists1.IsDone() ? mozilla::layout::ChildListName(lists1.CurrentID()) : "(null)",
    9619           0 :               !lists2.IsDone() ? mozilla::layout::ChildListName(lists2.CurrentID()) : "(null)");
    9620             :       break;
    9621             :     }
    9622           0 :   } while (ok && !lists1.IsDone());
    9623             : 
    9624           0 :   return ok;
    9625             : }
    9626             : #endif
    9627             : 
    9628             : #if 0
    9629             : static nsIFrame*
    9630             : FindTopFrame(nsIFrame* aRoot)
    9631             : {
    9632             :   if (aRoot) {
    9633             :     nsIContent* content = aRoot->GetContent();
    9634             :     if (content) {
    9635             :       nsAtom* tag;
    9636             :       content->GetTag(tag);
    9637             :       if (nullptr != tag) {
    9638             :         NS_RELEASE(tag);
    9639             :         return aRoot;
    9640             :       }
    9641             :     }
    9642             : 
    9643             :     // Try one of the children
    9644             :     for (nsIFrame* kid : aRoot->PrincipalChildList()) {
    9645             :       nsIFrame* result = FindTopFrame(kid);
    9646             :       if (nullptr != result) {
    9647             :         return result;
    9648             :       }
    9649             :     }
    9650             :   }
    9651             :   return nullptr;
    9652             : }
    9653             : #endif
    9654             : 
    9655             : 
    9656             : #ifdef DEBUG
    9657             : 
    9658             : static void
    9659           0 : CopySheetsIntoClone(ServoStyleSet* aSet, ServoStyleSet* aClone)
    9660             : {
    9661           0 :   int32_t i, n = aSet->SheetCount(SheetType::Override);
    9662           0 :   for (i = 0; i < n; i++) {
    9663           0 :     StyleSheet* ss = aSet->StyleSheetAt(SheetType::Override, i);
    9664           0 :     if (ss)
    9665           0 :       aClone->AppendStyleSheet(SheetType::Override, ss);
    9666             :   }
    9667             : 
    9668             :   // The document expects to insert document stylesheets itself
    9669             : #if 0
    9670             :   n = aSet->SheetCount(SheetType::Doc);
    9671             :   for (i = 0; i < n; i++) {
    9672             :     StyleSheet* ss = aSet->StyleSheetAt(SheetType::Doc, i);
    9673             :     if (ss)
    9674             :       aClone->AddDocStyleSheet(ss, mDocument);
    9675             :   }
    9676             : #endif
    9677             : 
    9678           0 :   n = aSet->SheetCount(SheetType::User);
    9679           0 :   for (i = 0; i < n; i++) {
    9680           0 :     StyleSheet* ss = aSet->StyleSheetAt(SheetType::User, i);
    9681           0 :     if (ss)
    9682           0 :       aClone->AppendStyleSheet(SheetType::User, ss);
    9683             :   }
    9684             : 
    9685           0 :   n = aSet->SheetCount(SheetType::Agent);
    9686           0 :   for (i = 0; i < n; i++) {
    9687           0 :     StyleSheet* ss = aSet->StyleSheetAt(SheetType::Agent, i);
    9688           0 :     if (ss)
    9689           0 :       aClone->AppendStyleSheet(SheetType::Agent, ss);
    9690             :   }
    9691           0 : }
    9692             : 
    9693             : 
    9694             : UniquePtr<ServoStyleSet>
    9695           0 : PresShell::CloneStyleSet(ServoStyleSet* aSet)
    9696             : {
    9697           0 :   auto clone = MakeUnique<ServoStyleSet>();
    9698           0 :   CopySheetsIntoClone(aSet, clone.get());
    9699           0 :   return clone;
    9700             : }
    9701             : 
    9702             : // After an incremental reflow, we verify the correctness by doing a
    9703             : // full reflow into a fresh frame tree.
    9704             : bool
    9705           0 : PresShell::VerifyIncrementalReflow()
    9706             : {
    9707           0 :    if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
    9708             :      printf("Building Verification Tree...\n");
    9709             :    }
    9710             : 
    9711             :   // Create a presentation context to view the new frame tree
    9712             :   RefPtr<nsPresContext> cx =
    9713           0 :        new nsRootPresContext(mDocument, mPresContext->IsPaginated() ?
    9714             :                                         nsPresContext::eContext_PrintPreview :
    9715           0 :                                         nsPresContext::eContext_Galley);
    9716           0 :   NS_ENSURE_TRUE(cx, false);
    9717             : 
    9718           0 :   nsDeviceContext *dc = mPresContext->DeviceContext();
    9719           0 :   nsresult rv = cx->Init(dc);
    9720           0 :   NS_ENSURE_SUCCESS(rv, false);
    9721             : 
    9722             :   // Get our scrolling preference
    9723           0 :   nsView* rootView = mViewManager->GetRootView();
    9724           0 :   NS_ENSURE_TRUE(rootView->HasWidget(), false);
    9725           0 :   nsIWidget* parentWidget = rootView->GetWidget();
    9726             : 
    9727             :   // Create a new view manager.
    9728           0 :   RefPtr<nsViewManager> vm = new nsViewManager();
    9729           0 :   NS_ENSURE_TRUE(vm, false);
    9730           0 :   rv = vm->Init(dc);
    9731           0 :   NS_ENSURE_SUCCESS(rv, false);
    9732             : 
    9733             :   // Create a child window of the parent that is our "root view/window"
    9734             :   // Create a view
    9735           0 :   nsRect tbounds = mPresContext->GetVisibleArea();
    9736           0 :   nsView* view = vm->CreateView(tbounds, nullptr);
    9737           0 :   NS_ENSURE_TRUE(view, false);
    9738             : 
    9739             :   //now create the widget for the view
    9740           0 :   rv = view->CreateWidgetForParent(parentWidget, nullptr, true);
    9741           0 :   NS_ENSURE_SUCCESS(rv, false);
    9742             : 
    9743             :   // Setup hierarchical relationship in view manager
    9744           0 :   vm->SetRootView(view);
    9745             : 
    9746             :   // Make the new presentation context the same size as our
    9747             :   // presentation context.
    9748           0 :   cx->SetVisibleArea(mPresContext->GetVisibleArea());
    9749             : 
    9750             :   // Create a new presentation shell to view the document. Use the
    9751             :   // exact same style information that this document has.
    9752           0 :   UniquePtr<ServoStyleSet> newSet = CloneStyleSet(StyleSet());
    9753             : 
    9754           0 :   nsCOMPtr<nsIPresShell> sh = mDocument->CreateShell(cx, vm, std::move(newSet));
    9755           0 :   NS_ENSURE_TRUE(sh, false);
    9756             :   // Note that after we create the shell, we must make sure to destroy it
    9757           0 :   sh->SetVerifyReflowEnable(false); // turn off verify reflow while we're reflowing the test frame tree
    9758           0 :   vm->SetPresShell(sh);
    9759             :   {
    9760           0 :     nsAutoCauseReflowNotifier crNotifier(this);
    9761           0 :     sh->Initialize();
    9762             :   }
    9763           0 :   mDocument->BindingManager()->ProcessAttachedQueue();
    9764           0 :   sh->FlushPendingNotifications(FlushType::Layout);
    9765           0 :   sh->SetVerifyReflowEnable(true);  // turn on verify reflow again now that we're done reflowing the test frame tree
    9766             :   // Force the non-primary presshell to unsuppress; it doesn't want to normally
    9767             :   // because it thinks it's hidden
    9768           0 :   ((PresShell*)sh.get())->mPaintingSuppressed = false;
    9769           0 :   if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
    9770             :      printf("Verification Tree built, comparing...\n");
    9771             :   }
    9772             : 
    9773             :   // Now that the document has been reflowed, use its frame tree to
    9774             :   // compare against our frame tree.
    9775           0 :   nsIFrame* root1 = mFrameConstructor->GetRootFrame();
    9776           0 :   nsIFrame* root2 = sh->GetRootFrame();
    9777           0 :   bool ok = CompareTrees(mPresContext, root1, cx, root2);
    9778           0 :   if (!ok && (VERIFY_REFLOW_NOISY & gVerifyReflowFlags)) {
    9779           0 :     printf("Verify reflow failed, primary tree:\n");
    9780           0 :     root1->List(stdout, 0);
    9781           0 :     printf("Verification tree:\n");
    9782           0 :     root2->List(stdout, 0);
    9783             :   }
    9784             : 
    9785             : #if 0
    9786             :   // Sample code for dumping page to png
    9787             :   // XXX Needs to be made more flexible
    9788             :   if (!ok) {
    9789             :     nsString stra;
    9790             :     static int num = 0;
    9791             :     stra.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea");
    9792             :     stra.AppendInt(num);
    9793             :     stra.AppendLiteral(".png");
    9794             :     gfxUtils::WriteAsPNG(sh, stra);
    9795             :     nsString strb;
    9796             :     strb.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb");
    9797             :     strb.AppendInt(num);
    9798             :     strb.AppendLiteral(".png");
    9799             :     gfxUtils::WriteAsPNG(sh, strb);
    9800             :     ++num;
    9801             :   }
    9802             : #endif
    9803             : 
    9804           0 :   sh->EndObservingDocument();
    9805           0 :   sh->Destroy();
    9806           0 :   if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
    9807             :     printf("Finished Verifying Reflow...\n");
    9808             :   }
    9809             : 
    9810             :   return ok;
    9811             : }
    9812             : 
    9813             : // Layout debugging hooks
    9814             : void
    9815           0 : PresShell::ListComputedStyles(FILE *out, int32_t aIndent)
    9816             : {
    9817           0 :   nsIFrame* rootFrame = GetRootFrame();
    9818           0 :   if (rootFrame) {
    9819           0 :     rootFrame->Style()->List(out, aIndent);
    9820             :   }
    9821             : 
    9822             :   // The root element's frame's ComputedStyle is the root of a separate tree.
    9823           0 :   Element* rootElement = mDocument->GetRootElement();
    9824           0 :   if (rootElement) {
    9825           0 :     nsIFrame* rootElementFrame = rootElement->GetPrimaryFrame();
    9826           0 :     if (rootElementFrame) {
    9827           0 :       rootElementFrame->Style()->List(out, aIndent);
    9828             :     }
    9829             :   }
    9830           0 : }
    9831             : 
    9832             : void
    9833           0 : PresShell::ListStyleSheets(FILE *out, int32_t aIndent)
    9834             : {
    9835           0 :   int32_t sheetCount = mStyleSet->SheetCount(SheetType::Doc);
    9836           0 :   for (int32_t i = 0; i < sheetCount; ++i) {
    9837           0 :     mStyleSet->StyleSheetAt(SheetType::Doc, i)->List(out, aIndent);
    9838           0 :     fputs("\n", out);
    9839             :   }
    9840           0 : }
    9841             : #endif
    9842             : 
    9843             : //=============================================================
    9844             : //=============================================================
    9845             : //-- Debug Reflow Counts
    9846             : //=============================================================
    9847             : //=============================================================
    9848             : #ifdef MOZ_REFLOW_PERF
    9849             : //-------------------------------------------------------------
    9850             : void
    9851           8 : PresShell::DumpReflows()
    9852             : {
    9853           8 :   if (mReflowCountMgr) {
    9854          16 :     nsAutoCString uriStr;
    9855           0 :     if (mDocument) {
    9856          16 :       nsIURI *uri = mDocument->GetDocumentURI();
    9857           0 :       if (uri) {
    9858           0 :         uri->GetPathQueryRef(uriStr);
    9859             :       }
    9860             :     }
    9861           0 :     mReflowCountMgr->DisplayTotals(uriStr.get());
    9862           0 :     mReflowCountMgr->DisplayHTMLTotals(uriStr.get());
    9863           8 :     mReflowCountMgr->DisplayDiffsInTotals();
    9864             :   }
    9865           0 : }
    9866             : 
    9867             : //-------------------------------------------------------------
    9868             : void
    9869           0 : PresShell::CountReflows(const char * aName, nsIFrame * aFrame)
    9870             : {
    9871         353 :   if (mReflowCountMgr) {
    9872         353 :     mReflowCountMgr->Add(aName, aFrame);
    9873             :   }
    9874         353 : }
    9875             : 
    9876             : //-------------------------------------------------------------
    9877             : void
    9878           0 : PresShell::PaintCount(const char * aName,
    9879             :                       gfxContext* aRenderingContext,
    9880             :                       nsPresContext* aPresContext,
    9881             :                       nsIFrame * aFrame,
    9882             :                       const nsPoint& aOffset,
    9883             :                       uint32_t aColor)
    9884             : {
    9885           0 :   if (mReflowCountMgr) {
    9886             :     mReflowCountMgr->PaintCount(aName, aRenderingContext, aPresContext,
    9887           0 :                                 aFrame, aOffset, aColor);
    9888             :   }
    9889           0 : }
    9890             : 
    9891             : //-------------------------------------------------------------
    9892             : void
    9893           0 : PresShell::SetPaintFrameCount(bool aPaintFrameCounts)
    9894             : {
    9895           0 :   if (mReflowCountMgr) {
    9896           0 :     mReflowCountMgr->SetPaintFrameCounts(aPaintFrameCounts);
    9897             :   }
    9898           0 : }
    9899             : 
    9900             : bool
    9901          24 : PresShell::IsPaintingFrameCounts()
    9902             : {
    9903          24 :   if (mReflowCountMgr)
    9904          24 :     return mReflowCountMgr->IsPaintingFrameCounts();
    9905             :   return false;
    9906             : }
    9907             : 
    9908             : //------------------------------------------------------------------
    9909             : //-- Reflow Counter Classes Impls
    9910             : //------------------------------------------------------------------
    9911             : 
    9912             : //------------------------------------------------------------------
    9913           0 : ReflowCounter::ReflowCounter(ReflowCountMgr * aMgr) :
    9914           0 :   mMgr(aMgr)
    9915             : {
    9916           0 :   ClearTotals();
    9917           0 :   SetTotalsCache();
    9918           0 : }
    9919             : 
    9920             : //------------------------------------------------------------------
    9921           0 : ReflowCounter::~ReflowCounter()
    9922             : {
    9923             : 
    9924           0 : }
    9925             : 
    9926             : //------------------------------------------------------------------
    9927           0 : void ReflowCounter::ClearTotals()
    9928             : {
    9929           0 :   mTotal = 0;
    9930           0 : }
    9931             : 
    9932             : //------------------------------------------------------------------
    9933           0 : void ReflowCounter::SetTotalsCache()
    9934             : {
    9935           0 :   mCacheTotal = mTotal;
    9936           0 : }
    9937             : 
    9938             : //------------------------------------------------------------------
    9939           0 : void ReflowCounter::CalcDiffInTotals()
    9940             : {
    9941           0 :   mCacheTotal = mTotal - mCacheTotal;
    9942           0 : }
    9943             : 
    9944             : //------------------------------------------------------------------
    9945           0 : void ReflowCounter::DisplayTotals(const char * aStr)
    9946             : {
    9947           0 :   DisplayTotals(mTotal, aStr?aStr:"Totals");
    9948           0 : }
    9949             : 
    9950             : //------------------------------------------------------------------
    9951           0 : void ReflowCounter::DisplayDiffTotals(const char * aStr)
    9952             : {
    9953           0 :   DisplayTotals(mCacheTotal, aStr?aStr:"Diff Totals");
    9954           0 : }
    9955             : 
    9956             : //------------------------------------------------------------------
    9957           0 : void ReflowCounter::DisplayHTMLTotals(const char * aStr)
    9958             : {
    9959           0 :   DisplayHTMLTotals(mTotal, aStr?aStr:"Totals");
    9960           0 : }
    9961             : 
    9962             : //------------------------------------------------------------------
    9963           0 : void ReflowCounter::DisplayTotals(uint32_t aTotal, const char * aTitle)
    9964             : {
    9965             :   // figure total
    9966           0 :   if (aTotal == 0) {
    9967             :     return;
    9968             :   }
    9969           0 :   ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr);
    9970             : 
    9971           0 :   printf("%25s\t", aTitle);
    9972           0 :   printf("%d\t", aTotal);
    9973           0 :   if (gTots != this && aTotal > 0) {
    9974           0 :     gTots->Add(aTotal);
    9975             :   }
    9976             : }
    9977             : 
    9978             : //------------------------------------------------------------------
    9979           0 : void ReflowCounter::DisplayHTMLTotals(uint32_t aTotal, const char * aTitle)
    9980             : {
    9981           0 :   if (aTotal == 0) {
    9982             :     return;
    9983             :   }
    9984             : 
    9985           0 :   ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr);
    9986           0 :   FILE * fd = mMgr->GetOutFile();
    9987           0 :   if (!fd) {
    9988             :     return;
    9989             :   }
    9990             : 
    9991           0 :   fprintf(fd, "<tr><td><center>%s</center></td>", aTitle);
    9992           0 :   fprintf(fd, "<td><center>%d</center></td></tr>\n", aTotal);
    9993             : 
    9994           0 :   if (gTots != this && aTotal > 0) {
    9995           0 :     gTots->Add(aTotal);
    9996             :   }
    9997             : }
    9998             : 
    9999             : //------------------------------------------------------------------
   10000             : //-- ReflowCountMgr
   10001             : //------------------------------------------------------------------
   10002             : 
   10003             : #define KEY_BUF_SIZE_FOR_PTR  24 // adequate char[] buffer to sprintf a pointer
   10004             : 
   10005          27 : ReflowCountMgr::ReflowCountMgr()
   10006             :   : mCounts(10)
   10007          81 :   , mIndiFrameCounts(10)
   10008             : {
   10009           0 :   mCycledOnce              = false;
   10010          27 :   mDumpFrameCounts         = false;
   10011           0 :   mDumpFrameByFrameCounts  = false;
   10012          27 :   mPaintFrameByFrameCounts = false;
   10013           0 : }
   10014             : 
   10015             : //------------------------------------------------------------------
   10016           0 : ReflowCountMgr::~ReflowCountMgr()
   10017             : {
   10018          24 : }
   10019             : 
   10020             : //------------------------------------------------------------------
   10021           0 : ReflowCounter * ReflowCountMgr::LookUp(const char * aName)
   10022             : {
   10023           0 :   return mCounts.Get(aName);
   10024             : }
   10025             : 
   10026             : //------------------------------------------------------------------
   10027           1 : void ReflowCountMgr::Add(const char * aName, nsIFrame * aFrame)
   10028             : {
   10029         353 :   NS_ASSERTION(aName != nullptr, "Name shouldn't be null!");
   10030             : 
   10031           0 :   if (mDumpFrameCounts) {
   10032           0 :     ReflowCounter * counter = mCounts.LookupForAdd(aName).OrInsert([this]() {
   10033           0 :       return new ReflowCounter(this);
   10034           0 :     });
   10035           0 :     counter->Add();
   10036             :   }
   10037             : 
   10038           1 :   if ((mDumpFrameByFrameCounts || mPaintFrameByFrameCounts) &&
   10039           0 :       aFrame != nullptr) {
   10040             :     char key[KEY_BUF_SIZE_FOR_PTR];
   10041           0 :     SprintfLiteral(key, "%p", (void*)aFrame);
   10042             :     IndiReflowCounter * counter =
   10043           0 :       mIndiFrameCounts.LookupForAdd(key).OrInsert([&aName, &aFrame, this]() {
   10044           0 :         auto counter = new IndiReflowCounter(this);
   10045           0 :         counter->mFrame = aFrame;
   10046           0 :         counter->mName.AssignASCII(aName);
   10047           0 :         return counter;
   10048           0 :       });
   10049             :     // this eliminates extra counts from super classes
   10050           0 :     if (counter != nullptr && counter->mName.EqualsASCII(aName)) {
   10051           0 :       counter->mCount++;
   10052           0 :       counter->mCounter.Add(1);
   10053             :     }
   10054             :   }
   10055           1 : }
   10056             : 
   10057             : //------------------------------------------------------------------
   10058           0 : void ReflowCountMgr::PaintCount(const char*     aName,
   10059             :                                 gfxContext*     aRenderingContext,
   10060             :                                 nsPresContext*  aPresContext,
   10061             :                                 nsIFrame*       aFrame,
   10062             :                                 const nsPoint&  aOffset,
   10063             :                                 uint32_t        aColor)
   10064             : {
   10065           0 :   if (mPaintFrameByFrameCounts &&
   10066             :       aFrame != nullptr) {
   10067             :     char key[KEY_BUF_SIZE_FOR_PTR];
   10068           0 :     SprintfLiteral(key, "%p", (void*)aFrame);
   10069           0 :     IndiReflowCounter * counter = mIndiFrameCounts.Get(key);
   10070           0 :     if (counter != nullptr && counter->mName.EqualsASCII(aName)) {
   10071           0 :       DrawTarget* drawTarget = aRenderingContext->GetDrawTarget();
   10072           0 :       int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
   10073             : 
   10074           0 :       aRenderingContext->Save();
   10075             :       gfxPoint devPixelOffset =
   10076           0 :         nsLayoutUtils::PointToGfxPoint(aOffset, appUnitsPerDevPixel);
   10077             :       aRenderingContext->SetMatrixDouble(
   10078           0 :         aRenderingContext->CurrentMatrixDouble().PreTranslate(devPixelOffset));
   10079             : 
   10080             :       // We don't care about the document language or user fonts here;
   10081             :       // just get a default Latin font.
   10082           0 :       nsFont font(eFamily_serif, nsPresContext::CSSPixelsToAppUnits(11));
   10083           0 :       nsFontMetrics::Params params;
   10084           0 :       params.language = nsGkAtoms::x_western;
   10085           0 :       params.textPerf = aPresContext->GetTextPerfMetrics();
   10086             :       RefPtr<nsFontMetrics> fm =
   10087           0 :         aPresContext->DeviceContext()->GetMetricsFor(font, params);
   10088             : 
   10089             :       char buf[16];
   10090           0 :       int len = SprintfLiteral(buf, "%d", counter->mCount);
   10091           0 :       nscoord x = 0, y = fm->MaxAscent();
   10092           0 :       nscoord width, height = fm->MaxHeight();
   10093           0 :       fm->SetTextRunRTL(false);
   10094           0 :       width = fm->GetWidth(buf, len, drawTarget);
   10095             : 
   10096           0 :       Color color;
   10097           0 :       Color color2;
   10098           0 :       if (aColor != 0) {
   10099           0 :         color  = Color::FromABGR(aColor);
   10100           0 :         color2 = Color(0.f, 0.f, 0.f);
   10101             :       } else {
   10102           0 :         gfx::Float rc = 0.f, gc = 0.f, bc = 0.f;
   10103           0 :         if (counter->mCount < 5) {
   10104             :           rc = 1.f;
   10105             :           gc = 1.f;
   10106           0 :         } else if (counter->mCount < 11) {
   10107             :           gc = 1.f;
   10108             :         } else {
   10109           0 :           rc = 1.f;
   10110             :         }
   10111           0 :         color  = Color(rc, gc, bc);
   10112           0 :         color2 = Color(rc/2, gc/2, bc/2);
   10113             :       }
   10114             : 
   10115           0 :       nsRect rect(0,0, width+15, height+15);
   10116             :       Rect devPxRect =
   10117           0 :         NSRectToSnappedRect(rect, appUnitsPerDevPixel, *drawTarget);
   10118           0 :       ColorPattern black(ToDeviceColor(Color(0.f, 0.f, 0.f, 1.f)));
   10119           0 :       drawTarget->FillRect(devPxRect, black);
   10120             : 
   10121           0 :       aRenderingContext->SetColor(color2);
   10122           0 :       fm->DrawString(buf, len, x+15, y+15, aRenderingContext);
   10123           0 :       aRenderingContext->SetColor(color);
   10124           0 :       fm->DrawString(buf, len, x, y, aRenderingContext);
   10125             : 
   10126           0 :       aRenderingContext->Restore();
   10127             :     }
   10128             :   }
   10129           0 : }
   10130             : 
   10131             : //------------------------------------------------------------------
   10132           0 : void ReflowCountMgr::DoGrandTotals()
   10133             : {
   10134           0 :   auto entry = mCounts.LookupForAdd(kGrandTotalsStr);
   10135           0 :   if (!entry) {
   10136           0 :     entry.OrInsert([this]() { return new ReflowCounter(this); });
   10137             :   } else {
   10138           0 :     entry.Data()->ClearTotals();
   10139             :   }
   10140             : 
   10141           0 :   printf("\t\t\t\tTotal\n");
   10142           0 :   for (uint32_t i=0;i<78;i++) {
   10143           0 :     printf("-");
   10144             :   }
   10145           0 :   printf("\n");
   10146           0 :   for (auto iter = mCounts.Iter(); !iter.Done(); iter.Next()) {
   10147           0 :     iter.Data()->DisplayTotals(iter.Key());
   10148             :   }
   10149           0 : }
   10150             : 
   10151           0 : static void RecurseIndiTotals(nsPresContext* aPresContext,
   10152             :                               nsClassHashtable<nsCharPtrHashKey,
   10153             :                                                IndiReflowCounter>& aHT,
   10154             :                               nsIFrame *      aParentFrame,
   10155             :                               int32_t         aLevel)
   10156             : {
   10157           0 :   if (aParentFrame == nullptr) {
   10158           0 :     return;
   10159             :   }
   10160             : 
   10161             :   char key[KEY_BUF_SIZE_FOR_PTR];
   10162           0 :   SprintfLiteral(key, "%p", (void*)aParentFrame);
   10163           0 :   IndiReflowCounter * counter = aHT.Get(key);
   10164           0 :   if (counter) {
   10165           0 :     counter->mHasBeenOutput = true;
   10166           0 :     char * name = ToNewCString(counter->mName);
   10167           0 :     for (int32_t i=0;i<aLevel;i++) printf(" ");
   10168           0 :     printf("%s - %p   [%d][", name, (void*)aParentFrame, counter->mCount);
   10169           0 :     printf("%d", counter->mCounter.GetTotal());
   10170           0 :     printf("]\n");
   10171           0 :     free(name);
   10172             :   }
   10173             : 
   10174           0 :   for (nsIFrame* child : aParentFrame->PrincipalChildList()) {
   10175           0 :     RecurseIndiTotals(aPresContext, aHT, child, aLevel+1);
   10176             :   }
   10177             : 
   10178             : }
   10179             : 
   10180             : //------------------------------------------------------------------
   10181           0 : void ReflowCountMgr::DoIndiTotalsTree()
   10182             : {
   10183           0 :   printf("\n------------------------------------------------\n");
   10184           0 :   printf("-- Individual Frame Counts\n");
   10185           0 :   printf("------------------------------------------------\n");
   10186             : 
   10187           0 :   if (mPresShell) {
   10188           0 :     nsIFrame* rootFrame = mPresShell->GetRootFrame();
   10189           0 :     RecurseIndiTotals(mPresContext, mIndiFrameCounts, rootFrame, 0);
   10190           0 :     printf("------------------------------------------------\n");
   10191           0 :     printf("-- Individual Counts of Frames not in Root Tree\n");
   10192           0 :     printf("------------------------------------------------\n");
   10193           0 :     for (auto iter = mIndiFrameCounts.Iter(); !iter.Done(); iter.Next()) {
   10194           0 :       IndiReflowCounter* counter = iter.Data();
   10195           0 :       if (!counter->mHasBeenOutput) {
   10196           0 :         char * name = ToNewCString(counter->mName);
   10197           0 :         printf("%s - %p   [%d][", name, (void*)counter->mFrame, counter->mCount);
   10198           0 :         printf("%d", counter->mCounter.GetTotal());
   10199           0 :         printf("]\n");
   10200           0 :         free(name);
   10201             :       }
   10202             :     }
   10203             :   }
   10204           0 : }
   10205             : 
   10206             : //------------------------------------------------------------------
   10207           0 : void ReflowCountMgr::DoGrandHTMLTotals()
   10208             : {
   10209           0 :   auto entry = mCounts.LookupForAdd(kGrandTotalsStr);
   10210           0 :   if (!entry) {
   10211           0 :     entry.OrInsert([this]() { return new ReflowCounter(this); });
   10212             :   } else {
   10213           0 :     entry.Data()->ClearTotals();
   10214             :   }
   10215             : 
   10216             :   static const char * title[] = {"Class", "Reflows"};
   10217           0 :   fprintf(mFD, "<tr>");
   10218           0 :   for (uint32_t i=0; i < ArrayLength(title); i++) {
   10219           0 :     fprintf(mFD, "<td><center><b>%s<b></center></td>", title[i]);
   10220             :   }
   10221           0 :   fprintf(mFD, "</tr>\n");
   10222             : 
   10223           0 :   for (auto iter = mCounts.Iter(); !iter.Done(); iter.Next()) {
   10224           0 :     iter.Data()->DisplayHTMLTotals(iter.Key());
   10225             :   }
   10226           0 : }
   10227             : 
   10228             : //------------------------------------
   10229           8 : void ReflowCountMgr::DisplayTotals(const char * aStr)
   10230             : {
   10231             : #ifdef DEBUG_rods
   10232             :   printf("%s\n", aStr?aStr:"No name");
   10233             : #endif
   10234           8 :   if (mDumpFrameCounts) {
   10235           0 :     DoGrandTotals();
   10236             :   }
   10237           8 :   if (mDumpFrameByFrameCounts) {
   10238           0 :     DoIndiTotalsTree();
   10239             :   }
   10240             : 
   10241           0 : }
   10242             : //------------------------------------
   10243           0 : void ReflowCountMgr::DisplayHTMLTotals(const char * aStr)
   10244             : {
   10245             : #ifdef WIN32x // XXX NOT XP!
   10246             :   char name[1024];
   10247             : 
   10248             :   char * sptr = strrchr(aStr, '/');
   10249             :   if (sptr) {
   10250             :     sptr++;
   10251             :     strcpy(name, sptr);
   10252             :     char * eptr = strrchr(name, '.');
   10253             :     if (eptr) {
   10254             :       *eptr = 0;
   10255             :     }
   10256             :     strcat(name, "_stats.html");
   10257             :   }
   10258             :   mFD = fopen(name, "w");
   10259             :   if (mFD) {
   10260             :     fprintf(mFD, "<html><head><title>Reflow Stats</title></head><body>\n");
   10261             :     const char * title = aStr?aStr:"No name";
   10262             :     fprintf(mFD, "<center><b>%s</b><br><table border=1 style=\"background-color:#e0e0e0\">", title);
   10263             :     DoGrandHTMLTotals();
   10264             :     fprintf(mFD, "</center></table>\n");
   10265             :     fprintf(mFD, "</body></html>\n");
   10266             :     fclose(mFD);
   10267             :     mFD = nullptr;
   10268             :   }
   10269             : #endif // not XP!
   10270           0 : }
   10271             : 
   10272             : //------------------------------------------------------------------
   10273           0 : void ReflowCountMgr::ClearTotals()
   10274             : {
   10275           0 :   for (auto iter = mCounts.Iter(); !iter.Done(); iter.Next()) {
   10276           0 :     iter.Data()->ClearTotals();
   10277             :   }
   10278           0 : }
   10279             : 
   10280             : //------------------------------------------------------------------
   10281           0 : void ReflowCountMgr::ClearGrandTotals()
   10282             : {
   10283           0 :   auto entry = mCounts.LookupForAdd(kGrandTotalsStr);
   10284           0 :   if (!entry) {
   10285           0 :     entry.OrInsert([this]() { return new ReflowCounter(this); });
   10286             :   } else {
   10287           0 :     entry.Data()->ClearTotals();
   10288           0 :     entry.Data()->SetTotalsCache();
   10289             :   }
   10290           0 : }
   10291             : 
   10292             : //------------------------------------------------------------------
   10293           8 : void ReflowCountMgr::DisplayDiffsInTotals()
   10294             : {
   10295           8 :   if (mCycledOnce) {
   10296           0 :     printf("Differences\n");
   10297           0 :     for (int32_t i=0;i<78;i++) {
   10298           0 :       printf("-");
   10299             :     }
   10300           0 :     printf("\n");
   10301           0 :     ClearGrandTotals();
   10302             :   }
   10303             : 
   10304           1 :   for (auto iter = mCounts.Iter(); !iter.Done(); iter.Next()) {
   10305           0 :     if (mCycledOnce) {
   10306           0 :       iter.Data()->CalcDiffInTotals();
   10307           0 :       iter.Data()->DisplayDiffTotals(iter.Key());
   10308             :     }
   10309           0 :     iter.Data()->SetTotalsCache();
   10310             :   }
   10311             : 
   10312           8 :   mCycledOnce = true;
   10313           1 : }
   10314             : 
   10315             : #endif // MOZ_REFLOW_PERF
   10316             : 
   10317           0 : nsIFrame* nsIPresShell::GetAbsoluteContainingBlock(nsIFrame *aFrame)
   10318             : {
   10319           0 :   return FrameConstructor()->GetAbsoluteContainingBlock(aFrame,
   10320           0 :       nsCSSFrameConstructor::ABS_POS);
   10321             : }
   10322             : 
   10323             : #ifdef ACCESSIBILITY
   10324             : bool
   10325           1 : nsIPresShell::IsAccessibilityActive()
   10326             : {
   10327           1 :   return GetAccService() != nullptr;
   10328             : }
   10329             : 
   10330             : nsAccessibilityService*
   10331           0 : nsIPresShell::AccService()
   10332             : {
   10333          75 :   return GetAccService();
   10334             : }
   10335             : #endif
   10336             : 
   10337             : // Asks our docshell whether we're active.
   10338          27 : void PresShell::QueryIsActive()
   10339             : {
   10340          54 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
   10341          54 :   if (mDocument) {
   10342           0 :     nsIDocument* displayDoc = mDocument->GetDisplayDocument();
   10343          27 :     if (displayDoc) {
   10344             :       // Ok, we're an external resource document -- we need to use our display
   10345             :       // document's docshell to determine "IsActive" status, since we lack
   10346             :       // a container.
   10347           0 :       MOZ_ASSERT(!container,
   10348             :                  "external resource doc shouldn't have its own container");
   10349             : 
   10350           0 :       nsPresContext* displayPresContext = displayDoc->GetPresContext();
   10351           0 :       if (displayPresContext) {
   10352           0 :         container = displayPresContext->GetContainerWeak();
   10353             :       }
   10354             :     }
   10355             :   }
   10356             : 
   10357          81 :   nsCOMPtr<nsIDocShell> docshell(do_QueryInterface(container));
   10358          27 :   if (docshell) {
   10359             :     bool isActive;
   10360          14 :     nsresult rv = docshell->GetIsActive(&isActive);
   10361             :     // Even though in theory the docshell here could be "Inactive and
   10362             :     // Foreground", thus implying aIsHidden=false for SetIsActive(),
   10363             :     // this is a newly created PresShell so we'd like to invalidate anyway
   10364             :     // upon being made active to ensure that the contents get painted.
   10365          14 :     if (NS_SUCCEEDED(rv))
   10366          14 :       SetIsActive(isActive);
   10367             :   }
   10368          27 : }
   10369             : 
   10370             : // Helper for propagating mIsActive changes to external resources
   10371             : static bool
   10372           0 : SetExternalResourceIsActive(nsIDocument* aDocument, void* aClosure)
   10373             : {
   10374           0 :   nsIPresShell* shell = aDocument->GetShell();
   10375           0 :   if (shell) {
   10376           0 :     shell->SetIsActive(*static_cast<bool*>(aClosure));
   10377             :   }
   10378           0 :   return true;
   10379             : }
   10380             : 
   10381             : static void
   10382           0 : SetPluginIsActive(nsISupports* aSupports, void* aClosure)
   10383             : {
   10384           0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports));
   10385           0 :   if (!content) {
   10386           0 :     return;
   10387             :   }
   10388             : 
   10389           0 :   nsIFrame *frame = content->GetPrimaryFrame();
   10390           0 :   nsIObjectFrame *objectFrame = do_QueryFrame(frame);
   10391           0 :   if (objectFrame) {
   10392           0 :     objectFrame->SetIsDocumentActive(*static_cast<bool*>(aClosure));
   10393             :   }
   10394             : }
   10395             : 
   10396             : nsresult
   10397          21 : PresShell::SetIsActive(bool aIsActive)
   10398             : {
   10399          42 :   MOZ_ASSERT(mDocument, "should only be called with a document");
   10400             : 
   10401           0 :   mIsActive = aIsActive;
   10402             : 
   10403           0 :   nsPresContext* presContext = GetPresContext();
   10404          42 :   if (presContext &&
   10405           0 :       presContext->RefreshDriver()->GetPresContext() == presContext) {
   10406          42 :     presContext->RefreshDriver()->SetThrottled(!mIsActive);
   10407             :   }
   10408             : 
   10409             :   // Propagate state-change to my resource documents' PresShells
   10410           0 :   mDocument->EnumerateExternalResources(SetExternalResourceIsActive,
   10411          21 :                                         &aIsActive);
   10412          21 :   mDocument->EnumerateActivityObservers(SetPluginIsActive,
   10413          21 :                                         &aIsActive);
   10414           0 :   nsresult rv = UpdateImageLockingState();
   10415             : #ifdef ACCESSIBILITY
   10416           0 :   if (aIsActive) {
   10417           0 :     nsAccessibilityService* accService = AccService();
   10418           0 :     if (accService) {
   10419           0 :       accService->PresShellActivated(this);
   10420             :     }
   10421             :   }
   10422             : #endif
   10423           0 :   return rv;
   10424             : }
   10425             : 
   10426             : /*
   10427             :  * Determines the current image locking state. Called when one of the
   10428             :  * dependent factors changes.
   10429             :  */
   10430             : nsresult
   10431          21 : PresShell::UpdateImageLockingState()
   10432             : {
   10433             :   // We're locked if we're both thawed and active.
   10434          21 :   bool locked = !mFrozen && mIsActive;
   10435             : 
   10436          21 :   nsresult rv = mDocument->ImageTracker()->SetLockingState(locked);
   10437             : 
   10438           0 :   if (locked) {
   10439             :     // Request decodes for visible image frames; we want to start decoding as
   10440             :     // quickly as possible when we get foregrounded to minimize flashing.
   10441          63 :     for (auto iter = mApproximatelyVisibleFrames.Iter(); !iter.Done(); iter.Next()) {
   10442           0 :       nsImageFrame* imageFrame = do_QueryFrame(iter.Get()->GetKey());
   10443           0 :       if (imageFrame) {
   10444           0 :         imageFrame->MaybeDecodeForPredictedSize();
   10445             :       }
   10446             :     }
   10447             :   }
   10448             : 
   10449          21 :   return rv;
   10450             : }
   10451             : 
   10452             : PresShell*
   10453           0 : PresShell::GetRootPresShell()
   10454             : {
   10455           6 :   if (mPresContext) {
   10456           3 :     nsPresContext* rootPresContext = mPresContext->GetRootPresContext();
   10457           0 :     if (rootPresContext) {
   10458           3 :       return static_cast<PresShell*>(rootPresContext->PresShell());
   10459             :     }
   10460             :   }
   10461             :   return nullptr;
   10462             : }
   10463             : 
   10464             : void
   10465          13 : PresShell::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
   10466             : {
   10467          13 :   MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
   10468          13 :   mFrameArena.AddSizeOfExcludingThis(aSizes);
   10469           0 :   aSizes.mLayoutPresShellSize += mallocSizeOf(this);
   10470          26 :   if (mCaret) {
   10471           0 :     aSizes.mLayoutPresShellSize += mCaret->SizeOfIncludingThis(mallocSizeOf);
   10472             :   }
   10473           0 :   aSizes.mLayoutPresShellSize +=
   10474           0 :     mApproximatelyVisibleFrames.ShallowSizeOfExcludingThis(mallocSizeOf) +
   10475           0 :     mFramesToDirty.ShallowSizeOfExcludingThis(mallocSizeOf);
   10476             : 
   10477           0 :   StyleSet()->AddSizeOfIncludingThis(aSizes);
   10478             : 
   10479           0 :   aSizes.mLayoutTextRunsSize += SizeOfTextRuns(mallocSizeOf);
   10480             : 
   10481           0 :   aSizes.mLayoutPresContextSize +=
   10482          13 :     mPresContext->SizeOfIncludingThis(mallocSizeOf);
   10483             : 
   10484          13 :   mFrameConstructor->AddSizeOfIncludingThis(aSizes);
   10485           0 : }
   10486             : 
   10487             : size_t
   10488           0 : PresShell::SizeOfTextRuns(MallocSizeOf aMallocSizeOf) const
   10489             : {
   10490          13 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
   10491          13 :   if (!rootFrame) {
   10492             :     return 0;
   10493             :   }
   10494             : 
   10495             :   // clear the TEXT_RUN_MEMORY_ACCOUNTED flags
   10496             :   nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, nullptr,
   10497          13 :                                          /* clear = */true);
   10498             : 
   10499             :   // collect the total memory in use for textruns
   10500             :   return nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, aMallocSizeOf,
   10501           0 :                                                 /* clear = */false);
   10502             : }
   10503             : 
   10504             : void
   10505           0 : nsIPresShell::MarkFixedFramesForReflow(IntrinsicDirty aIntrinsicDirty)
   10506             : {
   10507           0 :   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
   10508           0 :   if (rootFrame) {
   10509           0 :     const nsFrameList& childList = rootFrame->GetChildList(nsIFrame::kFixedList);
   10510           0 :     for (nsIFrame* childFrame : childList) {
   10511           0 :       FrameNeedsReflow(childFrame, aIntrinsicDirty, NS_FRAME_IS_DIRTY);
   10512             :     }
   10513             :   }
   10514           0 : }
   10515             : 
   10516             : void
   10517           0 : nsIPresShell::SetScrollPositionClampingScrollPortSize(nscoord aWidth, nscoord aHeight)
   10518             : {
   10519           0 :   if (!mScrollPositionClampingScrollPortSizeSet ||
   10520           0 :       mScrollPositionClampingScrollPortSize.width != aWidth ||
   10521           0 :       mScrollPositionClampingScrollPortSize.height != aHeight) {
   10522           0 :     mScrollPositionClampingScrollPortSizeSet = true;
   10523           0 :     mScrollPositionClampingScrollPortSize.width = aWidth;
   10524           0 :     mScrollPositionClampingScrollPortSize.height = aHeight;
   10525             : 
   10526           0 :     if (nsIScrollableFrame* rootScrollFrame = GetRootScrollFrameAsScrollable()) {
   10527           0 :       rootScrollFrame->MarkScrollbarsDirtyForReflow();
   10528             :     }
   10529           0 :     MarkFixedFramesForReflow(nsIPresShell::eResize);
   10530             :   }
   10531           0 : }
   10532             : 
   10533             : void
   10534          19 : nsIPresShell::RecomputeFontSizeInflationEnabled()
   10535             : {
   10536          19 :   mFontSizeInflationEnabled = DetermineFontSizeInflationState();
   10537             : 
   10538           0 :   float fontScale = nsLayoutUtils::SystemFontScale();
   10539          19 :   if (fontScale == 0.0f) {
   10540             :     return;
   10541             :   }
   10542             : 
   10543           0 :   MOZ_ASSERT(mDocument);
   10544          38 :   MOZ_ASSERT(mPresContext);
   10545          38 :   if (mFontSizeInflationEnabled || mDocument->IsSyntheticDocument()) {
   10546           0 :     mPresContext->SetSystemFontScale(1.0f);
   10547             :   } else {
   10548           0 :     mPresContext->SetSystemFontScale(fontScale);
   10549             :   }
   10550             : }
   10551             : 
   10552             : bool
   10553          19 : nsIPresShell::DetermineFontSizeInflationState()
   10554             : {
   10555          38 :   MOZ_ASSERT(mPresContext, "our pres context should not be null");
   10556          38 :   if (mPresContext->IsChrome()) {
   10557             :     return false;
   10558             :   }
   10559             : 
   10560           0 :   if (FontSizeInflationEmPerLine() == 0 && FontSizeInflationMinTwips() == 0) {
   10561             :     return false;
   10562             :   }
   10563             : 
   10564             :   // Force-enabling font inflation always trumps the heuristics here.
   10565           0 :   if (!FontSizeInflationForceEnabled()) {
   10566           0 :     if (TabChild* tab = TabChild::GetFrom(this)) {
   10567             :       // We're in a child process.  Cancel inflation if we're not
   10568             :       // async-pan zoomed.
   10569           0 :       if (!tab->AsyncPanZoomEnabled()) {
   10570             :         return false;
   10571             :       }
   10572           0 :     } else if (XRE_IsParentProcess()) {
   10573             :       // We're in the master process.  Cancel inflation if it's been
   10574             :       // explicitly disabled.
   10575           0 :       if (FontSizeInflationDisabledInMasterProcess()) {
   10576             :         return false;
   10577             :       }
   10578             :     }
   10579             :   }
   10580             : 
   10581             :   // XXXjwir3:
   10582             :   // See bug 706918, comment 23 for more information on this particular section
   10583             :   // of the code. We're using "screen size" in place of the size of the content
   10584             :   // area, because on mobile, these are close or equal. This will work for our
   10585             :   // purposes (bug 706198), but it will need to be changed in the future to be
   10586             :   // more correct when we bring the rest of the viewport code into platform.
   10587             :   // We actually want the size of the content area, in the event that we don't
   10588             :   // have any metadata about the width and/or height. On mobile, the screen size
   10589             :   // and the size of the content area are very close, or the same value.
   10590             :   // In XUL fennec, the content area is the size of the <browser> widget, but
   10591             :   // in native fennec, the content area is the size of the Gecko LayerView
   10592             :   // object.
   10593             : 
   10594             :   // TODO:
   10595             :   // Once bug 716575 has been resolved, this code should be changed so that it
   10596             :   // does the right thing on all platforms.
   10597             :   nsresult rv;
   10598             :   nsCOMPtr<nsIScreenManager> screenMgr =
   10599           0 :     do_GetService("@mozilla.org/gfx/screenmanager;1", &rv);
   10600           0 :   if (!NS_SUCCEEDED(rv)) {
   10601             :     return false;
   10602             :   }
   10603             : 
   10604           0 :   nsCOMPtr<nsIScreen> screen;
   10605           0 :   screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
   10606           0 :   if (screen) {
   10607             :     int32_t screenLeft, screenTop, screenWidth, screenHeight;
   10608           0 :     screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
   10609             : 
   10610             :     nsViewportInfo vInf =
   10611           0 :       GetDocument()->GetViewportInfo(ScreenIntSize(screenWidth, screenHeight));
   10612             : 
   10613           0 :     if (vInf.GetDefaultZoom() >= CSSToScreenScale(1.0f) || vInf.IsAutoSizeEnabled()) {
   10614           0 :       return false;
   10615             :     }
   10616             :   }
   10617             : 
   10618             :   return true;
   10619             : }
   10620             : 
   10621             : void
   10622           0 : PresShell::PausePainting()
   10623             : {
   10624           0 :   if (GetPresContext()->RefreshDriver()->GetPresContext() != GetPresContext())
   10625             :     return;
   10626             : 
   10627           0 :   mPaintingIsFrozen = true;
   10628           0 :   GetPresContext()->RefreshDriver()->Freeze();
   10629             : }
   10630             : 
   10631             : void
   10632           0 : PresShell::ResumePainting()
   10633             : {
   10634           0 :   if (GetPresContext()->RefreshDriver()->GetPresContext() != GetPresContext())
   10635             :     return;
   10636             : 
   10637           0 :   mPaintingIsFrozen = false;
   10638           0 :   GetPresContext()->RefreshDriver()->Thaw();
   10639             : }
   10640             : 
   10641             : void
   10642           1 : nsIPresShell::SyncWindowProperties(nsView* aView)
   10643             : {
   10644           7 :   nsIFrame* frame = aView->GetFrame();
   10645          14 :   if (frame && mPresContext) {
   10646             :     // CreateReferenceRenderingContext can return nullptr
   10647          21 :     RefPtr<gfxContext> rcx(CreateReferenceRenderingContext());
   10648           0 :     nsContainerFrame::SyncWindowProperties(mPresContext, frame, aView, rcx, 0);
   10649             :   }
   10650           7 : }
   10651             : 
   10652             : static SheetType
   10653           0 : ToSheetType(uint32_t aServiceSheetType)
   10654             : {
   10655           0 :   switch (aServiceSheetType) {
   10656             :     case nsIStyleSheetService::AGENT_SHEET:
   10657             :       return SheetType::Agent;
   10658             :       break;
   10659             :     case nsIStyleSheetService::USER_SHEET:
   10660           0 :       return SheetType::User;
   10661             :       break;
   10662             :     default:
   10663           0 :       MOZ_FALLTHROUGH_ASSERT("unexpected aSheetType value");
   10664             :     case nsIStyleSheetService::AUTHOR_SHEET:
   10665           0 :       return SheetType::Doc;
   10666             :   }
   10667             : }
   10668             : 
   10669             : nsresult
   10670           0 : nsIPresShell::HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType,
   10671             :                                                       bool* aRetVal)
   10672             : {
   10673           0 :   *aRetVal = false;
   10674           0 :   return NS_OK;
   10675             : }
   10676             : 
   10677             : void
   10678           0 : PresShell::NotifyStyleSheetServiceSheetAdded(StyleSheet* aSheet,
   10679             :                                              uint32_t aSheetType)
   10680             : {
   10681           0 :   if (!mStyleSet) {
   10682             :     return;
   10683             :   }
   10684             : 
   10685           0 :   switch (aSheetType) {
   10686             :     case nsIStyleSheetService::AGENT_SHEET:
   10687           0 :       AddAgentSheet(aSheet);
   10688           0 :       break;
   10689             :     case nsIStyleSheetService::USER_SHEET:
   10690           0 :       AddUserSheet(aSheet);
   10691           0 :       break;
   10692             :     case nsIStyleSheetService::AUTHOR_SHEET:
   10693           0 :       AddAuthorSheet(aSheet);
   10694           0 :       break;
   10695             :     default:
   10696           0 :       MOZ_ASSERT_UNREACHABLE("unexpected aSheetType value");
   10697             :       break;
   10698             :   }
   10699             : }
   10700             : 
   10701             : void
   10702           0 : PresShell::NotifyStyleSheetServiceSheetRemoved(StyleSheet* aSheet,
   10703             :                                                uint32_t aSheetType)
   10704             : {
   10705           0 :   if (!mStyleSet) {
   10706             :     return;
   10707             :   }
   10708             : 
   10709           0 :   RemoveSheet(ToSheetType(aSheetType), aSheet);
   10710             : }
   10711             : 
   10712             : nsIContent*
   10713           0 : PresShell::GetOverrideClickTarget(WidgetGUIEvent* aEvent,
   10714             :                                   nsIFrame* aFrame)
   10715             : {
   10716           0 :   if (aEvent->mMessage != eMouseUp) {
   10717             :     return nullptr;
   10718             :   }
   10719             : 
   10720           0 :   MOZ_ASSERT(aEvent->mClass == eMouseEventClass);
   10721           0 :   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
   10722             : 
   10723           0 :   uint32_t flags = 0;
   10724             :   nsPoint eventPoint =
   10725           0 :     nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aFrame);
   10726           0 :   if (mouseEvent->mIgnoreRootScrollFrame) {
   10727           0 :     flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME;
   10728             :   }
   10729             : 
   10730             :   nsIFrame* target =
   10731           0 :     FindFrameTargetedByInputEvent(aEvent, aFrame, eventPoint, flags);
   10732           0 :   if (!target) {
   10733             :     return nullptr;
   10734             :   }
   10735             : 
   10736           0 :   nsIContent* overrideClickTarget = target->GetContent();
   10737           0 :   while (overrideClickTarget && !overrideClickTarget->IsElement()) {
   10738           0 :     overrideClickTarget = overrideClickTarget->GetFlattenedTreeParent();
   10739             :   }
   10740             :   return overrideClickTarget;
   10741             : }

Generated by: LCOV version 1.13-14-ga5dd952